Function to change color lightness
[gmodulargraph.git] / src / gtkgraph-demo.c
blob7664fc6d0cdac9d44cccdb03205bd47a26f331c0
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 } GModularGraph_Wire;
142 #define G_MODULAR_GRAPH_WIRE(p) ((GModularGraph_Wire *) (p))
144 GModularGraph_Wire * g_modular_graph_wire_new (double x1, double y1, double angle1,
145 double x2, double y2, double angle2,
146 char * tooltip, unsigned color);
148 /* Canvas data */
149 GtkWidget * canvas;
150 GooCanvasItem * root_item;
151 static double rounding = 3;
153 static GModularGraph_Module * module[2] = {NULL, NULL};
155 void g_modular_graph_module_add_ports_group (GModularGraphPortsGroup ** ret, GModularGraph_Module * module, GModularGraphPortDirection direction);
157 static void canvas_text_size (GooCanvasItem * item, double * w, double * h)
159 PangoRectangle rect;
161 goo_canvas_text_get_natural_extents (GOO_CANVAS_TEXT (item), NULL, & rect);
162 if (w) *w = (double) PANGO_PIXELS (rect.width);
163 if (h) *h = (double) PANGO_PIXELS (rect.height);
166 static inline void
167 text_wanted_size (GooCanvasItem * item, double * w, double * h)
169 canvas_text_size (item, w, h);
170 if (w) *w += rounding * 2;
173 static void module_update_size (GModularGraph_Module * module)
175 double w = 0, h = 0;
176 double x = 0, y = 0;
177 GooCanvasBounds bounds;
179 g_object_get (module->layout, "x", & x, "y", & y, NULL);
180 goo_canvas_item_get_bounds (module->layout, & bounds);
181 w = bounds.x2 - bounds.x1 + x;
182 h = bounds.y2 - bounds.y1 + y;
184 double text_w, text_h;
185 text_wanted_size (module->caption, & text_w, & text_h);
186 if (w < text_w) w = text_w;
187 h += rounding;
188 w --; // Strangely, without this line right side of border is placed later by 1 pixel, relatively to output ports borders
189 g_object_set (module->box, "width", w, "height", h, NULL);
192 GModularGraph_Module * g_modular_graph_module_new (GooCanvasItem * parent,
193 char * caption, char * tooltip,
194 int placing, int x, int y)
196 GModularGraph_Module * module;
197 unsigned width = 50, height = 20;
199 /* Fundament */
200 module = calloc (1, sizeof (GModularGraph_Module));
201 module->group = goo_canvas_group_new (parent, "x", (double) x, "y", (double) y, "tooltip", tooltip, NULL);
203 /* Decoration */
204 module->outer_border = goo_canvas_rect_new (module->group,
205 - border_threshold / 2, - border_threshold / 2,
206 width + border_threshold, height + border_threshold,
207 "radius-x", rounding + border_threshold / 2, "radius-y", rounding + border_threshold / 2,
208 "stroke-color-rgba", 0x0000005f, NULL);
210 module->box = goo_canvas_rect_new (module->group,
211 border_threshold / 2, border_threshold / 2,
212 width - border_threshold, height - border_threshold,
213 "radius-x", rounding, "radius-y", rounding,
214 "stroke-color", "gray45", "fill-color", "gray30",
215 NULL);
217 module->inner_border = goo_canvas_rect_new (module->group,
218 border_threshold * 1.5, border_threshold * 1.5,
219 width - border_threshold * 3, height - border_threshold * 3,
220 "radius-x", rounding - border_threshold / 2, "radius-y", rounding - border_threshold / 2,
221 "stroke-color", "gray33", NULL);
223 g_signal_connect (G_OBJECT (module->box), "notify::width", G_CALLBACK (on_module_notify_width), module);
224 g_signal_connect (G_OBJECT (module->box), "notify::height", G_CALLBACK (on_module_notify_height), module);
226 /* Caption */
227 module->caption = goo_canvas_text_new (module->group, "",
228 rounding, 0, -1, GTK_ANCHOR_NORTH_WEST,
229 "font", "sans 8",
230 "fill-color", "white", NULL);
231 g_signal_connect (G_OBJECT (module->caption), "notify::text", G_CALLBACK (on_module_text_notify), module);
233 /* Predefined groups */
234 module->layout = goo_canvas_table_new (module->group, "y", 15.0, "column-spacing", 5.0, NULL);
235 g_modular_graph_module_add_ports_group (NULL, module, G_MODULAR_GRAPH_PORT_DIRECTION_IN);
236 g_modular_graph_module_add_ports_group (NULL, module, G_MODULAR_GRAPH_PORT_DIRECTION_OUT);
238 /* Dragging capabilities */
239 g_signal_connect (G_OBJECT (module->group), "button-press-event", G_CALLBACK (on_module_buttonPress_event), module);
240 g_signal_connect (G_OBJECT (module->group), "button-release-event", G_CALLBACK (on_module_buttonRelease_event), module);
242 /* Mouse over */
243 g_signal_connect (G_OBJECT (module->group), "enter-notify-event", G_CALLBACK (on_module_enterNotify_event), module);
244 g_signal_connect (G_OBJECT (module->group), "leave-notify-event", G_CALLBACK (on_module_leaveNotify_event), module);
246 g_object_set (G_OBJECT (module->caption), "text", caption, NULL);
247 return module;
250 void g_modular_graph_module_add_ports_group (GModularGraphPortsGroup ** ret, GModularGraph_Module * module, GModularGraphPortDirection direction)
252 GModularGraphPortsGroup * group;
253 GooCanvasItem * parent;
255 if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_IN || direction == G_MODULAR_GRAPH_PORT_DIRECTION_OUT)
256 parent = module->layout;
257 else parent = module->group;
259 group = calloc (1, sizeof(GModularGraphPortsGroup));
260 group->direction = direction;
261 group->container = goo_canvas_table_new (parent, "x", 0.0, "y", 0.0, "row-spacing", 1.0, "column-spacing", 0.0,
262 //"clip-path", "M 0 0 h 100 v 20 h -20 Z",
263 //"horz-grid-line-width", 1.0, "vert-grid-line-width", 1.0,
264 "stroke-color", "yellow", NULL);
265 if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_IN)
266 goo_canvas_item_set_child_properties (module->layout, group->container, "column", 0, "x-align", 0.0, NULL);
267 else if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_OUT)
268 goo_canvas_item_set_child_properties (module->layout, group->container, "column", 1, "x-align", 1.0, NULL);
270 goo_canvas_item_set_child_properties (module->layout, group->container, "y-align", 0.0, NULL);
272 module->ports = g_list_append (module->ports, group);
274 if (ret) * ret = group;
277 static double ports_group_update_width (GModularGraphPortsGroup * group)
279 double min_width = 0;
280 GList * sib = group->ports;
282 while (1)
284 if (G_MODULAR_GRAPH_PORT (sib->data)->min_width > min_width)
285 min_width = G_MODULAR_GRAPH_PORT (sib->data)->min_width;
287 if (! sib->next) break;
288 sib = sib->next;
290 sib = group->ports;
291 while (1)
293 g_object_set (G_MODULAR_GRAPH_PORT (sib->data)->box, "width", min_width, NULL);
294 if (! sib->next) break;
295 sib = sib->next;
297 return min_width;
300 void g_modular_graph_module_add_port (GModularGraph_Port ** ret,
301 GModularGraph_Module * module,
302 int direction,
303 char * name, char * tooltip)
305 /* Create ports group */
306 GModularGraphPortsGroup * group = NULL;
307 if (module->ports)
309 GList * elem = module->ports;
310 while (1)
312 if (G_MODULAR_GRAPH_PORTS_GROUP (elem->data)->direction == direction)
314 group = elem->data;
315 break;
317 if (! elem->next) break;
318 elem = elem->next;
321 if (! group)
323 g_modular_graph_module_add_ports_group (& group, module, direction);
326 GModularGraph_Port * port = calloc (1, sizeof (GModularGraph_Port));
328 /* Decoration */
329 port->box = goo_canvas_rect_new (group->container,
330 0.5, 0.5, 50, 5,
331 "tooltip", tooltip,
332 //"radius-x", rounding,
333 //"radius-y", rounding,
334 "line-width", border_threshold,
335 "stroke-color", "gray70",
336 "fill-color", "gray60",
337 NULL);
338 /* Caption */
339 port->text = goo_canvas_text_new (group->container, "",
340 rounding, 0, -1, GTK_ANCHOR_NORTH_WEST,
341 "tooltip", tooltip,
342 "font", "sans 8",
343 "fill-color", "gray90", NULL);
344 goo_canvas_item_set_child_properties (group->container, port->box, "row", group->p_count, "x-expand", TRUE, "x-fill", TRUE, NULL);
345 goo_canvas_item_set_child_properties (group->container, port->text, "row", group->p_count, "x-expand", TRUE, "x-fill", TRUE,
346 "left-padding", rounding, "x-align", 0.5, NULL);
348 g_signal_connect (G_OBJECT (port->text), "notify::text", G_CALLBACK (on_port_text_notify), port);
350 /* Wire point */
351 switch (direction)
353 case G_MODULAR_GRAPH_PORT_DIRECTION_IN:
354 port->direction = 180.0; break;
355 case G_MODULAR_GRAPH_PORT_DIRECTION_OUT:
356 port->direction = 0.0; break;
359 /* Add port to group */
360 port->ports_group = group;
361 if (! g_list_find (group->ports, port))
362 group->ports = g_list_append (group->ports, port);
364 /* Complete initialization */
365 g_object_set (G_OBJECT (port->text), "text", name, NULL);
366 module_update_size (module);
368 group->p_count++;
369 if (ret) *ret = port;
372 typedef
373 union {
374 struct {
375 uint8_t alpha;
376 uint8_t blue;
377 uint8_t green;
378 uint8_t red;
380 uint32_t value;
381 } Color;
383 static void sort_uint8_ptr (uint8_t ** v, size_t size)
385 uint8_t ** ptr, ** ptr_end;
386 ptr_end = size - 1 + v;
387 unsigned needs_repeat;
389 do {
390 needs_repeat = (0 == 0);
391 ptr = v;
392 while (ptr < ptr_end)
394 if (* ptr[0] > * ptr[1] )
396 uint8_t * tmp = ptr[0];
397 ptr[0] = ptr[1];
398 ptr[1] = tmp;
400 else
401 needs_repeat = (1 == 0);
403 ptr++;
406 while (needs_repeat);
409 void color_adjust_lightness (unsigned * value, double diff)
411 Color color;
412 color.value = * value;
413 double mid_relative;
414 double range;
416 if (diff > 1.0)
419 uint8_t * color_c[3] = {& color.red, & color.green, & color.blue};
420 sort_uint8_ptr ((void *)color_c, 3);
422 range = * color_c[2] - * color_c[0];
424 mid_relative = (range == 0.0) ? 0.0 : (* color_c[1] - * color_c[0]) / range;
425 * color_c[0] = (* color_c[0] * diff > 255) ? 255 : * color_c[0] * diff;
426 * color_c[2] = (* color_c[2] * diff > 255) ? 255 : * color_c[2] * diff;
427 if (* color_c[0] == 255)
428 * color_c[1] = 255;
429 else
430 * color_c[1] = * color_c[2] + (* color_c[2] - * color_c[0]) * mid_relative;
432 else
434 color.red *= diff;
435 color.green *= diff;
436 color.blue *= diff;
439 * value = color.value;
442 GModularGraph_Wire * g_modular_graph_wire_new (double x1, double y1, double angle1, double x2, double y2, double angle2, char * tooltip, unsigned color)
444 char * wire_data;
445 GModularGraph_Wire * wire;
446 wire = calloc (1, sizeof (GModularGraph_Wire));
447 wire->x1 = x1, wire->y1 = y1;
448 wire->x2 = x2, wire->y2 = y2;
449 wire->angle1 = angle1;
450 wire->angle2 = angle2;
452 wire->cx1 = wire->x1 + cos (wire->angle1 * G_PI / 180) * 50;
453 wire->cy1 = wire->y1 + sin (wire->angle1 * G_PI / 180) * 50;
454 wire->cx2 = wire->x2 + cos (wire->angle2 * G_PI / 180) * 50;
455 wire->cy2 = wire->y2 + sin (wire->angle2 * G_PI / 180) * 50;
456 asprintf (& wire_data, "M%i,%i C%i,%i %i,%i %i,%i",
457 (int) wire->x1, (int) wire->y1,
458 (int) wire->cx1, (int) wire->cy1,
459 (int) wire->cx2, (int) wire->cy2,
460 (int) wire->x2, (int) wire->y2);
462 wire->group = goo_canvas_group_new (root_item);
464 wire->path_b = goo_canvas_path_new (wire->group,
465 wire_data,
466 "line-width", 2.0,
467 "stroke-color-rgba", color,
468 "line-cap", CAIRO_LINE_CAP_BUTT, NULL);
470 unsigned color_t = color;
471 color_adjust_lightness (& color_t, 2.0);
472 wire->path_t = goo_canvas_path_new (wire->group,
473 wire_data,
474 "line-width", 1.0,
475 "stroke-color-rgba", color_t,
476 "line-cap", CAIRO_LINE_CAP_BUTT, NULL);
478 g_signal_connect (G_OBJECT (wire->group), "enter-notify-event", G_CALLBACK (wire_entered), wire);
479 g_signal_connect (G_OBJECT (wire->group), "leave-notify-event", G_CALLBACK (wire_left), wire);
480 g_object_set (wire->group, "tooltip", tooltip, NULL);
482 return wire;
485 int main( int argc, char ** argv )
487 GtkWidget * win;
488 GtkWidget * scroller;
490 gtk_init (& argc, & argv);
491 win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
492 g_signal_connect (G_OBJECT (win), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
494 scroller = gtk_scrolled_window_new (NULL, NULL);
495 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller), GTK_SHADOW_IN);
496 gtk_container_add (GTK_CONTAINER (win), scroller);
498 /* Create canvas widget */
499 canvas = goo_canvas_new ();
500 gtk_widget_set_size_request (canvas, 600, 450);
501 goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000);
502 g_object_set (G_OBJECT (canvas), "automatic-bounds", TRUE, NULL);
504 gtk_container_add (GTK_CONTAINER (scroller), canvas);
506 /* Root */
507 root_item = goo_canvas_get_root_item (GOO_CANVAS (canvas));
508 g_object_set (G_OBJECT (root_item), "antialias", CAIRO_ANTIALIAS_SUBPIXEL, NULL);
509 g_object_set (G_OBJECT (root_item), "line-join", CAIRO_LINE_JOIN_ROUND, NULL);
510 g_object_set (G_OBJECT (root_item), "line-cap", CAIRO_LINE_CAP_ROUND, NULL);
511 g_object_set (G_OBJECT (root_item), "line-width", border_threshold, NULL);
512 g_signal_connect (G_OBJECT (root_item), "button-press-enter", G_CALLBACK (on_root_buttonPress_event), NULL);
513 g_signal_connect (G_OBJECT (root_item), "button-press-enter", G_CALLBACK (on_root_buttonRelease_event), NULL);
515 module[0] = g_modular_graph_module_new (root_item, "Module 1", "Module 1 tip", 0, 50, 50);
516 g_modular_graph_module_add_port (NULL, module[0], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-1", "Port 1 tip");
517 g_modular_graph_module_add_port (NULL, module[0], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-2", "Port 2 tip");
518 module[1] = g_modular_graph_module_new (root_item, "Module 2", "Module 2 tip", 0, 200, 10);
519 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-1", "Port 1 tip");
520 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-2", "Port 2 tip");
521 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "input-3", "Port 3 tip");
522 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_OUT, "out-1", "Out 1 tip");
523 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_OUT, "out-2", "Out 2 tip");
525 /* 2. Connection */
526 g_modular_graph_wire_new (50, 100, 0.0, 300, 300, 180, "Test wire", 0x5f0000ff);
527 g_modular_graph_wire_new (50, 300, 0.0, 300, 100, 180, "Test wire", 0x5f0000ff);
529 /* * * * */
531 gtk_widget_set_has_tooltip (canvas, TRUE);
533 gtk_widget_show_all (win);
534 gtk_main ();
535 return 0;
538 /* Helpers (nothing yet) */
540 /* Root callbacks */
542 static gboolean on_root_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
544 return FALSE;
547 static gboolean on_root_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
549 return FALSE;
552 static gboolean on_root_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data)
554 return FALSE;
557 /* Module callbacks */
559 static gboolean on_module_enterNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data)
561 char
562 * inner_border_color = "gray40",
563 * outer_border_color = "gray70";
564 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "stroke-color", inner_border_color, NULL);
565 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "stroke-color", outer_border_color, NULL);
566 return FALSE;
569 static gboolean on_module_leaveNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data)
571 char
572 * inner_border_color = "gray33",
573 * outer_border_color = "gray45";
574 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "stroke-color", inner_border_color, NULL);
575 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "stroke-color", outer_border_color, NULL);
576 return FALSE;
579 static gboolean on_module_notify_width (GooCanvasItem * item, GParamSpec * event, gpointer data)
581 double w;
582 g_object_get (G_MODULAR_GRAPH_MODULE (data)->box, "width", & w, NULL);
583 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "width", w - border_threshold * 2, NULL);
584 g_object_set (G_MODULAR_GRAPH_MODULE (data)->outer_border, "width", w + border_threshold * 2, NULL);
585 return FALSE;
588 static gboolean on_module_notify_height (GooCanvasItem * item, GParamSpec * event, gpointer data)
590 double h;
591 g_object_get (G_MODULAR_GRAPH_MODULE (data)->box, "height", & h, NULL);
592 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "height", h - border_threshold * 2, NULL);
593 g_object_set (G_MODULAR_GRAPH_MODULE (data)->outer_border, "height", h + border_threshold * 2, NULL);
594 return FALSE;
597 #define DRAG_CB( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_cb)
598 #define DRAG_HOLD_X( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_hold_x)
599 #define DRAG_HOLD_Y( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_hold_y)
601 static gboolean drag_redraw = TRUE;
602 static unsigned drag_redraw_timeout_id = 0;
604 static gboolean drag_redraw_timeout (gpointer data)
606 drag_redraw = TRUE;
607 return TRUE;
610 static
611 gboolean on_module_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
613 if (event->button == drag_button)
615 g_object_get (G_OBJECT (item),
616 "x", & DRAG_HOLD_X (data),
617 "y", & DRAG_HOLD_Y (data), NULL);
618 DRAG_HOLD_X (data) = event->x - DRAG_HOLD_X (data);
619 DRAG_HOLD_Y (data) = event->y - DRAG_HOLD_Y (data);
621 DRAG_CB (data) = g_signal_connect (G_OBJECT (root_item), "motion-notify-event", G_CALLBACK (on_module_dragged), data);
622 drag_redraw_timeout_id = g_timeout_add (30, drag_redraw_timeout, NULL);
624 return FALSE;
627 static
628 gboolean on_module_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
630 if (event->button == drag_button)
632 g_source_remove (drag_redraw_timeout_id);
633 drag_redraw_timeout_id = 0;
634 if (DRAG_CB (data))
635 g_signal_handler_disconnect (G_OBJECT (root_item), DRAG_CB (data));
637 return FALSE;
640 static
641 gboolean on_module_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data)
643 if (drag_redraw)
645 g_object_set (G_MODULAR_GRAPH_MODULE (data)->group, "x", event->x - DRAG_HOLD_X (data), NULL);
646 g_object_set (G_MODULAR_GRAPH_MODULE (data)->group, "y", event->y - DRAG_HOLD_Y (data), NULL);
647 drag_redraw = FALSE;
649 return FALSE;
652 static gboolean on_module_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data)
654 double w, h;
655 text_wanted_size (item, &w, &h);
657 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "width", w, NULL);
658 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "height", h, NULL);
660 return FALSE;
663 #undef DRAG_CB
664 #undef DRAG_HOLD_X
665 #undef DRAG_HOLD_Y
667 /* Port callbacks */
669 static gboolean on_port_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data)
671 double w, h;
672 text_wanted_size (item, &w, &h);
673 if (G_MODULAR_GRAPH_PORT (data)->min_width == w) return FALSE;
675 G_MODULAR_GRAPH_PORT (data)->min_width = w;
676 ports_group_update_width (G_MODULAR_GRAPH_PORT (data)->ports_group);
677 g_object_set (G_MODULAR_GRAPH_PORT (data)->box, "height", h, NULL);
679 return FALSE;
682 /* Wire callbacks */
684 static
685 gboolean wire_entered (GooCanvasItem *item,
686 GooCanvasItem *target,
687 GdkEventCrossing *event,
688 gpointer data)
690 g_object_set (G_MODULAR_GRAPH_WIRE (data)->path_t, "stroke-color", "white", NULL);
691 return FALSE;
694 static
695 gboolean wire_left (GooCanvasItem *item,
696 GooCanvasItem *target,
697 GdkEventCrossing *event,
698 gpointer data)
700 g_object_set (G_MODULAR_GRAPH_WIRE (data)->path_t, "stroke-color", "violet", NULL);
701 return FALSE;