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