📄 xo-paint.c
字号:
reset_selection(); ui.cur_item_type = ITEM_SELECTRECT; ui.selection = g_new(struct Selection, 1); ui.selection->type = ITEM_SELECTRECT; ui.selection->items = NULL; ui.selection->layer = ui.cur_layer; get_pointer_coords(event, pt); ui.selection->bbox.left = ui.selection->bbox.right = pt[0]; ui.selection->bbox.top = ui.selection->bbox.bottom = pt[1]; 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", pt[0], "x2", pt[0], "y1", pt[1], "y2", pt[1], NULL); update_cursor();}void finalize_selectrect(void){ double x1, x2, y1, y2; GList *itemlist; struct Item *item; ui.cur_item_type = ITEM_NONE; if (ui.selection->bbox.left > ui.selection->bbox.right) { x1 = ui.selection->bbox.right; x2 = ui.selection->bbox.left; ui.selection->bbox.left = x1; ui.selection->bbox.right = x2; } else { x1 = ui.selection->bbox.left; x2 = ui.selection->bbox.right; } if (ui.selection->bbox.top > ui.selection->bbox.bottom) { y1 = ui.selection->bbox.bottom; y2 = ui.selection->bbox.top; ui.selection->bbox.top = y1; ui.selection->bbox.bottom = y2; } else { y1 = ui.selection->bbox.top; y2 = ui.selection->bbox.bottom; } for (itemlist = ui.selection->layer->items; itemlist!=NULL; itemlist = itemlist->next) { item = (struct Item *)itemlist->data; if (item->bbox.left >= x1 && item->bbox.right <= x2 && item->bbox.top >= y1 && item->bbox.bottom <= y2) { ui.selection->items = g_list_append(ui.selection->items, item); } } if (ui.selection->items == NULL) { // if we clicked inside a text zone ? item = click_is_in_text(ui.selection->layer, x1, y1); if (item!=NULL && item==click_is_in_text(ui.selection->layer, x2, y2)) { ui.selection->items = g_list_append(ui.selection->items, item); g_memmove(&(ui.selection->bbox), &(item->bbox), sizeof(struct BBox)); gnome_canvas_item_set(ui.selection->canvas_item, "x1", item->bbox.left, "x2", item->bbox.right, "y1", item->bbox.top, "y2", item->bbox.bottom, NULL); } } if (ui.selection->items == NULL) reset_selection(); else make_dashed(ui.selection->canvas_item); update_cursor(); update_copy_paste_enabled(); update_font_button();}gboolean start_movesel(GdkEvent *event){ double pt[2]; if (ui.selection==NULL) return FALSE; if (ui.cur_layer != ui.selection->layer) return FALSE; get_pointer_coords(event, pt); if (ui.selection->type == ITEM_SELECTRECT) { if (pt[0]<ui.selection->bbox.left || pt[0]>ui.selection->bbox.right || pt[1]<ui.selection->bbox.top || pt[1]>ui.selection->bbox.bottom) return FALSE; ui.cur_item_type = ITEM_MOVESEL; ui.selection->anchor_x = ui.selection->last_x = pt[0]; ui.selection->anchor_y = ui.selection->last_y = pt[1]; ui.selection->orig_pageno = ui.pageno; ui.selection->move_pageno = ui.pageno; ui.selection->move_layer = ui.selection->layer; ui.selection->move_pagedelta = 0.; gnome_canvas_item_set(ui.selection->canvas_item, "dash", NULL, NULL); update_cursor(); return TRUE; } return FALSE;}void start_vertspace(GdkEvent *event){ double pt[2]; GList *itemlist; struct Item *item; reset_selection(); ui.cur_item_type = ITEM_MOVESEL_VERT; ui.selection = g_new(struct Selection, 1); ui.selection->type = ITEM_MOVESEL_VERT; ui.selection->items = NULL; ui.selection->layer = ui.cur_layer; get_pointer_coords(event, pt); ui.selection->bbox.top = ui.selection->bbox.bottom = pt[1]; for (itemlist = ui.cur_layer->items; itemlist!=NULL; itemlist = itemlist->next) { item = (struct Item *)itemlist->data; if (item->bbox.top >= pt[1]) { ui.selection->items = g_list_append(ui.selection->items, item); if (item->bbox.bottom > ui.selection->bbox.bottom) ui.selection->bbox.bottom = item->bbox.bottom; } } ui.selection->anchor_x = ui.selection->last_x = 0; ui.selection->anchor_y = ui.selection->last_y = pt[1]; ui.selection->orig_pageno = ui.pageno; ui.selection->move_pageno = ui.pageno; ui.selection->move_layer = ui.selection->layer; ui.selection->move_pagedelta = 0.; 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", -100.0, "x2", ui.cur_page->width+100, "y1", pt[1], "y2", pt[1], NULL); update_cursor();}void continue_movesel(GdkEvent *event){ double pt[2], dx, dy, upmargin; GList *list; struct Item *item; int tmppageno; struct Page *tmppage; get_pointer_coords(event, pt); if (ui.cur_item_type == ITEM_MOVESEL_VERT) pt[0] = 0; pt[1] += ui.selection->move_pagedelta; // check for page jumps if (ui.cur_item_type == ITEM_MOVESEL_VERT) upmargin = ui.selection->bbox.bottom - ui.selection->bbox.top; else upmargin = VIEW_CONTINUOUS_SKIP; tmppageno = ui.selection->move_pageno; tmppage = g_list_nth_data(journal.pages, tmppageno); while (ui.view_continuous && (pt[1] < - upmargin)) { if (tmppageno == 0) break; tmppageno--; tmppage = g_list_nth_data(journal.pages, tmppageno); pt[1] += tmppage->height + VIEW_CONTINUOUS_SKIP; ui.selection->move_pagedelta += tmppage->height + VIEW_CONTINUOUS_SKIP; } while (ui.view_continuous && (pt[1] > tmppage->height+VIEW_CONTINUOUS_SKIP)) { if (tmppageno == journal.npages-1) break; pt[1] -= tmppage->height + VIEW_CONTINUOUS_SKIP; ui.selection->move_pagedelta -= tmppage->height + VIEW_CONTINUOUS_SKIP; tmppageno++; tmppage = g_list_nth_data(journal.pages, tmppageno); } if (tmppageno != ui.selection->move_pageno) { // move to a new page ! ui.selection->move_pageno = tmppageno; if (tmppageno == ui.selection->orig_pageno) ui.selection->move_layer = ui.selection->layer; else ui.selection->move_layer = (struct Layer *)(g_list_last( ((struct Page *)g_list_nth_data(journal.pages, tmppageno))->layers)->data); gnome_canvas_item_reparent(ui.selection->canvas_item, ui.selection->move_layer->group); for (list = ui.selection->items; list!=NULL; list = list->next) { item = (struct Item *)list->data; if (item->canvas_item!=NULL) gnome_canvas_item_reparent(item->canvas_item, ui.selection->move_layer->group); } // avoid a refresh bug gnome_canvas_item_move(GNOME_CANVAS_ITEM(ui.selection->move_layer->group), 0., 0.); if (ui.cur_item_type == ITEM_MOVESEL_VERT) gnome_canvas_item_set(ui.selection->canvas_item, "x2", tmppage->width+100, "y1", ui.selection->anchor_y+ui.selection->move_pagedelta, NULL); } // now, process things normally dx = pt[0] - ui.selection->last_x; dy = pt[1] - ui.selection->last_y; if (hypot(dx,dy) < 1) return; // don't move subpixel ui.selection->last_x = pt[0]; ui.selection->last_y = pt[1]; // move the canvas items if (ui.cur_item_type == ITEM_MOVESEL_VERT) gnome_canvas_item_set(ui.selection->canvas_item, "y2", pt[1], NULL); else gnome_canvas_item_move(ui.selection->canvas_item, dx, dy); for (list = ui.selection->items; list != NULL; list = list->next) { item = (struct Item *)list->data; if (item->canvas_item != NULL) gnome_canvas_item_move(item->canvas_item, dx, dy); }}void finalize_movesel(void){ GList *list, *link; struct Item *item; 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); } ui.cur_item_type = ITEM_NONE; update_cursor();}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 callback_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data){ int length; g_memmove(&length, user_data, sizeof(int)); gtk_selection_data_set(selection_data, gdk_atom_intern("_XOURNAL", FALSE), 8, user_data, length);}void callback_clipboard_clear(GtkClipboard *clipboard, gpointer user_data){ g_free(user_data);}void selection_to_clip(void){ int bufsz, nitems, val; char *buf, *p; GList *list; struct Item *item; GtkTargetEntry target; if (ui.selection == NULL) return; bufsz = 2*sizeof(int) // bufsz, nitems + sizeof(struct BBox); // bbox nitems = 0; for (list = ui.selection->items; list != NULL; list = list->next) { item = (struct Item *)list->data; nitems++; if (item->type == ITEM_STROKE) { bufsz+= sizeof(int) // type + sizeof(struct Brush) // brush + sizeof(int) // num_points + 2*item->path->num_points*sizeof(double); // the points } else if (item->type == ITEM_TEXT) { bufsz+= sizeof(int) // type + sizeof(struct Brush) // brush + 2*sizeof(double) // bbox upper-left + sizeof(int) // text len + strlen(item->text)+1 // text + sizeof(int) // font_name len + strlen(item->font_name)+1 // font_name + sizeof(double); // font_size } else bufsz+= sizeof(int); // type } p = buf = g_malloc(bufsz); g_memmove(p, &bufsz, sizeof(int)); p+= sizeof(int); g_memmove(p, &nitems, sizeof(int)); p+= sizeof(int); g_memmove(p, &ui.selection->bbox, sizeof(struct BBox)); p+= sizeof(struct BBox); for (list = ui.selection->items; list != NULL; list = list->next) { item = (struct Item *)list->data; g_memmove(p, &item->type, sizeof(int)); p+= sizeof(int); if (item->type == ITEM_STROKE) { g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush); g_memmove(p, &item->path->num_points, sizeof(int)); p+= sizeof(int); g_memmove(p, item->path->coords, 2*item->path->num_points*sizeof(double)); p+= 2*item->path->num_points*sizeof(double); } if (item->type == ITEM_TEXT) { g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush); g_memmove(p, &item->bbox.left, sizeof(double)); p+= sizeof(double); g_memmove(p, &item->bbox.top, sizeof(double)); p+= sizeof(double); val = strlen(item->text); g_memmove(p, &val, sizeof(int)); p+= sizeof(int); g_memmove(p, item->text, val+1); p+= val+1; val = strlen(item->font_name); g_memmove(p, &val, sizeof(int)); p+= sizeof(int); g_memmove(p, item->font_name, val+1); p+= val+1; g_memmove(p, &item->font_size, sizeof(double)); p+= sizeof(double); } } target.target = "_XOURNAL"; target.flags = 0; target.info = 0; gtk_clipboard_set_with_data(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), &target, 1, callback_clipboard_get, callback_clipboard_clear, buf);}void clipboard_paste(void){ GtkSelectionData *sel_data; unsigned char *p; int nitems, npts, i, len; GList *list; struct Item *item; double hoffset, voffset, cx, cy; double *pf; int sx, sy, wx, wy; if (ui.cur_layer == NULL) return; ui.cur_item_type = ITEM_PASTE; sel_data = gtk_clipboard_wait_for_contents( gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), gdk_atom_intern("_XOURNAL", FALSE)); ui.cur_item_type = ITEM_NONE; if (sel_data == NULL) return; // paste failed 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -