1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Nikita Zlobin 2011 <nick87720z@gmail.com>
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/>.
22 #include <goocanvas.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;
63 unsigned border_color
;
66 unsigned shadow_color
;
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 */
93 double drag_hold_x
, drag_hold_y
;
95 } GModularGraph_Module
;
97 #define G_MODULAR_GRAPH_MODULE(p) ((GModularGraph_Module *) (p))
100 G_MODULAR_GRAPH_PORT_DIRECTION_IN
= 1,
101 G_MODULAR_GRAPH_PORT_DIRECTION_OUT
102 } GModularGraphPortDirection
;
107 GModularGraphPortDirection direction
;
111 GooCanvasItem
* container
;
113 GModularGraph_Module
* module
;
114 } GModularGraphPortsGroup
;
116 #define G_MODULAR_GRAPH_PORTS_GROUP(p) ((GModularGraphPortsGroup *) (p))
121 GooCanvasItem
* text
;
122 GooCanvasItem
* group
;
123 GModularGraphPortsGroup
* ports_group
;
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))
135 GooCanvasItem
* path_b
;
136 GooCanvasItem
* path_t
;
137 GooCanvasItem
* group
;
140 //unsigned * cmd_len;
142 double x1
, y1
, cx1
, cy1
;
143 double x2
, y2
, cx2
, cy2
;
145 double angle1
, angle2
; /* In degreens */
149 } GModularGraph_Wire
;
151 #define G_MODULAR_GRAPH_WIRE(p) ((GModularGraph_Wire *) (p))
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
);
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
)
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
);
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
)
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
;
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;
218 module
= calloc (1, sizeof (GModularGraph_Module
));
219 module
->group
= goo_canvas_group_new (parent
, "x", (double) x
, "y", (double) y
, "tooltip", tooltip
, NULL
);
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",
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
);
245 module
->caption
= goo_canvas_text_new (module
->group
, "",
246 rounding
, 0, -1, GTK_ANCHOR_NORTH_WEST
,
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
);
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
);
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
;
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;
313 g_object_set (G_MODULAR_GRAPH_PORT (sib
->data
)->box
, "width", min_width
, NULL
);
314 if (! sib
->next
) break;
320 void g_modular_graph_module_add_port (GModularGraph_Port
** ret
,
321 GModularGraph_Module
* module
,
323 char * name
, char * tooltip
)
325 /* Create ports group */
326 GModularGraphPortsGroup
* group
= NULL
;
329 GList
* elem
= module
->ports
;
332 if (G_MODULAR_GRAPH_PORTS_GROUP (elem
->data
)->direction
== direction
)
337 if (! elem
->next
) break;
343 g_modular_graph_module_add_ports_group (& group
, module
, direction
);
346 GModularGraph_Port
* port
= calloc (1, sizeof (GModularGraph_Port
));
349 port
->box
= goo_canvas_rect_new (group
->container
,
352 //"radius-x", rounding,
353 //"radius-y", rounding,
354 "line-width", border_threshold
,
355 "stroke-color", "gray70",
356 "fill-color", "gray60",
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
);
364 port
->text
= goo_canvas_text_new (group
->container
, "",
365 rounding
, 0, -1, GTK_ANCHOR_NORTH_WEST
,
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
);
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
;
395 if (ret
) *ret
= port
;
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
;
416 needs_repeat
= (0 == 0);
418 while (ptr
< ptr_end
)
420 if (* ptr
[0] > * ptr
[1] )
422 uint8_t * tmp
= ptr
[0];
427 needs_repeat
= (1 == 0);
432 while (needs_repeat
);
435 void color_adjust_lightness (unsigned * value
, double diff
)
438 color
.value
= * value
;
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)
456 * color_c
[1] = * color_c
[0] + (* color_c
[2] - * color_c
[0]) * mid_relative
;
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
);
495 GModularGraph_Wire
* g_modular_graph_wire_new (double x1
, double y1
, double angle1
, double x2
, double y2
, double angle2
, char * tooltip
, unsigned color
)
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
;
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
,
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
,
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
);
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
);
550 int main( int argc
, char ** argv
)
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
);
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");
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
);
606 /* Helpers (nothing yet) */
610 static gboolean
on_root_buttonPress_event (GooCanvasItem
* item
, GooCanvasItem
* target
, GdkEventButton
* event
, gpointer data
)
615 static gboolean
on_root_buttonRelease_event (GooCanvasItem
* item
, GooCanvasItem
* target
, GdkEventButton
* event
, gpointer data
)
620 static gboolean
on_root_dragged (GooCanvasItem
* item
, GooCanvasItem
* target
, GdkEventMotion
* event
, gpointer data
)
625 /* Module callbacks */
627 static gboolean
on_module_enterNotify_event (GooCanvasItem
* item
, GooCanvasItem
* target
, GdkEventCrossing
* event
, gpointer data
)
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
);
637 static gboolean
on_module_leaveNotify_event (GooCanvasItem
* item
, GooCanvasItem
* target
, GdkEventCrossing
* event
, gpointer data
)
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
);
647 static gboolean
on_module_notify_width (GooCanvasItem
* item
, GParamSpec
* event
, gpointer data
)
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
);
656 static gboolean
on_module_notify_height (GooCanvasItem
* item
, GParamSpec
* event
, gpointer data
)
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
);
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
)
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
);
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;
703 g_signal_handler_disconnect (G_OBJECT (root_item
), DRAG_CB (data
));
709 gboolean
on_module_dragged (GooCanvasItem
* item
, GooCanvasItem
* target
, GdkEventMotion
* event
, gpointer data
)
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
);
720 static gboolean
on_module_text_notify (GooCanvasItem
* item
, GParamSpec
* event
, gpointer data
)
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
);
737 static gboolean
on_port_text_notify (GooCanvasItem
* item
, GParamSpec
* event
, gpointer data
)
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
);
750 static void port_update_wire_pos (GModularGraph_Port
* port
)
753 g_object_get (port
->box
, "width", & w
, "height", & h
, NULL
);
755 port
->wire_y
= h
/ 2;
756 if (port
->direction
== 0.0)
758 else if (port
->direction
== 180.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
);
769 static gboolean
on_port_moved (GooCanvasItem
* item
, GParamSpec
* event
, gpointer data
)
771 g_print ("on_port_moved: %s\n", event
->name
);
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)
782 gboolean
wire_entered (GooCanvasItem
*item
,
783 GooCanvasItem
*target
,
784 GdkEventCrossing
*event
,
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
);
795 gboolean
wire_left (GooCanvasItem
*item
,
796 GooCanvasItem
*target
,
797 GdkEventCrossing
*event
,
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
);
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");