the ongoing story of umpteen lines of code and its love affair with GTK2
[ardour.git] / gtk2_ardour / canvas-simpleline.c
1 #include <stdio.h>
2 #include <math.h>
3 #include <libgnomecanvas/libgnomecanvas.h>
4
5 #include "canvas-simpleline.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_COLOR_RGBA
15 };
16
17 static void gnome_canvas_simpleline_class_init (GnomeCanvasSimpleLineClass *class);
18 static void gnome_canvas_simpleline_init       (GnomeCanvasSimpleLine      *simpleline);
19 static void gnome_canvas_simpleline_set_arg    (GtkObject              *object,
20                                               GtkArg                 *arg,
21                                               guint                   arg_id);
22 static void gnome_canvas_simpleline_get_arg    (GtkObject              *object,
23                                               GtkArg                 *arg,
24                                               guint                   arg_id);
25
26 static void   gnome_canvas_simpleline_update      (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
27 static void   gnome_canvas_simpleline_bounds      (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
28 static double gnome_canvas_simpleline_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item);
29 static void   gnome_canvas_simpleline_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
30 static void   gnome_canvas_simpleline_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
31
32 static GnomeCanvasItemClass *parent_class;
33
34
35 GtkType
36 gnome_canvas_simpleline_get_type (void)
37 {
38         static GtkType simpleline_type = 0;
39
40         if (!simpleline_type) {
41                 GtkTypeInfo simpleline_info = {
42                         "GnomeCanvasSimpleLine",
43                         sizeof (GnomeCanvasSimpleLine),
44                         sizeof (GnomeCanvasSimpleLineClass),
45                         (GtkClassInitFunc) gnome_canvas_simpleline_class_init,
46                         (GtkObjectInitFunc) gnome_canvas_simpleline_init,
47                         NULL, /* reserved_1 */
48                         NULL, /* reserved_2 */
49                         (GtkClassInitFunc) NULL
50                 };
51
52                 simpleline_type = gtk_type_unique (gnome_canvas_item_get_type (), &simpleline_info);
53         }
54
55         return simpleline_type;
56 }
57
58 static void
59 gnome_canvas_simpleline_class_init (GnomeCanvasSimpleLineClass *class)
60 {
61         GtkObjectClass *object_class;
62         GnomeCanvasItemClass *item_class;
63
64         object_class = (GtkObjectClass *) class;
65         item_class = (GnomeCanvasItemClass *) class;
66
67         parent_class = gtk_type_class (gnome_canvas_item_get_type ());
68
69         gtk_object_add_arg_type ("GnomeCanvasSimpleLine::x1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X1);
70         gtk_object_add_arg_type ("GnomeCanvasSimpleLine::y1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y1);
71         gtk_object_add_arg_type ("GnomeCanvasSimpleLine::x2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X2);
72         gtk_object_add_arg_type ("GnomeCanvasSimpleLine::y2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y2);
73         gtk_object_add_arg_type ("GnomeCanvasSimpleLine::color-rgba", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_COLOR_RGBA);
74
75         object_class->set_arg = gnome_canvas_simpleline_set_arg;
76         object_class->get_arg = gnome_canvas_simpleline_get_arg;
77
78         item_class->update = gnome_canvas_simpleline_update;
79         item_class->bounds = gnome_canvas_simpleline_bounds;
80         item_class->point = gnome_canvas_simpleline_point;
81         item_class->render = gnome_canvas_simpleline_render;
82         item_class->draw = gnome_canvas_simpleline_draw;
83 }
84
85 static void
86 gnome_canvas_simpleline_init (GnomeCanvasSimpleLine *simpleline)
87 {
88         simpleline->x1 = 0.0;
89         simpleline->y1 = 0.0;
90         simpleline->x2 = 0.0;
91         simpleline->y2 = 0.0;
92         simpleline->color = RGBA_TO_UINT(98,123,174,241);
93         simpleline->horizontal = TRUE; /* reset in the _update() method */
94         // GTK2FIX
95         // GNOME_CANVAS_ITEM(simpleline)->object.flags |= GNOME_CANVAS_ITEM_NO_AUTO_REDRAW;
96 }
97
98 static void
99 gnome_canvas_simpleline_bounds_world (GnomeCanvasItem *item, int* ix1, int* iy1, int* ix2, int* iy2)
100 {
101         double x1, x2, y1, y2;
102         ArtPoint i1, i2;
103         ArtPoint w1, w2;
104         double i2w[6];
105         GnomeCanvasSimpleLine *simpleline = GNOME_CANVAS_SIMPLELINE(item);
106
107         gnome_canvas_simpleline_bounds (item, &x1, &y1, &x2, &y2);
108
109         i1.x = x1;
110         i1.y = y1;
111         i2.x = x2;
112         i2.y = y2;
113         
114         gnome_canvas_item_i2w_affine (item, i2w);
115         art_affine_point (&w1, &i1, i2w);
116         art_affine_point (&w2, &i2, i2w);
117
118         *ix1 = (int) rint(w1.x);
119         *ix2 = (int) rint(w2.x);
120         *iy1 = (int) rint(w1.y);
121         *iy2 = (int) rint(w2.y);
122
123         /* the update rect has to be of non-zero width and height */
124
125         if (x1 == x2) {
126                 simpleline->horizontal = FALSE;
127                 *ix2 += 1;
128         } else {
129                 simpleline->horizontal = TRUE;
130                 *iy2 += 1;
131         }
132 }
133
134 static void 
135 gnome_canvas_simpleline_reset_bounds (GnomeCanvasItem *item)
136 {
137         int Ix1, Ix2, Iy1, Iy2;
138
139         gnome_canvas_simpleline_bounds_world (item, &Ix1, &Iy1, &Ix2, &Iy2);
140         gnome_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
141 }
142
143 /* 
144  * CANVAS CALLBACKS 
145  */
146
147 static void
148 gnome_canvas_simpleline_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
149 {
150         GnomeCanvasItem *item;
151         GnomeCanvasSimpleLine *simpleline;
152         int redraw;
153         int calc_bounds;
154
155         item = GNOME_CANVAS_ITEM (object);
156         simpleline = GNOME_CANVAS_SIMPLELINE (object);
157
158         redraw = FALSE;
159         calc_bounds = FALSE;
160
161         switch (arg_id) {
162         case ARG_X1:
163                 if (simpleline->x1 != GTK_VALUE_DOUBLE (*arg)) {
164                         simpleline->x1 = GTK_VALUE_DOUBLE (*arg);
165                         calc_bounds = TRUE;
166                 }
167                 break;
168
169         case ARG_Y1:
170                 if (simpleline->y1 != GTK_VALUE_DOUBLE (*arg)) {
171                         simpleline->y1 = GTK_VALUE_DOUBLE (*arg);
172                         calc_bounds = TRUE;
173                 }
174                 break;
175
176         case ARG_X2:
177                 if (simpleline->x2 != GTK_VALUE_DOUBLE (*arg)) {
178                         simpleline->x2 = GTK_VALUE_DOUBLE (*arg);
179                         calc_bounds = TRUE;
180                 }
181                 break;
182
183         case ARG_Y2:
184                 if (simpleline->y2 != GTK_VALUE_DOUBLE (*arg)) {
185                         simpleline->y2 = GTK_VALUE_DOUBLE (*arg);
186                         calc_bounds = TRUE;
187                 }
188                 break;
189
190         case ARG_COLOR_RGBA:
191                 if (simpleline->color != GTK_VALUE_INT(*arg)) {
192                         simpleline->color = GTK_VALUE_INT(*arg);
193                         UINT_TO_RGBA (simpleline->color, &simpleline->r, &simpleline->g, &simpleline->b, &simpleline->a);
194                         redraw = TRUE;
195                 }
196                 break;
197
198         default:
199                 break;
200         }
201         
202         if (calc_bounds) {
203
204                 gnome_canvas_item_request_update (item);
205
206         } else if (redraw) {
207
208                 int Ix1, Ix2, Iy1, Iy2;
209                 gnome_canvas_simpleline_bounds_world (item, &Ix1, &Iy1, &Ix2, &Iy2);
210                 gnome_canvas_request_redraw (item->canvas, Ix1, Iy1, Ix2, Iy2);
211         }
212 }
213
214 static void
215 gnome_canvas_simpleline_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
216 {
217         GnomeCanvasSimpleLine *simpleline;
218
219         simpleline = GNOME_CANVAS_SIMPLELINE (object);
220
221         switch (arg_id) {
222         case ARG_X1:
223                 GTK_VALUE_DOUBLE (*arg) = simpleline->x1;
224                 break;
225         case ARG_Y1:
226                 GTK_VALUE_DOUBLE (*arg) = simpleline->y1;
227                 break;
228         case ARG_X2:
229                 GTK_VALUE_DOUBLE (*arg) = simpleline->x2;
230                 break;
231         case ARG_Y2:
232                 GTK_VALUE_DOUBLE (*arg) = simpleline->y2;
233                 break;
234         case ARG_COLOR_RGBA:
235                 GTK_VALUE_INT (*arg) = simpleline->color;
236                 break;
237         default:
238                 arg->type = GTK_TYPE_INVALID;
239                 break;
240         }
241 }
242
243 static void
244 gnome_canvas_simpleline_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
245 {
246         GnomeCanvasSimpleLine *simpleline;
247         double x;
248         double y;
249
250         simpleline = GNOME_CANVAS_SIMPLELINE (item);
251
252         if (parent_class->update)
253                 (* parent_class->update) (item, affine, clip_path, flags);
254
255         gnome_canvas_simpleline_reset_bounds (item);
256
257         x = simpleline->x1;
258         y = simpleline->y1;
259
260         gnome_canvas_item_i2w (item, &x, &y);
261         gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &simpleline->bbox_ulx, &simpleline->bbox_uly);
262
263         x = simpleline->x2;
264         y = simpleline->y2;
265
266         gnome_canvas_item_i2w (item, &x, &y);
267         gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x, y, &simpleline->bbox_lrx, &simpleline->bbox_lry);
268 }
269
270 static void
271 gnome_canvas_simpleline_render (GnomeCanvasItem *item,
272                               GnomeCanvasBuf *buf)
273 {
274         GnomeCanvasSimpleLine *simpleline;
275         int end, begin;
276
277         simpleline = GNOME_CANVAS_SIMPLELINE (item);
278
279         if (parent_class->render) {
280                 (*parent_class->render) (item, buf);
281         }
282
283         if (buf->is_bg) {
284                 gnome_canvas_buf_ensure_buf (buf);
285                 buf->is_bg = FALSE;
286         }
287
288         // begin = MAX(simpleline->bbox_ulx,buf->rect.x0);
289         // end = MIN(simpleline->bbox_lrx,buf->rect.x1);
290         
291         begin = simpleline->bbox_ulx;
292         end = simpleline->bbox_lrx;
293
294         if (simpleline->color != 0) {
295                 if (simpleline->horizontal) {
296                         PAINT_HORIZA(buf, simpleline->r, simpleline->g, simpleline->b, simpleline->a, 
297                                      begin, end, simpleline->bbox_uly);
298                 } else {
299                         PAINT_VERTA(buf, simpleline->r, simpleline->g, simpleline->b, simpleline->a, 
300                                     begin, simpleline->bbox_uly, simpleline->bbox_lry);
301                 }
302         }
303 }
304
305 static void
306 gnome_canvas_simpleline_draw (GnomeCanvasItem *item,
307                             GdkDrawable *drawable,
308                             int x, int y,
309                             int width, int height)
310 {
311         GnomeCanvasSimpleLine *simpleline;
312
313         simpleline = GNOME_CANVAS_SIMPLELINE (item);
314
315         if (parent_class->draw) {
316                 (* parent_class->draw) (item, drawable, x, y, width, height);
317         }
318
319         fprintf (stderr, "please don't use the CanvasSimpleLine item in a non-aa Canvas\n");
320         abort ();
321 }
322
323 static void
324 gnome_canvas_simpleline_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
325 {
326         GnomeCanvasSimpleLine *simpleline = GNOME_CANVAS_SIMPLELINE (item);
327
328         *x1 = simpleline->x1;
329         *y1 = simpleline->y1;
330         *x2 = simpleline->x2;
331         *y2 = simpleline->y2;
332 }
333
334 static double
335 gnome_canvas_simpleline_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
336 {
337         GnomeCanvasSimpleLine *simpleline;
338         double x1, y1, x2, y2;
339         double dx, dy;
340
341         simpleline = GNOME_CANVAS_SIMPLELINE (item);
342
343         *actual_item = item;
344
345         /* Find the bounds for the rectangle plus its outline width */
346
347         gnome_canvas_simpleline_bounds (item, &x1, &y1, &x2, &y2);
348
349         /* Is point inside rectangle */
350         
351         if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
352                 return 0.0;
353         }
354
355         /* Point is outside rectangle */
356
357         if (x < x1)
358                 dx = x1 - x;
359         else if (x > x2)
360                 dx = x - x2;
361         else
362                 dx = 0.0;
363
364         if (y < y1)
365                 dy = y1 - y;
366         else if (y > y2)
367                 dy = y - y2;
368         else
369                 dy = 0.0;
370
371         return sqrt (dx * dx + dy * dy);
372 }