⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xo-paint.c

📁 高手写的手写代码!欢迎大家下载,共同交流,如果有问题,请联系我!谢谢!
💻 C
📖 第 1 页 / 共 3 页
字号:
#ifdef HAVE_CONFIG_H#  include <config.h>#endif#include <math.h>#include <string.h>#include <gtk/gtk.h>#include <libgnomecanvas/libgnomecanvas.h>#include <libart_lgpl/art_vpath_dash.h>#include "xournal.h"#include "xo-callbacks.h"#include "xo-interface.h"#include "xo-support.h"#include "xo-misc.h"#include "xo-paint.h"/************** drawing nice cursors *********/static char cursor_pen_bits[] = {   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};static char cursor_eraser_bits[] = {   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x08, 0x08, 0x08, 0x08,   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x0f,   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};static char cursor_eraser_mask[] = {   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f,   0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f,   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};void set_cursor_busy(gboolean busy){  GdkCursor *cursor;    if (busy) {    cursor = gdk_cursor_new(GDK_WATCH);    gdk_window_set_cursor(GTK_WIDGET(winMain)->window, cursor);    gdk_window_set_cursor(GTK_WIDGET(canvas)->window, cursor);    gdk_cursor_unref(cursor);  }  else {    gdk_window_set_cursor(GTK_WIDGET(winMain)->window, NULL);    update_cursor();  }  gdk_display_sync(gdk_display_get_default());}void update_cursor(void){  GdkPixmap *source, *mask;  GdkColor fg = {0, 0, 0, 0}, bg = {0, 65535, 65535, 65535};  if (GTK_WIDGET(canvas)->window == NULL) return;    if (ui.cursor!=NULL) {     gdk_cursor_unref(ui.cursor);    ui.cursor = NULL;  }  if (ui.cur_item_type == ITEM_MOVESEL_VERT)    ui.cursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);  else if (ui.cur_item_type == ITEM_MOVESEL)    ui.cursor = gdk_cursor_new(GDK_FLEUR);  else if (ui.toolno[ui.cur_mapping] == TOOL_PEN) {    fg.red = (ui.cur_brush->color_rgba >> 16) & 0xff00;    fg.green = (ui.cur_brush->color_rgba >> 8) & 0xff00;    fg.blue = (ui.cur_brush->color_rgba >> 0) & 0xff00;    source = gdk_bitmap_create_from_data(NULL, cursor_pen_bits, 16, 16);    ui.cursor = gdk_cursor_new_from_pixmap(source, source, &fg, &bg, 7, 7);    gdk_bitmap_unref(source);  }  else if (ui.toolno[ui.cur_mapping] == TOOL_ERASER) {    source = gdk_bitmap_create_from_data(NULL, cursor_eraser_bits, 16, 16);    mask = gdk_bitmap_create_from_data(NULL, cursor_eraser_mask, 16, 16);    ui.cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 7, 7);    gdk_bitmap_unref(source);    gdk_bitmap_unref(mask);  }  else if (ui.toolno[ui.cur_mapping] == TOOL_HIGHLIGHTER) {    source = gdk_bitmap_create_from_data(NULL, cursor_eraser_bits, 16, 16);    mask = gdk_bitmap_create_from_data(NULL, cursor_eraser_mask, 16, 16);    bg.red = (ui.cur_brush->color_rgba >> 16) & 0xff00;    bg.green = (ui.cur_brush->color_rgba >> 8) & 0xff00;    bg.blue = (ui.cur_brush->color_rgba >> 0) & 0xff00;    ui.cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 7, 7);    gdk_bitmap_unref(source);    gdk_bitmap_unref(mask);  }  else if (ui.cur_item_type == ITEM_SELECTRECT) {    ui.cursor = gdk_cursor_new(GDK_TCROSS);  }  else if (ui.toolno[ui.cur_mapping] == TOOL_HAND) {    ui.cursor = gdk_cursor_new(GDK_HAND1);  }  else if (ui.toolno[ui.cur_mapping] == TOOL_TEXT) {    ui.cursor = gdk_cursor_new(GDK_XTERM);  }    gdk_window_set_cursor(GTK_WIDGET(canvas)->window, ui.cursor);}/************** painting strokes *************/#define SUBDIVIDE_MAXDIST 5.0void subdivide_cur_path(null){  int n, pieces, k;  double *p;  double x0, y0, x1, y1;  for (n=0, p=ui.cur_path.coords; n<ui.cur_path.num_points-1; n++, p+=2) {    pieces = (int)floor(hypot(p[2]-p[0], p[3]-p[1])/SUBDIVIDE_MAXDIST);    if (pieces>1) {      x0 = p[0]; y0 = p[1];      x1 = p[2]; y1 = p[3];      realloc_cur_path(ui.cur_path.num_points+pieces-1);      g_memmove(ui.cur_path.coords+2*(n+pieces), ui.cur_path.coords+2*(n+1),                    2*(ui.cur_path.num_points-n-1)*sizeof(double));      p = ui.cur_path.coords+2*n;      ui.cur_path.num_points += pieces-1;      n += (pieces-1);      for (k=1; k<pieces; k++) {        p+=2;        p[0] = x0 + k*(x1-x0)/pieces;        p[1] = y0 + k*(y1-y0)/pieces;      }     }  }}void create_new_stroke(GdkEvent *event){  ui.cur_item_type = ITEM_STROKE;  ui.cur_item = g_new(struct Item, 1);  ui.cur_item->type = ITEM_STROKE;  g_memmove(&(ui.cur_item->brush), ui.cur_brush, sizeof(struct Brush));  ui.cur_item->path = &ui.cur_path;  realloc_cur_path(2);  ui.cur_path.num_points = 1;  get_pointer_coords(event, ui.cur_path.coords);    if (ui.ruler[ui.cur_mapping])     ui.cur_item->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,      gnome_canvas_line_get_type(),      "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,      "fill-color-rgba", ui.cur_item->brush.color_rgba,      "width-units", ui.cur_item->brush.thickness, NULL);  else    ui.cur_item->canvas_item = gnome_canvas_item_new(      ui.cur_layer->group, gnome_canvas_group_get_type(), NULL);}void continue_stroke(GdkEvent *event){  GnomeCanvasPoints seg;  double *pt;  if (ui.ruler[ui.cur_mapping]) {    pt = ui.cur_path.coords;  } else {    realloc_cur_path(ui.cur_path.num_points+1);    pt = ui.cur_path.coords + 2*(ui.cur_path.num_points-1);  }     get_pointer_coords(event, pt+2);    if (ui.ruler[ui.cur_mapping])    ui.cur_path.num_points = 2;  else {    if (hypot(pt[0]-pt[2], pt[1]-pt[3]) < PIXEL_MOTION_THRESHOLD/ui.zoom)      return;  // not a meaningful motion    ui.cur_path.num_points++;  }  seg.coords = pt;   seg.num_points = 2;  seg.ref_count = 1;    /* note: we're using a piece of the cur_path array. This is ok because     upon creation the line just copies the contents of the GnomeCanvasPoints     into an internal structure */  if (ui.ruler[ui.cur_mapping])    gnome_canvas_item_set(ui.cur_item->canvas_item, "points", &seg, NULL);  else    gnome_canvas_item_new((GnomeCanvasGroup *)ui.cur_item->canvas_item,       gnome_canvas_line_get_type(), "points", &seg,       "cap-style", GDK_CAP_ROUND, "join-style", GDK_JOIN_ROUND,       "fill-color-rgba", ui.cur_item->brush.color_rgba,       "width-units", ui.cur_item->brush.thickness, NULL);}void finalize_stroke(void){  if (ui.cur_path.num_points == 1) { // GnomeCanvas doesn't like num_points=1    ui.cur_path.coords[2] = ui.cur_path.coords[0]+0.1;    ui.cur_path.coords[3] = ui.cur_path.coords[1];    ui.cur_path.num_points = 2;  }    subdivide_cur_path(); // split the segment so eraser will work  ui.cur_item->path = gnome_canvas_points_new(ui.cur_path.num_points);  g_memmove(ui.cur_item->path->coords, ui.cur_path.coords,       2*ui.cur_path.num_points*sizeof(double));  update_item_bbox(ui.cur_item);  ui.cur_path.num_points = 0;  // destroy the entire group of temporary line segments  gtk_object_destroy(GTK_OBJECT(ui.cur_item->canvas_item));  // make a new line item to replace it  make_canvas_item_one(ui.cur_layer->group, ui.cur_item);  // add undo information  prepare_new_undo();  undo->type = ITEM_STROKE;  undo->item = ui.cur_item;  undo->layer = ui.cur_layer;  // store the item on top of the layer stack  ui.cur_layer->items = g_list_append(ui.cur_layer->items, ui.cur_item);  ui.cur_layer->nitems++;  ui.cur_item = NULL;  ui.cur_item_type = ITEM_NONE;}/************** eraser tool *************/void erase_stroke_portions(struct Item *item, double x, double y, double radius,                   gboolean whole_strokes, struct UndoErasureData *erasure){  int i;  double *pt;  struct Item *newhead, *newtail;  gboolean need_recalc = FALSE;  for (i=0, pt=item->path->coords; i<item->path->num_points; i++, pt+=2) {    if (hypot(pt[0]-x, pt[1]-y) <= radius) { // found an intersection      // FIXME: need to test if line SEGMENT hits the circle      // hide the canvas item, and create erasure data if needed      if (erasure == NULL) {        item->type = ITEM_TEMP_STROKE;        gnome_canvas_item_hide(item->canvas_item);              /*  we'll use this hidden item as an insertion point later */        erasure = (struct UndoErasureData *)g_malloc(sizeof(struct UndoErasureData));        item->erasure = erasure;        erasure->item = item;        erasure->npos = g_list_index(ui.cur_layer->items, item);        erasure->nrepl = 0;        erasure->replacement_items = NULL;      }      // split the stroke      newhead = newtail = NULL;      if (!whole_strokes) {        if (i>=2) {          newhead = (struct Item *)g_malloc(sizeof(struct Item));          newhead->type = ITEM_STROKE;          g_memmove(&newhead->brush, &item->brush, sizeof(struct Brush));          newhead->path = gnome_canvas_points_new(i);          g_memmove(newhead->path->coords, item->path->coords, 2*i*sizeof(double));        }        while (++i < item->path->num_points) {          pt+=2;          if (hypot(pt[0]-x, pt[1]-y) > radius) break;        }        if (i<item->path->num_points-1) {          newtail = (struct Item *)g_malloc(sizeof(struct Item));          newtail->type = ITEM_STROKE;          g_memmove(&newtail->brush, &item->brush, sizeof(struct Brush));          newtail->path = gnome_canvas_points_new(item->path->num_points-i);          g_memmove(newtail->path->coords, item->path->coords+2*i,                            2*(item->path->num_points-i)*sizeof(double));          newtail->canvas_item = NULL;        }      }      if (item->type == ITEM_STROKE) {         // it's inside an erasure list - we destroy it        gnome_canvas_points_free(item->path);        if (item->canvas_item != NULL)           gtk_object_destroy(GTK_OBJECT(item->canvas_item));        erasure->nrepl--;        erasure->replacement_items = g_list_remove(erasure->replacement_items, item);        g_free(item);      }      // add the new head      if (newhead != NULL) {        update_item_bbox(newhead);        make_canvas_item_one(ui.cur_layer->group, newhead);        lower_canvas_item_to(ui.cur_layer->group,                  newhead->canvas_item, erasure->item->canvas_item);        erasure->replacement_items = g_list_prepend(erasure->replacement_items, newhead);        erasure->nrepl++;        // prepending ensures it won't get processed twice      }      // recurse into the new tail      need_recalc = (newtail!=NULL);      if (newtail == NULL) break;      item = newtail;      erasure->replacement_items = g_list_prepend(erasure->replacement_items, newtail);      erasure->nrepl++;      i=0; pt=item->path->coords;    }  }  // add the tail if needed  if (!need_recalc) return;  update_item_bbox(item);  make_canvas_item_one(ui.cur_layer->group, item);  lower_canvas_item_to(ui.cur_layer->group, item->canvas_item,                                       erasure->item->canvas_item);}void do_eraser(GdkEvent *event, double radius, gboolean whole_strokes){  struct Item *item, *repl;  GList *itemlist, *repllist;  double pos[2];  struct BBox eraserbox;    get_pointer_coords(event, pos);  eraserbox.left = pos[0]-radius;  eraserbox.right = pos[0]+radius;  eraserbox.top = pos[1]-radius;  eraserbox.bottom = pos[1]+radius;  for (itemlist = ui.cur_layer->items; itemlist!=NULL; itemlist = itemlist->next) {    item = (struct Item *)itemlist->data;    if (item->type == ITEM_STROKE) {      if (!have_intersect(&(item->bbox), &eraserbox)) continue;      erase_stroke_portions(item, pos[0], pos[1], radius, whole_strokes, NULL);    } else if (item->type == ITEM_TEMP_STROKE) {      repllist = item->erasure->replacement_items;      while (repllist!=NULL) {        repl = (struct Item *)repllist->data;          // we may delete the item soon! so advance now in the list        repllist = repllist->next;         if (have_intersect(&(repl->bbox), &eraserbox))          erase_stroke_portions(repl, pos[0], pos[1], radius, whole_strokes, item->erasure);      }    }  }}void finalize_erasure(void){  GList *itemlist, *partlist;  struct Item *item, *part;    prepare_new_undo();  undo->type = ITEM_ERASURE;  undo->layer = ui.cur_layer;  undo->erasurelist = NULL;    itemlist = ui.cur_layer->items;  while (itemlist!=NULL) {    item = (struct Item *)itemlist->data;    itemlist = itemlist->next;    if (item->type != ITEM_TEMP_STROKE) continue;    item->type = ITEM_STROKE;    ui.cur_layer->items = g_list_remove(ui.cur_layer->items, item);    // the item has an invisible canvas item, which used to act as anchor    if (item->canvas_item!=NULL) {      gtk_object_destroy(GTK_OBJECT(item->canvas_item));      item->canvas_item = NULL;    }    undo->erasurelist = g_list_append(undo->erasurelist, item->erasure);    // add the new strokes into the current layer    for (partlist = item->erasure->replacement_items; partlist!=NULL; partlist = partlist->next)      ui.cur_layer->items = g_list_insert_before(                      ui.cur_layer->items, itemlist, partlist->data);    ui.cur_layer->nitems += item->erasure->nrepl-1;  }      ui.cur_item = NULL;  ui.cur_item_type = ITEM_NONE;    /* NOTE: the list of erasures goes in the depth order of the layer;     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 */}/************ selection tools ***********/void make_dashed(GnomeCanvasItem *item){  double dashlen[2];  ArtVpathDash dash;    dash.n_dash = 2;  dash.offset = 3.0;  dash.dash = dashlen;  dashlen[0] = dashlen[1] = 6.0;  gnome_canvas_item_set(item, "dash", &dash, NULL);}void start_selectrect(GdkEvent *event){  double pt[2];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -