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;
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 }
109 }
111 static void sp_ctrlrect_vline(SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba, guint dashed)
112 {
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 }
130 }
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)
134 {
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 }
152 }
154 static void sp_ctrlrect_render(SPCanvasItem *item, SPCanvasBuf *buf)
155 {
156 SP_CTRLRECT(item)->render(buf);
157 }
160 static void sp_ctrlrect_update(SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
161 {
162 SP_CTRLRECT(item)->update(affine, flags);
163 }
167 void CtrlRect::init()
168 {
169 _has_fill = false;
170 _dashed = false;
171 _shadow = 0;
173 _area.x0 = _area.y0 = 0;
174 _area.x1 = _area.y1 = -1;
176 _shadow_size = 0;
178 _border_color = 0x000000ff;
179 _fill_color = 0xffffffff;
180 _shadow_color = 0x000000ff;
181 }
184 void CtrlRect::render(SPCanvasBuf *buf)
185 {
186 if ((_area.x0 < buf->rect.x1) &&
187 (_area.y0 < buf->rect.y1) &&
188 ((_area.x1 + _shadow_size) >= buf->rect.x0) &&
189 ((_area.y1 + _shadow_size) >= buf->rect.y0)) {
190 sp_canvas_prepare_buffer(buf);
192 /* Top */
193 sp_ctrlrect_hline(buf, _area.y0, _area.x0, _area.x1, _border_color, _dashed);
194 /* Bottom */
195 sp_ctrlrect_hline(buf, _area.y1, _area.x0, _area.x1, _border_color, _dashed);
196 /* Left */
197 sp_ctrlrect_vline(buf, _area.x0, _area.y0 + 1, _area.y1 - 1, _border_color, _dashed);
198 /* Right */
199 sp_ctrlrect_vline(buf, _area.x1, _area.y0 + 1, _area.y1 - 1, _border_color, _dashed);
200 if (_shadow_size > 0) {
201 /* Right shadow */
202 sp_ctrlrect_area(buf, _area.x1 + 1, _area.y0 + _shadow_size,
203 _area.x1 + _shadow_size, _area.y1 + _shadow_size, _shadow_color);
204 /* Bottom shadow */
205 sp_ctrlrect_area(buf, _area.x0 + _shadow_size, _area.y1 + 1,
206 _area.x1, _area.y1 + _shadow_size, _shadow_color);
207 }
208 if (_has_fill) {
209 /* Fill */
210 sp_ctrlrect_area(buf, _area.x0 + 1, _area.y0 + 1,
211 _area.x1 - 1, _area.y1 - 1, _fill_color);
212 }
213 }
214 }
217 void CtrlRect::update(NR::Matrix const &affine, unsigned int flags)
218 {
219 if (((SPCanvasItemClass *) parent_class)->update) {
220 ((SPCanvasItemClass *) parent_class)->update(this, affine, flags);
221 }
223 sp_canvas_item_reset_bounds(this);
225 /* Request redraw old */
226 if (!_has_fill) {
227 /* Top */
228 sp_canvas_request_redraw(canvas,
229 _area.x0 - 1, _area.y0 - 1,
230 _area.x1 + 1, _area.y0 + 1);
231 /* Left */
232 sp_canvas_request_redraw(canvas,
233 _area.x0 - 1, _area.y0 - 1,
234 _area.x0 + 1, _area.y1 + 1);
235 /* Right */
236 sp_canvas_request_redraw(canvas,
237 _area.x1 - 1, _area.y0 - 1,
238 _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
239 /* Bottom */
240 sp_canvas_request_redraw(canvas,
241 _area.x0 - 1, _area.y1 - 1,
242 _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
243 } else {
244 sp_canvas_request_redraw(canvas,
245 _area.x0 - 1, _area.y0 - 1,
246 _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
247 }
249 NR::Rect bbox(_rect.min() * affine, _rect.max() * affine);
251 _area.x0 = (int) floor(bbox.min()[NR::X] + 0.5);
252 _area.y0 = (int) floor(bbox.min()[NR::Y] + 0.5);
253 _area.x1 = (int) floor(bbox.max()[NR::X] + 0.5);
254 _area.y1 = (int) floor(bbox.max()[NR::Y] + 0.5);
256 _shadow_size = _shadow;
258 /* Request redraw new */
259 if (!_has_fill) {
260 /* Top */
261 sp_canvas_request_redraw(canvas,
262 _area.x0 - 1, _area.y0 - 1,
263 _area.x1 + 1, _area.y0 + 1);
264 /* Left */
265 sp_canvas_request_redraw(canvas,
266 _area.x0 - 1, _area.y0 - 1,
267 _area.x0 + 1, _area.y1 + 1);
268 /* Right */
269 sp_canvas_request_redraw(canvas,
270 _area.x1 - 1, _area.y0 - 1,
271 _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
272 /* Bottom */
273 sp_canvas_request_redraw(canvas,
274 _area.x0 - 1, _area.y1 - 1,
275 _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
276 } else {
277 sp_canvas_request_redraw(canvas,
278 _area.x0 - 1, _area.y0 - 1,
279 _area.x1 + _shadow_size + 1, _area.y1 + _shadow_size + 1);
280 }
282 x1 = _area.x0 - 1;
283 y1 = _area.y0 - 1;
284 x2 = _area.x1 + _shadow_size + 1;
285 y2 = _area.y1 + _shadow_size + 1;
286 }
289 void CtrlRect::setColor(guint32 b, bool h, guint f)
290 {
291 _border_color = b;
292 _has_fill = h;
293 _fill_color = f;
294 _requestUpdate();
295 }
297 void CtrlRect::setShadow(int s, guint c)
298 {
299 _shadow = s;
300 _shadow_color = c;
301 _requestUpdate();
302 }
304 void CtrlRect::setRectangle(NR::Rect const &r)
305 {
306 _rect = r;
307 _requestUpdate();
308 }
310 void CtrlRect::setDashed(bool d)
311 {
312 _dashed = d;
313 _requestUpdate();
314 }
316 void CtrlRect::_requestUpdate()
317 {
318 sp_canvas_item_request_update(SP_CANVAS_ITEM(this));
319 }
321 /*
322 Local Variables:
323 mode:c++
324 c-file-style:"stroustrup"
325 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
326 indent-tabs-mode:nil
327 fill-column:99
328 End:
329 */
330 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :