From: auroux Date: Sun, 29 Jan 2006 18:48:25 +0000 (+0000) Subject: Initial revision X-Git-Url: https://git.donarmstrong.com/?p=xournal.git;a=commitdiff_plain;h=e93f1837951e3c7a09dd224273de3983c8ecc2e6 Initial revision --- diff --git a/src/xo-misc.c b/src/xo-misc.c new file mode 100644 index 0000000..eb30aac --- /dev/null +++ b/src/xo-misc.c @@ -0,0 +1,1290 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "xournal.h" +#include "xo-interface.h" +#include "xo-support.h" +#include "xo-callbacks.h" +#include "xo-misc.h" + +// some global constants + +guint predef_colors_rgba[COLOR_MAX] = + { 0x000000ff, 0x3333ccff, 0xff0000ff, 0x008000ff, + 0x808080ff, 0x00c0ffff, 0x00ff00ff, 0xff00ffff, + 0xff8000ff, 0xffff00ff, 0xffffffff }; + +guint predef_bgcolors_rgba[COLOR_MAX] = // meaningless ones set to white + { 0xffffffff, 0xa0e8ffff, 0xffc0d4ff, 0x80ffc0ff, + 0xffffffff, 0xa0e8ffff, 0x80ffc0ff, 0xffc0d4ff, + 0xffc080ff, 0xffff80ff, 0xffffffff }; + +double predef_thickness[NUM_STROKE_TOOLS][THICKNESS_MAX] = + { { 0.42, 0.85, 1.41, 2.26, 5.67 }, // pen thicknesses = 0.15, 0.3, 0.5, 0.8, 2 mm + { 2.83, 2.83, 7.08, 14.17, 14.17 }, // eraser thicknesses = 1, 2.5, 5 mm + { 2.83, 2.83, 7.08, 14.17, 14.17 }, // highlighter thicknesses = 1, 2.5, 5 mm + }; + +// some manipulation functions + +struct Page *new_page(struct Page *template) +{ + struct Page *pg = (struct Page *) g_memdup(template, sizeof(struct Page)); + struct Layer *l = g_new(struct Layer, 1); + + l->items = NULL; + l->nitems = 0; + pg->layers = g_list_append(NULL, l); + pg->nlayers = 1; + pg->bg = (struct Background *)g_memdup(template->bg, sizeof(struct Background)); + pg->bg->canvas_item = NULL; + if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) { + gdk_pixbuf_ref(pg->bg->pixbuf); + refstring_ref(pg->bg->filename); + } + pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new( + gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL); + make_page_clipbox(pg); + update_canvas_bg(pg); + l->group = (GnomeCanvasGroup *) gnome_canvas_item_new( + pg->group, gnome_canvas_group_get_type(), NULL); + + return pg; +} + +/* Create a page from a background. + Note: bg should be an UNREFERENCED background. + If needed, first duplicate it and increase the refcount of the pixbuf. +*/ +struct Page *new_page_with_bg(struct Background *bg, double width, double height) +{ + struct Page *pg = g_new(struct Page, 1); + struct Layer *l = g_new(struct Layer, 1); + + l->items = NULL; + l->nitems = 0; + pg->layers = g_list_append(NULL, l); + pg->nlayers = 1; + pg->bg = bg; + pg->bg->canvas_item = NULL; + pg->height = height; + pg->width = width; + pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new( + gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL); + make_page_clipbox(pg); + update_canvas_bg(pg); + l->group = (GnomeCanvasGroup *) gnome_canvas_item_new( + pg->group, gnome_canvas_group_get_type(), NULL); + + return pg; +} + +void realloc_cur_path(int n) +{ + if (n <= ui.cur_path_storage_alloc) return; + ui.cur_path_storage_alloc = n+10; + ui.cur_path.coords = g_realloc(ui.cur_path.coords, 2*(n+10)*sizeof(double)); +} + +// undo utility functions + +void prepare_new_undo(void) +{ + struct UndoItem *u; + // add a new UndoItem on the stack + u = (struct UndoItem *)g_malloc(sizeof(struct UndoItem)); + u->next = undo; + u->multiop = 0; + undo = u; + ui.saved = FALSE; + clear_redo_stack(); +} + +void clear_redo_stack(void) +{ + struct UndoItem *u; + GList *list, *repl; + struct UndoErasureData *erasure; + struct Item *it; + + /* Warning: the redo items might reference items from past redo entries, + which have been destroyed before them. Be careful! As a rule, it's + safe to destroy data which has been created at the current history step, + it's unsafe to refer to any data from previous history steps */ + + while (redo!=NULL) { + if (redo->type == ITEM_STROKE) { + gnome_canvas_points_free(redo->item->path); + g_free(redo->item); + /* the strokes are unmapped, so there are no associated canvas items */ + } + else if (redo->type == ITEM_ERASURE) { + for (list = redo->erasurelist; list!=NULL; list=list->next) { + erasure = (struct UndoErasureData *)list->data; + for (repl = erasure->replacement_items; repl!=NULL; repl=repl->next) { + it = (struct Item *)repl->data; + gnome_canvas_points_free(it->path); + g_free(it); + } + g_list_free(erasure->replacement_items); + g_free(erasure); + } + g_list_free(redo->erasurelist); + } + else if (redo->type == ITEM_NEW_BG_ONE || redo->type == ITEM_NEW_BG_RESIZE + || redo->type == ITEM_NEW_DEFAULT_BG) { + if (redo->bg->type == BG_PIXMAP || redo->bg->type == BG_PDF) { + if (redo->bg->pixbuf!=NULL) gdk_pixbuf_unref(redo->bg->pixbuf); + refstring_unref(redo->bg->filename); + } + g_free(redo->bg); + } + else if (redo->type == ITEM_NEW_PAGE) { + redo->page->group = NULL; + delete_page(redo->page); + } + else if (redo->type == ITEM_MOVESEL) { + g_list_free(redo->itemlist); + } + else if (redo->type == ITEM_PASTE) { + for (list = redo->itemlist; list!=NULL; list=list->next) { + it = (struct Item *)list->data; + if (it->type == ITEM_STROKE) gnome_canvas_points_free(it->path); + g_free(it); + } + g_list_free(redo->itemlist); + } + else if (redo->type == ITEM_NEW_LAYER) { + g_free(redo->layer); + } + + u = redo; + redo = redo->next; + g_free(u); + } + update_undo_redo_enabled(); +} + +void clear_undo_stack(void) +{ + struct UndoItem *u; + GList *list; + struct UndoErasureData *erasure; + + while (undo!=NULL) { + // for strokes, items are already in the journal, so we don't free them + // for erasures, we need to free the dead items + if (undo->type == ITEM_ERASURE) { + for (list = undo->erasurelist; list!=NULL; list=list->next) { + erasure = (struct UndoErasureData *)list->data; + gnome_canvas_points_free(erasure->item->path); + g_free(erasure->item); + g_list_free(erasure->replacement_items); + g_free(erasure); + } + g_list_free(undo->erasurelist); + } + else if (undo->type == ITEM_NEW_BG_ONE || undo->type == ITEM_NEW_BG_RESIZE + || undo->type == ITEM_NEW_DEFAULT_BG) { + if (undo->bg->type == BG_PIXMAP || undo->bg->type == BG_PDF) { + if (undo->bg->pixbuf!=NULL) gdk_pixbuf_unref(undo->bg->pixbuf); + refstring_unref(undo->bg->filename); + } + g_free(undo->bg); + } + else if (undo->type == ITEM_MOVESEL || undo->type == ITEM_PASTE) { + g_list_free(undo->itemlist); + } + else if (undo->type == ITEM_DELETE_LAYER) { + undo->layer->group = NULL; + delete_layer(undo->layer); + } + else if (undo->type == ITEM_DELETE_PAGE) { + undo->page->group = NULL; + delete_page(undo->page); + } + + u = undo; + undo = undo->next; + g_free(u); + } + update_undo_redo_enabled(); +} + +// free data structures + +void delete_journal(struct Journal *j) +{ + while (j->pages!=NULL) { + delete_page((struct Page *)j->pages->data); + j->pages = g_list_delete_link(j->pages, j->pages); + } +} + +void delete_page(struct Page *pg) +{ + struct Layer *l; + + while (pg->layers!=NULL) { + l = (struct Layer *)pg->layers->data; + l->group = NULL; + delete_layer(l); + pg->layers = g_list_delete_link(pg->layers, pg->layers); + } + if (pg->group!=NULL) gtk_object_destroy(GTK_OBJECT(pg->group)); + // this also destroys the background's canvas items + if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) { + if (pg->bg->pixbuf != NULL) gdk_pixbuf_unref(pg->bg->pixbuf); + if (pg->bg->filename != NULL) refstring_unref(pg->bg->filename); + } + g_free(pg->bg); + g_free(pg); +} + +void delete_layer(struct Layer *l) +{ + struct Item *item; + + while (l->items!=NULL) { + item = (struct Item *)l->items->data; + if (item->type == ITEM_STROKE && item->path != NULL) + gnome_canvas_points_free(item->path); + // don't need to delete the canvas_item, as it's part of the group destroyed below + g_free(item); + l->items = g_list_delete_link(l->items, l->items); + } + if (l->group!= NULL) gtk_object_destroy(GTK_OBJECT(l->group)); + g_free(l); +} + +// referenced strings + +struct Refstring *new_refstring(const char *s) +{ + struct Refstring *rs = g_new(struct Refstring, 1); + rs->nref = 1; + if (s!=NULL) rs->s = g_strdup(s); + else rs->s = NULL; + rs->aux = NULL; + return rs; +} + +struct Refstring *refstring_ref(struct Refstring *rs) +{ + rs->nref++; + return rs; +} + +void refstring_unref(struct Refstring *rs) +{ + rs->nref--; + if (rs->nref == 0) { + if (rs->s!=NULL) g_free(rs->s); + if (rs->aux!=NULL) g_free(rs->aux); + g_free(rs); + } +} + + +// some helper functions + +void get_pointer_coords(GdkEvent *event, gdouble *ret) +{ + double x, y; + gdk_event_get_coords(event, &x, &y); + gnome_canvas_window_to_world(canvas, x, y, ret, ret+1); + ret[0] -= ui.cur_page->hoffset; + ret[1] -= ui.cur_page->voffset; +} + +void fix_xinput_coords(GdkEvent *event) +{ + double *axes, *px, *py, axis_width; + GdkDevice *device; + int wx, wy, sx, sy; + + if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) { + axes = event->button.axes; + px = &(event->button.x); + py = &(event->button.y); + device = event->button.device; + } + else if (event->type == GDK_MOTION_NOTIFY) { + axes = event->motion.axes; + px = &(event->motion.x); + py = &(event->motion.y); + device = event->motion.device; + } + else return; // nothing we know how to do + + gdk_window_get_origin(event->any.window, &wx, &wy); + gnome_canvas_get_scroll_offsets(canvas, &sx, &sy); + + axis_width = device->axes[0].max - device->axes[0].min; + if (axis_width>EPSILON) + *px = (axes[0]/axis_width)*ui.screen_width + sx - wx; + + axis_width = device->axes[1].max - device->axes[1].min; + if (axis_width>EPSILON) + *py = (axes[1]/axis_width)*ui.screen_height + sy - wy; +} + +void update_item_bbox(struct Item *item) +{ + int i; + double *p; + + if (item->type == ITEM_STROKE) { + item->bbox.left = item->bbox.right = item->path->coords[0]; + item->bbox.top = item->bbox.bottom = item->path->coords[1]; + for (i=1, p=item->path->coords+2; ipath->num_points; i++, p+=2) + { + if (p[0] < item->bbox.left) item->bbox.left = p[0]; + if (p[0] > item->bbox.right) item->bbox.right = p[0]; + if (p[1] < item->bbox.top) item->bbox.top = p[1]; + if (p[1] > item->bbox.bottom) item->bbox.bottom = p[1]; + } + } +} + +void make_page_clipbox(struct Page *pg) +{ + GnomeCanvasPathDef *pg_clip; + + pg_clip = gnome_canvas_path_def_new_sized(4); + gnome_canvas_path_def_moveto(pg_clip, 0., 0.); + gnome_canvas_path_def_lineto(pg_clip, 0., pg->height); + gnome_canvas_path_def_lineto(pg_clip, pg->width, pg->height); + gnome_canvas_path_def_lineto(pg_clip, pg->width, 0.); + gnome_canvas_path_def_closepath(pg_clip); + gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), "path", pg_clip, NULL); + gnome_canvas_path_def_unref(pg_clip); +} + +void make_canvas_items(void) +{ + struct Page *pg; + struct Layer *l; + struct Item *item; + GList *pagelist, *layerlist, *itemlist; + + for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) { + pg = (struct Page *)pagelist->data; + if (pg->group == NULL) { + pg->group = (GnomeCanvasGroup *) gnome_canvas_item_new( + gnome_canvas_root(canvas), gnome_canvas_clipgroup_get_type(), NULL); + make_page_clipbox(pg); + } + if (pg->bg->canvas_item == NULL) update_canvas_bg(pg); + for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) { + l = (struct Layer *)layerlist->data; + if (l->group == NULL) + l->group = (GnomeCanvasGroup *) gnome_canvas_item_new( + pg->group, gnome_canvas_group_get_type(), NULL); + for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) { + item = (struct Item *)itemlist->data; + if (item->type == ITEM_STROKE && item->canvas_item == NULL) { + item->canvas_item = gnome_canvas_item_new(l->group, + gnome_canvas_line_get_type(), "points", item->path, + "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND, + "fill-color-rgba", item->brush.color_rgba, + "width-units", item->brush.thickness, NULL); + } + } + } + } +} + +void update_canvas_bg(struct Page *pg) +{ + GnomeCanvasGroup *group; + GnomeCanvasPoints *seg; + GdkPixbuf *scaled_pix; + double *pt; + double x, y; + int w, h; + + if (pg->bg->canvas_item != NULL) + gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item)); + pg->bg->canvas_item = NULL; + + if (pg->bg->type == BG_SOLID) + { + pg->bg->canvas_item = gnome_canvas_item_new(pg->group, + gnome_canvas_group_get_type(), NULL); + group = GNOME_CANVAS_GROUP(pg->bg->canvas_item); + lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL); + gnome_canvas_item_new(group, gnome_canvas_rect_get_type(), + "x1", 0., "x2", pg->width, "y1", 0., "y2", pg->height, + "fill-color-rgba", pg->bg->color_rgba, NULL); + if (pg->bg->ruling == RULING_NONE) return; + seg = gnome_canvas_points_new(2); + pt = seg->coords; + if (pg->bg->ruling == RULING_GRAPH) { + pt[1] = 0; pt[3] = pg->height; + for (x=RULING_GRAPHSPACING; xwidth-1; x+=RULING_GRAPHSPACING) { + pt[0] = pt[2] = x; + gnome_canvas_item_new(group, gnome_canvas_line_get_type(), + "points", seg, "fill-color-rgba", RULING_COLOR, + "width-units", RULING_THICKNESS, NULL); + } + pt[0] = 0; pt[2] = pg->width; + for (y=RULING_GRAPHSPACING; yheight-1; y+=RULING_GRAPHSPACING) { + pt[1] = pt[3] = y; + gnome_canvas_item_new(group, gnome_canvas_line_get_type(), + "points", seg, "fill-color-rgba", RULING_COLOR, + "width-units", RULING_THICKNESS, NULL); + } + gnome_canvas_points_free(seg); + return; + } + pt[0] = 0; pt[2] = pg->width; + for (y=RULING_TOPMARGIN; yheight-1; y+=RULING_SPACING) { + pt[1] = pt[3] = y; + gnome_canvas_item_new(group, gnome_canvas_line_get_type(), + "points", seg, "fill-color-rgba", RULING_COLOR, + "width-units", RULING_THICKNESS, NULL); + } + if (pg->bg->ruling == RULING_LINED) { + pt[0] = pt[2] = RULING_LEFTMARGIN; + pt[1] = 0; pt[3] = pg->height; + gnome_canvas_item_new(group, gnome_canvas_line_get_type(), + "points", seg, "fill-color-rgba", RULING_MARGIN_COLOR, + "width-units", RULING_THICKNESS, NULL); + } + gnome_canvas_points_free(seg); + return; + } + + if (pg->bg->type == BG_PIXMAP) + { + if (ui.antialias_bg) { + set_cursor_busy(TRUE); + w = (int)floor(pg->width*ui.zoom+0.5); + h = (int)floor(pg->height*ui.zoom+0.5); + if (w == gdk_pixbuf_get_width(pg->bg->pixbuf) && + h == gdk_pixbuf_get_height(pg->bg->pixbuf)) + scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf); + else + scaled_pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf, w, h, GDK_INTERP_BILINEAR); + pg->bg->pixbuf_scale = ui.zoom; + set_cursor_busy(FALSE); + } + else { + scaled_pix = gdk_pixbuf_ref(pg->bg->pixbuf); + pg->bg->pixbuf_scale = 0; + } + pg->bg->canvas_item = gnome_canvas_item_new(pg->group, + gnome_canvas_pixbuf_get_type(), + "pixbuf", scaled_pix, + "width", pg->width, "height", pg->height, + "width-set", TRUE, "height-set", TRUE, + NULL); + gdk_pixbuf_unref(scaled_pix); + lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL); + } + + if (pg->bg->type == BG_PDF) + { + if (pg->bg->pixbuf == NULL) return; + pg->bg->canvas_item = gnome_canvas_item_new(pg->group, + gnome_canvas_pixbuf_get_type(), + "pixbuf", pg->bg->pixbuf, + "width", pg->width, "height", pg->height, + "width-set", TRUE, "height-set", TRUE, + NULL); + lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL); + } + +} + +gboolean is_visible(struct Page *pg) +{ + GtkAdjustment *v_adj; + double ytop, ybot; + + if (!ui.view_continuous) return (pg == ui.cur_page); + v_adj = gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)); + ytop = v_adj->value/ui.zoom; + ybot = (v_adj->value + v_adj->page_size) / ui.zoom; + return (MAX(ytop, pg->voffset) < MIN(ybot, pg->voffset+pg->height)); +} + +void rescale_bg_pixmaps(void) +{ + GList *pglist; + struct Page *pg; + GdkPixbuf *pix; + + for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) { + pg = (struct Page *)pglist->data; + // in progressive mode we scale only visible pages + if (ui.progressive_bg && !is_visible(pg)) continue; + + if (pg->bg->type == BG_PIXMAP) { // do the rescaling ourselves + if (ui.antialias_bg) { + if (pg->bg->pixbuf_scale == ui.zoom) continue; + set_cursor_busy(TRUE); + pix = gdk_pixbuf_scale_simple(pg->bg->pixbuf, + (int)floor(pg->width*ui.zoom+0.5), (int)floor(pg->height*ui.zoom+0.5), + GDK_INTERP_BILINEAR); + gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pix, NULL); + gdk_pixbuf_unref(pix); + pg->bg->pixbuf_scale = ui.zoom; + set_cursor_busy(FALSE); + } else + { + pix = GDK_PIXBUF(g_object_get_data(G_OBJECT(pg->bg->canvas_item), "pixbuf")); + if (pix!=pg->bg->pixbuf) + gnome_canvas_item_set(pg->bg->canvas_item, "pixbuf", pg->bg->pixbuf, NULL); + pg->bg->pixbuf_scale = 0; + } + } + if (pg->bg->type == BG_PDF) { // request an asynchronous update + if (pg->bg->pixbuf_scale == ui.zoom) continue; + add_bgpdf_request(pg->bg->file_page_seq, ui.zoom, FALSE); + pg->bg->pixbuf_scale = ui.zoom; + } + } +} + +gboolean have_intersect(struct BBox *a, struct BBox *b) +{ + return (MAX(a->top, b->top) <= MIN(a->bottom, b->bottom)) && + (MAX(a->left, b->left) <= MIN(a->right, b->right)); +} + +/* In libgnomecanvas 2.10.0, the lower/raise functions fail to update + correctly the end of the group's item list. We try to work around this. + DON'T USE gnome_canvas_item_raise/lower directly !! */ + +void lower_canvas_item_to(GnomeCanvasGroup *g, GnomeCanvasItem *item, GnomeCanvasItem *after) +{ + int i1, i2; + + i1 = g_list_index(g->item_list, item); + if (i1 == -1) return; + + if (after == NULL) i2 = -1; + else i2 = g_list_index(g->item_list, after); + + if (i1 < i2) gnome_canvas_item_raise(item, i2-i1); + if (i1 > i2+1) gnome_canvas_item_lower(item, i1-i2-1); + + // BUGFIX for libgnomecanvas + g->item_list_end = g_list_last(g->item_list); +} + +// some interface functions + +void update_thickness_buttons(void) +{ + if (ui.toolno >= NUM_STROKE_TOOLS) { + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE); + } else + switch (ui.cur_brush->thickness_no) { + case THICKNESS_FINE: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFine")), TRUE); + break; + case THICKNESS_MEDIUM: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMedium")), TRUE); + break; + case THICKNESS_THICK: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThick")), TRUE); + break; + default: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonThicknessOther")), TRUE); + } +} + +void update_color_buttons(void) +{ + if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER) { + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE); + } else + switch (ui.cur_brush->color_no) { + case COLOR_BLACK: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlack")), TRUE); + break; + case COLOR_BLUE: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonBlue")), TRUE); + break; + case COLOR_RED: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRed")), TRUE); + break; + case COLOR_GREEN: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGreen")), TRUE); + break; + case COLOR_GRAY: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonGray")), TRUE); + break; + case COLOR_LIGHTBLUE: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightBlue")), TRUE); + break; + case COLOR_LIGHTGREEN: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonLightGreen")), TRUE); + break; + case COLOR_MAGENTA: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonMagenta")), TRUE); + break; + case COLOR_ORANGE: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonOrange")), TRUE); + break; + case COLOR_YELLOW: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonYellow")), TRUE); + break; + case COLOR_WHITE: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonWhite")), TRUE); + break; + default: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonColorOther")), TRUE); + } +} + +void update_tool_buttons(void) +{ + switch(ui.toolno) { + case TOOL_PEN: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonPen")), TRUE); + break; + case TOOL_ERASER: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonEraser")), TRUE); + break; + case TOOL_HIGHLIGHTER: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonHighlighter")), TRUE); + break; + case TOOL_TEXT: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE); + break; + case TOOL_SELECTREGION: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE); + break; + case TOOL_SELECTRECT: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRectangle")), TRUE); + break; + case TOOL_VERTSPACE: + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonVerticalSpace")), TRUE); + break; + } + + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), ui.ruler); + update_thickness_buttons(); + update_color_buttons(); +} + +void update_tool_menu(void) +{ + switch(ui.toolno) { + case TOOL_PEN: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsPen")), TRUE); + break; + case TOOL_ERASER: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsEraser")), TRUE); + break; + case TOOL_HIGHLIGHTER: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsHighlighter")), TRUE); + break; + case TOOL_TEXT: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsText")), TRUE); + break; + case TOOL_SELECTREGION: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRegion")), TRUE); + break; + case TOOL_SELECTRECT: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsSelectRectangle")), TRUE); + break; + case TOOL_VERTSPACE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsVerticalSpace")), TRUE); + break; + } + + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), ui.ruler); +} + +void update_ruler_indicator(void) +{ + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonRuler")), ui.ruler); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("toolsRuler")), ui.ruler); +} + +void update_color_menu(void) +{ + if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER) { + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorNA")), TRUE); + } else + switch (ui.cur_brush->color_no) { + case COLOR_BLACK: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlack")), TRUE); + break; + case COLOR_BLUE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorBlue")), TRUE); + break; + case COLOR_RED: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorRed")), TRUE); + break; + case COLOR_GREEN: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGreen")), TRUE); + break; + case COLOR_GRAY: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorGray")), TRUE); + break; + case COLOR_LIGHTBLUE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightBlue")), TRUE); + break; + case COLOR_LIGHTGREEN: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorLightGreen")), TRUE); + break; + case COLOR_MAGENTA: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorMagenta")), TRUE); + break; + case COLOR_ORANGE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOrange")), TRUE); + break; + case COLOR_YELLOW: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorYellow")), TRUE); + break; + case COLOR_WHITE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorWhite")), TRUE); + break; + default: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("colorOther")), TRUE); + } +} + +void update_pen_props_menu(void) +{ + switch(ui.brushes[TOOL_PEN].thickness_no) { + case THICKNESS_VERYFINE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryFine")), TRUE); + break; + case THICKNESS_FINE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessFine")), TRUE); + break; + case THICKNESS_MEDIUM: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessMedium")), TRUE); + break; + case THICKNESS_THICK: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessThick")), TRUE); + break; + case THICKNESS_VERYTHICK: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("penthicknessVeryThick")), TRUE); + break; + } +} + +void update_eraser_props_menu(void) +{ + switch (ui.brushes[TOOL_ERASER].thickness_no) { + case THICKNESS_FINE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserFine")), TRUE); + break; + case THICKNESS_MEDIUM: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserMedium")), TRUE); + break; + case THICKNESS_THICK: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserThick")), TRUE); + break; + } + + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserStandard")), + ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_STANDARD); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserWhiteout")), + ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_WHITEOUT); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("eraserDeleteStrokes")), + ui.brushes[TOOL_ERASER].tool_options == TOOLOPT_ERASER_STROKES); +} + +void update_highlighter_props_menu(void) +{ + switch (ui.brushes[TOOL_HIGHLIGHTER].thickness_no) { + case THICKNESS_FINE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterFine")), TRUE); + break; + case THICKNESS_MEDIUM: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterMedium")), TRUE); + break; + case THICKNESS_THICK: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("highlighterThick")), TRUE); + break; + } +} + +void do_switch_page(int pg, gboolean rescroll) +{ + int i; + struct Layer *layer; + GList *list; + + ui.pageno = pg; + + /* re-show all the layers of the old page */ + if (ui.cur_page != NULL) + for (i=0, list = ui.cur_page->layers; list!=NULL; i++, list = list->next) { + layer = (struct Layer *)list->data; + if (layer->group!=NULL) + gnome_canvas_item_show(GNOME_CANVAS_ITEM(layer->group)); + } + + ui.cur_page = g_list_nth_data(journal.pages, ui.pageno); + ui.layerno = ui.cur_page->nlayers-1; + ui.cur_layer = (struct Layer *)(g_list_last(ui.cur_page->layers)->data); + update_page_stuff(); + if (ui.progressive_bg) rescale_bg_pixmaps(); + + if (rescroll) { // scroll and force a refresh + gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)), + ui.cur_page->voffset*ui.zoom); + gnome_canvas_set_pixels_per_unit(canvas, ui.zoom); + } +} + +void update_page_stuff(void) +{ + gchar tmp[10]; + GtkComboBox *layerbox; + int i; + GList *pglist; + GtkSpinButton *spin; + struct Page *pg; + double vertpos, maxwidth; + struct Layer *layer; + int relscroll; + + // move the page groups to their rightful locations or hide them + if (ui.view_continuous) { + vertpos = 0.; + maxwidth = 0.; + for (i=0, pglist = journal.pages; pglist!=NULL; i++, pglist = pglist->next) { + pg = (struct Page *)pglist->data; + if (pg->group!=NULL) { + pg->hoffset = 0.; pg->voffset = vertpos; + gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), + "x", pg->hoffset, "y", pg->voffset, NULL); + gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group)); + } + vertpos += pg->height + VIEW_CONTINUOUS_SKIP; + if (pg->width > maxwidth) maxwidth = pg->width; + } + vertpos -= VIEW_CONTINUOUS_SKIP; + gnome_canvas_set_scroll_region(canvas, 0, 0, maxwidth, vertpos); + } else { + for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) { + pg = (struct Page *)pglist->data; + if (pg == ui.cur_page && pg->group!=NULL) { + pg->hoffset = 0.; pg->voffset = 0.; + gnome_canvas_item_set(GNOME_CANVAS_ITEM(pg->group), + "x", pg->hoffset, "y", pg->voffset, NULL); + gnome_canvas_item_show(GNOME_CANVAS_ITEM(pg->group)); + } else { + if (pg->group!=NULL) gnome_canvas_item_hide(GNOME_CANVAS_ITEM(pg->group)); + } + } + gnome_canvas_set_scroll_region(canvas, 0, 0, ui.cur_page->width, ui.cur_page->height); + } + + // update the page / layer info at bottom of screen + + spin = GTK_SPIN_BUTTON(GET_COMPONENT("spinPageNo")); + ui.in_update_page_stuff = TRUE; // avoid a bad retroaction + gtk_spin_button_set_range(spin, 1, journal.npages+1); + /* npages+1 will be used to create a new page at end */ + gtk_spin_button_set_value(spin, ui.pageno+1); + g_snprintf(tmp, 10, " of %d", journal.npages); + gtk_label_set_text(GTK_LABEL(GET_COMPONENT("labelNumpages")), tmp); + + layerbox = GTK_COMBO_BOX(GET_COMPONENT("comboLayer")); + if (ui.layerbox_length == 0) { + gtk_combo_box_prepend_text(layerbox, "Background"); + ui.layerbox_length++; + } + while (ui.layerbox_length > ui.cur_page->nlayers+1) { + gtk_combo_box_remove_text(layerbox, 0); + ui.layerbox_length--; + } + while (ui.layerbox_length < ui.cur_page->nlayers+1) { + g_snprintf(tmp, 10, "Layer %d", ui.layerbox_length++); + gtk_combo_box_prepend_text(layerbox, tmp); + } + gtk_combo_box_set_active(layerbox, ui.cur_page->nlayers-1-ui.layerno); + ui.in_update_page_stuff = FALSE; + + // update the paper-style menu radio buttons + + if (ui.view_continuous) + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewContinuous")), TRUE); + else + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewOnePage")), TRUE); + + if (ui.cur_page->bg->type == BG_SOLID) { + switch (ui.cur_page->bg->color_no) { + case COLOR_WHITE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorWhite")), TRUE); + break; + case COLOR_YELLOW: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorYellow")), TRUE); + break; + case COLOR_RED: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorPink")), TRUE); + break; + case COLOR_ORANGE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOrange")), TRUE); + break; + case COLOR_BLUE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorBlue")), TRUE); + break; + case COLOR_GREEN: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorGreen")), TRUE); + break; + default: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorOther")), TRUE); + break; + } + switch (ui.cur_page->bg->ruling) { + case RULING_NONE: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstylePlain")), TRUE); + break; + case RULING_LINED: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleLined")), TRUE); + break; + case RULING_RULED: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleRuled")), TRUE); + break; + case RULING_GRAPH: + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleGraph")), TRUE); + break; + } + } else { + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("paperstyleNA")), TRUE); + } + + // enable/disable the page/layer menu items and toolbar buttons + + gtk_widget_set_sensitive(GET_COMPONENT("journalPaperColor"), + ui.cur_page->bg->type == BG_SOLID); + gtk_widget_set_sensitive(GET_COMPONENT("journalSetAsDefault"), + ui.cur_page->bg->type == BG_SOLID); + + gtk_widget_set_sensitive(GET_COMPONENT("viewFirstPage"), ui.pageno!=0); + gtk_widget_set_sensitive(GET_COMPONENT("viewPreviousPage"), ui.pageno!=0); + gtk_widget_set_sensitive(GET_COMPONENT("viewNextPage"), TRUE); + gtk_widget_set_sensitive(GET_COMPONENT("viewLastPage"), ui.pageno!=journal.npages-1); + gtk_widget_set_sensitive(GET_COMPONENT("buttonFirstPage"), ui.pageno!=0); + gtk_widget_set_sensitive(GET_COMPONENT("buttonPreviousPage"), ui.pageno!=0); + gtk_widget_set_sensitive(GET_COMPONENT("buttonNextPage"), TRUE); + gtk_widget_set_sensitive(GET_COMPONENT("buttonLastPage"), ui.pageno!=journal.npages-1); + + gtk_widget_set_sensitive(GET_COMPONENT("viewShowLayer"), ui.layerno!=ui.cur_page->nlayers-1); + gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0); + + gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL); +} + +void update_toolbar_and_menu(void) +{ + update_tool_buttons(); // takes care of other toolbar buttons as well + update_tool_menu(); + update_color_menu(); + update_pen_props_menu(); + update_eraser_props_menu(); + update_highlighter_props_menu(); + + gtk_toggle_tool_button_set_active( + GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen); +} + +void update_file_name(char *filename) +{ + gchar tmp[100], *p; + if (ui.filename != NULL) g_free(ui.filename); + ui.filename = filename; + if (filename == NULL) { + gtk_window_set_title(GTK_WINDOW (winMain), "Xournal"); + return; + } + p = g_utf8_strrchr(filename, -1, '/'); + if (p == NULL) p = filename; + else p = g_utf8_next_char(p); + g_snprintf(tmp, 100, "Xournal - %s", p); + gtk_window_set_title(GTK_WINDOW (winMain), tmp); +} + +void update_undo_redo_enabled(void) +{ + gtk_widget_set_sensitive(GET_COMPONENT("editUndo"), undo!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("editRedo"), redo!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("buttonUndo"), undo!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("buttonRedo"), redo!=NULL); +} + +void update_copy_paste_enabled(void) +{ + gtk_widget_set_sensitive(GET_COMPONENT("editCut"), ui.selection!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("editCopy"), ui.selection!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("editDelete"), ui.selection!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("buttonCut"), ui.selection!=NULL); + gtk_widget_set_sensitive(GET_COMPONENT("buttonCopy"), ui.selection!=NULL); +} + +void set_cur_color(int color) +{ + ui.cur_brush->color_no = color; + if (ui.toolno == TOOL_HIGHLIGHTER) + ui.cur_brush->color_rgba = predef_colors_rgba[color] & HILITER_ALPHA_MASK; + else + ui.cur_brush->color_rgba = predef_colors_rgba[color]; +} + +void process_color_activate(GtkMenuItem *menuitem, int color) +{ + if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) { + if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem))) + return; + } else { + if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem))) + return; + } + + if (ui.toolno != TOOL_PEN && ui.toolno != TOOL_HIGHLIGHTER + && ui.toolno != TOOL_TEXT && ui.selection == NULL) { + ui.toolno = TOOL_PEN; + ui.cur_brush = ui.brushes+TOOL_PEN; + update_tool_buttons(); + update_tool_menu(); + } + + if (ui.toolno == TOOL_PEN || ui.toolno == TOOL_HIGHLIGHTER) + set_cur_color(color); + + // later add selection tools + + update_color_buttons(); + update_color_menu(); + update_cursor(); +} + +void process_thickness_activate(GtkMenuItem *menuitem, int tool, int val) +{ + if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) { + if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem))) + return; + } else { + if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem))) + return; + } + + if (tool >= NUM_STROKE_TOOLS) { + update_thickness_buttons(); // undo illegal button selection + return; + } + + if (ui.brushes[tool].thickness_no == val) return; // avoid loops + ui.brushes[tool].thickness_no = val; + ui.brushes[tool].thickness = predef_thickness[tool][val]; + + update_thickness_buttons(); + if (tool == TOOL_PEN) update_pen_props_menu(); + if (tool == TOOL_ERASER) update_eraser_props_menu(); + if (tool == TOOL_HIGHLIGHTER) update_highlighter_props_menu(); + update_cursor(); +} + +void process_papercolor_activate(GtkMenuItem *menuitem, int color) +{ + if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem))) + return; + + if (ui.cur_page->bg->type != BG_SOLID) { + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(GET_COMPONENT("papercolorNA")), TRUE); + return; + } + + if (ui.cur_page->bg->color_no == color) return; + + reset_selection(); + prepare_new_undo(); + undo->type = ITEM_NEW_BG_ONE; + undo->page = ui.cur_page; + undo->bg = (struct Background *)g_memdup(ui.cur_page->bg, sizeof(struct Background)); + undo->bg->canvas_item = NULL; + + ui.cur_page->bg->color_no = color; + ui.cur_page->bg->color_rgba = predef_bgcolors_rgba[color]; + update_canvas_bg(ui.cur_page); +} + +void process_paperstyle_activate(GtkMenuItem *menuitem, int style) +{ + if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem))) + return; + + if (ui.cur_page->bg->type == BG_SOLID && ui.cur_page->bg->ruling == style) + return; + + reset_selection(); + prepare_new_undo(); + undo->type = ITEM_NEW_BG_ONE; + undo->page = ui.cur_page; + undo->bg = (struct Background *)g_memdup(ui.cur_page->bg, sizeof(struct Background)); + undo->bg->canvas_item = NULL; + + if (ui.cur_page->bg->type != BG_SOLID) { + ui.cur_page->bg->type = BG_SOLID; + ui.cur_page->bg->color_no = COLOR_WHITE; + ui.cur_page->bg->color_rgba = predef_bgcolors_rgba[COLOR_WHITE]; + ui.cur_page->bg->filename = NULL; + ui.cur_page->bg->pixbuf = NULL; + update_page_stuff(); + } + + ui.cur_page->bg->ruling = style; + update_canvas_bg(ui.cur_page); +} + +gboolean ok_to_close(void) +{ + GtkWidget *dialog; + GtkResponseType response; + GList *pagelist; + + if (ui.saved) return TRUE; + dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, "Save changes to '%s'?", + (ui.filename!=NULL) ? ui.filename:"Untitled"); + gtk_dialog_add_button(GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + response = gtk_dialog_run(GTK_DIALOG (dialog)); + gtk_widget_destroy(dialog); + if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) + return FALSE; // aborted + if (response == GTK_RESPONSE_YES) { + on_fileSave_activate(NULL, NULL); + if (!ui.saved) return FALSE; // if save failed, then we abort + } + return TRUE; +} + +// test if we're still busy loading a PDF background file +gboolean page_ops_forbidden(void) +{ + return (bgpdf.status != STATUS_NOT_INIT && bgpdf.create_pages); +} + +// selection / clipboard stuff + +void reset_selection(void) +{ + if (ui.selection == NULL) return; + if (ui.selection->canvas_item != NULL) + gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item)); + g_list_free(ui.selection->items); + g_free(ui.selection); + ui.selection = NULL; + update_copy_paste_enabled(); +} + +void move_journal_items_by(GList *itemlist, double dx, double dy) +{ + struct Item *item; + int i; + double *pt; + + while (itemlist!=NULL) { + item = (struct Item *)itemlist->data; + if (item->type == ITEM_STROKE) { + for (pt=item->path->coords, i=0; ipath->num_points; i++, pt+=2) + { pt[0] += dx; pt[1] += dy; } + item->bbox.left += dx; + item->bbox.right += dx; + item->bbox.top += dy; + item->bbox.bottom += dy; + } + itemlist = itemlist->next; + } +}