Code

1eee3a860ee243aadbcfcb6f89bbe59e0e9b343e
[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 "display-forward.h"
19 #include "sp-canvas-util.h"
20 #include "sodipodi-ctrlrect.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, NR::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 GtkType sp_ctrlrect_get_type()
41 {
42     static GtkType ctrlrect_type = 0;
43     
44     if (!ctrlrect_type) {
45         GtkTypeInfo ctrlrect_info = {
46             "SPCtrlRect",
47             sizeof(CtrlRect),
48             sizeof(SPCtrlRectClass),
49             (GtkClassInitFunc) sp_ctrlrect_class_init,
50             (GtkObjectInitFunc) sp_ctrlrect_init,
51             NULL, NULL, NULL
52         };
53         ctrlrect_type = gtk_type_unique(SP_TYPE_CANVAS_ITEM, &ctrlrect_info);
54     }
55     return ctrlrect_type;
56 }
58 static void sp_ctrlrect_class_init(SPCtrlRectClass *c)
59 {
60     GtkObjectClass *object_class = (GtkObjectClass *) c;
61     SPCanvasItemClass *item_class = (SPCanvasItemClass *) c;
63     parent_class = (SPCanvasItemClass*) gtk_type_class(sp_canvas_item_get_type());
65     object_class->destroy = sp_ctrlrect_destroy;
67     item_class->update = sp_ctrlrect_update;
68     item_class->render = sp_ctrlrect_render;
69 }
71 static void sp_ctrlrect_init(CtrlRect *cr)
72 {
73     cr->init();
74 }
76 static void sp_ctrlrect_destroy(GtkObject *object)
77 {
78     if (GTK_OBJECT_CLASS(parent_class)->destroy) {
79         (* GTK_OBJECT_CLASS(parent_class)->destroy)(object);
80     }
81 }
83 /* FIXME: use definitions from somewhere else */
84 #define RGBA_R(v) ((v) >> 24)
85 #define RGBA_G(v) (((v) >> 16) & 0xff)
86 #define RGBA_B(v) (((v) >> 8) & 0xff)
87 #define RGBA_A(v) ((v) & 0xff)
88 #define COMPOSE(b,f,a) ( ( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) ((b ^ ~f) + b/4 - (b>127? 63 : 0))) * ((guchar) a) ) / 0xff )
90 static void sp_ctrlrect_hline(SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba, guint dashed)
91 {
92     if (y >= buf->rect.y0 && y < buf->rect.y1) {
93         guint const r = RGBA_R(rgba);
94         guint const g = RGBA_G(rgba);
95         guint const b = RGBA_B(rgba);
96         guint const a = RGBA_A(rgba);
97         gint const x0 = MAX(buf->rect.x0, xs);
98         gint const x1 = MIN(buf->rect.x1, xe + 1);
99         guchar *p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 3;
100         for (gint x = x0; x < x1; x++) {
101             if (!dashed || ((x / DASH_LENGTH) % 2)) {
102                 p[0] = COMPOSE(p[0], r, a);
103                 p[1] = COMPOSE(p[1], g, a);
104                 p[2] = COMPOSE(p[2], b, a);
105             }
106             p += 3;
107         }
108     }
111 static void sp_ctrlrect_vline(SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba, guint dashed)
113     if (x >= buf->rect.x0 && x < buf->rect.x1) {
114         guint const r = RGBA_R(rgba);
115         guint const g = RGBA_G(rgba);
116         guint const b = RGBA_B(rgba);
117         guint const a = RGBA_A(rgba);
118         gint const y0 = MAX(buf->rect.y0, ys);
119         gint const y1 = MIN(buf->rect.y1, ye + 1);
120         guchar *p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 3;
121         for (gint y = y0; y < y1; y++) {
122             if (!dashed || ((y / DASH_LENGTH) % 2)) {
123                 p[0] = COMPOSE(p[0], r, a);
124                 p[1] = COMPOSE(p[1], g, a);
125                 p[2] = COMPOSE(p[2], b, a);
126             }
127             p += buf->buf_rowstride;
128         }
129     }
132 /** Fills the pixels in [xs, xe)*[ys,ye) clipped to the tile with rgb * a. */
133 static void sp_ctrlrect_area(SPCanvasBuf *buf, gint xs, gint ys, gint xe, gint ye, guint32 rgba)
135     guint const r = RGBA_R(rgba);
136     guint const g = RGBA_G(rgba);
137     guint const b = RGBA_B(rgba);
138     guint const a = RGBA_A(rgba);
139     gint const x0 = MAX(buf->rect.x0, xs);
140     gint const x1 = MIN(buf->rect.x1, xe + 1);
141     gint const y0 = MAX(buf->rect.y0, ys);
142     gint const y1 = MIN(buf->rect.y1, ye + 1);
143     for (gint y = y0; y < y1; y++) {
144         guchar *p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 3;
145         for (gint x = x0; x < x1; x++) {
146             p[0] = COMPOSE(p[0], r, a);
147             p[1] = COMPOSE(p[1], g, a);
148             p[2] = COMPOSE(p[2], b, a);
149             p += 3;
150         }
151     }
154 static void sp_ctrlrect_render(SPCanvasItem *item, SPCanvasBuf *buf)
156     SP_CTRLRECT(item)->render(buf);
160 static void sp_ctrlrect_update(SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
162     SP_CTRLRECT(item)->update(affine, flags);
167 void CtrlRect::init()
169     _has_fill = false;
170     _dashed = false;
171     _shadow = 0;
173     _area.x0 = _area.y0 = 0;
174     _area.x1 = _area.y1 = 0;
176     _rect = NR::Rect(NR::Point(0,0),NR::Point(0,0));
178     _shadow_size = 0;
180     _border_color = 0x000000ff;
181     _fill_color = 0xffffffff;
182     _shadow_color = 0x000000ff;
186 void CtrlRect::render(SPCanvasBuf *buf)
188     if ((_area.x0 != 0 || _area.x1 != 0 || _area.y0 != 0 || _area.y1 != 0) &&
189         (_area.x0 < buf->rect.x1) &&
190         (_area.y0 < buf->rect.y1) &&
191         ((_area.x1 + _shadow_size) >= buf->rect.x0) &&
192         ((_area.y1 + _shadow_size) >= buf->rect.y0)) {
193         sp_canvas_prepare_buffer(buf);
195         /* Top */
196         sp_ctrlrect_hline(buf, _area.y0, _area.x0, _area.x1, _border_color, _dashed);
197         /* Bottom */
198         sp_ctrlrect_hline(buf, _area.y1, _area.x0, _area.x1, _border_color, _dashed);
199         /* Left */
200         sp_ctrlrect_vline(buf, _area.x0, _area.y0 + 1, _area.y1 - 1, _border_color, _dashed);
201         /* Right */
202         sp_ctrlrect_vline(buf, _area.x1, _area.y0 + 1, _area.y1 - 1, _border_color, _dashed);
203         if (_shadow_size > 0) {
204             /* Right shadow */
205             sp_ctrlrect_area(buf, _area.x1 + 1, _area.y0 + _shadow_size,
206                              _area.x1 + _shadow_size, _area.y1 + _shadow_size, _shadow_color);
207             /* Bottom shadow */
208             sp_ctrlrect_area(buf, _area.x0 + _shadow_size, _area.y1 + 1,
209                              _area.x1, _area.y1 + _shadow_size, _shadow_color);
210         }
211         if (_has_fill) {
212             /* Fill */
213             sp_ctrlrect_area(buf, _area.x0 + 1, _area.y0 + 1,
214                              _area.x1 - 1, _area.y1 - 1, _fill_color);
215         }
216     }
220 void CtrlRect::update(NR::Matrix const &affine, unsigned int flags)
222     if (((SPCanvasItemClass *) parent_class)->update) {
223         ((SPCanvasItemClass *) parent_class)->update(this, affine, flags);
224     }
226     sp_canvas_item_reset_bounds(this);
228     if (_area.x0 != 0 || _area.x1 != 0 || _area.y0 != 0 || _area.y1 != 0) {
229         /* Request redraw old */
230         if (!_has_fill) {
231             /* Top */
232             sp_canvas_request_redraw(canvas,
233                                      _area.x0 - 1, _area.y0 - 1,
234                                      _area.x1 + 1, _area.y0 + 1);
235             /* Left */
236             sp_canvas_request_redraw(canvas,
237                                      _area.x0 - 1, _area.y0 - 1,
238                                      _area.x0 + 1, _area.y1 + 1);
239             /* Right */
240             sp_canvas_request_redraw(canvas,
241                                      _area.x1 - 1, _area.y0 - 1,
242                                      _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
243             /* Bottom */
244             sp_canvas_request_redraw(canvas,
245                                      _area.x0 - 1, _area.y1 - 1,
246                                      _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
247         } else {
248             sp_canvas_request_redraw(canvas,
249                                      _area.x0 - 1, _area.y0 - 1,
250                                      _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
251         }
252     }
254     NR::Rect bbox(_rect.min() * affine, _rect.max() * affine);
255     
256     _area.x0 = (int) floor(bbox.min()[NR::X] + 0.5);
257     _area.y0 = (int) floor(bbox.min()[NR::Y] + 0.5);
258     _area.x1 = (int) floor(bbox.max()[NR::X] + 0.5);
259     _area.y1 = (int) floor(bbox.max()[NR::Y] + 0.5);
260     
261     _shadow_size = _shadow;
263     if (_area.x0 != 0 || _area.x1 != 0 || _area.y0 != 0 || _area.y1 != 0) {
264         /* Request redraw new */
265         if (!_has_fill) {
266             /* Top */
267             sp_canvas_request_redraw(canvas,
268                                      _area.x0 - 1, _area.y0 - 1,
269                                      _area.x1 + 1, _area.y0 + 1);
270             /* Left */
271             sp_canvas_request_redraw(canvas,
272                                      _area.x0 - 1, _area.y0 - 1,
273                                      _area.x0 + 1, _area.y1 + 1);
274             /* Right */
275             sp_canvas_request_redraw(canvas,
276                                      _area.x1 - 1, _area.y0 - 1,
277                                      _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
278             /* Bottom */
279             sp_canvas_request_redraw(canvas,
280                                      _area.x0 - 1, _area.y1 - 1,
281                                      _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
282         } else {
283             sp_canvas_request_redraw(canvas,
284                                      _area.x0 - 1, _area.y0 - 1,
285                                      _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
286         }
288         x1 = _area.x0 - 1;
289         y1 = _area.y0 - 1;
290         x2 = _area.x1 + _shadow_size + 1;
291         y2 = _area.y1 + _shadow_size + 1;
292     }
293   
297 void CtrlRect::setColor(guint32 b, bool h, guint f)
299     _border_color = b;
300     _has_fill = h;
301     _fill_color = f;
302     _requestUpdate();
305 void CtrlRect::setShadow(int s, guint c)
307     _shadow = s;
308     _shadow_color = c;
309     _requestUpdate();
312 void CtrlRect::setRectangle(NR::Rect const &r)
314     _rect = r;
315     _requestUpdate();
318 void CtrlRect::setDashed(bool d)
320     _dashed = d;
321     _requestUpdate();
324 void CtrlRect::_requestUpdate()
326     sp_canvas_item_request_update(SP_CANVAS_ITEM(this));
329 /*
330   Local Variables:
331   mode:c++
332   c-file-style:"stroustrup"
333   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
334   indent-tabs-mode:nil
335   fill-column:99
336   End:
337 */
338 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :