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/sketchwidget.h>
23 #include <hildon-widgets/hildon-finger.h>
26 * SketchWidget's "Privates"
28 void calc_rect(GdkRectangle
*res
, gint x1
, gint y1
, gint x2
, gint y2
, gint bs
);
29 void sketchwidget_init_backpixmaps(SketchWidget
* sk
);
30 void sketch_draw_brush(GtkWidget
* widget
, gdouble x
, gdouble y
, gdouble pressure
, SketchWidget
* sk
);
31 guint
sketch_calc_brush_size_from_pressure(gdouble pressure
, SketchWidget
* sk
);
32 gboolean
sketch_teststupid(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
);
33 gboolean
sketch_button_release(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
);
34 gboolean
sketch_button_press(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
);
35 gboolean
sketch_motion_notify(GtkWidget
* widget
, GdkEventMotion
* event
, SketchWidget
* sk
);
36 gboolean
sketch_configure(GtkWidget
* widget
, GdkEventConfigure
* event
, SketchWidget
* sk
);
37 gboolean
sketch_expose(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
);
38 void sketchwidget_invoke_undocallback(SketchWidget
* sk
, gboolean st
);
39 void sketchwidget_invoke_redocallback(SketchWidget
* sk
, gboolean st
);
40 void sketch_calc_pressurecolors(SketchWidget
*sk
);
42 void sketch_calc_pressurecolors(SketchWidget
*sk
)
44 guint pc
= PRESSURE_COLORS
+ 1;
45 gdouble step
= (PRESSURE_COLOR_MAX
- PRESSURE_MIN
) / PRESSURE_COLORS
;
54 /*if (maxr==0 && maxg==0 && maxb==0) maxr=maxg=maxb=32768;*/
55 if (maxr
<sk
->brush_color
.red
||
56 maxg
<sk
->brush_color
.green
||
57 maxb
<sk
->brush_color
.blue
)
64 guint stepr
= (maxr
- sk
->brush_color
.red
) / pc
;
65 guint stepg
= (maxg
- sk
->brush_color
.green
) / pc
;
66 guint stepb
= (maxb
- sk
->brush_color
.blue
) / pc
;
68 #ifdef PRESSURECOLORS_DEBUG
69 fprintf(stderr
, "step=%f stepr=%d stepg=%d stepb=%d\n", step
, stepr
, stepg
, stepb
);
72 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
75 for(i
=0;i
<PRESSURE_COLORS
;i
++)
77 sk
->brush_colors
[i
].red
=sk
->brush_color
.red
+ ((i
+1)*stepr
);
78 sk
->brush_colors
[i
].green
=sk
->brush_color
.green
+ ((i
+1)*stepg
);
79 sk
->brush_colors
[i
].blue
=sk
->brush_color
.blue
+ ((i
+1)*stepb
);
80 sk
->brush_colors_pressure_index
[i
]=PRESSURE_MIN
+ ((PRESSURE_COLORS
-i
-1)*step
);
81 if (sk
->brush_colors_pressure_index
[i
]>PRESSURE_MAX
) sk
->brush_colors_pressure_index
[i
]=PRESSURE_MAX
;
82 gdk_color_alloc(colormap
, &sk
->brush_colors
[i
]);
84 #ifdef PRESSURECOLORS_DEBUG
85 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
);
90 GdkColor
sketch_calc_brush_color_from_pressure(gdouble pressure
, SketchWidget
* sk
)
92 GdkColor ret
=sk
->brush_color
;
95 for(i
=PRESSURE_COLORS
-1;i
>=0;i
--)
97 if (pressure
<=sk
->brush_colors_pressure_index
[i
])
99 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_colors
[i
]);
100 ret
=sk
->brush_colors
[i
];
101 #ifdef PRESSURECOLORS_DEBUG
102 fprintf(stderr
, "pressureindex is %d (pressure=%f)\n", i
, pressure
);
111 void sketchwidget_invoke_undocallback(SketchWidget
* sk
, gboolean st
)
113 if (sk
->callback_undotoggle
!= NULL
)
114 (sk
->callback_undotoggle
) (sk
, st
, sk
->callback_undotoggle_data
);
117 void sketchwidget_invoke_redocallback(SketchWidget
* sk
, gboolean st
)
119 if (sk
->callback_redotoggle
!= NULL
)
120 (sk
->callback_redotoggle
) (sk
, st
, sk
->callback_redotoggle_data
);
124 * these two functions are tested and they work
126 void tile_getcoords(guint tileid
, guint
* x
, guint
* y
)
128 guint t
= tileid
% TILES_ROWSTRIDE
;
130 *y
= (tileid
- t
) / TILES_ROWSTRIDE
* TILE_SIZE
;
134 guint
tile_getid(guint x
, guint y
)
136 guint tx
= x
% TILE_SIZE
;
137 guint xbase
= (x
- tx
) / TILE_SIZE
;
139 guint ty
= y
% TILE_SIZE
;
140 guint ybase
= (y
- ty
) / TILE_SIZE
;
142 return (ybase
* TILES_ROWSTRIDE
+ xbase
);
148 void sketchundo_free_list(GList
* ulist
)
154 SketchWidgetUndo
*un
= li
->data
;
158 GSList
*tl
= un
->tileList
;
162 if (tl
->data
!= NULL
)
164 SketchWidgetTile
*ti
= (SketchWidgetTile
*) tl
->data
;
168 if (ti
->tiledata
) { gdk_pixmap_unref(ti
->tiledata
); ti
->tiledata
=NULL
; }
169 if (ti
->tiledata_new
) { gdk_pixmap_unref(ti
->tiledata_new
); ti
->tiledata_new
=NULL
; }
173 tl
= g_slist_next(tl
);
175 g_slist_free(un
->tileList
);
177 li
= g_list_next(li
);
179 /*fixme: this one eventually causes a crash (in g_list_length) instead we keep the list for now*/
186 * call everytime mouse is pressed
188 void sketchundo_new(SketchWidget
* sk
)
190 if (sk
->undocurbuffer
!= NULL
) return; /*assert?*/
192 SketchWidgetUndo
*su
= g_new0(SketchWidgetUndo
, 1);
194 su
->tileList
= NULL
; /*unnecessary */
195 sk
->undocurbuffer
= su
;
197 fprintf(stderr, "UNDO: new\n");
202 * call everytime mouse is released
204 void sketchundo_commit(SketchWidget
* sk
)
206 sketchwidget_set_edited(sk
, TRUE
);
208 if (sk
->undocurbuffer
==NULL
) /*sometimes happens (esp on gregale) with scrolledwindow expose stupid hack enabled, should be fixed though*/
210 fprintf(stderr
, "[sketchundo] undocurbuffer is null!\n");
214 /* g_assert(sk->undocurbuffer != NULL);*/
217 * free structs ahead of undocurrent here
219 if (sk
->undocurrent
> 0)
222 GList
*startsnip
= sk
->undolist
;
223 GList
*endsnip
= g_list_nth(sk
->undolist
, sk
->undocurrent
);
227 sk
->undolist
=endsnip
;
228 if (endsnip
->prev
!=NULL
) (endsnip
->prev
)->next
=NULL
;
235 fixme:crash--see comment in func. probably due to bad "snipping" somewhere above
237 sketchundo_free_list(startsnip
);
243 * check for UNDO_LEVELS and free structs here
245 guint llen
= g_list_length(sk
->undolist
);
247 if (llen
>= (UNDO_LEVELS
- 1))
248 { /*we will add (erm, prepend is the right word) one more so we check for one less */
249 GList
*startsnip
= g_list_nth(sk
->undolist
, UNDO_LEVELS
- 1);
251 if (startsnip
!= NULL
&& startsnip
->prev
!= NULL
)
253 /* cut the portion off and free it */
254 (startsnip
->prev
)->next
= NULL
;
255 sketchundo_free_list(startsnip
);
260 GSList
*tl
=sk
->undocurbuffer
->tileList
;
263 SketchWidgetTile
*ti
= (SketchWidgetTile
*) tl
->data
;
267 tile_getcoords(ti
->tileid
, &sx
, &sy
);
268 ti
->tiledata_new
= gdk_pixmap_new(sk
->drawingarea
->window
, TILE_SIZE
, TILE_SIZE
, -1);
269 gdk_draw_drawable(ti
->tiledata_new
, sk
->drawingarea
->style
->white_gc
, sk
->pixmap
, sx
, sy
, 0, 0, TILE_SIZE
, TILE_SIZE
);
274 sk
->undolist
= g_list_prepend(sk
->undolist
, sk
->undocurbuffer
);
275 sk
->undocurbuffer
= NULL
;
276 sk
->undocurrent
= 0; /*reset our position */
278 sketchwidget_invoke_undocallback(sk
, TRUE
);
279 sketchwidget_invoke_redocallback(sk
, FALSE
);
281 fprintf(stderr, "UNDO: commit\n");
288 void sketchundo_savetile(SketchWidget
* sk
, guint tileid
)
290 if (tileid
> TILES_X
* TILES_Y
)
291 return; /*FIXME:ugly, to keep drawing off the canvas */
293 if (sk
->undocurbuffer
->saved_tiles
[tileid
] == 1) /*dupe-check*/
298 tile_getcoords(tileid
, &sx
, &sy
);
301 * fprintf(stderr, "savetile:%d coords:%d,%d\n", tileid, sx, sy);
304 SketchWidgetTile
*t
= g_new0(SketchWidgetTile
, 1);
307 t
->tiledata
= gdk_pixmap_new(sk
->drawingarea
->window
, TILE_SIZE
, TILE_SIZE
, -1);
308 t
->tiledata_new
= NULL
;
310 gdk_draw_drawable(t
->tiledata
, sk
->drawingarea
->style
->white_gc
, sk
->pixmap
, sx
, sy
, 0, 0, TILE_SIZE
, TILE_SIZE
);
312 sk
->undocurbuffer
->tileList
= g_slist_prepend(sk
->undocurbuffer
->tileList
, t
);
314 sk
->undocurbuffer
->saved_tiles
[tileid
] = 1;
318 * call for each pixel before it's drawn
320 void sketchundo_drawpoint(SketchWidget
* sk
, guint px
, guint py
)
322 g_assert(sk
->undocurbuffer
!= NULL
);
324 guint tileid
= tile_getid(px
, py
);
326 sketchundo_savetile(sk
, tileid
);
330 * call for each rect before it's drawn
332 void sketchundo_drawrect(SketchWidget
* sk
, guint rx
, guint ry
, guint w
, guint h
)
334 g_assert(sk
->undocurbuffer
!= NULL
);
339 for(j
= ry
; j
<= ry
+ h
+ TILE_SIZE
; j
+= TILE_SIZE
)
341 guint x_tile_start
= tile_getid(rx
, j
);
342 guint x_tile_end
= tile_getid(rx
+ w
/*+TILE_SIZE */ , j
);
344 for(i
= x_tile_start
; i
<= x_tile_end
; i
++)
346 sketchundo_savetile(sk
, i
);
353 guint tileid
=tile_getid(rx
+j
, ry
+i
);
354 sketchundo_savetile(sk
, tileid
);
359 void sketchundo_drawtiles(SketchWidget
* sk
, SketchWidgetUndo
* un
, gboolean isredo
)
362 GdkGC *tmpgc = gdk_gc_new(sk->drawingarea->window);
363 gdk_gc_copy(tmpgc, sk->drawingarea->style->white_gc);
364 gdk_gc_set_function(tmpgc, GDK_AND_REVERSE);
366 GSList
*tl
= un
->tileList
;
370 SketchWidgetTile
*t
= (SketchWidgetTile
*) (tl
->data
);
372 if (isredo
==TRUE
) ourpix
=t
->tiledata_new
;
373 else ourpix
=t
->tiledata
;
379 tile_getcoords(t
->tileid
, &x
, &y
);
381 gdk_draw_drawable(sk
->pixmap
, /*tmpgc*/sk
->drawingarea
->style
->white_gc
,
382 ourpix
, 0, 0, x
, y
, TILE_SIZE
, TILE_SIZE
);
386 fprintf(stderr
, "NOTILEDATA! %d\n", t
->tileid
);
388 tl
= g_slist_next(tl
);
391 g_object_unref(tmpgc);
395 gboolean
sketchwidget_undo(SketchWidget
* sk
)
397 g_assert(sk
!= NULL
);
399 guint llen
= g_list_length(sk
->undolist
);
401 fprintf(stderr, "UNDO listlen is %d undocurrent is %d\n", llen, sk->undocurrent);
403 if (llen
<= (sk
->undocurrent
))
405 sketchwidget_invoke_undocallback(sk
, FALSE
);
409 SketchWidgetUndo
*un
= g_list_nth_data(sk
->undolist
, sk
->undocurrent
);
416 sketchundo_drawtiles(sk
, un
, FALSE
);
417 gtk_widget_queue_draw(sk
->drawingarea
);
419 fprintf(stderr, "UNDO undocurrent now is %d\n", sk->undocurrent);
421 if (llen
== sk
->undocurrent
)
422 sketchwidget_invoke_undocallback(sk
, FALSE
);
423 sketchwidget_invoke_redocallback(sk
, TRUE
);
428 gboolean
sketchwidget_redo(SketchWidget
* sk
)
430 g_assert(sk
!= NULL
);
432 if (sk
->undocurrent
< 1)
434 sketchwidget_invoke_redocallback(sk
, FALSE
);
438 fprintf(stderr, "REDO listlen is %d undocurrent is %d\n", g_list_length(sk->undolist), sk->undocurrent);
441 SketchWidgetUndo
*un
= g_list_nth_data(sk
->undolist
, sk
->undocurrent
- 1);
445 fprintf(stderr
, "REDO ERR!\n");
451 sketchundo_drawtiles(sk
, un
, TRUE
);
452 gtk_widget_queue_draw(sk
->drawingarea
);
454 fprintf(stderr, "REDO undocurrent now is %d\n", sk->undocurrent);
456 if (sk
->undocurrent
< 1)
457 sketchwidget_invoke_redocallback(sk
, FALSE
);
458 sketchwidget_invoke_undocallback(sk
, TRUE
);
463 void sketchwidget_wipe_undo(SketchWidget
* sk
)
465 if (sk
->undocurbuffer
)
466 sketchundo_commit(sk
); /*get rid of undocurbuffer */
469 sketchundo_free_list(sk
->undolist
);
472 sketchwidget_invoke_undocallback(sk
, FALSE
);
473 sketchwidget_invoke_redocallback(sk
, FALSE
);
476 void sketchwidget_set_fingercallback(SketchWidget
* sk
, void *func
, gpointer data
)
478 g_assert(sk
!= NULL
);
479 sk
->callback_finger
= func
;
480 sk
->callback_finger_data
= data
;
483 void sketchwidget_set_undocallback(SketchWidget
* sk
, void *func
, gpointer data
)
485 g_assert(sk
!= NULL
);
486 sk
->callback_undotoggle
= func
;
487 sk
->callback_undotoggle_data
= data
;
490 void sketchwidget_set_redocallback(SketchWidget
* sk
, void *func
, gpointer data
)
492 g_assert(sk
!= NULL
);
493 sk
->callback_redotoggle
= func
;
494 sk
->callback_redotoggle_data
= data
;
497 void sketchwidget_clear_real(SketchWidget
* sk
)
499 gdk_draw_rectangle(sk
->pixmap
, sk
->drawingarea
->style
->white_gc
, TRUE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
502 GtkWidget
*sketchwidget_get_drawingarea(SketchWidget
* sk
)
504 g_assert(sk
!= NULL
);
505 return (sk
->drawingarea
);
508 GtkWidget
*sketchwidget_get_mainwidget(SketchWidget
* sk
)
510 g_assert(sk
!= NULL
);
511 return (sk
->scrolledwindow
);
514 GdkPixbuf
*sketchwidget_trim_image(GdkPixbuf
* pixbuf
, guint totalw
, guint totalh
, double *w
, double *h
, gboolean doTopLeft
)
516 guint i
, j
, startx
= 0, starty
= 0, endx
, endy
;
521 guint newendy
= endy
, newendx
= endx
;
522 int rowstride
= gdk_pixbuf_get_rowstride(pixbuf
);
523 int nchan
= gdk_pixbuf_get_n_channels(pixbuf
);
526 pixels
= gdk_pixbuf_get_pixels(pixbuf
);
529 * fprintf(stderr, "nchan=%d\n", nchan);
532 gboolean dobr
= FALSE
;
535 for(i
= 0; i
< endy
; i
++)
537 int yoff
= i
* rowstride
;
539 for(j
= 0; j
< endx
; j
++)
541 p
= pixels
+ yoff
+ (j
* nchan
);
542 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
554 for(i
= endy
- 1; i
>= starty
; i
--)
556 int yoff
= i
* rowstride
;
558 for(j
= 0; j
< endx
; j
++)
560 p
= pixels
+ yoff
+ (j
* nchan
);
561 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
574 for(i
= 0; i
< endx
; i
++)
578 for(j
= starty
; j
< endy
; j
++)
580 p
= pixels
+ (j
* rowstride
) + ni
;
581 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
585 * fprintf(stderr, "S x=%d, y=%d, %d %d %d\n", i, j, p[0], p[1], p[2]);
597 for(i
= endx
- 1; i
>= startx
; i
--)
601 for(j
= starty
; j
< endy
; j
++)
603 p
= pixels
+ (j
* rowstride
) + ni
;
604 if (p
[0] != 255 || p
[1] != 255 || p
[2] != 255)
608 * fprintf(stderr, "E x=%d, y=%d, %d %d %d\n", i, j, p[0], p[1], p[2]);
620 * fprintf(stderr, "start:%dx%d end:%dx%d\n", startx, starty, newendx, newendy);
623 *w
= newendx
- startx
;
624 *h
= newendy
- starty
;
627 gdk_pixbuf_unref(pixbuf
);
631 GdkPixbuf
*pixbuf2
= gdk_pixbuf_new_subpixbuf(pixbuf
, startx
, starty
, *w
, *h
);
635 void sketchwidget_clear(SketchWidget
* sk
)
638 sketchundo_drawrect(sk
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
639 sketchwidget_clear_real(sk
);
640 sketchundo_commit(sk
);
641 gtk_widget_queue_draw(sk
->drawingarea
);
644 gboolean
sketchwidget_cut(SketchWidget
* sk
, GtkClipboard
* clippy
)
646 gboolean ret
= sketchwidget_copy(sk
, clippy
);
650 sketchwidget_clear(sk
);
654 gboolean
sketchwidget_copy(SketchWidget
* sk
, GtkClipboard
* clippy
)
656 g_assert(sk
!= NULL
);
658 gboolean ret
= FALSE
;
660 GdkPixbuf
*pixbuf
= gdk_pixbuf_get_from_drawable(NULL
, GDK_DRAWABLE(sk
->pixmap
), NULL
,
663 sk
->drawingarea
->allocation
.width
,
664 sk
->drawingarea
->allocation
.height
);
666 if (pixbuf
!= NULL
&& GDK_IS_PIXBUF(pixbuf
))
669 GdkPixbuf
*pixbuf2
= sketchwidget_trim_image(pixbuf
,
670 sk
->drawingarea
->allocation
.width
,
671 sk
->drawingarea
->allocation
.height
, &w
,
674 if (pixbuf2
&& GDK_IS_PIXBUF(pixbuf2
))
678 GdkPixbuf
*pixbuf3
= gdk_pixbuf_copy(pixbuf2
);
679 gtk_clipboard_set_image(clippy
, pixbuf3
);
680 g_object_unref(pixbuf3
);
683 g_object_unref(pixbuf2
);
689 gboolean
sketchwidget_paste(SketchWidget
* sk
, GtkClipboard
* clippy
)
691 g_assert(sk
!= NULL
);
693 gboolean ret
= FALSE
;
695 GdkPixbuf
*pixbuf
= gtk_clipboard_wait_for_image(clippy
);
697 if (pixbuf
!= NULL
&& GDK_IS_PIXBUF(pixbuf
))
699 int w
= gdk_pixbuf_get_width(pixbuf
);
700 int h
= gdk_pixbuf_get_height(pixbuf
);
702 if (w
> sk
->drawingarea
->allocation
.width
)
703 w
= sk
->drawingarea
->allocation
.width
;
704 if (h
> sk
->drawingarea
->allocation
.height
)
705 h
= sk
->drawingarea
->allocation
.height
;
709 sketchundo_drawrect(sk
, 0, 0, w
, h
);
710 gdk_draw_pixbuf(GDK_DRAWABLE(sk
->pixmap
), NULL
, pixbuf
, 0, 0, 0, 0, w
, h
, GDK_RGB_DITHER_NONE
, 0, 0);
711 sketchundo_commit(sk
);
712 gtk_widget_queue_draw(sk
->drawingarea
);
715 g_object_unref(pixbuf
);
720 GdkPixmap
*sketchwidget_get_Pixmap(SketchWidget
* sk
)
722 g_assert(sk
!= NULL
);
723 g_object_ref(sk
->pixmap
);
727 gboolean
sketchwidget_get_edited(SketchWidget
* sk
)
729 g_assert(sk
!= NULL
);
730 return (sk
->is_edited
);
733 void sketchwidget_set_edited(SketchWidget
* sk
, gboolean status
)
735 g_assert(sk
!= NULL
);
736 sk
->is_edited
= status
;
740 * Creates and initialises a main_view
742 SketchWidget
*sketchwidget_new(gint sizex
, gint sizey
, gboolean border
)
746 * Zero memory with g_new0
748 SketchWidget
*result
= g_new0(SketchWidget
, 1);
750 sketchwidget_set_edited(result
, FALSE
);
751 sketchwidget_set_brushsize(result
, 0);
753 result
->backstyle_currentimage
= SKETCHBACK_UNSET
;
754 result
->backstyle
= SKETCHBACK_NONE
;
756 result
->shape
= SKETCHSHAPE_FREEHAND
;
757 result
->pressed
= FALSE
;
758 result
->fillmode
= FALSE
;
760 result
->border
= border
;
761 result
->scrolledwindow
= gtk_scrolled_window_new(NULL
, NULL
);
762 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(result
->scrolledwindow
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
764 result
->drawingarea
= gtk_drawing_area_new();
765 gtk_widget_set_size_request(result
->drawingarea
, sizex
, sizey
);
770 result
->brush_color
.red
= 0;
771 result
->brush_color
.green
= 0;
772 result
->brush_color
.blue
= 0;
774 result
->pressuresensitivity
= FALSE
;
776 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(result
->scrolledwindow
), result
->drawingarea
);
778 g_signal_connect(G_OBJECT(result
->drawingarea
), "expose_event", G_CALLBACK(sketch_expose
), result
);
779 g_signal_connect(G_OBJECT(result
->drawingarea
), "configure_event", G_CALLBACK(sketch_configure
), result
);
780 g_signal_connect(G_OBJECT(result
->drawingarea
), "motion_notify_event", G_CALLBACK(sketch_motion_notify
), result
);
781 g_signal_connect(G_OBJECT(result
->drawingarea
), "button_press_event", G_CALLBACK(sketch_button_press
), result
);
782 g_signal_connect(G_OBJECT(result
->drawingarea
), "button_release_event", G_CALLBACK(sketch_button_release
), result
);
784 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*/);
786 g_signal_connect(G_OBJECT(result
->scrolledwindow
), "expose_event", G_CALLBACK(sketch_teststupid
), result
);
787 gtk_widget_set_extension_events(result
->drawingarea
, GDK_EXTENSION_EVENTS_CURSOR
); /* root of all evil */
789 gtk_widget_show(result
->drawingarea
);
790 gtk_widget_hide(result
->scrolledwindow
);
792 result
->undocurrent
= 0;
793 result
->undolist
= NULL
;
799 * clean up the allocated memory
801 void sketchwidget_destroy(SketchWidget
* sk
)
803 g_assert(sk
!= NULL
);
808 g_list_free(sk
->undolist
);
810 g_object_unref(sk
->pixmap
);
812 g_object_unref(sk
->backpixmap
);
813 for(i
= 0; i
< SKETCHBACK_COUNT
; i
++)
814 if (sk
->backpixmaps
[i
])
815 g_object_unref(sk
->backpixmaps
[i
]);
818 gdk_gc_unref(sk
->gc
);
821 * FIXME, segfault at GTK_IS_WIDGET
822 * if (sk->scrolledwindow && GTK_IS_WIDGET(sk->scrolledwindow)) gtk_widget_destroy(sk->scrolledwindow);
827 void sketchwidget_set_shape(SketchWidget
* sk
, sketchShape sp
)
829 g_assert(sk
!= NULL
);
834 void sketchwidget_set_fillmode(SketchWidget
* sk
, gboolean filled
)
836 g_assert(sk
!= NULL
);
838 sk
->fillmode
= filled
;
841 void sketchwidget_set_shift(SketchWidget
* sk
, gboolean shift
)
843 g_assert(sk
!= NULL
);
845 sk
->shiftmode
= shift
;
848 gboolean
sketchwidget_get_shift(SketchWidget
* sk
)
850 g_assert(sk
!= NULL
);
852 return(sk
->shiftmode
);
856 void sketchwidget_set_brushcolor(SketchWidget
* sk
, GdkColor col
)
858 g_assert(sk
!= NULL
);
860 if (sk
->drawingarea
!= NULL
)
862 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
864 gdk_color_alloc(colormap
, &col
);
866 sk
->brush_color
= col
;
867 sketch_calc_pressurecolors(sk
);
870 gdk_gc_set_foreground(sk
->gc
, &col
);
873 GdkColor
sketchwidget_get_brushcolor(SketchWidget
* sk
)
875 g_assert(sk
!= NULL
);
877 return (sk
->brush_color
);
880 void sketchwidget_set_backstyle(SketchWidget
* sk
, sketchBack style
)
882 g_assert(sk
!= NULL
);
884 sk
->backstyle
= style
;
885 gtk_widget_queue_draw(sk
->drawingarea
);
888 if (sk
->backpixmap
== NULL
)
889 return; /*our widget not configured yet, configure will call this again */
891 if (sk
->backstyle
== sk
->backstyle_currentimage
)
894 sk
->backstyle_currentimage
= sk
->backstyle
;
896 gdk_draw_rectangle(sk
->backpixmap
, sk
->drawingarea
->style
->white_gc
, TRUE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
898 gdk_gc_unref(sk
->backgc
);
899 sk
->backgc
= gdk_gc_new(GDK_DRAWABLE(sk
->backpixmap
));
901 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
903 if (style
== SKETCHBACK_LINES
)
908 tmpcol
.red
= 0x40 * 256;
909 tmpcol
.green
= 0xA0 * 256;
910 tmpcol
.blue
= 0xFF * 256;
911 gdk_color_alloc(colormap
, &tmpcol
);
912 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
913 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
915 for(i
= BACKGRAPH_LINE_HEIGHT
; i
< sk
->drawingarea
->allocation
.height
; i
+= BACKGRAPH_LINE_HEIGHT
)
917 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
920 tmpcol
.red
= 0xFF * 256;
921 tmpcol
.green
= 0x00 * 256;
922 tmpcol
.blue
= 0x80 * 256;
923 gdk_color_alloc(colormap
, &tmpcol
);
924 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
925 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_MARGIN_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
926 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, BACKGRAPH_LINE_MARGIN
, 0, BACKGRAPH_LINE_MARGIN
, sk
->drawingarea
->allocation
.height
);
928 else if (style
== SKETCHBACK_GRAPH
)
933 tmpcol
.red
= 0x7F * 256;
934 tmpcol
.green
= 0xB0 * 256;
935 tmpcol
.blue
= 0xFF * 256;
936 gdk_color_alloc(colormap
, &tmpcol
);
937 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
938 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_GRAPH_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
940 for(i
= BACKGRAPH_GRAPH_WIDTH
; i
< sk
->drawingarea
->allocation
.height
; i
+= BACKGRAPH_GRAPH_WIDTH
)
942 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
944 for(i
= BACKGRAPH_GRAPH_WIDTH
; i
< sk
->drawingarea
->allocation
.width
; i
+= BACKGRAPH_GRAPH_WIDTH
)
946 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, i
, 0, i
, sk
->drawingarea
->allocation
.height
);
949 else if (style
== SKETCHBACK_NONE
)
954 tmpcol
.red
= 0x7F * 256;
955 tmpcol
.green
= 0xB0 * 256;
956 tmpcol
.blue
= 0xFF * 256;
957 gdk_color_alloc(colormap
, &tmpcol
);
958 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
959 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_GRAPH_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
961 for(i
= 0; i
< sk
->drawingarea
->allocation
.height
; i
+= TILE_SIZE
)
963 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
965 for(i
= 0; i
< sk
->drawingarea
->allocation
.width
; i
+= TILE_SIZE
)
967 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmap
), sk
->backgc
, i
, 0, i
, sk
->drawingarea
->allocation
.height
);
971 if (sk
->border
== TRUE
)
975 tmpcol
.red
= 192 * 256;
976 tmpcol
.green
= 192 * 256;
977 tmpcol
.blue
= 192 * 256;
978 gdk_color_alloc(colormap
, &tmpcol
);
979 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
980 gdk_gc_set_line_attributes(sk
->backgc
, 2, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
982 gdk_draw_rectangle(sk
->backpixmap
, sk
->backgc
, FALSE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->drawingarea
->allocation
.height
);
985 gtk_widget_queue_draw(sk
->drawingarea
);
989 void sketchwidget_init_backpixmaps(SketchWidget
* sk
)
991 g_assert(sk
!= NULL
);
995 sk
->backpixmapheights
[0] = 0; /*or TILE_SIZE*/
996 sk
->backpixmapheights
[1] = BACKGRAPH_LINE_HEIGHT
+ 1;
997 sk
->backpixmapheights
[2] = BACKGRAPH_GRAPH_WIDTH
;
1000 gdk_gc_unref(sk
->backgc
);
1002 for(i
= 0; i
< SKETCHBACK_COUNT
; i
++)
1004 if (sk
->backpixmapheights
[i
] == 0)
1007 if (sk
->backpixmaps
[i
] != NULL
)
1008 g_object_unref(sk
->backpixmaps
[i
]);
1010 sk
->backpixmaps
[i
] = gdk_pixmap_new(sk
->drawingarea
->window
, sk
->drawingarea
->allocation
.width
, sk
->backpixmapheights
[i
], -1);
1011 gdk_draw_rectangle(sk
->backpixmaps
[i
], sk
->drawingarea
->style
->white_gc
, TRUE
, 0, 0, sk
->drawingarea
->allocation
.width
, sk
->backpixmapheights
[i
]);
1013 if (sk
->backgc
== NULL
)
1014 sk
->backgc
= gdk_gc_new(GDK_DRAWABLE(sk
->backpixmaps
[i
]));
1017 GdkColormap
*colormap
= gdk_window_get_colormap(sk
->drawingarea
->window
);
1022 tmpcol
.red
= 0x40 * 256;
1023 tmpcol
.green
= 0xA0 * 256;
1024 tmpcol
.blue
= 0xFF * 256;
1025 gdk_color_alloc(colormap
, &tmpcol
);
1026 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
1027 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1029 for(i
= BACKGRAPH_LINE_HEIGHT
; i
<= sk
->backpixmapheights
[SKETCHBACK_LINES
]; i
+= BACKGRAPH_LINE_HEIGHT
)
1031 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_LINES
]), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
1034 tmpcol
.red
= 0xFF * 256;
1035 tmpcol
.green
= 0x00 * 256;
1036 tmpcol
.blue
= 0x80 * 256;
1037 gdk_color_alloc(colormap
, &tmpcol
);
1038 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
1039 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_LINE_MARGIN_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1040 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_LINES
]), sk
->backgc
, BACKGRAPH_LINE_MARGIN
, 0, BACKGRAPH_LINE_MARGIN
, sk
->backpixmapheights
[SKETCHBACK_LINES
]);
1043 tmpcol
.red
= 0x7F * 256;
1044 tmpcol
.green
= 0xB0 * 256;
1045 tmpcol
.blue
= 0xFF * 256;
1046 gdk_color_alloc(colormap
, &tmpcol
);
1047 gdk_gc_set_foreground(sk
->backgc
, &tmpcol
);
1048 gdk_gc_set_line_attributes(sk
->backgc
, BACKGRAPH_GRAPH_SIZE
, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1050 /* for(i = BACKGRAPH_GRAPH_WIDTH; i <= sk->backpixmapheights[SKETCHBACK_GRAPH]; i += BACKGRAPH_GRAPH_WIDTH)*/
1051 for(i
= 0; i
< sk
->backpixmapheights
[SKETCHBACK_GRAPH
]; i
+= BACKGRAPH_GRAPH_WIDTH
)
1053 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_GRAPH
]), sk
->backgc
, 0, i
, sk
->drawingarea
->allocation
.width
, i
);
1055 /* for(i = BACKGRAPH_GRAPH_WIDTH; i < sk->drawingarea->allocation.width; i += BACKGRAPH_GRAPH_WIDTH)*/
1056 for(i
= 0; i
< sk
->drawingarea
->allocation
.width
; i
+= BACKGRAPH_GRAPH_WIDTH
)
1058 gdk_draw_line(GDK_DRAWABLE(sk
->backpixmaps
[SKETCHBACK_GRAPH
]), sk
->backgc
, i
, 0, i
, sk
->backpixmapheights
[SKETCHBACK_GRAPH
]);
1064 #define BACKGRAPH_DOT_WIDTH 32
1065 tmpcol.red = 0xC0 * 256;
1066 tmpcol.green = 0xC0 * 256;
1067 tmpcol.blue = 0xC0 * 256;
1068 gdk_color_alloc(colormap, &tmpcol);
1069 gdk_gc_set_foreground(sk->backgc, &tmpcol);
1071 for(i = 0; i < sk->backpixmapheights[SKETCHBACK_NONE]; i += BACKGRAPH_DOT_WIDTH)
1072 for(j = 0; j < sk->drawingarea->allocation.width; j += BACKGRAPH_DOT_WIDTH)
1074 gdk_draw_point(GDK_DRAWABLE(sk->backpixmaps[SKETCHBACK_NONE]), sk->backgc, i, j);
1078 tmpcol.red = 0x7F * 256;
1079 tmpcol.green = 0xB0 * 256;
1080 tmpcol.blue = 0xFF * 256;
1081 gdk_color_alloc(colormap, &tmpcol);
1082 gdk_gc_set_foreground(sk->backgc, &tmpcol);
1083 gdk_gc_set_line_attributes(sk->backgc, BACKGRAPH_GRAPH_SIZE, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
1085 for(i = 0; i < sk->backpixmapheights[SKETCHBACK_NONE]; i += TILE_SIZE)
1087 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[SKETCHBACK_NONE]), sk->backgc, 0, i, sk->drawingarea->allocation.width, i);
1089 for(i = 0; i < sk->drawingarea->allocation.width; i += TILE_SIZE)
1091 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[SKETCHBACK_NONE]), sk->backgc, i, 0, i, sk->backpixmapheights[SKETCHBACK_NONE]);
1096 /*important:sk->backgc should be configured for later use in expose()*/
1097 if (sk
->border
==TRUE
)
1100 bordercol
.red
= 192 * 256;
1101 bordercol
.green
= 192 * 256;
1102 bordercol
.blue
= 192 * 256;
1103 gdk_color_alloc(colormap
, &bordercol
);
1105 gdk_gc_set_foreground(sk
->backgc
, &bordercol
);
1106 gdk_gc_set_line_attributes(sk
->backgc
, 2, GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_BEVEL
);
1108 for(i = 0; i < SKETCHBACK_COUNT; i++)
1110 if (sk->backpixmapheights[i] == 0)
1113 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[i]), sk->backgc, 0, 0, 0, sk->backpixmapheights[i]);
1114 gdk_draw_line(GDK_DRAWABLE(sk->backpixmaps[i]), sk->backgc, sk->drawingarea->allocation.width, 0, sk->drawingarea->allocation.width, sk->backpixmapheights[i]);
1121 void sketchwidget_set_brushsize(SketchWidget
* sk
, guint bsize
)
1123 g_assert(sk
!= NULL
);
1129 sk
->brush_radius
= 0;
1134 sk
->brush_radius
= bsize
/ 2;
1135 if (sk
->brush_radius
< 1)
1136 sk
->brush_radius
= 1;
1138 sk
->brush_size
= sk
->brush_radius
* 2;
1142 gdk_gc_set_line_attributes(sk
->gc
, sk
->brush_size
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1145 guint
sketchwidget_get_brushsize(SketchWidget
* sk
)
1147 g_assert(sk
!= NULL
);
1149 return (sk
->brush_size
);
1152 void calc_rect(GdkRectangle
*res
, gint x1
, gint y1
, gint x2
, gint y2
, gint bs
)
1184 void sketch_draw_brush(GtkWidget
* widget
, gdouble x
, gdouble y
, gdouble pressure
, SketchWidget
* sk
)
1186 GdkRectangle update_rect
;
1193 br
= sk
->brush_radius
;
1194 /* bs = sk->brush_size;*/
1198 bs
=sketch_calc_brush_size_from_pressure(pressure
, sk
);
1199 oldbs
=sk
->brush_size
;
1200 oldcol
=sk
->brush_color
;
1203 gdk_gc_set_line_attributes(sk
->gc
, bs
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1204 if (sk
->pressuresensitivity
)
1206 sk
->brush_color
=sketch_calc_brush_color_from_pressure(pressure
, sk
);
1207 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_color
);
1220 update_rect
.width
= 1;
1221 update_rect
.height
= 1;
1223 sketchundo_drawrect(sk
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1225 gdk_draw_rectangle(sk
->pixmap
, gc
, TRUE
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1230 update_rect
.x
= x
- br
;
1231 update_rect
.y
= y
- br
;
1232 update_rect
.width
= bs
;
1233 update_rect
.height
= bs
;
1235 sketchundo_drawrect(sk
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1237 gdk_draw_arc(sk
->pixmap
, gc
, TRUE
, x
- br
, y
- br
, bs
, bs
, 0, 64 * 360);
1242 gdk_gc_set_line_attributes(sk
->gc
, oldbs
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1243 if (sk
->pressuresensitivity
)
1245 sk
->brush_color
=oldcol
;
1246 gdk_gc_set_foreground(sk
->gc
, &oldcol
);
1250 gtk_widget_queue_draw_area(widget
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1253 gboolean
sketch_teststupid(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
)
1255 /*fprintf(stderr, "TEST: %d, %d, %d, %d\n", event->area.x, event->area.y, event->area.width, event->area.height);*/
1257 if (event
->area
.height
>=350)
1259 #ifdef NOTIFY_STUPID
1260 fprintf(stderr
, "STUPID\n");
1268 gboolean
sketch_button_release(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
)
1270 if (sk
->pressed
==FALSE
) return TRUE
;
1272 if (event
->button
== 1)
1274 if (sk
->shape
!= SKETCHSHAPE_FREEHAND
)
1278 GdkRectangle update_rect
;
1283 bs
= sk
->brush_size
+ 3;
1285 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1289 if (sk
->shape
== SKETCHSHAPE_LINE
)
1291 int xd
=abs(sk
->start_x
- sk
->cur_x
);
1292 int yd
=abs(sk
->start_y
- sk
->cur_y
);
1293 if (xd
>(yd
*1.8)) sk
->cur_y
=sk
->start_y
;
1294 else if (yd
>(xd
*1.8)) sk
->cur_x
=sk
->start_x
;
1297 if (sk
->cur_x
<sk
->start_x
&& sk
->cur_y
>sk
->start_y
)
1298 sk
->cur_x
=sk
->start_x
- abs(sk
->cur_y
- sk
->start_y
);
1299 else if (sk
->cur_x
>sk
->start_x
&& sk
->cur_y
<sk
->start_y
)
1300 sk
->cur_x
=sk
->start_x
+ abs(sk
->cur_y
- sk
->start_y
);
1302 sk
->cur_y
=sk
->start_y
+ (sk
->cur_x
- sk
->start_x
);
1304 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1308 update_rect
.width
=update_rect
.height
=sqrt((update_rect
.height
*update_rect
.height
)+(update_rect
.width
*update_rect
.width
));
1312 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));
1313 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
);
1314 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);
1315 else if (sk
->shape
== SKETCHSHAPE_LINE
) gdk_draw_line(sk
->pixmap
, gc
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
);
1317 /* gtk_widget_queue_draw_area(widget, update_rect.x, update_rect.y, update_rect.width+(bs*2), update_rect.height+(bs*2));
1319 gtk_widget_queue_draw(widget
);
1322 sketchundo_commit(sk
);
1326 sk
->lastevent_x
= 0;
1327 sk
->lastevent_y
= 0;
1335 sk
->coords_valid
= FALSE
;
1341 gboolean
sketch_button_press(GtkWidget
* widget
, GdkEventButton
* event
, SketchWidget
* sk
)
1344 if (sk
->stupidflag
==2)
1346 #ifdef NOTIFY_STUPID
1347 fprintf(stderr
, "STUPID 2\n");
1349 sk
->pressed
=TRUE
; /*first action after the stupid call wouldn't register otherwise*/
1352 sk
->coords_valid
= FALSE
;
1358 FIXME: not compatible with maemo2
1359 if (hildon_button_event_is_finger(event))
1361 #ifdef NOTIFY_COORDS
1362 fprintf(stderr, "GOT FINGERPRESS (%d,%d)\n", (int)event->x, (int)event->y);
1365 if (sk->callback_finger != NULL)
1368 if (!gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure)) pressure=1;
1370 (sk->callback_finger) (sk, (int)event->x, (int)event->y, pressure, sk->callback_finger_data);
1377 if (!gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_PRESSURE
, &pressure
)) pressure
=1;
1378 if ((pressure
!=1 && pressure
>HILDON_FINGER_PRESSURE_THRESHOLD
) || event
->button
==2 || event
->button
==8 || (event
->button
==1 && event
->state
&GDK_MOD4_MASK
))
1380 #ifdef NOTIFY_COORDS
1381 fprintf(stderr
, "GOT FINGERPRESS (%d,%d)\n", (int)event
->x
, (int)event
->y
);
1383 if (sk
->callback_finger
!= NULL
)
1384 (sk
->callback_finger
) (sk
, (int)event
->x
, (int)event
->y
, pressure
, sk
->callback_finger_data
);
1387 if (event
->button
== 1 && sk
->pixmap
!= NULL
)
1390 if (event
->x
<0 || event
->y
<0 || event
->x
>=sk
->sizex
|| event
->y
>=sk
->sizey
) return TRUE
;
1392 #ifdef NOTIFY_COORDS
1393 fprintf(stderr
, "GOT BUTTONPRESS! (%d,%d)\n", (int)event
->x
, (int)event
->y
);
1396 if (sk
->shape
== SKETCHSHAPE_FREEHAND
)
1399 sketch_draw_brush(widget
, event
->x
, event
->y
, pressure
, sk
);
1401 sk
->lastevent_x
= event
->x
;
1402 sk
->lastevent_y
= event
->y
;
1406 sk
->start_x
= event
->x
;
1407 sk
->start_y
= event
->y
;
1408 sk
->coords_valid
= TRUE
;
1416 guint
sketch_calc_brush_size_from_pressure(gdouble pressure
, SketchWidget
* sk
)
1418 if (pressure
<PRESSURE_MIN
) pressure
=PRESSURE_MIN
;
1419 else if (pressure
==1 || pressure
>PRESSURE_MAX
) pressure
=PRESSURE_MAX
;
1421 gdouble rp
=pressure
/PRESSURE_MAX
;
1423 guint bs
=ceil(sk
->brush_size
*rp
);
1424 /*fprintf(stderr, "returned %f for pressure %f (new bs=%d)\n", rp, pressure, bs);*/
1429 gboolean
sketch_motion_notify(GtkWidget
* widget
, GdkEventMotion
* event
, SketchWidget
* sk
)
1431 double x
, y
, pressure
;
1432 GdkModifierType state
;
1434 if (sk
->stupidflag
==1)
1436 #ifdef NOTIFY_STUPID
1437 fprintf(stderr
, "STUPID 1\n");
1443 if (sk
->shape
== SKETCHSHAPE_FREEHAND
&& sk
->pressed
== FALSE
)
1445 #ifdef NOTIFY_COORDS
1446 fprintf(stderr
, "IGN\n");
1453 /* gdk_window_get_pointer(event->window, &x, &y, &state);*/
1455 gdk_device_get_state (event
->device
, event
->window
, NULL
, &state
);
1456 gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_X
, &x
);
1457 gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_Y
, &y
);
1458 if (!gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_PRESSURE
, &pressure
)) pressure
=1;
1460 #ifdef NOTIFY_COORDS
1461 fprintf(stderr
, "GOT HINT! (%d,%d)\n", (int)x
, (int)y
);
1468 state
= event
->state
;
1469 if (!gdk_event_get_axis ((GdkEvent
*)event
, GDK_AXIS_PRESSURE
, &pressure
)) pressure
=1;
1471 #ifdef NOTIFY_COORDS
1472 fprintf(stderr
, "GOT MOTIONNOTIFY! (%d,%d)\n", (int)x
, (int)y
);
1476 if (x
<0 || y
<0 || x
>=sk
->sizex
|| y
>=sk
->sizey
) return TRUE
;
1478 if (sk
->shape
!= SKETCHSHAPE_FREEHAND
)
1480 if (sk
->coords_valid
==FALSE
)
1484 sk
->coords_valid
=TRUE
;
1491 GdkRectangle update_rect;
1493 bs = sk->brush_size + 3;
1494 calc_rect(&update_rect, sk->start_x, sk->start_y, sk->cur_x, sk->cur_y, bs);
1495 if (sk->shiftmode) update_rect.width=update_rect.height;
1497 gtk_widget_queue_draw_area(widget, update_rect.x, update_rect.y, update_rect.width+(bs*2), update_rect.height+(bs*2));
1499 gtk_widget_queue_draw(widget
);
1506 if (state
& GDK_BUTTON1_MASK
&& sk
->pixmap
!= NULL
)
1510 if (sk
->lastevent_x
== 0 && sk
->lastevent_y
== 0)
1512 sketch_draw_brush(widget
, x
, y
, pressure
, sk
);
1521 bs2
=sketch_calc_brush_size_from_pressure(pressure
, sk
);
1522 oldbs
=sk
->brush_size
;
1523 oldcol
=sk
->brush_color
;
1526 gdk_gc_set_line_attributes(sk
->gc
, bs2
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1527 if (sk
->pressuresensitivity
)
1529 sk
->brush_color
=sketch_calc_brush_color_from_pressure(pressure
, sk
);
1530 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_color
);
1542 if (x
< sk
->lastevent_x
)
1544 w
= sk
->lastevent_x
- x
;
1549 w
= x
- sk
->lastevent_x
;
1550 x1
= sk
->lastevent_x
;
1553 if (y
< sk
->lastevent_y
)
1555 h
= sk
->lastevent_y
- y
;
1560 h
= y
- sk
->lastevent_y
;
1561 y1
= sk
->lastevent_y
;
1576 GdkColor col=sketchwidget_get_brushcolor(sk);
1577 GdkColor col2, col3;
1578 col2.red=col2.green=0;
1580 sketchwidget_set_brushcolor(sk, col2);
1582 col3.red=col2.green=col3.blue=255*255;
1583 GdkColormap *colormap = gdk_window_get_colormap(sk->drawingarea->window);
1584 gdk_color_alloc(colormap, &col3);
1585 gdk_gc_set_background(sk->gc, &col3);
1587 gdk_gc_set_line_attributes(sk->gc, 1, GDK_LINE_DOUBLE_DASH, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
1588 gdk_draw_rectangle(sk->pixmap, sk->gc, FALSE, x1, y1, w+(bs*2), h+(bs*2));
1590 sketchwidget_set_brushcolor(sk, col);
1591 gdk_gc_set_line_attributes(sk->gc, sk->brush_size, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
1592 gtk_widget_queue_draw(widget);
1594 sketchundo_drawrect(sk
, x1
, y1
, w
+ (bs
* 2), h
+ (bs
* 2));
1596 gdk_draw_line(sk
->pixmap
, sk
->gc
, sk
->lastevent_x
, sk
->lastevent_y
, x
, y
);
1598 gtk_widget_queue_draw_area(widget
, x1
, y1
, w
+ (bs
* 2), h
+ (bs
* 2));
1600 if (pressure
!=1 && sk
->gc
)
1602 gdk_gc_set_line_attributes(sk
->gc
, oldbs
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1603 if (sk
->pressuresensitivity
)
1605 sk
->brush_color
=oldcol
;
1606 gdk_gc_set_foreground(sk
->gc
, &sk
->brush_color
);
1611 sk
->lastevent_x
= xb
;
1612 sk
->lastevent_y
= yb
;
1618 gboolean
sketch_configure(GtkWidget
* widget
, GdkEventConfigure
* event
, SketchWidget
* sk
)
1621 g_object_unref(sk
->backpixmap
);
1623 sketchwidget_init_backpixmaps(sk
);
1625 sk
->backpixmap
= gdk_pixmap_new(widget
->window
, widget
->allocation
.width
, widget
->allocation
.height
, -1);
1628 g_object_unref(sk
->pixmap
);
1630 sk
->pixmap
= gdk_pixmap_new(widget
->window
, widget
->allocation
.width
, widget
->allocation
.height
, -1);
1631 sketchwidget_clear_real(sk
);
1634 gdk_gc_unref(sk
->gc
);
1636 sk
->gc
= gdk_gc_new(GDK_DRAWABLE(sk
->pixmap
));
1638 sketchwidget_set_backstyle(sk
, sk
->backstyle
);
1640 sketchwidget_set_brushcolor(sk
, sk
->brush_color
);
1642 gdk_gc_set_line_attributes(sk
->gc
, sk
->brush_size
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
1648 * Redraw the screen from the backing pixmap
1650 gboolean
sketch_expose(GtkWidget
* widget
, GdkEventExpose
* event
, SketchWidget
* sk
)
1652 /* fprintf(stderr, "EXPOSE: %d, %d, %d, %d\n", event->area.x, event->area.y, event->area.width, event->area.height);*/
1654 GdkGC
*tmpgc
= gdk_gc_new(widget
->window
);
1656 gdk_gc_copy(tmpgc
, widget
->style
->fg_gc
[GTK_WIDGET_STATE(widget
)]);
1659 gdk_draw_drawable(widget->window,
1660 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1662 event->area.x, event->area.y,
1663 event->area.x, event->area.y,
1664 event->area.width, event->area.height);
1667 int bh
= sk
->backpixmapheights
[sk
->backstyle
];
1668 GdkPixmap
*bp
= sk
->backpixmaps
[sk
->backstyle
];
1670 if (bh
> 0 && bp
!= NULL
)
1672 int starty
= event
->area
.y
% bh
;
1674 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
);
1676 starty
= event
->area
.y
+ bh
- starty
;
1677 int endy
= event
->area
.y
+ event
->area
.height
;
1679 int tmp
= endy
% bh
;
1680 int midy
= endy
- tmp
;
1688 for(i
= starty
; i
< midy
; i
+= bh
)
1690 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
);
1697 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
);
1699 gdk_gc_set_function(tmpgc
, GDK_AND
);
1704 this code kinda works but it won't do what a decent gtkrc can so why bother
1705 also it if the widget scrolls the borders scroll with it too :p
1707 if (sk
->border
==TRUE
)
1709 /*take care of left and right borders*/
1710 if (event
->area
.x
<2)
1711 gdk_draw_line(widget
->window
, sk
->backgc
, 0, event
->area
.y
, 2, event
->area
.height
);
1712 if (event
->area
.x
>=(widget
->allocation
.width
-2) || (event
->area
.x
+event
->area
.width
)>=(widget
->allocation
.width
-2))
1713 gdk_draw_line(widget
->window
, sk
->backgc
, widget
->allocation
.width
-2, event
->area
.y
, 2, event
->area
.height
);
1715 /*take care of top and bottom borders*/
1716 if (event
->area
.y
<2)
1717 gdk_draw_line(widget
->window
, sk
->backgc
, event
->area
.x
, 0, event
->area
.width
, 2);
1718 if (event
->area
.y
>=(widget
->allocation
.height
-2) || (event
->area
.y
+event
->area
.height
)>=(widget
->allocation
.height
-2))
1719 gdk_draw_line(widget
->window
, sk
->backgc
, event
->area
.x
, widget
->allocation
.height
-2, event
->area
.width
, 2);
1723 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
);
1725 g_object_unref(tmpgc
);
1727 if (sk
->shape
!= SKETCHSHAPE_FREEHAND
&& sk
->pressed
)
1729 GdkRectangle update_rect
;
1732 bs
= sk
->brush_size
+ 3;
1734 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1737 if (sk
->shape
== SKETCHSHAPE_LINE
)
1739 int xd
=abs(sk
->start_x
- sk
->cur_x
);
1740 int yd
=abs(sk
->start_y
- sk
->cur_y
);
1741 if (xd
>(yd
*1.8)) sk
->cur_y
=sk
->start_y
;
1742 else if (yd
>(xd
*1.8)) sk
->cur_x
=sk
->start_x
;
1745 if (sk
->cur_x
<sk
->start_x
&& sk
->cur_y
>sk
->start_y
)
1746 sk
->cur_x
=sk
->start_x
- abs(sk
->cur_y
- sk
->start_y
);
1747 else if (sk
->cur_x
>sk
->start_x
&& sk
->cur_y
<sk
->start_y
)
1748 sk
->cur_x
=sk
->start_x
+ abs(sk
->cur_y
- sk
->start_y
);
1750 sk
->cur_y
=sk
->start_y
+ (sk
->cur_x
- sk
->start_x
);
1752 calc_rect(&update_rect
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
, bs
);
1756 update_rect
.width
=update_rect
.height
=sqrt((update_rect
.height
*update_rect
.height
)+(update_rect
.width
*update_rect
.width
));
1760 if (sk
->shape
== SKETCHSHAPE_RECT
)
1761 gdk_draw_rectangle(widget
->window
, sk
->gc
, sk
->fillmode
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
);
1762 else if (sk
->shape
== SKETCHSHAPE_ELLIPSE
)
1763 gdk_draw_arc(widget
->window
, sk
->gc
, sk
->fillmode
, update_rect
.x
, update_rect
.y
, update_rect
.width
, update_rect
.height
, 0, 360*64);
1764 else if (sk
->shape
== SKETCHSHAPE_LINE
)
1765 gdk_draw_line(widget
->window
, sk
->gc
, sk
->start_x
, sk
->start_y
, sk
->cur_x
, sk
->cur_y
);