Maemopad+ 0.37 released
[maemopadplus.git] / src / ui / sketchwidget.c
blob258d7f0e8727aba2aca9491afb95caf6a66a2a31
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/interface.h>
23 #include <ui/sketchwidget.h>
24 #include <config.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;
48 guint maxr = 32767;
49 guint maxg = 32767;
50 guint maxb = 32767;
52 if (maxr<0) maxr=0;
53 if (maxg<0) maxg=0;
54 if (maxb<0) maxb=0;
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)
61 maxr=65535;
62 maxg=65535;
63 maxb=65535;
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);
72 #endif
74 GdkColormap *colormap = gdk_window_get_colormap(sk->drawingarea->window);
76 int i;
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);
88 #endif
92 GdkColor sketch_calc_brush_color_from_pressure(gdouble pressure, SketchWidget * sk)
94 GdkColor ret=sk->brush_color;
95 int i;
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);
105 #endif
106 break;
110 return(ret);
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;
133 *x = t * 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);
148 * internal
150 void sketchundo_free_list(GList * ulist)
152 GList *li = ulist;
154 while(li != NULL)
156 SketchWidgetUndo *un = li->data;
158 if (un != NULL)
160 GSList *tl = un->tileList;
162 while(tl != NULL)
164 if (tl->data != NULL)
166 SketchWidgetTile *ti = (SketchWidgetTile *) tl->data;
168 if (ti)
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*/
182 #if 0
183 g_list_free(ulist);
184 #endif
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");
213 return;
216 /* g_assert(sk->undocurbuffer != NULL);*/
219 * free structs ahead of undocurrent here
221 if (sk->undocurrent > 0)
223 #if 1
224 GList *startsnip = sk->undolist;
225 GList *endsnip = g_list_nth(sk->undolist, sk->undocurrent);
227 if (endsnip != NULL)
229 sk->undolist=endsnip;
230 if (endsnip->prev!=NULL) (endsnip->prev)->next=NULL;
232 else
234 sk->undolist = NULL;
237 fixme:crash--see comment in func. probably due to bad "snipping" somewhere above
239 sketchundo_free_list(startsnip);
240 #endif
241 sk->undocurrent = 0;
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;
263 while(tl!=NULL)
265 SketchWidgetTile *ti = (SketchWidgetTile *) tl->data;
266 if (ti!=NULL)
268 guint sx, sy;
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);
273 tl=g_slist_next(tl);
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");
288 * internal
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*/
296 return;
298 guint sx, sy;
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);
308 t->tileid = tileid;
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);
338 int i, j;
340 #if 1
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);
351 #else
352 for(i=0;i<h;i++)
353 for(j=0;j<w;j++)
355 guint tileid=tile_getid(rx+j, ry+i);
356 sketchundo_savetile(sk, tileid);
358 #endif
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;
370 while(tl != NULL)
372 SketchWidgetTile *t = (SketchWidgetTile *) (tl->data);
373 GdkPixmap *ourpix;
374 if (isredo==TRUE) ourpix=t->tiledata_new;
375 else ourpix=t->tiledata;
377 if (ourpix)
379 guint x, y;
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);
386 else
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);
408 return (FALSE);
411 SketchWidgetUndo *un = g_list_nth_data(sk->undolist, sk->undocurrent);
413 if (un == NULL)
414 return (FALSE);
416 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);
427 return (TRUE);
430 gboolean sketchwidget_redo(SketchWidget * sk)
432 g_assert(sk != NULL);
434 if (sk->undocurrent < 1)
436 sketchwidget_invoke_redocallback(sk, FALSE);
437 return (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);
445 if (un == NULL)
447 fprintf(stderr, "REDO ERR!\n");
448 return (FALSE);
451 sk->undocurrent--;
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);
462 return (TRUE);
465 void sketchwidget_wipe_undo(SketchWidget * sk)
467 if (sk->undocurbuffer)
468 sketchundo_commit(sk); /*get rid of undocurbuffer */
469 sk->undocurrent = 0;
471 sketchundo_free_list(sk->undolist);
472 sk->undolist = NULL;
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;
520 endx = totalw;
521 endy = totalh;
523 guint newendy = endy, newendx = endx;
524 int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
525 int nchan = gdk_pixbuf_get_n_channels(pixbuf);
526 guchar *pixels, *p;
528 pixels = gdk_pixbuf_get_pixels(pixbuf);
531 * fprintf(stderr, "nchan=%d\n", nchan);
534 gboolean dobr = FALSE;
535 if (doTopLeft==TRUE)
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)
546 starty = i;
547 dobr = TRUE;
548 break;
551 if (dobr == TRUE)
552 break;
554 dobr = FALSE;
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)
565 newendy = i + 1;
566 dobr = TRUE;
567 break;
570 if (dobr == TRUE)
571 break;
573 dobr = FALSE;
574 if (doTopLeft==TRUE)
576 for(i = 0; i < endx; i++)
578 int ni = i * nchan;
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]);
589 startx = i;
590 dobr = TRUE;
591 break;
594 if (dobr == TRUE)
595 break;
597 dobr = FALSE;
599 for(i = endx - 1; i >= startx; i--)
601 int ni = i * nchan;
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]);
612 newendx = i + 1;
613 dobr = TRUE;
614 break;
617 if (dobr == TRUE)
618 break;
622 * fprintf(stderr, "start:%dx%d end:%dx%d\n", startx, starty, newendx, newendy);
625 *w = newendx - startx;
626 *h = newendy - starty;
627 if (w==0 && h==0)
629 gdk_pixbuf_unref(pixbuf);
630 return(NULL);
633 GdkPixbuf *pixbuf2 = gdk_pixbuf_new_subpixbuf(pixbuf, startx, starty, *w, *h);
634 return (pixbuf2);
637 void sketchwidget_clear(SketchWidget * sk)
639 sketchundo_new(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);
650 if (ret == FALSE)
651 return (ret);
652 sketchwidget_clear(sk);
653 return (TRUE);
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,
663 0, 0,
664 0, 0,
665 sk->drawingarea->allocation.width,
666 sk->drawingarea->allocation.height);
668 if (pixbuf != NULL && GDK_IS_PIXBUF(pixbuf))
670 double w, h;
671 GdkPixbuf *pixbuf2 = sketchwidget_trim_image(pixbuf,
672 sk->drawingarea->allocation.width,
673 sk->drawingarea->allocation.height, &w,
674 &h, TRUE);
676 if (pixbuf2 && GDK_IS_PIXBUF(pixbuf2))
678 if (w > 0 && h > 0)
680 GdkPixbuf *pixbuf3 = gdk_pixbuf_copy(pixbuf2);
681 gtk_clipboard_set_image(clippy, pixbuf3);
682 g_object_unref(pixbuf3);
683 ret = TRUE;
685 g_object_unref(pixbuf2);
688 return (ret);
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;
708 if (w > 0 && h > 0)
710 sketchundo_new(sk);
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);
715 ret = TRUE;
717 g_object_unref(pixbuf);
719 return (ret);
722 GdkPixmap *sketchwidget_get_Pixmap(SketchWidget * sk)
724 g_assert(sk != NULL);
725 g_object_ref(sk->pixmap);
726 return (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);
766 #endif
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);
772 result->sizex=sizex;
773 result->sizey=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;
800 return result;
804 * clean up the allocated memory
806 void sketchwidget_destroy(SketchWidget * sk)
808 g_assert(sk != NULL);
810 int i;
812 if (sk->undolist)
813 g_list_free(sk->undolist);
814 if (sk->pixmap)
815 g_object_unref(sk->pixmap);
816 if (sk->backpixmap)
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]);
822 if (sk->gc)
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);
829 g_free(sk);
832 void sketchwidget_set_shape(SketchWidget * sk, sketchShape sp)
834 g_assert(sk != NULL);
836 sk->shape = sp;
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);
874 if (sk->gc != NULL)
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);
892 #if 0
893 if (sk->backpixmap == NULL)
894 return; /*our widget not configured yet, configure will call this again */
896 if (sk->backstyle == sk->backstyle_currentimage)
897 return;
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);
902 if (sk->backgc)
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)
910 int i;
911 GdkColor tmpcol;
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)
935 int i;
936 GdkColor tmpcol;
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)
956 int i;
957 GdkColor tmpcol;
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)
978 GdkColor tmpcol;
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);
991 #endif
994 void sketchwidget_init_backpixmaps(SketchWidget * sk)
996 g_assert(sk != NULL);
998 int i;
1000 sk->backpixmapheights[0] = 0; /*or TILE_SIZE*/
1001 sk->backpixmapheights[1] = BACKGRAPH_LINE_HEIGHT + 1;
1002 sk->backpixmapheights[2] = BACKGRAPH_GRAPH_WIDTH;
1004 if (sk->backgc)
1005 gdk_gc_unref(sk->backgc);
1007 for(i = 0; i < SKETCHBACK_COUNT; i++)
1009 if (sk->backpixmapheights[i] == 0)
1010 continue;
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);
1024 /*lines*/
1025 GdkColor tmpcol;
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]);
1047 /*graph*/
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]);
1067 /*none*/
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]);
1100 #if 0
1101 /*important:sk->backgc should be configured for later use in expose()*/
1102 if (sk->border==TRUE)
1104 GdkColor bordercol;
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);
1112 /* don't.
1113 for(i = 0; i < SKETCHBACK_COUNT; i++)
1115 if (sk->backpixmapheights[i] == 0)
1116 continue;
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]);
1123 #endif
1126 void sketchwidget_set_brushsize(SketchWidget * sk, guint bsize)
1128 g_assert(sk != NULL);
1130 if (bsize < 0)
1131 bsize = 0;
1132 if (bsize == 0)
1134 sk->brush_radius = 0;
1135 sk->brush_size = 1;
1137 else
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;
1146 if (sk->gc)
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)
1159 gint x, y, w, h;
1161 if (x1 < x2)
1163 w = x2 - x1;
1164 x = x1;
1166 else
1168 w = x1 - x2;
1169 x = x2;
1172 if (y1 < y2)
1174 h = y2 - y1;
1175 y = y1;
1177 else
1179 h = y1 - y2;
1180 y = y2;
1183 res->x=x;
1184 res->y=y;
1185 res->width=w;
1186 res->height=h;
1189 void sketch_draw_brush(GtkWidget * widget, gdouble x, gdouble y, gdouble pressure, SketchWidget * sk)
1191 GdkRectangle update_rect;
1193 GdkGC *gc;
1194 int br, bs, oldbs;
1195 GdkColor oldcol;
1197 gc = sk->gc;
1198 br = sk->brush_radius;
1199 /* bs = sk->brush_size;*/
1201 if (pressure!=1)
1203 bs=sketch_calc_brush_size_from_pressure(pressure, sk);
1204 oldbs=sk->brush_size;
1205 oldcol=sk->brush_color;
1206 if (sk->gc)
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);
1216 else
1218 bs=sk->brush_size;
1221 if (bs == 1)
1223 update_rect.x = x;
1224 update_rect.y = y;
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);
1232 else
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);
1245 if (pressure!=1)
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");
1266 #endif
1267 sk->stupidflag=1;
1270 return FALSE;
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)
1281 sketchundo_new(sk);
1283 GdkRectangle update_rect;
1284 GdkGC *gc;
1285 int bs;
1287 gc = sk->gc;
1288 bs = sk->brush_size + 3;
1290 calc_rect(&update_rect, sk->start_x, sk->start_y, sk->cur_x, sk->cur_y, bs);
1292 if (sk->shiftmode)
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;
1300 else
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);
1306 else
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);
1311 else
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);
1329 sk->pressed=FALSE;
1331 sk->lastevent_x = 0;
1332 sk->lastevent_y = 0;
1334 sk->start_x = 0;
1335 sk->start_y = 0;
1337 sk->cur_x = 0;
1338 sk->cur_y = 0;
1340 sk->coords_valid = FALSE;
1343 return TRUE;
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");
1353 #endif
1354 sk->pressed=TRUE; /*first action after the stupid call wouldn't register otherwise*/
1355 sk->stupidflag=0;
1357 sk->coords_valid = FALSE;
1359 return TRUE;
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);
1368 #endif
1370 if (sk->callback_finger != NULL)
1372 gdouble pressure;
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);
1377 return TRUE;
1381 gdouble pressure;
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);
1388 #endif
1389 if (sk->callback_finger != NULL)
1390 (sk->callback_finger) (sk, (int)event->x, (int)event->y, pressure, sk->callback_finger_data);
1391 return TRUE;
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);
1402 #endif
1404 if (sk->shape == SKETCHSHAPE_FREEHAND)
1406 sketchundo_new(sk);
1407 sketch_draw_brush(widget, event->x, event->y, pressure, sk);
1409 sk->lastevent_x = event->x;
1410 sk->lastevent_y = event->y;
1412 else
1414 sk->start_x = event->x;
1415 sk->start_y = event->y;
1416 sk->coords_valid = TRUE;
1419 sk->pressed = TRUE;
1421 return 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);*/
1434 return(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");
1446 #endif
1447 sk->stupidflag++;
1448 return TRUE;
1451 if (sk->shape == SKETCHSHAPE_FREEHAND && sk->pressed == FALSE)
1453 #ifdef NOTIFY_COORDS
1454 fprintf(stderr, "IGN\n");
1455 #endif
1456 return TRUE;
1459 if (event->is_hint)
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);
1470 #endif
1472 else
1474 x = event->x;
1475 y = event->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);
1481 #endif
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)
1490 sk->start_x = x;
1491 sk->start_y = y;
1492 sk->coords_valid=TRUE;
1493 return TRUE;
1496 sk->cur_x = x;
1497 sk->cur_y = y;
1499 GdkRectangle update_rect;
1500 int bs;
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);
1509 return TRUE;
1512 int xb = x, yb = y;
1514 if (state & GDK_BUTTON1_MASK && sk->pixmap != NULL)
1516 sketchundo_new(sk);
1518 if (sk->lastevent_x == 0 && sk->lastevent_y == 0)
1520 sketch_draw_brush(widget, x, y, pressure, sk);
1522 else
1524 gint bs2, oldbs;
1525 GdkColor oldcol;
1527 if (pressure!=1)
1529 bs2=sketch_calc_brush_size_from_pressure(pressure, sk);
1530 oldbs=sk->brush_size;
1531 oldcol=sk->brush_color;
1532 if (sk->gc)
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);
1542 else
1544 bs2=sk->brush_size;
1547 gint x1, y1, w, h;
1548 gint bs = bs2 + 3;
1550 if (x < sk->lastevent_x)
1552 w = sk->lastevent_x - x;
1553 x1 = x;
1555 else
1557 w = x - sk->lastevent_x;
1558 x1 = sk->lastevent_x;
1561 if (y < sk->lastevent_y)
1563 h = sk->lastevent_y - y;
1564 y1 = y;
1566 else
1568 h = y - sk->lastevent_y;
1569 y1 = sk->lastevent_y;
1572 if (x1 >= bs)
1573 x1 -= bs;
1574 else
1575 x1 = 0;
1577 if (y1 >= bs)
1578 y1 -= bs;
1579 else
1580 y1 = 0;
1583 nice debug code
1584 GdkColor col=sketchwidget_get_brushcolor(sk);
1585 GdkColor col2, col3;
1586 col2.red=col2.green=0;
1587 col2.blue=255*255;
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;
1623 return TRUE;
1626 gboolean sketch_configure(GtkWidget * widget, GdkEventConfigure * event, SketchWidget * sk)
1628 if (sk->backpixmap)
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);
1635 if (sk->pixmap)
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);
1641 if (sk->gc)
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);
1652 return TRUE;
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)],
1669 sk->backpixmap,
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;
1691 * midy=endy;
1694 int i;
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);
1702 * fill the rest
1704 if (midy < endy)
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);
1710 #if 0
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);
1729 #endif
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;
1739 int bs;
1740 bs = sk->brush_size + 3;
1742 calc_rect(&update_rect, sk->start_x, sk->start_y, sk->cur_x, sk->cur_y, bs);
1743 if (sk->shiftmode)
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;
1751 else
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);
1757 else
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);
1762 else
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);
1777 return FALSE;