2 * This file is part of maemopad+
5 * This software is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
10 * This software is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this software; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 #include <ui/interface.h>
23 #include <ui/sketchwidget.h>
25 #include <hildon/hildon-helper.h>
28 * SketchWidget's "Privates"
30 void calc_rect(GdkRectangle
*res
, gint x1
, gint y1
, gint x2
, gint y2
, gint bs
);
31 void sketchwidget_init_backpixmaps(SketchWidget
* sk
);
32 void sketch_draw_brush(GtkWidget
* widget
, gdouble x
, gdouble y
, gdouble pressure
, SketchWidget
* sk
);
33 guint
sketch_calc_brush_size_from_pressure(gdouble pressure
, SketchWidget
* sk
);
34 gboolean
sketch_teststupid(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
);
35 gboolean
sketch_button_release(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
);
36 gboolean
sketch_button_press(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
);
37 gboolean
sketch_motion_notify(GtkWidget
* widget
, GdkEventMotion
* event
, SketchWidget
* sk
);
38 gboolean
sketch_configure(GtkWidget
* widget
, GdkEventConfigure
* event
, SketchWidget
* sk
);
39 gboolean
sketch_expose(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
);
40 void sketchwidget_invoke_undocallback(SketchWidget
* sk
, gboolean st
);
41 void sketchwidget_invoke_redocallback(SketchWidget
* sk
, gboolean st
);
42 void sketch_calc_pressurecolors(SketchWidget
*sk
);
44 void sketch_calc_pressurecolors(SketchWidget
*sk
)
46 guint pc
= PRESSURE_COLORS
+ 1;
47 gdouble step
= (PRESSURE_COLOR_MAX
- PRESSURE_MIN
) / PRESSURE_COLORS
;
56 /*if (maxr==0 && maxg==0 && maxb==0) maxr=maxg=maxb=32768;*/
57 if (maxr
<sk
->brush_color
.red
||
58 maxg
<sk
->brush_color
.green
||
59 maxb
<sk
->brush_color
.blue
)
66 guint stepr
= (maxr
- sk
->brush_color
.red
) / pc
;
67 guint stepg
= (maxg
- sk
->brush_color
.green
) / pc
;
68 guint stepb
= (maxb
- sk
->brush_color
.blue
) / pc
;
70 #ifdef PRESSURECOLORS_DEBUG
71 fprintf(stderr
, "step=%f stepr=%d stepg=%d stepb=%d\n", step
, stepr
, stepg
, stepb
);
74 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
77 for(i
=0;i
<PRESSURE_COLORS
;i
++)
79 sk
->brush_colors
[i
].red
=sk
->brush_color
.red
+ ((i
+1)*stepr
);
80 sk
->brush_colors
[i
].green
=sk
->brush_color
.green
+ ((i
+1)*stepg
);
81 sk
->brush_colors
[i
].blue
=sk
->brush_color
.blue
+ ((i
+1)*stepb
);
82 sk
->brush_colors_pressure_index
[i
]=PRESSURE_MIN
+ ((PRESSURE_COLORS
-i
-1)*step
);
83 if (sk
->brush_colors_pressure_index
[i
]>PRESSURE_MAX
) sk
->brush_colors_pressure_index
[i
]=PRESSURE_MAX
;
84 gdk_color_alloc(colormap
, &sk
->brush_colors
[i
]);
86 #ifdef PRESSURECOLORS_DEBUG
87 fprintf(stderr
, "i=%d - p=%f r=%d g=%d b=%d\n", i
, sk
->brush_colors_pressure_index
[i
], sk
->brush_colors
[i
].red
, sk
->brush_colors
[i
].green
, sk
->brush_colors
[i
].blue
);
92 GdkColor
sketch_calc_brush_color_from_pressure(gdouble pressure
, SketchWidget
* sk
)
94 GdkColor ret
=sk
->brush_color
;
97 for(i
=PRESSURE_COLORS
-1;i
>=0;i
--)
99 if (pressure
<=sk
->brush_colors_pressure_index
[i
])
101 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_colors
[i
]);
102 ret
=sk
->brush_colors
[i
];
103 #ifdef PRESSURECOLORS_DEBUG
104 fprintf(stderr
, "pressureindex is %d (pressure=%f)\n", i
, pressure
);
113 void sketchwidget_invoke_undocallback(SketchWidget
* sk
, gboolean st
)
115 if (sk
->callback_undotoggle
!= NULL
)
116 (sk
->callback_undotoggle
) (sk
, st
, sk
->callback_undotoggle_data
);
119 void sketchwidget_invoke_redocallback(SketchWidget
* sk
, gboolean st
)
121 if (sk
->callback_redotoggle
!= NULL
)
122 (sk
->callback_redotoggle
) (sk
, st
, sk
->callback_redotoggle_data
);
126 * these two functions are tested and they work
128 void tile_getcoords(guint tileid
, guint
* x
, guint
* y
)
130 guint t
= tileid
% TILES_ROWSTRIDE
;
132 *y
= (tileid
- t
) / TILES_ROWSTRIDE
* TILE_SIZE
;
136 guint
tile_getid(guint x
, guint y
)
138 guint tx
= x
% TILE_SIZE
;
139 guint xbase
= (x
- tx
) / TILE_SIZE
;
141 guint ty
= y
% TILE_SIZE
;
142 guint ybase
= (y
- ty
) / TILE_SIZE
;
144 return (ybase
* TILES_ROWSTRIDE
+ xbase
);
150 void sketchundo_free_list(GList
* ulist
)
156 SketchWidgetUndo
*un
= li
->data
;
160 GSList
*tl
= un
->tileList
;
164 if (tl
->data
!= NULL
)
166 SketchWidgetTile
*ti
= (SketchWidgetTile
*) tl
->data
;
170 if (ti
->tiledata
) { gdk_pixmap_unref(ti
->tiledata
); ti
->tiledata
=NULL
; }
171 if (ti
->tiledata_new
) { gdk_pixmap_unref(ti
->tiledata_new
); ti
->tiledata_new
=NULL
; }
175 tl
= g_slist_next(tl
);
177 g_slist_free(un
->tileList
);
179 li
= g_list_next(li
);
181 /*fixme: this one eventually causes a crash (in g_list_length) instead we keep the list for now*/
188 * call everytime mouse is pressed
190 void sketchundo_new(SketchWidget
* sk
)
192 if (sk
->undocurbuffer
!= NULL
) return; /*assert?*/
194 SketchWidgetUndo
*su
= g_new0(SketchWidgetUndo
, 1);
196 su
->tileList
= NULL
; /*unnecessary */
197 sk
->undocurbuffer
= su
;
199 fprintf(stderr, "UNDO: new\n");
204 * call everytime mouse is released
206 void sketchundo_commit(SketchWidget
* sk
)
208 sketchwidget_set_edited(sk
, TRUE
);
210 if (sk
->undocurbuffer
==NULL
) /*sometimes happens (esp on gregale) with scrolledwindow expose stupid hack enabled, should be fixed though*/
212 fprintf(stderr
, "[sketchundo] undocurbuffer is null!\n");
216 /* g_assert(sk->undocurbuffer != NULL);*/
219 * free structs ahead of undocurrent here
221 if (sk
->undocurrent
> 0)
224 GList
*startsnip
= sk
->undolist
;
225 GList
*endsnip
= g_list_nth(sk
->undolist
, sk
->undocurrent
);
229 sk
->undolist
=endsnip
;
230 if (endsnip
->prev
!=NULL
) (endsnip
->prev
)->next
=NULL
;
237 fixme:crash--see comment in func. probably due to bad "snipping" somewhere above
239 sketchundo_free_list(startsnip
);
245 * check for UNDO_LEVELS and free structs here
247 guint llen
= g_list_length(sk
->undolist
);
249 if (llen
>= (UNDO_LEVELS
- 1))
250 { /*we will add (erm, prepend is the right word) one more so we check for one less */
251 GList
*startsnip
= g_list_nth(sk
->undolist
, UNDO_LEVELS
- 1);
253 if (startsnip
!= NULL
&& startsnip
->prev
!= NULL
)
255 /* cut the portion off and free it */
256 (startsnip
->prev
)->next
= NULL
;
257 sketchundo_free_list(startsnip
);
262 GSList
*tl
=sk
->undocurbuffer
->tileList
;
265 SketchWidgetTile
*ti
= (SketchWidgetTile
*) tl
->data
;
269 tile_getcoords(ti
->tileid
, &sx
, &sy
);
270 ti
->tiledata_new
= gdk_pixmap_new(sk
->drawingarea
->window
, TILE_SIZE
, TILE_SIZE
, -1);
271 gdk_draw_drawable(ti
->tiledata_new
, sk
->drawingarea
->style
->white_gc
, sk
->pixmap
, sx
, sy
, 0, 0, TILE_SIZE
, TILE_SIZE
);
276 sk
->undolist
= g_list_prepend(sk
->undolist
, sk
->undocurbuffer
);
277 sk
->undocurbuffer
= NULL
;
278 sk
->undocurrent
= 0; /*reset our position */
280 sketchwidget_invoke_undocallback(sk
, TRUE
);
281 sketchwidget_invoke_redocallback(sk
, FALSE
);
283 fprintf(stderr, "UNDO: commit\n");
290 void sketchundo_savetile(SketchWidget
* sk
, guint tileid
)
292 if (tileid
> TILES_X
* TILES_Y
)
293 return; /*FIXME:ugly, to keep drawing off the canvas */
295 if (sk
->undocurbuffer
->saved_tiles
[tileid
] == 1) /*dupe-check*/
300 tile_getcoords(tileid
, &sx
, &sy
);
303 * fprintf(stderr, "savetile:%d coords:%d,%d\n", tileid, sx, sy);
306 SketchWidgetTile
*t
= g_new0(SketchWidgetTile
, 1);
309 t
->tiledata
= gdk_pixmap_new(sk
->drawingarea
->window
, TILE_SIZE
, TILE_SIZE
, -1);
310 t
->tiledata_new
= NULL
;
312 gdk_draw_drawable(t
->tiledata
, sk
->drawingarea
->style
->white_gc
, sk
->pixmap
, sx
, sy
, 0, 0, TILE_SIZE
, TILE_SIZE
);
314 sk
->undocurbuffer
->tileList
= g_slist_prepend(sk
->undocurbuffer
->tileList
, t
);
316 sk
->undocurbuffer
->saved_tiles
[tileid
] = 1;
320 * call for each pixel before it's drawn
322 void sketchundo_drawpoint(SketchWidget
* sk
, guint px
, guint py
)
324 g_assert(sk
->undocurbuffer
!= NULL
);
326 guint tileid
= tile_getid(px
, py
);
328 sketchundo_savetile(sk
, tileid
);
332 * call for each rect before it's drawn
334 void sketchundo_drawrect(SketchWidget
* sk
, guint rx
, guint ry
, guint w
, guint h
)
336 g_assert(sk
->undocurbuffer
!= NULL
);
341 for(j
= ry
; j
<= ry
+ h
+ TILE_SIZE
; j
+= TILE_SIZE
)
343 guint x_tile_start
= tile_getid(rx
, j
);
344 guint x_tile_end
= tile_getid(rx
+ w
/*+TILE_SIZE */ , j
);
346 for(i
= x_tile_start
; i
<= x_tile_end
; i
++)
348 sketchundo_savetile(sk
, i
);
355 guint tileid
=tile_getid(rx
+j
, ry
+i
);
356 sketchundo_savetile(sk
, tileid
);
361 void sketchundo_drawtiles(SketchWidget
* sk
, SketchWidgetUndo
* un
, gboolean isredo
)
364 GdkGC *tmpgc = gdk_gc_new(sk->drawingarea->window);
365 gdk_gc_copy(tmpgc, sk->drawingarea->style->white_gc);
366 gdk_gc_set_function(tmpgc, GDK_AND_REVERSE);
368 GSList
*tl
= un
->tileList
;
372 SketchWidgetTile
*t
= (SketchWidgetTile
*) (tl
->data
);
374 if (isredo
==TRUE
) ourpix
=t
->tiledata_new
;
375 else ourpix
=t
->tiledata
;
381 tile_getcoords(t
->tileid
, &x
, &y
);
383 gdk_draw_drawable(sk
->pixmap
, /*tmpgc*/sk
->drawingarea
->style
->white_gc
,
384 ourpix
, 0, 0, x
, y
, TILE_SIZE
, TILE_SIZE
);
388 fprintf(stderr
, "NOTILEDATA! %d\n", t
->tileid
);
390 tl
= g_slist_next(tl
);
393 g_object_unref(tmpgc);
397 gboolean
sketchwidget_undo(SketchWidget
* sk
)
399 g_assert(sk
!= NULL
);
401 guint llen
= g_list_length(sk
->undolist
);
403 fprintf(stderr, "UNDO listlen is %d undocurrent is %d\n", llen, sk->undocurrent);
405 if (llen
<= (sk
->undocurrent
))
407 sketchwidget_invoke_undocallback(sk
, FALSE
);
411 SketchWidgetUndo
*un
= g_list_nth_data(sk
->undolist
, sk
->undocurrent
);
418 sketchundo_drawtiles(sk
, un
, FALSE
);
419 gtk_widget_queue_draw(sk
->drawingarea
);
421 fprintf(stderr, "UNDO undocurrent now is %d\n", sk->undocurrent);
423 if (llen
== sk
->undocurrent
)
424 sketchwidget_invoke_undocallback(sk
, FALSE
);
425 sketchwidget_invoke_redocallback(sk
, TRUE
);
430 gboolean
sketchwidget_redo(SketchWidget
* sk
)
432 g_assert(sk
!= NULL
);
434 if (sk
->undocurrent
< 1)
436 sketchwidget_invoke_redocallback(sk
, FALSE
);
440 fprintf(stderr, "REDO listlen is %d undocurrent is %d\n", g_list_length(sk->undolist), sk->undocurrent);
443 SketchWidgetUndo
*un
= g_list_nth_data(sk
->undolist
, sk
->undocurrent
- 1);
447 fprintf(stderr
, "REDO ERR!\n");
453 sketchundo_drawtiles(sk
, un
, TRUE
);
454 gtk_widget_queue_draw(sk
->drawingarea
);
456 fprintf(stderr, "REDO undocurrent now is %d\n", sk->undocurrent);
458 if (sk
->undocurrent
< 1)
459 sketchwidget_invoke_redocallback(sk
, FALSE
);
460 sketchwidget_invoke_undocallback(sk
, TRUE
);
465 void sketchwidget_wipe_undo(SketchWidget
* sk
)
467 if (sk
->undocurbuffer
)
468 sketchundo_commit(sk
); /*get rid of undocurbuffer */
471 sketchundo_free_list(sk
->undolist
);
474 sketchwidget_invoke_undocallback(sk
, FALSE
);
475 sketchwidget_invoke_redocallback(sk
, FALSE
);
478 void sketchwidget_set_fingercallback(SketchWidget
* sk
, void *func
, gpointer data
)
480 g_assert(sk
!= NULL
);
481 sk
->callback_finger
= func
;
482 sk
->callback_finger_data
= data
;
485 void sketchwidget_set_undocallback(SketchWidget
* sk
, void *func
, gpointer data
)
487 g_assert(sk
!= NULL
);
488 sk
->callback_undotoggle
= func
;
489 sk
->callback_undotoggle_data
= data
;
492 void sketchwidget_set_redocallback(SketchWidget
* sk
, void *func
, gpointer data
)
494 g_assert(sk
!= NULL
);
495 sk
->callback_redotoggle
= func
;
496 sk
->callback_redotoggle_data
= data
;
499 void sketchwidget_clear_real(SketchWidget
* sk
)
501 gdk_draw_rectangle(sk
->pixmap
, sk
->drawingarea
->style
->white_gc
, TRUE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
504 GtkWidget
*sketchwidget_get_drawingarea(SketchWidget
* sk
)
506 g_assert(sk
!= NULL
);
507 return (sk
->drawingarea
);
510 GtkWidget
*sketchwidget_get_mainwidget(SketchWidget
* sk
)
512 g_assert(sk
!= NULL
);
513 return (sk
->scrolledwindow
);
516 GdkPixbuf
*sketchwidget_trim_image(GdkPixbuf
* pixbuf
, guint totalw
, guint totalh
, double *w
, double *h
, gboolean doTopLeft
)
518 guint i
, j
, startx
= 0, starty
= 0, endx
, endy
;
523 guint newendy
= endy
, newendx
= endx
;
524 int rowstride
= gdk_pixbuf_get_rowstride(pixbuf
);
525 int nchan
= gdk_pixbuf_get_n_channels(pixbuf
);
528 pixels
= gdk_pixbuf_get_pixels(pixbuf
);
531 * fprintf(stderr, "nchan=%d\n", nchan);
534 gboolean dobr
= FALSE
;
537 for(i
= 0; i
< endy
; i
++)
539 int yoff
= i
* rowstride
;
541 for(j
= 0; j
< endx
; j
++)
543 p
= pixels
+ yoff
+ (j
* nchan
);
544 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
556 for(i
= endy
- 1; i
>= starty
; i
--)
558 int yoff
= i
* rowstride
;
560 for(j
= 0; j
< endx
; j
++)
562 p
= pixels
+ yoff
+ (j
* nchan
);
563 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
576 for(i
= 0; i
< endx
; i
++)
580 for(j
= starty
; j
< endy
; j
++)
582 p
= pixels
+ (j
* rowstride
) + ni
;
583 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
587 * fprintf(stderr, "S x=%d, y=%d, %d %d %d\n", i, j, p[0], p[1], p[2]);
599 for(i
= endx
- 1; i
>= startx
; i
--)
603 for(j
= starty
; j
< endy
; j
++)
605 p
= pixels
+ (j
* rowstride
) + ni
;
606 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
610 * fprintf(stderr, "E x=%d, y=%d, %d %d %d\n", i, j, p[0], p[1], p[2]);
622 * fprintf(stderr, "start:%dx%d end:%dx%d\n", startx, starty, newendx, newendy);
625 *w
= newendx
- startx
;
626 *h
= newendy
- starty
;
629 gdk_pixbuf_unref(pixbuf
);
633 GdkPixbuf
*pixbuf2
= gdk_pixbuf_new_subpixbuf(pixbuf
, startx
, starty
, *w
, *h
);
637 void sketchwidget_clear(SketchWidget
* sk
)
640 sketchundo_drawrect(sk
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
641 sketchwidget_clear_real(sk
);
642 sketchundo_commit(sk
);
643 gtk_widget_queue_draw(sk
->drawingarea
);
646 gboolean
sketchwidget_cut(SketchWidget
* sk
, GtkClipboard
* clippy
)
648 gboolean ret
= sketchwidget_copy(sk
, clippy
);
652 sketchwidget_clear(sk
);
656 gboolean
sketchwidget_copy(SketchWidget
* sk
, GtkClipboard
* clippy
)
658 g_assert(sk
!= NULL
);
660 gboolean ret
= FALSE
;
662 GdkPixbuf
*pixbuf
= gdk_pixbuf_get_from_drawable(NULL
, GDK_DRAWABLE(sk
->pixmap
), NULL
,
665 sk
->drawingarea
->allocation
.width
,
666 sk
->drawingarea
->allocation
.height
);
668 if (pixbuf
!= NULL
&& GDK_IS_PIXBUF(pixbuf
))
671 GdkPixbuf
*pixbuf2
= sketchwidget_trim_image(pixbuf
,
672 sk
->drawingarea
->allocation
.width
,
673 sk
->drawingarea
->allocation
.height
, &w
,
676 if (pixbuf2
&& GDK_IS_PIXBUF(pixbuf2
))
680 GdkPixbuf
*pixbuf3
= gdk_pixbuf_copy(pixbuf2
);
681 gtk_clipboard_set_image(clippy
, pixbuf3
);
682 g_object_unref(pixbuf3
);
685 g_object_unref(pixbuf2
);
691 gboolean
sketchwidget_paste(SketchWidget
* sk
, GtkClipboard
* clippy
)
693 g_assert(sk
!= NULL
);
695 gboolean ret
= FALSE
;
697 GdkPixbuf
*pixbuf
= gtk_clipboard_wait_for_image(clippy
);
699 if (pixbuf
!= NULL
&& GDK_IS_PIXBUF(pixbuf
))
701 int w
= gdk_pixbuf_get_width(pixbuf
);
702 int h
= gdk_pixbuf_get_height(pixbuf
);
704 if (w
> sk
->drawingarea
->allocation
.width
)
705 w
= sk
->drawingarea
->allocation
.width
;
706 if (h
> sk
->drawingarea
->allocation
.height
)
707 h
= sk
->drawingarea
->allocation
.height
;
711 sketchundo_drawrect(sk
, 0, 0, w
, h
);
712 gdk_draw_pixbuf(GDK_DRAWABLE(sk
->pixmap
), NULL
, pixbuf
, 0, 0, 0, 0, w
, h
, GDK_RGB_DITHER_NONE
, 0, 0);
713 sketchundo_commit(sk
);
714 gtk_widget_queue_draw(sk
->drawingarea
);
717 g_object_unref(pixbuf
);
722 GdkPixmap
*sketchwidget_get_Pixmap(SketchWidget
* sk
)
724 g_assert(sk
!= NULL
);
725 g_object_ref(sk
->pixmap
);
729 gboolean
sketchwidget_get_edited(SketchWidget
* sk
)
731 g_assert(sk
!= NULL
);
732 return (sk
->is_edited
);
735 void sketchwidget_set_edited(SketchWidget
* sk
, gboolean status
)
737 g_assert(sk
!= NULL
);
738 sk
->is_edited
= status
;
742 * Creates and initialises a main_view
744 SketchWidget
*sketchwidget_new(gint sizex
, gint sizey
, gboolean border
)
748 * Zero memory with g_new0
750 SketchWidget
*result
= g_new0(SketchWidget
, 1);
752 sketchwidget_set_edited(result
, FALSE
);
753 sketchwidget_set_brushsize(result
, 0);
755 result
->backstyle_currentimage
= SKETCHBACK_UNSET
;
756 result
->backstyle
= SKETCHBACK_NONE
;
758 result
->shape
= SKETCHSHAPE_FREEHAND
;
759 result
->pressed
= FALSE
;
760 result
->fillmode
= FALSE
;
762 result
->border
= border
;
763 result
->scrolledwindow
= gtk_scrolled_window_new(NULL
, NULL
);
764 #ifdef MAEMOPADPLUS_FINGER_FRIENDLY
765 hildon_helper_set_thumb_scrollbar(result
->scrolledwindow
, TRUE
);
767 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(result
->scrolledwindow
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
769 result
->drawingarea
= gtk_drawing_area_new();
770 gtk_widget_set_size_request(result
->drawingarea
, sizex
, sizey
);
775 result
->brush_color
.red
= 0;
776 result
->brush_color
.green
= 0;
777 result
->brush_color
.blue
= 0;
779 result
->pressuresensitivity
= FALSE
;
781 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(result
->scrolledwindow
), result
->drawingarea
);
783 g_signal_connect(G_OBJECT(result
->drawingarea
), "expose_event", G_CALLBACK(sketch_expose
), result
);
784 g_signal_connect(G_OBJECT(result
->drawingarea
), "configure_event", G_CALLBACK(sketch_configure
), result
);
785 g_signal_connect(G_OBJECT(result
->drawingarea
), "motion_notify_event", G_CALLBACK(sketch_motion_notify
), result
);
786 g_signal_connect(G_OBJECT(result
->drawingarea
), "button_press_event", G_CALLBACK(sketch_button_press
), result
);
787 g_signal_connect(G_OBJECT(result
->drawingarea
), "button_release_event", G_CALLBACK(sketch_button_release
), result
);
789 gtk_widget_set_events(result
->drawingarea
, GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
/* | GDK_ALL_EVENTS_MASK*/);
791 g_signal_connect(G_OBJECT(result
->scrolledwindow
), "expose_event", G_CALLBACK(sketch_teststupid
), result
);
792 gtk_widget_set_extension_events(result
->drawingarea
, GDK_EXTENSION_EVENTS_CURSOR
); /* root of all evil */
794 gtk_widget_show(result
->drawingarea
);
795 gtk_widget_hide(result
->scrolledwindow
);
797 result
->undocurrent
= 0;
798 result
->undolist
= NULL
;
804 * clean up the allocated memory
806 void sketchwidget_destroy(SketchWidget
* sk
)
808 g_assert(sk
!= NULL
);
813 g_list_free(sk
->undolist
);
815 g_object_unref(sk
->pixmap
);
817 g_object_unref(sk
->backpixmap
);
818 for(i
= 0; i
< SKETCHBACK_COUNT
; i
++)
819 if (sk
->backpixmaps
[i
])
820 g_object_unref(sk
->backpixmaps
[i
]);
823 gdk_gc_unref(sk
->gc
);
826 * FIXME, segfault at GTK_IS_WIDGET
827 * if (sk->scrolledwindow && GTK_IS_WIDGET(sk->scrolledwindow)) gtk_widget_destroy(sk->scrolledwindow);
832 void sketchwidget_set_shape(SketchWidget
* sk
, sketchShape sp
)
834 g_assert(sk
!= NULL
);
839 void sketchwidget_set_fillmode(SketchWidget
* sk
, gboolean filled
)
841 g_assert(sk
!= NULL
);
843 sk
->fillmode
= filled
;
846 void sketchwidget_set_shift(SketchWidget
* sk
, gboolean shift
)
848 g_assert(sk
!= NULL
);
850 sk
->shiftmode
= shift
;
853 gboolean
sketchwidget_get_shift(SketchWidget
* sk
)
855 g_assert(sk
!= NULL
);
857 return(sk
->shiftmode
);
861 void sketchwidget_set_brushcolor(SketchWidget
* sk
, GdkColor col
)
863 g_assert(sk
!= NULL
);
865 if (sk
->drawingarea
!= NULL
)
867 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
869 gdk_color_alloc(colormap
, &col
);
871 sk
->brush_color
= col
;
872 sketch_calc_pressurecolors(sk
);
875 gdk_gc_set_foreground(sk
->gc
, &col
);
878 GdkColor
sketchwidget_get_brushcolor(SketchWidget
* sk
)
880 g_assert(sk
!= NULL
);
882 return (sk
->brush_color
);
885 void sketchwidget_set_backstyle(SketchWidget
* sk
, sketchBack style
)
887 g_assert(sk
!= NULL
);
889 sk
->backstyle
= style
;
890 gtk_widget_queue_draw(sk
->drawingarea
);
893 if (sk
->backpixmap
== NULL
)
894 return; /*our widget not configured yet, configure will call this again */
896 if (sk
->backstyle
== sk
->backstyle_currentimage
)
899 sk
->backstyle_currentimage
= sk
->backstyle
;
901 gdk_draw_rectangle(sk
->backpixmap
, sk
->drawingarea
->style
->white_gc
, TRUE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
903 gdk_gc_unref(sk
->backgc
);
904 sk
->backgc
= gdk_gc_new(GDK_DRAWABLE(sk
->backpixmap
));
906 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
908 if (style
== SKETCHBACK_LINES
)
913 tmpcol
.red
= 0x40 * 256;
914 tmpcol
.green
= 0xA0 * 256;
915 tmpcol
.blue
= 0xFF * 256;
916 gdk_color_alloc(colormap
, &tmpcol
);
917 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
918 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
920 for(i
= BACKGRAPH_LINE_HEIGHT
; i
< sk
->drawingarea
->allocation
.height
; i
+= BACKGRAPH_LINE_HEIGHT
)
922 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
925 tmpcol
.red
= 0xFF * 256;
926 tmpcol
.green
= 0x00 * 256;
927 tmpcol
.blue
= 0x80 * 256;
928 gdk_color_alloc(colormap
, &tmpcol
);
929 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
930 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_MARGIN_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
931 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, BACKGRAPH_LINE_MARGIN
, 0, BACKGRAPH_LINE_MARGIN
, sk
->drawingarea
->allocation
.height
);
933 else if (style
== SKETCHBACK_GRAPH
)
938 tmpcol
.red
= 0x7F * 256;
939 tmpcol
.green
= 0xB0 * 256;
940 tmpcol
.blue
= 0xFF * 256;
941 gdk_color_alloc(colormap
, &tmpcol
);
942 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
943 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_GRAPH_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
945 for(i
= BACKGRAPH_GRAPH_WIDTH
; i
< sk
->drawingarea
->allocation
.height
; i
+= BACKGRAPH_GRAPH_WIDTH
)
947 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
949 for(i
= BACKGRAPH_GRAPH_WIDTH
; i
< sk
->drawingarea
->allocation
.width
; i
+= BACKGRAPH_GRAPH_WIDTH
)
951 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, i
, 0, i
, sk
->drawingarea
->allocation
.height
);
954 else if (style
== SKETCHBACK_NONE
)
959 tmpcol
.red
= 0x7F * 256;
960 tmpcol
.green
= 0xB0 * 256;
961 tmpcol
.blue
= 0xFF * 256;
962 gdk_color_alloc(colormap
, &tmpcol
);
963 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
964 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_GRAPH_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
966 for(i
= 0; i
< sk
->drawingarea
->allocation
.height
; i
+= TILE_SIZE
)
968 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
970 for(i
= 0; i
< sk
->drawingarea
->allocation
.width
; i
+= TILE_SIZE
)
972 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, i
, 0, i
, sk
->drawingarea
->allocation
.height
);
976 if (sk
->border
== TRUE
)
980 tmpcol
.red
= 192 * 256;
981 tmpcol
.green
= 192 * 256;
982 tmpcol
.blue
= 192 * 256;
983 gdk_color_alloc(colormap
, &tmpcol
);
984 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
985 gdk_gc_set_line_attributes(sk
->backgc
, 2, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
987 gdk_draw_rectangle(sk
->backpixmap
, sk
->backgc
, FALSE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
990 gtk_widget_queue_draw(sk
->drawingarea
);
994 void sketchwidget_init_backpixmaps(SketchWidget
* sk
)
996 g_assert(sk
!= NULL
);
1000 sk
->backpixmapheights
[0] = 0; /*or TILE_SIZE*/
1001 sk
->backpixmapheights
[1] = BACKGRAPH_LINE_HEIGHT
+ 1;
1002 sk
->backpixmapheights
[2] = BACKGRAPH_GRAPH_WIDTH
;
1005 gdk_gc_unref(sk
->backgc
);
1007 for(i
= 0; i
< SKETCHBACK_COUNT
; i
++)
1009 if (sk
->backpixmapheights
[i
] == 0)
1012 if (sk
->backpixmaps
[i
] != NULL
)
1013 g_object_unref(sk
->backpixmaps
[i
]);
1015 sk
->backpixmaps
[i
] = gdk_pixmap_new(sk
->drawingarea
->window
, sk
->drawingarea
->allocation
.width
, sk
->backpixmapheights
[i
], -1);
1016 gdk_draw_rectangle(sk
->backpixmaps
[i
], sk
->drawingarea
->style
->white_gc
, TRUE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->backpixmapheights
[i
]);
1018 if (sk
->backgc
== NULL
)
1019 sk
->backgc
= gdk_gc_new(GDK_DRAWABLE(sk
->backpixmaps
[i
]));
1022 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
1027 tmpcol
.red
= 0x40 * 256;
1028 tmpcol
.green
= 0xA0 * 256;
1029 tmpcol
.blue
= 0xFF * 256;
1030 gdk_color_alloc(colormap
, &tmpcol
);
1031 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
1032 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1034 for(i
= BACKGRAPH_LINE_HEIGHT
; i
<= sk
->backpixmapheights
[SKETCHBACK_LINES
]; i
+= BACKGRAPH_LINE_HEIGHT
)
1036 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_LINES
]), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
1039 tmpcol
.red
= 0xFF * 256;
1040 tmpcol
.green
= 0x00 * 256;
1041 tmpcol
.blue
= 0x80 * 256;
1042 gdk_color_alloc(colormap
, &tmpcol
);
1043 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
1044 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_MARGIN_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1045 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_LINES
]), sk
->backgc
, BACKGRAPH_LINE_MARGIN
, 0, BACKGRAPH_LINE_MARGIN
, sk
->backpixmapheights
[SKETCHBACK_LINES
]);
1048 tmpcol
.red
= 0x7F * 256;
1049 tmpcol
.green
= 0xB0 * 256;
1050 tmpcol
.blue
= 0xFF * 256;
1051 gdk_color_alloc(colormap
, &tmpcol
);
1052 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
1053 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_GRAPH_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1055 /* for(i = BACKGRAPH_GRAPH_WIDTH; i <= sk->backpixmapheights[SKETCHBACK_GRAPH]; i += BACKGRAPH_GRAPH_WIDTH)*/
1056 for(i
= 0; i
< sk
->backpixmapheights
[SKETCHBACK_GRAPH
]; i
+= BACKGRAPH_GRAPH_WIDTH
)
1058 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_GRAPH
]), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
1060 /* for(i = BACKGRAPH_GRAPH_WIDTH; i < sk->drawingarea->allocation.width; i += BACKGRAPH_GRAPH_WIDTH)*/
1061 for(i
= 0; i
< sk
->drawingarea
->allocation
.width
; i
+= BACKGRAPH_GRAPH_WIDTH
)
1063 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_GRAPH
]), sk
->backgc
, i
, 0, i
, sk
->backpixmapheights
[SKETCHBACK_GRAPH
]);
1069 #define BACKGRAPH_DOT_WIDTH 32
1070 tmpcol.red = 0xC0 * 256;
1071 tmpcol.green = 0xC0 * 256;
1072 tmpcol.blue = 0xC0 * 256;
1073 gdk_color_alloc(colormap, &tmpcol);
1074 gdk_gc_set_foreground(sk->backgc, &tmpcol);
1076 for(i = 0; i < sk->backpixmapheights[SKETCHBACK_NONE]; i += BACKGRAPH_DOT_WIDTH)
1077 for(j = 0; j < sk->drawingarea->allocation.width; j += BACKGRAPH_DOT_WIDTH)
1079 gdk_draw_point(GDK_DRAWABLE(sk->backpixmaps[SKETCHBACK_NONE]), sk->backgc, i, j);
1083 tmpcol.red = 0x7F * 256;
1084 tmpcol.green = 0xB0 * 256;
1085 tmpcol.blue = 0xFF * 256;
1086 gdk_color_alloc(colormap, &tmpcol);
1087 gdk_gc_set_foreground(sk->backgc, &tmpcol);
1088 gdk_gc_set_line_attributes(sk->backgc, BACKGRAPH_GRAPH_SIZE, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
1090 for(i = 0; i < sk->backpixmapheights[SKETCHBACK_NONE]; i += TILE_SIZE)
1092 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[SKETCHBACK_NONE]), sk->backgc, 0, i, sk->drawingarea->allocation.width, i);
1094 for(i = 0; i < sk->drawingarea->allocation.width; i += TILE_SIZE)
1096 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[SKETCHBACK_NONE]), sk->backgc, i, 0, i, sk->backpixmapheights[SKETCHBACK_NONE]);
1101 /*important:sk->backgc should be configured for later use in expose()*/
1102 if (sk
->border
==TRUE
)
1105 bordercol
.red
= 192 * 256;
1106 bordercol
.green
= 192 * 256;
1107 bordercol
.blue
= 192 * 256;
1108 gdk_color_alloc(colormap
, &bordercol
);
1110 gdk_gc_set_foreground(sk
->backgc
, &bordercol
);
1111 gdk_gc_set_line_attributes(sk
->backgc
, 2, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1113 for(i = 0; i < SKETCHBACK_COUNT; i++)
1115 if (sk->backpixmapheights[i] == 0)
1118 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[i]), sk->backgc, 0, 0, 0, sk->backpixmapheights[i]);
1119 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[i]), sk->backgc, sk->drawingarea->allocation.width, 0, sk->drawingarea->allocation.width, sk->backpixmapheights[i]);
1126 void sketchwidget_set_brushsize(SketchWidget
* sk
, guint bsize
)
1128 g_assert(sk
!= NULL
);
1134 sk
->brush_radius
= 0;
1139 sk
->brush_radius
= bsize
/ 2;
1140 if (sk
->brush_radius
< 1)
1141 sk
->brush_radius
= 1;
1143 sk
->brush_size
= sk
->brush_radius
* 2;
1147 gdk_gc_set_line_attributes(sk
->gc
, sk
->brush_size
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1150 guint
sketchwidget_get_brushsize(SketchWidget
* sk
)
1152 g_assert(sk
!= NULL
);
1154 return (sk
->brush_size
);
1157 void calc_rect(GdkRectangle
*res
, gint x1
, gint y1
, gint x2
, gint y2
, gint bs
)
1189 void sketch_draw_brush(GtkWidget
* widget
, gdouble x
, gdouble y
, gdouble pressure
, SketchWidget
* sk
)
1191 GdkRectangle update_rect
;
1198 br
= sk
->brush_radius
;
1199 /* bs = sk->brush_size;*/
1203 bs
=sketch_calc_brush_size_from_pressure(pressure
, sk
);
1204 oldbs
=sk
->brush_size
;
1205 oldcol
=sk
->brush_color
;
1208 gdk_gc_set_line_attributes(sk
->gc
, bs
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1209 if (sk
->pressuresensitivity
)
1211 sk
->brush_color
=sketch_calc_brush_color_from_pressure(pressure
, sk
);
1212 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_color
);
1225 update_rect
.width
= 1;
1226 update_rect
.height
= 1;
1228 sketchundo_drawrect(sk
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1230 gdk_draw_rectangle(sk
->pixmap
, gc
, TRUE
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1235 update_rect
.x
= x
- br
;
1236 update_rect
.y
= y
- br
;
1237 update_rect
.width
= bs
;
1238 update_rect
.height
= bs
;
1240 sketchundo_drawrect(sk
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1242 gdk_draw_arc(sk
->pixmap
, gc
, TRUE
, x
- br
, y
- br
, bs
, bs
, 0, 64 * 360);
1247 gdk_gc_set_line_attributes(sk
->gc
, oldbs
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1248 if (sk
->pressuresensitivity
)
1250 sk
->brush_color
=oldcol
;
1251 gdk_gc_set_foreground(sk
->gc
, &oldcol
);
1255 gtk_widget_queue_draw_area(widget
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1258 gboolean
sketch_teststupid(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
)
1260 /*fprintf(stderr, "TEST: %d, %d, %d, %d\n", event->area.x, event->area.y, event->area.width, event->area.height);*/
1262 if (event
->area
.height
>=350)
1264 #ifdef NOTIFY_STUPID
1265 fprintf(stderr
, "STUPID\n");
1273 gboolean
sketch_button_release(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
)
1275 if (sk
->pressed
==FALSE
) return TRUE
;
1277 if (event
->button
== 1)
1279 if (sk
->shape
!= SKETCHSHAPE_FREEHAND
)
1283 GdkRectangle update_rect
;
1288 bs
= sk
->brush_size
+ 3;
1290 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1294 if (sk
->shape
== SKETCHSHAPE_LINE
)
1296 int xd
=abs(sk
->start_x
- sk
->cur_x
);
1297 int yd
=abs(sk
->start_y
- sk
->cur_y
);
1298 if (xd
>(yd
*1.8)) sk
->cur_y
=sk
->start_y
;
1299 else if (yd
>(xd
*1.8)) sk
->cur_x
=sk
->start_x
;
1302 if (sk
->cur_x
<sk
->start_x
&& sk
->cur_y
>sk
->start_y
)
1303 sk
->cur_x
=sk
->start_x
- abs(sk
->cur_y
- sk
->start_y
);
1304 else if (sk
->cur_x
>sk
->start_x
&& sk
->cur_y
<sk
->start_y
)
1305 sk
->cur_x
=sk
->start_x
+ abs(sk
->cur_y
- sk
->start_y
);
1307 sk
->cur_y
=sk
->start_y
+ (sk
->cur_x
- sk
->start_x
);
1309 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1313 update_rect
.width
=update_rect
.height
=sqrt((update_rect
.height
*update_rect
.height
)+(update_rect
.width
*update_rect
.width
));
1317 sketchundo_drawrect(sk
, (update_rect
.x
>bs
)?(update_rect
.x
-bs
):0, (update_rect
.y
>bs
)?(update_rect
.y
-bs
):0, update_rect
.width
+(bs
*2), update_rect
.height
+(bs
*2));
1318 if (sk
->shape
== SKETCHSHAPE_RECT
) gdk_draw_rectangle(sk
->pixmap
, gc
, sk
->fillmode
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1319 else if (sk
->shape
== SKETCHSHAPE_ELLIPSE
) gdk_draw_arc(sk
->pixmap
, gc
, sk
->fillmode
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
, 0, 360*64);
1320 else if (sk
->shape
== SKETCHSHAPE_LINE
) gdk_draw_line(sk
->pixmap
, gc
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
);
1322 /* gtk_widget_queue_draw_area(widget, update_rect.x, update_rect.y, update_rect.width+(bs*2), update_rect.height+(bs*2));
1324 gtk_widget_queue_draw(widget
);
1327 sketchundo_commit(sk
);
1331 sk
->lastevent_x
= 0;
1332 sk
->lastevent_y
= 0;
1340 sk
->coords_valid
= FALSE
;
1346 gboolean
sketch_button_press(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
)
1349 if (sk
->stupidflag
==2)
1351 #ifdef NOTIFY_STUPID
1352 fprintf(stderr
, "STUPID 2\n");
1354 sk
->pressed
=TRUE
; /*first action after the stupid call wouldn't register otherwise*/
1357 sk
->coords_valid
= FALSE
;
1363 FIXME: not compatible with maemo2
1364 if (hildon_button_event_is_finger(event))
1366 #ifdef NOTIFY_COORDS
1367 fprintf(stderr, "GOT FINGERPRESS (%d,%d)\n", (int)event->x, (int)event->y);
1370 if (sk->callback_finger != NULL)
1373 if (!gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure)) pressure=1;
1375 (sk->callback_finger) (sk, (int)event->x, (int)event->y, pressure, sk->callback_finger_data);
1382 if (!gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_PRESSURE
, &pressure
)) pressure
=1;
1384 if (hildon_helper_event_button_is_finger(event
))
1386 #ifdef NOTIFY_COORDS
1387 fprintf(stderr
, "GOT FINGERPRESS (%d,%d)\n", (int)event
->x
, (int)event
->y
);
1389 if (sk
->callback_finger
!= NULL
)
1390 (sk
->callback_finger
) (sk
, (int)event
->x
, (int)event
->y
, pressure
, sk
->callback_finger_data
);
1395 if (event
->button
== 1 && sk
->pixmap
!= NULL
)
1398 if (event
->x
<0 || event
->y
<0 || event
->x
>=sk
->sizex
|| event
->y
>=sk
->sizey
) return TRUE
;
1400 #ifdef NOTIFY_COORDS
1401 fprintf(stderr
, "GOT BUTTONPRESS! (%d,%d)\n", (int)event
->x
, (int)event
->y
);
1404 if (sk
->shape
== SKETCHSHAPE_FREEHAND
)
1407 sketch_draw_brush(widget
, event
->x
, event
->y
, pressure
, sk
);
1409 sk
->lastevent_x
= event
->x
;
1410 sk
->lastevent_y
= event
->y
;
1414 sk
->start_x
= event
->x
;
1415 sk
->start_y
= event
->y
;
1416 sk
->coords_valid
= TRUE
;
1424 guint
sketch_calc_brush_size_from_pressure(gdouble pressure
, SketchWidget
* sk
)
1426 if (pressure
<PRESSURE_MIN
) pressure
=PRESSURE_MIN
;
1427 else if (pressure
==1 || pressure
>PRESSURE_MAX
) pressure
=PRESSURE_MAX
;
1429 gdouble rp
=pressure
/PRESSURE_MAX
;
1431 guint bs
=ceil(sk
->brush_size
*rp
);
1432 /*fprintf(stderr, "returned %f for pressure %f (new bs=%d)\n", rp, pressure, bs);*/
1437 gboolean
sketch_motion_notify(GtkWidget
* widget
, GdkEventMotion
* event
, SketchWidget
* sk
)
1439 double x
, y
, pressure
;
1440 GdkModifierType state
;
1442 if (sk
->stupidflag
==1)
1444 #ifdef NOTIFY_STUPID
1445 fprintf(stderr
, "STUPID 1\n");
1451 if (sk
->shape
== SKETCHSHAPE_FREEHAND
&& sk
->pressed
== FALSE
)
1453 #ifdef NOTIFY_COORDS
1454 fprintf(stderr
, "IGN\n");
1461 /* gdk_window_get_pointer(event->window, &x, &y, &state);*/
1463 gdk_device_get_state (event
->device
, event
->window
, NULL
, &state
);
1464 gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_X
, &x
);
1465 gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_Y
, &y
);
1466 if (!gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_PRESSURE
, &pressure
)) pressure
=1;
1468 #ifdef NOTIFY_COORDS
1469 fprintf(stderr
, "GOT HINT! (%d,%d)\n", (int)x
, (int)y
);
1476 state
= event
->state
;
1477 if (!gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_PRESSURE
, &pressure
)) pressure
=1;
1479 #ifdef NOTIFY_COORDS
1480 fprintf(stderr
, "GOT MOTIONNOTIFY! (%d,%d)\n", (int)x
, (int)y
);
1484 if (x
<0 || y
<0 || x
>=sk
->sizex
|| y
>=sk
->sizey
) return TRUE
;
1486 if (sk
->shape
!= SKETCHSHAPE_FREEHAND
)
1488 if (sk
->coords_valid
==FALSE
)
1492 sk
->coords_valid
=TRUE
;
1499 GdkRectangle update_rect;
1501 bs = sk->brush_size + 3;
1502 calc_rect(&update_rect, sk->start_x, sk->start_y, sk->cur_x, sk->cur_y, bs);
1503 if (sk->shiftmode) update_rect.width=update_rect.height;
1505 gtk_widget_queue_draw_area(widget, update_rect.x, update_rect.y, update_rect.width+(bs*2), update_rect.height+(bs*2));
1507 gtk_widget_queue_draw(widget
);
1514 if (state
& GDK_BUTTON1_MASK
&& sk
->pixmap
!= NULL
)
1518 if (sk
->lastevent_x
== 0 && sk
->lastevent_y
== 0)
1520 sketch_draw_brush(widget
, x
, y
, pressure
, sk
);
1529 bs2
=sketch_calc_brush_size_from_pressure(pressure
, sk
);
1530 oldbs
=sk
->brush_size
;
1531 oldcol
=sk
->brush_color
;
1534 gdk_gc_set_line_attributes(sk
->gc
, bs2
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1535 if (sk
->pressuresensitivity
)
1537 sk
->brush_color
=sketch_calc_brush_color_from_pressure(pressure
, sk
);
1538 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_color
);
1550 if (x
< sk
->lastevent_x
)
1552 w
= sk
->lastevent_x
- x
;
1557 w
= x
- sk
->lastevent_x
;
1558 x1
= sk
->lastevent_x
;
1561 if (y
< sk
->lastevent_y
)
1563 h
= sk
->lastevent_y
- y
;
1568 h
= y
- sk
->lastevent_y
;
1569 y1
= sk
->lastevent_y
;
1584 GdkColor col=sketchwidget_get_brushcolor(sk);
1585 GdkColor col2, col3;
1586 col2.red=col2.green=0;
1588 sketchwidget_set_brushcolor(sk, col2);
1590 col3.red=col2.green=col3.blue=255*255;
1591 GdkColormap *colormap = gdk_window_get_colormap(sk->drawingarea->window);
1592 gdk_color_alloc(colormap, &col3);
1593 gdk_gc_set_background(sk->gc, &col3);
1595 gdk_gc_set_line_attributes(sk->gc, 1, GDK_LINE_DOUBLE_DASH, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
1596 gdk_draw_rectangle(sk->pixmap, sk->gc, FALSE, x1, y1, w+(bs*2), h+(bs*2));
1598 sketchwidget_set_brushcolor(sk, col);
1599 gdk_gc_set_line_attributes(sk->gc, sk->brush_size, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
1600 gtk_widget_queue_draw(widget);
1602 sketchundo_drawrect(sk
, x1
, y1
, w
+ (bs
* 2), h
+ (bs
* 2));
1604 gdk_draw_line(sk
->pixmap
, sk
->gc
, sk
->lastevent_x
, sk
->lastevent_y
, x
, y
);
1606 gtk_widget_queue_draw_area(widget
, x1
, y1
, w
+ (bs
* 2), h
+ (bs
* 2));
1608 if (pressure
!=1 && sk
->gc
)
1610 gdk_gc_set_line_attributes(sk
->gc
, oldbs
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1611 if (sk
->pressuresensitivity
)
1613 sk
->brush_color
=oldcol
;
1614 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_color
);
1619 sk
->lastevent_x
= xb
;
1620 sk
->lastevent_y
= yb
;
1626 gboolean
sketch_configure(GtkWidget
* widget
, GdkEventConfigure
* event
, SketchWidget
* sk
)
1629 g_object_unref(sk
->backpixmap
);
1631 sketchwidget_init_backpixmaps(sk
);
1633 sk
->backpixmap
= gdk_pixmap_new(widget
->window
, widget
->allocation
.width
, widget
->allocation
.height
, -1);
1636 g_object_unref(sk
->pixmap
);
1638 sk
->pixmap
= gdk_pixmap_new(widget
->window
, widget
->allocation
.width
, widget
->allocation
.height
, -1);
1639 sketchwidget_clear_real(sk
);
1642 gdk_gc_unref(sk
->gc
);
1644 sk
->gc
= gdk_gc_new(GDK_DRAWABLE(sk
->pixmap
));
1646 sketchwidget_set_backstyle(sk
, sk
->backstyle
);
1648 sketchwidget_set_brushcolor(sk
, sk
->brush_color
);
1650 gdk_gc_set_line_attributes(sk
->gc
, sk
->brush_size
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1656 * Redraw the screen from the backing pixmap
1658 gboolean
sketch_expose(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
)
1660 /* fprintf(stderr, "EXPOSE: %d, %d, %d, %d\n", event->area.x, event->area.y, event->area.width, event->area.height);*/
1662 GdkGC
*tmpgc
= gdk_gc_new(widget
->window
);
1664 gdk_gc_copy(tmpgc
, widget
->style
->fg_gc
[GTK_WIDGET_STATE(widget
)]);
1667 gdk_draw_drawable(widget->window,
1668 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1670 event->area.x, event->area.y,
1671 event->area.x, event->area.y,
1672 event->area.width, event->area.height);
1675 int bh
= sk
->backpixmapheights
[sk
->backstyle
];
1676 GdkPixmap
*bp
= sk
->backpixmaps
[sk
->backstyle
];
1678 if (bh
> 0 && bp
!= NULL
)
1680 int starty
= event
->area
.y
% bh
;
1682 gdk_draw_drawable(widget
->window
, widget
->style
->fg_gc
[GTK_WIDGET_STATE(widget
)], bp
, event
->area
.x
, starty
, event
->area
.x
, event
->area
.y
, event
->area
.width
, bh
- starty
);
1684 starty
= event
->area
.y
+ bh
- starty
;
1685 int endy
= event
->area
.y
+ event
->area
.height
;
1687 int tmp
= endy
% bh
;
1688 int midy
= endy
- tmp
;
1696 for(i
= starty
; i
< midy
; i
+= bh
)
1698 gdk_draw_drawable(widget
->window
, widget
->style
->fg_gc
[GTK_WIDGET_STATE(widget
)], bp
, event
->area
.x
, 0, event
->area
.x
, i
, event
->area
.width
, bh
);
1705 gdk_draw_drawable(widget
->window
, widget
->style
->fg_gc
[GTK_WIDGET_STATE(widget
)], bp
, event
->area
.x
, 0, event
->area
.x
, midy
, event
->area
.width
, midy
- endy
);
1707 gdk_gc_set_function(tmpgc
, GDK_AND
);
1712 this code kinda works but it won't do what a decent gtkrc can so why bother
1713 also it if the widget scrolls the borders scroll with it too :p
1715 if (sk
->border
==TRUE
)
1717 /*take care of left and right borders*/
1718 if (event
->area
.x
<2)
1719 gdk_draw_line(widget
->window
, sk
->backgc
, 0, event
->area
.y
, 2, event
->area
.height
);
1720 if (event
->area
.x
>=(widget
->allocation
.width
-2) || (event
->area
.x
+event
->area
.width
)>=(widget
->allocation
.width
-2))
1721 gdk_draw_line(widget
->window
, sk
->backgc
, widget
->allocation
.width
-2, event
->area
.y
, 2, event
->area
.height
);
1723 /*take care of top and bottom borders*/
1724 if (event
->area
.y
<2)
1725 gdk_draw_line(widget
->window
, sk
->backgc
, event
->area
.x
, 0, event
->area
.width
, 2);
1726 if (event
->area
.y
>=(widget
->allocation
.height
-2) || (event
->area
.y
+event
->area
.height
)>=(widget
->allocation
.height
-2))
1727 gdk_draw_line(widget
->window
, sk
->backgc
, event
->area
.x
, widget
->allocation
.height
-2, event
->area
.width
, 2);
1731 gdk_draw_drawable(widget
->window
, tmpgc
, sk
->pixmap
, event
->area
.x
, event
->area
.y
, event
->area
.x
, event
->area
.y
, event
->area
.width
, event
->area
.height
);
1733 g_object_unref(tmpgc
);
1735 if (sk
->shape
!= SKETCHSHAPE_FREEHAND
&& sk
->pressed
)
1737 GdkRectangle update_rect
;
1740 bs
= sk
->brush_size
+ 3;
1742 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1745 if (sk
->shape
== SKETCHSHAPE_LINE
)
1747 int xd
=abs(sk
->start_x
- sk
->cur_x
);
1748 int yd
=abs(sk
->start_y
- sk
->cur_y
);
1749 if (xd
>(yd
*1.8)) sk
->cur_y
=sk
->start_y
;
1750 else if (yd
>(xd
*1.8)) sk
->cur_x
=sk
->start_x
;
1753 if (sk
->cur_x
<sk
->start_x
&& sk
->cur_y
>sk
->start_y
)
1754 sk
->cur_x
=sk
->start_x
- abs(sk
->cur_y
- sk
->start_y
);
1755 else if (sk
->cur_x
>sk
->start_x
&& sk
->cur_y
<sk
->start_y
)
1756 sk
->cur_x
=sk
->start_x
+ abs(sk
->cur_y
- sk
->start_y
);
1758 sk
->cur_y
=sk
->start_y
+ (sk
->cur_x
- sk
->start_x
);
1760 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1764 update_rect
.width
=update_rect
.height
=sqrt((update_rect
.height
*update_rect
.height
)+(update_rect
.width
*update_rect
.width
));
1768 if (sk
->shape
== SKETCHSHAPE_RECT
)
1769 gdk_draw_rectangle(widget
->window
, sk
->gc
, sk
->fillmode
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1770 else if (sk
->shape
== SKETCHSHAPE_ELLIPSE
)
1771 gdk_draw_arc(widget
->window
, sk
->gc
, sk
->fillmode
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
, 0, 360*64);
1772 else if (sk
->shape
== SKETCHSHAPE_LINE
)
1773 gdk_draw_line(widget
->window
, sk
->gc
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
);