Began to implement connections. Incompleted.
[gmodulargraph.git] / src / gtkgraph-demo.c
blob05ff48483c54c9bec1b672e68aaa29a7cb85cb4c
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);
45 static gboolean on_port_size_notify (GooCanvasItem * item, GParamSpec * event, gpointer data);
46 static gboolean on_port_moved (GooCanvasItem * item, GParamSpec * event, gpointer data);
48 static gboolean wire_entered (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data);
49 static gboolean wire_left (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data);
50 static gboolean on_wire_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data);
52 double border_threshold = 1.0;
54 #define drag_button 1
56 typedef
57 struct {
58 struct {
59 unsigned color;
60 float rounding;
61 struct {
62 unsigned threshold;
63 unsigned border_color;
64 } border;
65 struct {
66 unsigned shadow_color;
67 float shadow_size;
68 } shadow;
69 struct {
70 unsigned alignment;
71 char * font;
72 } caption;
73 } moduleBox;
74 } GModularGraphStyle;
76 typedef
77 struct {
78 GooCanvasItem * box; /* Background */
79 GooCanvasItem * outer_border;
80 GooCanvasItem * inner_border;
82 GtkOrientation * orientation;
84 GooCanvasItem * caption;
85 GooCanvasItem * group; /* Just a logical container, without any look */
86 GooCanvasItem * layout; /* Used to organize elements (caption, ports) */
88 /* List of ports groups */
89 GList * ports;
90 GList * connections;
92 /* Dragging data */
93 double drag_hold_x, drag_hold_y;
94 unsigned drag_cb;
95 } GModularGraph_Module;
97 #define G_MODULAR_GRAPH_MODULE(p) ((GModularGraph_Module *) (p))
99 typedef enum {
100 G_MODULAR_GRAPH_PORT_DIRECTION_IN = 1,
101 G_MODULAR_GRAPH_PORT_DIRECTION_OUT
102 } GModularGraphPortDirection;
104 typedef
105 struct {
106 GList * ports;
107 GModularGraphPortDirection direction;
109 unsigned width;
110 unsigned p_count;
111 GooCanvasItem * container;
113 GModularGraph_Module * module;
114 } GModularGraphPortsGroup;
116 #define G_MODULAR_GRAPH_PORTS_GROUP(p) ((GModularGraphPortsGroup *) (p))
118 typedef
119 struct {
120 GooCanvasItem * box;
121 GooCanvasItem * text;
122 GooCanvasItem * group;
123 GModularGraphPortsGroup * ports_group;
124 double min_width;
126 GList * connections;
127 double wire_x, wire_y;
128 double direction; /* In deegreens. Also affects wire direction. */
129 } GModularGraph_Port;
131 #define G_MODULAR_GRAPH_PORT(p) ((GModularGraph_Port *) (p))
133 typedef
134 struct {
135 GooCanvasItem * path_b;
136 GooCanvasItem * path_t;
137 GooCanvasItem * group;
139 //char ** cmd_v;
140 //unsigned * cmd_len;
142 double x1, y1, cx1, cy1;
143 double x2, y2, cx2, cy2;
145 double angle1, angle2; /* In degreens */
146 unsigned color;
147 double blink;
148 double highlight;
149 } GModularGraph_Wire;
151 #define G_MODULAR_GRAPH_WIRE(p) ((GModularGraph_Wire *) (p))
153 typedef
154 struct {
155 GModularGraph_Wire * wire;
156 GModularGraph_Port * port1;
157 GModularGraph_Port * port2;
158 } GModularGraph_Connection;
160 #define G_MODULAR_GRAPH_CONNECTION(p) ((GModularGraph_Connection *) (p))
162 GModularGraph_Wire * g_modular_graph_wire_new (double x1, double y1, double angle1,
163 double x2, double y2, double angle2,
164 char * tooltip, unsigned color);
166 /* Canvas data */
167 GtkWidget * canvas;
168 GooCanvasItem * root_item;
169 static double rounding = 3;
171 static GModularGraph_Module * module[2] = {NULL, NULL};
173 void g_modular_graph_module_add_ports_group (GModularGraphPortsGroup ** ret, GModularGraph_Module * module, GModularGraphPortDirection direction);
175 static void canvas_text_size (GooCanvasItem * item, double * w, double * h)
177 PangoRectangle rect;
179 goo_canvas_text_get_natural_extents (GOO_CANVAS_TEXT (item), NULL, & rect);
180 if (w) *w = (double) PANGO_PIXELS (rect.width);
181 if (h) *h = (double) PANGO_PIXELS (rect.height);
184 static inline void
185 text_wanted_size (GooCanvasItem * item, double * w, double * h)
187 canvas_text_size (item, w, h);
188 if (w) *w += rounding * 2;
191 static void module_update_size (GModularGraph_Module * module)
193 double w = 0, h = 0;
194 double x = 0, y = 0;
195 GooCanvasBounds bounds;
197 g_object_get (module->layout, "x", & x, "y", & y, NULL);
198 goo_canvas_item_get_bounds (module->layout, & bounds);
199 w = bounds.x2 - bounds.x1 + x;
200 h = bounds.y2 - bounds.y1 + y;
202 double text_w, text_h;
203 text_wanted_size (module->caption, & text_w, & text_h);
204 if (w < text_w) w = text_w;
205 h += rounding;
206 w --; // Strangely, without this line right side of border is placed later by 1 pixel, relatively to output ports borders
207 g_object_set (module->box, "width", w, "height", h, NULL);
210 GModularGraph_Module * g_modular_graph_module_new (GooCanvasItem * parent,
211 char * caption, char * tooltip,
212 int placing, int x, int y)
214 GModularGraph_Module * module;
215 unsigned width = 50, height = 20;
217 /* Fundament */
218 module = calloc (1, sizeof (GModularGraph_Module));
219 module->group = goo_canvas_group_new (parent, "x", (double) x, "y", (double) y, "tooltip", tooltip, NULL);
221 /* Decoration */
222 module->outer_border = goo_canvas_rect_new (module->group,
223 - border_threshold / 2, - border_threshold / 2,
224 width + border_threshold, height + border_threshold,
225 "radius-x", rounding + border_threshold / 2, "radius-y", rounding + border_threshold / 2,
226 "stroke-color-rgba", 0x0000005f, NULL);
228 module->box = goo_canvas_rect_new (module->group,
229 border_threshold / 2, border_threshold / 2,
230 width - border_threshold, height - border_threshold,
231 "radius-x", rounding, "radius-y", rounding,
232 "stroke-color", "gray45", "fill-color", "gray30",
233 NULL);
235 module->inner_border = goo_canvas_rect_new (module->group,
236 border_threshold * 1.5, border_threshold * 1.5,
237 width - border_threshold * 3, height - border_threshold * 3,
238 "radius-x", rounding - border_threshold / 2, "radius-y", rounding - border_threshold / 2,
239 "stroke-color", "gray33", NULL);
241 g_signal_connect (G_OBJECT (module->box), "notify::width", G_CALLBACK (on_module_notify_width), module);
242 g_signal_connect (G_OBJECT (module->box), "notify::height", G_CALLBACK (on_module_notify_height), module);
244 /* Caption */
245 module->caption = goo_canvas_text_new (module->group, "",
246 rounding, 0, -1, GTK_ANCHOR_NORTH_WEST,
247 "font", "sans 8",
248 "fill-color", "white", NULL);
249 g_signal_connect (G_OBJECT (module->caption), "notify::text", G_CALLBACK (on_module_text_notify), module);
251 /* Predefined groups */
252 module->layout = goo_canvas_table_new (module->group, "y", 15.0, "column-spacing", 5.0, NULL);
253 g_modular_graph_module_add_ports_group (NULL, module, G_MODULAR_GRAPH_PORT_DIRECTION_IN);
254 g_modular_graph_module_add_ports_group (NULL, module, G_MODULAR_GRAPH_PORT_DIRECTION_OUT);
256 /* Dragging capabilities */
257 g_signal_connect (G_OBJECT (module->group), "button-press-event", G_CALLBACK (on_module_buttonPress_event), module);
258 g_signal_connect (G_OBJECT (module->group), "button-release-event", G_CALLBACK (on_module_buttonRelease_event), module);
260 /* Mouse over */
261 g_signal_connect (G_OBJECT (module->group), "enter-notify-event", G_CALLBACK (on_module_enterNotify_event), module);
262 g_signal_connect (G_OBJECT (module->group), "leave-notify-event", G_CALLBACK (on_module_leaveNotify_event), module);
264 module->connections = NULL;
265 g_object_set (G_OBJECT (module->caption), "text", caption, NULL);
266 return module;
269 void g_modular_graph_module_add_ports_group (GModularGraphPortsGroup ** ret, GModularGraph_Module * module, GModularGraphPortDirection direction)
271 GModularGraphPortsGroup * group;
272 GooCanvasItem * parent;
274 if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_IN || direction == G_MODULAR_GRAPH_PORT_DIRECTION_OUT)
275 parent = module->layout;
276 else parent = module->group;
278 group = calloc (1, sizeof(GModularGraphPortsGroup));
279 group->direction = direction;
280 group->container = goo_canvas_table_new (parent, "x", 0.0, "y", 0.0, "row-spacing", 1.0, "column-spacing", 0.0,
281 //"clip-path", "M 0 0 h 100 v 20 h -20 Z",
282 //"horz-grid-line-width", 1.0, "vert-grid-line-width", 1.0,
283 "stroke-color", "yellow", NULL);
284 if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_IN)
285 goo_canvas_item_set_child_properties (module->layout, group->container, "column", 0, "x-align", 0.0, NULL);
286 else if (direction == G_MODULAR_GRAPH_PORT_DIRECTION_OUT)
287 goo_canvas_item_set_child_properties (module->layout, group->container, "column", 1, "x-align", 1.0, NULL);
289 goo_canvas_item_set_child_properties (module->layout, group->container, "y-align", 0.0, NULL);
291 module->ports = g_list_append (module->ports, group);
292 group->module = module;
294 if (ret) * ret = group;
297 static double ports_group_update_width (GModularGraphPortsGroup * group)
299 double min_width = 0;
300 GList * sib = group->ports;
302 while (1)
304 if (G_MODULAR_GRAPH_PORT (sib->data)->min_width > min_width)
305 min_width = G_MODULAR_GRAPH_PORT (sib->data)->min_width;
307 if (! sib->next) break;
308 sib = sib->next;
310 sib = group->ports;
311 while (1)
313 g_object_set (G_MODULAR_GRAPH_PORT (sib->data)->box, "width", min_width, NULL);
314 if (! sib->next) break;
315 sib = sib->next;
317 return min_width;
320 void g_modular_graph_module_add_port (GModularGraph_Port ** ret,
321 GModularGraph_Module * module,
322 int direction,
323 char * name, char * tooltip)
325 /* Create ports group */
326 GModularGraphPortsGroup * group = NULL;
327 if (module->ports)
329 GList * elem = module->ports;
330 while (1)
332 if (G_MODULAR_GRAPH_PORTS_GROUP (elem->data)->direction == direction)
334 group = elem->data;
335 break;
337 if (! elem->next) break;
338 elem = elem->next;
341 if (! group)
343 g_modular_graph_module_add_ports_group (& group, module, direction);
346 GModularGraph_Port * port = calloc (1, sizeof (GModularGraph_Port));
348 /* Decoration */
349 port->box = goo_canvas_rect_new (group->container,
350 0.5, 0.5, 50, 5,
351 "tooltip", tooltip,
352 //"radius-x", rounding,
353 //"radius-y", rounding,
354 "line-width", border_threshold,
355 "stroke-color", "gray70",
356 "fill-color", "gray60",
357 NULL);
358 g_signal_connect (G_OBJECT (port->box), "notify::width", G_CALLBACK (on_port_size_notify), port);
359 g_signal_connect (G_OBJECT (port->box), "notify::height", G_CALLBACK (on_port_size_notify), port);
360 g_signal_connect (G_OBJECT (port->box), "notify::x", G_CALLBACK (on_port_moved), port);
361 g_signal_connect (G_OBJECT (port->box), "notify::y", G_CALLBACK (on_port_moved), port);
363 /* Caption */
364 port->text = goo_canvas_text_new (group->container, "",
365 rounding, 0, -1, GTK_ANCHOR_NORTH_WEST,
366 "tooltip", tooltip,
367 "font", "sans 8",
368 "fill-color", "gray90", NULL);
369 goo_canvas_item_set_child_properties (group->container, port->box, "row", group->p_count, "x-expand", TRUE, "x-fill", TRUE, NULL);
370 goo_canvas_item_set_child_properties (group->container, port->text, "row", group->p_count, "x-expand", TRUE, "x-fill", TRUE,
371 "left-padding", rounding, "x-align", 0.5, NULL);
373 g_signal_connect (G_OBJECT (port->text), "notify::text", G_CALLBACK (on_port_text_notify), port);
375 /* Wire point */
376 switch (direction)
378 case G_MODULAR_GRAPH_PORT_DIRECTION_IN:
379 port->direction = 180.0; break;
380 case G_MODULAR_GRAPH_PORT_DIRECTION_OUT:
381 port->direction = 0.0; break;
384 /* Add port to group */
385 port->ports_group = group;
386 if (! g_list_find (group->ports, port))
387 group->ports = g_list_append (group->ports, port);
389 /* Complete initialization */
390 g_object_set (G_OBJECT (port->text), "text", name, NULL);
391 module_update_size (module);
392 port->connections = NULL;
394 group->p_count++;
395 if (ret) *ret = port;
398 typedef
399 union {
400 struct {
401 uint8_t alpha;
402 uint8_t blue;
403 uint8_t green;
404 uint8_t red;
406 uint32_t value;
407 } Color;
409 static void sort_uint8_ptr (uint8_t ** v, size_t size)
411 uint8_t ** ptr, ** ptr_end;
412 ptr_end = size - 1 + v;
413 unsigned needs_repeat;
415 do {
416 needs_repeat = (0 == 0);
417 ptr = v;
418 while (ptr < ptr_end)
420 if (* ptr[0] > * ptr[1] )
422 uint8_t * tmp = ptr[0];
423 ptr[0] = ptr[1];
424 ptr[1] = tmp;
426 else
427 needs_repeat = (1 == 0);
429 ptr++;
432 while (needs_repeat);
435 void color_adjust_lightness (unsigned * value, double diff)
437 Color color;
438 color.value = * value;
439 double mid_relative;
440 double range;
442 if (diff > 1.0)
444 uint8_t * color_c[3] = {& color.red, & color.green, & color.blue};
445 sort_uint8_ptr ((void *)color_c, 3);
447 range = * color_c[2] - * color_c[0];
449 mid_relative = (range == 0.0) ? 0.0 : (* color_c[1] - * color_c[0]) / range;
450 * color_c[0] = (* color_c[0] * diff > 255) ? 255 : * color_c[0] * diff;
451 * color_c[2] = (* color_c[2] * diff > 255) ? 255 : * color_c[2] * diff;
453 if (* color_c[0] == 255)
454 * color_c[1] = 255;
455 else
456 * color_c[1] = * color_c[0] + (* color_c[2] - * color_c[0]) * mid_relative;
458 else
460 color.red *= diff;
461 color.green *= diff;
462 color.blue *= diff;
465 * value = color.value;
468 GModularGraph_Connection * g_modular_graph_connection_new (GModularGraph_Port * out, GModularGraph_Port * in)
470 GModularGraph_Connection * connection = calloc (1, sizeof (GModularGraph_Connection));
471 connection->port1 = out;
472 connection->port2 = in;
474 GooCanvasBounds p_bounds [2];
475 goo_canvas_item_get_bounds (out->box, & p_bounds [0]);
476 goo_canvas_item_get_bounds (in->box, & p_bounds [1]);
477 connection->wire = g_modular_graph_wire_new (p_bounds[0].x2, (p_bounds[0].y1 + p_bounds[0].y2) / 2, out->direction,
478 p_bounds[1].x1, (p_bounds[1].y1 + p_bounds[1].y2) / 2, in->direction,
479 "Test connection", 0x803030ff);
481 GModularGraph_Module * module;
482 module = out->ports_group->module;
483 module->connections = g_list_append (module->connections, connection);
484 out->connections = g_list_append (out->connections, connection);
486 module = in->ports_group->module;
487 module->connections = g_list_append (module->connections, connection);
488 in->connections = g_list_append (in->connections, connection);
490 g_signal_connect (G_OBJECT (connection->wire->group), "button-release-event",
491 G_CALLBACK (on_wire_buttonPress_event), connection->wire->group);
492 return NULL;
495 GModularGraph_Wire * g_modular_graph_wire_new (double x1, double y1, double angle1, double x2, double y2, double angle2, char * tooltip, unsigned color)
497 char * wire_data;
498 GModularGraph_Wire * wire;
499 wire = calloc (1, sizeof (GModularGraph_Wire));
500 wire->x1 = x1, wire->y1 = y1;
501 wire->x2 = x2, wire->y2 = y2;
502 wire->angle1 = angle1;
503 wire->angle2 = angle2;
504 wire->color = color;
505 wire->blink = 1.5;
506 wire->highlight = 1.5;
508 wire->cx1 = wire->x1 + cos (wire->angle1 * G_PI / 180) * 50;
509 wire->cy1 = wire->y1 + sin (wire->angle1 * G_PI / 180) * 50;
510 wire->cx2 = wire->x2 + cos (wire->angle2 * G_PI / 180) * 50;
511 wire->cy2 = wire->y2 + sin (wire->angle2 * G_PI / 180) * 50;
512 asprintf (& wire_data, "M%i,%i C%i,%i %i,%i %i,%i",
513 (int) wire->x1, (int) wire->y1,
514 (int) wire->cx1, (int) wire->cy1,
515 (int) wire->cx2, (int) wire->cy2,
516 (int) wire->x2, (int) wire->y2);
518 wire->group = goo_canvas_group_new (root_item);
520 unsigned color_b = color;
521 color_adjust_lightness (& color_b, 1 / wire->blink);
522 wire->path_b = goo_canvas_path_new (wire->group,
523 wire_data,
524 "line-width", 3.0,
525 "stroke-color-rgba", color_b,
526 "line-cap", CAIRO_LINE_CAP_BUTT, NULL);
528 unsigned color_t = color;
529 color_adjust_lightness (& color_t, wire->blink);
530 wire->path_t = goo_canvas_path_new (wire->group,
531 wire_data,
532 "line-width", 1.5,
533 "stroke-color-rgba", color_t,
534 "line-cap", CAIRO_LINE_CAP_BUTT, NULL);
536 g_signal_connect (G_OBJECT (wire->group), "enter-notify-event", G_CALLBACK (wire_entered), wire);
537 g_signal_connect (G_OBJECT (wire->group), "leave-notify-event", G_CALLBACK (wire_left), wire);
538 g_object_set (wire->group, "tooltip", tooltip, NULL);
540 return wire;
543 static gboolean after_init (gpointer data)
545 goo_canvas_item_remove (G_MODULAR_GRAPH_PORT (data)->box);
546 goo_canvas_item_remove (G_MODULAR_GRAPH_PORT (data)->text);
547 return TRUE;
550 int main( int argc, char ** argv )
552 GtkWidget * win;
553 GtkWidget * scroller;
555 gtk_init (& argc, & argv);
556 win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
557 g_signal_connect (G_OBJECT (win), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
559 scroller = gtk_scrolled_window_new (NULL, NULL);
560 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller), GTK_SHADOW_IN);
561 gtk_container_add (GTK_CONTAINER (win), scroller);
563 /* Create canvas widget */
564 canvas = goo_canvas_new ();
565 gtk_widget_set_size_request (canvas, 600, 450);
566 goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000);
567 g_object_set (G_OBJECT (canvas), "automatic-bounds", TRUE, NULL);
569 gtk_container_add (GTK_CONTAINER (scroller), canvas);
571 /* Root */
572 root_item = goo_canvas_get_root_item (GOO_CANVAS (canvas));
573 g_object_set (G_OBJECT (root_item), "antialias", CAIRO_ANTIALIAS_SUBPIXEL, NULL);
574 g_object_set (G_OBJECT (root_item), "line-join", CAIRO_LINE_JOIN_ROUND, NULL);
575 g_object_set (G_OBJECT (root_item), "line-cap", CAIRO_LINE_CAP_ROUND, NULL);
576 g_object_set (G_OBJECT (root_item), "line-width", border_threshold, NULL);
577 g_signal_connect (G_OBJECT (root_item), "button-press-enter", G_CALLBACK (on_root_buttonPress_event), NULL);
578 g_signal_connect (G_OBJECT (root_item), "button-press-enter", G_CALLBACK (on_root_buttonRelease_event), NULL);
580 GModularGraph_Port * port1, * port2;
581 module[0] = g_modular_graph_module_new (root_item, "Module 1", "Module 1 tip", 0, 50, 50);
582 g_modular_graph_module_add_port (NULL, module[0], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-1", "Port 1 tip");
583 g_modular_graph_module_add_port (& port2, module[0], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-2", "Port 2 tip");
584 module[1] = g_modular_graph_module_new (root_item, "Module 2", "Module 2 tip", 0, 200, 10);
585 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-1", "Port 1 tip");
586 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "in-2", "Port 2 tip");
587 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_IN, "input-3", "Port 3 tip");
588 g_modular_graph_module_add_port (& port1, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_OUT, "out-1", "Out 1 tip");
589 g_modular_graph_module_add_port (NULL, module[1], G_MODULAR_GRAPH_PORT_DIRECTION_OUT, "out-2", "Out 2 tip");
591 /* 2. Connection */
592 g_modular_graph_wire_new (50, 100, 0.0, 300, 300, 180, "Test wire", 0x5f0000ff);
593 g_modular_graph_wire_new (50, 300, 0.0, 300, 100, 180, "Test wire", 0x5f0000ff);
595 g_modular_graph_connection_new (port1, port2);
597 //g_timeout_add (3000, after_init, myport);
599 gtk_widget_set_has_tooltip (canvas, TRUE);
601 gtk_widget_show_all (win);
602 gtk_main ();
603 return 0;
606 /* Helpers (nothing yet) */
608 /* Root callbacks */
610 static gboolean on_root_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
612 return FALSE;
615 static gboolean on_root_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
617 return FALSE;
620 static gboolean on_root_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data)
622 return FALSE;
625 /* Module callbacks */
627 static gboolean on_module_enterNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data)
629 char
630 * inner_border_color = "gray40",
631 * outer_border_color = "gray70";
632 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "stroke-color", inner_border_color, NULL);
633 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "stroke-color", outer_border_color, NULL);
634 return FALSE;
637 static gboolean on_module_leaveNotify_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventCrossing * event, gpointer data)
639 char
640 * inner_border_color = "gray33",
641 * outer_border_color = "gray45";
642 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "stroke-color", inner_border_color, NULL);
643 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "stroke-color", outer_border_color, NULL);
644 return FALSE;
647 static gboolean on_module_notify_width (GooCanvasItem * item, GParamSpec * event, gpointer data)
649 double w;
650 g_object_get (G_MODULAR_GRAPH_MODULE (data)->box, "width", & w, NULL);
651 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "width", w - border_threshold * 2, NULL);
652 g_object_set (G_MODULAR_GRAPH_MODULE (data)->outer_border, "width", w + border_threshold * 2, NULL);
653 return FALSE;
656 static gboolean on_module_notify_height (GooCanvasItem * item, GParamSpec * event, gpointer data)
658 double h;
659 g_object_get (G_MODULAR_GRAPH_MODULE (data)->box, "height", & h, NULL);
660 g_object_set (G_MODULAR_GRAPH_MODULE (data)->inner_border, "height", h - border_threshold * 2, NULL);
661 g_object_set (G_MODULAR_GRAPH_MODULE (data)->outer_border, "height", h + border_threshold * 2, NULL);
662 return FALSE;
665 #define DRAG_CB( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_cb)
666 #define DRAG_HOLD_X( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_hold_x)
667 #define DRAG_HOLD_Y( mod ) (G_MODULAR_GRAPH_MODULE( mod )->drag_hold_y)
669 static gboolean drag_redraw = TRUE;
670 static unsigned drag_redraw_timeout_id = 0;
672 static gboolean drag_redraw_timeout (gpointer data)
674 drag_redraw = TRUE;
675 return TRUE;
678 static
679 gboolean on_module_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
681 if (event->button == drag_button)
683 g_object_get (G_OBJECT (item),
684 "x", & DRAG_HOLD_X (data),
685 "y", & DRAG_HOLD_Y (data), NULL);
686 DRAG_HOLD_X (data) = event->x - DRAG_HOLD_X (data);
687 DRAG_HOLD_Y (data) = event->y - DRAG_HOLD_Y (data);
689 DRAG_CB (data) = g_signal_connect (G_OBJECT (root_item), "motion-notify-event", G_CALLBACK (on_module_dragged), data);
690 drag_redraw_timeout_id = g_timeout_add (30, drag_redraw_timeout, NULL);
692 return FALSE;
695 static
696 gboolean on_module_buttonRelease_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
698 if (event->button == drag_button)
700 g_source_remove (drag_redraw_timeout_id);
701 drag_redraw_timeout_id = 0;
702 if (DRAG_CB (data))
703 g_signal_handler_disconnect (G_OBJECT (root_item), DRAG_CB (data));
705 return FALSE;
708 static
709 gboolean on_module_dragged (GooCanvasItem * item, GooCanvasItem * target, GdkEventMotion * event, gpointer data)
711 if (drag_redraw)
713 g_object_set (G_MODULAR_GRAPH_MODULE (data)->group, "x", event->x - DRAG_HOLD_X (data), NULL);
714 g_object_set (G_MODULAR_GRAPH_MODULE (data)->group, "y", event->y - DRAG_HOLD_Y (data), NULL);
715 drag_redraw = FALSE;
717 return FALSE;
720 static gboolean on_module_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data)
722 double w, h;
723 text_wanted_size (item, &w, &h);
725 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "width", w, NULL);
726 g_object_set (G_MODULAR_GRAPH_MODULE (data)->box, "height", h, NULL);
728 return FALSE;
731 #undef DRAG_CB
732 #undef DRAG_HOLD_X
733 #undef DRAG_HOLD_Y
735 /* Port callbacks */
737 static gboolean on_port_text_notify (GooCanvasItem * item, GParamSpec * event, gpointer data)
739 double w, h;
740 text_wanted_size (item, &w, &h);
741 if (G_MODULAR_GRAPH_PORT (data)->min_width == w) return FALSE;
743 G_MODULAR_GRAPH_PORT (data)->min_width = w;
744 ports_group_update_width (G_MODULAR_GRAPH_PORT (data)->ports_group);
745 g_object_set (G_MODULAR_GRAPH_PORT (data)->box, "height", h, NULL);
747 return FALSE;
750 static void port_update_wire_pos (GModularGraph_Port * port)
752 double w, h;
753 g_object_get (port->box, "width", & w, "height", & h, NULL);
755 port->wire_y = h / 2;
756 if (port->direction == 0.0)
757 port->wire_x = w;
758 else if (port->direction == 180.0)
759 port->wire_x = 0.0;
762 static gboolean on_port_size_notify (GooCanvasItem * item, GParamSpec * event, gpointer data)
764 g_print ("on_port_size_notify: %s\n", event->name);
765 port_update_wire_pos (data);
766 return FALSE;
769 static gboolean on_port_moved (GooCanvasItem * item, GParamSpec * event, gpointer data)
771 g_print ("on_port_moved: %s\n", event->name);
772 return FALSE;
775 #define DRAG_CB( mod ) (G_MODULAR_GRAPH_PORT( mod )->drag_cb)
776 #define DRAG_HOLD_X( mod ) (G_MODULAR_GRAPH_PORT( mod )->drag_hold_x)
777 #define DRAG_HOLD_Y( mod ) (G_MODULAR_GRAPH_PORT( mod )->drag_hold_y)
779 /* Wire callbacks */
781 static
782 gboolean wire_entered (GooCanvasItem *item,
783 GooCanvasItem *target,
784 GdkEventCrossing *event,
785 gpointer data)
787 unsigned color = G_MODULAR_GRAPH_WIRE (data)->color;
788 color_adjust_lightness (& color, G_MODULAR_GRAPH_WIRE (data)->blink * G_MODULAR_GRAPH_WIRE (data)->highlight);
790 g_object_set (G_MODULAR_GRAPH_WIRE (data)->path_t, "stroke-color-rgba", color, NULL);
791 return FALSE;
794 static
795 gboolean wire_left (GooCanvasItem *item,
796 GooCanvasItem *target,
797 GdkEventCrossing *event,
798 gpointer data)
800 unsigned color = G_MODULAR_GRAPH_WIRE (data)->color;
801 color_adjust_lightness (& color, G_MODULAR_GRAPH_WIRE (data)->blink);
803 g_object_set (G_MODULAR_GRAPH_WIRE (data)->path_t, "stroke-color-rgba", color, NULL);
804 return FALSE;
807 static
808 gboolean on_wire_buttonPress_event (GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data)
810 if (event->button == 2)
812 g_print ("Wire was clicked\n");
814 return FALSE;