8 #include <libgnomecanvas/libgnomecanvas.h>
9 #include <gdk/gdkkeysyms.h>
13 #include "xo-interface.h"
14 #include "xo-support.h"
15 #include "xo-callbacks.h"
19 #include "xo-shapes.h"
21 // some global constants
23 guint predef_colors_rgba[COLOR_MAX] =
24 { 0x000000ff, 0x3333ccff, 0xff0000ff, 0x008000ff,
25 0x808080ff, 0x00c0ffff, 0x00ff00ff, 0xff00ffff,
26 0xff8000ff, 0xffff00ff, 0xffffffff };
28 guint predef_bgcolors_rgba[COLOR_MAX] = // meaningless ones set to white
29 { 0xffffffff, 0xa0e8ffff, 0xffc0d4ff, 0x80ffc0ff,
30 0xffffffff, 0xa0e8ffff, 0x80ffc0ff, 0xffc0d4ff,
31 0xffc080ff, 0xffff80ff, 0xffffffff };
33 double predef_thickness[NUM_STROKE_TOOLS][THICKNESS_MAX] =
34 { { 0.42, 0.85, 1.41, 2.26, 5.67 }, // pen thicknesses = 0.15, 0.3, 0.5, 0.8, 2 mm
35 { 2.83, 2.83, 8.50, 19.84, 19.84 }, // eraser thicknesses = 1, 3, 7 mm
36 { 2.83, 2.83, 8.50, 19.84, 19.84 }, // highlighter thicknesses = 1, 3, 7 mm
39 // some manipulation functions
41 struct Page *new_page(struct Page *template)
43 struct Page *pg = (struct Page *) g_memdup(template, sizeof(struct Page));
44 struct Layer *l = g_new(struct Layer, 1);
48 pg->layers = g_list_append(NULL, l);
50 pg->bg = (struct Background *)g_memdup(template->bg, sizeof(struct Background));
51 pg->bg->canvas_item = NULL;
52 if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
53 gdk_pixbuf_ref(pg->bg->pixbuf);
54 refstring_ref(pg->bg->filename);
56 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
57 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
58 make_page_clipbox(pg);
60 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
61 pg->group, gnome_canvas_group_get_type(), NULL);
66 /* Create a page from a background.
67 Note: bg should be an UNREFERENCED background.
68 If needed, first duplicate it and increase the refcount of the pixbuf.
70 struct Page *new_page_with_bg(struct Background *bg, double width, double height)
72 struct Page *pg = g_new(struct Page, 1);
73 struct Layer *l = g_new(struct Layer, 1);
77 pg->layers = g_list_append(NULL, l);
80 pg->bg->canvas_item = NULL;
83 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
84 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
85 make_page_clipbox(pg);
87 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
88 pg->group, gnome_canvas_group_get_type(), NULL);
93 void realloc_cur_path(int n)
95 if (n <= ui.cur_path_storage_alloc) return;
96 ui.cur_path_storage_alloc = n+100;
97 ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+100)*sizeof(double));
100 void realloc_cur_widths(int n)
102 if (n <= ui.cur_widths_storage_alloc) return;
103 ui.cur_widths_storage_alloc = n+100;
104 ui.cur_widths = g_realloc(ui.cur_widths, (n+100)*sizeof(double));
107 // undo utility functions
109 void prepare_new_undo(void)
112 // add a new UndoItem on the stack
113 u = (struct UndoItem *)g_malloc(sizeof(struct UndoItem));
121 void clear_redo_stack(void)
125 struct UndoErasureData *erasure;
128 /* Warning: the redo items might reference items from past redo entries,
129 which have been destroyed before them. Be careful! As a rule, it's
130 safe to destroy data which has been created at the current history step,
131 it's unsafe to refer to any data from previous history steps */
134 if (redo->type == ITEM_STROKE) {
135 gnome_canvas_points_free(redo->item->path);
136 if (redo->item->brush.variable_width) g_free(redo->item->widths);
138 /* the strokes are unmapped, so there are no associated canvas items */
140 else if (redo->type == ITEM_TEXT) {
141 g_free(redo->item->text);
142 g_free(redo->item->font_name);
145 else if (redo->type == ITEM_ERASURE || redo->type == ITEM_RECOGNIZER) {
146 for (list = redo->erasurelist; list!=NULL; list=list->next) {
147 erasure = (struct UndoErasureData *)list->data;
148 for (repl = erasure->replacement_items; repl!=NULL; repl=repl->next) {
149 it = (struct Item *)repl->data;
150 gnome_canvas_points_free(it->path);
151 if (it->brush.variable_width) g_free(it->widths);
154 g_list_free(erasure->replacement_items);
157 g_list_free(redo->erasurelist);
159 else if (redo->type == ITEM_NEW_BG_ONE || redo->type == ITEM_NEW_BG_RESIZE
160 || redo->type == ITEM_NEW_DEFAULT_BG) {
161 if (redo->bg->type == BG_PIXMAP || redo->bg->type == BG_PDF) {
162 if (redo->bg->pixbuf!=NULL) gdk_pixbuf_unref(redo->bg->pixbuf);
163 refstring_unref(redo->bg->filename);
167 else if (redo->type == ITEM_NEW_PAGE) {
168 redo->page->group = NULL;
169 delete_page(redo->page);
171 else if (redo->type == ITEM_MOVESEL || redo->type == ITEM_REPAINTSEL) {
172 g_list_free(redo->itemlist); g_list_free(redo->auxlist);
174 else if (redo->type == ITEM_RESIZESEL) {
175 g_list_free(redo->itemlist);
177 else if (redo->type == ITEM_PASTE) {
178 for (list = redo->itemlist; list!=NULL; list=list->next) {
179 it = (struct Item *)list->data;
180 if (it->type == ITEM_STROKE) {
181 gnome_canvas_points_free(it->path);
182 if (it->brush.variable_width) g_free(it->widths);
186 g_list_free(redo->itemlist);
188 else if (redo->type == ITEM_NEW_LAYER) {
191 else if (redo->type == ITEM_TEXT_EDIT || redo->type == ITEM_TEXT_ATTRIB) {
193 if (redo->type == ITEM_TEXT_ATTRIB) g_free(redo->brush);
200 update_undo_redo_enabled();
203 void clear_undo_stack(void)
207 struct UndoErasureData *erasure;
210 // for strokes, items are already in the journal, so we don't free them
211 // for erasures, we need to free the dead items
212 if (undo->type == ITEM_ERASURE || undo->type == ITEM_RECOGNIZER) {
213 for (list = undo->erasurelist; list!=NULL; list=list->next) {
214 erasure = (struct UndoErasureData *)list->data;
215 if (erasure->item->type == ITEM_STROKE) {
216 gnome_canvas_points_free(erasure->item->path);
217 if (erasure->item->brush.variable_width) g_free(erasure->item->widths);
219 if (erasure->item->type == ITEM_TEXT)
220 { g_free(erasure->item->text); g_free(erasure->item->font_name); }
221 g_free(erasure->item);
222 g_list_free(erasure->replacement_items);
225 g_list_free(undo->erasurelist);
227 else if (undo->type == ITEM_NEW_BG_ONE || undo->type == ITEM_NEW_BG_RESIZE
228 || undo->type == ITEM_NEW_DEFAULT_BG) {
229 if (undo->bg->type == BG_PIXMAP || undo->bg->type == BG_PDF) {
230 if (undo->bg->pixbuf!=NULL) gdk_pixbuf_unref(undo->bg->pixbuf);
231 refstring_unref(undo->bg->filename);
235 else if (undo->type == ITEM_MOVESEL || undo->type == ITEM_REPAINTSEL) {
236 g_list_free(undo->itemlist); g_list_free(undo->auxlist);
238 else if (undo->type == ITEM_RESIZESEL) {
239 g_list_free(undo->itemlist);
241 else if (undo->type == ITEM_PASTE) {
242 g_list_free(undo->itemlist);
244 else if (undo->type == ITEM_DELETE_LAYER) {
245 undo->layer->group = NULL;
246 delete_layer(undo->layer);
248 else if (undo->type == ITEM_DELETE_PAGE) {
249 undo->page->group = NULL;
250 delete_page(undo->page);
252 else if (undo->type == ITEM_TEXT_EDIT || undo->type == ITEM_TEXT_ATTRIB) {
254 if (undo->type == ITEM_TEXT_ATTRIB) g_free(undo->brush);
261 update_undo_redo_enabled();
264 // free data structures
266 void delete_journal(struct Journal *j)
268 while (j->pages!=NULL) {
269 delete_page((struct Page *)j->pages->data);
270 j->pages = g_list_delete_link(j->pages, j->pages);
274 void delete_page(struct Page *pg)
278 while (pg->layers!=NULL) {
279 l = (struct Layer *)pg->layers->data;
282 pg->layers = g_list_delete_link(pg->layers, pg->layers);
284 if (pg->group!=NULL) gtk_object_destroy(GTK_OBJECT(pg->group));
285 // this also destroys the background's canvas items
286 if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
287 if (pg->bg->pixbuf != NULL) gdk_pixbuf_unref(pg->bg->pixbuf);
288 if (pg->bg->filename != NULL) refstring_unref(pg->bg->filename);
294 void delete_layer(struct Layer *l)
298 while (l->items!=NULL) {
299 item = (struct Item *)l->items->data;
300 if (item->type == ITEM_STROKE && item->path != NULL)
301 gnome_canvas_points_free(item->path);
302 if (item->type == ITEM_TEXT) {
303 g_free(item->font_name); g_free(item->text);
305 // don't need to delete the canvas_item, as it's part of the group destroyed below
307 l->items = g_list_delete_link(l->items, l->items);
309 if (l->group!= NULL) gtk_object_destroy(GTK_OBJECT(l->group));
313 // referenced strings
315 struct Refstring *new_refstring(const char *s)
317 struct Refstring *rs = g_new(struct Refstring, 1);
319 if (s!=NULL) rs->s = g_strdup(s);
325 struct Refstring *refstring_ref(struct Refstring *rs)
331 void refstring_unref(struct Refstring *rs)
335 if (rs->s!=NULL) g_free(rs->s);
336 if (rs->aux!=NULL) g_free(rs->aux);
342 // some helper functions
344 void get_pointer_coords(GdkEvent *event, gdouble *ret)
347 gdk_event_get_coords(event, &x, &y);
348 gnome_canvas_window_to_world(canvas, x, y, ret, ret+1);
349 ret[0] -= ui.cur_page->hoffset;
350 ret[1] -= ui.cur_page->voffset;
353 void fix_xinput_coords(GdkEvent *event)
355 double *axes, *px, *py, axis_width;
357 int wx, wy, sx, sy, ix, iy;
359 if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
360 axes = event->button.axes;
361 px = &(event->button.x);
362 py = &(event->button.y);
363 device = event->button.device;
365 else if (event->type == GDK_MOTION_NOTIFY) {
366 axes = event->motion.axes;
367 px = &(event->motion.x);
368 py = &(event->motion.y);
369 device = event->motion.device;
371 else return; // nothing we know how to do
373 gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
375 #ifdef ENABLE_XINPUT_BUGFIX
376 // fix broken events with the core pointer's location
377 if (!finite(axes[0]) || !finite(axes[1]) || (axes[0]==0. && axes[1]==0.)) {
378 gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
383 gdk_window_get_origin(GTK_WIDGET(canvas)->window, &wx, &wy);
384 axis_width = device->axes[0].max - device->axes[0].min;
385 if (axis_width>EPSILON)
386 *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
387 axis_width = device->axes[1].max - device->axes[1].min;
388 if (axis_width>EPSILON)
389 *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
392 if (!finite(*px) || !finite(*py) || (*px==0. && *py==0.)) {
393 gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
398 /* with GTK+ 2.16 or earlier, the event comes from the parent gdkwindow
399 and so needs to be adjusted for scrolling */
400 if (gtk_major_version == 2 && gtk_minor_version <= 16) {
404 /* with GTK+ 2.17, events come improperly translated, and the event's
405 GdkWindow isn't even the same for ButtonDown as for MotionNotify... */
406 if (gtk_major_version == 2 && gtk_minor_version == 17) { // GTK+ 2.17 issues !!
407 gdk_window_get_position(GTK_WIDGET(canvas)->window, &wx, &wy);
415 double get_pressure_multiplier(GdkEvent *event)
419 if (event->button.device == gdk_device_get_core_pointer()
420 || event->button.device->num_axes <= 2) return 1.0;
422 rawpressure = event->button.axes[2]/(event->button.device->axes[2].max - event->button.device->axes[2].min);
424 return ((1-rawpressure)*ui.width_minimum_multiplier + rawpressure*ui.width_maximum_multiplier);
427 void update_item_bbox(struct Item *item)
432 if (item->type == ITEM_STROKE) {
433 item->bbox.left = item->bbox.right = item->path->coords[0];
434 item->bbox.top = item->bbox.bottom = item->path->coords[1];
435 for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
437 if (p[0] < item->bbox.left) item->bbox.left = p[0];
438 if (p[0] > item->bbox.right) item->bbox.right = p[0];
439 if (p[1] < item->bbox.top) item->bbox.top = p[1];
440 if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
443 if (item->type == ITEM_TEXT && item->canvas_item!=NULL) {
445 g_object_get(item->canvas_item, "text_width", &w, "text_height", &h, NULL);
446 item->bbox.right = item->bbox.left + w;
447 item->bbox.bottom = item->bbox.top + h;
451 void make_page_clipbox(struct Page *pg)
453 GnomeCanvasPathDef *pg_clip;
455 pg_clip = gnome_canvas_path_def_new_sized(4);
456 gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
457 gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
458 gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
459 gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
460 gnome_canvas_path_def_closepath(pg_clip);
461 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
462 gnome_canvas_path_def_unref(pg_clip);
465 void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item)
467 PangoFontDescription *font_desc;
468 GnomeCanvasPoints points;
471 if (item->type == ITEM_STROKE) {
472 if (!item->brush.variable_width)
473 item->canvas_item = gnome_canvas_item_new(group,
474 gnome_canvas_line_get_type(), "points", item->path,
475 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
476 "fill-color-rgba", item->brush.color_rgba,
477 "width-units", item->brush.thickness, NULL);
479 item->canvas_item = gnome_canvas_item_new(group,
480 gnome_canvas_group_get_type(), NULL);
481 points.num_points = 2;
482 points.ref_count = 1;
483 for (j = 0; j < item->path->num_points-1; j++) {
484 points.coords = item->path->coords+2*j;
485 gnome_canvas_item_new((GnomeCanvasGroup *) item->canvas_item,
486 gnome_canvas_line_get_type(), "points", &points,
487 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
488 "fill-color-rgba", item->brush.color_rgba,
489 "width-units", item->widths[j], NULL);
493 if (item->type == ITEM_TEXT) {
494 font_desc = pango_font_description_from_string(item->font_name);
495 pango_font_description_set_absolute_size(font_desc,
496 item->font_size*ui.zoom*PANGO_SCALE);
497 item->canvas_item = gnome_canvas_item_new(group,
498 gnome_canvas_text_get_type(),
499 "x", item->bbox.left, "y", item->bbox.top, "anchor", GTK_ANCHOR_NW,
500 "font-desc", font_desc, "fill-color-rgba", item->brush.color_rgba,
501 "text", item->text, NULL);
502 update_item_bbox(item);
506 void make_canvas_items(void)
511 GList *pagelist, *layerlist, *itemlist;
513 for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
514 pg = (struct Page *)pagelist->data;
515 if (pg->group == NULL) {
516 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
517 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
518 make_page_clipbox(pg);
520 if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
521 for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
522 l = (struct Layer *)layerlist->data;
523 if (l->group == NULL)
524 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
525 pg->group, gnome_canvas_group_get_type(), NULL);
526 for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
527 item = (struct Item *)itemlist->data;
528 if (item->canvas_item == NULL)
529 make_canvas_item_one(l->group, item);
535 void update_canvas_bg(struct Page *pg)
537 GnomeCanvasGroup *group;
538 GnomeCanvasPoints *seg;
539 GdkPixbuf *scaled_pix;
543 gboolean is_well_scaled;
545 if (pg->bg->canvas_item != NULL)
546 gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
547 pg->bg->canvas_item = NULL;
549 if (pg->bg->type == BG_SOLID)
551 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
552 gnome_canvas_group_get_type(), NULL);
553 group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
554 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
555 gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
556 "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
557 "fill-color-rgba", pg->bg->color_rgba, NULL);
558 if (pg->bg->ruling == RULING_NONE) return;
559 seg = gnome_canvas_points_new(2);
561 if (pg->bg->ruling == RULING_GRAPH) {
562 pt[1] = 0; pt[3] = pg->height;
563 for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
565 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
566 "points", seg, "fill-color-rgba", RULING_COLOR,
567 "width-units", RULING_THICKNESS, NULL);
569 pt[0] = 0; pt[2] = pg->width;
570 for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
572 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
573 "points", seg, "fill-color-rgba", RULING_COLOR,
574 "width-units", RULING_THICKNESS, NULL);
576 gnome_canvas_points_free(seg);
579 pt[0] = 0; pt[2] = pg->width;
580 for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
582 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
583 "points", seg, "fill-color-rgba", RULING_COLOR,
584 "width-units", RULING_THICKNESS, NULL);
586 if (pg->bg->ruling == RULING_LINED) {
587 pt[0] = pt[2] = RULING_LEFTMARGIN;
588 pt[1] = 0; pt[3] = pg->height;
589 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
590 "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
591 "width-units", RULING_THICKNESS, NULL);
593 gnome_canvas_points_free(seg);
597 if (pg->bg->type == BG_PIXMAP)
599 pg->bg->pixbuf_scale = 0;
600 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
601 gnome_canvas_pixbuf_get_type(),
602 "pixbuf", pg->bg->pixbuf,
603 "width", pg->width, "height", pg->height,
604 "width-set", TRUE, "height-set", TRUE,
606 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
609 if (pg->bg->type == BG_PDF)
611 if (pg->bg->pixbuf == NULL) return;
612 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
613 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
615 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
616 gnome_canvas_pixbuf_get_type(),
617 "pixbuf", pg->bg->pixbuf,
618 "width-in-pixels", TRUE, "height-in-pixels", TRUE,
621 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
622 gnome_canvas_pixbuf_get_type(),
623 "pixbuf", pg->bg->pixbuf,
624 "width", pg->width, "height", pg->height,
625 "width-set", TRUE, "height-set", TRUE,
627 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
631 gboolean is_visible(struct Page *pg)
633 GtkAdjustment *v_adj;
636 if (!ui.view_continuous) return (pg == ui.cur_page);
637 v_adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
638 ytop = v_adj->value/ui.zoom;
639 ybot = (v_adj->value + v_adj->page_size) / ui.zoom;
640 return (MAX(ytop, pg->voffset) < MIN(ybot, pg->voffset+pg->height));
643 void rescale_bg_pixmaps(void)
648 gboolean is_well_scaled;
649 gdouble zoom_to_request;
651 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
652 pg = (struct Page *)pglist->data;
653 // in progressive mode we scale only visible pages
654 if (ui.progressive_bg && !is_visible(pg)) continue;
656 if (pg->bg->type == BG_PIXMAP && pg->bg->canvas_item!=NULL) { // do the rescaling ourselves
657 g_object_get(G_OBJECT(pg->bg->canvas_item), "pixbuf", &pix, NULL);
658 if (pix!=pg->bg->pixbuf)
659 gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
660 pg->bg->pixbuf_scale = 0;
662 if (pg->bg->type == BG_PDF) {
663 // make pixmap scale to correct size if current one is wrong
664 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
665 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
666 if (pg->bg->canvas_item != NULL && !is_well_scaled) {
667 g_object_get(pg->bg->canvas_item, "width-in-pixels", &is_well_scaled, NULL);
669 gnome_canvas_item_set(pg->bg->canvas_item,
670 "width", pg->width, "height", pg->height,
671 "width-in-pixels", FALSE, "height-in-pixels", FALSE,
672 "width-set", TRUE, "height-set", TRUE,
675 // request an asynchronous update to a better pixmap if needed
676 zoom_to_request = MIN(ui.zoom, MAX_SAFE_RENDER_DPI/72.0);
677 if (pg->bg->pixbuf_scale == zoom_to_request) continue;
678 add_bgpdf_request(pg->bg->file_page_seq, zoom_to_request);
679 pg->bg->pixbuf_scale = zoom_to_request;
684 gboolean have_intersect(struct BBox *a, struct BBox *b)
686 return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
687 (MAX(a->left, b->left) <= MIN(a->right, b->right));
690 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
691 correctly the end of the group's item list. We try to work around this.
692 DON'T USE gnome_canvas_item_raise/lower directly !! */
694 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
698 i1 = g_list_index(g->item_list, item);
699 if (i1 == -1) return;
701 if (after == NULL) i2 = -1;
702 else i2 = g_list_index(g->item_list, after);
704 if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
705 if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
707 // BUGFIX for libgnomecanvas
708 g->item_list_end = g_list_last(g->item_list);
711 void rgb_to_gdkcolor(guint rgba, GdkColor *color)
714 color->red = ((rgba>>24)&0xff)*0x101;
715 color->green = ((rgba>>16)&0xff)*0x101;
716 color->blue = ((rgba>>8)&0xff)*0x101;
719 guint32 gdkcolor_to_rgba(GdkColor gdkcolor, guint16 alpha)
721 guint32 rgba = ((gdkcolor.red & 0xff00) << 16) |
722 ((gdkcolor.green & 0xff00) << 8) |
723 ((gdkcolor.blue & 0xff00) ) |
724 ((alpha & 0xff00) >> 8);
729 // some interface functions
731 void update_thickness_buttons(void)
733 if (ui.selection!=NULL || ui.toolno[ui.cur_mapping] >= NUM_STROKE_TOOLS) {
734 gtk_toggle_tool_button_set_active(
735 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
737 switch (ui.cur_brush->thickness_no) {
739 gtk_toggle_tool_button_set_active(
740 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
742 case THICKNESS_MEDIUM:
743 gtk_toggle_tool_button_set_active(
744 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
746 case THICKNESS_THICK:
747 gtk_toggle_tool_button_set_active(
748 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
751 gtk_toggle_tool_button_set_active(
752 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
756 void update_color_buttons(void)
759 GtkColorButton *colorbutton;
761 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
762 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
763 gtk_toggle_tool_button_set_active(
764 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
766 switch (ui.cur_brush->color_no) {
768 gtk_toggle_tool_button_set_active(
769 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE);
772 gtk_toggle_tool_button_set_active(
773 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE);
776 gtk_toggle_tool_button_set_active(
777 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE);
780 gtk_toggle_tool_button_set_active(
781 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE);
784 gtk_toggle_tool_button_set_active(
785 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE);
787 case COLOR_LIGHTBLUE:
788 gtk_toggle_tool_button_set_active(
789 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE);
791 case COLOR_LIGHTGREEN:
792 gtk_toggle_tool_button_set_active(
793 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE);
796 gtk_toggle_tool_button_set_active(
797 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE);
800 gtk_toggle_tool_button_set_active(
801 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE);
804 gtk_toggle_tool_button_set_active(
805 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE);
808 gtk_toggle_tool_button_set_active(
809 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE);
812 gtk_toggle_tool_button_set_active(
813 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
816 colorbutton = GTK_COLOR_BUTTON(GET_COMPONENT("buttonColorChooser"));
817 if ((ui.toolno[ui.cur_mapping] != TOOL_PEN &&
818 ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER &&
819 ui.toolno[ui.cur_mapping] != TOOL_TEXT))
820 gdkcolor.red = gdkcolor.blue = gdkcolor.green = 0;
821 else rgb_to_gdkcolor(ui.cur_brush->color_rgba, &gdkcolor);
822 gtk_color_button_set_color(colorbutton, &gdkcolor);
823 if (ui.toolno[ui.cur_mapping] == TOOL_HIGHLIGHTER) {
824 gtk_color_button_set_alpha(colorbutton,
825 (ui.cur_brush->color_rgba&0xff)*0x101);
826 gtk_color_button_set_use_alpha(colorbutton, TRUE);
828 gtk_color_button_set_alpha(colorbutton, 0xffff);
829 gtk_color_button_set_use_alpha(colorbutton, FALSE);
833 void update_tool_buttons(void)
835 switch(ui.toolno[ui.cur_mapping]) {
837 gtk_toggle_tool_button_set_active(
838 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
841 gtk_toggle_tool_button_set_active(
842 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
844 case TOOL_HIGHLIGHTER:
845 gtk_toggle_tool_button_set_active(
846 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
849 gtk_toggle_tool_button_set_active(
850 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
852 case TOOL_SELECTREGION:
853 gtk_toggle_tool_button_set_active(
854 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
856 case TOOL_SELECTRECT:
857 gtk_toggle_tool_button_set_active(
858 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
861 gtk_toggle_tool_button_set_active(
862 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
865 gtk_toggle_tool_button_set_active(
866 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHand")), TRUE);
870 gtk_toggle_tool_button_set_active(
871 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
872 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
873 gtk_toggle_tool_button_set_active(
874 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
875 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
877 update_thickness_buttons();
878 update_color_buttons();
881 void update_tool_menu(void)
883 switch(ui.toolno[0]) {
885 gtk_check_menu_item_set_active(
886 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
889 gtk_check_menu_item_set_active(
890 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
892 case TOOL_HIGHLIGHTER:
893 gtk_check_menu_item_set_active(
894 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
897 gtk_check_menu_item_set_active(
898 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
900 case TOOL_SELECTREGION:
901 gtk_check_menu_item_set_active(
902 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
904 case TOOL_SELECTRECT:
905 gtk_check_menu_item_set_active(
906 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
909 gtk_check_menu_item_set_active(
910 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
913 gtk_check_menu_item_set_active(
914 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHand")), TRUE);
918 gtk_check_menu_item_set_active(
919 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
920 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
921 gtk_check_menu_item_set_active(
922 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
923 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
926 void update_ruler_indicator(void)
928 gtk_toggle_tool_button_set_active(
929 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
930 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
931 gtk_toggle_tool_button_set_active(
932 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
933 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
934 gtk_check_menu_item_set_active(
935 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
936 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
937 gtk_check_menu_item_set_active(
938 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
939 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
942 void update_color_menu(void)
944 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
945 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
946 gtk_check_menu_item_set_active(
947 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
949 switch (ui.cur_brush->color_no) {
951 gtk_check_menu_item_set_active(
952 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
955 gtk_check_menu_item_set_active(
956 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
959 gtk_check_menu_item_set_active(
960 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
963 gtk_check_menu_item_set_active(
964 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
967 gtk_check_menu_item_set_active(
968 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
970 case COLOR_LIGHTBLUE:
971 gtk_check_menu_item_set_active(
972 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
974 case COLOR_LIGHTGREEN:
975 gtk_check_menu_item_set_active(
976 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
979 gtk_check_menu_item_set_active(
980 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
983 gtk_check_menu_item_set_active(
984 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
987 gtk_check_menu_item_set_active(
988 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
991 gtk_check_menu_item_set_active(
992 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
995 gtk_check_menu_item_set_active(
996 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
1000 void update_pen_props_menu(void)
1002 switch(ui.brushes[0][TOOL_PEN].thickness_no) {
1003 case THICKNESS_VERYFINE:
1004 gtk_check_menu_item_set_active(
1005 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
1007 case THICKNESS_FINE:
1008 gtk_check_menu_item_set_active(
1009 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
1011 case THICKNESS_MEDIUM:
1012 gtk_check_menu_item_set_active(
1013 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
1015 case THICKNESS_THICK:
1016 gtk_check_menu_item_set_active(
1017 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
1019 case THICKNESS_VERYTHICK:
1020 gtk_check_menu_item_set_active(
1021 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
1026 void update_eraser_props_menu(void)
1028 switch (ui.brushes[0][TOOL_ERASER].thickness_no) {
1029 case THICKNESS_FINE:
1030 gtk_check_menu_item_set_active(
1031 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
1033 case THICKNESS_MEDIUM:
1034 gtk_check_menu_item_set_active(
1035 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
1037 case THICKNESS_THICK:
1038 gtk_check_menu_item_set_active(
1039 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
1043 gtk_check_menu_item_set_active(
1044 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
1045 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
1046 gtk_check_menu_item_set_active(
1047 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
1048 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
1049 gtk_check_menu_item_set_active(
1050 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
1051 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
1054 void update_highlighter_props_menu(void)
1056 switch (ui.brushes[0][TOOL_HIGHLIGHTER].thickness_no) {
1057 case THICKNESS_FINE:
1058 gtk_check_menu_item_set_active(
1059 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
1061 case THICKNESS_MEDIUM:
1062 gtk_check_menu_item_set_active(
1063 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
1065 case THICKNESS_THICK:
1066 gtk_check_menu_item_set_active(
1067 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
1072 void update_mappings_menu_linkings(void)
1074 switch (ui.linked_brush[1]) {
1076 gtk_check_menu_item_set_active(
1077 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2LinkBrush")), TRUE);
1080 gtk_check_menu_item_set_active(
1081 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2CopyBrush")), TRUE);
1084 gtk_check_menu_item_set_active(
1085 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2NABrush")), TRUE);
1088 switch (ui.linked_brush[2]) {
1090 gtk_check_menu_item_set_active(
1091 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3LinkBrush")), TRUE);
1094 gtk_check_menu_item_set_active(
1095 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3CopyBrush")), TRUE);
1098 gtk_check_menu_item_set_active(
1099 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3NABrush")), TRUE);
1104 void update_mappings_menu(void)
1106 gtk_widget_set_sensitive(GET_COMPONENT("optionsButtonMappings"), ui.use_xinput);
1107 gtk_widget_set_sensitive(GET_COMPONENT("optionsDiscardCoreEvents"), ui.use_xinput);
1108 gtk_widget_set_sensitive(GET_COMPONENT("optionsPressureSensitive"), ui.use_xinput);
1109 gtk_check_menu_item_set_active(
1110 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsButtonMappings")), ui.use_erasertip);
1111 gtk_check_menu_item_set_active(
1112 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsDiscardCoreEvents")), ui.discard_corepointer);
1113 gtk_check_menu_item_set_active(
1114 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsPressureSensitive")), ui.pressure_sensitivity);
1116 switch(ui.toolno[1]) {
1118 gtk_check_menu_item_set_active(
1119 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Pen")), TRUE);
1122 gtk_check_menu_item_set_active(
1123 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Eraser")), TRUE);
1125 case TOOL_HIGHLIGHTER:
1126 gtk_check_menu_item_set_active(
1127 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Highlighter")), TRUE);
1130 gtk_check_menu_item_set_active(
1131 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Text")), TRUE);
1133 case TOOL_SELECTREGION:
1134 gtk_check_menu_item_set_active(
1135 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRegion")), TRUE);
1137 case TOOL_SELECTRECT:
1138 gtk_check_menu_item_set_active(
1139 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRectangle")), TRUE);
1141 case TOOL_VERTSPACE:
1142 gtk_check_menu_item_set_active(
1143 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2VerticalSpace")), TRUE);
1146 switch(ui.toolno[2]) {
1148 gtk_check_menu_item_set_active(
1149 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Pen")), TRUE);
1152 gtk_check_menu_item_set_active(
1153 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Eraser")), TRUE);
1155 case TOOL_HIGHLIGHTER:
1156 gtk_check_menu_item_set_active(
1157 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Highlighter")), TRUE);
1160 gtk_check_menu_item_set_active(
1161 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Text")), TRUE);
1163 case TOOL_SELECTREGION:
1164 gtk_check_menu_item_set_active(
1165 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRegion")), TRUE);
1167 case TOOL_SELECTRECT:
1168 gtk_check_menu_item_set_active(
1169 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRectangle")), TRUE);
1171 case TOOL_VERTSPACE:
1172 gtk_check_menu_item_set_active(
1173 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3VerticalSpace")), TRUE);
1176 update_mappings_menu_linkings();
1179 void do_switch_page(int pg, gboolean rescroll, gboolean refresh_all)
1182 struct Layer *layer;
1187 /* re-show all the layers of the old page */
1188 if (ui.cur_page != NULL)
1189 for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
1190 layer = (struct Layer *)list->data;
1191 if (layer->group!=NULL)
1192 gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
1195 ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
1196 ui.layerno = ui.cur_page->nlayers-1;
1197 ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
1198 update_page_stuff();
1199 if (ui.progressive_bg) rescale_bg_pixmaps();
1201 if (rescroll) { // scroll and force a refresh
1202 /* -- this seems to cause some display bugs ??
1203 gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)),
1204 ui.cur_page->voffset*ui.zoom); */
1205 gnome_canvas_get_scroll_offsets(canvas, &cx, &cy);
1206 cy = ui.cur_page->voffset*ui.zoom;
1207 gnome_canvas_scroll_to(canvas, cx, cy);
1210 gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
1211 else if (!ui.view_continuous)
1212 gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.cur_page->group), 0., 0.);
1216 void update_page_stuff(void)
1219 GtkComboBox *layerbox;
1222 GtkSpinButton *spin;
1224 double vertpos, maxwidth;
1226 // move the page groups to their rightful locations or hide them
1227 if (ui.view_continuous) {
1230 for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
1231 pg = (struct Page *)pglist->data;
1232 if (pg->group!=NULL) {
1233 pg->hoffset = 0.; pg->voffset = vertpos;
1234 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1235 "x", pg->hoffset, "y", pg->voffset, NULL);
1236 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1238 vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
1239 if (pg->width > maxwidth) maxwidth = pg->width;
1241 vertpos -= VIEW_CONTINUOUS_SKIP;
1242 gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
1244 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1245 pg = (struct Page *)pglist->data;
1246 if (pg == ui.cur_page && pg->group!=NULL) {
1247 pg->hoffset = 0.; pg->voffset = 0.;
1248 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1249 "x", pg->hoffset, "y", pg->voffset, NULL);
1250 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1252 if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
1255 gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
1258 // update the page / layer info at bottom of screen
1260 spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
1261 ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
1262 gtk_spin_button_set_range(spin, 1, journal.npages+1);
1263 /* npages+1 will be used to create a new page at end */
1264 gtk_spin_button_set_value(spin, ui.pageno+1);
1265 g_snprintf(tmp, 10, _(" of %d"), journal.npages);
1266 gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
1268 layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
1269 if (ui.layerbox_length == 0) {
1270 gtk_combo_box_prepend_text(layerbox, _("Background"));
1271 ui.layerbox_length++;
1273 while (ui.layerbox_length > ui.cur_page->nlayers+1) {
1274 gtk_combo_box_remove_text(layerbox, 0);
1275 ui.layerbox_length--;
1277 while (ui.layerbox_length < ui.cur_page->nlayers+1) {
1278 g_snprintf(tmp, 10, _("Layer %d"), ui.layerbox_length++);
1279 gtk_combo_box_prepend_text(layerbox, tmp);
1281 gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
1282 ui.in_update_page_stuff = FALSE;
1284 // update the paper-style menu radio buttons
1286 if (ui.view_continuous)
1287 gtk_check_menu_item_set_active(
1288 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
1290 gtk_check_menu_item_set_active(
1291 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
1293 if (ui.cur_page->bg->type == BG_SOLID && !ui.bg_apply_all_pages) {
1294 switch (ui.cur_page->bg->color_no) {
1296 gtk_check_menu_item_set_active(
1297 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
1300 gtk_check_menu_item_set_active(
1301 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
1304 gtk_check_menu_item_set_active(
1305 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1308 gtk_check_menu_item_set_active(
1309 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1312 gtk_check_menu_item_set_active(
1313 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1316 gtk_check_menu_item_set_active(
1317 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1320 gtk_check_menu_item_set_active(
1321 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE);
1324 switch (ui.cur_page->bg->ruling) {
1326 gtk_check_menu_item_set_active(
1327 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1330 gtk_check_menu_item_set_active(
1331 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1334 gtk_check_menu_item_set_active(
1335 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1338 gtk_check_menu_item_set_active(
1339 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1343 gtk_check_menu_item_set_active(
1344 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1345 gtk_check_menu_item_set_active(
1346 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1349 // enable/disable the page/layer menu items and toolbar buttons
1351 gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"),
1352 ui.cur_page->bg->type == BG_SOLID || ui.bg_apply_all_pages);
1353 gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1354 ui.cur_page->bg->type == BG_SOLID);
1356 gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1357 gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1358 gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1359 gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1360 gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1361 gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1362 gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1363 gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1365 gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1366 gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1368 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1369 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1372 void update_toolbar_and_menu(void)
1374 update_tool_buttons(); // takes care of other toolbar buttons as well
1376 update_color_menu();
1377 update_pen_props_menu();
1378 update_eraser_props_menu();
1379 update_highlighter_props_menu();
1380 update_mappings_menu();
1382 gtk_toggle_tool_button_set_active(
1383 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1384 gtk_check_menu_item_set_active(
1385 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1388 void update_file_name(char *filename)
1391 if (ui.filename != NULL) g_free(ui.filename);
1392 ui.filename = filename;
1393 if (filename == NULL) {
1394 gtk_window_set_title(GTK_WINDOW (winMain), _("Xournal"));
1397 p = g_utf8_strrchr(filename, -1, '/');
1398 if (p == NULL) p = filename;
1399 else p = g_utf8_next_char(p);
1400 g_snprintf(tmp, 100, _("Xournal - %s"), p);
1401 gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1402 new_mru_entry(filename);
1404 if (filename[0]=='/') {
1405 if (ui.default_path!=NULL) g_free(ui.default_path);
1406 ui.default_path = g_path_get_dirname(filename);
1410 void update_undo_redo_enabled(void)
1412 gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1413 gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1414 gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1415 gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1418 void update_copy_paste_enabled(void)
1420 gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1421 gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1422 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_item_type!=ITEM_TEXT);
1423 gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1424 gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1425 gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1426 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_item_type!=ITEM_TEXT);
1429 void update_mapping_linkings(int toolno)
1433 for (i = 1; i<=NUM_BUTTONS; i++) {
1434 if (ui.linked_brush[i] == BRUSH_LINKED) {
1435 if (toolno >= 0 && toolno < NUM_STROKE_TOOLS)
1436 g_memmove(&(ui.brushes[i][toolno]), &(ui.brushes[0][toolno]), sizeof(struct Brush));
1438 if (ui.linked_brush[i] == BRUSH_COPIED && toolno == ui.toolno[i]) {
1439 ui.linked_brush[i] = BRUSH_STATIC;
1440 if (i==1 || i==2) update_mappings_menu_linkings();
1445 void set_cur_color(int color_no, guint color_rgba)
1447 int which_mapping, tool;
1449 if (ui.toolno[ui.cur_mapping] == TOOL_HIGHLIGHTER) tool = TOOL_HIGHLIGHTER;
1450 else tool = TOOL_PEN;
1451 if (ui.cur_mapping>0 && ui.linked_brush[ui.cur_mapping]!=BRUSH_LINKED)
1452 which_mapping = ui.cur_mapping;
1453 else which_mapping = 0;
1455 ui.brushes[which_mapping][tool].color_no = color_no;
1456 if (tool == TOOL_HIGHLIGHTER && (color_rgba & 0xff) == 0xff)
1457 ui.brushes[which_mapping][tool].color_rgba = color_rgba & ui.hiliter_alpha_mask;
1459 ui.brushes[which_mapping][tool].color_rgba = color_rgba;
1460 update_mapping_linkings(tool);
1463 void recolor_temp_text(int color_no, guint color_rgba)
1467 if (ui.cur_item_type!=ITEM_TEXT) return;
1468 if (ui.cur_item->text!=NULL && ui.cur_item->brush.color_rgba != color_rgba) {
1470 undo->type = ITEM_TEXT_ATTRIB;
1471 undo->item = ui.cur_item;
1472 undo->str = g_strdup(ui.cur_item->font_name);
1473 undo->val_x = ui.cur_item->font_size;
1474 undo->brush = (struct Brush *)g_memdup(&(ui.cur_item->brush), sizeof(struct Brush));
1476 ui.cur_item->brush.color_no = color_no;
1477 ui.cur_item->brush.color_rgba = color_rgba;
1478 rgb_to_gdkcolor(color_rgba, &gdkcolor);
1479 gtk_widget_modify_text(ui.cur_item->widget, GTK_STATE_NORMAL, &gdkcolor);
1480 gtk_widget_grab_focus(ui.cur_item->widget);
1483 void process_color_activate(GtkMenuItem *menuitem, int color_no, guint color_rgba)
1485 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1486 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1489 else if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_TOOL_BUTTON) {
1490 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1494 if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
1497 if (ui.cur_item_type == ITEM_TEXT)
1498 recolor_temp_text(color_no, color_rgba);
1500 if (ui.selection != NULL) {
1501 recolor_selection(color_no, color_rgba);
1502 update_color_buttons();
1503 update_color_menu();
1506 if (ui.toolno[ui.cur_mapping] != TOOL_PEN && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER
1507 && ui.toolno[ui.cur_mapping] != TOOL_TEXT) {
1508 if (ui.selection != NULL) return;
1511 ui.toolno[ui.cur_mapping] = TOOL_PEN;
1512 ui.cur_brush = &(ui.brushes[ui.cur_mapping][TOOL_PEN]);
1513 update_tool_buttons();
1517 set_cur_color(color_no, color_rgba);
1518 update_color_buttons();
1519 update_color_menu();
1523 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1527 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1528 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1531 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1535 if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
1537 if (ui.selection != NULL && GTK_OBJECT_TYPE(menuitem) != GTK_TYPE_RADIO_MENU_ITEM) {
1539 rethicken_selection(val);
1540 update_thickness_buttons();
1543 if (tool >= NUM_STROKE_TOOLS) {
1544 update_thickness_buttons(); // undo illegal button selection
1548 if (ui.cur_mapping>0 && ui.linked_brush[ui.cur_mapping]!=BRUSH_LINKED)
1549 which_mapping = ui.cur_mapping;
1550 else which_mapping = 0;
1551 if (ui.brushes[which_mapping][tool].thickness_no == val) return;
1554 ui.brushes[which_mapping][tool].thickness_no = val;
1555 ui.brushes[which_mapping][tool].thickness = predef_thickness[tool][val];
1556 update_mapping_linkings(tool);
1558 update_thickness_buttons();
1559 if (tool == TOOL_PEN) update_pen_props_menu();
1560 if (tool == TOOL_ERASER) update_eraser_props_menu();
1561 if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1565 void process_papercolor_activate(GtkMenuItem *menuitem, int color)
1571 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1574 if ((ui.cur_page->bg->type != BG_SOLID) || ui.bg_apply_all_pages)
1575 gtk_check_menu_item_set_active(
1576 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1580 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1581 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1582 if (pg->bg->type == BG_SOLID && pg->bg->color_no != color) {
1584 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1585 undo->multiop |= MULTIOP_CONT_REDO;
1587 undo->type = ITEM_NEW_BG_ONE;
1589 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1590 undo->bg->canvas_item = NULL;
1592 pg->bg->color_no = color;
1593 pg->bg->color_rgba = predef_bgcolors_rgba[color];
1594 update_canvas_bg(pg);
1596 if (!ui.bg_apply_all_pages) break;
1598 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1601 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1605 gboolean hasdone, must_upd;
1607 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1610 if (ui.bg_apply_all_pages)
1611 gtk_check_menu_item_set_active(
1612 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1617 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1618 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1619 if (pg->bg->type != BG_SOLID || pg->bg->ruling != style) {
1621 undo->type = ITEM_NEW_BG_ONE;
1622 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1623 undo->multiop |= MULTIOP_CONT_REDO;
1626 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1627 undo->bg->canvas_item = NULL;
1629 if (pg->bg->type != BG_SOLID) {
1630 pg->bg->type = BG_SOLID;
1631 pg->bg->color_no = COLOR_WHITE;
1632 pg->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1633 pg->bg->filename = NULL;
1634 pg->bg->pixbuf = NULL;
1637 pg->bg->ruling = style;
1638 update_canvas_bg(pg);
1640 if (!ui.bg_apply_all_pages) break;
1642 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1643 if (must_upd) update_page_stuff();
1646 gboolean ok_to_close(void)
1649 GtkResponseType response;
1651 if (ui.saved) return TRUE;
1652 dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1653 GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Save changes to '%s'?"),
1654 (ui.filename!=NULL) ? ui.filename:_("Untitled"));
1655 gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1656 response = gtk_dialog_run(GTK_DIALOG (dialog));
1657 gtk_widget_destroy(dialog);
1658 if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT)
1659 return FALSE; // aborted
1660 if (response == GTK_RESPONSE_YES) {
1661 on_fileSave_activate(NULL, NULL);
1662 if (!ui.saved) return FALSE; // if save failed, then we abort
1667 // send the focus back to the appropriate widget
1668 void reset_focus(void)
1671 if (ui.cur_item_type == ITEM_TEXT)
1672 gtk_widget_grab_focus(ui.cur_item->widget);
1674 gtk_widget_grab_focus(GTK_WIDGET(canvas));
1679 // selection / clipboard stuff
1681 void reset_selection(void)
1683 if (ui.selection == NULL) return;
1684 if (ui.selection->canvas_item != NULL)
1685 gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1686 g_list_free(ui.selection->items);
1687 g_free(ui.selection);
1688 ui.selection = NULL;
1689 update_copy_paste_enabled();
1690 update_color_menu();
1691 update_thickness_buttons();
1692 update_color_buttons();
1693 update_font_button();
1697 void move_journal_items_by(GList *itemlist, double dx, double dy,
1698 struct Layer *l1, struct Layer *l2, GList *depths)
1701 GnomeCanvasItem *refitem;
1706 while (itemlist!=NULL) {
1707 item = (struct Item *)itemlist->data;
1708 if (item->type == ITEM_STROKE)
1709 for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1710 { pt[0] += dx; pt[1] += dy; }
1711 if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type == ITEM_TEMP_TEXT) {
1712 item->bbox.left += dx;
1713 item->bbox.right += dx;
1714 item->bbox.top += dy;
1715 item->bbox.bottom += dy;
1718 // find out where to insert
1719 if (depths != NULL) {
1720 if (depths->data == NULL) link = l2->items;
1722 link = g_list_find(l2->items, depths->data);
1723 if (link != NULL) link = link->next;
1726 l2->items = g_list_insert_before(l2->items, link, item);
1728 l1->items = g_list_remove(l1->items, item);
1731 if (depths != NULL) { // also raise/lower the canvas items
1732 if (item->canvas_item!=NULL) {
1733 if (depths->data == NULL) link = NULL;
1734 else link = g_list_find(l2->items, depths->data);
1735 if (link != NULL) refitem = ((struct Item *)(link->data))->canvas_item;
1736 else refitem = NULL;
1737 lower_canvas_item_to(l2->group, item->canvas_item, refitem);
1739 depths = depths->next;
1741 itemlist = itemlist->next;
1745 void resize_journal_items_by(GList *itemlist, double scaling_x, double scaling_y,
1746 double offset_x, double offset_y)
1750 double mean_scaling, temp;
1752 GnomeCanvasGroup *group;
1755 /* geometric mean of x and y scalings = rescaling for stroke widths
1756 and for text font sizes */
1757 mean_scaling = sqrt(fabs(scaling_x * scaling_y));
1759 for (list = itemlist; list != NULL; list = list->next) {
1760 item = (struct Item *)list->data;
1761 if (item->type == ITEM_STROKE) {
1762 item->brush.thickness = item->brush.thickness * mean_scaling;
1763 for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {
1764 pt[0] = pt[0]*scaling_x + offset_x;
1765 pt[1] = pt[1]*scaling_y + offset_y;
1767 if (item->brush.variable_width)
1768 for (i=0, wid=item->widths; i<item->path->num_points-1; i++, wid++)
1769 *wid = *wid * mean_scaling;
1771 item->bbox.left = item->bbox.left*scaling_x + offset_x;
1772 item->bbox.right = item->bbox.right*scaling_x + offset_x;
1773 item->bbox.top = item->bbox.top*scaling_y + offset_y;
1774 item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
1775 if (item->bbox.left > item->bbox.right) {
1776 temp = item->bbox.left;
1777 item->bbox.left = item->bbox.right;
1778 item->bbox.right = temp;
1780 if (item->bbox.top > item->bbox.bottom) {
1781 temp = item->bbox.top;
1782 item->bbox.top = item->bbox.bottom;
1783 item->bbox.bottom = temp;
1786 if (item->type == ITEM_TEXT) {
1787 /* must scale about NW corner -- all other points of the text box
1788 are font- and zoom-dependent, so scaling about center of text box
1789 couldn't be undone properly. FIXME? */
1790 item->font_size *= mean_scaling;
1791 item->bbox.left = item->bbox.left*scaling_x + offset_x;
1792 item->bbox.top = item->bbox.top*scaling_y + offset_y;
1795 if (item->canvas_item!=NULL) {
1796 group = (GnomeCanvasGroup *) item->canvas_item->parent;
1797 gtk_object_destroy(GTK_OBJECT(item->canvas_item));
1798 make_canvas_item_one(group, item);
1803 // Switch between button mappings
1805 /* NOTE ABOUT BUTTON MAPPINGS: ui.cur_mapping is 0 except while a canvas
1806 click event is being processed ... or if ui.button_switch_mapping is
1807 enabled and mappings are switched (but even then, canvas should have
1808 a pointer grab from the initial click that switched the mapping) */
1810 void switch_mapping(int m)
1812 if (ui.cur_mapping == m) return;
1815 if (ui.toolno[m] < NUM_STROKE_TOOLS)
1816 ui.cur_brush = &(ui.brushes[m][ui.toolno[m]]);
1817 if (ui.toolno[m] == TOOL_TEXT)
1818 ui.cur_brush = &(ui.brushes[m][TOOL_PEN]);
1819 if (m==0) ui.which_unswitch_button = 0;
1821 update_tool_buttons();
1822 update_color_menu();
1826 void process_mapping_activate(GtkMenuItem *menuitem, int m, int tool)
1828 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return;
1829 if (ui.cur_mapping!=0 && !ui.button_switch_mapping) return;
1830 if (ui.toolno[m] == tool) return;
1835 ui.toolno[m] = tool;
1836 if (ui.linked_brush[m] == BRUSH_COPIED) {
1837 ui.linked_brush[m] = BRUSH_STATIC;
1838 update_mappings_menu_linkings();
1842 // update the ordering of components in the main vbox
1844 const char *vbox_component_names[VBOX_MAIN_NITEMS]=
1845 {"scrolledwindowMain", "menubar", "toolbarMain", "toolbarPen", "hbox1"};
1847 void update_vbox_order(int *order)
1851 GtkBox *vboxMain = GTK_BOX(GET_COMPONENT("vboxMain"));
1852 gboolean present[VBOX_MAIN_NITEMS];
1854 for (i=0; i<VBOX_MAIN_NITEMS; i++) present[i] = FALSE;
1856 for (i=0; i<VBOX_MAIN_NITEMS; i++) {
1857 if (order[i]<0 || order[i]>=VBOX_MAIN_NITEMS) continue;
1858 present[order[i]] = TRUE;
1859 child = GET_COMPONENT(vbox_component_names[order[i]]);
1860 gtk_box_reorder_child(vboxMain, child, j++);
1861 gtk_widget_show(child);
1863 for (i=1; i<VBOX_MAIN_NITEMS; i++) // hide others, but not the drawing area!
1864 if (!present[i]) gtk_widget_hide(GET_COMPONENT(vbox_component_names[i]));
1867 gchar *make_cur_font_name(void)
1872 if (ui.cur_item_type == ITEM_TEXT)
1873 str = g_strdup_printf("%s %.1f", ui.cur_item->font_name, ui.cur_item->font_size);
1874 else if (ui.selection!=NULL && ui.selection->items!=NULL &&
1875 ui.selection->items->next==NULL &&
1876 (it=(struct Item*)ui.selection->items->data)->type == ITEM_TEXT)
1877 str = g_strdup_printf("%s %.1f", it->font_name, it->font_size);
1879 str = g_strdup_printf("%s %.1f", ui.font_name, ui.font_size);
1883 void update_font_button(void)
1887 str = make_cur_font_name();
1888 gtk_font_button_set_font_name(GTK_FONT_BUTTON(GET_COMPONENT("fontButton")), str);
1892 gboolean can_accel(GtkWidget *widget, guint id, gpointer data)
1894 return GTK_WIDGET_SENSITIVE(widget);
1897 gboolean can_accel_except_text(GtkWidget *widget, guint id, gpointer data)
1899 if (ui.cur_item_type == ITEM_TEXT) {
1900 g_signal_stop_emission_by_name(widget, "can-activate-accel");
1903 return GTK_WIDGET_SENSITIVE(widget);
1906 void allow_all_accels(void)
1908 g_signal_connect((gpointer) GET_COMPONENT("fileNew"),
1909 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1910 g_signal_connect((gpointer) GET_COMPONENT("fileOpen"),
1911 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1912 g_signal_connect((gpointer) GET_COMPONENT("fileSave"),
1913 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1914 g_signal_connect((gpointer) GET_COMPONENT("filePrint"),
1915 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1916 g_signal_connect((gpointer) GET_COMPONENT("filePrintPDF"),
1917 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1918 g_signal_connect((gpointer) GET_COMPONENT("fileQuit"),
1919 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1920 g_signal_connect((gpointer) GET_COMPONENT("editUndo"),
1921 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1922 g_signal_connect((gpointer) GET_COMPONENT("editRedo"),
1923 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1924 g_signal_connect((gpointer) GET_COMPONENT("editCut"),
1925 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1926 g_signal_connect((gpointer) GET_COMPONENT("editCopy"),
1927 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1928 g_signal_connect((gpointer) GET_COMPONENT("editPaste"),
1929 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1930 g_signal_connect((gpointer) GET_COMPONENT("editDelete"),
1931 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1932 g_signal_connect((gpointer) GET_COMPONENT("viewFullscreen"),
1933 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1934 g_signal_connect((gpointer) GET_COMPONENT("viewZoomIn"),
1935 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1936 g_signal_connect((gpointer) GET_COMPONENT("viewZoomOut"),
1937 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1938 g_signal_connect((gpointer) GET_COMPONENT("viewNormalSize"),
1939 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1940 g_signal_connect((gpointer) GET_COMPONENT("viewPageWidth"),
1941 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1942 g_signal_connect((gpointer) GET_COMPONENT("viewFirstPage"),
1943 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1944 g_signal_connect((gpointer) GET_COMPONENT("viewPreviousPage"),
1945 "can-activate-accel", G_CALLBACK(can_accel_except_text), NULL);
1946 g_signal_connect((gpointer) GET_COMPONENT("viewNextPage"),
1947 "can-activate-accel", G_CALLBACK(can_accel_except_text), NULL);
1948 g_signal_connect((gpointer) GET_COMPONENT("viewLastPage"),
1949 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1950 g_signal_connect((gpointer) GET_COMPONENT("toolsPen"),
1951 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1952 g_signal_connect((gpointer) GET_COMPONENT("toolsEraser"),
1953 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1954 g_signal_connect((gpointer) GET_COMPONENT("toolsHighlighter"),
1955 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1956 g_signal_connect((gpointer) GET_COMPONENT("toolsText"),
1957 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1958 /* g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
1959 "can-activate-accel", G_CALLBACK(can_accel), NULL); */
1960 g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRectangle"),
1961 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1962 g_signal_connect((gpointer) GET_COMPONENT("toolsVerticalSpace"),
1963 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1964 g_signal_connect((gpointer) GET_COMPONENT("toolsHand"),
1965 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1966 g_signal_connect((gpointer) GET_COMPONENT("toolsTextFont"),
1967 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1968 g_signal_connect((gpointer) GET_COMPONENT("toolsRuler"),
1969 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1970 g_signal_connect((gpointer) GET_COMPONENT("toolsReco"),
1971 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1974 void add_scroll_bindings(void)
1976 GtkBindingSet *binding_set;
1978 binding_set = gtk_binding_set_by_class(
1979 G_OBJECT_GET_CLASS(GET_COMPONENT("scrolledwindowMain")));
1980 gtk_binding_entry_add_signal(binding_set, GDK_Up, 0,
1981 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1982 G_TYPE_BOOLEAN, FALSE);
1983 gtk_binding_entry_add_signal(binding_set, GDK_KP_Up, 0,
1984 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1985 G_TYPE_BOOLEAN, FALSE);
1986 gtk_binding_entry_add_signal(binding_set, GDK_Down, 0,
1987 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1988 G_TYPE_BOOLEAN, FALSE);
1989 gtk_binding_entry_add_signal(binding_set, GDK_KP_Down, 0,
1990 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1991 G_TYPE_BOOLEAN, FALSE);
1992 gtk_binding_entry_add_signal(binding_set, GDK_Left, 0,
1993 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1994 G_TYPE_BOOLEAN, TRUE);
1995 gtk_binding_entry_add_signal(binding_set, GDK_KP_Left, 0,
1996 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1997 G_TYPE_BOOLEAN, TRUE);
1998 gtk_binding_entry_add_signal(binding_set, GDK_Right, 0,
1999 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
2000 G_TYPE_BOOLEAN, TRUE);
2001 gtk_binding_entry_add_signal(binding_set, GDK_KP_Right, 0,
2002 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
2003 G_TYPE_BOOLEAN, TRUE);
2006 gboolean is_event_within_textview(GdkEventButton *event)
2010 if (ui.cur_item_type!=ITEM_TEXT) return FALSE;
2011 get_pointer_coords((GdkEvent *)event, pt);
2012 if (pt[0]<ui.cur_item->bbox.left || pt[0]>ui.cur_item->bbox.right) return FALSE;
2013 if (pt[1]<ui.cur_item->bbox.top || pt[1]>ui.cur_item->bbox.bottom) return FALSE;
2017 void hide_unimplemented(void)
2019 gtk_widget_hide(GET_COMPONENT("filePrintOptions"));
2020 gtk_widget_hide(GET_COMPONENT("journalFlatten"));
2021 gtk_widget_hide(GET_COMPONENT("papercolorOther"));
2022 gtk_widget_hide(GET_COMPONENT("toolsSelectRegion"));
2023 gtk_widget_hide(GET_COMPONENT("buttonSelectRegion"));
2024 gtk_widget_hide(GET_COMPONENT("button2SelectRegion"));
2025 gtk_widget_hide(GET_COMPONENT("button3SelectRegion"));
2026 gtk_widget_hide(GET_COMPONENT("helpIndex"));
2028 /* config file only works with glib 2.6 and beyond */
2029 if (glib_minor_version<6) {
2030 gtk_widget_hide(GET_COMPONENT("optionsAutoSavePrefs"));
2031 gtk_widget_hide(GET_COMPONENT("optionsSavePreferences"));
2033 /* gtkprint only works with gtk+ 2.10 and beyond */
2034 if (gtk_check_version(2, 10, 0)) {
2035 gtk_widget_hide(GET_COMPONENT("filePrint"));
2039 // toggle fullscreen mode
2040 void do_fullscreen(gboolean active)
2044 ui.fullscreen = active;
2045 gtk_check_menu_item_set_active(
2046 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
2047 gtk_toggle_tool_button_set_active(
2048 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
2050 if (ui.fullscreen) gtk_window_fullscreen(GTK_WINDOW(winMain));
2051 else gtk_window_unfullscreen(GTK_WINDOW(winMain));
2053 update_vbox_order(ui.vertical_order[ui.fullscreen?1:0]);
2056 /* attempt to work around GTK+ 2.16/2.17 bugs where random interface
2057 elements receive XInput events that they can't handle properly */
2059 // prevent interface items from getting bogus XInput events
2061 gboolean filter_extended_events (GtkWidget *widget, GdkEvent *event,
2064 if (event->type == GDK_MOTION_NOTIFY &&
2065 event->motion.device != gdk_device_get_core_pointer())
2067 if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
2068 event->type == GDK_3BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2069 event->button.device != gdk_device_get_core_pointer())
2074 /* Code to turn an extended input event into a core event and send it to
2075 a different GdkWindow -- e.g. could be used when a click in a text edit box
2076 gets sent to the canvas instead due to incorrect event translation.
2077 We now turn off xinput altogether while editing text under GTK+ 2.17, so
2078 this isn't needed any more... but could become useful again someday!
2082 gboolean fix_extended_events (GtkWidget *widget, GdkEvent *event,
2088 if (user_data) window = (GdkWindow *)user_data;
2089 else window = widget->window;
2091 if (event->type == GDK_MOTION_NOTIFY &&
2092 event->motion.device != gdk_device_get_core_pointer()) {
2093 // printf("fixing motion\n");
2094 gdk_window_get_pointer(window, &ix, &iy, NULL);
2095 event->motion.x = ix; event->motion.y = iy;
2096 event->motion.device = gdk_device_get_core_pointer();
2097 g_object_unref(event->motion.window);
2098 event->motion.window = g_object_ref(window);
2099 gtk_widget_event(widget, event);
2102 if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2103 event->button.device != gdk_device_get_core_pointer()) {
2104 // printf("fixing button from pos = %f, %f\n", event->button.x, event->button.y);
2105 gdk_window_get_pointer(window, &ix, &iy, NULL);
2106 event->button.x = ix; event->button.y = iy;
2107 event->button.device = gdk_device_get_core_pointer();
2108 g_object_unref(event->button.window);
2109 event->button.window = g_object_ref(window);
2110 // printf("fixing button to pos = %f, %f\n", event->button.x, event->button.y);
2111 gtk_widget_event(widget, event);
2118 // disable xinput when layer combo box is popped up, to avoid GTK+ 2.17 crash
2120 gboolean combobox_popup_disable_xinput (GtkWidget *widget, GdkEvent *event,
2125 g_object_get(G_OBJECT(widget), "popup-shown", &is_shown, NULL);
2126 gtk_widget_set_extension_events(GTK_WIDGET (canvas),
2127 (ui.use_xinput && !is_shown)?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);
2130 /* When enter is pressed into page spinbox, send focus back to canvas. */
2132 gboolean handle_activate_signal(GtkWidget *widget, gpointer user_data)
2134 gtk_widget_grab_focus(GTK_WIDGET(canvas));
2138 /* recursively unset widget flags */
2140 void unset_flags(GtkWidget *w, gpointer flag)
2142 GTK_WIDGET_UNSET_FLAGS(w, (GtkWidgetFlags)flag);
2143 if(GTK_IS_CONTAINER(w))
2144 gtk_container_foreach(GTK_CONTAINER(w), unset_flags, flag);