1
/***************************************************************************
4
* Sat Jun 19 16:12:19 2010
5
* Copyright 2010 rogerio
6
* <rogerioferro@gmail.com>
7
****************************************************************************/
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU Library General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
25
#include "selection.h"
26
#include "cv_drawing.h"
51
GdkPoint sp; /*Start Point*/
52
GdkPoint ep; /*End Poind*/
53
GpSelBox boxes[SEL_NONE];
56
gint show_borders : 1;
59
GdkPixbuf *pb_clipboard;
62
static gboolean gp_selection_get_bg_color_rgb(guchar *r, guchar *g, guchar *b);
65
static PrivData *m_priv = NULL;
68
create_private_data( void )
72
m_priv = g_slice_new0 (PrivData);
79
destroy_image ( void )
81
if ( m_priv->image != NULL )
83
g_object_unref ( m_priv->image );
89
destroy_private_data( void )
94
g_slice_free (PrivData, m_priv);
101
update_clipbox ( void )
103
GdkPoint *sp = &m_priv->sp;
104
GdkPoint *ep = &m_priv->ep;
105
GpSelBox *clipbox = &m_priv->boxes[SEL_CLIPBOX];
109
clipbox->p0.x = sp->x;
110
clipbox->p1.x = ep->x;
114
clipbox->p1.x = sp->x;
115
clipbox->p0.x = ep->x;
120
clipbox->p0.y = sp->y;
121
clipbox->p1.y = ep->y;
125
clipbox->p1.y = sp->y;
126
clipbox->p0.y = ep->y;
131
set_sel_box ( GpSelBox *box, gint x0, gint y0, gint x1, gint y1 )
140
update_borders ( void )
143
if ( m_priv->show_borders )
145
GdkPoint *sp = &m_priv->sp;
146
GdkPoint *ep = &m_priv->ep;
147
GpSelBox *clipbox = &m_priv->boxes[SEL_CLIPBOX];
149
gint xl,yt,xr,yb,xm,ym;
151
sp->x = clipbox->p0.x;
152
sp->y = clipbox->p0.y;
153
ep->x = clipbox->p1.x;
154
ep->y = clipbox->p1.y;
164
set_sel_box ( &m_priv->boxes[SEL_TOP_LEFT],
166
set_sel_box ( &m_priv->boxes[SEL_TOP_MID],
167
xm-s/2,yt,xm+s/2,yt+s);
168
set_sel_box ( &m_priv->boxes[SEL_TOP_RIGHT],
170
set_sel_box ( &m_priv->boxes[SEL_MID_LEFT],
171
xl,ym-s/2,xl+s,ym+s/2);
172
set_sel_box ( &m_priv->boxes[SEL_MID_RIGHT],
173
xr-s,ym-s/2,xr,ym+s/2);
174
set_sel_box ( &m_priv->boxes[SEL_BOTTOM_LEFT],
176
set_sel_box ( &m_priv->boxes[SEL_BOTTOM_MID],
177
xm-s/2,yb-s,xm+s/2,yb);
178
set_sel_box ( &m_priv->boxes[SEL_BOTTOM_RIGHT],
184
point_in ( GdkPoint *point, GpSelBox *box)
186
if ( point->x >= box->p0.x &&
187
point->x <= box->p1.x &&
188
point->y >= box->p0.y &&
189
point->y <= box->p1.y )
200
get_box_in ( GdkPoint *point )
203
for ( box = SEL_TOP_LEFT; box < SEL_NONE; box++ )
205
if ( point_in ( point, &m_priv->boxes[box] ) )
213
gp_selection_init ( void )
215
create_private_data ();
219
gp_selection_clear ( void )
221
destroy_private_data ();
225
gp_selection_clipbox_set_start_point ( GdkPoint *p )
227
g_return_if_fail ( m_priv != NULL );
234
gp_selection_clipbox_set_end_point ( GdkPoint *p )
236
g_return_if_fail ( m_priv != NULL );
243
gp_selection_set_active ( gboolean active )
245
g_return_if_fail ( m_priv != NULL );
246
m_priv->active = active;
250
gp_selection_set_borders ( gboolean borders )
252
g_return_if_fail ( m_priv != NULL );
253
m_priv->show_borders = borders;
257
/* If pixbuf is NULL, a selection is created from the two points
258
* 's' is the top left point of a rectangle and 'e' is the bottom
259
* right. If pixbuf is not NULL a selection is created from the pixbuf
260
* and 's' is the x,y position to place the selection.
262
gboolean gp_selection_create (GdkPoint *s, GdkPoint *e, GdkPixbuf *pixbuf)
264
GdkPoint tmp = {0, 0};
269
if((NULL == s) || (NULL == e)){
278
if(GDK_IS_PIXBUF(pixbuf)){
279
m_priv->pb_clipboard = gdk_pixbuf_copy(pixbuf);
280
w = gdk_pixbuf_get_width(m_priv->pb_clipboard);
281
h = gdk_pixbuf_get_height(m_priv->pb_clipboard);
282
if(ABS(S.x - E.x) != w){
285
if(ABS(S.y - E.y) != h){
288
/* Allow for selection border */
292
gp_selection_set_floating ( TRUE );
293
gp_selection_set_active ( FALSE );
294
gp_selection_clipbox_set_start_point ( &S );
295
gp_selection_clipbox_set_end_point ( &E );
296
gp_selection_set_active ( TRUE );
298
tmp.x = ABS(S.x - E.x);
299
tmp.y = ABS(S.y - E.y);
301
gp_selection_start_action ( &tmp );
303
gp_selection_set_floating ( FALSE );
305
gp_selection_set_borders ( TRUE );
306
cv = cv_get_canvas ();
307
gtk_widget_queue_draw ( cv->widget );
312
/* button press ---+----gp_selection_set_active ( FALSE );
313
* `+--gp_selection_set_active ( TRUE );
314
* double click -> gp_selection_set_floating ( FALSE );
317
gp_selection_set_floating ( gboolean floating )
319
g_return_if_fail ( m_priv != NULL );
320
m_priv->floating = floating;
321
if ( m_priv->active )
323
GpSelBox *clipbox = &m_priv->boxes[SEL_CLIPBOX];
326
cv = cv_get_canvas ();
327
rect.x = MIN(clipbox->p0.x,clipbox->p1.x);
328
rect.y = MIN(clipbox->p0.y,clipbox->p1.y);
329
rect.width = ABS(clipbox->p1.x - clipbox->p0.x)+1;
330
rect.height = ABS(clipbox->p1.y - clipbox->p0.y)+1;
331
if ( m_priv->floating )
333
printf("gp_selection_set_floating() TRUE\n");
334
if ( m_priv->image != NULL )
336
gp_image_draw ( m_priv->image,
340
rect.width, rect.height );
346
printf("gp_selection_set_floating() FALSE\n");
348
/* Create selection from a pixbuf */
349
if(GDK_IS_PIXBUF(m_priv->pb_clipboard))
354
w = gdk_pixbuf_get_width(m_priv->pb_clipboard);
355
h = gdk_pixbuf_get_height(m_priv->pb_clipboard);
357
pm = gdk_pixmap_new (cv->widget->window, w, h, -1);
358
gdk_draw_pixbuf (pm, cv->gc_fg, m_priv->pb_clipboard, 0, 0,
359
0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0);
361
m_priv->image = gp_image_new_from_pixmap ( pm, &rect, TRUE );
363
g_object_unref(m_priv->pb_clipboard);
364
m_priv->pb_clipboard = NULL;
366
/* Create selection */
369
GdkRectangle undo_area = {0, 0, 0, 0};
371
/* Save all pixmap so redraw where selection was copied from
372
* and where sel will be pasted - which we don't know where
374
gdk_drawable_get_size (cv->pixmap, &undo_area.width, &undo_area.height);
375
undo_add ( &undo_area, NULL, NULL, TOOL_RECT_SELECT);
377
m_priv->image = gp_image_new_from_pixmap ( cv->pixmap, &rect, TRUE );
379
printf(" x: %d, y: %d, w: %d, h: %d\n", rect.x, rect.y,
380
rect.width, rect.height);
382
gdk_draw_rectangle ( cv->pixmap, cv->gc_bg, TRUE,
383
rect.x, rect.y, rect.width, rect.height );
385
/* Add transparancy if necessary */
390
m_priv->transparent = cv->transparent;
391
gp_selection_get_bg_color_rgb(&r, &g, &b);
392
gp_image_make_color_transparent( m_priv->image, r, g, b, 0);
400
gp_selection_get_cursor ( GdkPoint *p )
402
g_return_val_if_fail ( m_priv != NULL, GDK_BLANK_CURSOR);
403
switch ( get_box_in ( p ) )
406
return GDK_TOP_LEFT_CORNER;
410
return GDK_TOP_RIGHT_CORNER;
412
return GDK_LEFT_SIDE;
414
return GDK_RIGHT_SIDE;
415
case SEL_BOTTOM_LEFT:
416
return GDK_BOTTOM_LEFT_CORNER;
418
return GDK_BOTTOM_SIDE;
419
case SEL_BOTTOM_RIGHT:
420
return GDK_BOTTOM_RIGHT_CORNER;
424
return GDK_BLANK_CURSOR;
429
gp_selection_start_action ( GdkPoint *p )
431
g_return_val_if_fail ( m_priv != NULL, FALSE );
432
if ( m_priv->active )
434
m_priv->action = get_box_in ( p );
435
m_priv->p_drag.x = p->x;
436
m_priv->p_drag.y = p->y;
438
g_print ("action:%i\n", m_priv->action);
440
return (m_priv->action != SEL_NONE);
447
gp_selection_do_action ( GdkPoint *p )
449
g_return_if_fail ( m_priv != NULL );
451
GpSelBox *clipbox = &m_priv->boxes[SEL_CLIPBOX];
452
gint dx = p->x - m_priv->p_drag.x;
453
gint dy = p->y - m_priv->p_drag.y;
455
switch ( m_priv->action )
467
case SEL_BOTTOM_LEFT:
475
case SEL_BOTTOM_RIGHT:
481
m_priv->p_drag.x += dx;
482
m_priv->p_drag.y += dy;
487
draw_sel_box ( GdkDrawable *drawing, GdkGC *gc, GpSelBox *box )
492
w = (box->p1.x - x + 1);
493
h = (box->p1.y - y + 1);
494
gdk_draw_rectangle ( drawing, gc, TRUE,
499
draw_top_line ( GdkDrawable *drawing, GdkGC *gc )
501
GpSelBox *tlbox = &m_priv->boxes[SEL_TOP_LEFT];
502
GpSelBox *tmbox = &m_priv->boxes[SEL_TOP_MID];
503
GpSelBox *trbox = &m_priv->boxes[SEL_TOP_RIGHT];
504
gdk_draw_line ( drawing, gc, tlbox->p1.x+1, tlbox->p0.y,
505
tmbox->p0.x-1, tmbox->p0.y );
506
gdk_draw_line ( drawing, gc, tmbox->p1.x+1, tmbox->p0.y,
507
trbox->p0.x-1, trbox->p0.y );
511
draw_right_line ( GdkDrawable *drawing, GdkGC *gc )
513
GpSelBox *trbox = &m_priv->boxes[SEL_TOP_RIGHT];
514
GpSelBox *mrbox = &m_priv->boxes[SEL_MID_RIGHT];
515
GpSelBox *brbox = &m_priv->boxes[SEL_BOTTOM_RIGHT];
516
gdk_draw_line ( drawing, gc, trbox->p1.x, trbox->p1.y+1,
517
mrbox->p1.x, mrbox->p0.y-1);
518
gdk_draw_line ( drawing, gc, mrbox->p1.x, mrbox->p1.y+1,
519
brbox->p1.x, brbox->p0.y-1 );
524
draw_left_line ( GdkDrawable *drawing, GdkGC *gc )
526
GpSelBox *tlbox = &m_priv->boxes[SEL_TOP_LEFT];
527
GpSelBox *mlbox = &m_priv->boxes[SEL_MID_LEFT];
528
GpSelBox *blbox = &m_priv->boxes[SEL_BOTTOM_LEFT];
529
gdk_draw_line ( drawing, gc, tlbox->p0.x, tlbox->p1.y+1,
530
mlbox->p0.x, mlbox->p0.y-1 );
531
gdk_draw_line ( drawing, gc, mlbox->p0.x, mlbox->p1.y+1,
532
blbox->p0.x, blbox->p0.y-1 );
536
draw_bottom_line ( GdkDrawable *drawing, GdkGC *gc )
538
GpSelBox *brbox = &m_priv->boxes[SEL_BOTTOM_RIGHT];
539
GpSelBox *bmbox = &m_priv->boxes[SEL_BOTTOM_MID];
540
GpSelBox *blbox = &m_priv->boxes[SEL_BOTTOM_LEFT];
541
gdk_draw_line ( drawing, gc, brbox->p0.x-1, brbox->p1.y,
542
bmbox->p1.x+1, bmbox->p1.y );
543
gdk_draw_line ( drawing, gc, bmbox->p0.x-1, bmbox->p1.y,
544
blbox->p1.x+1, blbox->p1.y );
548
draw_borders ( GdkDrawable *drawing, GdkGC *gc )
551
for ( box = SEL_TOP_LEFT; box < SEL_CLIPBOX; box++ )
553
draw_sel_box ( drawing, gc, &m_priv->boxes[box] );
555
draw_top_line ( drawing, gc );
556
draw_right_line ( drawing, gc );
557
draw_bottom_line ( drawing, gc );
558
draw_left_line ( drawing, gc );
563
gp_selection_draw ( GdkDrawable *gdkd )
565
g_return_if_fail ( m_priv != NULL );
566
if ( m_priv->active )
568
GpSelBox *clipbox = &m_priv->boxes[SEL_CLIPBOX];
571
gint8 dash_list[] = { 3, 3 };
574
cv = cv_get_canvas ();
575
gc = gdk_gc_new ( cv->widget->window );
576
gdk_gc_set_function ( gc, GDK_INVERT );
577
gdk_gc_set_dashes ( gc, 0, dash_list, 2 );
578
gdk_gc_set_line_attributes ( gc, 1, GDK_LINE_ON_OFF_DASH,
579
GDK_CAP_NOT_LAST, GDK_JOIN_ROUND );
581
x = MIN(clipbox->p0.x,clipbox->p1.x);
582
y = MIN(clipbox->p0.y,clipbox->p1.y);
583
w = ABS(clipbox->p1.x - clipbox->p0.x)+1;
584
h = ABS(clipbox->p1.y - clipbox->p0.y)+1;
587
if ( m_priv->floating )
590
cr = gdk_cairo_create ( cv->drawing );
591
cairo_set_line_width (cr, 1.0);
592
cairo_set_source_rgba (cr, 0.7, 0.9, 1.0, 0.3);
593
cairo_rectangle ( cr, x, y, w, h);
599
/* Make transparent/opaque */
600
if(cv->transparent != m_priv->transparent)
602
guchar r, g, b, a = 0xFF;
604
m_priv->transparent = cv->transparent;
605
gp_selection_get_bg_color_rgb ( &r, &g, &b );
610
gp_image_make_color_transparent ( m_priv->image, r, g, b, a );
614
/* Had to add this here because the selection
615
* was being erased when changing tools. Don't
616
* know if this was by design or not, but just
617
* doesn't seem right. This is just temporary
620
if(GDK_IS_DRAWABLE(gdkd)){
621
gp_image_draw ( m_priv->image,
627
gp_image_draw ( m_priv->image,
635
if ( m_priv->show_borders )
637
draw_borders ( cv->drawing, gc );
641
gdk_draw_rectangle ( cv->drawing, gc, FALSE,
646
g_object_unref ( gc );
651
/* Get background color's rgb values */
652
static gboolean gp_selection_get_bg_color_rgb(guchar *r, guchar *g, guchar *b)
656
cv = cv_get_canvas ();
657
if((cv) && (r) && (g) && (b))
661
GdkColormap* colormap = gdk_colormap_get_system();
663
gdk_gc_get_values (cv->gc_bg, &values);
664
gdk_colormap_query_color(colormap, values.foreground.pixel, &color);
666
*r = color.red >>= 8;
667
*g = color.green >>= 8;
668
*b = color.blue >>= 8;
676
/* See if there is a selection image */
677
gboolean gp_selection_query(void)
688
void gp_selection_invert(void)
692
gp_image_invert_colors ( m_priv->image);
697
void gp_selection_flip(gboolean flip)
701
gp_image_flip ( m_priv->image, flip );
706
void gp_selection_rotate(GdkPixbufRotation angle)
714
gp_canvas *cv = cv_get_canvas ();
716
gp_image_rotate ( m_priv->image, angle );
717
pixbuf = gp_image_get_pixbuf(m_priv->image);
719
clipbox = &m_priv->boxes[SEL_CLIPBOX];
720
s.x = MIN(clipbox->p0.x,clipbox->p1.x);
721
s.y = MIN(clipbox->p0.y,clipbox->p1.y);
722
e.x = gdk_pixbuf_get_width(pixbuf);
723
e.y = gdk_pixbuf_get_height(pixbuf);
727
/* -1 to allow for border width */
728
clipbox->p1.x = clipbox->p0.x + e.x - 1;
729
clipbox->p1.y = clipbox->p0.y + e.y - 1;
733
g_object_unref ( m_priv->image );
734
m_priv->image = gp_image_new_from_pixbuf ( pixbuf, TRUE );
736
g_object_unref(pixbuf);
741
/* Return a copy of selection's image pixbuf */
742
GdkPixbuf *gp_selection_get_pixbuf(void)
746
return gp_image_get_pixbuf(m_priv->image);
753
/* Clear selection. Does not clear
754
* as in destroying m_priv.
755
* draw == TRUE to draw image
757
void gp_selection_draw_and_clear (gboolean draw)
759
GdkPoint pt = {0, 0};
760
gp_canvas *cv = cv_get_canvas ();
762
g_return_if_fail( gp_selection_query() );
764
pt.x = m_priv->sp.x - 1;
767
if(!draw){ g_object_unref (m_priv->image) ; m_priv->image = NULL ; }
769
gp_selection_set_floating ( TRUE );
770
gp_selection_set_active ( FALSE );
771
gp_selection_clipbox_set_start_point ( &pt );
772
gp_selection_clipbox_set_end_point ( &pt );
773
gp_selection_set_active ( TRUE );
775
gp_selection_set_borders ( FALSE );
776
gtk_widget_queue_draw ( cv->widget );