Code

Split SPCanvasItem and SPCanvasGroup to individual .h files. Removed forward header.
[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 <2geom/transforms.h>
12 #include "sp-canvas-util.h"
13 #include "sodipodi-ctrl.h"
14 #include "libnr/nr-pixops.h"
16 enum {
17     ARG_0,
18     ARG_SHAPE,
19     ARG_MODE,
20     ARG_ANCHOR,
21     ARG_SIZE,
22     ARG_FILLED,
23     ARG_FILL_COLOR,
24     ARG_STROKED,
25     ARG_STROKE_COLOR,
26     ARG_PIXBUF
27 };
30 static void sp_ctrl_class_init (SPCtrlClass *klass);
31 static void sp_ctrl_init (SPCtrl *ctrl);
32 static void sp_ctrl_destroy (GtkObject *object);
33 static void sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
35 static void sp_ctrl_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags);
36 static void sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf);
38 static double sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
41 static SPCanvasItemClass *parent_class;
43 GtkType
44 sp_ctrl_get_type (void)
45 {
46     static GtkType ctrl_type = 0;
47     if (!ctrl_type) {
48         static GTypeInfo const ctrl_info = {
49             sizeof (SPCtrlClass),
50             NULL,   /* base_init */
51             NULL,   /* base_finalize */
52             (GClassInitFunc) sp_ctrl_class_init,
53             NULL,   /* class_finalize */
54             NULL,   /* class_data */
55             sizeof (SPCtrl),
56             0,   /* n_preallocs */
57             (GInstanceInitFunc) sp_ctrl_init,
58             NULL
59         };
60         ctrl_type = g_type_register_static (SP_TYPE_CANVAS_ITEM, "SPCtrl", &ctrl_info, (GTypeFlags)0);
61     }
62     return ctrl_type;
63 }
65 static void
66 sp_ctrl_class_init (SPCtrlClass *klass)
67 {
68     GtkObjectClass *object_class;
69     SPCanvasItemClass *item_class;
71     object_class = (GtkObjectClass *) klass;
72     item_class = (SPCanvasItemClass *) klass;
74     parent_class = (SPCanvasItemClass *)gtk_type_class (sp_canvas_item_get_type ());
76     gtk_object_add_arg_type ("SPCtrl::shape", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_SHAPE);
77     gtk_object_add_arg_type ("SPCtrl::mode", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_MODE);
78     gtk_object_add_arg_type ("SPCtrl::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR);
79     gtk_object_add_arg_type ("SPCtrl::size", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_SIZE);
80     gtk_object_add_arg_type ("SPCtrl::pixbuf", GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PIXBUF);
81     gtk_object_add_arg_type ("SPCtrl::filled", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_FILLED);
82     gtk_object_add_arg_type ("SPCtrl::fill_color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_FILL_COLOR);
83     gtk_object_add_arg_type ("SPCtrl::stroked", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_STROKED);
84     gtk_object_add_arg_type ("SPCtrl::stroke_color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_STROKE_COLOR);
86     object_class->destroy = sp_ctrl_destroy;
87     object_class->set_arg = sp_ctrl_set_arg;
89     item_class->update = sp_ctrl_update;
90     item_class->render = sp_ctrl_render;
91     item_class->point = sp_ctrl_point;
92 }
94 static void
95 sp_ctrl_init (SPCtrl *ctrl)
96 {
97     ctrl->shape = SP_CTRL_SHAPE_SQUARE;
98     ctrl->mode = SP_CTRL_MODE_COLOR;
99     ctrl->anchor = GTK_ANCHOR_CENTER;
100     ctrl->span = 3;
101     ctrl->defined = TRUE;
102     ctrl->shown = FALSE;
103     ctrl->build = FALSE;
104     ctrl->filled = 1;
105     ctrl->stroked = 0;
106     ctrl->fill_color = 0x000000ff;
107     ctrl->stroke_color = 0x000000ff;
108     ctrl->_moved = false;
110     ctrl->box.x0 = ctrl->box.y0 = ctrl->box.x1 = ctrl->box.y1 = 0;
111     ctrl->cache = NULL;
112     ctrl->pixbuf = NULL;
114     ctrl->_point = Geom::Point(0,0);
117 static void
118 sp_ctrl_destroy (GtkObject *object)
120     SPCtrl *ctrl;
122     g_return_if_fail (object != NULL);
123     g_return_if_fail (SP_IS_CTRL (object));
125     ctrl = SP_CTRL (object);
127     if (ctrl->cache) {
128         g_free(ctrl->cache);
129         ctrl->cache = NULL;
130     }
132     if (GTK_OBJECT_CLASS (parent_class)->destroy)
133         (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
136 static void
137 sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
139     SPCanvasItem *item;
140     SPCtrl *ctrl;
141     GdkPixbuf * pixbuf = NULL;
143     item = SP_CANVAS_ITEM (object);
144     ctrl = SP_CTRL (object);
146     switch (arg_id) {
147         case ARG_SHAPE:
148             ctrl->shape = (SPCtrlShapeType)(GTK_VALUE_INT (*arg));
149             ctrl->build = FALSE;
150             sp_canvas_item_request_update (item);
151             break;
153         case ARG_MODE:
154             ctrl->mode = (SPCtrlModeType)(GTK_VALUE_INT (*arg));
155             ctrl->build = FALSE;
156             sp_canvas_item_request_update (item);
157             break;
159         case ARG_ANCHOR:
160             ctrl->anchor = (GtkAnchorType)(GTK_VALUE_INT (*arg));
161             ctrl->build = FALSE;
162             sp_canvas_item_request_update (item);
163             break;
165         case ARG_SIZE:
166             ctrl->span = (gint) ((GTK_VALUE_DOUBLE (*arg) - 1.0) / 2.0 + 0.5);
167             ctrl->defined = (ctrl->span > 0);
168             ctrl->build = FALSE;
169             sp_canvas_item_request_update (item);
170             break;
172         case ARG_FILLED:
173             ctrl->filled = GTK_VALUE_BOOL (*arg);
174             ctrl->build = FALSE;
175             sp_canvas_item_request_update (item);
176             break;
178         case ARG_FILL_COLOR:
179             ctrl->fill_color = GTK_VALUE_INT (*arg);
180             ctrl->build = FALSE;
181             sp_canvas_item_request_update (item);
182             break;
184         case ARG_STROKED:
185             ctrl->stroked = GTK_VALUE_BOOL (*arg);
186             ctrl->build = FALSE;
187             sp_canvas_item_request_update (item);
188             break;
190         case ARG_STROKE_COLOR:
191             ctrl->stroke_color = GTK_VALUE_INT (*arg);
192             ctrl->build = FALSE;
193             sp_canvas_item_request_update (item);
194             break;
196         case ARG_PIXBUF:
197             pixbuf  = (GdkPixbuf*)(GTK_VALUE_POINTER (*arg));
198             if (gdk_pixbuf_get_has_alpha (pixbuf)) {
199                 ctrl->pixbuf = pixbuf;
200             } else {
201                 ctrl->pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
202                 gdk_pixbuf_unref (pixbuf);
203             }
204             ctrl->build = FALSE;
205             break;
207         default:
208             break;
209     }
212 static void
213 sp_ctrl_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags)
215     SPCtrl *ctrl;
216     gint x, y;
218     ctrl = SP_CTRL (item);
220     if (((SPCanvasItemClass *) parent_class)->update)
221         (* ((SPCanvasItemClass *) parent_class)->update) (item, affine, flags);
223     sp_canvas_item_reset_bounds (item);
225     if (!ctrl->_moved) return;
227     if (ctrl->shown) {
228         sp_canvas_request_redraw (item->canvas, ctrl->box.x0, ctrl->box.y0, ctrl->box.x1 + 1, ctrl->box.y1 + 1);
229     }
231     if (!ctrl->defined) return;
233     x = (gint) ((affine[4] > 0) ? (affine[4] + 0.5) : (affine[4] - 0.5)) - ctrl->span;
234     y = (gint) ((affine[5] > 0) ? (affine[5] + 0.5) : (affine[5] - 0.5)) - ctrl->span;
236     switch (ctrl->anchor) {
237         case GTK_ANCHOR_N:
238         case GTK_ANCHOR_CENTER:
239         case GTK_ANCHOR_S:
240             break;
242         case GTK_ANCHOR_NW:
243         case GTK_ANCHOR_W:
244         case GTK_ANCHOR_SW:
245             x += ctrl->span;
246             break;
248         case GTK_ANCHOR_NE:
249         case GTK_ANCHOR_E:
250         case GTK_ANCHOR_SE:
251             x -= (ctrl->span + 1);
252             break;
253     }
255     switch (ctrl->anchor) {
256         case GTK_ANCHOR_W:
257         case GTK_ANCHOR_CENTER:
258         case GTK_ANCHOR_E:
259             break;
261         case GTK_ANCHOR_NW:
262         case GTK_ANCHOR_N:
263         case GTK_ANCHOR_NE:
264             y += ctrl->span;
265             break;
267         case GTK_ANCHOR_SW:
268         case GTK_ANCHOR_S:
269         case GTK_ANCHOR_SE:
270             y -= (ctrl->span + 1);
271             break;
272     }
274     ctrl->box.x0 = x;
275     ctrl->box.y0 = y;
276     ctrl->box.x1 = ctrl->box.x0 + 2 * ctrl->span;
277     ctrl->box.y1 = ctrl->box.y0 + 2 * ctrl->span;
279     sp_canvas_update_bbox (item, ctrl->box.x0, ctrl->box.y0, ctrl->box.x1 + 1, ctrl->box.y1 + 1);
282 static double
283 sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item)
285     SPCtrl *ctrl = SP_CTRL (item);
287     *actual_item = item;
289     double const x = p[Geom::X];
290     double const y = p[Geom::Y];
292     if ((x >= ctrl->box.x0) && (x <= ctrl->box.x1) && (y >= ctrl->box.y0) && (y <= ctrl->box.y1)) return 0.0;
294     return 1e18;
297 static void
298 sp_ctrl_build_cache (SPCtrl *ctrl)
300     guchar * p, *q;
301     gint size, x, y, z, s, a, side, c;
302     guint8 fr, fg, fb, fa, sr, sg, sb, sa;
304     if (ctrl->filled) {
305         fr = (ctrl->fill_color >> 24) & 0xff;
306         fg = (ctrl->fill_color >> 16) & 0xff;
307         fb = (ctrl->fill_color >> 8) & 0xff;
308         fa = (ctrl->fill_color) & 0xff;
309     } else {
310         fr = 0x00; fg = 0x00; fb = 0x00; fa = 0x00;
311     }
312     if (ctrl->stroked) {
313         sr = (ctrl->stroke_color >> 24) & 0xff;
314         sg = (ctrl->stroke_color >> 16) & 0xff;
315         sb = (ctrl->stroke_color >> 8) & 0xff;
316         sa = (ctrl->stroke_color) & 0xff;
317     } else {
318         sr = fr; sg = fg; sb = fb; sa = fa;
319     }
322     side = (ctrl->span * 2 +1);
323     c = ctrl->span ;
324     size = (side) * (side) * 4;
325     if (side < 2) return;
327     if (ctrl->cache)
328         g_free (ctrl->cache);
329     ctrl->cache = (guchar*)g_malloc (size);
331     switch (ctrl->shape) {
332         case SP_CTRL_SHAPE_SQUARE:
333             p = ctrl->cache;
334             for (x=0; x < side; x++) {
335                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
336             }
337             for (y = 2; y < side; y++) {
338                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
339                 for (x=2; x < side; x++) {
340                     *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa;
341                 }
342                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
343             }
344             for (x=0; x < side; x++) {
345                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa;
346             }
347             ctrl->build = TRUE;
348             break;
350         case SP_CTRL_SHAPE_DIAMOND:
351             p = ctrl->cache;
352             for (y = 0; y < side; y++) {
353                 z = abs (c - y);
354                 for (x = 0; x < z; x++) {
355                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
356                 }
357                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
358                 for (; x < side - z -1; x++) {
359                     *p++ = fr; *p++ = fg; *p++ = fb; *p++ = fa;
360                 }
361                 if (z != c) {
362                     *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
363                 }
364                 for (; x < side; x++) {
365                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
366                 }
367             }
368             break;
370         case SP_CTRL_SHAPE_CIRCLE:
371             p = ctrl->cache;
372             q = p + size -1;
373             s = -1;
374             for (y = 0; y <= c ; y++) {
375                 a = abs (c - y);
376                 z = (gint)(0.0 + sqrt ((c+.4)*(c+.4) - a*a));
377                 x = 0;
378                 while (x < c-z) {
379                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
380                     *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00;
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-s);
388                 while (x < MIN(c+s+1, c+z)) {
389                     *p++ = fr;   *p++ = fg;   *p++ = fb;   *p++ = fa;
390                     *q-- = fa;   *q-- = fb;   *q-- = fg;   *q-- = fr;
391                     x++;
392                 }
393                 do {
394                     *p++ = sr;   *p++ = sg;   *p++ = sb;   *p++ = sa;
395                     *q-- = sa; *q-- = sb; *q-- = sg; *q-- = sr;
396                     x++;
397                 } while (x <= c+z);
398                 while (x < side) {
399                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
400                     *q-- = 0x00; *q-- = 0x00; *q-- = 0x00; *q-- = 0x00;
401                     x++;
402                 }
403                 s = z;
404             }
405             ctrl->build = TRUE;
406             break;
408         case SP_CTRL_SHAPE_CROSS:
409             p = ctrl->cache;
410             for (y = 0; y < side; y++) {
411                 z = abs (c - y);
412                 for (x = 0; x < c-z; x++) {
413                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
414                 }
415                 *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
416                 for (; x < c + z; x++) {
417                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
418                 }
419                 if (z != 0) {
420                     *p++ = sr; *p++ = sg; *p++ = sb; *p++ = sa; x++;
421                 }
422                 for (; x < side; x++) {
423                     *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
424                 }
425             }
426             ctrl->build = TRUE;
427             break;
429         case SP_CTRL_SHAPE_BITMAP:
430             if (ctrl->pixbuf) {
431                 unsigned char *px;
432                 unsigned int rs;
433                 px = gdk_pixbuf_get_pixels (ctrl->pixbuf);
434                 rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf);
435                 for (y = 0; y < side; y++){
436                     unsigned char *s, *d;
437                     s = px + y * rs;
438                     d = ctrl->cache + 4 * side * y;
439                     for (x = 0; x < side; x++) {
440                         if (s[3] < 0x80) {
441                             d[0] = 0x00;
442                             d[1] = 0x00;
443                             d[2] = 0x00;
444                             d[3] = 0x00;
445                         } else if (s[0] < 0x80) {
446                             d[0] = sr;
447                             d[1] = sg;
448                             d[2] = sb;
449                             d[3] = sa;
450                         } else {
451                             d[0] = fr;
452                             d[1] = fg;
453                             d[2] = fb;
454                             d[3] = fa;
455                         }
456                         s += 4;
457                         d += 4;
458                     }
459                 }
460             } else {
461                 g_print ("control has no pixmap\n");
462             }
463             ctrl->build = TRUE;
464             break;
466         case SP_CTRL_SHAPE_IMAGE:
467             if (ctrl->pixbuf) {
468                 guint r = gdk_pixbuf_get_rowstride (ctrl->pixbuf);
469                 guchar * pix;
470                 q = gdk_pixbuf_get_pixels (ctrl->pixbuf);
471                 p = ctrl->cache;
472                 for (y = 0; y < side; y++){
473                     pix = q + (y * r);
474                     for (x = 0; x < side; x++) {
475                         *p++ = *pix++;
476                         *p++ = *pix++;
477                         *p++ = *pix++;
478                         *p++ = *pix++;
479                     }
480                 }
481             } else {
482                 g_print ("control has no pixmap\n");
483             }
484             ctrl->build = TRUE;
485             break;
487         default:
488             break;
489     }
493 // composite background, foreground, alpha for xor mode
494 #define COMPOSE_X(b,f,a) ( FAST_DIVIDE<255>( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) ((b ^ ~f) + b/4 - (b>127? 63 : 0))) * ((guchar) a) ) )
495 // composite background, foreground, alpha for color mode
496 #define COMPOSE_N(b,f,a) ( FAST_DIVIDE<255>( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) f) * ((guchar) a) ) )
498 static void
499 sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf)
501     gint y0, y1, y, x0,x1,x;
502     guchar *p, *q, a;
504     SPCtrl *ctrl = SP_CTRL (item);
506     if (!ctrl->defined) return;
507     if ((!ctrl->filled) && (!ctrl->stroked)) return;
509     sp_canvas_prepare_buffer (buf);
511     // the control-image is rendered into ctrl->cache
512     if (!ctrl->build) {
513         sp_ctrl_build_cache (ctrl);
514     }
516     // then we render from ctrl->cache
517     y0 = MAX (ctrl->box.y0, buf->rect.y0);
518     y1 = MIN (ctrl->box.y1, buf->rect.y1 - 1);
519     x0 = MAX (ctrl->box.x0, buf->rect.x0);
520     x1 = MIN (ctrl->box.x1, buf->rect.x1 - 1);
522     bool colormode;
524     for (y = y0; y <= y1; y++) {
525         p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4;
526         q = ctrl->cache + ((y - ctrl->box.y0) * (ctrl->span*2+1) + (x0 - ctrl->box.x0)) * 4;
527         for (x = x0; x <= x1; x++) {
528             a = *(q + 3);
529             // 00000000 is the only way to get invisible; all other colors with alpha 00 are treated as mode_color with alpha ff
530             colormode = false;
531             if (a == 0x00 && !(q[0] == 0x00 && q[1] == 0x00 && q[2] == 0x00)) {
532                 a = 0xff;
533                 colormode = true;
534             }
535             if (ctrl->mode == SP_CTRL_MODE_COLOR || colormode) {
536                 p[0] = COMPOSE_N (p[0], q[0], a);
537                 p[1] = COMPOSE_N (p[1], q[1], a);
538                 p[2] = COMPOSE_N (p[2], q[2], a);
539                 q += 4;
540                 p += 4;
541             } else if (ctrl->mode == SP_CTRL_MODE_XOR) {
542                 p[0] = COMPOSE_X (p[0], q[0], a);
543                 p[1] = COMPOSE_X (p[1], q[1], a);
544                 p[2] = COMPOSE_X (p[2], q[2], a);
545                 q += 4;
546                 p += 4;
547             }
548         }
549     }
550     ctrl->shown = TRUE;
553 void SPCtrl::moveto (Geom::Point const p) {
554     if (p != _point) {
555         sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (this), Geom::Matrix(Geom::Translate (p)));
556         _moved = true;
557     }
558     _point = p;
562 /*
563   Local Variables:
564   mode:c++
565   c-file-style:"stroustrup"
566   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
567   indent-tabs-mode:nil
568   fill-column:99
569   End:
570 */
571 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :