head 1.14; access; symbols; locks; strict; comment @ * @; 1.14 date 2005.06.15.18.07.35; author cworth; state Exp; branches; next 1.13; commitid 550742b06e674567; 1.13 date 2005.05.17.14.50.15; author cworth; state Exp; branches; next 1.12; commitid cd9428a04a64567; 1.12 date 2005.05.13.22.33.59; author cworth; state Exp; branches; next 1.11; commitid 23ab42852b564567; 1.11 date 2005.02.07.13.38.19; author pippin; state Exp; branches; next 1.10; 1.10 date 2005.01.20.16.32.30; author cworth; state Exp; branches; next 1.9; 1.9 date 2004.11.10.16.08.23; author cworth; state Exp; branches; next 1.8; 1.8 date 2004.05.11.14.45.32; author pippin; state Exp; branches; next 1.7; 1.7 date 2003.12.08.20.58.41; author dajobe; state Exp; branches; next 1.6; 1.6 date 2003.11.07.20.09.14; author cworth; state Exp; branches; next 1.5; 1.5 date 2003.10.24.16.32.31; author cworth; state Exp; branches; next 1.4; 1.4 date 2003.10.01.02.04.48; author jamey; state Exp; branches; next 1.3; 1.3 date 2003.09.16.17.26.19; author cworth; state Exp; branches; next 1.2; 1.2 date 2003.09.04.13.54.29; author cworth; state Exp; branches; next 1.1; 1.1 date 2003.08.18.18.11.37; author cworth; state Exp; branches; next ; desc @@ 1.14 log @ * Makefile: Don't build gtkcairo_slide directory by default. * X11/cairo-demo-xcb.c: (win_draw): * X11/cairo-demo.c: (win_draw): * X11/cairo-spline.c: (win_refresh): Track replacement of cairo_status_string by cairo_status_to_string. @ text @#include #include #include #include #include #include #define EPSILON (1.0 / (2<<16)) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) typedef struct color { double red; double green; double blue; } color_t; typedef struct pt { double x; double y; } pt_t; typedef struct spline { pt_t pt[4]; } spline_t; typedef struct quadr { pt_t pt[4]; } quadr_t; typedef struct win { Display *dpy; int scr; Window win; GC gc; Pixmap pix; int width, height; long event_mask; int needs_refresh; double tolerance; double line_width; cairo_line_cap_t line_cap; spline_t spline; double zoom; double xtrans; double ytrans; int click; pt_t drag_pt; int active; } win_t; typedef struct callback_doc { void *callback; char *doc; } callback_doc_t; typedef int (*key_callback_t)(win_t *win); typedef struct key_binding { char *key; int is_alias; KeyCode keycode; key_callback_t callback; } key_binding_t; static void win_init(win_t *win, Display *dpy); static void win_deinit(win_t *win); static void win_refresh(win_t *win); static void win_select_events(win_t *win); static void win_handle_events(win_t *win); static void win_print_help(win_t *win); static int quit_cb(win_t *win); static int print_spline_cb(win_t *win); static int zoom_in_cb(win_t *win); static int zoom_out_cb(win_t *win); static int trans_left_cb(win_t *win); static int trans_right_cb(win_t *win); static int trans_up_cb(win_t *win); static int trans_down_cb(win_t *win); static int flatten_cb(win_t *win); static int smooth_cb(win_t *win); static int widen_line(win_t *win); static int narrow_line(win_t *win); static const double DEFAULT_XTRANS = 0.0; static const double DEFAULT_YTRANS = 0.0; static const double DEFAULT_TOLERANCE = .1; static const double DEFAULT_LINE_WIDTH = 10; static const double DEFAULT_ZOOM = 1.0; static const cairo_line_cap_t DEFAULT_LINE_CAP = CAIRO_LINE_CAP_ROUND; /* A simple looping spline. */ static const spline_t ribbon = { { {110, 20}, {310, 300}, {10, 310}, {210, 20} } }; #define DEFAULT_SPLINE ribbon static const callback_doc_t callback_doc[] = { { quit_cb, "Exit the program" }, { print_spline_cb, "Print current spline coordinates on stdout" }, { zoom_in_cb, "Zoom in" }, { zoom_out_cb, "Zoom out" }, { trans_left_cb, "Translate left" }, { trans_right_cb, "Translate right" }, { trans_up_cb, "Translate up" }, { trans_down_cb, "Translate down" }, { flatten_cb, "Decrease rendering accuracy, (tolerance *= 10)" }, { smooth_cb, "Increase rendering accuracy, (tolerance /= 10)" }, { widen_line, "Widen line width" }, { narrow_line, "Narrow line width" }, }; static key_binding_t key_binding[] = { /* Keysym, Alias, Keycode, callback */ { "Q", 0, 0, quit_cb }, { "Left", 0, 0, trans_left_cb }, { "Right", 0, 0, trans_right_cb }, { "Up", 0, 0, trans_up_cb }, { "Down", 0, 0, trans_down_cb }, { "Return", 0, 0, print_spline_cb }, { "plus", 0, 0, zoom_in_cb }, { "equal", 1, 0, zoom_in_cb }, { "minus", 0, 0, zoom_out_cb }, { "greater",0, 0, smooth_cb }, { "period", 1, 0, smooth_cb }, { "less", 0, 0, flatten_cb }, { "comma", 1, 0, flatten_cb }, { "W", 0, 0, widen_line }, { "N", 0, 0, narrow_line }, }; int main(int argc, char *argv[]) { win_t win; Display *dpy = XOpenDisplay(0); if (dpy == NULL) { fprintf(stderr, "Failed to open display: %s\n", XDisplayName(0)); return 1; } win_init(&win, dpy); win_print_help(&win); win_handle_events(&win); win_deinit(&win); XCloseDisplay(dpy); return 0; } static void draw_control_line(cairo_t *cr, pt_t *a, pt_t *b, double width) { cairo_save(cr); cairo_set_source_rgb(cr, 0, 0, 1); cairo_set_line_width(cr, width); cairo_move_to(cr, a->x, a->y); cairo_line_to(cr, b->x, b->y); cairo_stroke(cr); cairo_restore(cr); } static void draw_spline(cairo_t *cr, win_t *win) { spline_t *spline = &win->spline; double zoom = win->zoom; double drag_user_x = win->drag_pt.x; double drag_user_y = win->drag_pt.y; int i; cairo_device_to_user (cr, &drag_user_x, &drag_user_y); cairo_save(cr); cairo_move_to(cr, spline->pt[0].x, spline->pt[0].y); cairo_curve_to(cr, spline->pt[1].x, spline->pt[1].y, spline->pt[2].x, spline->pt[2].y, spline->pt[3].x, spline->pt[3].y); if (win->click && cairo_in_stroke (cr, drag_user_x, drag_user_y)) { win->active = 0xf; } cairo_stroke(cr); draw_control_line(cr, &spline->pt[0], &spline->pt[1], 2.0 / zoom); draw_control_line(cr, &spline->pt[3], &spline->pt[2], 2.0 / zoom); for (i=0; i < 4; i++) { cairo_save(cr); cairo_set_source_rgba (cr, 1, 0, 0, 0.5); cairo_new_path (cr); cairo_arc (cr, spline->pt[i].x, spline->pt[i].y, win->line_width / 1.25, 0, 2 * M_PI); if (win->click && cairo_in_fill (cr, drag_user_x, drag_user_y)) { win->active = (1<click = 0; } cairo_fill (cr); cairo_restore(cr); } cairo_restore(cr); } static void win_refresh(win_t *win) { Display *dpy = win->dpy; cairo_surface_t *surface; cairo_t *cr; cairo_status_t status; XFillRectangle(dpy, win->pix, win->gc, 0, 0, win->width, win->height); surface = cairo_xlib_surface_create (dpy, win->pix, DefaultVisual (dpy, win->scr), win->width, win->height); cr = cairo_create(surface); cairo_set_source_rgb(cr, 0, 0, 0); cairo_set_line_width(cr, win->line_width); cairo_set_line_cap(cr, win->line_cap); cairo_translate(cr, win->xtrans, win->ytrans); cairo_scale(cr, win->zoom, win->zoom); cairo_set_tolerance(cr, win->tolerance); draw_spline(cr, win); status = cairo_status(cr); if (status) { fprintf(stderr, "Cairo is unhappy: %s\n", cairo_status_to_string(status)); } cairo_destroy(cr); cairo_surface_destroy (surface); XCopyArea(win->dpy, win->pix, win->win, win->gc, 0, 0, win->width, win->height, 0, 0); } static void win_init(win_t *win, Display *dpy) { int i; Window root; XGCValues gcv; win->dpy = dpy; win->width = 400; win->height = 400; root = DefaultRootWindow(dpy); win->scr = DefaultScreen(dpy); win->win = XCreateSimpleWindow(dpy, root, 0, 0, win->width, win->height, 0, WhitePixel(dpy, win->scr), WhitePixel(dpy, win->scr)); win->pix = XCreatePixmap(dpy, win->win, win->width, win->height, DefaultDepth (dpy, win->scr)); gcv.foreground = WhitePixel(dpy, win->scr); win->gc = XCreateGC(dpy, win->pix, GCForeground, &gcv); XFillRectangle(dpy, win->pix, win->gc, 0, 0, win->width, win->height); for (i=0; i < ARRAY_SIZE(key_binding); i++) { KeySym keysym; keysym = XStringToKeysym(key_binding[i].key); if (keysym == NoSymbol) fprintf(stderr, "ERROR: No keysym for \"%s\"\n", key_binding[i].key); else key_binding[i].keycode = XKeysymToKeycode(dpy, keysym); } win->active = 0; win->spline = DEFAULT_SPLINE; win->tolerance = DEFAULT_TOLERANCE; win->line_width = DEFAULT_LINE_WIDTH; win->line_cap = DEFAULT_LINE_CAP; win->zoom = DEFAULT_ZOOM; win->xtrans = DEFAULT_XTRANS; win->ytrans = DEFAULT_YTRANS; win->click = 0; win->drag_pt.x = 0.0; win->drag_pt.y = 0.0; win_refresh(win); win->needs_refresh = 0; win_select_events(win); XMapWindow(dpy, win->win); } static void win_deinit(win_t *win) { XFreeGC(win->dpy, win->gc); XFreePixmap(win->dpy, win->pix); XDestroyWindow(win->dpy, win->win); } static void win_select_events(win_t *win) { win->event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | StructureNotifyMask | ExposureMask; XSelectInput(win->dpy, win->win, win->event_mask); } static char * get_callback_doc(void *callback) { int i; for (i=0; i < ARRAY_SIZE(callback_doc); i++) if (callback_doc[i].callback == callback) return callback_doc[i].doc; return ""; } static void win_print_help(win_t *win) { int i; printf("A cairo spline demonstration\n"); printf("Click and drag to move the spline or adjust its controls. Or:\n\n"); for (i=0; i < ARRAY_SIZE(key_binding); i++) if (! key_binding[i].is_alias) printf("%s:\t%s\n", key_binding[i].key, get_callback_doc(key_binding[i].callback)); } static void win_handle_button_press(win_t *win, XButtonEvent *bev) { win->click = 1; win->drag_pt.x = bev->x; win->drag_pt.y = bev->y; win->needs_refresh = 1; } static void win_handle_motion(win_t *win, XMotionEvent *mev) { int i; if (win->active == 0) return; for (i = 0; i < 4; i++) { if (((1<active) == 0) continue; win->spline.pt[i].x += (mev->x - win->drag_pt.x) / win->zoom; win->spline.pt[i].y += (mev->y - win->drag_pt.y) / win->zoom; win->needs_refresh = 1; } win->drag_pt.x = mev->x; win->drag_pt.y = mev->y; } static int win_handle_key_press(win_t *win, XKeyEvent *kev) { int i; for (i=0; i < ARRAY_SIZE(key_binding); i++) if (key_binding[i].keycode == kev->keycode) return (key_binding[i].callback)(win); return 0; } static void win_grow_pixmap(win_t *win) { Pixmap new; new = XCreatePixmap(win->dpy, win->win, win->width, win->height, DefaultDepth (win->dpy, win->scr)); XFillRectangle(win->dpy, new, win->gc, 0, 0, win->width, win->height); XCopyArea(win->dpy, win->pix, new, win->gc, 0, 0, win->width, win->height, 0, 0); XFreePixmap(win->dpy, win->pix); win->pix = new; win->needs_refresh = 1; } static void win_handle_configure(win_t *win, XConfigureEvent *cev) { int has_grown = 0; if (cev->width > win->width || cev->height > win->height) { has_grown = 1; } win->width = cev->width; win->height = cev->height; if (has_grown) { win_grow_pixmap(win); } } static void win_handle_expose(win_t *win, XExposeEvent *eev) { XCopyArea(win->dpy, win->pix, win->win, win->gc, eev->x, eev->y, eev->width, eev->height, eev->x, eev->y); } static void win_handle_events(win_t *win) { int done; XEvent xev; while (1) { if (!XPending(win->dpy) && win->needs_refresh) { win_refresh(win); win->needs_refresh = 0; } XNextEvent(win->dpy, &xev); switch(xev.type) { case ButtonPress: win_handle_button_press(win, &xev.xbutton); break; case MotionNotify: win_handle_motion(win, &xev.xmotion); break; case ButtonRelease: win->click = 0; win->active = 0; break; case KeyPress: done = win_handle_key_press(win, &xev.xkey); if (done) return; break; case ConfigureNotify: win_handle_configure(win, &xev.xconfigure); break; case Expose: win_handle_expose(win, &xev.xexpose); break; } } } /* Callbacks */ static int quit_cb(win_t *win) { return 1; } static int print_spline_cb(win_t *win) { pt_t *pt = win->spline.pt; printf("{ { %.20g, %.20g }, { %.20g, %.20g }, { %.20g, %.20g }, { %.20g, %.20g } }\n", pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x, pt[2].y, pt[3].x, pt[3].y); return 0; } static int zoom_in_cb(win_t *win) { win->zoom *= 1.1; win->needs_refresh = 1; return 0; } static int trans_left_cb(win_t *win) { win->xtrans -= win->width / 16.0; win->needs_refresh = 1; return 0; } static int trans_right_cb(win_t *win) { win->xtrans += win->width / 16.0; win->needs_refresh = 1; return 0; } static int trans_up_cb(win_t *win) { win->ytrans -= win->height / 16.0; win->needs_refresh = 1; return 0; } static int trans_down_cb(win_t *win) { win->ytrans += win->height / 16.0; win->needs_refresh = 1; return 0; } static int zoom_out_cb(win_t *win) { win->zoom /= 1.1; win->needs_refresh = 1; return 0; } static int flatten_cb(win_t *win) { win->tolerance *= 10; win->needs_refresh = 1; return 0; } static int smooth_cb(win_t *win) { win->tolerance /= 10; win->needs_refresh = 1; return 0; } static int widen_line(win_t *win) { win->line_width *= 2; win->needs_refresh = 1; return 0; } static int narrow_line(win_t *win) { win->line_width /= 2; win->needs_refresh = 1; return 0; } @ 1.13 log @ * cairo-demo-xcb.c: (win_draw): * cairo-demo.c: (win_draw): * cairo-knockout.c: (main): * cairo-spline.c: (win_refresh): Update for yet more cairo API changes. @ text @d256 2 a257 1 fprintf(stderr, "Cairo is unhappy: %s\n", cairo_status_string(cr)); @ 1.12 log @ * .cvsignore: * Makefile: * cairo-demo-xcb.c: Split XCB stuff out out cairo-demo and into its own cairo-demo-xcb. * cairo-demo.c: * cairo-demo-xcb.c: * cairo-knockout.c: * cairo-spline.c: Update all X11 demos to latest cairo API changes. @ text @d239 3 a241 3 surface = cairo_xlib_surface_create_for_pixmap_with_visual (dpy, win->pix, DefaultVisual (dpy, win->scr)); @ 1.11 log @initializing data to silence valgrind @ text @d168 1 a168 1 cairo_set_rgb_color(cr, 0, 0, 1); d188 1 a188 1 cairo_inverse_transform_point (cr, &drag_user_x, &drag_user_y); d210 1 a210 3 cairo_set_rgb_color(cr, 1, 0, 0); cairo_set_alpha (cr, 0.5); d233 1 a235 1 Drawable drawable = win->pix; d239 4 a242 3 cr = cairo_create(); cairo_set_target_drawable (cr, dpy, drawable); d244 1 a244 1 cairo_set_rgb_color(cr, 0, 0, 0); d260 1 @ 1.10 log @ * cairo-spline.c: * cairo-knockout.c: * cairo-demo.c: Track split-up of cairo.h. @ text @d309 2 @ 1.9 log @ * cairo-spline.c (win_grow_pixmap): Don't refresh immediately. Just schedule for later when idle. @ text @d7 1 @ 1.8 log @replacing ct with cr @ text @d419 1 a419 1 win_refresh(win); @ 1.7 log @ * cairo-spline.c: cairo-knockout.c, cairo-demo.c: Remove cairo-xlib.h, no longer needed. @ text @d163 1 a163 1 draw_control_line(cairo_t *ct, pt_t *a, pt_t *b, double width) d165 1 a165 1 cairo_save(ct); d167 2 a168 2 cairo_set_rgb_color(ct, 0, 0, 1); cairo_set_line_width(ct, width); d170 3 a172 3 cairo_move_to(ct, a->x, a->y); cairo_line_to(ct, b->x, b->y); cairo_stroke(ct); d174 1 a174 1 cairo_restore(ct); d178 1 a178 1 draw_spline(cairo_t *ct, win_t *win) d187 1 a187 1 cairo_inverse_transform_point (ct, &drag_user_x, &drag_user_y); d189 1 a189 1 cairo_save(ct); d191 2 a192 2 cairo_move_to(ct, spline->pt[0].x, spline->pt[0].y); cairo_curve_to(ct, d197 1 a197 1 if (win->click && cairo_in_stroke (ct, drag_user_x, drag_user_y)) { d201 1 a201 1 cairo_stroke(ct); d203 2 a204 2 draw_control_line(ct, &spline->pt[0], &spline->pt[1], 2.0 / zoom); draw_control_line(ct, &spline->pt[3], &spline->pt[2], 2.0 / zoom); d207 1 a207 1 cairo_save(ct); d209 1 a209 1 cairo_set_rgb_color(ct, 1, 0, 0); d211 1 a211 1 cairo_set_alpha (ct, 0.5); d213 2 a214 2 cairo_new_path (ct); cairo_arc (ct, d217 1 a217 1 if (win->click && cairo_in_fill (ct, drag_user_x, drag_user_y)) { d221 1 a221 1 cairo_fill (ct); d223 1 a223 1 cairo_restore(ct); d226 1 a226 1 cairo_restore(ct); d234 1 a234 1 cairo_t *ct; d240 1 a240 1 ct = cairo_create(); d242 1 a242 1 cairo_set_target_drawable (ct, dpy, drawable); d244 1 a244 1 cairo_set_rgb_color(ct, 0, 0, 0); d246 5 a250 5 cairo_set_line_width(ct, win->line_width); cairo_set_line_cap(ct, win->line_cap); cairo_translate(ct, win->xtrans, win->ytrans); cairo_scale(ct, win->zoom, win->zoom); cairo_set_tolerance(ct, win->tolerance); d252 1 a252 1 draw_spline(ct, win); d254 1 a254 1 status = cairo_status(ct); d256 1 a256 1 fprintf(stderr, "Cairo is unhappy: %s\n", cairo_status_string(ct)); d259 1 a259 1 cairo_destroy(ct); @ 1.6 log @ * cairo-spline.c: Added code to demonstrate use of cairo_in_stroke and cairo_in_fill. Various code cleanups. * Makefile (PROGS): Remove cairo-freq which wasn't adding anything. @ text @a6 1 #include @ 1.5 log @Fix old string referring to Xr @ text @a48 1 int show_path; d50 1 a50 1 int drag; a51 1 pt_t *active_pt; a69 8 typedef int (*button_callback_t)(win_t *win, int x, int y); typedef struct button_binding { int button; button_callback_t callback; } button_binding_t; a76 3 static int select_point_cb(win_t *win, int x, int y); static int snap_point_cb(win_t *win, int x, int y); a77 5 static int select_next_cb(win_t *win); static int left_epsilon_cb(win_t *win); static int right_epsilon_cb(win_t *win); static int up_epsilon_cb(win_t *win); static int down_epsilon_cb(win_t *win); a86 1 static int toggle_path(win_t *win); d94 1 d97 1 a97 36 /* This was breaking the polygon tessellation code. All fixed now. */ static const spline_t polygon_killer = { { { 613.125, 4643.06 }, { 21957.1, 3763.06 }, { 12906, 256 }, { 524, 8788 } } }; static const spline_t intersection_killer = { { { 244.56999999999999318, 268.56999999999993634 }, { 364.56000000000000227, 747.55999999999994543 }, { 34.380000000000002558, 412.56000000000000227 }, { 576.37000000000000455, 203.56999999999999318 } } }; /* #define DEFAULT_SPLINE intersection_killer #define DEFAULT_ZOOM 1.0 */ /* Showing off the problems with wide butt-capped splines that turn sharply at the end. */ static const spline_t funky_fangs = { { { 69.25, 48.185 }, { 40.225, 43.06 }, { 59.5, 34.5 }, { 59.4998, 35.2514 } } }; /* Adjust any point by an epsilon to see the fangs appear. (The fact that they are missing is a bug) -- Actually, it looks like this one is working now. */ static const spline_t touchy_fangs = { { { 18.25, 21.875 }, { 18.25, 23.875 }, { 30, 30.375 }, { 30, 27 } } }; /* Here's another one that starts off buggy, but small adjustments change it, (here you need to change a control point by a pixel or two in order to have an effect) */ static const spline_t touchy_shell = { { { 8.9375, 6.32812 }, { 8.23434, 10.3594 }, { 8.5625, 4.25 }, { 11.9531, 7.6875 } } }; /* A simple looping spline. No known problems. */ a101 81 static const spline_t simple = { { {10, 10}, {70, 10}, {100, 40}, {100, 100} } }; /* This one's fixed with some proper sorting/duplicate elimination on the pen */ static const spline_t non_uniform_width = { { { 18, 12 }, { 18.0001373291015625, 30.26085662841796875 }, { 99.9996185302734375, 48.72466278076171875 }, { 100, 100 } } }; /* This one shows why my incremental trapexoid generation scheme was flawed */ static const spline_t warts = { { { 14.75, 25.25 }, { 30.5001373291015625, 57.76085662841796875 }, { 127.4996185302734375, -17.77533721923828125 }, { 61.75, 33.75 } } }; /* This one is designed to torture ghostscript */ static const spline_t gstorture = { {{51.57, 51.57}, {412.56, 412.56}, {34.38, 412.56}, {395.37, 51.57}} }; /* #define DEFAULT_SPLINE gstorture #define DEFAULT_ZOOM 1.0 */ /* #define DEFAULT_SPLINE simple #define DEFAULT_ZOOM 1.0 */ /* This was causing an infitie loop at one point. The bug is now fixed, (the while loop no longer exists) */ static const spline_t infinite_loop = { { {32 * 4008192 / 65536.0, 32 * 10819706 / 65536.0}, {32 * 44968140 / 65536.0, 32 * 7706746 / 65536.0}, {32 * 26431488 / 65536.0, 32 * 524288 / 65536.0}, {32 * 1073152 / 65536.0, 32 * 17997824 / 65536.0} } }; /* This one shows a tiny sub-pixel trapezoid that was being rasterized with a fully-lit pixel. The fix for this has now been applied to the trap code in the server. */ static const spline_t wart = { { { 179, 410 }, { 448, 475 }, { 33, 514 }, { 313, 399 } } }; /* A new wart, (right on the tip of the spike). I haven't chased this one down yet. */ static const spline_t another_wart = { { { 37.5, 22.125 }, { 40.875, 23.625 }, { 13.375, 57 }, { 34.25, 35.375 } } }; /* What happens when the spline folds over on itself at the end? */ static const spline_t overlap = { { { 3.03125, 5.1875 }, { 12.25, 11.1875 }, { 15.1875, 7.375 }, { 14.25, 7.45312 } } }; /* #define DEFAULT_SPLINE funky_fangs #define DEFAULT_ZOOM 8.0 */ /* #define DEFAULT_SPLINE touchy_fangs #define DEFAULT_ZOOM 8.0 */ /* #define DEFAULT_SPLINE touchy_shell #define DEFAULT_ZOOM 16.0 */ /* #define DEFAULT_SPLINE polygon_killer #define DEFAULT_ZOOM (1 / 32.0) */ /* #define DEFAULT_SPLINE infinite_loop #define DEFAULT_ZOOM 1 / 32.0 */ a102 18 #define DEFAULT_ZOOM 1.0 /* #define DEFAULT_SPLINE wart #define DEFAULT_ZOOM 1.0 */ /* #define DEFAULT_SPLINE another_wart #define DEFAULT_ZOOM 8.0 #define DEFAULT_WIDTH 256 #define DEFAULT_TOLERANCE .001 */ /* #define DEFAULT_SPLINE overlap #define DEFAULT_ZOOM 64 */ a105 7 { select_point_cb, "Activate closest control point" }, { select_next_cb, "Activate next control point" }, { snap_point_cb, "Snap active point to closest control point" }, { left_epsilon_cb, "Move active point left by an epsilon" }, { right_epsilon_cb, "Move active point right by an epsilon" }, { up_epsilon_cb, "Move active point up by an epsilon" }, { down_epsilon_cb, "Move active point down by an epsilon" }, d107 6 a112 6 { zoom_in_cb, "Zoom in (2X)" }, { zoom_out_cb, "Zoom out (2X)" }, { trans_left_cb, "Translate left (25%)" }, { trans_right_cb, "Translate right (25%)" }, { trans_up_cb, "Translate up (25%)" }, { trans_down_cb, "Translate down (25%)" }, a114 1 { toggle_path, "Toggle thin display of spline path" }, d122 4 a125 4 { "Left", 0, 0, left_epsilon_cb }, { "Right", 0, 0, right_epsilon_cb }, { "Up", 0, 0, up_epsilon_cb }, { "Down", 0, 0, down_epsilon_cb }, a126 1 { "space", 0, 0, select_next_cb }, a133 1 { "P", 0, 0, toggle_path }, a137 5 static const button_binding_t button_binding[] = { { 1, select_point_cb }, { 3, snap_point_cb } }; a178 22 draw_handle(cairo_t *ct, pt_t *p, int is_active, double size, double width) { cairo_save(ct); if (is_active) cairo_set_rgb_color(ct, 0, 1, 0); else cairo_set_rgb_color(ct, 1, 0, 0); cairo_set_line_width(ct, width); cairo_move_to(ct, p->x - size / 2.0, p->y - size / 2.0); cairo_rel_line_to(ct, size, 0); cairo_rel_line_to(ct, 0, size); cairo_rel_line_to(ct, -size, 0); cairo_rel_line_to(ct, 0, -size); cairo_stroke(ct); cairo_restore(ct); } static void d183 2 d188 2 a196 1 cairo_stroke(ct); d198 2 a199 9 if (win->show_path) { cairo_set_line_width(ct, 1 / zoom); cairo_set_rgb_color(ct, 1, 1, 1); cairo_move_to(ct, spline->pt[0].x, spline->pt[0].y); cairo_curve_to(ct, spline->pt[1].x, spline->pt[1].y, spline->pt[2].x, spline->pt[2].y, spline->pt[3].x, spline->pt[3].y); cairo_stroke(ct); d202 2 d208 17 a224 1 draw_handle(ct, &spline->pt[i], i == win->active, 5.0 / zoom, 1.0 / zoom); a242 5 /* if (win->restrict_traps) cairo_restrict_spline_traps(ct, win->trap_start, win->trap_stop); */ a299 1 win->active_pt = &win->spline.pt[win->active]; d308 1 a308 3 win->show_path = 1; win->drag = 0; d357 2 a358 9 printf("Cairo spline demonstration\n"); printf("Click and drag to move spline endpoints and control points, or:\n\n"); for (i=0; i < ARRAY_SIZE(button_binding); i++) printf("Button %d:\t%s\n", button_binding[i].button, get_callback_doc(button_binding[i].callback)); printf("\n"); d367 2 a368 2 static double distance_sq(pt_t *a, pt_t *b) d370 5 a374 4 double dx = b->x - a->x; double dy = b->y - a->y; return dx*dx + dy*dy; d377 2 a378 2 static int win_handle_button_press(win_t *win, XButtonEvent *bev) d382 2 a383 3 for (i=0; i < ARRAY_SIZE(button_binding); i++) if (button_binding[i].button == bev->button) return (button_binding[i].callback)(win, bev->x, bev->y); d385 5 a389 2 return 0; } a390 7 static void win_handle_motion(win_t *win, XMotionEvent *mev) { if (win->drag) { win->active_pt->x += (mev->x - win->drag_pt.x) / win->zoom; win->active_pt->y += (mev->y - win->drag_pt.y) / win->zoom; a391 3 win->drag_pt.x = mev->x; win->drag_pt.y = mev->y; d393 3 d471 2 a472 1 win->drag = 0; a491 47 /* nearest control point in spline to given point */ static int find_nearest(spline_t *spline, double x, double y) { int i, nearest; double dist, min_dist; pt_t pt; pt.x = x; pt.y = y; for (i=0; i<4; i++) { dist = distance_sq(&spline->pt[i], &pt); if (i==0 || dist < min_dist) { nearest = i; min_dist = dist; } } return nearest; } static int select_point_cb(win_t *win, int x, int y) { win->drag = 1; win->drag_pt.x = x; win->drag_pt.y = y; win->active = find_nearest(&win->spline, x / win->zoom, y / win->zoom); win->active_pt = &win->spline.pt[win->active]; win->needs_refresh = 1; return 0; } static int snap_point_cb(win_t *win, int x, int y) { *win->active_pt = win->spline.pt[find_nearest(&win->spline, x / win->zoom, y / win->zoom)]; win->needs_refresh = 1; return 0; } a498 51 select_next_cb(win_t *win) { win->active = (win->active + 1) % 4; win->active_pt = &win->spline.pt[win->active]; win->needs_refresh = 1; return 0; } static int left_epsilon_cb(win_t *win) { win->active_pt->x -= EPSILON; win->needs_refresh = 1; return 0; } static int right_epsilon_cb(win_t *win) { win->active_pt->x += EPSILON; win->needs_refresh = 1; return 0; } static int up_epsilon_cb(win_t *win) { win->active_pt->y -= EPSILON; win->needs_refresh = 1; return 0; } static int down_epsilon_cb(win_t *win) { win->active_pt->y += EPSILON; win->needs_refresh = 1; return 0; } static int d515 1 a515 1 win->zoom *= 2.0; d525 1 a525 1 win->xtrans -= win->width / 4.0; d535 1 a535 1 win->xtrans += win->width / 4.0; d545 1 a545 1 win->ytrans -= win->height / 4.0; d555 1 a555 1 win->ytrans += win->height / 4.0; d565 1 a565 1 win->zoom /= 2.0; a592 10 toggle_path(win_t *win) { win->show_path = ! win->show_path; win->needs_refresh = 1; return 0; } static int @ 1.4 log @Added cairo-xlib.h include needed for new Cairo bits; added text demo to cairo-demo. @ text @d437 1 a437 1 fprintf(stderr, "Xr is unhappy: %s\n", cairo_status_string(ct)); d540 1 a540 1 printf("Xr spline demonstration\n"); @ 1.3 log @Fix uninitialized values @ text @d7 1 @ 1.2 log @Updated to track changes in Cairo API @ text @d485 3 @ 1.1 log @Added demos from OLS paper. @ text @d434 1 a434 1 status = cairo_get_status(ct); d436 1 a436 1 fprintf(stderr, "Xr is unhappy: %s\n", cairo_get_status_string(ct)); @