4ee4985a2c7c64839171e5c712473392aea0f826
[ardour.git] / gtk2_ardour / canvas-simplerect.c
1 #include <stdio.h>
2 #include <math.h>
3 #include <gtk-canvas.h>
4
5 #include "canvas-simplerect.h"
6 #include "rgb_macros.h"
7
8 enum {
9         ARG_0,
10         ARG_X1,
11         ARG_Y1,
12         ARG_X2,
13         ARG_Y2,
14         ARG_OUTLINE_PIXELS,
15         ARG_OUTLINE_WHAT,
16         ARG_FILL,
17         ARG_FILL_COLOR_RGBA,
18         ARG_OUTLINE_COLOR_RGBA,
19         ARG_DRAW
20         
21 };
22
23 static void gtk_canvas_simplerect_class_init (GtkCanvasSimpleRectClass *class);
24 static void gtk_canvas_simplerect_init       (GtkCanvasSimpleRect      *simplerect);
25 static void gtk_canvas_simplerect_set_arg    (GtkObject              *object,
26                                               GtkArg                 *arg,
27                                               guint                   arg_id);
28 static void gtk_canvas_simplerect_get_arg    (GtkObject              *object,
29                                               GtkArg                 *arg,
30                                               guint                   arg_id);
31
32 static void   gtk_canvas_simplerect_update      (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
33 static void   gtk_canvas_simplerect_bounds      (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
34 static double gtk_canvas_simplerect_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item);
35 static void   gtk_canvas_simplerect_render (GtkCanvasItem *item, GtkCanvasBuf *buf);
36 static void   gtk_canvas_simplerect_draw (GtkCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
37
38 static GtkCanvasItemClass *parent_class;
39
40
41 GtkType
42 gtk_canvas_simplerect_get_type (void)
43 {
44         static GtkType simplerect_type = 0;
45
46         if (!simplerect_type) {
47                 GtkTypeInfo simplerect_info = {
48                         "GtkCanvasSimpleRect",
49                         sizeof (GtkCanvasSimpleRect),
50                         sizeof (GtkCanvasSimpleRectClass),
51                         (GtkClassInitFunc) gtk_canvas_simplerect_class_init,
52                         (GtkObjectInitFunc) gtk_canvas_simplerect_init,
53                         NULL, /* reserved_1 */
54                         NULL, /* reserved_2 */
55                         (GtkClassInitFunc) NULL
56                 };
57
58                 simplerect_type = gtk_type_unique (gtk_canvas_item_get_type (), &simplerect_info);
59         }
60
61         return simplerect_type;
62 }
63
64 static void
65 gtk_canvas_simplerect_class_init (GtkCanvasSimpleRectClass *class)
66 {
67         GtkObjectClass *object_class;
68         GtkCanvasItemClass *item_class;
69
70         object_class = (GtkObjectClass *) class;
71         item_class = (GtkCanvasItemClass *) class;
72
73         parent_class = gtk_type_class (gtk_canvas_item_get_type ());
74
75         gtk_object_add_arg_type ("GtkCanvasSimpleRect::x1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X1);
76         gtk_object_add_arg_type ("GtkCanvasSimpleRect::y1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y1);
77         gtk_object_add_arg_type ("GtkCanvasSimpleRect::x2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X2);
78         gtk_object_add_arg_type ("GtkCanvasSimpleRect::y2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y2);
79         gtk_object_add_arg_type ("GtkCanvasSimpleRect::fill", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_FILL);
80         gtk_object_add_arg_type ("GtkCanvasSimpleRect::draw", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_DRAW);
81         gtk_object_add_arg_type ("GtkCanvasSimpleRect::fill_color_rgba", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_FILL_COLOR_RGBA);
82         gtk_object_add_arg_type ("GtkCanvasSimpleRect::outline_color_rgba", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_OUTLINE_COLOR_RGBA);
83         gtk_object_add_arg_type ("GtkCanvasSimpleRect::outline_pixels", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_OUTLINE_PIXELS);
84         gtk_object_add_arg_type ("GtkCanvasSimpleRect::outline_what", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_OUTLINE_WHAT);
85
86         object_class->set_arg = gtk_canvas_simplerect_set_arg;
87         object_class->get_arg = gtk_canvas_simplerect_get_arg;
88
89         item_class->update = gtk_canvas_simplerect_update;
90         item_class->bounds = gtk_canvas_simplerect_bounds;
91         item_class->point = gtk_canvas_simplerect_point;
92         item_class->render = gtk_canvas_simplerect_render;
93         item_class->draw = gtk_canvas_simplerect_draw;
94 }
95
96 static void
97 gtk_canvas_simplerect_init (GtkCanvasSimpleRect *simplerect)
98 {
99         simplerect->x1 = 0.0;
100         simplerect->y1 = 0.0;
101         simplerect->x2 = 0.0;
102         simplerect->y2 = 0.0;
103         simplerect->fill = TRUE;
104         simplerect->draw = TRUE;
105         simplerect->full_draw_on_update = TRUE;
106         simplerect->fill_color = 0;
107         simplerect->outline_color = 0;
108         simplerect->outline_pixels = 1;
109         simplerect->outline_what = 0xf;
110
111         GTK_CANVAS_ITEM(simplerect)->object.flags |= GTK_CANVAS_ITEM_NO_AUTO_REDRAW;
112 }
113
114 static void
115 gtk_canvas_simplerect_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
116 {
117         GtkCanvasSimpleRect *simplerect = GTK_CANVAS_SIMPLERECT (item);
118
119         *x1 = simplerect->x1;
120         *y1 = simplerect->y1;
121         *x2 = simplerect->x2 + 1;
122         *y2 = simplerect->y2 + 1;
123
124 }
125
126 static void 
127 gtk_canvas_simplerect_reset_bounds (GtkCanvasItem *item)
128 {
129         GtkCanvasSimpleRect* simplerect;
130         double x1, x2, y1, y2;
131         double old_x1, old_x2, old_y1, old_y2;
132         double a, b;
133         
134         old_x1 = item->x1;
135         old_y1 = item->y1;
136         old_x2 = item->x2;
137         old_y2 = item->y2;
138
139         gtk_canvas_simplerect_bounds (item, &x1, &y1, &x2, &y2);
140         gtk_canvas_item_i2w (item, &x1, &y1);
141         gtk_canvas_item_i2w (item, &x2, &y2);
142
143         item->x1 = x1;
144         item->y1 = y1;
145         item->x2 = x2;
146         item->y2 = y2;
147
148         /* now compute bounding box in canvas units */
149
150         simplerect = GTK_CANVAS_SIMPLERECT (item);
151
152         gtk_canvas_w2c (GTK_CANVAS(item->canvas), x1, y1, &simplerect->bbox_ulx, &simplerect->bbox_uly);
153         gtk_canvas_w2c (GTK_CANVAS(item->canvas), x2, y2, &simplerect->bbox_lrx, &simplerect->bbox_lry);
154
155         /* now queue redraws for changed areas */
156
157         if (item->x1 != old_x1) {
158                 
159                 /* left edge changed. redraw the area that altered */
160                 
161                 a = MIN(item->x1, old_x1); 
162                 b = MAX(item->x1, old_x1);
163                 gtk_canvas_request_redraw (item->canvas, a - 1, item->y1, b + 1, item->y2);
164         }
165         
166         if (item->x2 != old_x2) {
167                 
168                 /* right edge changed. redraw the area that altered */
169                 
170                 a = MIN(item->x2, old_x2);
171                 b = MAX(item->x2, old_x2);
172                 gtk_canvas_request_redraw (item->canvas, a - 1, item->y1, b + 1, item->y2);
173         }
174         
175         if (item->y1 != old_y1) {
176                 
177                 /* top edge changed. redraw the area that altered */
178                 
179                 a = MIN(item->y1, old_y1);
180                 b = MAX(item->y1, old_y1);
181                 gtk_canvas_request_redraw (item->canvas, item->x1, a - 1, item->x2, b + 1);
182         }
183         
184         if (item->y2 != old_y2) {
185                 
186                 /* lower edge changed. redraw the area that altered */
187                 
188                 a = MIN(item->y2, old_y2);
189                 b = MAX(item->y2, old_y2);
190                 gtk_canvas_request_redraw (item->canvas, item->x1, a - 1, item->x2, b + 1);
191         }
192 }
193
194 /* 
195  * CANVAS CALLBACKS 
196  */
197
198 static void
199 gtk_canvas_simplerect_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
200 {
201         GtkCanvasItem *item;
202         GtkCanvasSimpleRect *simplerect;
203         int update;
204         int bounds_changed;
205
206         item = GTK_CANVAS_ITEM (object);
207         simplerect = GTK_CANVAS_SIMPLERECT (object);
208
209         update = FALSE;
210         bounds_changed = FALSE;
211
212         switch (arg_id) {
213         case ARG_X1:
214                 if (simplerect->x1 != GTK_VALUE_DOUBLE (*arg)) {
215                         simplerect->x1 = GTK_VALUE_DOUBLE (*arg);
216                         bounds_changed = TRUE;
217                 }
218                 break;
219
220         case ARG_Y1:
221                 if (simplerect->y1 != GTK_VALUE_DOUBLE (*arg)) {
222                         simplerect->y1 = GTK_VALUE_DOUBLE (*arg);
223                         bounds_changed = TRUE;
224                 }
225                 break;
226
227         case ARG_X2:
228                 if (simplerect->x2 != GTK_VALUE_DOUBLE (*arg)) {
229                         simplerect->x2 = GTK_VALUE_DOUBLE (*arg);
230                         bounds_changed = TRUE;
231                 }
232                 break;
233
234         case ARG_Y2:
235                 if (simplerect->y2 != GTK_VALUE_DOUBLE (*arg)) {
236                         simplerect->y2 = GTK_VALUE_DOUBLE (*arg);
237                         bounds_changed = TRUE;
238                 }
239                 break;
240
241         case ARG_DRAW:
242                 if (simplerect->draw != GTK_VALUE_BOOL (*arg)) {
243                         simplerect->draw = GTK_VALUE_BOOL (*arg);
244                         update = TRUE;
245                 }
246                 break;
247
248
249         case ARG_FILL:
250                 if (simplerect->fill != GTK_VALUE_BOOL (*arg)) {
251                         simplerect->fill = GTK_VALUE_BOOL (*arg);
252                         update = TRUE;
253                 }
254                 break;
255
256         case ARG_FILL_COLOR_RGBA:
257                 if (simplerect->fill_color != GTK_VALUE_INT(*arg)) {
258                         simplerect->fill_color = GTK_VALUE_INT(*arg);
259                         update = TRUE;
260                 }
261                 break;
262
263         case ARG_OUTLINE_COLOR_RGBA:
264                 if (simplerect->outline_color != GTK_VALUE_INT(*arg)) {
265                         simplerect->outline_color = GTK_VALUE_INT(*arg);
266                         update = TRUE;
267                 }
268                 break;
269
270         case ARG_OUTLINE_PIXELS:
271                 if (simplerect->outline_pixels != GTK_VALUE_INT(*arg)) {
272                         simplerect->outline_pixels = GTK_VALUE_INT(*arg);
273                         update = TRUE;
274                 }
275                 break;
276
277         case ARG_OUTLINE_WHAT:
278                 if (simplerect->outline_what != GTK_VALUE_INT(*arg)) {
279                         simplerect->outline_what = GTK_VALUE_INT(*arg);
280                         update = TRUE;
281                 }
282                 break;
283
284         default:
285                 break;
286         }
287
288         simplerect->full_draw_on_update = update;
289
290         if (update || bounds_changed) {
291                 gtk_canvas_item_request_update (item);
292         }
293 }
294
295 static void
296 gtk_canvas_simplerect_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
297 {
298         GtkCanvasSimpleRect *simplerect;
299
300         simplerect = GTK_CANVAS_SIMPLERECT (object);
301
302         switch (arg_id) {
303         case ARG_X1:
304                 GTK_VALUE_DOUBLE (*arg) = simplerect->x1;
305                 break;
306         case ARG_Y1:
307                 GTK_VALUE_DOUBLE (*arg) = simplerect->y1;
308                 break;
309         case ARG_X2:
310                 GTK_VALUE_DOUBLE (*arg) = simplerect->x2;
311                 break;
312         case ARG_Y2:
313                 GTK_VALUE_DOUBLE (*arg) = simplerect->y2;
314                 break;
315         case ARG_DRAW:
316                 GTK_VALUE_BOOL (*arg) = simplerect->draw;
317                 break;
318         case ARG_FILL:
319                 GTK_VALUE_BOOL (*arg) = simplerect->fill;
320                 break;
321         case ARG_FILL_COLOR_RGBA:
322                 GTK_VALUE_INT (*arg) = simplerect->fill_color;
323                 break;
324         case ARG_OUTLINE_COLOR_RGBA:
325                 GTK_VALUE_INT (*arg) = simplerect->outline_color;
326                 break;
327         case ARG_OUTLINE_PIXELS:
328                 GTK_VALUE_INT (*arg) = simplerect->outline_pixels;
329                 break;
330         case ARG_OUTLINE_WHAT:
331                 GTK_VALUE_INT (*arg) = simplerect->outline_what;
332                 break;
333         default:
334                 arg->type = GTK_TYPE_INVALID;
335                 break;
336         }
337 }
338
339 static void
340 gtk_canvas_simplerect_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
341 {
342         GtkCanvasSimpleRect *simplerect;
343         unsigned char foo;
344
345         simplerect = GTK_CANVAS_SIMPLERECT (item);
346
347         if (parent_class->update)
348                 (* parent_class->update) (item, affine, clip_path, flags);
349
350         gtk_canvas_simplerect_reset_bounds (item);
351
352         if (simplerect->full_draw_on_update) {
353                 gtk_canvas_request_redraw (item->canvas, 
354                                            simplerect->bbox_ulx,
355                                            simplerect->bbox_uly,
356                                            simplerect->bbox_lrx+1,
357                                            simplerect->bbox_lry+1);
358                 simplerect->full_draw_on_update = FALSE;
359         }
360
361         UINT_TO_RGBA (simplerect->fill_color, &simplerect->fill_r, &simplerect->fill_g, &simplerect->fill_b, &simplerect->fill_a);
362         UINT_TO_RGBA (simplerect->outline_color, &simplerect->outline_r, &simplerect->outline_g, &simplerect->outline_b, &foo);
363 }
364
365 #define SIMPLERECT_FAST_RENDERER
366 #ifdef SIMPLERECT_FAST_RENDERER
367
368 static void
369 gtk_canvas_simplerect_render (GtkCanvasItem *item,
370                               GtkCanvasBuf *buf)
371 {
372         GtkCanvasSimpleRect *simplerect;
373         int end, begin;
374         int ey, sy;
375         unsigned int i;
376         ArtIRect intersection;
377         ArtIRect self;
378
379         simplerect = GTK_CANVAS_SIMPLERECT (item);
380
381         if (parent_class->render) {
382                 (*parent_class->render) (item, buf);
383         }
384
385         if (buf->is_bg) {
386
387                 // this can be useful for debugging/understanding how the canvas redraws
388                 // stuff.
389
390                 // gint randr, randg, randb;
391                 // randr = random() % 255;
392                 // randg = random() % 255;
393                 // randb = random() % 255;
394                 // PAINT_BOX(buf, randr, randg, randb, 255, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1);
395
396                 gtk_canvas_buf_ensure_buf (buf);
397                 buf->is_bg = FALSE;
398         }
399
400         if (!simplerect->draw) {
401                 return;
402         }
403         
404         self.x0 = simplerect->bbox_ulx;
405         self.y0 = simplerect->bbox_uly;
406         self.x1 = simplerect->bbox_lrx;
407         self.y1 = simplerect->bbox_lry;
408
409         art_irect_intersect (&intersection, &self, &buf->rect);
410
411         begin = MAX(simplerect->bbox_ulx, buf->rect.x0);
412         end = MIN((simplerect->bbox_lrx-1), buf->rect.x1);
413
414         sy = simplerect->bbox_uly;
415         ey = simplerect->bbox_lry-1;
416
417         if (simplerect->fill) {
418                 
419                 // this can be useful for debugging/understanding how the canvas redraws
420                 // stuff.
421                 
422                 // gint randr, randg, randb;
423                 // randr = random() % 255;
424                 // randg = random() % 255;
425                 // randb = random() % 255;
426                 // PAINT_BOX(buf, randr, randg, randb, simplerect->fill_a, begin, sy, end, ey);
427                 
428                 FAST_PAINT_BOX (buf, simplerect->fill_r, simplerect->fill_g, simplerect->fill_b, simplerect->fill_a, 
429                                 intersection.x0, intersection.y0,
430                                 intersection.x1, intersection.y1);
431                 
432         }
433
434         for (i = 0; i < simplerect->outline_pixels; ++i) {
435
436                 if (simplerect->outline_what & 0x1) {
437                         if (begin == simplerect->bbox_ulx) {
438                                 PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin + i, sy, ey);
439                         }
440                 }
441
442                 if (simplerect->outline_what & 0x2) {
443                         if (end == (simplerect->bbox_lrx - 1)) {
444                                 PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, end - i, sy, ey + 1);
445                         }
446                 }
447
448                 if (simplerect->outline_what & 0x4) {
449                         PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end, sy+i);
450                 }
451         
452                 if (simplerect->outline_what & 0x8) {
453                         PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end + 1, ey-i);
454                 }
455         }
456 }
457
458 #else /* SIMPLERECT_FAST_RENDERER */
459
460 static void
461 gtk_canvas_simplerect_render (GtkCanvasItem *item,
462                               GtkCanvasBuf *buf)
463 {
464         GtkCanvasSimpleRect *simplerect;
465         int end, begin;
466         int ey, sy;
467         unsigned int i;
468
469         simplerect = GTK_CANVAS_SIMPLERECT (item);
470
471         if (parent_class->render) {
472                 (*parent_class->render) (item, buf);
473         }
474
475         if (buf->is_bg) {
476
477                 // this can be useful for debugging/understanding how the canvas redraws
478                 // stuff.
479
480                 // gint randr, randg, randb;
481                 // randr = random() % 255;
482                 // randg = random() % 255;
483                 // randb = random() % 255;
484                 // PAINT_BOX(buf, randr, randg, randb, 255, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1);
485
486                 gtk_canvas_buf_ensure_buf (buf);
487                 buf->is_bg = FALSE;
488         }
489
490         if (!simplerect->draw) {
491                 return;
492         }
493
494         begin = MAX(simplerect->bbox_ulx,buf->rect.x0);
495         end = MIN((simplerect->bbox_lrx-1),buf->rect.x1);
496
497         sy = simplerect->bbox_uly;
498         ey = simplerect->bbox_lry-1;
499
500         if (simplerect->fill) {
501                 
502                 // this can be useful for debugging/understanding how the canvas redraws
503                 // stuff.
504                 
505                 // gint randr, randg, randb;
506                 // randr = random() % 255;
507                 // randg = random() % 255;
508                 // randb = random() % 255;
509                 // PAINT_BOX(buf, randr, randg, randb, simplerect->fill_a, begin, sy, end, ey);
510                 
511                 PAINT_BOX(buf, simplerect->fill_r, simplerect->fill_g, simplerect->fill_b, simplerect->fill_a, begin, sy, end, ey);
512         }
513
514         for (i = 0; i < simplerect->outline_pixels; ++i) {
515
516                 if (simplerect->outline_what & 0x1) {
517                         if (begin == simplerect->bbox_ulx) {
518                                 PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin + i, sy, ey);
519                         }
520                 }
521
522                 if (simplerect->outline_what & 0x2) {
523                         if (end == (simplerect->bbox_lrx - 1)) {
524                                 PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, end - i, sy, ey + 1);
525                         }
526                 }
527
528                 if (simplerect->outline_what & 0x4) {
529                         PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end, sy+i);
530                 }
531         
532                 if (simplerect->outline_what & 0x8) {
533                         PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end + 1, ey-i);
534                 }
535         }
536 }
537 #endif /* SIMPLERECT_FAST_RENDERER */
538
539 static void
540 gtk_canvas_simplerect_draw (GtkCanvasItem *item,
541                             GdkDrawable *drawable,
542                             int x, int y,
543                             int width, int height)
544 {
545         fprintf (stderr, "please don't use the CanvasSimpleRect item in a non-aa Canvas\n");
546         abort ();
547 }
548
549 static double
550 gtk_canvas_simplerect_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item)
551 {
552         GtkCanvasSimpleRect *simplerect;
553         double x1, y1, x2, y2;
554         double dx, dy;
555
556         simplerect = GTK_CANVAS_SIMPLERECT (item);
557
558         *actual_item = item;
559
560         /* Find the bounds for the rectangle plus its outline width */
561
562         gtk_canvas_simplerect_bounds (item, &x1, &y1, &x2, &y2);
563
564         /* Is point inside rectangle */
565         
566         if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
567                 return 0.0;
568         }
569
570         /* Point is outside rectangle */
571
572         if (x < x1)
573                 dx = x1 - x;
574         else if (x > x2)
575                 dx = x - x2;
576         else
577                 dx = 0.0;
578
579         if (y < y1)
580                 dy = y1 - y;
581         else if (y > y2)
582                 dy = y - y2;
583         else
584                 dy = 0.0;
585
586         return sqrt (dx * dx + dy * dy);
587 }