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+10;
97 ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+10)*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+10;
104 ui.cur_widths = g_realloc(ui.cur_widths, (n+10)*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 // use canvas window, not event window (else get GTK+ 2.11 bugs!)
374 gdk_window_get_origin(GTK_WIDGET(canvas)->window, &wx, &wy);
375 gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
377 #ifdef ENABLE_XINPUT_BUGFIX
378 // fix broken events with the core pointer's location
379 if (!finite(axes[0]) || !finite(axes[1]) || (axes[0]==0. && axes[1]==0.)) {
380 gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
385 axis_width = device->axes[0].max - device->axes[0].min;
386 if (axis_width>EPSILON)
387 *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
388 axis_width = device->axes[1].max - device->axes[1].min;
389 if (axis_width>EPSILON)
390 *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
395 double get_pressure_multiplier(GdkEvent *event)
399 if (event->button.device == gdk_device_get_core_pointer()
400 || event->button.device->num_axes <= 2) return 1.0;
402 rawpressure = event->button.axes[2]/(event->button.device->axes[2].max - event->button.device->axes[2].min);
404 return ((1-rawpressure)*ui.width_minimum_multiplier + rawpressure*ui.width_maximum_multiplier);
407 void update_item_bbox(struct Item *item)
412 if (item->type == ITEM_STROKE) {
413 item->bbox.left = item->bbox.right = item->path->coords[0];
414 item->bbox.top = item->bbox.bottom = item->path->coords[1];
415 for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
417 if (p[0] < item->bbox.left) item->bbox.left = p[0];
418 if (p[0] > item->bbox.right) item->bbox.right = p[0];
419 if (p[1] < item->bbox.top) item->bbox.top = p[1];
420 if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
423 if (item->type == ITEM_TEXT && item->canvas_item!=NULL) {
425 g_object_get(item->canvas_item, "text_width", &w, "text_height", &h, NULL);
426 item->bbox.right = item->bbox.left + w;
427 item->bbox.bottom = item->bbox.top + h;
431 void make_page_clipbox(struct Page *pg)
433 GnomeCanvasPathDef *pg_clip;
435 pg_clip = gnome_canvas_path_def_new_sized(4);
436 gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
437 gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
438 gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
439 gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
440 gnome_canvas_path_def_closepath(pg_clip);
441 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
442 gnome_canvas_path_def_unref(pg_clip);
445 void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item)
447 PangoFontDescription *font_desc;
448 GnomeCanvasPoints points;
451 if (item->type == ITEM_STROKE) {
452 if (!item->brush.variable_width)
453 item->canvas_item = gnome_canvas_item_new(group,
454 gnome_canvas_line_get_type(), "points", item->path,
455 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
456 "fill-color-rgba", item->brush.color_rgba,
457 "width-units", item->brush.thickness, NULL);
459 item->canvas_item = gnome_canvas_item_new(group,
460 gnome_canvas_group_get_type(), NULL);
461 points.num_points = 2;
462 points.ref_count = 1;
463 for (j = 0; j < item->path->num_points-1; j++) {
464 points.coords = item->path->coords+2*j;
465 gnome_canvas_item_new((GnomeCanvasGroup *) item->canvas_item,
466 gnome_canvas_line_get_type(), "points", &points,
467 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
468 "fill-color-rgba", item->brush.color_rgba,
469 "width-units", item->widths[j], NULL);
473 if (item->type == ITEM_TEXT) {
474 font_desc = pango_font_description_from_string(item->font_name);
475 pango_font_description_set_absolute_size(font_desc,
476 item->font_size*ui.zoom*PANGO_SCALE);
477 item->canvas_item = gnome_canvas_item_new(group,
478 gnome_canvas_text_get_type(),
479 "x", item->bbox.left, "y", item->bbox.top, "anchor", GTK_ANCHOR_NW,
480 "font-desc", font_desc, "fill-color-rgba", item->brush.color_rgba,
481 "text", item->text, NULL);
482 update_item_bbox(item);
486 void make_canvas_items(void)
491 GList *pagelist, *layerlist, *itemlist;
493 for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
494 pg = (struct Page *)pagelist->data;
495 if (pg->group == NULL) {
496 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
497 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
498 make_page_clipbox(pg);
500 if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
501 for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
502 l = (struct Layer *)layerlist->data;
503 if (l->group == NULL)
504 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
505 pg->group, gnome_canvas_group_get_type(), NULL);
506 for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
507 item = (struct Item *)itemlist->data;
508 if (item->canvas_item == NULL)
509 make_canvas_item_one(l->group, item);
515 void update_canvas_bg(struct Page *pg)
517 GnomeCanvasGroup *group;
518 GnomeCanvasPoints *seg;
519 GdkPixbuf *scaled_pix;
523 gboolean is_well_scaled;
525 if (pg->bg->canvas_item != NULL)
526 gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
527 pg->bg->canvas_item = NULL;
529 if (pg->bg->type == BG_SOLID)
531 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
532 gnome_canvas_group_get_type(), NULL);
533 group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
534 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
535 gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
536 "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
537 "fill-color-rgba", pg->bg->color_rgba, NULL);
538 if (pg->bg->ruling == RULING_NONE) return;
539 seg = gnome_canvas_points_new(2);
541 if (pg->bg->ruling == RULING_GRAPH) {
542 pt[1] = 0; pt[3] = pg->height;
543 for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
545 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
546 "points", seg, "fill-color-rgba", RULING_COLOR,
547 "width-units", RULING_THICKNESS, NULL);
549 pt[0] = 0; pt[2] = pg->width;
550 for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
552 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
553 "points", seg, "fill-color-rgba", RULING_COLOR,
554 "width-units", RULING_THICKNESS, NULL);
556 gnome_canvas_points_free(seg);
559 pt[0] = 0; pt[2] = pg->width;
560 for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
562 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
563 "points", seg, "fill-color-rgba", RULING_COLOR,
564 "width-units", RULING_THICKNESS, NULL);
566 if (pg->bg->ruling == RULING_LINED) {
567 pt[0] = pt[2] = RULING_LEFTMARGIN;
568 pt[1] = 0; pt[3] = pg->height;
569 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
570 "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
571 "width-units", RULING_THICKNESS, NULL);
573 gnome_canvas_points_free(seg);
577 if (pg->bg->type == BG_PIXMAP)
579 if (ui.antialias_bg) {
580 set_cursor_busy(TRUE);
581 w = (int)floor(pg->width*ui.zoom+0.5);
582 h = (int)floor(pg->height*ui.zoom+0.5);
583 if (w == gdk_pixbuf_get_width(pg->bg->pixbuf) &&
584 h == gdk_pixbuf_get_height(pg->bg->pixbuf))
585 scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
587 scaled_pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf, w, h, GDK_INTERP_BILINEAR);
588 pg->bg->pixbuf_scale = ui.zoom;
589 set_cursor_busy(FALSE);
592 scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
593 pg->bg->pixbuf_scale = 0;
595 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
596 gnome_canvas_pixbuf_get_type(),
597 "pixbuf", scaled_pix,
598 "width", pg->width, "height", pg->height,
599 "width-set", TRUE, "height-set", TRUE,
601 gdk_pixbuf_unref(scaled_pix);
602 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
605 if (pg->bg->type == BG_PDF)
607 if (pg->bg->pixbuf == NULL) return;
608 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
609 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
611 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
612 gnome_canvas_pixbuf_get_type(),
613 "pixbuf", pg->bg->pixbuf,
614 "width-in-pixels", TRUE, "height-in-pixels", TRUE,
617 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
618 gnome_canvas_pixbuf_get_type(),
619 "pixbuf", pg->bg->pixbuf,
620 "width", pg->width, "height", pg->height,
621 "width-set", TRUE, "height-set", TRUE,
623 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
627 gboolean is_visible(struct Page *pg)
629 GtkAdjustment *v_adj;
632 if (!ui.view_continuous) return (pg == ui.cur_page);
633 v_adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
634 ytop = v_adj->value/ui.zoom;
635 ybot = (v_adj->value + v_adj->page_size) / ui.zoom;
636 return (MAX(ytop, pg->voffset) < MIN(ybot, pg->voffset+pg->height));
639 void rescale_bg_pixmaps(void)
644 gboolean is_well_scaled;
645 gdouble zoom_to_request;
647 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
648 pg = (struct Page *)pglist->data;
649 // in progressive mode we scale only visible pages
650 if (ui.progressive_bg && !is_visible(pg)) continue;
652 if (pg->bg->type == BG_PIXMAP && pg->bg->canvas_item!=NULL) { // do the rescaling ourselves
653 if (ui.antialias_bg) {
654 if (pg->bg->pixbuf_scale == ui.zoom) continue;
655 set_cursor_busy(TRUE);
656 pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf,
657 (int)floor(pg->width*ui.zoom+0.5), (int)floor(pg->height*ui.zoom+0.5),
658 GDK_INTERP_BILINEAR);
659 gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pix, NULL);
660 gdk_pixbuf_unref(pix);
661 pg->bg->pixbuf_scale = ui.zoom;
662 set_cursor_busy(FALSE);
665 g_object_get(G_OBJECT(pg->bg->canvas_item), "pixbuf", &pix, NULL);
666 if (pix!=pg->bg->pixbuf)
667 gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
668 pg->bg->pixbuf_scale = 0;
671 if (pg->bg->type == BG_PDF) {
672 // make pixmap scale to correct size if current one is wrong
673 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
674 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
675 if (pg->bg->canvas_item != NULL && !is_well_scaled) {
676 g_object_get(pg->bg->canvas_item, "width-in-pixels", &is_well_scaled, NULL);
678 gnome_canvas_item_set(pg->bg->canvas_item,
679 "width", pg->width, "height", pg->height,
680 "width-in-pixels", FALSE, "height-in-pixels", FALSE,
681 "width-set", TRUE, "height-set", TRUE,
684 // request an asynchronous update to a better pixmap if needed
685 zoom_to_request = MIN(ui.zoom, MAX_SAFE_RENDER_DPI/72.0);
686 if (pg->bg->pixbuf_scale == zoom_to_request) continue;
687 add_bgpdf_request(pg->bg->file_page_seq, zoom_to_request);
688 pg->bg->pixbuf_scale = zoom_to_request;
693 gboolean have_intersect(struct BBox *a, struct BBox *b)
695 return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
696 (MAX(a->left, b->left) <= MIN(a->right, b->right));
699 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
700 correctly the end of the group's item list. We try to work around this.
701 DON'T USE gnome_canvas_item_raise/lower directly !! */
703 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
707 i1 = g_list_index(g->item_list, item);
708 if (i1 == -1) return;
710 if (after == NULL) i2 = -1;
711 else i2 = g_list_index(g->item_list, after);
713 if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
714 if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
716 // BUGFIX for libgnomecanvas
717 g->item_list_end = g_list_last(g->item_list);
720 void rgb_to_gdkcolor(guint rgba, GdkColor *color)
723 color->red = ((rgba>>24)&0xff)*0x101;
724 color->green = ((rgba>>16)&0xff)*0x101;
725 color->blue = ((rgba>>8)&0xff)*0x101;
728 // some interface functions
730 void update_thickness_buttons(void)
732 if (ui.selection!=NULL || ui.toolno[ui.cur_mapping] >= NUM_STROKE_TOOLS) {
733 gtk_toggle_tool_button_set_active(
734 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
736 switch (ui.cur_brush->thickness_no) {
738 gtk_toggle_tool_button_set_active(
739 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
741 case THICKNESS_MEDIUM:
742 gtk_toggle_tool_button_set_active(
743 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
745 case THICKNESS_THICK:
746 gtk_toggle_tool_button_set_active(
747 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
750 gtk_toggle_tool_button_set_active(
751 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
755 void update_color_buttons(void)
757 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
758 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
759 gtk_toggle_tool_button_set_active(
760 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
762 switch (ui.cur_brush->color_no) {
764 gtk_toggle_tool_button_set_active(
765 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE);
768 gtk_toggle_tool_button_set_active(
769 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE);
772 gtk_toggle_tool_button_set_active(
773 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE);
776 gtk_toggle_tool_button_set_active(
777 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE);
780 gtk_toggle_tool_button_set_active(
781 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE);
783 case COLOR_LIGHTBLUE:
784 gtk_toggle_tool_button_set_active(
785 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE);
787 case COLOR_LIGHTGREEN:
788 gtk_toggle_tool_button_set_active(
789 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE);
792 gtk_toggle_tool_button_set_active(
793 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE);
796 gtk_toggle_tool_button_set_active(
797 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE);
800 gtk_toggle_tool_button_set_active(
801 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE);
804 gtk_toggle_tool_button_set_active(
805 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE);
808 gtk_toggle_tool_button_set_active(
809 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
813 void update_tool_buttons(void)
815 switch(ui.toolno[ui.cur_mapping]) {
817 gtk_toggle_tool_button_set_active(
818 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
821 gtk_toggle_tool_button_set_active(
822 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
824 case TOOL_HIGHLIGHTER:
825 gtk_toggle_tool_button_set_active(
826 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
829 gtk_toggle_tool_button_set_active(
830 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
832 case TOOL_SELECTREGION:
833 gtk_toggle_tool_button_set_active(
834 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
836 case TOOL_SELECTRECT:
837 gtk_toggle_tool_button_set_active(
838 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
841 gtk_toggle_tool_button_set_active(
842 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
845 gtk_toggle_tool_button_set_active(
846 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHand")), TRUE);
850 gtk_toggle_tool_button_set_active(
851 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
852 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
853 gtk_toggle_tool_button_set_active(
854 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
855 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
857 update_thickness_buttons();
858 update_color_buttons();
861 void update_tool_menu(void)
863 switch(ui.toolno[0]) {
865 gtk_check_menu_item_set_active(
866 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
869 gtk_check_menu_item_set_active(
870 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
872 case TOOL_HIGHLIGHTER:
873 gtk_check_menu_item_set_active(
874 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
877 gtk_check_menu_item_set_active(
878 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
880 case TOOL_SELECTREGION:
881 gtk_check_menu_item_set_active(
882 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
884 case TOOL_SELECTRECT:
885 gtk_check_menu_item_set_active(
886 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
889 gtk_check_menu_item_set_active(
890 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
893 gtk_check_menu_item_set_active(
894 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHand")), TRUE);
898 gtk_check_menu_item_set_active(
899 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
900 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
901 gtk_check_menu_item_set_active(
902 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
903 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
906 void update_ruler_indicator(void)
908 gtk_toggle_tool_button_set_active(
909 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
910 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
911 gtk_toggle_tool_button_set_active(
912 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
913 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
914 gtk_check_menu_item_set_active(
915 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
916 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
917 gtk_check_menu_item_set_active(
918 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
919 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
922 void update_color_menu(void)
924 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
925 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
926 gtk_check_menu_item_set_active(
927 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
929 switch (ui.cur_brush->color_no) {
931 gtk_check_menu_item_set_active(
932 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
935 gtk_check_menu_item_set_active(
936 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
939 gtk_check_menu_item_set_active(
940 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
943 gtk_check_menu_item_set_active(
944 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
947 gtk_check_menu_item_set_active(
948 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
950 case COLOR_LIGHTBLUE:
951 gtk_check_menu_item_set_active(
952 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
954 case COLOR_LIGHTGREEN:
955 gtk_check_menu_item_set_active(
956 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
959 gtk_check_menu_item_set_active(
960 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
963 gtk_check_menu_item_set_active(
964 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
967 gtk_check_menu_item_set_active(
968 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
971 gtk_check_menu_item_set_active(
972 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
975 gtk_check_menu_item_set_active(
976 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOther")), TRUE);
980 void update_pen_props_menu(void)
982 switch(ui.brushes[0][TOOL_PEN].thickness_no) {
983 case THICKNESS_VERYFINE:
984 gtk_check_menu_item_set_active(
985 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
988 gtk_check_menu_item_set_active(
989 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
991 case THICKNESS_MEDIUM:
992 gtk_check_menu_item_set_active(
993 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
995 case THICKNESS_THICK:
996 gtk_check_menu_item_set_active(
997 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
999 case THICKNESS_VERYTHICK:
1000 gtk_check_menu_item_set_active(
1001 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
1006 void update_eraser_props_menu(void)
1008 switch (ui.brushes[0][TOOL_ERASER].thickness_no) {
1009 case THICKNESS_FINE:
1010 gtk_check_menu_item_set_active(
1011 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
1013 case THICKNESS_MEDIUM:
1014 gtk_check_menu_item_set_active(
1015 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
1017 case THICKNESS_THICK:
1018 gtk_check_menu_item_set_active(
1019 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
1023 gtk_check_menu_item_set_active(
1024 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
1025 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
1026 gtk_check_menu_item_set_active(
1027 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
1028 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
1029 gtk_check_menu_item_set_active(
1030 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
1031 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
1034 void update_highlighter_props_menu(void)
1036 switch (ui.brushes[0][TOOL_HIGHLIGHTER].thickness_no) {
1037 case THICKNESS_FINE:
1038 gtk_check_menu_item_set_active(
1039 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
1041 case THICKNESS_MEDIUM:
1042 gtk_check_menu_item_set_active(
1043 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
1045 case THICKNESS_THICK:
1046 gtk_check_menu_item_set_active(
1047 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
1052 void update_mappings_menu_linkings(void)
1054 switch (ui.linked_brush[1]) {
1056 gtk_check_menu_item_set_active(
1057 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2LinkBrush")), TRUE);
1060 gtk_check_menu_item_set_active(
1061 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2CopyBrush")), TRUE);
1064 gtk_check_menu_item_set_active(
1065 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2NABrush")), TRUE);
1068 switch (ui.linked_brush[2]) {
1070 gtk_check_menu_item_set_active(
1071 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3LinkBrush")), TRUE);
1074 gtk_check_menu_item_set_active(
1075 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3CopyBrush")), TRUE);
1078 gtk_check_menu_item_set_active(
1079 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3NABrush")), TRUE);
1084 void update_mappings_menu(void)
1086 gtk_widget_set_sensitive(GET_COMPONENT("optionsButtonMappings"), ui.use_xinput);
1087 gtk_widget_set_sensitive(GET_COMPONENT("optionsDiscardCoreEvents"), ui.use_xinput);
1088 gtk_widget_set_sensitive(GET_COMPONENT("optionsPressureSensitive"), ui.use_xinput);
1089 gtk_check_menu_item_set_active(
1090 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsButtonMappings")), ui.use_erasertip);
1091 gtk_check_menu_item_set_active(
1092 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsDiscardCoreEvents")), ui.discard_corepointer);
1093 gtk_check_menu_item_set_active(
1094 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsPressureSensitive")), ui.pressure_sensitivity);
1096 switch(ui.toolno[1]) {
1098 gtk_check_menu_item_set_active(
1099 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Pen")), TRUE);
1102 gtk_check_menu_item_set_active(
1103 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Eraser")), TRUE);
1105 case TOOL_HIGHLIGHTER:
1106 gtk_check_menu_item_set_active(
1107 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Highlighter")), TRUE);
1110 gtk_check_menu_item_set_active(
1111 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Text")), TRUE);
1113 case TOOL_SELECTREGION:
1114 gtk_check_menu_item_set_active(
1115 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRegion")), TRUE);
1117 case TOOL_SELECTRECT:
1118 gtk_check_menu_item_set_active(
1119 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRectangle")), TRUE);
1121 case TOOL_VERTSPACE:
1122 gtk_check_menu_item_set_active(
1123 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2VerticalSpace")), TRUE);
1126 switch(ui.toolno[2]) {
1128 gtk_check_menu_item_set_active(
1129 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Pen")), TRUE);
1132 gtk_check_menu_item_set_active(
1133 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Eraser")), TRUE);
1135 case TOOL_HIGHLIGHTER:
1136 gtk_check_menu_item_set_active(
1137 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Highlighter")), TRUE);
1140 gtk_check_menu_item_set_active(
1141 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Text")), TRUE);
1143 case TOOL_SELECTREGION:
1144 gtk_check_menu_item_set_active(
1145 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRegion")), TRUE);
1147 case TOOL_SELECTRECT:
1148 gtk_check_menu_item_set_active(
1149 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRectangle")), TRUE);
1151 case TOOL_VERTSPACE:
1152 gtk_check_menu_item_set_active(
1153 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3VerticalSpace")), TRUE);
1156 update_mappings_menu_linkings();
1159 void do_switch_page(int pg, gboolean rescroll, gboolean refresh_all)
1162 struct Layer *layer;
1167 /* re-show all the layers of the old page */
1168 if (ui.cur_page != NULL)
1169 for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
1170 layer = (struct Layer *)list->data;
1171 if (layer->group!=NULL)
1172 gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
1175 ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
1176 ui.layerno = ui.cur_page->nlayers-1;
1177 ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
1178 update_page_stuff();
1179 if (ui.progressive_bg) rescale_bg_pixmaps();
1181 if (rescroll) { // scroll and force a refresh
1182 /* -- this seems to cause some display bugs ??
1183 gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)),
1184 ui.cur_page->voffset*ui.zoom); */
1185 gnome_canvas_get_scroll_offsets(canvas, &cx, &cy);
1186 cy = ui.cur_page->voffset*ui.zoom;
1187 gnome_canvas_scroll_to(canvas, cx, cy);
1190 gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
1191 else if (!ui.view_continuous)
1192 gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.cur_page->group), 0., 0.);
1196 void update_page_stuff(void)
1199 GtkComboBox *layerbox;
1202 GtkSpinButton *spin;
1204 double vertpos, maxwidth;
1206 // move the page groups to their rightful locations or hide them
1207 if (ui.view_continuous) {
1210 for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
1211 pg = (struct Page *)pglist->data;
1212 if (pg->group!=NULL) {
1213 pg->hoffset = 0.; pg->voffset = vertpos;
1214 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1215 "x", pg->hoffset, "y", pg->voffset, NULL);
1216 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1218 vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
1219 if (pg->width > maxwidth) maxwidth = pg->width;
1221 vertpos -= VIEW_CONTINUOUS_SKIP;
1222 gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
1224 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1225 pg = (struct Page *)pglist->data;
1226 if (pg == ui.cur_page && pg->group!=NULL) {
1227 pg->hoffset = 0.; pg->voffset = 0.;
1228 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1229 "x", pg->hoffset, "y", pg->voffset, NULL);
1230 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1232 if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
1235 gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
1238 // update the page / layer info at bottom of screen
1240 spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
1241 ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
1242 gtk_spin_button_set_range(spin, 1, journal.npages+1);
1243 /* npages+1 will be used to create a new page at end */
1244 gtk_spin_button_set_value(spin, ui.pageno+1);
1245 g_snprintf(tmp, 10, _(" of %d"), journal.npages);
1246 gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
1248 layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
1249 if (ui.layerbox_length == 0) {
1250 gtk_combo_box_prepend_text(layerbox, _("Background"));
1251 ui.layerbox_length++;
1253 while (ui.layerbox_length > ui.cur_page->nlayers+1) {
1254 gtk_combo_box_remove_text(layerbox, 0);
1255 ui.layerbox_length--;
1257 while (ui.layerbox_length < ui.cur_page->nlayers+1) {
1258 g_snprintf(tmp, 10, _("Layer %d"), ui.layerbox_length++);
1259 gtk_combo_box_prepend_text(layerbox, tmp);
1261 gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
1262 ui.in_update_page_stuff = FALSE;
1264 // update the paper-style menu radio buttons
1266 if (ui.view_continuous)
1267 gtk_check_menu_item_set_active(
1268 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
1270 gtk_check_menu_item_set_active(
1271 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
1273 if (ui.cur_page->bg->type == BG_SOLID && !ui.bg_apply_all_pages) {
1274 switch (ui.cur_page->bg->color_no) {
1276 gtk_check_menu_item_set_active(
1277 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
1280 gtk_check_menu_item_set_active(
1281 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
1284 gtk_check_menu_item_set_active(
1285 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1288 gtk_check_menu_item_set_active(
1289 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1292 gtk_check_menu_item_set_active(
1293 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1296 gtk_check_menu_item_set_active(
1297 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1300 gtk_check_menu_item_set_active(
1301 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE);
1304 switch (ui.cur_page->bg->ruling) {
1306 gtk_check_menu_item_set_active(
1307 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1310 gtk_check_menu_item_set_active(
1311 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1314 gtk_check_menu_item_set_active(
1315 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1318 gtk_check_menu_item_set_active(
1319 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1323 gtk_check_menu_item_set_active(
1324 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1325 gtk_check_menu_item_set_active(
1326 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1329 // enable/disable the page/layer menu items and toolbar buttons
1331 gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"),
1332 ui.cur_page->bg->type == BG_SOLID || ui.bg_apply_all_pages);
1333 gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1334 ui.cur_page->bg->type == BG_SOLID);
1336 gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1337 gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1338 gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1339 gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1340 gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1341 gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1342 gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1343 gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1345 gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1346 gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1348 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1349 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1352 void update_toolbar_and_menu(void)
1354 update_tool_buttons(); // takes care of other toolbar buttons as well
1356 update_color_menu();
1357 update_pen_props_menu();
1358 update_eraser_props_menu();
1359 update_highlighter_props_menu();
1360 update_mappings_menu();
1362 gtk_toggle_tool_button_set_active(
1363 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1364 gtk_check_menu_item_set_active(
1365 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1368 void update_file_name(char *filename)
1371 if (ui.filename != NULL) g_free(ui.filename);
1372 ui.filename = filename;
1373 if (filename == NULL) {
1374 gtk_window_set_title(GTK_WINDOW (winMain), _("Xournal"));
1377 p = g_utf8_strrchr(filename, -1, '/');
1378 if (p == NULL) p = filename;
1379 else p = g_utf8_next_char(p);
1380 g_snprintf(tmp, 100, _("Xournal - %s"), p);
1381 gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1382 new_mru_entry(filename);
1385 void update_undo_redo_enabled(void)
1387 gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1388 gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1389 gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1390 gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1393 void update_copy_paste_enabled(void)
1395 gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1396 gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1397 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_item_type!=ITEM_TEXT);
1398 gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1399 gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1400 gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1401 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_item_type!=ITEM_TEXT);
1404 void update_mapping_linkings(int toolno)
1408 for (i = 1; i<=NUM_BUTTONS; i++) {
1409 if (ui.linked_brush[i] == BRUSH_LINKED) {
1410 if (toolno >= 0 && toolno < NUM_STROKE_TOOLS)
1411 g_memmove(&(ui.brushes[i][toolno]), &(ui.brushes[0][toolno]), sizeof(struct Brush));
1413 if (ui.linked_brush[i] == BRUSH_COPIED && toolno == ui.toolno[i]) {
1414 ui.linked_brush[i] = BRUSH_STATIC;
1415 if (i==1 || i==2) update_mappings_menu_linkings();
1420 void set_cur_color(int color)
1422 ui.cur_brush->color_no = color;
1423 if (ui.toolno[0] == TOOL_HIGHLIGHTER)
1424 ui.cur_brush->color_rgba = predef_colors_rgba[color] & ui.hiliter_alpha_mask;
1426 ui.cur_brush->color_rgba = predef_colors_rgba[color];
1427 update_mapping_linkings(ui.toolno[0]);
1430 void recolor_temp_text(int color_no, guint color_rgba)
1434 if (ui.cur_item_type!=ITEM_TEXT) return;
1435 if (ui.cur_item->text!=NULL && ui.cur_item->brush.color_rgba != color_rgba) {
1437 undo->type = ITEM_TEXT_ATTRIB;
1438 undo->item = ui.cur_item;
1439 undo->str = g_strdup(ui.cur_item->font_name);
1440 undo->val_x = ui.cur_item->font_size;
1441 undo->brush = (struct Brush *)g_memdup(&(ui.cur_item->brush), sizeof(struct Brush));
1443 ui.cur_item->brush.color_no = color_no;
1444 ui.cur_item->brush.color_rgba = color_rgba;
1445 rgb_to_gdkcolor(color_rgba, &gdkcolor);
1446 gtk_widget_modify_text(ui.cur_item->widget, GTK_STATE_NORMAL, &gdkcolor);
1447 gtk_widget_grab_focus(ui.cur_item->widget);
1450 void process_color_activate(GtkMenuItem *menuitem, int color)
1452 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1453 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1456 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1460 if (ui.cur_mapping != 0) return; // not user-generated
1463 if (ui.cur_item_type == ITEM_TEXT)
1464 recolor_temp_text(color, predef_colors_rgba[color]);
1466 if (ui.selection != NULL) {
1467 recolor_selection(color);
1468 update_color_buttons();
1469 update_color_menu();
1472 if (ui.toolno[0] != TOOL_PEN && ui.toolno[0] != TOOL_HIGHLIGHTER
1473 && ui.toolno[0] != TOOL_TEXT) {
1474 if (ui.selection != NULL) return;
1476 ui.toolno[0] = TOOL_PEN;
1477 ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
1478 update_tool_buttons();
1482 set_cur_color(color);
1483 update_color_buttons();
1484 update_color_menu();
1488 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1490 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1491 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1494 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1498 if (ui.cur_mapping != 0) return; // not user-generated
1500 if (ui.selection != NULL && GTK_OBJECT_TYPE(menuitem) != GTK_TYPE_RADIO_MENU_ITEM) {
1502 rethicken_selection(val);
1503 update_thickness_buttons();
1506 if (tool >= NUM_STROKE_TOOLS) {
1507 update_thickness_buttons(); // undo illegal button selection
1511 if (ui.brushes[0][tool].thickness_no == val) return;
1514 ui.brushes[0][tool].thickness_no = val;
1515 ui.brushes[0][tool].thickness = predef_thickness[tool][val];
1516 update_mapping_linkings(tool);
1518 update_thickness_buttons();
1519 if (tool == TOOL_PEN) update_pen_props_menu();
1520 if (tool == TOOL_ERASER) update_eraser_props_menu();
1521 if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1525 void process_papercolor_activate(GtkMenuItem *menuitem, int color)
1531 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1534 if ((ui.cur_page->bg->type != BG_SOLID) || ui.bg_apply_all_pages)
1535 gtk_check_menu_item_set_active(
1536 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1540 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1541 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1542 if (pg->bg->type == BG_SOLID && pg->bg->color_no != color) {
1544 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1545 undo->multiop |= MULTIOP_CONT_REDO;
1547 undo->type = ITEM_NEW_BG_ONE;
1549 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1550 undo->bg->canvas_item = NULL;
1552 pg->bg->color_no = color;
1553 pg->bg->color_rgba = predef_bgcolors_rgba[color];
1554 update_canvas_bg(pg);
1556 if (!ui.bg_apply_all_pages) break;
1558 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1561 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1565 gboolean hasdone, must_upd;
1567 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1570 if (ui.bg_apply_all_pages)
1571 gtk_check_menu_item_set_active(
1572 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1577 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1578 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1579 if (pg->bg->type != BG_SOLID || pg->bg->ruling != style) {
1581 undo->type = ITEM_NEW_BG_ONE;
1582 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1583 undo->multiop |= MULTIOP_CONT_REDO;
1586 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1587 undo->bg->canvas_item = NULL;
1589 if (pg->bg->type != BG_SOLID) {
1590 pg->bg->type = BG_SOLID;
1591 pg->bg->color_no = COLOR_WHITE;
1592 pg->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1593 pg->bg->filename = NULL;
1594 pg->bg->pixbuf = NULL;
1597 pg->bg->ruling = style;
1598 update_canvas_bg(pg);
1600 if (!ui.bg_apply_all_pages) break;
1602 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1603 if (must_upd) update_page_stuff();
1606 gboolean ok_to_close(void)
1609 GtkResponseType response;
1611 if (ui.saved) return TRUE;
1612 dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1613 GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Save changes to '%s'?"),
1614 (ui.filename!=NULL) ? ui.filename:_("Untitled"));
1615 gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1616 response = gtk_dialog_run(GTK_DIALOG (dialog));
1617 gtk_widget_destroy(dialog);
1618 if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT)
1619 return FALSE; // aborted
1620 if (response == GTK_RESPONSE_YES) {
1621 on_fileSave_activate(NULL, NULL);
1622 if (!ui.saved) return FALSE; // if save failed, then we abort
1627 // send the focus back to the appropriate widget
1628 void reset_focus(void)
1630 if (ui.cur_item_type == ITEM_TEXT)
1631 gtk_widget_grab_focus(ui.cur_item->widget);
1633 gtk_widget_grab_focus(GTK_WIDGET(canvas));
1637 // selection / clipboard stuff
1639 void reset_selection(void)
1641 if (ui.selection == NULL) return;
1642 if (ui.selection->canvas_item != NULL)
1643 gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1644 g_list_free(ui.selection->items);
1645 g_free(ui.selection);
1646 ui.selection = NULL;
1647 update_copy_paste_enabled();
1648 update_color_menu();
1649 update_thickness_buttons();
1650 update_color_buttons();
1651 update_font_button();
1655 void move_journal_items_by(GList *itemlist, double dx, double dy,
1656 struct Layer *l1, struct Layer *l2, GList *depths)
1659 GnomeCanvasItem *refitem;
1664 while (itemlist!=NULL) {
1665 item = (struct Item *)itemlist->data;
1666 if (item->type == ITEM_STROKE)
1667 for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1668 { pt[0] += dx; pt[1] += dy; }
1669 if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type == ITEM_TEMP_TEXT) {
1670 item->bbox.left += dx;
1671 item->bbox.right += dx;
1672 item->bbox.top += dy;
1673 item->bbox.bottom += dy;
1676 // find out where to insert
1677 if (depths != NULL) {
1678 if (depths->data == NULL) link = l2->items;
1680 link = g_list_find(l2->items, depths->data);
1681 if (link != NULL) link = link->next;
1684 l2->items = g_list_insert_before(l2->items, link, item);
1686 l1->items = g_list_remove(l1->items, item);
1689 if (depths != NULL) { // also raise/lower the canvas items
1690 if (item->canvas_item!=NULL) {
1691 if (depths->data == NULL) link = NULL;
1692 else link = g_list_find(l2->items, depths->data);
1693 if (link != NULL) refitem = ((struct Item *)(link->data))->canvas_item;
1694 else refitem = NULL;
1695 lower_canvas_item_to(l2->group, item->canvas_item, refitem);
1697 depths = depths->next;
1699 itemlist = itemlist->next;
1703 void resize_journal_items_by(GList *itemlist, double scaling_x, double scaling_y,
1704 double offset_x, double offset_y)
1708 double mean_scaling, temp;
1710 GnomeCanvasGroup *group;
1713 /* geometric mean of x and y scalings = rescaling for stroke widths
1714 and for text font sizes */
1715 mean_scaling = sqrt(fabs(scaling_x * scaling_y));
1717 for (list = itemlist; list != NULL; list = list->next) {
1718 item = (struct Item *)list->data;
1719 if (item->type == ITEM_STROKE) {
1720 item->brush.thickness = item->brush.thickness * mean_scaling;
1721 for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {
1722 pt[0] = pt[0]*scaling_x + offset_x;
1723 pt[1] = pt[1]*scaling_y + offset_y;
1725 if (item->brush.variable_width)
1726 for (i=0, wid=item->widths; i<item->path->num_points-1; i++, wid++)
1727 *wid = *wid * mean_scaling;
1729 item->bbox.left = item->bbox.left*scaling_x + offset_x;
1730 item->bbox.right = item->bbox.right*scaling_x + offset_x;
1731 item->bbox.top = item->bbox.top*scaling_y + offset_y;
1732 item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
1733 if (item->bbox.left > item->bbox.right) {
1734 temp = item->bbox.left;
1735 item->bbox.left = item->bbox.right;
1736 item->bbox.right = temp;
1738 if (item->bbox.top > item->bbox.bottom) {
1739 temp = item->bbox.top;
1740 item->bbox.top = item->bbox.bottom;
1741 item->bbox.bottom = temp;
1744 if (item->type == ITEM_TEXT) {
1745 /* must scale about NW corner -- all other points of the text box
1746 are font- and zoom-dependent, so scaling about center of text box
1747 couldn't be undone properly. FIXME? */
1748 item->font_size *= mean_scaling;
1749 item->bbox.left = item->bbox.left*scaling_x + offset_x;
1750 item->bbox.top = item->bbox.top*scaling_y + offset_y;
1753 if (item->canvas_item!=NULL) {
1754 group = (GnomeCanvasGroup *) item->canvas_item->parent;
1755 gtk_object_destroy(GTK_OBJECT(item->canvas_item));
1756 make_canvas_item_one(group, item);
1761 // Switch between button mappings
1763 /* NOTE ABOUT BUTTON MAPPINGS: ui.cur_mapping is 0 except while a canvas
1764 click event is being processed ... */
1766 void switch_mapping(int m)
1768 if (ui.cur_mapping == m) return;
1771 if (ui.toolno[m] < NUM_STROKE_TOOLS)
1772 ui.cur_brush = &(ui.brushes[m][ui.toolno[m]]);
1773 if (ui.toolno[m] == TOOL_TEXT)
1774 ui.cur_brush = &(ui.brushes[m][TOOL_PEN]);
1775 update_tool_buttons();
1776 update_color_menu();
1780 void process_mapping_activate(GtkMenuItem *menuitem, int m, int tool)
1782 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return;
1783 if (ui.cur_mapping!=0) return;
1784 if (ui.toolno[m] == tool) return;
1788 ui.toolno[m] = tool;
1789 if (ui.linked_brush[m] == BRUSH_COPIED) {
1790 ui.linked_brush[m] = BRUSH_STATIC;
1791 update_mappings_menu_linkings();
1795 // update the ordering of components in the main vbox
1797 const char *vbox_component_names[VBOX_MAIN_NITEMS]=
1798 {"scrolledwindowMain", "menubar", "toolbarMain", "toolbarPen", "hbox1"};
1800 void update_vbox_order(int *order)
1804 GtkBox *vboxMain = GTK_BOX(GET_COMPONENT("vboxMain"));
1805 gboolean present[VBOX_MAIN_NITEMS];
1807 for (i=0; i<VBOX_MAIN_NITEMS; i++) present[i] = FALSE;
1809 for (i=0; i<VBOX_MAIN_NITEMS; i++) {
1810 if (order[i]<0 || order[i]>=VBOX_MAIN_NITEMS) continue;
1811 present[order[i]] = TRUE;
1812 child = GET_COMPONENT(vbox_component_names[order[i]]);
1813 gtk_box_reorder_child(vboxMain, child, j++);
1814 gtk_widget_show(child);
1816 for (i=1; i<VBOX_MAIN_NITEMS; i++) // hide others, but not the drawing area!
1817 if (!present[i]) gtk_widget_hide(GET_COMPONENT(vbox_component_names[i]));
1820 gchar *make_cur_font_name(void)
1825 if (ui.cur_item_type == ITEM_TEXT)
1826 str = g_strdup_printf("%s %.1f", ui.cur_item->font_name, ui.cur_item->font_size);
1827 else if (ui.selection!=NULL && ui.selection->items!=NULL &&
1828 ui.selection->items->next==NULL &&
1829 (it=(struct Item*)ui.selection->items->data)->type == ITEM_TEXT)
1830 str = g_strdup_printf("%s %.1f", it->font_name, it->font_size);
1832 str = g_strdup_printf("%s %.1f", ui.font_name, ui.font_size);
1836 void update_font_button(void)
1840 str = make_cur_font_name();
1841 gtk_font_button_set_font_name(GTK_FONT_BUTTON(GET_COMPONENT("fontButton")), str);
1845 gboolean can_accel(GtkWidget *widget, guint id, gpointer data)
1847 return GTK_WIDGET_SENSITIVE(widget);
1850 void allow_all_accels(void)
1852 g_signal_connect((gpointer) GET_COMPONENT("fileNew"),
1853 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1854 g_signal_connect((gpointer) GET_COMPONENT("fileOpen"),
1855 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1856 g_signal_connect((gpointer) GET_COMPONENT("fileSave"),
1857 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1858 g_signal_connect((gpointer) GET_COMPONENT("filePrint"),
1859 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1860 g_signal_connect((gpointer) GET_COMPONENT("filePrintPDF"),
1861 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1862 g_signal_connect((gpointer) GET_COMPONENT("fileQuit"),
1863 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1864 g_signal_connect((gpointer) GET_COMPONENT("editUndo"),
1865 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1866 g_signal_connect((gpointer) GET_COMPONENT("editRedo"),
1867 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1868 g_signal_connect((gpointer) GET_COMPONENT("editCut"),
1869 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1870 g_signal_connect((gpointer) GET_COMPONENT("editCopy"),
1871 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1872 g_signal_connect((gpointer) GET_COMPONENT("editPaste"),
1873 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1874 g_signal_connect((gpointer) GET_COMPONENT("editDelete"),
1875 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1876 g_signal_connect((gpointer) GET_COMPONENT("viewFullscreen"),
1877 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1878 g_signal_connect((gpointer) GET_COMPONENT("viewZoomIn"),
1879 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1880 g_signal_connect((gpointer) GET_COMPONENT("viewZoomOut"),
1881 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1882 g_signal_connect((gpointer) GET_COMPONENT("viewNormalSize"),
1883 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1884 g_signal_connect((gpointer) GET_COMPONENT("viewPageWidth"),
1885 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1886 g_signal_connect((gpointer) GET_COMPONENT("viewFirstPage"),
1887 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1888 g_signal_connect((gpointer) GET_COMPONENT("viewPreviousPage"),
1889 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1890 g_signal_connect((gpointer) GET_COMPONENT("viewNextPage"),
1891 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1892 g_signal_connect((gpointer) GET_COMPONENT("viewLastPage"),
1893 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1894 g_signal_connect((gpointer) GET_COMPONENT("toolsPen"),
1895 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1896 g_signal_connect((gpointer) GET_COMPONENT("toolsEraser"),
1897 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1898 g_signal_connect((gpointer) GET_COMPONENT("toolsHighlighter"),
1899 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1900 g_signal_connect((gpointer) GET_COMPONENT("toolsText"),
1901 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1902 /* g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
1903 "can-activate-accel", G_CALLBACK(can_accel), NULL); */
1904 g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRectangle"),
1905 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1906 g_signal_connect((gpointer) GET_COMPONENT("toolsVerticalSpace"),
1907 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1908 g_signal_connect((gpointer) GET_COMPONENT("toolsHand"),
1909 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1910 g_signal_connect((gpointer) GET_COMPONENT("toolsTextFont"),
1911 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1912 g_signal_connect((gpointer) GET_COMPONENT("toolsRuler"),
1913 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1914 g_signal_connect((gpointer) GET_COMPONENT("toolsReco"),
1915 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1918 void add_scroll_bindings(void)
1920 GtkBindingSet *binding_set;
1922 binding_set = gtk_binding_set_by_class(
1923 G_OBJECT_GET_CLASS(GET_COMPONENT("scrolledwindowMain")));
1924 gtk_binding_entry_add_signal(binding_set, GDK_Up, 0,
1925 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1926 G_TYPE_BOOLEAN, FALSE);
1927 gtk_binding_entry_add_signal(binding_set, GDK_KP_Up, 0,
1928 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1929 G_TYPE_BOOLEAN, FALSE);
1930 gtk_binding_entry_add_signal(binding_set, GDK_Down, 0,
1931 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1932 G_TYPE_BOOLEAN, FALSE);
1933 gtk_binding_entry_add_signal(binding_set, GDK_KP_Down, 0,
1934 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1935 G_TYPE_BOOLEAN, FALSE);
1936 gtk_binding_entry_add_signal(binding_set, GDK_Left, 0,
1937 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1938 G_TYPE_BOOLEAN, TRUE);
1939 gtk_binding_entry_add_signal(binding_set, GDK_KP_Left, 0,
1940 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1941 G_TYPE_BOOLEAN, TRUE);
1942 gtk_binding_entry_add_signal(binding_set, GDK_Right, 0,
1943 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1944 G_TYPE_BOOLEAN, TRUE);
1945 gtk_binding_entry_add_signal(binding_set, GDK_KP_Right, 0,
1946 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1947 G_TYPE_BOOLEAN, TRUE);
1950 gboolean is_event_within_textview(GdkEventButton *event)
1954 if (ui.cur_item_type!=ITEM_TEXT) return FALSE;
1955 get_pointer_coords((GdkEvent *)event, pt);
1956 if (pt[0]<ui.cur_item->bbox.left || pt[0]>ui.cur_item->bbox.right) return FALSE;
1957 if (pt[1]<ui.cur_item->bbox.top || pt[1]>ui.cur_item->bbox.bottom) return FALSE;
1961 void hide_unimplemented(void)
1963 gtk_widget_hide(GET_COMPONENT("filePrintOptions"));
1964 gtk_widget_hide(GET_COMPONENT("journalFlatten"));
1965 gtk_widget_hide(GET_COMPONENT("papercolorOther"));
1966 gtk_widget_hide(GET_COMPONENT("toolsSelectRegion"));
1967 gtk_widget_hide(GET_COMPONENT("buttonSelectRegion"));
1968 gtk_widget_hide(GET_COMPONENT("button2SelectRegion"));
1969 gtk_widget_hide(GET_COMPONENT("button3SelectRegion"));
1970 gtk_widget_hide(GET_COMPONENT("colorOther"));
1971 gtk_widget_hide(GET_COMPONENT("helpIndex"));
1973 /* config file only works with glib 2.6 and beyond */
1974 if (glib_minor_version<6) {
1975 gtk_widget_hide(GET_COMPONENT("optionsAutoSavePrefs"));
1976 gtk_widget_hide(GET_COMPONENT("optionsSavePreferences"));
1978 /* gtkprint only works with gtk+ 2.10 and beyond */
1979 if (gtk_check_version(2, 10, 0)) {
1980 gtk_widget_hide(GET_COMPONENT("filePrint"));
1984 // toggle fullscreen mode
1985 void do_fullscreen(gboolean active)
1989 ui.fullscreen = active;
1990 gtk_check_menu_item_set_active(
1991 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1992 gtk_toggle_tool_button_set_active(
1993 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1995 if (ui.fullscreen) gtk_window_fullscreen(GTK_WINDOW(winMain));
1996 else gtk_window_unfullscreen(GTK_WINDOW(winMain));
1998 update_vbox_order(ui.vertical_order[ui.fullscreen?1:0]);
2001 /* attempt to work around GTK+ 2.16/2.17 bugs where random interface
2002 elements receive XInput events that they can't handle properly */
2004 // prevent interface items from getting bogus XInput events
2006 gboolean filter_extended_events (GtkWidget *widget, GdkEvent *event,
2009 if (event->type == GDK_MOTION_NOTIFY &&
2010 event->motion.device != gdk_device_get_core_pointer())
2012 if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
2013 event->type == GDK_3BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2014 event->button.device != gdk_device_get_core_pointer())
2019 /* Code to turn an extended input event into a core event and send it to
2020 a different GdkWindow -- e.g. could be used when a click in a text edit box
2021 gets sent to the canvas instead due to incorrect event translation.
2022 We now turn off xinput altogether while editing text under GTK+ 2.17, so
2023 this isn't needed any more... but could become useful again someday!
2027 gboolean fix_extended_events (GtkWidget *widget, GdkEvent *event,
2033 if (user_data) window = (GdkWindow *)user_data;
2034 else window = widget->window;
2036 if (event->type == GDK_MOTION_NOTIFY &&
2037 event->motion.device != gdk_device_get_core_pointer()) {
2038 // printf("fixing motion\n");
2039 gdk_window_get_pointer(window, &ix, &iy, NULL);
2040 event->motion.x = ix; event->motion.y = iy;
2041 event->motion.device = gdk_device_get_core_pointer();
2042 g_object_unref(event->motion.window);
2043 event->motion.window = g_object_ref(window);
2044 gtk_widget_event(widget, event);
2047 if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2048 event->button.device != gdk_device_get_core_pointer()) {
2049 // printf("fixing button from pos = %f, %f\n", event->button.x, event->button.y);
2050 gdk_window_get_pointer(window, &ix, &iy, NULL);
2051 event->button.x = ix; event->button.y = iy;
2052 event->button.device = gdk_device_get_core_pointer();
2053 g_object_unref(event->button.window);
2054 event->button.window = g_object_ref(window);
2055 // printf("fixing button to pos = %f, %f\n", event->button.x, event->button.y);
2056 gtk_widget_event(widget, event);
2063 // disable xinput when layer combo box is popped up, to avoid crash
2065 gboolean combobox_popup_disable_xinput (GtkWidget *widget, GdkEvent *event,
2070 g_object_get(G_OBJECT(widget), "popup-shown", &is_shown, NULL);
2071 gdk_input_set_extension_events(GTK_WIDGET(canvas)->window,
2072 GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK,
2073 (ui.use_xinput && !is_shown)?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);