tagged 0.31
[maemopadplus.git] / src / ui / sketchwidget.c
blobe0012dd901638759f8a2f8ee32a89d3b0821148b
1 /*
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
18 * 02110-1301 USA
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;
46 guint maxr = 32767;
47 guint maxg = 32767;
48 guint maxb = 32767;
50 if (maxr<0) maxr=0;
51 if (maxg<0) maxg=0;
52 if (maxb<0) maxb=0;
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)
59 maxr=65535;
60 maxg=65535;
61 maxb=65535;
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);
70 #endif
72 GdkColormap *colormap = gdk_window_get_colormap(sk->drawingarea->window);
74 int i;
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);
86 #endif
90 GdkColor sketch_calc_brush_color_from_pressure(gdouble pressure, SketchWidget * sk)
92 GdkColor ret=sk->brush_color;
93 int i;
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);
103 #endif
104 break;
108 return(ret);
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;
131 *x = t * 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);
146 * internal
148 void sketchundo_free_list(GList * ulist)
150 GList *li = ulist;
152 while(li != NULL)
154 SketchWidgetUndo *un = li->data;
156 if (un != NULL)
158 GSList *tl = un->tileList;
160 while(tl != NULL)
162 if (tl->data != NULL)
164 SketchWidgetTile *ti = (SketchWidgetTile *) tl->data;
166 if (ti)
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*/
180 #if 0
181 g_list_free(ulist);
182 #endif
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");
211 return;
214 /* g_assert(sk->undocurbuffer != NULL);*/
217 * free structs ahead of undocurrent here
219 if (sk->undocurrent > 0)
221 #if 1
222 GList *startsnip = sk->undolist;
223 GList *endsnip = g_list_nth(sk->undolist, sk->undocurrent);
225 if (endsnip != NULL)
227 sk->undolist=endsnip;
228 if (endsnip->prev!=NULL) (endsnip->prev)->next=NULL;
230 else
232 sk->undolist = NULL;
235 fixme:crash--see comment in func. probably due to bad "snipping" somewhere above
237 sketchundo_free_list(startsnip);
238 #endif
239 sk->undocurrent = 0;
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;
261 while(tl!=NULL)
263 SketchWidgetTile *ti = (SketchWidgetTile *) tl->data;
264 if (ti!=NULL)
266 guint sx, sy;
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);
271 tl=g_slist_next(tl);
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");
286 * internal
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*/
294 return;
296 guint sx, sy;
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);
306 t->tileid = tileid;
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);
336 int i, j;
338 #if 1
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);
349 #else
350 for(i=0;i<h;i++)
351 for(j=0;j<w;j++)
353 guint tileid=tile_getid(rx+j, ry+i);
354 sketchundo_savetile(sk, tileid);
356 #endif
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;
368 while(tl != NULL)
370 SketchWidgetTile *t = (SketchWidgetTile *) (tl->data);
371 GdkPixmap *ourpix;
372 if (isredo==TRUE) ourpix=t->tiledata_new;
373 else ourpix=t->tiledata;
375 if (ourpix)
377 guint x, y;
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);
384 else
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);
406 return (FALSE);
409 SketchWidgetUndo *un = g_list_nth_data(sk->undolist, sk->undocurrent);
411 if (un == NULL)
412 return (FALSE);
414 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);
425 return (TRUE);
428 gboolean sketchwidget_redo(SketchWidget * sk)
430 g_assert(sk != NULL);
432 if (sk->undocurrent < 1)
434 sketchwidget_invoke_redocallback(sk, FALSE);
435 return (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);
443 if (un == NULL)
445 fprintf(stderr, "REDO ERR!\n");
446 return (FALSE);
449 sk->undocurrent--;
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);
460 return (TRUE);
463 void sketchwidget_wipe_undo(SketchWidget * sk)
465 if (sk->undocurbuffer)
466 sketchundo_commit(sk); /*get rid of undocurbuffer */
467 sk->undocurrent = 0;
469 sketchundo_free_list(sk->undolist);
470 sk->undolist = NULL;
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;
518 endx = totalw;
519 endy = totalh;
521 guint newendy = endy, newendx = endx;
522 int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
523 int nchan = gdk_pixbuf_get_n_channels(pixbuf);
524 guchar *pixels, *p;
526 pixels = gdk_pixbuf_get_pixels(pixbuf);
529 * fprintf(stderr, "nchan=%d\n", nchan);
532 gboolean dobr = FALSE;
533 if (doTopLeft==TRUE)
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)
544 starty = i;
545 dobr = TRUE;
546 break;
549 if (dobr == TRUE)
550 break;
552 dobr = FALSE;
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)
563 newendy = i + 1;
564 dobr = TRUE;
565 break;
568 if (dobr == TRUE)
569 break;
571 dobr = FALSE;
572 if (doTopLeft==TRUE)
574 for(i = 0; i < endx; i++)
576 int ni = i * nchan;
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]);
587 startx = i;
588 dobr = TRUE;
589 break;
592 if (dobr == TRUE)
593 break;
595 dobr = FALSE;
597 for(i = endx - 1; i >= startx; i--)
599 int ni = i * nchan;
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]);
610 newendx = i + 1;
611 dobr = TRUE;
612 break;
615 if (dobr == TRUE)
616 break;
620 * fprintf(stderr, "start:%dx%d end:%dx%d\n", startx, starty, newendx, newendy);
623 *w = newendx - startx;
624 *h = newendy - starty;
625 if (w==0 && h==0)
627 gdk_pixbuf_unref(pixbuf);
628 return(NULL);
631 GdkPixbuf *pixbuf2 = gdk_pixbuf_new_subpixbuf(pixbuf, startx, starty, *w, *h);
632 return (pixbuf2);
635 void sketchwidget_clear(SketchWidget * sk)
637 sketchundo_new(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);
648 if (ret == FALSE)
649 return (ret);
650 sketchwidget_clear(sk);
651 return (TRUE);
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,
661 0, 0,
662 0, 0,
663 sk->drawingarea->allocation.width,
664 sk->drawingarea->allocation.height);
666 if (pixbuf != NULL && GDK_IS_PIXBUF(pixbuf))
668 double w, h;
669 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf,
670 sk->drawingarea->allocation.width,
671 sk->drawingarea->allocation.height, &w,
672 &h, TRUE);
674 if (pixbuf2 && GDK_IS_PIXBUF(pixbuf2))
676 if (w > 0 && h > 0)
678 GdkPixbuf *pixbuf3 = gdk_pixbuf_copy(pixbuf2);
679 gtk_clipboard_set_image(clippy, pixbuf3);
680 g_object_unref(pixbuf3);
681 ret = TRUE;
683 g_object_unref(pixbuf2);
686 return (ret);
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;
706 if (w > 0 && h > 0)
708 sketchundo_new(sk);
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);
713 ret = TRUE;
715 g_object_unref(pixbuf);
717 return (ret);
720 GdkPixmap *sketchwidget_get_Pixmap(SketchWidget * sk)
722 g_assert(sk != NULL);
723 g_object_ref(sk->pixmap);
724 return (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);
767 result->sizex=sizex;
768 result->sizey=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;
795 return result;
799 * clean up the allocated memory
801 void sketchwidget_destroy(SketchWidget * sk)
803 g_assert(sk != NULL);
805 int i;
807 if (sk->undolist)
808 g_list_free(sk->undolist);
809 if (sk->pixmap)
810 g_object_unref(sk->pixmap);
811 if (sk->backpixmap)
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]);
817 if (sk->gc)
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);
824 g_free(sk);
827 void sketchwidget_set_shape(SketchWidget * sk, sketchShape sp)
829 g_assert(sk != NULL);
831 sk->shape = sp;
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);
869 if (sk->gc != NULL)
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);
887 #if 0
888 if (sk->backpixmap == NULL)
889 return; /*our widget not configured yet, configure will call this again */
891 if (sk->backstyle == sk->backstyle_currentimage)
892 return;
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);
897 if (sk->backgc)
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)
905 int i;
906 GdkColor tmpcol;
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)
930 int i;
931 GdkColor tmpcol;
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)
951 int i;
952 GdkColor tmpcol;
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)
973 GdkColor tmpcol;
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);
986 #endif
989 void sketchwidget_init_backpixmaps(SketchWidget * sk)
991 g_assert(sk != NULL);
993 int i;
995 sk->backpixmapheights[0] = 0; /*or TILE_SIZE*/
996 sk->backpixmapheights[1] = BACKGRAPH_LINE_HEIGHT + 1;
997 sk->backpixmapheights[2] = BACKGRAPH_GRAPH_WIDTH;
999 if (sk->backgc)
1000 gdk_gc_unref(sk->backgc);
1002 for(i = 0; i < SKETCHBACK_COUNT; i++)
1004 if (sk->backpixmapheights[i] == 0)
1005 continue;
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);
1019 /*lines*/
1020 GdkColor tmpcol;
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]);
1042 /*graph*/
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]);
1062 /*none*/
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]);
1095 #if 0
1096 /*important:sk->backgc should be configured for later use in expose()*/
1097 if (sk->border==TRUE)
1099 GdkColor bordercol;
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);
1107 /* don't.
1108 for(i = 0; i < SKETCHBACK_COUNT; i++)
1110 if (sk->backpixmapheights[i] == 0)
1111 continue;
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]);
1118 #endif
1121 void sketchwidget_set_brushsize(SketchWidget * sk, guint bsize)
1123 g_assert(sk != NULL);
1125 if (bsize < 0)
1126 bsize = 0;
1127 if (bsize == 0)
1129 sk->brush_radius = 0;
1130 sk->brush_size = 1;
1132 else
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;
1141 if (sk->gc)
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)
1154 gint x, y, w, h;
1156 if (x1 < x2)
1158 w = x2 - x1;
1159 x = x1;
1161 else
1163 w = x1 - x2;
1164 x = x2;
1167 if (y1 < y2)
1169 h = y2 - y1;
1170 y = y1;
1172 else
1174 h = y1 - y2;
1175 y = y2;
1178 res->x=x;
1179 res->y=y;
1180 res->width=w;
1181 res->height=h;
1184 void sketch_draw_brush(GtkWidget * widget, gdouble x, gdouble y, gdouble pressure, SketchWidget * sk)
1186 GdkRectangle update_rect;
1188 GdkGC *gc;
1189 int br, bs, oldbs;
1190 GdkColor oldcol;
1192 gc = sk->gc;
1193 br = sk->brush_radius;
1194 /* bs = sk->brush_size;*/
1196 if (pressure!=1)
1198 bs=sketch_calc_brush_size_from_pressure(pressure, sk);
1199 oldbs=sk->brush_size;
1200 oldcol=sk->brush_color;
1201 if (sk->gc)
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);
1211 else
1213 bs=sk->brush_size;
1216 if (bs == 1)
1218 update_rect.x = x;
1219 update_rect.y = y;
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);
1227 else
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);
1240 if (pressure!=1)
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");
1261 #endif
1262 sk->stupidflag=1;
1265 return FALSE;
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)
1276 sketchundo_new(sk);
1278 GdkRectangle update_rect;
1279 GdkGC *gc;
1280 int bs;
1282 gc = sk->gc;
1283 bs = sk->brush_size + 3;
1285 calc_rect(&update_rect, sk->start_x, sk->start_y, sk->cur_x, sk->cur_y, bs);
1287 if (sk->shiftmode)
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;
1295 else
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);
1301 else
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);
1306 else
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);
1324 sk->pressed=FALSE;
1326 sk->lastevent_x = 0;
1327 sk->lastevent_y = 0;
1329 sk->start_x = 0;
1330 sk->start_y = 0;
1332 sk->cur_x = 0;
1333 sk->cur_y = 0;
1335 sk->coords_valid = FALSE;
1338 return TRUE;
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");
1348 #endif
1349 sk->pressed=TRUE; /*first action after the stupid call wouldn't register otherwise*/
1350 sk->stupidflag=0;
1352 sk->coords_valid = FALSE;
1354 return TRUE;
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);
1363 #endif
1365 if (sk->callback_finger != NULL)
1367 gdouble pressure;
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);
1372 return TRUE;
1376 gdouble pressure;
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);
1382 #endif
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);
1394 #endif
1396 if (sk->shape == SKETCHSHAPE_FREEHAND)
1398 sketchundo_new(sk);
1399 sketch_draw_brush(widget, event->x, event->y, pressure, sk);
1401 sk->lastevent_x = event->x;
1402 sk->lastevent_y = event->y;
1404 else
1406 sk->start_x = event->x;
1407 sk->start_y = event->y;
1408 sk->coords_valid = TRUE;
1411 sk->pressed = TRUE;
1413 return 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);*/
1426 return(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");
1438 #endif
1439 sk->stupidflag++;
1440 return TRUE;
1443 if (sk->shape == SKETCHSHAPE_FREEHAND && sk->pressed == FALSE)
1445 #ifdef NOTIFY_COORDS
1446 fprintf(stderr, "IGN\n");
1447 #endif
1448 return TRUE;
1451 if (event->is_hint)
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);
1462 #endif
1464 else
1466 x = event->x;
1467 y = event->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);
1473 #endif
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)
1482 sk->start_x = x;
1483 sk->start_y = y;
1484 sk->coords_valid=TRUE;
1485 return TRUE;
1488 sk->cur_x = x;
1489 sk->cur_y = y;
1491 GdkRectangle update_rect;
1492 int bs;
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);
1501 return TRUE;
1504 int xb = x, yb = y;
1506 if (state & GDK_BUTTON1_MASK && sk->pixmap != NULL)
1508 sketchundo_new(sk);
1510 if (sk->lastevent_x == 0 && sk->lastevent_y == 0)
1512 sketch_draw_brush(widget, x, y, pressure, sk);
1514 else
1516 gint bs2, oldbs;
1517 GdkColor oldcol;
1519 if (pressure!=1)
1521 bs2=sketch_calc_brush_size_from_pressure(pressure, sk);
1522 oldbs=sk->brush_size;
1523 oldcol=sk->brush_color;
1524 if (sk->gc)
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);
1534 else
1536 bs2=sk->brush_size;
1539 gint x1, y1, w, h;
1540 gint bs = bs2 + 3;
1542 if (x < sk->lastevent_x)
1544 w = sk->lastevent_x - x;
1545 x1 = x;
1547 else
1549 w = x - sk->lastevent_x;
1550 x1 = sk->lastevent_x;
1553 if (y < sk->lastevent_y)
1555 h = sk->lastevent_y - y;
1556 y1 = y;
1558 else
1560 h = y - sk->lastevent_y;
1561 y1 = sk->lastevent_y;
1564 if (x1 >= bs)
1565 x1 -= bs;
1566 else
1567 x1 = 0;
1569 if (y1 >= bs)
1570 y1 -= bs;
1571 else
1572 y1 = 0;
1575 nice debug code
1576 GdkColor col=sketchwidget_get_brushcolor(sk);
1577 GdkColor col2, col3;
1578 col2.red=col2.green=0;
1579 col2.blue=255*255;
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;
1615 return TRUE;
1618 gboolean sketch_configure(GtkWidget * widget, GdkEventConfigure * event, SketchWidget * sk)
1620 if (sk->backpixmap)
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);
1627 if (sk->pixmap)
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);
1633 if (sk->gc)
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);
1644 return TRUE;
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)],
1661 sk->backpixmap,
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;
1683 * midy=endy;
1686 int i;
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);
1694 * fill the rest
1696 if (midy < endy)
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);
1702 #if 0
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);
1721 #endif
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;
1731 int bs;
1732 bs = sk->brush_size + 3;
1734 calc_rect(&update_rect, sk->start_x, sk->start_y, sk->cur_x, sk->cur_y, bs);
1735 if (sk->shiftmode)
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;
1743 else
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);
1749 else
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);
1754 else
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);
1769 return FALSE;