void selection_delete(void) { struct UndoErasureData *erasure; GList *itemlist; struct Item *item; if (ui.selection == NULL) return; prepare_new_undo(); undo->type = ITEM_ERASURE; undo->layer = ui.selection->layer; undo->erasurelist = NULL; for (itemlist = ui.selection->items; itemlist!=NULL; itemlist = itemlist->next) { item = (struct Item *)itemlist->data; if (item->canvas_item!=NULL) gtk_object_destroy(GTK_OBJECT(item->canvas_item)); erasure = g_new(struct UndoErasureData, 1); erasure->item = item; erasure->npos = g_list_index(ui.selection->layer->items, item); erasure->nrepl = 0; erasure->replacement_items = NULL; ui.selection->layer->items = g_list_remove(ui.selection->layer->items, item); ui.selection->layer->nitems--; undo->erasurelist = g_list_prepend(undo->erasurelist, erasure); } reset_selection(); /* NOTE: the erasurelist is built backwards; this guarantees that, upon undo, the erasure->npos fields give the correct position where each item should be reinserted as the list is traversed in the forward direction */ }
void remove_recognized_strokes(struct RecoSegment *rs, int num_old_items) { struct Item *old_item; int i, shift; struct UndoErasureData *erasure; old_item = NULL; prepare_new_undo(); undo->type = ITEM_RECOGNIZER; undo->layer = ui.cur_layer; undo->erasurelist = NULL; shift = 0; for (i=0; i<num_old_items; i++) { if (rs[i].item == old_item) continue; // already done old_item = rs[i].item; erasure = g_new(struct UndoErasureData, 1); erasure->item = old_item; erasure->npos = g_list_index(ui.cur_layer->items, old_item) + (shift++); erasure->nrepl = 0; erasure->replacement_items = NULL; undo->erasurelist = g_list_append(undo->erasurelist, erasure); if (old_item->canvas_item != NULL) gtk_object_destroy(GTK_OBJECT(old_item->canvas_item)); ui.cur_layer->items = g_list_remove(ui.cur_layer->items, old_item); ui.cur_layer->nitems--; } }
// paste external text void clipboard_paste_text(gchar *text) { struct Item *item; double pt[2]; reset_selection(); get_current_pointer_coords(pt); set_current_page(pt); ui.selection = g_new(struct Selection, 1); ui.selection->type = ITEM_SELECTRECT; ui.selection->layer = ui.cur_layer; ui.selection->items = NULL; item = g_new(struct Item, 1); ui.selection->items = g_list_append(ui.selection->items, item); ui.cur_layer->items = g_list_append(ui.cur_layer->items, item); ui.cur_layer->nitems++; item->type = ITEM_TEXT; g_memmove(&(item->brush), &(ui.brushes[ui.cur_mapping][TOOL_PEN]), sizeof(struct Brush)); item->text = text; // text was newly allocated, we keep it item->font_name = g_strdup(ui.font_name); item->font_size = ui.font_size; item->bbox.left = pt[0]; item->bbox.top = pt[1]; make_canvas_item_one(ui.cur_layer->group, item); update_item_bbox(item); // move the text to fit on the page if needed if (item->bbox.right > ui.cur_page->width) item->bbox.left += ui.cur_page->width-item->bbox.right; if (item->bbox.left < 0) item->bbox.left = 0; if (item->bbox.bottom > ui.cur_page->height) item->bbox.top += ui.cur_page->height-item->bbox.bottom; if (item->bbox.top < 0) item->bbox.top = 0; gnome_canvas_item_set(item->canvas_item, "x", item->bbox.left, "y", item->bbox.top, NULL); update_item_bbox(item); ui.selection->bbox = item->bbox; ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group, gnome_canvas_rect_get_type(), "width-pixels", 1, "outline-color-rgba", 0x000000ff, "fill-color-rgba", 0x80808040, "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL); make_dashed(ui.selection->canvas_item); prepare_new_undo(); undo->type = ITEM_PASTE; undo->layer = ui.cur_layer; undo->itemlist = g_list_copy(ui.selection->items); update_copy_paste_enabled(); update_color_menu(); update_thickness_buttons(); update_color_buttons(); update_font_button(); update_cursor(); // FIXME: can't know if pointer is within selection! }
void create_image_from_pixbuf(GdkPixbuf *pixbuf, double *pt) { double scale; struct Item *item; item = g_new(struct Item, 1); item->type = ITEM_IMAGE; item->canvas_item = NULL; item->bbox.left = pt[0]; item->bbox.top = pt[1]; item->image = pixbuf; item->image_png = NULL; item->image_png_len = 0; // Scale at native size, unless that won't fit, in which case we shrink it down. scale = 1 / ui.zoom; if ((scale * gdk_pixbuf_get_width(item->image)) > ui.cur_page->width - item->bbox.left) scale = (ui.cur_page->width - item->bbox.left) / gdk_pixbuf_get_width(item->image); if ((scale * gdk_pixbuf_get_height(item->image)) > ui.cur_page->height - item->bbox.top) scale = (ui.cur_page->height - item->bbox.top) / gdk_pixbuf_get_height(item->image); item->bbox.right = item->bbox.left + scale * gdk_pixbuf_get_width(item->image); item->bbox.bottom = item->bbox.top + scale * gdk_pixbuf_get_height(item->image); ui.cur_layer->items = g_list_append(ui.cur_layer->items, item); ui.cur_layer->nitems++; make_canvas_item_one(ui.cur_layer->group, item); // add undo information prepare_new_undo(); undo->type = ITEM_IMAGE; undo->item = item; undo->layer = ui.cur_layer; ui.cur_item = NULL; ui.cur_item_type = ITEM_NONE; // select image reset_selection(); ui.selection = g_new0(struct Selection, 1); ui.selection->type = ITEM_SELECTRECT; ui.selection->layer = ui.cur_layer; ui.selection->bbox = item->bbox; ui.selection->items = g_list_append(ui.selection->items, item); ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group, gnome_canvas_rect_get_type(), "width-pixels", 1, "outline-color-rgba", 0x000000ff, "fill-color-rgba", 0x80808040, "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL); make_dashed(ui.selection->canvas_item); update_copy_paste_enabled(); }
void finalize_resizesel(void) { struct Item *item; // build the affine transformation double offset_x, offset_y, scaling_x, scaling_y; scaling_x = (ui.selection->new_x2 - ui.selection->new_x1) / (ui.selection->bbox.right - ui.selection->bbox.left); scaling_y = (ui.selection->new_y2 - ui.selection->new_y1) / (ui.selection->bbox.bottom - ui.selection->bbox.top); // couldn't undo a resize-by-zero... if (fabs(scaling_x)<SCALING_EPSILON) scaling_x = SCALING_EPSILON; if (fabs(scaling_y)<SCALING_EPSILON) scaling_y = SCALING_EPSILON; offset_x = ui.selection->new_x1 - ui.selection->bbox.left * scaling_x; offset_y = ui.selection->new_y1 - ui.selection->bbox.top * scaling_y; if (ui.selection->items != NULL) { // create the undo information prepare_new_undo(); undo->type = ITEM_RESIZESEL; undo->itemlist = g_list_copy(ui.selection->items); undo->auxlist = NULL; undo->scaling_x = scaling_x; undo->scaling_y = scaling_y; undo->val_x = offset_x; undo->val_y = offset_y; // actually do the resize operation resize_journal_items_by(ui.selection->items, scaling_x, scaling_y, offset_x, offset_y); } if (scaling_x>0) { ui.selection->bbox.left = ui.selection->new_x1; ui.selection->bbox.right = ui.selection->new_x2; } else { ui.selection->bbox.left = ui.selection->new_x2; ui.selection->bbox.right = ui.selection->new_x1; } if (scaling_y>0) { ui.selection->bbox.top = ui.selection->new_y1; ui.selection->bbox.bottom = ui.selection->new_y2; } else { ui.selection->bbox.top = ui.selection->new_y2; ui.selection->bbox.bottom = ui.selection->new_y1; } make_dashed(ui.selection->canvas_item); ui.cur_item_type = ITEM_NONE; update_cursor(); }
void finalize_movesel(void) { GList *list, *link; if (ui.selection->items != NULL) { prepare_new_undo(); undo->type = ITEM_MOVESEL; undo->itemlist = g_list_copy(ui.selection->items); undo->val_x = ui.selection->last_x - ui.selection->anchor_x; undo->val_y = ui.selection->last_y - ui.selection->anchor_y; undo->layer = ui.selection->layer; undo->layer2 = ui.selection->move_layer; undo->auxlist = NULL; // build auxlist = pointers to Item's just before ours (for depths) for (list = ui.selection->items; list!=NULL; list = list->next) { link = g_list_find(ui.selection->layer->items, list->data); if (link!=NULL) link = link->prev; undo->auxlist = g_list_append(undo->auxlist, ((link!=NULL) ? link->data : NULL)); } ui.selection->layer = ui.selection->move_layer; move_journal_items_by(undo->itemlist, undo->val_x, undo->val_y, undo->layer, undo->layer2, (undo->layer == undo->layer2)?undo->auxlist:NULL); } if (ui.selection->move_pageno!=ui.selection->orig_pageno) do_switch_page(ui.selection->move_pageno, FALSE, FALSE); if (ui.cur_item_type == ITEM_MOVESEL_VERT) reset_selection(); else { ui.selection->bbox.left += undo->val_x; ui.selection->bbox.right += undo->val_x; ui.selection->bbox.top += undo->val_y; ui.selection->bbox.bottom += undo->val_y; make_dashed(ui.selection->canvas_item); /* update selection box object's offset to be trivial, and its internal coordinates to agree with those of the bbox; need this since resize operations will modify the box by setting its coordinates directly */ gnome_canvas_item_affine_absolute(ui.selection->canvas_item, NULL); gnome_canvas_item_set(ui.selection->canvas_item, "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL); } ui.cur_item_type = ITEM_NONE; update_cursor(); }
void rethicken_selection(int val) { GList *itemlist; struct Item *item; struct Brush *brush; GnomeCanvasGroup *group; if (ui.selection == NULL) return; prepare_new_undo(); undo->type = ITEM_REPAINTSEL; undo->itemlist = NULL; undo->auxlist = NULL; for (itemlist = ui.selection->items; itemlist!=NULL; itemlist = itemlist->next) { item = (struct Item *)itemlist->data; if (item->type != ITEM_STROKE || item->brush.tool_type!=TOOL_PEN) continue; // store info for undo undo->itemlist = g_list_append(undo->itemlist, item); brush = (struct Brush *)g_malloc(sizeof(struct Brush)); g_memmove(brush, &(item->brush), sizeof(struct Brush)); undo->auxlist = g_list_append(undo->auxlist, brush); // repaint the stroke item->brush.thickness_no = val; item->brush.thickness = predef_thickness[TOOL_PEN][val]; if (item->canvas_item!=NULL) { if (!item->brush.variable_width) gnome_canvas_item_set(item->canvas_item, "width-units", item->brush.thickness, NULL); else { group = (GnomeCanvasGroup *) item->canvas_item->parent; gtk_object_destroy(GTK_OBJECT(item->canvas_item)); item->brush.variable_width = FALSE; make_canvas_item_one(group, item); } } } }
void recolor_selection(int color_no, guint color_rgba) { GList *itemlist; struct Item *item; struct Brush *brush; GnomeCanvasGroup *group; if (ui.selection == NULL) return; prepare_new_undo(); undo->type = ITEM_REPAINTSEL; undo->itemlist = NULL; undo->auxlist = NULL; for (itemlist = ui.selection->items; itemlist!=NULL; itemlist = itemlist->next) { item = (struct Item *)itemlist->data; if (item->type != ITEM_STROKE && item->type != ITEM_TEXT) continue; if (item->type == ITEM_STROKE && item->brush.tool_type!=TOOL_PEN) continue; // store info for undo undo->itemlist = g_list_append(undo->itemlist, item); brush = (struct Brush *)g_malloc(sizeof(struct Brush)); g_memmove(brush, &(item->brush), sizeof(struct Brush)); undo->auxlist = g_list_append(undo->auxlist, brush); // repaint the stroke item->brush.color_no = color_no; item->brush.color_rgba = color_rgba | 0xff; // no alpha if (item->canvas_item!=NULL) { if (!item->brush.variable_width) gnome_canvas_item_set(item->canvas_item, "fill-color-rgba", item->brush.color_rgba, NULL); else { group = (GnomeCanvasGroup *) item->canvas_item->parent; gtk_object_destroy(GTK_OBJECT(item->canvas_item)); make_canvas_item_one(group, item); } } } }
// paste xournal native data void clipboard_paste_from_xournal(GtkSelectionData *sel_data) { unsigned char *p; int nitems, npts, i, len; struct Item *item; double hoffset, voffset, cx, cy; double *pf; int sx, sy, wx, wy; reset_selection(); ui.selection = g_new(struct Selection, 1); p = sel_data->data + sizeof(int); g_memmove(&nitems, p, sizeof(int)); p+= sizeof(int); ui.selection->type = ITEM_SELECTRECT; ui.selection->layer = ui.cur_layer; g_memmove(&ui.selection->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox); ui.selection->items = NULL; // find by how much we translate the pasted selection gnome_canvas_get_scroll_offsets(canvas, &sx, &sy); gdk_window_get_geometry(GTK_WIDGET(canvas)->window, NULL, NULL, &wx, &wy, NULL); gnome_canvas_window_to_world(canvas, sx + wx/2, sy + wy/2, &cx, &cy); cx -= ui.cur_page->hoffset; cy -= ui.cur_page->voffset; if (cx + (ui.selection->bbox.right-ui.selection->bbox.left)/2 > ui.cur_page->width) cx = ui.cur_page->width - (ui.selection->bbox.right-ui.selection->bbox.left)/2; if (cx - (ui.selection->bbox.right-ui.selection->bbox.left)/2 < 0) cx = (ui.selection->bbox.right-ui.selection->bbox.left)/2; if (cy + (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 > ui.cur_page->height) cy = ui.cur_page->height - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2; if (cy - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 < 0) cy = (ui.selection->bbox.bottom-ui.selection->bbox.top)/2; hoffset = cx - (ui.selection->bbox.right+ui.selection->bbox.left)/2; voffset = cy - (ui.selection->bbox.top+ui.selection->bbox.bottom)/2; ui.selection->bbox.left += hoffset; ui.selection->bbox.right += hoffset; ui.selection->bbox.top += voffset; ui.selection->bbox.bottom += voffset; ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group, gnome_canvas_rect_get_type(), "width-pixels", 1, "outline-color-rgba", 0x000000ff, "fill-color-rgba", 0x80808040, "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL); make_dashed(ui.selection->canvas_item); while (nitems-- > 0) { item = g_new(struct Item, 1); ui.selection->items = g_list_append(ui.selection->items, item); ui.cur_layer->items = g_list_append(ui.cur_layer->items, item); ui.cur_layer->nitems++; g_memmove(&item->type, p, sizeof(int)); p+= sizeof(int); if (item->type == ITEM_STROKE) { g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush); g_memmove(&npts, p, sizeof(int)); p+= sizeof(int); item->path = gnome_canvas_points_new(npts); pf = (double *)p; for (i=0; i<npts; i++) { item->path->coords[2*i] = pf[2*i] + hoffset; item->path->coords[2*i+1] = pf[2*i+1] + voffset; } p+= 2*item->path->num_points*sizeof(double); if (item->brush.variable_width) { item->widths = g_memdup(p, (item->path->num_points-1)*sizeof(double)); p+= (item->path->num_points-1)*sizeof(double); } else item->widths = NULL; update_item_bbox(item); make_canvas_item_one(ui.cur_layer->group, item); } if (item->type == ITEM_TEXT) { g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush); g_memmove(&item->bbox.left, p, sizeof(double)); p+= sizeof(double); g_memmove(&item->bbox.top, p, sizeof(double)); p+= sizeof(double); item->bbox.left += hoffset; item->bbox.top += voffset; g_memmove(&len, p, sizeof(int)); p+= sizeof(int); item->text = g_malloc(len+1); g_memmove(item->text, p, len+1); p+= len+1; g_memmove(&len, p, sizeof(int)); p+= sizeof(int); item->font_name = g_malloc(len+1); g_memmove(item->font_name, p, len+1); p+= len+1; g_memmove(&item->font_size, p, sizeof(double)); p+= sizeof(double); make_canvas_item_one(ui.cur_layer->group, item); } if (item->type == ITEM_IMAGE) { item->canvas_item = NULL; item->image_png = NULL; item->image_png_len = 0; g_memmove(&item->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox); item->bbox.left += hoffset; item->bbox.right += hoffset; item->bbox.top += voffset; item->bbox.bottom += voffset; g_memmove(&item->image_png_len, p, sizeof(gsize)); p+= sizeof(gsize); if (item->image_png_len > 0) { item->image_png = g_memdup(p, item->image_png_len); item->image = pixbuf_from_buffer(item->image_png, item->image_png_len); p+= item->image_png_len; } else { item->image = NULL; } make_canvas_item_one(ui.cur_layer->group, item); } } prepare_new_undo(); undo->type = ITEM_PASTE; undo->layer = ui.cur_layer; undo->itemlist = g_list_copy(ui.selection->items); gtk_selection_data_free(sel_data); update_copy_paste_enabled(); update_color_menu(); update_thickness_buttons(); update_color_buttons(); update_font_button(); update_cursor(); // FIXME: can't know if pointer is within selection! }