Code

Split SPCanvasItem and SPCanvasGroup to individual .h files. Removed forward header.
[inkscape.git] / src / display / sodipodi-ctrlrect.cpp
1 #define __INKSCAPE_CTRLRECT_C__
3 /*
4  * Simple non-transformed rectangle, usable for rubberband
5  *
6  * Author:
7  *   Lauris Kaplinski <lauris@ximian.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *   Carl Hetherington <inkscape@carlh.net>
10  *
11  * Copyright (C) 1999-2001 Lauris Kaplinski
12  * Copyright (C) 2000-2001 Ximian, Inc.
13  *
14  * Released under GNU GPL
15  *
16  */
18 #include "sp-canvas-util.h"
19 #include "sodipodi-ctrlrect.h"
20 #include "libnr/nr-pixops.h"
22 /*
23  * Currently we do not have point method, as it should always be painted
24  * during some transformation, which takes care of events...
25  *
26  * Corner coords can be in any order - i.e. x1 < x0 is allowed
27  */
29 static void sp_ctrlrect_class_init(SPCtrlRectClass *c);
30 static void sp_ctrlrect_init(CtrlRect *ctrlrect);
31 static void sp_ctrlrect_destroy(GtkObject *object);
33 static void sp_ctrlrect_update(SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags);
34 static void sp_ctrlrect_render(SPCanvasItem *item, SPCanvasBuf *buf);
36 static SPCanvasItemClass *parent_class;
38 static const guint DASH_LENGTH = 4;
40 GType sp_ctrlrect_get_type()
41 {
42     static GType type = 0;
44     if (!type) {
45         GTypeInfo info = {
46             sizeof(SPCtrlRectClass),
47             0, // base_init
48             0, // base_finalize
49             (GClassInitFunc)sp_ctrlrect_class_init,
50             0, // class_finalize
51             0, // class_data
52             sizeof(CtrlRect),
53             0, // n_preallocs
54             (GInstanceInitFunc)sp_ctrlrect_init,
55             0 // value_table
56         };
57         type = g_type_register_static(SP_TYPE_CANVAS_ITEM, "SPCtrlRect", &info, static_cast<GTypeFlags>(0));
58     }
59     return type;
60 }
62 static void sp_ctrlrect_class_init(SPCtrlRectClass *c)
63 {
64     GtkObjectClass *object_class = (GtkObjectClass *) c;
65     SPCanvasItemClass *item_class = (SPCanvasItemClass *) c;
67     parent_class = (SPCanvasItemClass*) gtk_type_class(sp_canvas_item_get_type());
69     object_class->destroy = sp_ctrlrect_destroy;
71     item_class->update = sp_ctrlrect_update;
72     item_class->render = sp_ctrlrect_render;
73 }
75 static void sp_ctrlrect_init(CtrlRect *cr)
76 {
77     cr->init();
78 }
80 static void sp_ctrlrect_destroy(GtkObject *object)
81 {
82     if (GTK_OBJECT_CLASS(parent_class)->destroy) {
83         (* GTK_OBJECT_CLASS(parent_class)->destroy)(object);
84     }
85 }
87 /* FIXME: use definitions from somewhere else */
88 #define RGBA_R(v) ((v) >> 24)
89 #define RGBA_G(v) (((v) >> 16) & 0xff)
90 #define RGBA_B(v) (((v) >> 8) & 0xff)
91 #define RGBA_A(v) ((v) & 0xff)
93 static void sp_ctrlrect_hline(SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba, guint dashed)
94 {
95     if (y >= buf->rect.y0 && y < buf->rect.y1) {
96         guint const r = RGBA_R(rgba);
97         guint const g = RGBA_G(rgba);
98         guint const b = RGBA_B(rgba);
99         guint const a = RGBA_A(rgba);
100         gint const x0 = MAX(buf->rect.x0, xs);
101         gint const x1 = MIN(buf->rect.x1, xe + 1);
102         guchar *p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4;
103         for (gint x = x0; x < x1; x++) {
104             if (!dashed || ((x / DASH_LENGTH) % 2)) {
105                 p[0] = INK_COMPOSE(r, a, p[0]);
106                 p[1] = INK_COMPOSE(g, a, p[1]);
107                 p[2] = INK_COMPOSE(b, a, p[2]);
108             }
109             p += 4;
110         }
111     }
114 static void sp_ctrlrect_vline(SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba, guint dashed)
116     if (x >= buf->rect.x0 && x < buf->rect.x1) {
117         guint const r = RGBA_R(rgba);
118         guint const g = RGBA_G(rgba);
119         guint const b = RGBA_B(rgba);
120         guint const a = RGBA_A(rgba);
121         gint const y0 = MAX(buf->rect.y0, ys);
122         gint const y1 = MIN(buf->rect.y1, ye + 1);
123         guchar *p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4;
124         for (gint y = y0; y < y1; y++) {
125             if (!dashed || ((y / DASH_LENGTH) % 2)) {
126                 p[0] = INK_COMPOSE(r, a, p[0]);
127                 p[1] = INK_COMPOSE(g, a, p[1]);
128                 p[2] = INK_COMPOSE(b, a, p[2]);
129             }
130             p += buf->buf_rowstride;
131         }
132     }
135 /** Fills the pixels in [xs, xe)*[ys,ye) clipped to the tile with rgb * a. */
136 static void sp_ctrlrect_area(SPCanvasBuf *buf, gint xs, gint ys, gint xe, gint ye, guint32 rgba)
138     guint const r = RGBA_R(rgba);
139     guint const g = RGBA_G(rgba);
140     guint const b = RGBA_B(rgba);
141     guint const a = RGBA_A(rgba);
142     gint const x0 = MAX(buf->rect.x0, xs);
143     gint const x1 = MIN(buf->rect.x1, xe + 1);
144     gint const y0 = MAX(buf->rect.y0, ys);
145     gint const y1 = MIN(buf->rect.y1, ye + 1);
146     for (gint y = y0; y < y1; y++) {
147         guchar *p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 4;
148         for (gint x = x0; x < x1; x++) {
149             p[0] = INK_COMPOSE(r, a, p[0]);
150             p[1] = INK_COMPOSE(g, a, p[1]);
151             p[2] = INK_COMPOSE(b, a, p[2]);
152             p += 4;
153         }
154     }
157 static void sp_ctrlrect_render(SPCanvasItem *item, SPCanvasBuf *buf)
159     SP_CTRLRECT(item)->render(buf);
163 static void sp_ctrlrect_update(SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags)
165     SP_CTRLRECT(item)->update(affine, flags);
170 void CtrlRect::init()
172     _has_fill = false;
173     _dashed = false;
174     _shadow = 0;
176     _area.x0 = _area.y0 = 0;
177     _area.x1 = _area.y1 = 0;
179     _rect = Geom::Rect(Geom::Point(0,0),Geom::Point(0,0));
181     _shadow_size = 0;
183     _border_color = 0x000000ff;
184     _fill_color = 0xffffffff;
185     _shadow_color = 0x000000ff;
189 void CtrlRect::render(SPCanvasBuf *buf)
191     if ((_area.x0 != 0 || _area.x1 != 0 || _area.y0 != 0 || _area.y1 != 0) &&
192         (_area.x0 < buf->rect.x1) &&
193         (_area.y0 < buf->rect.y1) &&
194         ((_area.x1 + _shadow_size) >= buf->rect.x0) &&
195         ((_area.y1 + _shadow_size) >= buf->rect.y0)) {
196         sp_canvas_prepare_buffer(buf);
198         /* Top */
199         sp_ctrlrect_hline(buf, _area.y0, _area.x0, _area.x1, _border_color, _dashed);
200         /* Bottom */
201         sp_ctrlrect_hline(buf, _area.y1, _area.x0, _area.x1, _border_color, _dashed);
202         /* Left */
203         sp_ctrlrect_vline(buf, _area.x0, _area.y0 + 1, _area.y1 - 1, _border_color, _dashed);
204         /* Right */
205         sp_ctrlrect_vline(buf, _area.x1, _area.y0 + 1, _area.y1 - 1, _border_color, _dashed);
206         if (_shadow_size > 0) {
207             /* Right shadow */
208             sp_ctrlrect_area(buf, _area.x1 + 1, _area.y0 + _shadow_size,
209                              _area.x1 + _shadow_size, _area.y1 + _shadow_size, _shadow_color);
210             /* Bottom shadow */
211             sp_ctrlrect_area(buf, _area.x0 + _shadow_size, _area.y1 + 1,
212                              _area.x1, _area.y1 + _shadow_size, _shadow_color);
213         }
214         if (_has_fill) {
215             /* Fill */
216             sp_ctrlrect_area(buf, _area.x0 + 1, _area.y0 + 1,
217                              _area.x1 - 1, _area.y1 - 1, _fill_color);
218         }
219     }
223 void CtrlRect::update(Geom::Matrix const &affine, unsigned int flags)
225     if (((SPCanvasItemClass *) parent_class)->update) {
226         ((SPCanvasItemClass *) parent_class)->update(this, affine, flags);
227     }
229     sp_canvas_item_reset_bounds(this);
231     NRRectL _area_old;
232     _area_old.x0 = _area.x0;
233     _area_old.x1 = _area.x1;
234     _area_old.y0 = _area.y0;
235     _area_old.y1 = _area.y1;
237     Geom::Rect bbox(_rect.min() * affine, _rect.max() * affine);
239     _area.x0 = (int) floor(bbox.min()[Geom::X] + 0.5);
240     _area.y0 = (int) floor(bbox.min()[Geom::Y] + 0.5);
241     _area.x1 = (int) floor(bbox.max()[Geom::X] + 0.5);
242     _area.y1 = (int) floor(bbox.max()[Geom::Y] + 0.5);
244     gint _shadow_size_old = _shadow_size;
245     _shadow_size = _shadow;
247     // FIXME: we don't process a possible change in _has_fill
248     if (_has_fill) {
249         if (_area_old.x0 != 0 || _area_old.x1 != 0 || _area_old.y0 != 0 || _area_old.y1 != 0) {
250             sp_canvas_request_redraw(canvas,
251                                  _area_old.x0 - 1, _area_old.y0 - 1,
252                                  _area_old.x1 + _shadow_size + 1, _area_old.y1 + _shadow_size + 1);
253         }
254         if (_area.x0 != 0 || _area.x1 != 0 || _area.y0 != 0 || _area.y1 != 0) {
255             sp_canvas_request_redraw(canvas,
256                                  _area.x0 - 1, _area.y0 - 1,
257                                  _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
258         }
259     } else { // clear box, be smart about what part of the frame to redraw
261         /* Top */
262         if (_area.y0 != _area_old.y0) { // different level, redraw fully old and new
263             if (_area_old.x0 != _area_old.x1)
264                 sp_canvas_request_redraw(canvas,
265                                          _area_old.x0 - 1, _area_old.y0 - 1,
266                                          _area_old.x1 + 1, _area_old.y0 + 1);
268             if (_area.x0 != _area.x1)
269                 sp_canvas_request_redraw(canvas,
270                                          _area.x0 - 1, _area.y0 - 1,
271                                          _area.x1 + 1, _area.y0 + 1);
272         } else { // same level, redraw only the ends
273             if (_area.x0 != _area_old.x0) {
274                 sp_canvas_request_redraw(canvas,
275                                          MIN(_area_old.x0,_area.x0) - 1, _area.y0 - 1,
276                                          MAX(_area_old.x0,_area.x0) + 1, _area.y0 + 1);
277             }
278             if (_area.x1 != _area_old.x1) {
279                 sp_canvas_request_redraw(canvas,
280                                          MIN(_area_old.x1,_area.x1) - 1, _area.y0 - 1,
281                                          MAX(_area_old.x1,_area.x1) + 1, _area.y0 + 1);
282             }
283         }
285         /* Left */
286         if (_area.x0 != _area_old.x0) { // different level, redraw fully old and new
287             if (_area_old.y0 != _area_old.y1)
288                 sp_canvas_request_redraw(canvas,
289                                          _area_old.x0 - 1, _area_old.y0 - 1,
290                                          _area_old.x0 + 1, _area_old.y1 + 1);
292             if (_area.y0 != _area.y1)
293                 sp_canvas_request_redraw(canvas,
294                                          _area.x0 - 1, _area.y0 - 1,
295                                          _area.x0 + 1, _area.y1 + 1);
296         } else { // same level, redraw only the ends
297             if (_area.y0 != _area_old.y0) {
298                 sp_canvas_request_redraw(canvas,
299                                          _area.x0 - 1, MIN(_area_old.y0,_area.y0) - 1, 
300                                          _area.x0 + 1, MAX(_area_old.y0,_area.y0) + 1);
301             }
302             if (_area.y1 != _area_old.y1) {
303                 sp_canvas_request_redraw(canvas,
304                                          _area.x0 - 1, MIN(_area_old.y1,_area.y1) - 1, 
305                                          _area.x0 + 1, MAX(_area_old.y1,_area.y1) + 1);
306             }
307         }
309         /* Right */
310         if (_area.x1 != _area_old.x1 || _shadow_size_old != _shadow_size) { 
311             if (_area_old.y0 != _area_old.y1)
312                 sp_canvas_request_redraw(canvas,
313                                          _area_old.x1 - 1, _area_old.y0 - 1,
314                                          _area_old.x1 + _shadow_size + 1, _area_old.y1 + _shadow_size + 1);
316             if (_area.y0 != _area.y1)
317                 sp_canvas_request_redraw(canvas,
318                                          _area.x1 - 1, _area.y0 - 1,
319                                          _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
320         } else { // same level, redraw only the ends
321             if (_area.y0 != _area_old.y0) {
322                 sp_canvas_request_redraw(canvas,
323                                          _area.x1 - 1, MIN(_area_old.y0,_area.y0) - 1, 
324                                          _area.x1 + _shadow_size + 1, MAX(_area_old.y0,_area.y0) + _shadow_size + 1);
325             }
326             if (_area.y1 != _area_old.y1) {
327                 sp_canvas_request_redraw(canvas,
328                                          _area.x1 - 1, MIN(_area_old.y1,_area.y1) - 1, 
329                                          _area.x1 + _shadow_size + 1, MAX(_area_old.y1,_area.y1) + _shadow_size + 1);
330             }
331         }
333         /* Bottom */
334         if (_area.y1 != _area_old.y1 || _shadow_size_old != _shadow_size) { 
335             if (_area_old.x0 != _area_old.x1)
336                 sp_canvas_request_redraw(canvas,
337                                          _area_old.x0 - 1, _area_old.y1 - 1,
338                                          _area_old.x1 + _shadow_size + 1, _area_old.y1 + _shadow_size + 1);
340             if (_area.x0 != _area.x1)
341                 sp_canvas_request_redraw(canvas,
342                                          _area.x0 - 1, _area.y1 - 1,
343                                          _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
344         } else { // same level, redraw only the ends
345             if (_area.x0 != _area_old.x0) {
346                 sp_canvas_request_redraw(canvas,
347                                          MIN(_area_old.x0,_area.x0) - 1, _area.y1 - 1,
348                                          MAX(_area_old.x0,_area.x0) + _shadow_size + 1, _area.y1 + _shadow_size + 1);
349             }
350             if (_area.x1 != _area_old.x1) {
351                 sp_canvas_request_redraw(canvas,
352                                          MIN(_area_old.x1,_area.x1) - 1, _area.y1 - 1,
353                                          MAX(_area_old.x1,_area.x1) + _shadow_size + 1, _area.y1 + _shadow_size + 1);
354             }
355         }
356     }
358     // update SPCanvasItem box
359     if (_area.x0 != 0 || _area.x1 != 0 || _area.y0 != 0 || _area.y1 != 0) {
360         x1 = _area.x0 - 1;
361         y1 = _area.y0 - 1;
362         x2 = _area.x1 + _shadow_size + 1;
363         y2 = _area.y1 + _shadow_size + 1;
364     }
368 void CtrlRect::setColor(guint32 b, bool h, guint f)
370     _border_color = b;
371     _has_fill = h;
372     _fill_color = f;
373     _requestUpdate();
376 void CtrlRect::setShadow(int s, guint c)
378     _shadow = s;
379     _shadow_color = c;
380     _requestUpdate();
383 void CtrlRect::setRectangle(Geom::Rect const &r)
385     _rect = r;
386     _requestUpdate();
389 void CtrlRect::setDashed(bool d)
391     _dashed = d;
392     _requestUpdate();
395 void CtrlRect::_requestUpdate()
397     sp_canvas_item_request_update(SP_CANVAS_ITEM(this));
400 /*
401   Local Variables:
402   mode:c++
403   c-file-style:"stroustrup"
404   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
405   indent-tabs-mode:nil
406   fill-column:99
407   End:
408 */
409 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :