]> git.donarmstrong.com Git - xournal.git/blob - src/xo-misc.c
Public release 0.2.1.
[xournal.git] / src / xo-misc.c
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4
5 #include <math.h>
6 #include <gtk/gtk.h>
7 #include <libgnomecanvas/libgnomecanvas.h>
8
9 #include "xournal.h"
10 #include "xo-interface.h"
11 #include "xo-support.h"
12 #include "xo-callbacks.h"
13 #include "xo-misc.h"
14 #include "xo-file.h"
15 #include "xo-paint.h"
16
17 // some global constants
18
19 guint predef_colors_rgba[COLOR_MAX] =
20   { 0x000000ff, 0x3333ccff, 0xff0000ff, 0x008000ff,
21     0x808080ff, 0x00c0ffff, 0x00ff00ff, 0xff00ffff,
22     0xff8000ff, 0xffff00ff, 0xffffffff };
23
24 guint predef_bgcolors_rgba[COLOR_MAX] = // meaningless ones set to white
25   { 0xffffffff, 0xa0e8ffff, 0xffc0d4ff, 0x80ffc0ff,
26     0xffffffff, 0xa0e8ffff, 0x80ffc0ff, 0xffc0d4ff,
27     0xffc080ff, 0xffff80ff, 0xffffffff };
28
29 double predef_thickness[NUM_STROKE_TOOLS][THICKNESS_MAX] =
30   { { 0.42, 0.85, 1.41,  2.26, 5.67 }, // pen thicknesses = 0.15, 0.3, 0.5, 0.8, 2 mm
31     { 2.83, 2.83, 7.08, 14.17, 14.17 }, // eraser thicknesses = 1, 2.5, 5 mm
32     { 2.83, 2.83, 7.08, 14.17, 14.17 }, // highlighter thicknesses = 1, 2.5, 5 mm
33   };
34
35 // some manipulation functions
36
37 struct Page *new_page(struct Page *template)
38 {
39   struct Page *pg = (struct Page *) g_memdup(template, sizeof(struct Page));
40   struct Layer *l = g_new(struct Layer, 1);
41   
42   l->items = NULL;
43   l->nitems = 0;
44   pg->layers = g_list_append(NULL, l);
45   pg->nlayers = 1;
46   pg->bg = (struct Background *)g_memdup(template->bg, sizeof(struct Background));
47   pg->bg->canvas_item = NULL;
48   if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
49     gdk_pixbuf_ref(pg->bg->pixbuf);
50     refstring_ref(pg->bg->filename);
51   }
52   pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
53       gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
54   make_page_clipbox(pg);
55   update_canvas_bg(pg);
56   l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
57       pg->group, gnome_canvas_group_get_type(), NULL);
58   
59   return pg;
60 }
61
62 /* Create a page from a background. 
63    Note: bg should be an UNREFERENCED background.
64    If needed, first duplicate it and increase the refcount of the pixbuf.
65 */
66 struct Page *new_page_with_bg(struct Background *bg, double width, double height)
67 {
68   struct Page *pg = g_new(struct Page, 1);
69   struct Layer *l = g_new(struct Layer, 1);
70   
71   l->items = NULL;
72   l->nitems = 0;
73   pg->layers = g_list_append(NULL, l);
74   pg->nlayers = 1;
75   pg->bg = bg;
76   pg->bg->canvas_item = NULL;
77   pg->height = height;
78   pg->width = width;
79   pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
80       gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
81   make_page_clipbox(pg);
82   update_canvas_bg(pg);
83   l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
84       pg->group, gnome_canvas_group_get_type(), NULL);
85   
86   return pg;
87 }
88
89 void realloc_cur_path(int n)
90 {
91   if (n <= ui.cur_path_storage_alloc) return;
92   ui.cur_path_storage_alloc = n+10;
93   ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+10)*sizeof(double));
94 }
95
96 // undo utility functions
97
98 void prepare_new_undo(void)
99 {
100   struct UndoItem *u;
101   // add a new UndoItem on the stack  
102   u = (struct UndoItem *)g_malloc(sizeof(struct UndoItem));
103   u->next = undo;
104   u->multiop = 0;
105   undo = u;
106   ui.saved = FALSE;
107   clear_redo_stack();
108 }
109
110 void clear_redo_stack(void)
111 {
112   struct UndoItem *u;  
113   GList *list, *repl;
114   struct UndoErasureData *erasure;
115   struct Item *it;
116
117   /* Warning: the redo items might reference items from past redo entries,
118      which have been destroyed before them. Be careful! As a rule, it's
119      safe to destroy data which has been created at the current history step,
120      it's unsafe to refer to any data from previous history steps */
121   
122   while (redo!=NULL) {
123     if (redo->type == ITEM_STROKE) {
124       gnome_canvas_points_free(redo->item->path);
125       g_free(redo->item);
126       /* the strokes are unmapped, so there are no associated canvas items */
127     }
128     else if (redo->type == ITEM_ERASURE) {
129       for (list = redo->erasurelist; list!=NULL; list=list->next) {
130         erasure = (struct UndoErasureData *)list->data;
131         for (repl = erasure->replacement_items; repl!=NULL; repl=repl->next) {
132           it = (struct Item *)repl->data;
133           gnome_canvas_points_free(it->path);
134           g_free(it);
135         }
136         g_list_free(erasure->replacement_items);
137         g_free(erasure);
138       }
139       g_list_free(redo->erasurelist);
140     }
141     else if (redo->type == ITEM_NEW_BG_ONE || redo->type == ITEM_NEW_BG_RESIZE
142           || redo->type == ITEM_NEW_DEFAULT_BG) {
143       if (redo->bg->type == BG_PIXMAP || redo->bg->type == BG_PDF) {
144         if (redo->bg->pixbuf!=NULL) gdk_pixbuf_unref(redo->bg->pixbuf);
145         refstring_unref(redo->bg->filename);
146       }
147       g_free(redo->bg);
148     }
149     else if (redo->type == ITEM_NEW_PAGE) {
150       redo->page->group = NULL;
151       delete_page(redo->page);
152     }
153     else if (redo->type == ITEM_MOVESEL) {
154       g_list_free(redo->itemlist);
155     }
156     else if (redo->type == ITEM_PASTE) {
157       for (list = redo->itemlist; list!=NULL; list=list->next) {
158         it = (struct Item *)list->data;
159         if (it->type == ITEM_STROKE) gnome_canvas_points_free(it->path);
160         g_free(it);
161       }
162       g_list_free(redo->itemlist);
163     }
164     else if (redo->type == ITEM_NEW_LAYER) {
165       g_free(redo->layer);
166     }
167
168     u = redo;
169     redo = redo->next;
170     g_free(u);
171   }
172   update_undo_redo_enabled();
173 }
174
175 void clear_undo_stack(void)
176 {
177   struct UndoItem *u;
178   GList *list;
179   struct UndoErasureData *erasure;
180   
181   while (undo!=NULL) {
182     // for strokes, items are already in the journal, so we don't free them
183     // for erasures, we need to free the dead items
184     if (undo->type == ITEM_ERASURE) {
185       for (list = undo->erasurelist; list!=NULL; list=list->next) {
186         erasure = (struct UndoErasureData *)list->data;
187         gnome_canvas_points_free(erasure->item->path);
188         g_free(erasure->item);
189         g_list_free(erasure->replacement_items);
190         g_free(erasure);
191       }
192       g_list_free(undo->erasurelist);
193     }
194     else if (undo->type == ITEM_NEW_BG_ONE || undo->type == ITEM_NEW_BG_RESIZE
195           || undo->type == ITEM_NEW_DEFAULT_BG) {
196       if (undo->bg->type == BG_PIXMAP || undo->bg->type == BG_PDF) {
197         if (undo->bg->pixbuf!=NULL) gdk_pixbuf_unref(undo->bg->pixbuf);
198         refstring_unref(undo->bg->filename);
199       }
200       g_free(undo->bg);
201     }
202     else if (undo->type == ITEM_MOVESEL || undo->type == ITEM_PASTE) {
203       g_list_free(undo->itemlist);
204     }
205     else if (undo->type == ITEM_DELETE_LAYER) {
206       undo->layer->group = NULL;
207       delete_layer(undo->layer);
208     }
209     else if (undo->type == ITEM_DELETE_PAGE) {
210       undo->page->group = NULL;
211       delete_page(undo->page);
212     }
213
214     u = undo;
215     undo = undo->next;
216     g_free(u);
217   }
218   update_undo_redo_enabled();
219 }
220
221 // free data structures 
222
223 void delete_journal(struct Journal *j)
224 {
225   while (j->pages!=NULL) {
226     delete_page((struct Page *)j->pages->data);
227     j->pages = g_list_delete_link(j->pages, j->pages);
228   }
229 }
230
231 void delete_page(struct Page *pg)
232 {
233   struct Layer *l;
234   
235   while (pg->layers!=NULL) {
236     l = (struct Layer *)pg->layers->data;
237     l->group = NULL;
238     delete_layer(l);
239     pg->layers = g_list_delete_link(pg->layers, pg->layers);
240   }
241   if (pg->group!=NULL) gtk_object_destroy(GTK_OBJECT(pg->group));
242               // this also destroys the background's canvas items
243   if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
244     if (pg->bg->pixbuf != NULL) gdk_pixbuf_unref(pg->bg->pixbuf);
245     if (pg->bg->filename != NULL) refstring_unref(pg->bg->filename);
246   }
247   g_free(pg->bg);
248   g_free(pg);
249 }
250
251 void delete_layer(struct Layer *l)
252 {
253   struct Item *item;
254   
255   while (l->items!=NULL) {
256     item = (struct Item *)l->items->data;
257     if (item->type == ITEM_STROKE && item->path != NULL) 
258       gnome_canvas_points_free(item->path);
259     // don't need to delete the canvas_item, as it's part of the group destroyed below
260     g_free(item);
261     l->items = g_list_delete_link(l->items, l->items);
262   }
263   if (l->group!= NULL) gtk_object_destroy(GTK_OBJECT(l->group));
264   g_free(l);
265 }
266
267 // referenced strings
268
269 struct Refstring *new_refstring(const char *s)
270 {
271   struct Refstring *rs = g_new(struct Refstring, 1);
272   rs->nref = 1;
273   if (s!=NULL) rs->s = g_strdup(s);
274   else rs->s = NULL;
275   rs->aux = NULL;
276   return rs;
277 }
278
279 struct Refstring *refstring_ref(struct Refstring *rs)
280 {
281   rs->nref++;
282   return rs;
283 }
284
285 void refstring_unref(struct Refstring *rs)
286 {
287   rs->nref--;
288   if (rs->nref == 0) {
289     if (rs->s!=NULL) g_free(rs->s);
290     if (rs->aux!=NULL) g_free(rs->aux);
291     g_free(rs);
292   }
293 }
294
295
296 // some helper functions
297
298 void get_pointer_coords(GdkEvent *event, gdouble *ret)
299 {
300   double x, y;
301   gdk_event_get_coords(event, &x, &y);
302   gnome_canvas_window_to_world(canvas, x, y, ret, ret+1);
303   ret[0] -= ui.cur_page->hoffset;
304   ret[1] -= ui.cur_page->voffset;
305 }
306
307 void fix_xinput_coords(GdkEvent *event)
308 {
309   double *axes, *px, *py, axis_width;
310   GdkDevice *device;
311   int wx, wy, sx, sy;
312   
313   if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
314     axes = event->button.axes;
315     px = &(event->button.x);
316     py = &(event->button.y);
317     device = event->button.device;
318   }
319   else if (event->type == GDK_MOTION_NOTIFY) {
320     axes = event->motion.axes;
321     px = &(event->motion.x);
322     py = &(event->motion.y);
323     device = event->motion.device;
324   }
325   else return; // nothing we know how to do
326   
327   gdk_window_get_origin(event->any.window, &wx, &wy);
328   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
329   
330   axis_width = device->axes[0].max - device->axes[0].min;
331   if (axis_width>EPSILON)
332     *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
333
334   axis_width = device->axes[1].max - device->axes[1].min;
335   if (axis_width>EPSILON)
336     *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
337 }
338
339 void update_item_bbox(struct Item *item)
340 {
341   int i;
342   double *p;
343   
344   if (item->type == ITEM_STROKE) {
345     item->bbox.left = item->bbox.right = item->path->coords[0];
346     item->bbox.top = item->bbox.bottom = item->path->coords[1];
347     for (i=1, p=item->path->coords+2; i<item->path->num_points; i++, p+=2)
348     {
349       if (p[0] < item->bbox.left) item->bbox.left = p[0];
350       if (p[0] > item->bbox.right) item->bbox.right = p[0];
351       if (p[1] < item->bbox.top) item->bbox.top = p[1];
352       if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1];
353     }
354   }
355 }
356
357 void make_page_clipbox(struct Page *pg)
358 {
359   GnomeCanvasPathDef *pg_clip;
360   
361   pg_clip = gnome_canvas_path_def_new_sized(4);
362   gnome_canvas_path_def_moveto(pg_clip, 0., 0.);
363   gnome_canvas_path_def_lineto(pg_clip, 0., pg->height);
364   gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height);
365   gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.);
366   gnome_canvas_path_def_closepath(pg_clip);
367   gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL);
368   gnome_canvas_path_def_unref(pg_clip);
369 }
370
371 void make_canvas_items(void)
372 {
373   struct Page *pg;
374   struct Layer *l;
375   struct Item *item;
376   GList *pagelist, *layerlist, *itemlist;
377   
378   for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) {
379     pg = (struct Page *)pagelist->data;
380     if (pg->group == NULL) {
381       pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
382          gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL);
383       make_page_clipbox(pg);
384     }
385     if (pg->bg->canvas_item == NULL) update_canvas_bg(pg);
386     for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) {
387       l = (struct Layer *)layerlist->data;
388       if (l->group == NULL)
389         l->group = (GnomeCanvasGroup *) gnome_canvas_item_new(
390            pg->group, gnome_canvas_group_get_type(), NULL);
391       for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
392         item = (struct Item *)itemlist->data;
393         if (item->type == ITEM_STROKE && item->canvas_item == NULL) {
394           item->canvas_item = gnome_canvas_item_new(l->group,
395               gnome_canvas_line_get_type(), "points", item->path,
396               "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
397               "fill-color-rgba", item->brush.color_rgba,
398               "width-units", item->brush.thickness, NULL);
399         }
400       }
401     }
402   }
403 }
404
405 void update_canvas_bg(struct Page *pg)
406 {
407   GnomeCanvasGroup *group;
408   GnomeCanvasPoints *seg;
409   GdkPixbuf *scaled_pix;
410   double *pt;
411   double x, y;
412   int w, h;
413   
414   if (pg->bg->canvas_item != NULL)
415     gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
416   pg->bg->canvas_item = NULL;
417   
418   if (pg->bg->type == BG_SOLID)
419   {
420     pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
421                                gnome_canvas_group_get_type(), NULL);
422     group = GNOME_CANVAS_GROUP(pg->bg->canvas_item);
423     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
424     gnome_canvas_item_new(group, gnome_canvas_rect_get_type(),
425       "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height,
426       "fill-color-rgba", pg->bg->color_rgba, NULL);
427     if (pg->bg->ruling == RULING_NONE) return;
428     seg = gnome_canvas_points_new(2);
429     pt = seg->coords;
430     if (pg->bg->ruling == RULING_GRAPH) {
431       pt[1] = 0; pt[3] = pg->height;
432       for (x=RULING_GRAPHSPACING; x<pg->width-1; x+=RULING_GRAPHSPACING) {
433         pt[0] = pt[2] = x;
434         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
435            "points", seg, "fill-color-rgba", RULING_COLOR,
436            "width-units", RULING_THICKNESS, NULL);
437       }      
438       pt[0] = 0; pt[2] = pg->width;
439       for (y=RULING_GRAPHSPACING; y<pg->height-1; y+=RULING_GRAPHSPACING) {
440         pt[1] = pt[3] = y;
441         gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
442            "points", seg, "fill-color-rgba", RULING_COLOR,
443            "width-units", RULING_THICKNESS, NULL);
444       }      
445       gnome_canvas_points_free(seg);
446       return;
447     }
448     pt[0] = 0; pt[2] = pg->width;
449     for (y=RULING_TOPMARGIN; y<pg->height-1; y+=RULING_SPACING) {
450       pt[1] = pt[3] = y;
451       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
452          "points", seg, "fill-color-rgba", RULING_COLOR,
453          "width-units", RULING_THICKNESS, NULL);
454     }      
455     if (pg->bg->ruling == RULING_LINED) {
456       pt[0] = pt[2] = RULING_LEFTMARGIN;
457       pt[1] = 0; pt[3] = pg->height;
458       gnome_canvas_item_new(group, gnome_canvas_line_get_type(),
459          "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR,
460          "width-units", RULING_THICKNESS, NULL);
461     }
462     gnome_canvas_points_free(seg);
463     return;
464   }
465   
466   if (pg->bg->type == BG_PIXMAP)
467   {
468     if (ui.antialias_bg) {
469       set_cursor_busy(TRUE);
470       w = (int)floor(pg->width*ui.zoom+0.5);
471       h = (int)floor(pg->height*ui.zoom+0.5);
472       if (w == gdk_pixbuf_get_width(pg->bg->pixbuf) &&
473           h == gdk_pixbuf_get_height(pg->bg->pixbuf))
474         scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
475       else
476         scaled_pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf, w, h, GDK_INTERP_BILINEAR);
477       pg->bg->pixbuf_scale = ui.zoom;
478       set_cursor_busy(FALSE);
479     }
480     else {
481       scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf);
482       pg->bg->pixbuf_scale = 0;
483     }
484     pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
485         gnome_canvas_pixbuf_get_type(), 
486         "pixbuf", scaled_pix,
487         "width", pg->width, "height", pg->height, 
488         "width-set", TRUE, "height-set", TRUE, 
489         NULL);
490     gdk_pixbuf_unref(scaled_pix);
491     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
492   }
493
494   if (pg->bg->type == BG_PDF)
495   {
496     if (pg->bg->pixbuf == NULL) return;
497     pg->bg->canvas_item = gnome_canvas_item_new(pg->group, 
498         gnome_canvas_pixbuf_get_type(), 
499         "pixbuf", pg->bg->pixbuf,
500         "width", pg->width, "height", pg->height, 
501         "width-set", TRUE, "height-set", TRUE, 
502         NULL);
503     lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
504   }
505
506 }
507
508 gboolean is_visible(struct Page *pg)
509 {
510   GtkAdjustment *v_adj;
511   double ytop, ybot;
512   
513   if (!ui.view_continuous) return (pg == ui.cur_page);
514   v_adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas));
515   ytop = v_adj->value/ui.zoom;
516   ybot = (v_adj->value + v_adj->page_size) / ui.zoom;
517   return (MAX(ytop, pg->voffset) < MIN(ybot, pg->voffset+pg->height));
518 }
519
520 void rescale_bg_pixmaps(void)
521 {
522   GList *pglist;
523   struct Page *pg;
524   GdkPixbuf *pix;
525   
526   for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
527     pg = (struct Page *)pglist->data;
528     // in progressive mode we scale only visible pages
529     if (ui.progressive_bg && !is_visible(pg)) continue;
530
531     if (pg->bg->type == BG_PIXMAP) { // do the rescaling ourselves
532       if (ui.antialias_bg) {
533         if (pg->bg->pixbuf_scale == ui.zoom) continue;
534         set_cursor_busy(TRUE);
535         pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf,
536           (int)floor(pg->width*ui.zoom+0.5), (int)floor(pg->height*ui.zoom+0.5),
537           GDK_INTERP_BILINEAR);
538         gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pix, NULL);
539         gdk_pixbuf_unref(pix);
540         pg->bg->pixbuf_scale = ui.zoom;
541         set_cursor_busy(FALSE);
542       } else
543       {
544         pix = GDK_PIXBUF(g_object_get_data(G_OBJECT(pg->bg->canvas_item), "pixbuf"));
545         if (pix!=pg->bg->pixbuf)
546           gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL);
547         pg->bg->pixbuf_scale = 0;
548       }
549     }
550     if (pg->bg->type == BG_PDF) { // request an asynchronous update
551       if (pg->bg->pixbuf_scale == ui.zoom) continue;
552       add_bgpdf_request(pg->bg->file_page_seq, ui.zoom, FALSE);
553       pg->bg->pixbuf_scale = ui.zoom;
554     }
555   }
556 }
557
558 gboolean have_intersect(struct BBox *a, struct BBox *b)
559 {
560   return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) &&
561          (MAX(a->left, b->left) <= MIN(a->right, b->right));
562 }
563
564 /* In libgnomecanvas 2.10.0, the lower/raise functions fail to update
565    correctly the end of the group's item list. We try to work around this.
566    DON'T USE gnome_canvas_item_raise/lower directly !! */
567
568 void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after)
569 {
570   int i1, i2;
571   
572   i1 = g_list_index(g->item_list, item);
573   if (i1 == -1) return;
574   
575   if (after == NULL) i2 = -1;
576   else i2 = g_list_index(g->item_list, after);
577
578   if (i1 < i2) gnome_canvas_item_raise(item, i2-i1);
579   if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1);
580   
581   // BUGFIX for libgnomecanvas
582   g->item_list_end = g_list_last(g->item_list);
583 }
584
585 // some interface functions
586
587 void update_thickness_buttons(void)
588 {
589   if (ui.toolno >= NUM_STROKE_TOOLS) {
590     gtk_toggle_tool_button_set_active(
591       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
592   } else 
593   switch (ui.cur_brush->thickness_no) {
594     case THICKNESS_FINE:
595       gtk_toggle_tool_button_set_active(
596         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE);
597       break;
598     case THICKNESS_MEDIUM:
599       gtk_toggle_tool_button_set_active(
600         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE);
601       break;
602     case THICKNESS_THICK:
603       gtk_toggle_tool_button_set_active(
604         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE);
605       break;
606     default:
607       gtk_toggle_tool_button_set_active(
608         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE);
609   }
610 }
611
612 void update_color_buttons(void)
613 {
614   if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER) {
615     gtk_toggle_tool_button_set_active(
616       GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
617   } else
618   switch (ui.cur_brush->color_no) {
619     case COLOR_BLACK:
620       gtk_toggle_tool_button_set_active(
621         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE);
622       break;
623     case COLOR_BLUE:
624       gtk_toggle_tool_button_set_active(
625         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE);
626       break;
627     case COLOR_RED:
628       gtk_toggle_tool_button_set_active(
629         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE);
630       break;
631     case COLOR_GREEN:
632       gtk_toggle_tool_button_set_active(
633         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE);
634       break;
635     case COLOR_GRAY:
636       gtk_toggle_tool_button_set_active(
637         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE);
638       break;
639     case COLOR_LIGHTBLUE:
640       gtk_toggle_tool_button_set_active(
641         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE);
642       break;
643     case COLOR_LIGHTGREEN:
644       gtk_toggle_tool_button_set_active(
645         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE);
646       break;
647     case COLOR_MAGENTA:
648       gtk_toggle_tool_button_set_active(
649         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE);
650       break;
651     case COLOR_ORANGE:
652       gtk_toggle_tool_button_set_active(
653         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE);
654       break;
655     case COLOR_YELLOW:
656       gtk_toggle_tool_button_set_active(
657         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE);
658       break;
659     case COLOR_WHITE:
660       gtk_toggle_tool_button_set_active(
661         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE);
662       break;
663     default:
664       gtk_toggle_tool_button_set_active(
665         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE);
666   }
667 }
668
669 void update_tool_buttons(void)
670 {
671   switch(ui.toolno) {
672     case TOOL_PEN:
673       gtk_toggle_tool_button_set_active(
674         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE);
675       break;
676     case TOOL_ERASER:
677       gtk_toggle_tool_button_set_active(
678         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE);
679       break;
680     case TOOL_HIGHLIGHTER:
681       gtk_toggle_tool_button_set_active(
682         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE);
683       break;
684     case TOOL_TEXT:
685       gtk_toggle_tool_button_set_active(
686         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
687       break;
688     case TOOL_SELECTREGION:
689       gtk_toggle_tool_button_set_active(
690         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
691       break;
692     case TOOL_SELECTRECT:
693       gtk_toggle_tool_button_set_active(
694         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE);
695       break;
696     case TOOL_VERTSPACE:
697       gtk_toggle_tool_button_set_active(
698         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE);
699       break;
700   }
701     
702   gtk_toggle_tool_button_set_active(
703     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), ui.ruler);
704   update_thickness_buttons();
705   update_color_buttons();
706 }
707
708 void update_tool_menu(void)
709 {
710   switch(ui.toolno) {
711     case TOOL_PEN:
712       gtk_check_menu_item_set_active(
713         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE);
714       break;
715     case TOOL_ERASER:
716       gtk_check_menu_item_set_active(
717         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE);
718       break;
719     case TOOL_HIGHLIGHTER:
720       gtk_check_menu_item_set_active(
721         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE);
722       break;
723     case TOOL_TEXT:
724       gtk_check_menu_item_set_active(
725         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE);
726       break;
727     case TOOL_SELECTREGION:
728       gtk_check_menu_item_set_active(
729         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE);
730       break;
731     case TOOL_SELECTRECT:
732       gtk_check_menu_item_set_active(
733         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE);
734       break;
735     case TOOL_VERTSPACE:
736       gtk_check_menu_item_set_active(
737         GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE);
738       break;
739   }
740
741   gtk_check_menu_item_set_active(
742     GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), ui.ruler);
743 }
744
745 void update_ruler_indicator(void)
746 {
747   gtk_toggle_tool_button_set_active(
748     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), ui.ruler);
749   gtk_check_menu_item_set_active(
750     GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), ui.ruler);
751 }
752
753 void update_color_menu(void)
754 {
755   if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER) {
756     gtk_check_menu_item_set_active(
757       GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE);
758   } else
759   switch (ui.cur_brush->color_no) {
760     case COLOR_BLACK:
761       gtk_check_menu_item_set_active(
762         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE);
763       break;
764     case COLOR_BLUE:
765       gtk_check_menu_item_set_active(
766         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE);
767       break;
768     case COLOR_RED:
769       gtk_check_menu_item_set_active(
770         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE);
771       break;
772     case COLOR_GREEN:
773       gtk_check_menu_item_set_active(
774         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE);
775       break;
776     case COLOR_GRAY:
777       gtk_check_menu_item_set_active(
778         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE);
779       break;
780     case COLOR_LIGHTBLUE:
781       gtk_check_menu_item_set_active(
782         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE);
783       break;
784     case COLOR_LIGHTGREEN:
785       gtk_check_menu_item_set_active(
786         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE);
787       break;
788     case COLOR_MAGENTA:
789       gtk_check_menu_item_set_active(
790         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE);
791       break;
792     case COLOR_ORANGE:
793       gtk_check_menu_item_set_active(
794         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE);
795       break;
796     case COLOR_YELLOW:
797       gtk_check_menu_item_set_active(
798         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE);
799       break;
800     case COLOR_WHITE:
801       gtk_check_menu_item_set_active(
802         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE);
803       break;
804     default:
805       gtk_check_menu_item_set_active(
806         GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOther")), TRUE);
807   }
808 }
809
810 void update_pen_props_menu(void)
811 {
812   switch(ui.brushes[TOOL_PEN].thickness_no) {
813     case THICKNESS_VERYFINE:
814       gtk_check_menu_item_set_active(
815         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE);
816       break;
817     case THICKNESS_FINE:
818       gtk_check_menu_item_set_active(
819         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE);
820       break;
821     case THICKNESS_MEDIUM:
822       gtk_check_menu_item_set_active(
823         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE);
824       break;
825     case THICKNESS_THICK:
826       gtk_check_menu_item_set_active(
827         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE);
828       break;
829     case THICKNESS_VERYTHICK:
830       gtk_check_menu_item_set_active(
831         GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE);
832       break;
833   }
834 }
835
836 void update_eraser_props_menu(void)
837 {
838   switch (ui.brushes[TOOL_ERASER].thickness_no) {
839     case THICKNESS_FINE:
840       gtk_check_menu_item_set_active(
841         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE);
842       break;
843     case THICKNESS_MEDIUM:
844       gtk_check_menu_item_set_active(
845         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE);
846       break;
847     case THICKNESS_THICK:
848       gtk_check_menu_item_set_active(
849         GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE);
850       break;
851   }
852   
853   gtk_check_menu_item_set_active(
854     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")),
855     ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD);
856   gtk_check_menu_item_set_active(
857     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")),
858     ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT);
859   gtk_check_menu_item_set_active(
860     GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")),
861     ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES);
862 }
863
864 void update_highlighter_props_menu(void)
865 {
866   switch (ui.brushes[TOOL_HIGHLIGHTER].thickness_no) {
867     case THICKNESS_FINE:
868       gtk_check_menu_item_set_active(
869         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE);
870       break;
871     case THICKNESS_MEDIUM:
872       gtk_check_menu_item_set_active(
873         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE);
874       break;
875     case THICKNESS_THICK:
876       gtk_check_menu_item_set_active(
877         GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE);
878       break;
879   }
880 }
881
882 void do_switch_page(int pg, gboolean rescroll, gboolean refresh_all)
883 {
884   int i;
885   struct Layer *layer;
886   GList *list;
887   
888   ui.pageno = pg;
889
890   /* re-show all the layers of the old page */
891   if (ui.cur_page != NULL)
892     for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) {
893       layer = (struct Layer *)list->data;
894       if (layer->group!=NULL)
895         gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group));
896     }
897   
898   ui.cur_page = g_list_nth_data(journal.pages, ui.pageno);
899   ui.layerno = ui.cur_page->nlayers-1;
900   ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data);
901   update_page_stuff();
902   if (ui.progressive_bg) rescale_bg_pixmaps();
903  
904   if (rescroll) { // scroll and force a refresh
905     gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)),
906       ui.cur_page->voffset*ui.zoom);
907     if (refresh_all) 
908       gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
909     else if (!ui.view_continuous)
910       gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.cur_page->group), 0., 0.);
911   }
912 }
913
914 void update_page_stuff(void)
915 {
916   gchar tmp[10];
917   GtkComboBox *layerbox;
918   int i;
919   GList *pglist;
920   GtkSpinButton *spin;
921   struct Page *pg;
922   double vertpos, maxwidth;
923   struct Layer *layer;
924   int relscroll;
925
926   // move the page groups to their rightful locations or hide them
927   if (ui.view_continuous) {
928     vertpos = 0.; 
929     maxwidth = 0.;
930     for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) {
931       pg = (struct Page *)pglist->data;
932       if (pg->group!=NULL) {
933         pg->hoffset = 0.; pg->voffset = vertpos;
934         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
935             "x", pg->hoffset, "y", pg->voffset, NULL);
936         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
937       }
938       vertpos += pg->height + VIEW_CONTINUOUS_SKIP;
939       if (pg->width > maxwidth) maxwidth = pg->width;
940     }
941     vertpos -= VIEW_CONTINUOUS_SKIP;
942     gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos);
943   } else {
944     for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
945       pg = (struct Page *)pglist->data;
946       if (pg == ui.cur_page && pg->group!=NULL) {
947         pg->hoffset = 0.; pg->voffset = 0.;
948         gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), 
949             "x", pg->hoffset, "y", pg->voffset, NULL);
950         gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group));
951       } else {
952         if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group));
953       }
954     }
955     gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height);
956   }
957
958   // update the page / layer info at bottom of screen
959
960   spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo"));
961   ui.in_update_page_stuff = TRUE; // avoid a bad retroaction
962   gtk_spin_button_set_range(spin, 1, journal.npages+1);
963     /* npages+1 will be used to create a new page at end */
964   gtk_spin_button_set_value(spin, ui.pageno+1);
965   g_snprintf(tmp, 10, " of %d", journal.npages);
966   gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp);
967
968   layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer"));
969   if (ui.layerbox_length == 0) {
970     gtk_combo_box_prepend_text(layerbox, "Background");
971     ui.layerbox_length++;
972   }
973   while (ui.layerbox_length > ui.cur_page->nlayers+1) {
974     gtk_combo_box_remove_text(layerbox, 0);
975     ui.layerbox_length--;
976   }
977   while (ui.layerbox_length < ui.cur_page->nlayers+1) {
978     g_snprintf(tmp, 10, "Layer %d", ui.layerbox_length++);
979     gtk_combo_box_prepend_text(layerbox, tmp);
980   }
981   gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno);
982   ui.in_update_page_stuff = FALSE;
983   
984   // update the paper-style menu radio buttons
985   
986   if (ui.view_continuous)
987     gtk_check_menu_item_set_active(
988        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE);
989   else
990     gtk_check_menu_item_set_active(
991        GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE);
992
993   if (ui.cur_page->bg->type == BG_SOLID) {
994     switch (ui.cur_page->bg->color_no) {
995       case COLOR_WHITE:
996         gtk_check_menu_item_set_active(
997           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE);
998         break;
999       case COLOR_YELLOW:
1000         gtk_check_menu_item_set_active(
1001           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE);
1002         break;
1003       case COLOR_RED:
1004         gtk_check_menu_item_set_active(
1005           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE);
1006         break;
1007       case COLOR_ORANGE:
1008         gtk_check_menu_item_set_active(
1009           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE);
1010         break;
1011       case COLOR_BLUE:
1012         gtk_check_menu_item_set_active(
1013           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE);
1014         break;
1015       case COLOR_GREEN:
1016         gtk_check_menu_item_set_active(
1017           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE);
1018         break;
1019       default:
1020         gtk_check_menu_item_set_active(
1021           GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE);
1022         break;
1023     }
1024     switch (ui.cur_page->bg->ruling) {
1025       case RULING_NONE:
1026         gtk_check_menu_item_set_active(
1027           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE);
1028         break;
1029       case RULING_LINED:
1030         gtk_check_menu_item_set_active(
1031           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE);
1032         break;
1033       case RULING_RULED:
1034         gtk_check_menu_item_set_active(
1035           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE);
1036         break;
1037       case RULING_GRAPH:
1038         gtk_check_menu_item_set_active(
1039           GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE);
1040         break;
1041     }
1042   } else {
1043     gtk_check_menu_item_set_active(
1044       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1045     gtk_check_menu_item_set_active(
1046       GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE);
1047   }
1048   
1049   // enable/disable the page/layer menu items and toolbar buttons
1050
1051   gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"), 
1052      ui.cur_page->bg->type == BG_SOLID);
1053   gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"),
1054      ui.cur_page->bg->type == BG_SOLID);
1055   gtk_widget_set_sensitive(GET_COMPONENT("journalApplyAllPages"),
1056      ui.cur_page->bg->type == BG_SOLID);
1057   
1058   gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0);
1059   gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0);
1060   gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE);
1061   gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1);
1062   gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0);
1063   gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0);
1064   gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE);
1065   gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1);
1066   
1067   gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1);
1068   gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
1069
1070   gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
1071   gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
1072 }
1073
1074 void update_toolbar_and_menu(void)
1075 {
1076   update_tool_buttons(); // takes care of other toolbar buttons as well  
1077   update_tool_menu();
1078   update_color_menu();
1079   update_pen_props_menu();
1080   update_eraser_props_menu();
1081   update_highlighter_props_menu();
1082
1083   gtk_toggle_tool_button_set_active(
1084     GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
1085   gtk_check_menu_item_set_active(
1086     GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
1087 }
1088
1089 void update_file_name(char *filename)
1090 {
1091   gchar tmp[100], *p;
1092   if (ui.filename != NULL) g_free(ui.filename);
1093   ui.filename = filename;
1094   if (filename == NULL) {
1095     gtk_window_set_title(GTK_WINDOW (winMain), "Xournal");
1096     return;
1097   }
1098   p = g_utf8_strrchr(filename, -1, '/');
1099   if (p == NULL) p = filename; 
1100   else p = g_utf8_next_char(p);
1101   g_snprintf(tmp, 100, "Xournal - %s", p);
1102   gtk_window_set_title(GTK_WINDOW (winMain), tmp);
1103   new_mru_entry(filename);
1104 }
1105
1106 void update_undo_redo_enabled(void)
1107 {
1108   gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL);
1109   gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL);
1110   gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL);
1111   gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL);
1112 }
1113
1114 void update_copy_paste_enabled(void)
1115 {
1116   gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL);
1117   gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL);
1118   gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL);
1119   gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL);
1120   gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL);
1121 }
1122
1123 void set_cur_color(int color)
1124 {
1125   ui.cur_brush->color_no = color;
1126   if (ui.toolno == TOOL_HIGHLIGHTER)
1127     ui.cur_brush->color_rgba = predef_colors_rgba[color] & HILITER_ALPHA_MASK;
1128   else
1129     ui.cur_brush->color_rgba = predef_colors_rgba[color];
1130 }
1131
1132 void process_color_activate(GtkMenuItem *menuitem, int color)
1133 {
1134   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1135     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1136       return;
1137   } else {
1138     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1139       return;
1140   }
1141
1142   if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER
1143         && ui.toolno != TOOL_TEXT && ui.selection == NULL) {
1144     ui.toolno = TOOL_PEN;
1145     ui.cur_brush = ui.brushes+TOOL_PEN;
1146     update_tool_buttons();
1147     update_tool_menu();
1148   }
1149   
1150   if (ui.toolno == TOOL_PEN || ui.toolno == TOOL_HIGHLIGHTER)
1151     set_cur_color(color);
1152
1153   if ((ui.toolno == TOOL_SELECTREGION || ui.toolno == TOOL_SELECTRECT) &&
1154        ui.selection != NULL)
1155     recolor_selection(color);
1156
1157   update_color_buttons();
1158   update_color_menu();
1159   update_cursor();
1160 }
1161
1162 void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val)
1163 {
1164   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
1165     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1166       return;
1167   } else {
1168     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
1169       return;
1170   }
1171
1172   if (tool >= NUM_STROKE_TOOLS) {
1173     if ((tool == TOOL_SELECTREGION || tool == TOOL_SELECTRECT) && ui.selection != NULL)
1174       rethicken_selection(val);
1175     update_thickness_buttons(); // undo illegal button selection
1176     return;
1177   }
1178   
1179   if (ui.brushes[tool].thickness_no == val) return; // avoid loops
1180   ui.brushes[tool].thickness_no = val;
1181   ui.brushes[tool].thickness = predef_thickness[tool][val];
1182   
1183   update_thickness_buttons();
1184   if (tool == TOOL_PEN) update_pen_props_menu();
1185   if (tool == TOOL_ERASER) update_eraser_props_menu();
1186   if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu();
1187   update_cursor();
1188 }
1189
1190 void process_papercolor_activate(GtkMenuItem *menuitem, int color)
1191 {
1192   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1193     return;
1194
1195   if (ui.cur_page->bg->type != BG_SOLID) {
1196     gtk_check_menu_item_set_active(
1197       GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE);
1198     return;
1199   }
1200
1201   if (ui.cur_page->bg->color_no == color) return;
1202   
1203   reset_selection();
1204   prepare_new_undo();
1205   undo->type = ITEM_NEW_BG_ONE;
1206   undo->page = ui.cur_page;
1207   undo->bg = (struct Background *)g_memdup(ui.cur_page->bg, sizeof(struct Background));
1208   undo->bg->canvas_item = NULL;
1209
1210   ui.cur_page->bg->color_no = color;
1211   ui.cur_page->bg->color_rgba = predef_bgcolors_rgba[color];
1212   update_canvas_bg(ui.cur_page);
1213 }
1214
1215 void process_paperstyle_activate(GtkMenuItem *menuitem, int style)
1216 {
1217   if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
1218     return;
1219
1220   if (ui.cur_page->bg->type == BG_SOLID && ui.cur_page->bg->ruling == style)
1221     return;
1222
1223   reset_selection();
1224   prepare_new_undo();
1225   undo->type = ITEM_NEW_BG_ONE;
1226   undo->page = ui.cur_page;
1227   undo->bg = (struct Background *)g_memdup(ui.cur_page->bg, sizeof(struct Background));
1228   undo->bg->canvas_item = NULL;
1229
1230   if (ui.cur_page->bg->type != BG_SOLID) {
1231     ui.cur_page->bg->type = BG_SOLID;
1232     ui.cur_page->bg->color_no = COLOR_WHITE;
1233     ui.cur_page->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE];
1234     ui.cur_page->bg->filename = NULL;
1235     ui.cur_page->bg->pixbuf = NULL;
1236     update_page_stuff();
1237   }
1238
1239   ui.cur_page->bg->ruling = style;
1240   update_canvas_bg(ui.cur_page);
1241 }
1242
1243 gboolean ok_to_close(void)
1244 {
1245   GtkWidget *dialog;
1246   GtkResponseType response;
1247   GList *pagelist;
1248
1249   if (ui.saved) return TRUE;
1250   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
1251     GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, "Save changes to '%s'?",
1252     (ui.filename!=NULL) ? ui.filename:"Untitled");
1253   gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1254   response = gtk_dialog_run(GTK_DIALOG (dialog));
1255   gtk_widget_destroy(dialog);
1256   if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) 
1257     return FALSE; // aborted
1258   if (response == GTK_RESPONSE_YES) {
1259     on_fileSave_activate(NULL, NULL);
1260     if (!ui.saved) return FALSE; // if save failed, then we abort
1261   }
1262   return TRUE;
1263 }
1264
1265 // test if we're still busy loading a PDF background file
1266 gboolean page_ops_forbidden(void)
1267 {
1268   return (bgpdf.status != STATUS_NOT_INIT && bgpdf.create_pages);
1269 }
1270
1271 // selection / clipboard stuff
1272
1273 void reset_selection(void)
1274 {
1275   if (ui.selection == NULL) return;
1276   if (ui.selection->canvas_item != NULL) 
1277     gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
1278   g_list_free(ui.selection->items);
1279   g_free(ui.selection);
1280   ui.selection = NULL;
1281   update_copy_paste_enabled();
1282 }
1283
1284 void move_journal_items_by(GList *itemlist, double dx, double dy)
1285 {
1286   struct Item *item;
1287   int i;
1288   double *pt;
1289   
1290   while (itemlist!=NULL) {
1291     item = (struct Item *)itemlist->data;
1292     if (item->type == ITEM_STROKE) {
1293       for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
1294         { pt[0] += dx; pt[1] += dy; }
1295       item->bbox.left += dx;
1296       item->bbox.right += dx;
1297       item->bbox.top += dy;
1298       item->bbox.bottom += dy;
1299     }
1300     itemlist = itemlist->next;
1301   }
1302 }