Fix color brightness adjustment function
[gmodulargraph.git] / src / gtkgraph-demo.c
blob1fa2d34cf45cd13cb8bdfe4ad8c944c28373aea2
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * gtkgraph-demo.c
4 * Copyright (C) Nikita Zlobin 2011 <nick87720z@gmail.com>
5 *
6 * gtkgraph is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * gtkgraph is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #define _GNU_SOURCE
22 #include <goocanvas.h>
23 #include <math.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
29 static gboolean on_root_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data);
30 static gboolean on_root_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data);
31 static gboolean on_root_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data);
33 static gboolean on_module_enterNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data);
34 static gboolean on_module_leaveNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data);
36 static gboolean on_module_notify_width (GooCanvasItem * item, GParamSpec * event, gpointer data);
37 static gboolean on_module_notify_height (GooCanvasItem * item, GParamSpec * event, gpointer data);
39 static gboolean on_module_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data);
40 static gboolean on_module_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data);
41 static gboolean on_module_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data);
43 static gboolean on_module_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data);
44 static gboolean on_port_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data);
46 static gboolean wire_entered (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data);
47 static gboolean wire_left (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data);
49 double border_threshold = 1.0;
51 #define drag_button 1
53 typedef
54 struct {
55 struct {
56 unsigned color;
57 float rounding;
58 struct {
59 unsigned threshold;
60 unsigned border_color;
61 } border;
62 struct {
63 unsigned shadow_color;
64 float shadow_size;
65 } shadow;
66 struct {
67 unsigned alignment;
68 char * font;
69 } caption;
70 } moduleBox;
71 } GModularGraphStyle;
73 typedef
74 struct {
75 GooCanvasItem * box; /* Background */
76 GooCanvasItem * outer_border;
77 GooCanvasItem * inner_border;
79 GtkOrientation * orientation;
81 GooCanvasItem * caption;
82 GooCanvasItem * group; /* Just a logical container, without any look */
83 GooCanvasItem * layout; /* Used to organize elements (caption, ports) */
85 /* List of ports groups */
86 GList * ports;
88 /* Dragging data */
89 double drag_hold_x, drag_hold_y;
90 unsigned drag_cb;
91 } GModularGraph_Module;
93 #define G_MODULAR_GRAPH_MODULE(p) ((GModularGraph_Module *) (p))
95 typedef enum {
96 G_MODULAR_GRAPH_PORT_DIRECTION_IN = 1,
97 G_MODULAR_GRAPH_PORT_DIRECTION_OUT
98 } GModularGraphPortDirection;
100 typedef
101 struct {
102 GList * ports;
103 GModularGraphPortDirection direction;
105 unsigned width;
106 unsigned p_count;
107 GooCanvasItem * container;
108 } GModularGraphPortsGroup;
110 #define G_MODULAR_GRAPH_PORTS_GROUP(p) ((GModularGraphPortsGroup *) (p))
112 typedef
113 struct {
114 GooCanvasItem * box;
115 GooCanvasItem * text;
116 GooCanvasItem * group;
117 GModularGraphPortsGroup * ports_group;
118 double min_width;
120 double wire_x, wire_y;
121 double direction; /* In deegreens. Also affects wire direction. */
122 } GModularGraph_Port;
124 #define G_MODULAR_GRAPH_PORT(p) ((GModularGraph_Port *) (p))
126 typedef
127 struct {
128 GooCanvasItem * path_b;
129 GooCanvasItem * path_t;
130 GooCanvasItem * group;
132 //char ** cmd_v;
133 //unsigned * cmd_len;
135 double x1, y1, cx1, cy1;
136 double x2, y2, cx2, cy2;
138 double angle1, angle2; /* In degreens */
139 unsigned color;
140 double blink;
141 double highlight;
142 } GModularGraph_Wire;
144 #define G_MODULAR_GRAPH_WIRE(p) ((GModularGraph_Wire *) (p))
146 GModularGraph_Wire * g_modular_graph_wire_new (double x1, double y1, double angle1,
147 double x2, double y2, double angle2,
148 char * tooltip, unsigned color);
150 /* Canvas data */
151 GtkWidget * canvas;
152 GooCanvasItem * root_item;
153 static double rounding = 3;
155 static GModularGraph_Module * module[2] = {NULL, NULL};
157 void g_modular_graph_module_add_ports_group (GModularGraphPortsGroup ** ret, GModularGraph_Module * module, GModularGraphPortDirection direction);
159 static void canvas_text_size (GooCanvasItem * item, double * w, double * h)
161 PangoRectangle rect;
163 goo_canvas_text_get_natural_extents (GOO_CANVAS_TEXT (item), NULL, & rect);
164 if (w) *w = (double) PANGO_PIXELS (rect.width);
165 if (h) *h = (double) PANGO_PIXELS (rect.height);
168 static inline void
169 text_wanted_size (GooCanvasItem * item, double * w, double * h)
171 canvas_text_size (item, w, h);
172 if (w) *w += rounding * 2;
175 static void module_update_size (GModularGraph_Module * module)
177 double w = 0, h = 0;
178 double x = 0, y = 0;
179 GooCanvasBounds bounds;
181 g_object_get (module->layout, "x", & x, "y", & y, NULL);
182 goo_canvas_item_get_bounds (module->layout, & bounds);
183 w = bounds.x2 - bounds.x1 + x;
184 h = bounds.y2 - bounds.y1 + y;
186 double text_w, text_h;
187 text_wanted_size (module->caption, & text_w, & text_h);
188 if (w < text_w) w = text_w;
189 h += rounding;
190 w --; // Strangely, without this line right side of border is placed later by 1 pixel, relatively to output ports borders
191 g_object_set (module->box, "width", w, "height", h, NULL);
194 GModularGraph_Module * g_modular_graph_module_new (GooCanvasItem * parent,
195 char * caption, char * tooltip,
196 int placing, int x, int y)
198 GModularGraph_Module * module;
199 unsigned width = 50, height = 20;
201 /* Fundament */
202 module = calloc (1, sizeof (GModularGraph_Module));
203 module->group = goo_canvas_group_new (parent, "x", (double) x, "y", (double) y, "tooltip", tooltip, NULL);
205 /* Decoration */
206 module->outer_border = goo_canvas_rect_new (module->group,
207 - border_threshold / 2, - border_threshold / 2,
208 width + border_threshold, height + border_threshold,
209 "radius-x", rounding + border_threshold / 2, "radius-y", rounding + border_threshold / 2,
210 "stroke-color-rgba", 0x0000005f, NULL);
212 module->box = goo_canvas_rect_new (module->group,
213 border_threshold / 2, border_threshold / 2,
214 width - border_threshold, height - border_threshold,
215 "radius-x", rounding, "radius-y", rounding,
216 "stroke-color", "gray45", "fill-color", "gray30",
217 NULL);
219 module->inner_border = goo_canvas_rect_new (module->group,
220 border_threshold * 1.5, border_threshold * 1.5,
221 width - border_threshold * 3, height - border_threshold * 3,
222 "radius-x", rounding - border_threshold / 2, "radius-y", rounding - border_threshold / 2,
223 "stroke-color", "gray33", NULL);
225 g_signal_connect (G_OBJECT (module->box), "notify::width", G_CALLBACK (on_module_notify_width), module);
226 g_signal_connect (G_OBJECT (module->box), "notify::height", G_CALLBACK (on_module_notify_height), module);
228 /* Caption */
229 module->caption = goo_canvas_text_new (module->group, "",
230 rounding, 0, -1, GTK_ANCHOR_NORTH_WEST,
231 "font", "sans 8",
232 "fill-color", "white", NULL);
233 g_signal_connect (G_OBJECT (module->caption), "notify::text", G_CALLBACK (on_module_text_notify), module);
235 /* Predefined groups */
236 module->layout = goo_canvas_table_new (module->group, "y", 15.0, "column-spacing", 5.0, NULL);
237 g_modular_graph_module_add_ports_group (NULL, module, G_MODULAR_GRAPH_PORT_DIRECTION_IN);
238 g_modular_graph_module_add_ports_group (NULL, module, G_MODULAR_GRAPH_PORT_DIRECTION_OUT);
240 /* Dragging capabilities */
241 g_signal_connect (G_OBJECT (module->group), "button-press-event", G_CALLBACK (on_module_buttonPress_event), module);
242 g_signal_connect (G_OBJECT (module->group), "button-release-event", G_CALLBACK (on_module_buttonRelease_event), module);
244 /* Mouse over */
245 g_signal_connect (G_OBJECT (module->group), "enter-notify-event", G_CALLBACK (on_module_enterNotify_event), module);
246 g_signal_connect (G_OBJECT (module->group), "leave-notify-event", G_CALLBACK (on_module_leaveNotify_event), module);
248 g_object_set (G_OBJECT (module->caption), "text", caption, NULL);
249 return module;
252 void g_modular_graph_module_add_ports_group (GModularGraphPortsGroup ** ret, GModularGraph_Module * module, GModularGraphPortDirection direction)
254 GModularGraphPortsGroup * group;
255 GooCanvasItem * parent;
257 if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_IN || direction == G_MODULAR_GRAPH_PORT_DIRECTION_OUT)
258 parent = module->layout;
259 else parent = module->group;
261 group = calloc (1, sizeof(GModularGraphPortsGroup));
262 group->direction = direction;
263 group->container = goo_canvas_table_new (parent, "x", 0.0, "y", 0.0, "row-spacing", 1.0, "column-spacing", 0.0,
264 //"clip-path", "M 0 0 h 100 v 20 h -20 Z",
265 //"horz-grid-line-width", 1.0, "vert-grid-line-width", 1.0,
266 "stroke-color", "yellow", NULL);
267 if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_IN)
268 goo_canvas_item_set_child_properties (module->layout, group->container, "column", 0, "x-align", 0.0, NULL);
269 else if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_OUT)
270 goo_canvas_item_set_child_properties (module->layout, group->container, "column", 1, "x-align", 1.0, NULL);
272 goo_canvas_item_set_child_properties (module->layout, group->container, "y-align", 0.0, NULL);
274 module->ports = g_list_append (module->ports, group);
276 if (ret) * ret = group;
279 static double ports_group_update_width (GModularGraphPortsGroup * group)
281 double min_width = 0;
282 GList * sib = group->ports;
284 while (1)
286 if (G_MODULAR_GRAPH_PORT (sib->data)->min_width > min_width)
287 min_width = G_MODULAR_GRAPH_PORT (sib->data)->min_width;
289 if (! sib->next) break;
290 sib = sib->next;
292 sib = group->ports;
293 while (1)
295 g_object_set (G_MODULAR_GRAPH_PORT (sib->data)->box, "width", min_width, NULL);
296 if (! sib->next) break;
297 sib = sib->next;
299 return min_width;
302 void g_modular_graph_module_add_port (GModularGraph_Port ** ret,
303 GModularGraph_Module * module,
304 int direction,
305 char * name, char * tooltip)
307 /* Create ports group */
308 GModularGraphPortsGroup * group = NULL;
309 if (module->ports)
311 GList * elem = module->ports;
312 while (1)
314 if (G_MODULAR_GRAPH_PORTS_GROUP (elem->data)->direction == direction)
316 group = elem->data;
317 break;
319 if (! elem->next) break;
320 elem = elem->next;
323 if (! group)
325 g_modular_graph_module_add_ports_group (& group, module, direction);
328 GModularGraph_Port * port = calloc (1, sizeof (GModularGraph_Port));
330 /* Decoration */
331 port->box = goo_canvas_rect_new (group->container,
332 0.5, 0.5, 50, 5,
333 "tooltip", tooltip,
334 //"radius-x", rounding,
335 //"radius-y", rounding,
336 "line-width", border_threshold,
337 "stroke-color", "gray70",
338 "fill-color", "gray60",
339 NULL);
340 /* Caption */
341 port->text = goo_canvas_text_new (group->container, "",
342 rounding, 0, -1, GTK_ANCHOR_NORTH_WEST,
343 "tooltip", tooltip,
344 "font", "sans 8",
345 "fill-color", "gray90", NULL);
346 goo_canvas_item_set_child_properties (group->container, port->box, "row", group->p_count, "x-expand", TRUE, "x-fill", TRUE, NULL);
347 goo_canvas_item_set_child_properties (group->container, port->text, "row", group->p_count, "x-expand", TRUE, "x-fill", TRUE,
348 "left-padding", rounding, "x-align", 0.5, NULL);
350 g_signal_connect (G_OBJECT (port->text), "notify::text", G_CALLBACK (on_port_text_notify), port);
352 /* Wire point */
353 switch (direction)
355 case G_MODULAR_GRAPH_PORT_DIRECTION_IN:
356 port->direction = 180.0; break;
357 case G_MODULAR_GRAPH_PORT_DIRECTION_OUT:
358 port->direction = 0.0; break;
361 /* Add port to group */
362 port->ports_group = group;
363 if (! g_list_find (group->ports, port))
364 group->ports = g_list_append (group->ports, port);
366 /* Complete initialization */
367 g_object_set (G_OBJECT (port->text), "text", name, NULL);
368 module_update_size (module);
370 group->p_count++;
371 if (ret) *ret = port;
374 typedef
375 union {
376 struct {
377 uint8_t alpha;
378 uint8_t blue;
379 uint8_t green;
380 uint8_t red;
382 uint32_t value;
383 } Color;
385 static void sort_uint8_ptr (uint8_t ** v, size_t size)
387 uint8_t ** ptr, ** ptr_end;
388 ptr_end = size - 1 + v;
389 unsigned needs_repeat;
391 do {
392 needs_repeat = (0 == 0);
393 ptr = v;
394 while (ptr < ptr_end)
396 if (* ptr[0] > * ptr[1] )
398 uint8_t * tmp = ptr[0];
399 ptr[0] = ptr[1];
400 ptr[1] = tmp;
402 else
403 needs_repeat = (1 == 0);
405 ptr++;
408 while (needs_repeat);
411 void color_adjust_lightness (unsigned * value, double diff)
413 Color color;
414 color.value = * value;
415 double mid_relative;
416 double range;
418 if (diff > 1.0)
420 uint8_t * color_c[0] = & color.red, color_c[1] = & color.green, color_c[2] = & color.blue;
421 sort_uint8_ptr ((void *)color_c, 3);
423 range = * color_c[2] - * color_c[0];
425 mid_relative = (range == 0.0) ? 0.0 : (* color_c[1] - * color_c[0]) / range;
426 * color_c[0] = (* color_c[0] * diff > 255) ? 255 : * color_c[0] * diff;
427 * color_c[2] = (* color_c[2] * diff > 255) ? 255 : * color_c[2] * diff;
429 if (* color_c[0] == 255)
430 * color_c[1] = 255;
431 else
432 * color_c[1] = * color_c[0] + (* color_c[2] - * color_c[0]) * mid_relative;
434 else
436 color.red *= diff;
437 color.green *= diff;
438 color.blue *= diff;
441 * value = color.value;
444 GModularGraph_Wire * g_modular_graph_wire_new (double x1, double y1, double angle1, double x2, double y2, double angle2, char * tooltip, unsigned color)
446 char * wire_data;
447 GModularGraph_Wire * wire;
448 wire = calloc (1, sizeof (GModularGraph_Wire));
449 wire->x1 = x1, wire->y1 = y1;
450 wire->x2 = x2, wire->y2 = y2;
451 wire->angle1 = angle1;
452 wire->angle2 = angle2;
453 wire->color = color;
454 wire->blink = 1.5;
455 wire->highlight = 1.5;
457 wire->cx1 = wire->x1 + cos (wire->angle1 * G_PI / 180) * 50;
458 wire->cy1 = wire->y1 + sin (wire->angle1 * G_PI / 180) * 50;
459 wire->cx2 = wire->x2 + cos (wire->angle2 * G_PI / 180) * 50;
460 wire->cy2 = wire->y2 + sin (wire->angle2 * G_PI / 180) * 50;
461 asprintf (& wire_data, "M%i,%i C%i,%i %i,%i %i,%i",
462 (int) wire->x1, (int) wire->y1,
463 (int) wire->cx1, (int) wire->cy1,
464 (int) wire->cx2, (int) wire->cy2,
465 (int) wire->x2, (int) wire->y2);
467 wire->group = goo_canvas_group_new (root_item);
469 unsigned color_b = color;
470 color_adjust_lightness (& color_b, 1 / wire->blink);
471 wire->path_b = goo_canvas_path_new (wire->group,
472 wire_data,
473 "line-width", 3.0,
474 "stroke-color-rgba", color_b,
475 "line-cap", CAIRO_LINE_CAP_BUTT, NULL);
477 unsigned color_t = color;
478 color_adjust_lightness (& color_t, wire->blink);
479 wire->path_t = goo_canvas_path_new (wire->group,
480 wire_data,
481 "line-width", 1.5,
482 "stroke-color-rgba", color_t,
483 "line-cap", CAIRO_LINE_CAP_BUTT, NULL);
485 g_signal_connect (G_OBJECT (wire->group), "enter-notify-event", G_CALLBACK (wire_entered), wire);
486 g_signal_connect (G_OBJECT (wire->group), "leave-notify-event", G_CALLBACK (wire_left), wire);
487 g_object_set (wire->group, "tooltip", tooltip, NULL);
489 return wire;
492 int main( int argc, char ** argv )
494 GtkWidget * win;
495 GtkWidget * scroller;
497 gtk_init (& argc, & argv);
498 win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
499 g_signal_connect (G_OBJECT (win), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
501 scroller = gtk_scrolled_window_new (NULL, NULL);
502 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller), GTK_SHADOW_IN);
503 gtk_container_add (GTK_CONTAINER (win), scroller);
505 /* Create canvas widget */
506 canvas = goo_canvas_new ();
507 gtk_widget_set_size_request (canvas, 600, 450);
508 goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000);
509 g_object_set (G_OBJECT (canvas), "automatic-bounds", TRUE, NULL);
511 gtk_container_add (GTK_CONTAINER (scroller), canvas);
513 /* Root */
514 root_item = goo_canvas_get_root_item (GOO_CANVAS (canvas));
515 g_object_set (G_OBJECT (root_item), "antialias", CAIRO_ANTIALIAS_SUBPIXEL, NULL);
516 g_object_set (G_OBJECT (root_item), "line-join", CAIRO_LINE_JOIN_ROUND, NULL);
517 g_object_set (G_OBJECT (root_item), "line-cap", CAIRO_LINE_CAP_ROUND, NULL);
518 g_object_set (G_OBJECT (root_item), "line-width", border_threshold, NULL);
519 g_signal_connect (G_OBJECT (root_item), "button-press-enter", G_CALLBACK (on_root_buttonPress_event), NULL);
520 g_signal_connect (G_OBJECT (root_item), "button-press-enter", G_CALLBACK (on_root_buttonRelease_event), NULL);
522 module[0] = g_modular_graph_module_new (root_item, "Module 1", "Module 1 tip", 0, 50, 50);
523 g_modular_graph_module_add_port (NULL, module[0], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-1", "Port 1 tip");
524 g_modular_graph_module_add_port (NULL, module[0], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-2", "Port 2 tip");
525 module[1] = g_modular_graph_module_new (root_item, "Module 2", "Module 2 tip", 0, 200, 10);
526 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-1", "Port 1 tip");
527 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-2", "Port 2 tip");
528 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "input-3", "Port 3 tip");
529 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_OUT, "out-1", "Out 1 tip");
530 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_OUT, "out-2", "Out 2 tip");
532 /* 2. Connection */
533 g_modular_graph_wire_new (50, 100, 0.0, 300, 300, 180, "Test wire", 0x5f0000ff);
534 g_modular_graph_wire_new (50, 300, 0.0, 300, 100, 180, "Test wire", 0x5f0000ff);
536 /* * * * */
538 gtk_widget_set_has_tooltip (canvas, TRUE);
540 gtk_widget_show_all (win);
541 gtk_main ();
542 return 0;
545 /* Helpers (nothing yet) */
547 /* Root callbacks */
549 static gboolean on_root_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
551 return FALSE;
554 static gboolean on_root_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
556 return FALSE;
559 static gboolean on_root_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data)
561 return FALSE;
564 /* Module callbacks */
566 static gboolean on_module_enterNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data)
568 char
569 * inner_border_color = "gray40",
570 * outer_border_color = "gray70";
571 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "stroke-color", inner_border_color, NULL);
572 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "stroke-color", outer_border_color, NULL);
573 return FALSE;
576 static gboolean on_module_leaveNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data)
578 char
579 * inner_border_color = "gray33",
580 * outer_border_color = "gray45";
581 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "stroke-color", inner_border_color, NULL);
582 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "stroke-color", outer_border_color, NULL);
583 return FALSE;
586 static gboolean on_module_notify_width (GooCanvasItem * item, GParamSpec * event, gpointer data)
588 double w;
589 g_object_get (G_MODULAR_GRAPH_MODULE (data)->box, "width", & w, NULL);
590 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "width", w - border_threshold * 2, NULL);
591 g_object_set (G_MODULAR_GRAPH_MODULE (data)->outer_border, "width", w + border_threshold * 2, NULL);
592 return FALSE;
595 static gboolean on_module_notify_height (GooCanvasItem * item, GParamSpec * event, gpointer data)
597 double h;
598 g_object_get (G_MODULAR_GRAPH_MODULE (data)->box, "height", & h, NULL);
599 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "height", h - border_threshold * 2, NULL);
600 g_object_set (G_MODULAR_GRAPH_MODULE (data)->outer_border, "height", h + border_threshold * 2, NULL);
601 return FALSE;
604 #define DRAG_CB( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_cb)
605 #define DRAG_HOLD_X( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_hold_x)
606 #define DRAG_HOLD_Y( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_hold_y)
608 static gboolean drag_redraw = TRUE;
609 static unsigned drag_redraw_timeout_id = 0;
611 static gboolean drag_redraw_timeout (gpointer data)
613 drag_redraw = TRUE;
614 return TRUE;
617 static
618 gboolean on_module_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
620 if (event->button == drag_button)
622 g_object_get (G_OBJECT (item),
623 "x", & DRAG_HOLD_X (data),
624 "y", & DRAG_HOLD_Y (data), NULL);
625 DRAG_HOLD_X (data) = event->x - DRAG_HOLD_X (data);
626 DRAG_HOLD_Y (data) = event->y - DRAG_HOLD_Y (data);
628 DRAG_CB (data) = g_signal_connect (G_OBJECT (root_item), "motion-notify-event", G_CALLBACK (on_module_dragged), data);
629 drag_redraw_timeout_id = g_timeout_add (30, drag_redraw_timeout, NULL);
631 return FALSE;
634 static
635 gboolean on_module_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
637 if (event->button == drag_button)
639 g_source_remove (drag_redraw_timeout_id);
640 drag_redraw_timeout_id = 0;
641 if (DRAG_CB (data))
642 g_signal_handler_disconnect (G_OBJECT (root_item), DRAG_CB (data));
644 return FALSE;
647 static
648 gboolean on_module_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data)
650 if (drag_redraw)
652 g_object_set (G_MODULAR_GRAPH_MODULE (data)->group, "x", event->x - DRAG_HOLD_X (data), NULL);
653 g_object_set (G_MODULAR_GRAPH_MODULE (data)->group, "y", event->y - DRAG_HOLD_Y (data), NULL);
654 drag_redraw = FALSE;
656 return FALSE;
659 static gboolean on_module_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data)
661 double w, h;
662 text_wanted_size (item, &w, &h);
664 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "width", w, NULL);
665 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "height", h, NULL);
667 return FALSE;
670 #undef DRAG_CB
671 #undef DRAG_HOLD_X
672 #undef DRAG_HOLD_Y
674 /* Port callbacks */
676 static gboolean on_port_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data)
678 double w, h;
679 text_wanted_size (item, &w, &h);
680 if (G_MODULAR_GRAPH_PORT (data)->min_width == w) return FALSE;
682 G_MODULAR_GRAPH_PORT (data)->min_width = w;
683 ports_group_update_width (G_MODULAR_GRAPH_PORT (data)->ports_group);
684 g_object_set (G_MODULAR_GRAPH_PORT (data)->box, "height", h, NULL);
686 return FALSE;
689 /* Wire callbacks */
691 static
692 gboolean wire_entered (GooCanvasItem *item,
693 GooCanvasItem *target,
694 GdkEventCrossing *event,
695 gpointer data)
697 unsigned color = G_MODULAR_GRAPH_WIRE (data)->color;
698 color_adjust_lightness (& color, G_MODULAR_GRAPH_WIRE (data)->blink * G_MODULAR_GRAPH_WIRE (data)->highlight);
700 g_object_set (G_MODULAR_GRAPH_WIRE (data)->path_t, "stroke-color-rgba", color, NULL);
701 return FALSE;
704 static
705 gboolean wire_left (GooCanvasItem *item,
706 GooCanvasItem *target,
707 GdkEventCrossing *event,
708 gpointer data)
710 unsigned color = G_MODULAR_GRAPH_WIRE (data)->color;
711 color_adjust_lightness (& color, G_MODULAR_GRAPH_WIRE (data)->blink);
713 g_object_set (G_MODULAR_GRAPH_WIRE (data)->path_t, "stroke-color-rgba", color, NULL);
714 return FALSE;