Code

Rename LPE: mirror reflect --> mirror symmetry
[inkscape.git] / src / display / sodipodi-ctrl.cpp
1 #define INKSCAPE_CTRL_C
3 /*
4  * SPCtrl
5  *
6  * We render it by hand to reduce allocing/freeing svps & to get clean
7  *    (non-aa) images
8  *
9  */
11 #include "sp-canvas-util.h"
12 #include "display-forward.h"
13 #include "sodipodi-ctrl.h"
15 enum {
16     ARG_0,
17     ARG_SHAPE,
18     ARG_MODE,
19     ARG_ANCHOR,
20     ARG_SIZE,
21     ARG_FILLED,
22     ARG_FILL_COLOR,
23     ARG_STROKED,
24     ARG_STROKE_COLOR,
25     ARG_PIXBUF
26 };
29 static void sp_ctrl_class_init (SPCtrlClass *klass);
30 static void sp_ctrl_init (SPCtrl *ctrl);
31 static void sp_ctrl_destroy (GtkObject *object);
32 static void sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
34 static void sp_ctrl_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
35 static void sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf);
37 static double sp_ctrl_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item);
40 static SPCanvasItemClass *parent_class;
42 GtkType
43 sp_ctrl_get_type (void)
44 {
45     static GtkType ctrl_type = 0;
46     if (!ctrl_type) {
47         static GTypeInfo const ctrl_info = {
48             sizeof (SPCtrlClass),
49             NULL,   /* base_init */
50             NULL,   /* base_finalize */
51             (GClassInitFunc) sp_ctrl_class_init,
52             NULL,   /* class_finalize */
53             NULL,   /* class_data */
54             sizeof (SPCtrl),
55             0,   /* n_preallocs */
56             (GInstanceInitFunc) sp_ctrl_init,
57             NULL
58         };
59         ctrl_type = g_type_register_static (SP_TYPE_CANVAS_ITEM, "SPCtrl", &ctrl_info, (GTypeFlags)0);
60     }
61     return ctrl_type;
62 }
64 static void
65 sp_ctrl_class_init (SPCtrlClass *klass)
66 {
67     GtkObjectClass *object_class;
68     SPCanvasItemClass *item_class;
70     object_class = (GtkObjectClass *) klass;
71     item_class = (SPCanvasItemClass *) klass;
73     parent_class = (SPCanvasItemClass *)gtk_type_class (sp_canvas_item_get_type ());
75     gtk_object_add_arg_type ("SPCtrl::shape", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_SHAPE);
76     gtk_object_add_arg_type ("SPCtrl::mode", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_MODE);
77     gtk_object_add_arg_type ("SPCtrl::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR);
78     gtk_object_add_arg_type ("SPCtrl::size", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_SIZE);
79     gtk_object_add_arg_type ("SPCtrl::pixbuf", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PIXBUF);
80     gtk_object_add_arg_type ("SPCtrl::filled", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_FILLED);
81     gtk_object_add_arg_type ("SPCtrl::fill_color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_FILL_COLOR);
82     gtk_object_add_arg_type ("SPCtrl::stroked", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_STROKED);
83     gtk_object_add_arg_type ("SPCtrl::stroke_color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_STROKE_COLOR);
85     object_class->destroy = sp_ctrl_destroy;
86     object_class->set_arg = sp_ctrl_set_arg;
88     item_class->update = sp_ctrl_update;
89     item_class->render = sp_ctrl_render;
90     item_class->point = sp_ctrl_point;
91 }
93 static void
94 sp_ctrl_init (SPCtrl *ctrl)
95 {
96     ctrl->shape = SP_CTRL_SHAPE_SQUARE;
97     ctrl->mode = SP_CTRL_MODE_COLOR;
98     ctrl->anchor = GTK_ANCHOR_CENTER;
99     ctrl->span = 3;
100     ctrl->defined = TRUE;
101     ctrl->shown = FALSE;
102     ctrl->build = FALSE;
103     ctrl->filled = 1;
104     ctrl->stroked = 0;
105     ctrl->fill_color = 0x000000ff;
106     ctrl->stroke_color = 0x000000ff;
107     ctrl->_moved = false;
109     ctrl->box.x0 = ctrl->box.y0 = ctrl->box.x1 = ctrl->box.y1 = 0;
110     ctrl->cache = NULL;
111     ctrl->pixbuf = NULL;
114 static void
115 sp_ctrl_destroy (GtkObject *object)
117     SPCtrl *ctrl;
119     g_return_if_fail (object != NULL);
120     g_return_if_fail (SP_IS_CTRL (object));
122     ctrl = SP_CTRL (object);
124     if (GTK_OBJECT_CLASS (parent_class)->destroy)
125         (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
128 static void
129 sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
131     SPCanvasItem *item;
132     SPCtrl *ctrl;
133     GdkPixbuf * pixbuf = NULL;
135     item = SP_CANVAS_ITEM (object);
136     ctrl = SP_CTRL (object);
138     switch (arg_id) {
139         case ARG_SHAPE:
140             ctrl->shape = (SPCtrlShapeType)(GTK_VALUE_INT (*arg));
141             ctrl->build = FALSE;
142             sp_canvas_item_request_update (item);
143             break;
145         case ARG_MODE:
146             ctrl->mode = (SPCtrlModeType)(GTK_VALUE_INT (*arg));
147             ctrl->build = FALSE;
148             sp_canvas_item_request_update (item);
149             break;
151         case ARG_ANCHOR:
152             ctrl->anchor = (GtkAnchorType)(GTK_VALUE_INT (*arg));
153             ctrl->build = FALSE;
154             sp_canvas_item_request_update (item);
155             break;
157         case ARG_SIZE:
158             ctrl->span = (gint) ((GTK_VALUE_DOUBLE (*arg) - 1.0) / 2.0 + 0.5);
159             ctrl->defined = (ctrl->span > 0);
160             ctrl->build = FALSE;
161             sp_canvas_item_request_update (item);
162             break;
164         case ARG_FILLED:
165             ctrl->filled = GTK_VALUE_BOOL (*arg);
166             ctrl->build = FALSE;
167             sp_canvas_item_request_update (item);
168             break;
170         case ARG_FILL_COLOR:
171             ctrl->fill_color = GTK_VALUE_INT (*arg);
172             ctrl->build = FALSE;
173             sp_canvas_item_request_update (item);
174             break;
176         case ARG_STROKED:
177             ctrl->stroked = GTK_VALUE_BOOL (*arg);
178             ctrl->build = FALSE;
179             sp_canvas_item_request_update (item);
180             break;
182         case ARG_STROKE_COLOR:
183             ctrl->stroke_color = GTK_VALUE_INT (*arg);
184             ctrl->build = FALSE;
185             sp_canvas_item_request_update (item);
186             break;
188         case ARG_PIXBUF:
189             pixbuf  = (GdkPixbuf*)(GTK_VALUE_POINTER (*arg));
190             if (gdk_pixbuf_get_has_alpha (pixbuf)) {
191                 ctrl->pixbuf = pixbuf;
192             } else {
193                 ctrl->pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
194                 gdk_pixbuf_unref (pixbuf);
195             }
196             ctrl->build = FALSE;
197             break;
199         default:
200             break;
201     }
204 static void
205 sp_ctrl_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
207     SPCtrl *ctrl;
208     gint x, y;
210     ctrl = SP_CTRL (item);
212     if (((SPCanvasItemClass *) parent_class)->update)
213         (* ((SPCanvasItemClass *) parent_class)->update) (item, affine, flags);
215     sp_canvas_item_reset_bounds (item);
217     if (!ctrl->_moved) return;
219     if (ctrl->shown) {
220         sp_canvas_request_redraw (item->canvas, ctrl->box.x0, ctrl->box.y0, ctrl->box.x1 + 1, ctrl->box.y1 + 1);
221     }
223     if (!ctrl->defined) return;
225     x = (gint) ((affine[4] > 0) ? (affine[4] + 0.5) : (affine[4] - 0.5)) - ctrl->span;
226     y = (gint) ((affine[5] > 0) ? (affine[5] + 0.5) : (affine[5] - 0.5)) - ctrl->span;
228     switch (ctrl->anchor) {
229         case GTK_ANCHOR_N:
230         case GTK_ANCHOR_CENTER:
231         case GTK_ANCHOR_S:
232             break;
234         case GTK_ANCHOR_NW:
235         case GTK_ANCHOR_W:
236         case GTK_ANCHOR_SW:
237             x += ctrl->span;
238             break;
240         case GTK_ANCHOR_NE:
241         case GTK_ANCHOR_E:
242         case GTK_ANCHOR_SE:
243             x -= (ctrl->span + 1);
244             break;
245     }
247     switch (ctrl->anchor) {
248         case GTK_ANCHOR_W:
249         case GTK_ANCHOR_CENTER:
250         case GTK_ANCHOR_E:
251             break;
253         case GTK_ANCHOR_NW:
254         case GTK_ANCHOR_N:
255         case GTK_ANCHOR_NE:
256             y += ctrl->span;
257             break;
259         case GTK_ANCHOR_SW:
260         case GTK_ANCHOR_S:
261         case GTK_ANCHOR_SE:
262             y -= (ctrl->span + 1);
263             break;
264     }
266     ctrl->box.x0 = x;
267     ctrl->box.y0 = y;
268     ctrl->box.x1 = ctrl->box.x0 + 2 * ctrl->span;
269     ctrl->box.y1 = ctrl->box.y0 + 2 * ctrl->span;
271     sp_canvas_update_bbox (item, ctrl->box.x0, ctrl->box.y0, ctrl->box.x1 + 1, ctrl->box.y1 + 1);
274 static double
275 sp_ctrl_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item)
277     SPCtrl *ctrl = SP_CTRL (item);
279     *actual_item = item;
281     double const x = p[NR::X];
282     double const y = p[NR::Y];
284     if ((x >= ctrl->box.x0) && (x <= ctrl->box.x1) && (y >= ctrl->box.y0) && (y <= ctrl->box.y1)) return 0.0;
286     return 1e18;
289 static void
290 sp_ctrl_build_cache (SPCtrl *ctrl)
292     guchar * p, *q;
293     gint size, x, y, z, s, a, side, c;
294     guint8 fr, fg, fb, fa, sr, sg, sb, sa;
296     if (ctrl->filled) {
297         fr = (ctrl->fill_color >> 24) & 0xff;
298         fg = (ctrl->fill_color >> 16) & 0xff;
299         fb = (ctrl->fill_color >> 8) & 0xff;
300         fa = (ctrl->fill_color) & 0xff;
301     } else {
302         fr = 0x00; fg = 0x00; fb = 0x00; fa = 0x00;
303     }
304     if (ctrl->stroked) {
305         sr = (ctrl->stroke_color >> 24) & 0xff;
306         sg = (ctrl->stroke_color >> 16) & 0xff;
307         sb = (ctrl->stroke_color >> 8) & 0xff;
308         sa = (ctrl->stroke_color) & 0xff;
309     } else {
310         sr = fr; sg = fg; sb = fb; sa = fa;
311     }
314     side = (ctrl->span * 2 +1);
315     c = ctrl->span ;
316     g_free (ctrl->cache);
317     size = (side) * (side) * 4;
318     ctrl->cache = (guchar*)g_malloc (size);
319     if (side < 2) return;
321     switch (ctrl->shape) {
322         case SP_CTRL_SHAPE_SQUARE:
323             p = ctrl->cache;
324             for (x=0; x < side; x++) {
325                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
326             }
327             for (y = 2; y < side; y++) {
328                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
329                 for (x=2; x < side; x++) {
330                     *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa;
331                 }
332                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
333             }
334             for (x=0; x < side; x++) {
335                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
336             }
337             ctrl->build = TRUE;
338             break;
340         case SP_CTRL_SHAPE_DIAMOND:
341             p = ctrl->cache;
342             for (y = 0; y < side; y++) {
343                 z = abs (c - y);
344                 for (x = 0; x < z; x++) {
345                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
346                 }
347                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
348                 for (; x < side - z -1; x++) {
349                     *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa;
350                 }
351                 if (z != c) {
352                     *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
353                 }
354                 for (; x < side; x++) {
355                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
356                 }
357             }
358             break;
360         case SP_CTRL_SHAPE_CIRCLE:
361             p = ctrl->cache;
362             q = p + size -1;
363             s = -1;
364             for (y = 0; y <= c ; y++) {
365                 a = abs (c - y);
366                 z = (gint)(0.0 + sqrt ((c+.4)*(c+.4) - a*a));
367                 x = 0;
368                 while (x < c-z) {
369                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
370                     *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00;
371                     x++;
372                 }
373                 do {
374                     *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
375                     *q-- = sa; *q-- = sb; *q-- = sg; *q-- = sr;
376                     x++;
377                 } while (x < c-s);
378                 while (x < MIN(c+s+1, c+z)) {
379                     *p++ = fr;   *p++ = fg;   *p++ = fb;   *p++ = fa;
380                     *q-- = fa;   *q-- = fb;   *q-- = fg;   *q-- = fr;
381                     x++;
382                 }
383                 do {
384                     *p++ = sr;   *p++ = sg;   *p++ = sb;   *p++ = sa;
385                     *q-- = sa; *q-- = sb; *q-- = sg; *q-- = sr;
386                     x++;
387                 } while (x <= c+z);
388                 while (x < side) {
389                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
390                     *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00;
391                     x++;
392                 }
393                 s = z;
394             }
395             ctrl->build = TRUE;
396             break;
398         case SP_CTRL_SHAPE_CROSS:
399             p = ctrl->cache;
400             for (y = 0; y < side; y++) {
401                 z = abs (c - y);
402                 for (x = 0; x < c-z; x++) {
403                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
404                 }
405                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
406                 for (; x < c + z; x++) {
407                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
408                 }
409                 if (z != 0) {
410                     *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
411                 }
412                 for (; x < side; x++) {
413                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
414                 }
415             }
416             ctrl->build = TRUE;
417             break;
419         case SP_CTRL_SHAPE_BITMAP:
420             if (ctrl->pixbuf) {
421                 unsigned char *px;
422                 unsigned int rs;
423                 px = gdk_pixbuf_get_pixels (ctrl->pixbuf);
424                 rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf);
425                 for (y = 0; y < side; y++){
426                     unsigned char *s, *d;
427                     s = px + y * rs;
428                     d = ctrl->cache + 4 * side * y;
429                     for (x = 0; x < side; x++) {
430                         if (s[3] < 0x80) {
431                             d[0] = 0x00;
432                             d[1] = 0x00;
433                             d[2] = 0x00;
434                             d[3] = 0x00;
435                         } else if (s[0] < 0x80) {
436                             d[0] = sr;
437                             d[1] = sg;
438                             d[2] = sb;
439                             d[3] = sa;
440                         } else {
441                             d[0] = fr;
442                             d[1] = fg;
443                             d[2] = fb;
444                             d[3] = fa;
445                         }
446                         s += 4;
447                         d += 4;
448                     }
449                 }
450             } else {
451                 g_print ("control has no pixmap\n");
452             }
453             ctrl->build = TRUE;
454             break;
456         case SP_CTRL_SHAPE_IMAGE:
457             if (ctrl->pixbuf) {
458                 guint r = gdk_pixbuf_get_rowstride (ctrl->pixbuf);
459                 guchar * pix;
460                 q = gdk_pixbuf_get_pixels (ctrl->pixbuf);
461                 p = ctrl->cache;
462                 for (y = 0; y < side; y++){
463                     pix = q + (y * r);
464                     for (x = 0; x < side; x++) {
465                         *p++ = *pix++;
466                         *p++ = *pix++;
467                         *p++ = *pix++;
468                         *p++ = *pix++;
469                     }
470                 }
471             } else {
472                 g_print ("control has no pixmap\n");
473             }
474             ctrl->build = TRUE;
475             break;
477         default:
478             break;
479     }
483 // composite background, foreground, alpha for xor mode
484 #define COMPOSE_X(b,f,a) ( ( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) ((b ^ ~f) + b/4 - (b>127? 63 : 0))) * ((guchar) a) ) / 0xff )
485 // composite background, foreground, alpha for color mode
486 #define COMPOSE_N(b,f,a) ( ( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) f) * ((guchar) a) ) / 0xff )
488 static void
489 sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf)
491     gint y0, y1, y, x0,x1,x;
492     guchar *p, *q, a;
494     SPCtrl *ctrl = SP_CTRL (item);
496     if (!ctrl->defined) return;
497     if ((!ctrl->filled) && (!ctrl->stroked)) return;
499     sp_canvas_prepare_buffer (buf);
501     // the control-image is rendered into ctrl->cache
502     if (!ctrl->build) {
503         sp_ctrl_build_cache (ctrl);
504     }
506     // then we render from ctrl->cache
507     y0 = MAX (ctrl->box.y0, buf->rect.y0);
508     y1 = MIN (ctrl->box.y1, buf->rect.y1 - 1);
509     x0 = MAX (ctrl->box.x0, buf->rect.x0);
510     x1 = MIN (ctrl->box.x1, buf->rect.x1 - 1);
512     bool colormode;
514     for (y = y0; y <= y1; y++) {
515         p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4;
516         q = ctrl->cache + ((y - ctrl->box.y0) * (ctrl->span*2+1) + (x0 - ctrl->box.x0)) * 4;
517         for (x = x0; x <= x1; x++) {
518             a = *(q + 3);
519             // 00000000 is the only way to get invisible; all other colors with alpha 00 are treated as mode_color with alpha ff
520             colormode = false;
521             if (a == 0x00 && !(q[0] == 0x00 && q[1] == 0x00 && q[2] == 0x00)) {
522                 a = 0xff;
523                 colormode = true;
524             }
525             if (ctrl->mode == SP_CTRL_MODE_COLOR || colormode) {
526                 p[0] = COMPOSE_N (p[0], q[0], a);
527                 p[1] = COMPOSE_N (p[1], q[1], a);
528                 p[2] = COMPOSE_N (p[2], q[2], a);
529                 q += 4;
530                 p += 4;
531             } else if (ctrl->mode == SP_CTRL_MODE_XOR) {
532                 p[0] = COMPOSE_X (p[0], q[0], a);
533                 p[1] = COMPOSE_X (p[1], q[1], a);
534                 p[2] = COMPOSE_X (p[2], q[2], a);
535                 q += 4;
536                 p += 4;
537             }
538         }
539     }
540     ctrl->shown = TRUE;
543 void SPCtrl::moveto (NR::Point const p) {
544     sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (this), NR::Matrix(NR::translate (p)));
545     _moved = true;
549 /*
550   Local Variables:
551   mode:c++
552   c-file-style:"stroustrup"
553   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
554   indent-tabs-mode:nil
555   fill-column:99
556   End:
557 */
558 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :