8 #include <libgnomecanvas/libgnomecanvas.h>
10 #include <libart_lgpl/art_vpath_dash.h>
13 #include "xo-callbacks.h"
14 #include "xo-interface.h"
15 #include "xo-support.h"
19 /************** drawing nice cursors *********/
21 static char cursor_pen_bits[] = {
22 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
26 static char cursor_eraser_bits[] = {
27 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x08, 0x08, 0x08, 0x08,
28 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x0f,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
31 static char cursor_eraser_mask[] = {
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f,
33 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f,
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
36 void set_cursor_busy(gboolean busy)
41 cursor = gdk_cursor_new(GDK_WATCH);
42 gdk_window_set_cursor(GTK_WIDGET(winMain)->window, cursor);
43 gdk_window_set_cursor(GTK_WIDGET(canvas)->window, cursor);
44 gdk_cursor_unref(cursor);
47 gdk_window_set_cursor(GTK_WIDGET(winMain)->window, NULL);
50 gdk_display_sync(gdk_display_get_default());
53 void update_cursor(void)
55 GdkPixmap *source, *mask;
56 GdkColor fg = {0, 0, 0, 0}, bg = {0, 65535, 65535, 65535};
58 if (GTK_WIDGET(canvas)->window == NULL) return;
60 if (ui.cursor!=NULL) {
61 gdk_cursor_unref(ui.cursor);
64 if (ui.toolno == TOOL_PEN) {
65 fg.red = (ui.cur_brush->color_rgba >> 16) & 0xff00;
66 fg.green = (ui.cur_brush->color_rgba >> 8) & 0xff00;
67 fg.blue = (ui.cur_brush->color_rgba >> 0) & 0xff00;
68 source = gdk_bitmap_create_from_data(NULL, cursor_pen_bits, 16, 16);
69 ui.cursor = gdk_cursor_new_from_pixmap(source, source, &fg, &bg, 7, 7);
70 gdk_bitmap_unref(source);
72 else if (ui.toolno == TOOL_ERASER) {
73 source = gdk_bitmap_create_from_data(NULL, cursor_eraser_bits, 16, 16);
74 mask = gdk_bitmap_create_from_data(NULL, cursor_eraser_mask, 16, 16);
75 ui.cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 7, 7);
76 gdk_bitmap_unref(source);
77 gdk_bitmap_unref(mask);
79 else if (ui.toolno == TOOL_HIGHLIGHTER) {
80 source = gdk_bitmap_create_from_data(NULL, cursor_eraser_bits, 16, 16);
81 mask = gdk_bitmap_create_from_data(NULL, cursor_eraser_mask, 16, 16);
82 bg.red = (ui.cur_brush->color_rgba >> 16) & 0xff00;
83 bg.green = (ui.cur_brush->color_rgba >> 8) & 0xff00;
84 bg.blue = (ui.cur_brush->color_rgba >> 0) & 0xff00;
85 ui.cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 7, 7);
86 gdk_bitmap_unref(source);
87 gdk_bitmap_unref(mask);
89 else if (ui.cur_item_type == ITEM_MOVESEL) {
90 if (ui.toolno == TOOL_VERTSPACE)
91 ui.cursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
93 ui.cursor = gdk_cursor_new(GDK_FLEUR);
95 else if (ui.cur_item_type == ITEM_SELECTRECT) {
96 ui.cursor = gdk_cursor_new(GDK_TCROSS);
99 gdk_window_set_cursor(GTK_WIDGET(canvas)->window, ui.cursor);
103 /************** painting strokes *************/
105 #define SUBDIVIDE_MAXDIST 5.0
107 void subdivide_cur_path(null)
111 double x0, y0, x1, y1;
113 for (n=0, p=ui.cur_path.coords; n<ui.cur_path.num_points-1; n++, p+=2) {
114 pieces = (int)floor(hypot(p[2]-p[0], p[3]-p[1])/SUBDIVIDE_MAXDIST);
116 x0 = p[0]; y0 = p[1];
117 x1 = p[2]; y1 = p[3];
118 realloc_cur_path(ui.cur_path.num_points+pieces-1);
119 g_memmove(ui.cur_path.coords+2*(n+pieces), ui.cur_path.coords+2*(n+1),
120 2*(ui.cur_path.num_points-n-1)*sizeof(double));
121 p = ui.cur_path.coords+2*n;
122 ui.cur_path.num_points += pieces-1;
124 for (k=1; k<pieces; k++) {
126 p[0] = x0 + k*(x1-x0)/pieces;
127 p[1] = y0 + k*(y1-y0)/pieces;
133 void create_new_stroke(GdkEvent *event)
135 ui.cur_item_type = ITEM_STROKE;
136 ui.cur_item = g_new(struct Item, 1);
137 ui.cur_item->type = ITEM_STROKE;
138 g_memmove(&(ui.cur_item->brush), ui.cur_brush, sizeof(struct Brush));
139 ui.cur_item->path = &ui.cur_path;
141 ui.cur_path.num_points = 1;
142 get_pointer_coords(event, ui.cur_path.coords);
145 ui.cur_item->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
146 gnome_canvas_line_get_type(),
147 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
148 "fill-color-rgba", ui.cur_item->brush.color_rgba,
149 "width-units", ui.cur_item->brush.thickness, NULL);
151 ui.cur_item->canvas_item = gnome_canvas_item_new(
152 ui.cur_layer->group, gnome_canvas_group_get_type(), NULL);
155 void continue_stroke(GdkEvent *event)
157 GnomeCanvasPoints seg;
161 pt = ui.cur_path.coords;
163 realloc_cur_path(ui.cur_path.num_points+1);
164 pt = ui.cur_path.coords + 2*(ui.cur_path.num_points-1);
167 get_pointer_coords(event, pt+2);
170 ui.cur_path.num_points = 2;
172 if (hypot(pt[0]-pt[2], pt[1]-pt[3]) < PIXEL_MOTION_THRESHOLD/ui.zoom)
173 return; // not a meaningful motion
174 ui.cur_path.num_points++;
181 /* note: we're using a piece of the cur_path array. This is ok because
182 upon creation the line just copies the contents of the GnomeCanvasPoints
183 into an internal structure */
186 gnome_canvas_item_set(ui.cur_item->canvas_item, "points", &seg, NULL);
188 gnome_canvas_item_new((GnomeCanvasGroup *)ui.cur_item->canvas_item,
189 gnome_canvas_line_get_type(), "points", &seg,
190 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
191 "fill-color-rgba", ui.cur_item->brush.color_rgba,
192 "width-units", ui.cur_item->brush.thickness, NULL);
195 void finalize_stroke(void)
197 if (ui.cur_path.num_points == 1) { // GnomeCanvas doesn't like num_points=1
198 ui.cur_path.coords[2] = ui.cur_path.coords[0]+0.1;
199 ui.cur_path.coords[3] = ui.cur_path.coords[1];
200 ui.cur_path.num_points = 2;
203 subdivide_cur_path(); // split the segment so eraser will work
205 ui.cur_item->path = gnome_canvas_points_new(ui.cur_path.num_points);
206 g_memmove(ui.cur_item->path->coords, ui.cur_path.coords,
207 2*ui.cur_path.num_points*sizeof(double));
208 update_item_bbox(ui.cur_item);
209 ui.cur_path.num_points = 0;
211 // destroy the entire group of temporary line segments
212 gtk_object_destroy(GTK_OBJECT(ui.cur_item->canvas_item));
213 // make a new line item to replace it
214 ui.cur_item->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
215 gnome_canvas_line_get_type(), "points", ui.cur_item->path,
216 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
217 "fill-color-rgba", ui.cur_item->brush.color_rgba,
218 "width-units", ui.cur_item->brush.thickness, NULL);
220 // add undo information
222 undo->type = ITEM_STROKE;
223 undo->item = ui.cur_item;
224 undo->layer = ui.cur_layer;
226 // store the item on top of the layer stack
227 ui.cur_layer->items = g_list_append(ui.cur_layer->items, ui.cur_item);
228 ui.cur_layer->nitems++;
230 ui.cur_item_type = ITEM_NONE;
233 /************** eraser tool *************/
235 void erase_stroke_portions(struct Item *item, double x, double y, double radius,
236 gboolean whole_strokes, struct UndoErasureData *erasure)
240 struct Item *newhead, *newtail;
241 gboolean need_recalc = FALSE;
243 for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {
244 if (hypot(pt[0]-x, pt[1]-y) <= radius) { // found an intersection
245 // FIXME: need to test if line SEGMENT hits the circle
246 // hide the canvas item, and create erasure data if needed
247 if (erasure == NULL) {
248 item->type = ITEM_TEMP_STROKE;
249 gnome_canvas_item_hide(item->canvas_item);
250 /* we'll use this hidden item as an insertion point later */
251 erasure = (struct UndoErasureData *)g_malloc(sizeof(struct UndoErasureData));
252 item->erasure = erasure;
253 erasure->item = item;
254 erasure->npos = g_list_index(ui.cur_layer->items, item);
256 erasure->replacement_items = NULL;
259 newhead = newtail = NULL;
260 if (!whole_strokes) {
262 newhead = (struct Item *)g_malloc(sizeof(struct Item));
263 newhead->type = ITEM_STROKE;
264 g_memmove(&newhead->brush, &item->brush, sizeof(struct Brush));
265 newhead->path = gnome_canvas_points_new(i);
266 g_memmove(newhead->path->coords, item->path->coords, 2*i*sizeof(double));
268 while (++i < item->path->num_points) {
270 if (hypot(pt[0]-x, pt[1]-y) > radius) break;
272 if (i<item->path->num_points-1) {
273 newtail = (struct Item *)g_malloc(sizeof(struct Item));
274 newtail->type = ITEM_STROKE;
275 g_memmove(&newtail->brush, &item->brush, sizeof(struct Brush));
276 newtail->path = gnome_canvas_points_new(item->path->num_points-i);
277 g_memmove(newtail->path->coords, item->path->coords+2*i,
278 2*(item->path->num_points-i)*sizeof(double));
279 newtail->canvas_item = NULL;
282 if (item->type == ITEM_STROKE) {
283 // it's inside an erasure list - we destroy it
284 gnome_canvas_points_free(item->path);
285 if (item->canvas_item != NULL)
286 gtk_object_destroy(GTK_OBJECT(item->canvas_item));
288 erasure->replacement_items = g_list_remove(erasure->replacement_items, item);
292 if (newhead != NULL) {
293 update_item_bbox(newhead);
294 newhead->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
295 gnome_canvas_line_get_type(), "points", newhead->path,
296 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
297 "fill-color-rgba", newhead->brush.color_rgba,
298 "width-units", newhead->brush.thickness, NULL);
299 lower_canvas_item_to(ui.cur_layer->group,
300 newhead->canvas_item, erasure->item->canvas_item);
301 erasure->replacement_items = g_list_prepend(erasure->replacement_items, newhead);
303 // prepending ensures it won't get processed twice
305 // recurse into the new tail
306 need_recalc = (newtail!=NULL);
307 if (newtail == NULL) break;
309 erasure->replacement_items = g_list_prepend(erasure->replacement_items, newtail);
311 i=0; pt=item->path->coords;
314 // add the tail if needed
315 if (!need_recalc) return;
316 update_item_bbox(item);
317 item->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
318 gnome_canvas_line_get_type(), "points", item->path,
319 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
320 "fill-color-rgba", item->brush.color_rgba,
321 "width-units", item->brush.thickness, NULL);
322 lower_canvas_item_to(ui.cur_layer->group, item->canvas_item,
323 erasure->item->canvas_item);
327 void do_eraser(GdkEvent *event, double radius, gboolean whole_strokes)
329 struct Item *item, *repl;
330 GList *itemlist, *repllist;
332 struct BBox eraserbox;
334 get_pointer_coords(event, pos);
335 eraserbox.left = pos[0]-radius;
336 eraserbox.right = pos[0]+radius;
337 eraserbox.top = pos[1]-radius;
338 eraserbox.bottom = pos[1]+radius;
339 for (itemlist = ui.cur_layer->items; itemlist!=NULL; itemlist = itemlist->next) {
340 item = (struct Item *)itemlist->data;
341 if (item->type == ITEM_STROKE) {
342 if (!have_intersect(&(item->bbox), &eraserbox)) continue;
343 erase_stroke_portions(item, pos[0], pos[1], radius, whole_strokes, NULL);
344 } else if (item->type == ITEM_TEMP_STROKE) {
345 repllist = item->erasure->replacement_items;
346 while (repllist!=NULL) {
347 repl = (struct Item *)repllist->data;
348 // we may delete the item soon! so advance now in the list
349 repllist = repllist->next;
350 if (have_intersect(&(repl->bbox), &eraserbox))
351 erase_stroke_portions(repl, pos[0], pos[1], radius, whole_strokes, item->erasure);
357 void finalize_erasure(void)
359 GList *itemlist, *partlist;
360 struct Item *item, *part;
363 undo->type = ITEM_ERASURE;
364 undo->layer = ui.cur_layer;
365 undo->erasurelist = NULL;
367 itemlist = ui.cur_layer->items;
368 while (itemlist!=NULL) {
369 item = (struct Item *)itemlist->data;
370 itemlist = itemlist->next;
371 if (item->type != ITEM_TEMP_STROKE) continue;
372 item->type = ITEM_STROKE;
373 ui.cur_layer->items = g_list_remove(ui.cur_layer->items, item);
374 // the item has an invisible canvas item, which used to act as anchor
375 if (item->canvas_item!=NULL) {
376 gtk_object_destroy(GTK_OBJECT(item->canvas_item));
377 item->canvas_item = NULL;
379 undo->erasurelist = g_list_append(undo->erasurelist, item->erasure);
380 // add the new strokes into the current layer
381 for (partlist = item->erasure->replacement_items; partlist!=NULL; partlist = partlist->next)
382 ui.cur_layer->items = g_list_insert_before(
383 ui.cur_layer->items, itemlist, partlist->data);
384 ui.cur_layer->nitems += item->erasure->nrepl-1;
388 ui.cur_item_type = ITEM_NONE;
390 /* NOTE: the list of erasures goes in the depth order of the layer;
391 this guarantees that, upon undo, the erasure->npos fields give the
392 correct position where each item should be reinserted as the list
393 is traversed in the forward direction */
396 /************ selection tools ***********/
398 void make_dashed(GnomeCanvasItem *item)
406 dashlen[0] = dashlen[1] = 6.0;
407 gnome_canvas_item_set(item, "dash", &dash, NULL);
411 void start_selectrect(GdkEvent *event)
416 ui.cur_item_type = ITEM_SELECTRECT;
417 ui.selection = g_new(struct Selection, 1);
418 ui.selection->type = ITEM_SELECTRECT;
419 ui.selection->items = NULL;
420 ui.selection->layer = ui.cur_layer;
422 get_pointer_coords(event, pt);
423 ui.selection->bbox.left = ui.selection->bbox.right = pt[0];
424 ui.selection->bbox.top = ui.selection->bbox.bottom = pt[1];
426 ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
427 gnome_canvas_rect_get_type(), "width-pixels", 1,
428 "outline-color-rgba", 0x000000ff,
429 "fill-color-rgba", 0x80808040,
430 "x1", pt[0], "x2", pt[0], "y1", pt[1], "y2", pt[1], NULL);
434 void finalize_selectrect(void)
436 double x1, x2, y1, y2;
441 ui.cur_item_type = ITEM_NONE;
443 if (ui.selection->bbox.left > ui.selection->bbox.right) {
444 x1 = ui.selection->bbox.right; x2 = ui.selection->bbox.left;
445 ui.selection->bbox.left = x1; ui.selection->bbox.right = x2;
447 x1 = ui.selection->bbox.left; x2 = ui.selection->bbox.right;
450 if (ui.selection->bbox.top > ui.selection->bbox.bottom) {
451 y1 = ui.selection->bbox.bottom; y2 = ui.selection->bbox.top;
452 ui.selection->bbox.top = y1; ui.selection->bbox.bottom = y2;
454 y1 = ui.selection->bbox.top; y2 = ui.selection->bbox.bottom;
457 for (itemlist = ui.selection->layer->items; itemlist!=NULL; itemlist = itemlist->next) {
458 item = (struct Item *)itemlist->data;
459 if (item->bbox.left >= x1 && item->bbox.right <= x2 &&
460 item->bbox.top >= y1 && item->bbox.bottom <= y2) {
461 ui.selection->items = g_list_append(ui.selection->items, item);
465 if (ui.selection->items == NULL) reset_selection();
466 else make_dashed(ui.selection->canvas_item);
468 update_copy_paste_enabled();
471 gboolean start_movesel(GdkEvent *event)
475 if (ui.selection==NULL) return FALSE;
476 if (ui.cur_layer != ui.selection->layer) return FALSE;
478 get_pointer_coords(event, pt);
479 if (ui.selection->type == ITEM_SELECTRECT) {
480 if (pt[0]<ui.selection->bbox.left || pt[0]>ui.selection->bbox.right ||
481 pt[1]<ui.selection->bbox.top || pt[1]>ui.selection->bbox.bottom)
483 ui.cur_item_type = ITEM_MOVESEL;
484 ui.selection->anchor_x = ui.selection->last_x = pt[0];
485 ui.selection->anchor_y = ui.selection->last_y = pt[1];
486 gnome_canvas_item_set(ui.selection->canvas_item, "dash", NULL, NULL);
493 void start_vertspace(GdkEvent *event)
500 ui.cur_item_type = ITEM_MOVESEL;
501 ui.selection = g_new(struct Selection, 1);
502 ui.selection->type = ITEM_MOVESEL;
503 ui.selection->items = NULL;
504 ui.selection->layer = ui.cur_layer;
506 get_pointer_coords(event, pt);
507 for (itemlist = ui.cur_layer->items; itemlist!=NULL; itemlist = itemlist->next) {
508 item = (struct Item *)itemlist->data;
509 if (item->bbox.top >= pt[1]) {
510 ui.selection->items = g_list_append(ui.selection->items, item);
514 ui.selection->anchor_x = ui.selection->last_x = 0;
515 ui.selection->anchor_y = ui.selection->last_y = pt[1];
516 ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
517 gnome_canvas_rect_get_type(), "width-pixels", 1,
518 "outline-color-rgba", 0x000000ff,
519 "fill-color-rgba", 0x80808040,
520 "x1", -100.0, "x2", ui.cur_page->width+100, "y1", pt[1], "y2", pt[1], NULL);
524 void continue_movesel(GdkEvent *event)
526 double pt[2], dx, dy;
530 get_pointer_coords(event, pt);
531 if (ui.toolno == TOOL_VERTSPACE) pt[0] = 0;
532 dx = pt[0] - ui.selection->last_x;
533 dy = pt[1] - ui.selection->last_y;
535 if (hypot(dx,dy) < 1) return; // don't move subpixel
536 ui.selection->last_x = pt[0];
537 ui.selection->last_y = pt[1];
539 // move the canvas items
540 if (ui.toolno == TOOL_VERTSPACE)
541 gnome_canvas_item_set(ui.selection->canvas_item, "y2", pt[1], NULL);
543 gnome_canvas_item_move(ui.selection->canvas_item, dx, dy);
545 for (list = ui.selection->items; list != NULL; list = list->next) {
546 item = (struct Item *)list->data;
547 if (item->canvas_item != NULL)
548 gnome_canvas_item_move(item->canvas_item, dx, dy);
551 /* consider: if view_continuous, move items to a different page if
552 y value gets out of range (same algo as in button_down event
553 processing); then need to reparent the canvas items, delete the
554 Items from the old Layer, insert them on the new Layer, ...
555 and make an undo-event, probably cut-and-paste style... */
558 void finalize_movesel(void)
560 if (ui.selection->items != NULL) {
562 undo->type = ITEM_MOVESEL;
563 undo->itemlist = g_list_copy(ui.selection->items);
564 undo->val_x = ui.selection->last_x - ui.selection->anchor_x;
565 undo->val_y = ui.selection->last_y - ui.selection->anchor_y;
566 move_journal_items_by(undo->itemlist, undo->val_x, undo->val_y);
569 if (ui.toolno == TOOL_VERTSPACE)
572 ui.selection->bbox.left += undo->val_x;
573 ui.selection->bbox.right += undo->val_x;
574 ui.selection->bbox.top += undo->val_y;
575 ui.selection->bbox.bottom += undo->val_y;
576 make_dashed(ui.selection->canvas_item);
578 ui.cur_item_type = ITEM_NONE;
583 void selection_delete(void)
585 struct UndoErasureData *erasure;
589 if (ui.selection == NULL) return;
591 undo->type = ITEM_ERASURE;
592 undo->layer = ui.selection->layer;
593 undo->erasurelist = NULL;
594 for (itemlist = ui.selection->items; itemlist!=NULL; itemlist = itemlist->next) {
595 item = (struct Item *)itemlist->data;
596 if (item->canvas_item!=NULL)
597 gtk_object_destroy(GTK_OBJECT(item->canvas_item));
598 erasure = g_new(struct UndoErasureData, 1);
599 erasure->item = item;
600 erasure->npos = g_list_index(ui.selection->layer->items, item);
602 erasure->replacement_items = NULL;
603 ui.selection->layer->items = g_list_remove(ui.selection->layer->items, item);
604 ui.selection->layer->nitems--;
605 undo->erasurelist = g_list_prepend(undo->erasurelist, erasure);
609 /* NOTE: the erasurelist is built backwards; this guarantees that,
610 upon undo, the erasure->npos fields give the correct position
611 where each item should be reinserted as the list is traversed in
612 the forward direction */
615 void callback_clipboard_get(GtkClipboard *clipboard,
616 GtkSelectionData *selection_data,
617 guint info, gpointer user_data)
621 g_memmove(&length, user_data, sizeof(int));
622 gtk_selection_data_set(selection_data,
623 gdk_atom_intern("_XOURNAL", FALSE), 8, user_data, length);
626 void callback_clipboard_clear(GtkClipboard *clipboard, gpointer user_data)
631 void selection_to_clip(void)
637 GtkTargetEntry target;
639 if (ui.selection == NULL) return;
640 bufsz = 2*sizeof(int) // bufsz, nitems
641 + sizeof(struct BBox); // bbox
643 for (list = ui.selection->items; list != NULL; list = list->next) {
644 item = (struct Item *)list->data;
646 if (item->type == ITEM_STROKE) {
647 bufsz+= sizeof(int) // type
648 + sizeof(struct Brush) // brush
649 + sizeof(int) // num_points
650 + 2*item->path->num_points*sizeof(double); // the points
652 else bufsz+= sizeof(int); // type
654 p = buf = g_malloc(bufsz);
655 g_memmove(p, &bufsz, sizeof(int)); p+= sizeof(int);
656 g_memmove(p, &nitems, sizeof(int)); p+= sizeof(int);
657 g_memmove(p, &ui.selection->bbox, sizeof(struct BBox)); p+= sizeof(struct BBox);
658 for (list = ui.selection->items; list != NULL; list = list->next) {
659 item = (struct Item *)list->data;
660 g_memmove(p, &item->type, sizeof(int)); p+= sizeof(int);
661 if (item->type == ITEM_STROKE) {
662 g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush);
663 g_memmove(p, &item->path->num_points, sizeof(int)); p+= sizeof(int);
664 g_memmove(p, item->path->coords, 2*item->path->num_points*sizeof(double));
665 p+= 2*item->path->num_points*sizeof(double);
669 target.target = "_XOURNAL";
673 gtk_clipboard_set_with_data(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
675 callback_clipboard_get, callback_clipboard_clear, buf);
679 void clipboard_paste(void)
681 GtkSelectionData *sel_data;
686 double hoffset, voffset, cx, cy;
690 if (ui.cur_layer == NULL) return;
692 ui.cur_item_type = ITEM_PASTE;
693 sel_data = gtk_clipboard_wait_for_contents(
694 gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
695 gdk_atom_intern("_XOURNAL", FALSE));
696 ui.cur_item_type = ITEM_NONE;
697 if (sel_data == NULL) return; // paste failed
700 ui.toolno = TOOL_SELECTRECT;
702 update_tool_buttons();
707 ui.selection = g_new(struct Selection, 1);
708 p = sel_data->data + sizeof(int);
709 g_memmove(&nitems, p, sizeof(int)); p+= sizeof(int);
710 ui.selection->type = ITEM_SELECTRECT;
711 ui.selection->layer = ui.cur_layer;
712 g_memmove(&ui.selection->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox);
713 ui.selection->items = NULL;
715 // find by how much we translate the pasted selection
716 gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
717 gdk_window_get_geometry(GTK_WIDGET(canvas)->window, NULL, NULL, &wx, &wy, NULL);
718 gnome_canvas_window_to_world(canvas, sx + wx/2, sy + wy/2, &cx, &cy);
719 cx -= ui.cur_page->hoffset;
720 cy -= ui.cur_page->voffset;
721 if (cx + (ui.selection->bbox.right-ui.selection->bbox.left)/2 > ui.cur_page->width)
722 cx = ui.cur_page->width - (ui.selection->bbox.right-ui.selection->bbox.left)/2;
723 if (cx - (ui.selection->bbox.right-ui.selection->bbox.left)/2 < 0)
724 cx = (ui.selection->bbox.right-ui.selection->bbox.left)/2;
725 if (cy + (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 > ui.cur_page->height)
726 cy = ui.cur_page->height - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
727 if (cy - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 < 0)
728 cy = (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
729 hoffset = cx - (ui.selection->bbox.right+ui.selection->bbox.left)/2;
730 voffset = cy - (ui.selection->bbox.top+ui.selection->bbox.bottom)/2;
731 ui.selection->bbox.left += hoffset;
732 ui.selection->bbox.right += hoffset;
733 ui.selection->bbox.top += voffset;
734 ui.selection->bbox.bottom += voffset;
736 ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
737 gnome_canvas_rect_get_type(), "width-pixels", 1,
738 "outline-color-rgba", 0x000000ff,
739 "fill-color-rgba", 0x80808040,
740 "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right,
741 "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL);
742 make_dashed(ui.selection->canvas_item);
744 while (nitems-- > 0) {
745 item = g_new(struct Item, 1);
746 ui.selection->items = g_list_append(ui.selection->items, item);
747 ui.cur_layer->items = g_list_append(ui.cur_layer->items, item);
748 ui.cur_layer->nitems++;
749 g_memmove(&item->type, p, sizeof(int)); p+= sizeof(int);
750 if (item->type == ITEM_STROKE) {
751 g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush);
752 g_memmove(&npts, p, sizeof(int)); p+= sizeof(int);
753 item->path = gnome_canvas_points_new(npts);
755 for (i=0; i<npts; i++) {
756 item->path->coords[2*i] = pf[2*i] + hoffset;
757 item->path->coords[2*i+1] = pf[2*i+1] + voffset;
759 p+= 2*item->path->num_points*sizeof(double);
760 update_item_bbox(item);
761 item->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
762 gnome_canvas_line_get_type(), "points", item->path,
763 "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,
764 "fill-color-rgba", item->brush.color_rgba,
765 "width-units", item->brush.thickness, NULL);
770 undo->type = ITEM_PASTE;
771 undo->layer = ui.cur_layer;
772 undo->itemlist = g_list_copy(ui.selection->items);
774 gtk_selection_data_free(sel_data);
775 update_copy_paste_enabled();