8 #include <libgnomecanvas/libgnomecanvas.h>
9 #include <gdk/gdkkeysyms.h>
12 #include "xo-interface.h"
13 #include "xo-support.h"
14 #include "xo-callbacks.h"
18 #include "xo-shapes.h"
20 // some global constants
22 guint predef_colors_rgba[COLOR_MAX] =
23 { 0x000000ff, 0x3333ccff, 0xff0000ff, 0x008000ff,
24 0x808080ff, 0x00c0ffff, 0x00ff00ff, 0xff00ffff,
25 0xff8000ff, 0xffff00ff, 0xffffffff };
27 guint predef_bgcolors_rgba[COLOR_MAX] = // meaningless ones set to white
28 { 0xffffffff, 0xa0e8ffff, 0xffc0d4ff, 0x80ffc0ff,
29 0xffffffff, 0xa0e8ffff, 0x80ffc0ff, 0xffc0d4ff,
30 0xffc080ff, 0xffff80ff, 0xffffffff };
32 double predef_thickness[NUM_STROKE_TOOLS][THICKNESS_MAX] =
33 { { 0.42, 0.85, 1.41, 2.26, 5.67 }, // pen thicknesses = 0.15, 0.3, 0.5, 0.8, 2 mm
34 { 2.83, 2.83, 8.50, 19.84, 19.84 }, // eraser thicknesses = 1, 3, 7 mm
35 { 2.83, 2.83, 8.50, 19.84, 19.84 }, // highlighter thicknesses = 1, 3, 7 mm
38 // some manipulation functions
40 struct Page *new_page(struct Page *template)
42 struct Page *pg = (struct Page *) g_memdup(template, sizeof(struct Page));
43 struct Layer *l = g_new(struct Layer, 1);
47 pg->layers = g_list_append(NULL, l);
49 pg->bg = (struct Background *)g_memdup(template->bg, sizeof(struct Background));
50 pg->bg->canvas_item = NULL;
51 if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
52 gdk_pixbuf_ref(pg->bg->pixbuf);
53 refstring_ref(pg->bg->filename);
55 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
56 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
57 make_page_clipbox(pg);
59 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
60 pg->group, gnome_canvas_group_get_type(), NULL);
65 /* Create a page from a background.
66 Note: bg should be an UNREFERENCED background.
67 If needed, first duplicate it and increase the refcount of the pixbuf.
69 struct Page *new_page_with_bg(struct Background *bg, double width, double height)
71 struct Page *pg = g_new(struct Page, 1);
72 struct Layer *l = g_new(struct Layer, 1);
76 pg->layers = g_list_append(NULL, l);
79 pg->bg->canvas_item = NULL;
82 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
83 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
84 make_page_clipbox(pg);
86 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
87 pg->group, gnome_canvas_group_get_type(), NULL);
92 void realloc_cur_path(int n)
94 if (n <= ui.cur_path_storage_alloc) return;
95 ui.cur_path_storage_alloc = n+10;
96 ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+10)*sizeof(double));
99 void realloc_cur_widths(int n)
101 if (n <= ui.cur_widths_storage_alloc) return;
102 ui.cur_widths_storage_alloc = n+10;
103 ui.cur_widths = g_realloc(ui.cur_widths, (n+10)*sizeof(double));
106 // undo utility functions
108 void prepare_new_undo(void)
111 // add a new UndoItem on the stack
112 u = (struct UndoItem *)g_malloc(sizeof(struct UndoItem));
120 void clear_redo_stack(void)
124 struct UndoErasureData *erasure;
127 /* Warning: the redo items might reference items from past redo entries,
128 which have been destroyed before them. Be careful! As a rule, it's
129 safe to destroy data which has been created at the current history step,
130 it's unsafe to refer to any data from previous history steps */
133 if (redo->type == ITEM_STROKE) {
134 gnome_canvas_points_free(redo->item->path);
135 if (redo->item->brush.variable_width) g_free(redo->item->widths);
137 /* the strokes are unmapped, so there are no associated canvas items */
139 else if (redo->type == ITEM_TEXT) {
140 g_free(redo->item->text);
141 g_free(redo->item->font_name);
144 else if (redo->type == ITEM_ERASURE || redo->type == ITEM_RECOGNIZER) {
145 for (list = redo->erasurelist; list!=NULL; list=list->next) {
146 erasure = (struct UndoErasureData *)list->data;
147 for (repl = erasure->replacement_items; repl!=NULL; repl=repl->next) {
148 it = (struct Item *)repl->data;
149 gnome_canvas_points_free(it->path);
150 if (it->brush.variable_width) g_free(it->widths);
153 g_list_free(erasure->replacement_items);
156 g_list_free(redo->erasurelist);
158 else if (redo->type == ITEM_NEW_BG_ONE || redo->type == ITEM_NEW_BG_RESIZE
159 || redo->type == ITEM_NEW_DEFAULT_BG) {
160 if (redo->bg->type == BG_PIXMAP || redo->bg->type == BG_PDF) {
161 if (redo->bg->pixbuf!=NULL) gdk_pixbuf_unref(redo->bg->pixbuf);
162 refstring_unref(redo->bg->filename);
166 else if (redo->type == ITEM_NEW_PAGE) {
167 redo->page->group = NULL;
168 delete_page(redo->page);
170 else if (redo->type == ITEM_MOVESEL || redo->type == ITEM_REPAINTSEL) {
171 g_list_free(redo->itemlist); g_list_free(redo->auxlist);
173 else if (redo->type == ITEM_RESIZESEL) {
174 g_list_free(redo->itemlist);
176 else if (redo->type == ITEM_PASTE) {
177 for (list = redo->itemlist; list!=NULL; list=list->next) {
178 it = (struct Item *)list->data;
179 if (it->type == ITEM_STROKE) {
180 gnome_canvas_points_free(it->path);
181 if (it->brush.variable_width) g_free(it->widths);
185 g_list_free(redo->itemlist);
187 else if (redo->type == ITEM_NEW_LAYER) {
190 else if (redo->type == ITEM_TEXT_EDIT || redo->type == ITEM_TEXT_ATTRIB) {
192 if (redo->type == ITEM_TEXT_ATTRIB) g_free(redo->brush);
199 update_undo_redo_enabled();
202 void clear_undo_stack(void)
206 struct UndoErasureData *erasure;
209 // for strokes, items are already in the journal, so we don't free them
210 // for erasures, we need to free the dead items
211 if (undo->type == ITEM_ERASURE || undo->type == ITEM_RECOGNIZER) {
212 for (list = undo->erasurelist; list!=NULL; list=list->next) {
213 erasure = (struct UndoErasureData *)list->data;
214 if (erasure->item->type == ITEM_STROKE) {
215 gnome_canvas_points_free(erasure->item->path);
216 if (erasure->item->brush.variable_width) g_free(erasure->item->widths);
218 if (erasure->item->type == ITEM_TEXT)
219 { g_free(erasure->item->text); g_free(erasure->item->font_name); }
220 g_free(erasure->item);
221 g_list_free(erasure->replacement_items);
224 g_list_free(undo->erasurelist);
226 else if (undo->type == ITEM_NEW_BG_ONE || undo->type == ITEM_NEW_BG_RESIZE
227 || undo->type == ITEM_NEW_DEFAULT_BG) {
228 if (undo->bg->type == BG_PIXMAP || undo->bg->type == BG_PDF) {
229 if (undo->bg->pixbuf!=NULL) gdk_pixbuf_unref(undo->bg->pixbuf);
230 refstring_unref(undo->bg->filename);
234 else if (undo->type == ITEM_MOVESEL || undo->type == ITEM_REPAINTSEL) {
235 g_list_free(undo->itemlist); g_list_free(undo->auxlist);
237 else if (undo->type == ITEM_RESIZESEL) {
238 g_list_free(undo->itemlist);
240 else if (undo->type == ITEM_PASTE) {
241 g_list_free(undo->itemlist);
243 else if (undo->type == ITEM_DELETE_LAYER) {
244 undo->layer->group = NULL;
245 delete_layer(undo->layer);
247 else if (undo->type == ITEM_DELETE_PAGE) {
248 undo->page->group = NULL;
249 delete_page(undo->page);
251 else if (undo->type == ITEM_TEXT_EDIT || undo->type == ITEM_TEXT_ATTRIB) {
253 if (undo->type == ITEM_TEXT_ATTRIB) g_free(undo->brush);
260 update_undo_redo_enabled();
263 // free data structures
265 void delete_journal(struct Journal *j)
267 while (j->pages!=NULL) {
268 delete_page((struct Page *)j->pages->data);
269 j->pages = g_list_delete_link(j->pages, j->pages);
273 void delete_page(struct Page *pg)
277 while (pg->layers!=NULL) {
278 l = (struct Layer *)pg->layers->data;
281 pg->layers = g_list_delete_link(pg->layers, pg->layers);
283 if (pg->group!=NULL) gtk_object_destroy(GTK_OBJECT(pg->group));
284 // this also destroys the background's canvas items
285 if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
286 if (pg->bg->pixbuf != NULL) gdk_pixbuf_unref(pg->bg->pixbuf);
287 if (pg->bg->filename != NULL) refstring_unref(pg->bg->filename);
293 void delete_layer(struct Layer *l)
297 while (l->items!=NULL) {
298 item = (struct Item *)l->items->data;
299 if (item->type == ITEM_STROKE && item->path != NULL)
300 gnome_canvas_points_free(item->path);
301 if (item->type == ITEM_TEXT) {
302 g_free(item->font_name); g_free(item->text);
304 // don't need to delete the canvas_item, as it's part of the group destroyed below
306 l->items = g_list_delete_link(l->items, l->items);
308 if (l->group!= NULL) gtk_object_destroy(GTK_OBJECT(l->group));
312 // referenced strings
314 struct Refstring *new_refstring(const char *s)
316 struct Refstring *rs = g_new(struct Refstring, 1);
318 if (s!=NULL) rs->s = g_strdup(s);
324 struct Refstring *refstring_ref(struct Refstring *rs)
330 void refstring_unref(struct Refstring *rs)
334 if (rs->s!=NULL) g_free(rs->s);
335 if (rs->aux!=NULL) g_free(rs->aux);
341 // some helper functions
343 void get_pointer_coords(GdkEvent *event, gdouble *ret)
346 gdk_event_get_coords(event, &x, &y);
347 gnome_canvas_window_to_world(canvas, x, y, ret, ret+1);
348 ret[0] -= ui.cur_page->hoffset;
349 ret[1] -= ui.cur_page->voffset;
352 void fix_xinput_coords(GdkEvent *event)
354 double *axes, *px, *py, axis_width;
356 int wx, wy, sx, sy, ix, iy;
358 if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
359 axes = event->button.axes;
360 px = &(event->button.x);
361 py = &(event->button.y);
362 device = event->button.device;
364 else if (event->type == GDK_MOTION_NOTIFY) {
365 axes = event->motion.axes;
366 px = &(event->motion.x);
367 py = &(event->motion.y);
368 device = event->motion.device;
370 else return; // nothing we know how to do
372 // use canvas window, not event window (else get GTK+ 2.11 bugs!)
373 gdk_window_get_origin(GTK_WIDGET(canvas)->window, &wx, &wy);
374 gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
376 #ifdef ENABLE_XINPUT_BUGFIX
377 // fix broken events with the core pointer's location
378 if (!finite(axes[0]) || !finite(axes[1]) || (axes[0]==0. && axes[1]==0.)) {
379 gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
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;
394 double get_pressure_multiplier(GdkEvent *event)
398 if (event->button.device == gdk_device_get_core_pointer()
399 || event->button.device->num_axes <= 2) return 1.0;
401 rawpressure = event->button.axes[2]/(event->button.device->axes[2].max - event->button.device->axes[2].min);
403 return ((1-rawpressure)*ui.width_minimum_multiplier + rawpressure*ui.width_maximum_multiplier);
406 void update_item_bbox(struct Item *item)
411 if (item->type == ITEM_STROKE) {
412 item->bbox.left = item->bbox.right = item->path->coords[0];
413 item->bbox.top = item->bbox.bottom = item->path->coords[1];
414 for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
416 if (p[0] < item->bbox.left) item->bbox.left = p[0];
417 if (p[0] > item->bbox.right) item->bbox.right = p[0];
418 if (p[1] < item->bbox.top) item->bbox.top = p[1];
419 if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
422 if (item->type == ITEM_TEXT && item->canvas_item!=NULL) {
424 g_object_get(item->canvas_item, "text_width", &w, "text_height", &h, NULL);
425 item->bbox.right = item->bbox.left + w;
426 item->bbox.bottom = item->bbox.top + h;
430 void make_page_clipbox(struct Page *pg)
432 GnomeCanvasPathDef *pg_clip;
434 pg_clip = gnome_canvas_path_def_new_sized(4);
435 gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
436 gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
437 gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
438 gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
439 gnome_canvas_path_def_closepath(pg_clip);
440 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
441 gnome_canvas_path_def_unref(pg_clip);
444 void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item)
446 PangoFontDescription *font_desc;
447 GnomeCanvasPoints points;
450 if (item->type == ITEM_STROKE) {
451 if (!item->brush.variable_width)
452 item->canvas_item = gnome_canvas_item_new(group,
453 gnome_canvas_line_get_type(), "points", item->path,
454 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
455 "fill-color-rgba", item->brush.color_rgba,
456 "width-units", item->brush.thickness, NULL);
458 item->canvas_item = gnome_canvas_item_new(group,
459 gnome_canvas_group_get_type(), NULL);
460 points.num_points = 2;
461 points.ref_count = 1;
462 for (j = 0; j < item->path->num_points-1; j++) {
463 points.coords = item->path->coords+2*j;
464 gnome_canvas_item_new((GnomeCanvasGroup *) item->canvas_item,
465 gnome_canvas_line_get_type(), "points", &points,
466 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
467 "fill-color-rgba", item->brush.color_rgba,
468 "width-units", item->widths[j], NULL);
472 if (item->type == ITEM_TEXT) {
473 font_desc = pango_font_description_from_string(item->font_name);
474 pango_font_description_set_absolute_size(font_desc,
475 item->font_size*ui.zoom*PANGO_SCALE);
476 item->canvas_item = gnome_canvas_item_new(group,
477 gnome_canvas_text_get_type(),
478 "x", item->bbox.left, "y", item->bbox.top, "anchor", GTK_ANCHOR_NW,
479 "font-desc", font_desc, "fill-color-rgba", item->brush.color_rgba,
480 "text", item->text, NULL);
481 update_item_bbox(item);
485 void make_canvas_items(void)
490 GList *pagelist, *layerlist, *itemlist;
492 for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
493 pg = (struct Page *)pagelist->data;
494 if (pg->group == NULL) {
495 pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
496 gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
497 make_page_clipbox(pg);
499 if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
500 for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
501 l = (struct Layer *)layerlist->data;
502 if (l->group == NULL)
503 l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
504 pg->group, gnome_canvas_group_get_type(), NULL);
505 for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
506 item = (struct Item *)itemlist->data;
507 if (item->canvas_item == NULL)
508 make_canvas_item_one(l->group, item);
514 void update_canvas_bg(struct Page *pg)
516 GnomeCanvasGroup *group;
517 GnomeCanvasPoints *seg;
518 GdkPixbuf *scaled_pix;
522 gboolean is_well_scaled;
524 if (pg->bg->canvas_item != NULL)
525 gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
526 pg->bg->canvas_item = NULL;
528 if (pg->bg->type == BG_SOLID)
530 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
531 gnome_canvas_group_get_type(), NULL);
532 group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
533 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
534 gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
535 "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
536 "fill-color-rgba", pg->bg->color_rgba, NULL);
537 if (pg->bg->ruling == RULING_NONE) return;
538 seg = gnome_canvas_points_new(2);
540 if (pg->bg->ruling == RULING_GRAPH) {
541 pt[1] = 0; pt[3] = pg->height;
542 for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
544 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
545 "points", seg, "fill-color-rgba", RULING_COLOR,
546 "width-units", RULING_THICKNESS, NULL);
548 pt[0] = 0; pt[2] = pg->width;
549 for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
551 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
552 "points", seg, "fill-color-rgba", RULING_COLOR,
553 "width-units", RULING_THICKNESS, NULL);
555 gnome_canvas_points_free(seg);
558 pt[0] = 0; pt[2] = pg->width;
559 for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
561 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
562 "points", seg, "fill-color-rgba", RULING_COLOR,
563 "width-units", RULING_THICKNESS, NULL);
565 if (pg->bg->ruling == RULING_LINED) {
566 pt[0] = pt[2] = RULING_LEFTMARGIN;
567 pt[1] = 0; pt[3] = pg->height;
568 gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
569 "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
570 "width-units", RULING_THICKNESS, NULL);
572 gnome_canvas_points_free(seg);
576 if (pg->bg->type == BG_PIXMAP)
578 if (ui.antialias_bg) {
579 set_cursor_busy(TRUE);
580 w = (int)floor(pg->width*ui.zoom+0.5);
581 h = (int)floor(pg->height*ui.zoom+0.5);
582 if (w == gdk_pixbuf_get_width(pg->bg->pixbuf) &&
583 h == gdk_pixbuf_get_height(pg->bg->pixbuf))
584 scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
586 scaled_pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf, w, h, GDK_INTERP_BILINEAR);
587 pg->bg->pixbuf_scale = ui.zoom;
588 set_cursor_busy(FALSE);
591 scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
592 pg->bg->pixbuf_scale = 0;
594 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
595 gnome_canvas_pixbuf_get_type(),
596 "pixbuf", scaled_pix,
597 "width", pg->width, "height", pg->height,
598 "width-set", TRUE, "height-set", TRUE,
600 gdk_pixbuf_unref(scaled_pix);
601 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
604 if (pg->bg->type == BG_PDF)
606 if (pg->bg->pixbuf == NULL) return;
607 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
608 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
610 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
611 gnome_canvas_pixbuf_get_type(),
612 "pixbuf", pg->bg->pixbuf,
613 "width-in-pixels", TRUE, "height-in-pixels", TRUE,
616 pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
617 gnome_canvas_pixbuf_get_type(),
618 "pixbuf", pg->bg->pixbuf,
619 "width", pg->width, "height", pg->height,
620 "width-set", TRUE, "height-set", TRUE,
622 lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
626 gboolean is_visible(struct Page *pg)
628 GtkAdjustment *v_adj;
631 if (!ui.view_continuous) return (pg == ui.cur_page);
632 v_adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
633 ytop = v_adj->value/ui.zoom;
634 ybot = (v_adj->value + v_adj->page_size) / ui.zoom;
635 return (MAX(ytop, pg->voffset) < MIN(ybot, pg->voffset+pg->height));
638 void rescale_bg_pixmaps(void)
643 gboolean is_well_scaled;
644 gdouble zoom_to_request;
646 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
647 pg = (struct Page *)pglist->data;
648 // in progressive mode we scale only visible pages
649 if (ui.progressive_bg && !is_visible(pg)) continue;
651 if (pg->bg->type == BG_PIXMAP && pg->bg->canvas_item!=NULL) { // do the rescaling ourselves
652 if (ui.antialias_bg) {
653 if (pg->bg->pixbuf_scale == ui.zoom) continue;
654 set_cursor_busy(TRUE);
655 pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf,
656 (int)floor(pg->width*ui.zoom+0.5), (int)floor(pg->height*ui.zoom+0.5),
657 GDK_INTERP_BILINEAR);
658 gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pix, NULL);
659 gdk_pixbuf_unref(pix);
660 pg->bg->pixbuf_scale = ui.zoom;
661 set_cursor_busy(FALSE);
664 g_object_get(G_OBJECT(pg->bg->canvas_item), "pixbuf", &pix, NULL);
665 if (pix!=pg->bg->pixbuf)
666 gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
667 pg->bg->pixbuf_scale = 0;
670 if (pg->bg->type == BG_PDF) {
671 // make pixmap scale to correct size if current one is wrong
672 is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
673 && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
674 if (pg->bg->canvas_item != NULL && !is_well_scaled) {
675 g_object_get(pg->bg->canvas_item, "width-in-pixels", &is_well_scaled, NULL);
677 gnome_canvas_item_set(pg->bg->canvas_item,
678 "width", pg->width, "height", pg->height,
679 "width-in-pixels", FALSE, "height-in-pixels", FALSE,
680 "width-set", TRUE, "height-set", TRUE,
683 // request an asynchronous update to a better pixmap if needed
684 zoom_to_request = MIN(ui.zoom, MAX_SAFE_RENDER_DPI/72.0);
685 if (pg->bg->pixbuf_scale == zoom_to_request) continue;
686 add_bgpdf_request(pg->bg->file_page_seq, zoom_to_request);
687 pg->bg->pixbuf_scale = zoom_to_request;
692 gboolean have_intersect(struct BBox *a, struct BBox *b)
694 return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
695 (MAX(a->left, b->left) <= MIN(a->right, b->right));
698 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
699 correctly the end of the group's item list. We try to work around this.
700 DON'T USE gnome_canvas_item_raise/lower directly !! */
702 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
706 i1 = g_list_index(g->item_list, item);
707 if (i1 == -1) return;
709 if (after == NULL) i2 = -1;
710 else i2 = g_list_index(g->item_list, after);
712 if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
713 if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
715 // BUGFIX for libgnomecanvas
716 g->item_list_end = g_list_last(g->item_list);
719 void rgb_to_gdkcolor(guint rgba, GdkColor *color)
722 color->red = ((rgba>>24)&0xff)*0x101;
723 color->green = ((rgba>>16)&0xff)*0x101;
724 color->blue = ((rgba>>8)&0xff)*0x101;
727 // some interface functions
729 void update_thickness_buttons(void)
731 if (ui.selection!=NULL || ui.toolno[ui.cur_mapping] >= NUM_STROKE_TOOLS) {
732 gtk_toggle_tool_button_set_active(
733 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
735 switch (ui.cur_brush->thickness_no) {
737 gtk_toggle_tool_button_set_active(
738 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
740 case THICKNESS_MEDIUM:
741 gtk_toggle_tool_button_set_active(
742 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
744 case THICKNESS_THICK:
745 gtk_toggle_tool_button_set_active(
746 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
749 gtk_toggle_tool_button_set_active(
750 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
754 void update_color_buttons(void)
756 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
757 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
758 gtk_toggle_tool_button_set_active(
759 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
761 switch (ui.cur_brush->color_no) {
763 gtk_toggle_tool_button_set_active(
764 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE);
767 gtk_toggle_tool_button_set_active(
768 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE);
771 gtk_toggle_tool_button_set_active(
772 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE);
775 gtk_toggle_tool_button_set_active(
776 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE);
779 gtk_toggle_tool_button_set_active(
780 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE);
782 case COLOR_LIGHTBLUE:
783 gtk_toggle_tool_button_set_active(
784 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE);
786 case COLOR_LIGHTGREEN:
787 gtk_toggle_tool_button_set_active(
788 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE);
791 gtk_toggle_tool_button_set_active(
792 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE);
795 gtk_toggle_tool_button_set_active(
796 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE);
799 gtk_toggle_tool_button_set_active(
800 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE);
803 gtk_toggle_tool_button_set_active(
804 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE);
807 gtk_toggle_tool_button_set_active(
808 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
812 void update_tool_buttons(void)
814 switch(ui.toolno[ui.cur_mapping]) {
816 gtk_toggle_tool_button_set_active(
817 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
820 gtk_toggle_tool_button_set_active(
821 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
823 case TOOL_HIGHLIGHTER:
824 gtk_toggle_tool_button_set_active(
825 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
828 gtk_toggle_tool_button_set_active(
829 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
831 case TOOL_SELECTREGION:
832 gtk_toggle_tool_button_set_active(
833 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
835 case TOOL_SELECTRECT:
836 gtk_toggle_tool_button_set_active(
837 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
840 gtk_toggle_tool_button_set_active(
841 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
844 gtk_toggle_tool_button_set_active(
845 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHand")), TRUE);
849 gtk_toggle_tool_button_set_active(
850 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
851 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
852 gtk_toggle_tool_button_set_active(
853 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
854 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
856 update_thickness_buttons();
857 update_color_buttons();
860 void update_tool_menu(void)
862 switch(ui.toolno[0]) {
864 gtk_check_menu_item_set_active(
865 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
868 gtk_check_menu_item_set_active(
869 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
871 case TOOL_HIGHLIGHTER:
872 gtk_check_menu_item_set_active(
873 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
876 gtk_check_menu_item_set_active(
877 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
879 case TOOL_SELECTREGION:
880 gtk_check_menu_item_set_active(
881 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
883 case TOOL_SELECTRECT:
884 gtk_check_menu_item_set_active(
885 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
888 gtk_check_menu_item_set_active(
889 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
892 gtk_check_menu_item_set_active(
893 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHand")), TRUE);
897 gtk_check_menu_item_set_active(
898 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
899 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
900 gtk_check_menu_item_set_active(
901 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
902 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
905 void update_ruler_indicator(void)
907 gtk_toggle_tool_button_set_active(
908 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")),
909 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->ruler);
910 gtk_toggle_tool_button_set_active(
911 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonReco")),
912 ui.toolno[ui.cur_mapping]<NUM_STROKE_TOOLS && ui.cur_brush->recognizer);
913 gtk_check_menu_item_set_active(
914 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")),
915 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].ruler);
916 gtk_check_menu_item_set_active(
917 GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsReco")),
918 ui.toolno[0]<NUM_STROKE_TOOLS && ui.brushes[0][ui.toolno[0]].recognizer);
921 void update_color_menu(void)
923 if (ui.selection!=NULL || (ui.toolno[ui.cur_mapping] != TOOL_PEN
924 && ui.toolno[ui.cur_mapping] != TOOL_HIGHLIGHTER && ui.toolno[ui.cur_mapping] != TOOL_TEXT)) {
925 gtk_check_menu_item_set_active(
926 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
928 switch (ui.cur_brush->color_no) {
930 gtk_check_menu_item_set_active(
931 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
934 gtk_check_menu_item_set_active(
935 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
938 gtk_check_menu_item_set_active(
939 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
942 gtk_check_menu_item_set_active(
943 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
946 gtk_check_menu_item_set_active(
947 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
949 case COLOR_LIGHTBLUE:
950 gtk_check_menu_item_set_active(
951 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
953 case COLOR_LIGHTGREEN:
954 gtk_check_menu_item_set_active(
955 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
958 gtk_check_menu_item_set_active(
959 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
962 gtk_check_menu_item_set_active(
963 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
966 gtk_check_menu_item_set_active(
967 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
970 gtk_check_menu_item_set_active(
971 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
974 gtk_check_menu_item_set_active(
975 GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOther")), TRUE);
979 void update_pen_props_menu(void)
981 switch(ui.brushes[0][TOOL_PEN].thickness_no) {
982 case THICKNESS_VERYFINE:
983 gtk_check_menu_item_set_active(
984 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
987 gtk_check_menu_item_set_active(
988 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
990 case THICKNESS_MEDIUM:
991 gtk_check_menu_item_set_active(
992 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
994 case THICKNESS_THICK:
995 gtk_check_menu_item_set_active(
996 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
998 case THICKNESS_VERYTHICK:
999 gtk_check_menu_item_set_active(
1000 GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
1005 void update_eraser_props_menu(void)
1007 switch (ui.brushes[0][TOOL_ERASER].thickness_no) {
1008 case THICKNESS_FINE:
1009 gtk_check_menu_item_set_active(
1010 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
1012 case THICKNESS_MEDIUM:
1013 gtk_check_menu_item_set_active(
1014 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
1016 case THICKNESS_THICK:
1017 gtk_check_menu_item_set_active(
1018 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
1022 gtk_check_menu_item_set_active(
1023 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
1024 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
1025 gtk_check_menu_item_set_active(
1026 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
1027 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
1028 gtk_check_menu_item_set_active(
1029 GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
1030 ui.brushes[0][TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
1033 void update_highlighter_props_menu(void)
1035 switch (ui.brushes[0][TOOL_HIGHLIGHTER].thickness_no) {
1036 case THICKNESS_FINE:
1037 gtk_check_menu_item_set_active(
1038 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
1040 case THICKNESS_MEDIUM:
1041 gtk_check_menu_item_set_active(
1042 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
1044 case THICKNESS_THICK:
1045 gtk_check_menu_item_set_active(
1046 GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
1051 void update_mappings_menu_linkings(void)
1053 switch (ui.linked_brush[1]) {
1055 gtk_check_menu_item_set_active(
1056 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2LinkBrush")), TRUE);
1059 gtk_check_menu_item_set_active(
1060 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2CopyBrush")), TRUE);
1063 gtk_check_menu_item_set_active(
1064 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2NABrush")), TRUE);
1067 switch (ui.linked_brush[2]) {
1069 gtk_check_menu_item_set_active(
1070 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3LinkBrush")), TRUE);
1073 gtk_check_menu_item_set_active(
1074 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3CopyBrush")), TRUE);
1077 gtk_check_menu_item_set_active(
1078 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3NABrush")), TRUE);
1083 void update_mappings_menu(void)
1085 gtk_widget_set_sensitive(GET_COMPONENT("optionsButtonMappings"), ui.use_xinput);
1086 gtk_widget_set_sensitive(GET_COMPONENT("optionsDiscardCoreEvents"), ui.use_xinput);
1087 gtk_widget_set_sensitive(GET_COMPONENT("optionsPressureSensitive"), ui.use_xinput);
1088 gtk_check_menu_item_set_active(
1089 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsButtonMappings")), ui.use_erasertip);
1090 gtk_check_menu_item_set_active(
1091 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsDiscardCoreEvents")), ui.discard_corepointer);
1092 gtk_check_menu_item_set_active(
1093 GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsPressureSensitive")), ui.pressure_sensitivity);
1095 switch(ui.toolno[1]) {
1097 gtk_check_menu_item_set_active(
1098 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Pen")), TRUE);
1101 gtk_check_menu_item_set_active(
1102 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Eraser")), TRUE);
1104 case TOOL_HIGHLIGHTER:
1105 gtk_check_menu_item_set_active(
1106 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Highlighter")), TRUE);
1109 gtk_check_menu_item_set_active(
1110 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2Text")), TRUE);
1112 case TOOL_SELECTREGION:
1113 gtk_check_menu_item_set_active(
1114 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRegion")), TRUE);
1116 case TOOL_SELECTRECT:
1117 gtk_check_menu_item_set_active(
1118 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2SelectRectangle")), TRUE);
1120 case TOOL_VERTSPACE:
1121 gtk_check_menu_item_set_active(
1122 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button2VerticalSpace")), TRUE);
1125 switch(ui.toolno[2]) {
1127 gtk_check_menu_item_set_active(
1128 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Pen")), TRUE);
1131 gtk_check_menu_item_set_active(
1132 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Eraser")), TRUE);
1134 case TOOL_HIGHLIGHTER:
1135 gtk_check_menu_item_set_active(
1136 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Highlighter")), TRUE);
1139 gtk_check_menu_item_set_active(
1140 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3Text")), TRUE);
1142 case TOOL_SELECTREGION:
1143 gtk_check_menu_item_set_active(
1144 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRegion")), TRUE);
1146 case TOOL_SELECTRECT:
1147 gtk_check_menu_item_set_active(
1148 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3SelectRectangle")), TRUE);
1150 case TOOL_VERTSPACE:
1151 gtk_check_menu_item_set_active(
1152 GTK_CHECK_MENU_ITEM(GET_COMPONENT("button3VerticalSpace")), TRUE);
1155 update_mappings_menu_linkings();
1158 void do_switch_page(int pg, gboolean rescroll, gboolean refresh_all)
1161 struct Layer *layer;
1166 /* re-show all the layers of the old page */
1167 if (ui.cur_page != NULL)
1168 for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
1169 layer = (struct Layer *)list->data;
1170 if (layer->group!=NULL)
1171 gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
1174 ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
1175 ui.layerno = ui.cur_page->nlayers-1;
1176 ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
1177 update_page_stuff();
1178 if (ui.progressive_bg) rescale_bg_pixmaps();
1180 if (rescroll) { // scroll and force a refresh
1181 /* -- this seems to cause some display bugs ??
1182 gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)),
1183 ui.cur_page->voffset*ui.zoom); */
1184 gnome_canvas_get_scroll_offsets(canvas, &cx, &cy);
1185 cy = ui.cur_page->voffset*ui.zoom;
1186 gnome_canvas_scroll_to(canvas, cx, cy);
1189 gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
1190 else if (!ui.view_continuous)
1191 gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.cur_page->group), 0., 0.);
1195 void update_page_stuff(void)
1198 GtkComboBox *layerbox;
1201 GtkSpinButton *spin;
1203 double vertpos, maxwidth;
1205 // move the page groups to their rightful locations or hide them
1206 if (ui.view_continuous) {
1209 for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
1210 pg = (struct Page *)pglist->data;
1211 if (pg->group!=NULL) {
1212 pg->hoffset = 0.; pg->voffset = vertpos;
1213 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1214 "x", pg->hoffset, "y", pg->voffset, NULL);
1215 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1217 vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
1218 if (pg->width > maxwidth) maxwidth = pg->width;
1220 vertpos -= VIEW_CONTINUOUS_SKIP;
1221 gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
1223 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1224 pg = (struct Page *)pglist->data;
1225 if (pg == ui.cur_page && pg->group!=NULL) {
1226 pg->hoffset = 0.; pg->voffset = 0.;
1227 gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group),
1228 "x", pg->hoffset, "y", pg->voffset, NULL);
1229 gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
1231 if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
1234 gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
1237 // update the page / layer info at bottom of screen
1239 spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
1240 ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
1241 gtk_spin_button_set_range(spin, 1, journal.npages+1);
1242 /* npages+1 will be used to create a new page at end */
1243 gtk_spin_button_set_value(spin, ui.pageno+1);
1244 g_snprintf(tmp, 10, " of %d", journal.npages);
1245 gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
1247 layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
1248 if (ui.layerbox_length == 0) {
1249 gtk_combo_box_prepend_text(layerbox, "Background");
1250 ui.layerbox_length++;
1252 while (ui.layerbox_length > ui.cur_page->nlayers+1) {
1253 gtk_combo_box_remove_text(layerbox, 0);
1254 ui.layerbox_length--;
1256 while (ui.layerbox_length < ui.cur_page->nlayers+1) {
1257 g_snprintf(tmp, 10, "Layer %d", ui.layerbox_length++);
1258 gtk_combo_box_prepend_text(layerbox, tmp);
1260 gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
1261 ui.in_update_page_stuff = FALSE;
1263 // update the paper-style menu radio buttons
1265 if (ui.view_continuous)
1266 gtk_check_menu_item_set_active(
1267 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
1269 gtk_check_menu_item_set_active(
1270 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
1272 if (ui.cur_page->bg->type == BG_SOLID && !ui.bg_apply_all_pages) {
1273 switch (ui.cur_page->bg->color_no) {
1275 gtk_check_menu_item_set_active(
1276 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
1279 gtk_check_menu_item_set_active(
1280 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
1283 gtk_check_menu_item_set_active(
1284 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1287 gtk_check_menu_item_set_active(
1288 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1291 gtk_check_menu_item_set_active(
1292 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1295 gtk_check_menu_item_set_active(
1296 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1299 gtk_check_menu_item_set_active(
1300 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE);
1303 switch (ui.cur_page->bg->ruling) {
1305 gtk_check_menu_item_set_active(
1306 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1309 gtk_check_menu_item_set_active(
1310 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1313 gtk_check_menu_item_set_active(
1314 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1317 gtk_check_menu_item_set_active(
1318 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1322 gtk_check_menu_item_set_active(
1323 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1324 gtk_check_menu_item_set_active(
1325 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1328 // enable/disable the page/layer menu items and toolbar buttons
1330 gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"),
1331 ui.cur_page->bg->type == BG_SOLID || ui.bg_apply_all_pages);
1332 gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1333 ui.cur_page->bg->type == BG_SOLID);
1335 gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1336 gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1337 gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1338 gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1339 gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1340 gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1341 gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1342 gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1344 gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1345 gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1347 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1348 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1351 void update_toolbar_and_menu(void)
1353 update_tool_buttons(); // takes care of other toolbar buttons as well
1355 update_color_menu();
1356 update_pen_props_menu();
1357 update_eraser_props_menu();
1358 update_highlighter_props_menu();
1359 update_mappings_menu();
1361 gtk_toggle_tool_button_set_active(
1362 GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1363 gtk_check_menu_item_set_active(
1364 GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1367 void update_file_name(char *filename)
1370 if (ui.filename != NULL) g_free(ui.filename);
1371 ui.filename = filename;
1372 if (filename == NULL) {
1373 gtk_window_set_title(GTK_WINDOW (winMain), "Xournal");
1376 p = g_utf8_strrchr(filename, -1, '/');
1377 if (p == NULL) p = filename;
1378 else p = g_utf8_next_char(p);
1379 g_snprintf(tmp, 100, "Xournal - %s", p);
1380 gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1381 new_mru_entry(filename);
1384 void update_undo_redo_enabled(void)
1386 gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1387 gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1388 gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1389 gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1392 void update_copy_paste_enabled(void)
1394 gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1395 gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1396 gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_item_type!=ITEM_TEXT);
1397 gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1398 gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1399 gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1400 gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_item_type!=ITEM_TEXT);
1403 void update_mapping_linkings(int toolno)
1407 for (i = 1; i<=NUM_BUTTONS; i++) {
1408 if (ui.linked_brush[i] == BRUSH_LINKED) {
1409 if (toolno >= 0 && toolno < NUM_STROKE_TOOLS)
1410 g_memmove(&(ui.brushes[i][toolno]), &(ui.brushes[0][toolno]), sizeof(struct Brush));
1412 if (ui.linked_brush[i] == BRUSH_COPIED && toolno == ui.toolno[i]) {
1413 ui.linked_brush[i] = BRUSH_STATIC;
1414 if (i==1 || i==2) update_mappings_menu_linkings();
1419 void set_cur_color(int color)
1421 ui.cur_brush->color_no = color;
1422 if (ui.toolno[0] == TOOL_HIGHLIGHTER)
1423 ui.cur_brush->color_rgba = predef_colors_rgba[color] & ui.hiliter_alpha_mask;
1425 ui.cur_brush->color_rgba = predef_colors_rgba[color];
1426 update_mapping_linkings(ui.toolno[0]);
1429 void recolor_temp_text(int color_no, guint color_rgba)
1433 if (ui.cur_item_type!=ITEM_TEXT) return;
1434 if (ui.cur_item->text!=NULL && ui.cur_item->brush.color_rgba != color_rgba) {
1436 undo->type = ITEM_TEXT_ATTRIB;
1437 undo->item = ui.cur_item;
1438 undo->str = g_strdup(ui.cur_item->font_name);
1439 undo->val_x = ui.cur_item->font_size;
1440 undo->brush = (struct Brush *)g_memdup(&(ui.cur_item->brush), sizeof(struct Brush));
1442 ui.cur_item->brush.color_no = color_no;
1443 ui.cur_item->brush.color_rgba = color_rgba;
1444 rgb_to_gdkcolor(color_rgba, &gdkcolor);
1445 gtk_widget_modify_text(ui.cur_item->widget, GTK_STATE_NORMAL, &gdkcolor);
1446 gtk_widget_grab_focus(ui.cur_item->widget);
1449 void process_color_activate(GtkMenuItem *menuitem, int color)
1451 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1452 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1455 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1459 if (ui.cur_mapping != 0) return; // not user-generated
1462 if (ui.cur_item_type == ITEM_TEXT)
1463 recolor_temp_text(color, predef_colors_rgba[color]);
1465 if (ui.selection != NULL) {
1466 recolor_selection(color);
1467 update_color_buttons();
1468 update_color_menu();
1471 if (ui.toolno[0] != TOOL_PEN && ui.toolno[0] != TOOL_HIGHLIGHTER
1472 && ui.toolno[0] != TOOL_TEXT) {
1473 if (ui.selection != NULL) return;
1475 ui.toolno[0] = TOOL_PEN;
1476 ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
1477 update_tool_buttons();
1481 set_cur_color(color);
1482 update_color_buttons();
1483 update_color_menu();
1487 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1489 if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1490 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1493 if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1497 if (ui.cur_mapping != 0) return; // not user-generated
1499 if (ui.selection != NULL && GTK_OBJECT_TYPE(menuitem) != GTK_TYPE_RADIO_MENU_ITEM) {
1501 rethicken_selection(val);
1502 update_thickness_buttons();
1505 if (tool >= NUM_STROKE_TOOLS) {
1506 update_thickness_buttons(); // undo illegal button selection
1510 if (ui.brushes[0][tool].thickness_no == val) return;
1513 ui.brushes[0][tool].thickness_no = val;
1514 ui.brushes[0][tool].thickness = predef_thickness[tool][val];
1515 update_mapping_linkings(tool);
1517 update_thickness_buttons();
1518 if (tool == TOOL_PEN) update_pen_props_menu();
1519 if (tool == TOOL_ERASER) update_eraser_props_menu();
1520 if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1524 void process_papercolor_activate(GtkMenuItem *menuitem, int color)
1530 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1533 if ((ui.cur_page->bg->type != BG_SOLID) || ui.bg_apply_all_pages)
1534 gtk_check_menu_item_set_active(
1535 GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1539 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1540 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1541 if (pg->bg->type == BG_SOLID && pg->bg->color_no != color) {
1543 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1544 undo->multiop |= MULTIOP_CONT_REDO;
1546 undo->type = ITEM_NEW_BG_ONE;
1548 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1549 undo->bg->canvas_item = NULL;
1551 pg->bg->color_no = color;
1552 pg->bg->color_rgba = predef_bgcolors_rgba[color];
1553 update_canvas_bg(pg);
1555 if (!ui.bg_apply_all_pages) break;
1557 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1560 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1564 gboolean hasdone, must_upd;
1566 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1569 if (ui.bg_apply_all_pages)
1570 gtk_check_menu_item_set_active(
1571 GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1576 for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
1577 if (ui.bg_apply_all_pages) pg = (struct Page *)pglist->data;
1578 if (pg->bg->type != BG_SOLID || pg->bg->ruling != style) {
1580 undo->type = ITEM_NEW_BG_ONE;
1581 if (hasdone) undo->multiop |= MULTIOP_CONT_UNDO;
1582 undo->multiop |= MULTIOP_CONT_REDO;
1585 undo->bg = (struct Background *)g_memdup(pg->bg, sizeof(struct Background));
1586 undo->bg->canvas_item = NULL;
1588 if (pg->bg->type != BG_SOLID) {
1589 pg->bg->type = BG_SOLID;
1590 pg->bg->color_no = COLOR_WHITE;
1591 pg->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1592 pg->bg->filename = NULL;
1593 pg->bg->pixbuf = NULL;
1596 pg->bg->ruling = style;
1597 update_canvas_bg(pg);
1599 if (!ui.bg_apply_all_pages) break;
1601 if (hasdone) undo->multiop -= MULTIOP_CONT_REDO;
1602 if (must_upd) update_page_stuff();
1605 gboolean ok_to_close(void)
1608 GtkResponseType response;
1610 if (ui.saved) return TRUE;
1611 dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1612 GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, "Save changes to '%s'?",
1613 (ui.filename!=NULL) ? ui.filename:"Untitled");
1614 gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1615 response = gtk_dialog_run(GTK_DIALOG (dialog));
1616 gtk_widget_destroy(dialog);
1617 if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT)
1618 return FALSE; // aborted
1619 if (response == GTK_RESPONSE_YES) {
1620 on_fileSave_activate(NULL, NULL);
1621 if (!ui.saved) return FALSE; // if save failed, then we abort
1626 // send the focus back to the appropriate widget
1627 void reset_focus(void)
1629 if (ui.cur_item_type == ITEM_TEXT)
1630 gtk_widget_grab_focus(ui.cur_item->widget);
1632 gtk_widget_grab_focus(GTK_WIDGET(canvas));
1636 // selection / clipboard stuff
1638 void reset_selection(void)
1640 if (ui.selection == NULL) return;
1641 if (ui.selection->canvas_item != NULL)
1642 gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1643 g_list_free(ui.selection->items);
1644 g_free(ui.selection);
1645 ui.selection = NULL;
1646 update_copy_paste_enabled();
1647 update_color_menu();
1648 update_thickness_buttons();
1649 update_color_buttons();
1650 update_font_button();
1654 void move_journal_items_by(GList *itemlist, double dx, double dy,
1655 struct Layer *l1, struct Layer *l2, GList *depths)
1658 GnomeCanvasItem *refitem;
1663 while (itemlist!=NULL) {
1664 item = (struct Item *)itemlist->data;
1665 if (item->type == ITEM_STROKE)
1666 for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1667 { pt[0] += dx; pt[1] += dy; }
1668 if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type == ITEM_TEMP_TEXT) {
1669 item->bbox.left += dx;
1670 item->bbox.right += dx;
1671 item->bbox.top += dy;
1672 item->bbox.bottom += dy;
1675 // find out where to insert
1676 if (depths != NULL) {
1677 if (depths->data == NULL) link = l2->items;
1679 link = g_list_find(l2->items, depths->data);
1680 if (link != NULL) link = link->next;
1683 l2->items = g_list_insert_before(l2->items, link, item);
1685 l1->items = g_list_remove(l1->items, item);
1688 if (depths != NULL) { // also raise/lower the canvas items
1689 if (item->canvas_item!=NULL) {
1690 if (depths->data == NULL) link = NULL;
1691 else link = g_list_find(l2->items, depths->data);
1692 if (link != NULL) refitem = ((struct Item *)(link->data))->canvas_item;
1693 else refitem = NULL;
1694 lower_canvas_item_to(l2->group, item->canvas_item, refitem);
1696 depths = depths->next;
1698 itemlist = itemlist->next;
1702 void resize_journal_items_by(GList *itemlist, double scaling_x, double scaling_y,
1703 double offset_x, double offset_y)
1707 double mean_scaling, temp;
1709 GnomeCanvasGroup *group;
1712 /* geometric mean of x and y scalings = rescaling for stroke widths
1713 and for text font sizes */
1714 mean_scaling = sqrt(fabs(scaling_x * scaling_y));
1716 for (list = itemlist; list != NULL; list = list->next) {
1717 item = (struct Item *)list->data;
1718 if (item->type == ITEM_STROKE) {
1719 item->brush.thickness = item->brush.thickness * mean_scaling;
1720 for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {
1721 pt[0] = pt[0]*scaling_x + offset_x;
1722 pt[1] = pt[1]*scaling_y + offset_y;
1724 if (item->brush.variable_width)
1725 for (i=0, wid=item->widths; i<item->path->num_points-1; i++, wid++)
1726 *wid = *wid * mean_scaling;
1728 item->bbox.left = item->bbox.left*scaling_x + offset_x;
1729 item->bbox.right = item->bbox.right*scaling_x + offset_x;
1730 item->bbox.top = item->bbox.top*scaling_y + offset_y;
1731 item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
1732 if (item->bbox.left > item->bbox.right) {
1733 temp = item->bbox.left;
1734 item->bbox.left = item->bbox.right;
1735 item->bbox.right = temp;
1737 if (item->bbox.top > item->bbox.bottom) {
1738 temp = item->bbox.top;
1739 item->bbox.top = item->bbox.bottom;
1740 item->bbox.bottom = temp;
1743 if (item->type == ITEM_TEXT) {
1744 /* must scale about NW corner -- all other points of the text box
1745 are font- and zoom-dependent, so scaling about center of text box
1746 couldn't be undone properly. FIXME? */
1747 item->font_size *= mean_scaling;
1748 item->bbox.left = item->bbox.left*scaling_x + offset_x;
1749 item->bbox.top = item->bbox.top*scaling_y + offset_y;
1752 if (item->canvas_item!=NULL) {
1753 group = (GnomeCanvasGroup *) item->canvas_item->parent;
1754 gtk_object_destroy(GTK_OBJECT(item->canvas_item));
1755 make_canvas_item_one(group, item);
1760 // Switch between button mappings
1762 /* NOTE ABOUT BUTTON MAPPINGS: ui.cur_mapping is 0 except while a canvas
1763 click event is being processed ... */
1765 void switch_mapping(int m)
1767 if (ui.cur_mapping == m) return;
1770 if (ui.toolno[m] < NUM_STROKE_TOOLS)
1771 ui.cur_brush = &(ui.brushes[m][ui.toolno[m]]);
1772 if (ui.toolno[m] == TOOL_TEXT)
1773 ui.cur_brush = &(ui.brushes[m][TOOL_PEN]);
1774 update_tool_buttons();
1775 update_color_menu();
1779 void process_mapping_activate(GtkMenuItem *menuitem, int m, int tool)
1781 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return;
1782 if (ui.cur_mapping!=0) return;
1783 if (ui.toolno[m] == tool) return;
1787 ui.toolno[m] = tool;
1788 if (ui.linked_brush[m] == BRUSH_COPIED) {
1789 ui.linked_brush[m] = BRUSH_STATIC;
1790 update_mappings_menu_linkings();
1794 // update the ordering of components in the main vbox
1796 const char *vbox_component_names[VBOX_MAIN_NITEMS]=
1797 {"scrolledwindowMain", "menubar", "toolbarMain", "toolbarPen", "hbox1"};
1799 void update_vbox_order(int *order)
1803 GtkBox *vboxMain = GTK_BOX(GET_COMPONENT("vboxMain"));
1804 gboolean present[VBOX_MAIN_NITEMS];
1806 for (i=0; i<VBOX_MAIN_NITEMS; i++) present[i] = FALSE;
1808 for (i=0; i<VBOX_MAIN_NITEMS; i++) {
1809 if (order[i]<0 || order[i]>=VBOX_MAIN_NITEMS) continue;
1810 present[order[i]] = TRUE;
1811 child = GET_COMPONENT(vbox_component_names[order[i]]);
1812 gtk_box_reorder_child(vboxMain, child, j++);
1813 gtk_widget_show(child);
1815 for (i=1; i<VBOX_MAIN_NITEMS; i++) // hide others, but not the drawing area!
1816 if (!present[i]) gtk_widget_hide(GET_COMPONENT(vbox_component_names[i]));
1819 gchar *make_cur_font_name(void)
1824 if (ui.cur_item_type == ITEM_TEXT)
1825 str = g_strdup_printf("%s %.1f", ui.cur_item->font_name, ui.cur_item->font_size);
1826 else if (ui.selection!=NULL && ui.selection->items!=NULL &&
1827 ui.selection->items->next==NULL &&
1828 (it=(struct Item*)ui.selection->items->data)->type == ITEM_TEXT)
1829 str = g_strdup_printf("%s %.1f", it->font_name, it->font_size);
1831 str = g_strdup_printf("%s %.1f", ui.font_name, ui.font_size);
1835 void update_font_button(void)
1839 str = make_cur_font_name();
1840 gtk_font_button_set_font_name(GTK_FONT_BUTTON(GET_COMPONENT("fontButton")), str);
1844 gboolean can_accel(GtkWidget *widget, guint id, gpointer data)
1846 return GTK_WIDGET_SENSITIVE(widget);
1849 void allow_all_accels(void)
1851 g_signal_connect((gpointer) GET_COMPONENT("fileNew"),
1852 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1853 g_signal_connect((gpointer) GET_COMPONENT("fileOpen"),
1854 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1855 g_signal_connect((gpointer) GET_COMPONENT("fileSave"),
1856 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1857 g_signal_connect((gpointer) GET_COMPONENT("filePrint"),
1858 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1859 g_signal_connect((gpointer) GET_COMPONENT("filePrintPDF"),
1860 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1861 g_signal_connect((gpointer) GET_COMPONENT("fileQuit"),
1862 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1863 g_signal_connect((gpointer) GET_COMPONENT("editUndo"),
1864 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1865 g_signal_connect((gpointer) GET_COMPONENT("editRedo"),
1866 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1867 g_signal_connect((gpointer) GET_COMPONENT("editCut"),
1868 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1869 g_signal_connect((gpointer) GET_COMPONENT("editCopy"),
1870 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1871 g_signal_connect((gpointer) GET_COMPONENT("editPaste"),
1872 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1873 g_signal_connect((gpointer) GET_COMPONENT("editDelete"),
1874 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1875 g_signal_connect((gpointer) GET_COMPONENT("viewFullscreen"),
1876 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1877 g_signal_connect((gpointer) GET_COMPONENT("viewZoomIn"),
1878 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1879 g_signal_connect((gpointer) GET_COMPONENT("viewZoomOut"),
1880 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1881 g_signal_connect((gpointer) GET_COMPONENT("viewNormalSize"),
1882 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1883 g_signal_connect((gpointer) GET_COMPONENT("viewPageWidth"),
1884 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1885 g_signal_connect((gpointer) GET_COMPONENT("viewFirstPage"),
1886 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1887 g_signal_connect((gpointer) GET_COMPONENT("viewPreviousPage"),
1888 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1889 g_signal_connect((gpointer) GET_COMPONENT("viewNextPage"),
1890 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1891 g_signal_connect((gpointer) GET_COMPONENT("viewLastPage"),
1892 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1893 g_signal_connect((gpointer) GET_COMPONENT("toolsPen"),
1894 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1895 g_signal_connect((gpointer) GET_COMPONENT("toolsEraser"),
1896 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1897 g_signal_connect((gpointer) GET_COMPONENT("toolsHighlighter"),
1898 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1899 g_signal_connect((gpointer) GET_COMPONENT("toolsText"),
1900 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1901 /* g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
1902 "can-activate-accel", G_CALLBACK(can_accel), NULL); */
1903 g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRectangle"),
1904 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1905 g_signal_connect((gpointer) GET_COMPONENT("toolsVerticalSpace"),
1906 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1907 g_signal_connect((gpointer) GET_COMPONENT("toolsHand"),
1908 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1909 g_signal_connect((gpointer) GET_COMPONENT("toolsTextFont"),
1910 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1911 g_signal_connect((gpointer) GET_COMPONENT("toolsRuler"),
1912 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1913 g_signal_connect((gpointer) GET_COMPONENT("toolsReco"),
1914 "can-activate-accel", G_CALLBACK(can_accel), NULL);
1917 void add_scroll_bindings(void)
1919 GtkBindingSet *binding_set;
1921 binding_set = gtk_binding_set_by_class(
1922 G_OBJECT_GET_CLASS(GET_COMPONENT("scrolledwindowMain")));
1923 gtk_binding_entry_add_signal(binding_set, GDK_Up, 0,
1924 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1925 G_TYPE_BOOLEAN, FALSE);
1926 gtk_binding_entry_add_signal(binding_set, GDK_KP_Up, 0,
1927 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1928 G_TYPE_BOOLEAN, FALSE);
1929 gtk_binding_entry_add_signal(binding_set, GDK_Down, 0,
1930 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1931 G_TYPE_BOOLEAN, FALSE);
1932 gtk_binding_entry_add_signal(binding_set, GDK_KP_Down, 0,
1933 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1934 G_TYPE_BOOLEAN, FALSE);
1935 gtk_binding_entry_add_signal(binding_set, GDK_Left, 0,
1936 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1937 G_TYPE_BOOLEAN, TRUE);
1938 gtk_binding_entry_add_signal(binding_set, GDK_KP_Left, 0,
1939 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
1940 G_TYPE_BOOLEAN, TRUE);
1941 gtk_binding_entry_add_signal(binding_set, GDK_Right, 0,
1942 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1943 G_TYPE_BOOLEAN, TRUE);
1944 gtk_binding_entry_add_signal(binding_set, GDK_KP_Right, 0,
1945 "scroll_child", 2, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
1946 G_TYPE_BOOLEAN, TRUE);
1949 gboolean is_event_within_textview(GdkEventButton *event)
1953 if (ui.cur_item_type!=ITEM_TEXT) return FALSE;
1954 get_pointer_coords((GdkEvent *)event, pt);
1955 if (pt[0]<ui.cur_item->bbox.left || pt[0]>ui.cur_item->bbox.right) return FALSE;
1956 if (pt[1]<ui.cur_item->bbox.top || pt[1]>ui.cur_item->bbox.bottom) return FALSE;
1960 void hide_unimplemented(void)
1962 gtk_widget_hide(GET_COMPONENT("filePrintOptions"));
1963 gtk_widget_hide(GET_COMPONENT("journalFlatten"));
1964 gtk_widget_hide(GET_COMPONENT("papercolorOther"));
1965 gtk_widget_hide(GET_COMPONENT("toolsSelectRegion"));
1966 gtk_widget_hide(GET_COMPONENT("buttonSelectRegion"));
1967 gtk_widget_hide(GET_COMPONENT("button2SelectRegion"));
1968 gtk_widget_hide(GET_COMPONENT("button3SelectRegion"));
1969 gtk_widget_hide(GET_COMPONENT("colorOther"));
1970 gtk_widget_hide(GET_COMPONENT("helpIndex"));
1972 /* config file only works with glib 2.6 */
1973 if (glib_minor_version<6) {
1974 gtk_widget_hide(GET_COMPONENT("optionsAutoSavePrefs"));
1975 gtk_widget_hide(GET_COMPONENT("optionsSavePreferences"));