From 89c5346a3377a2075954acc436d3d843183ad31a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 24 Apr 2012 01:44:43 +0000 Subject: Fix downward signal flow display (i.e. port labels disabled). git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@4260 a436a847-0d15-0410-975c-d299462d15a1 --- ganv/Canvas.hpp | 6 ++-- ganv/Module.hpp | 5 ++-- ganv/canvas.h | 16 ++++++++++ ganv/module.h | 4 +++ ganv/node.h | 1 + ganv/port.h | 4 +++ src/Canvas.cpp | 49 +++++++++++++++++++++++++++---- src/edge.c | 8 ++--- src/ganv-private.h | 2 +- src/ganv_bench.cpp | 1 - src/module.c | 44 +++++++++++----------------- src/node.c | 40 +++++++++++++++++++++---- src/port.c | 85 ++++++++++++++++++++++++++++++++++++++++++++---------- 13 files changed, 200 insertions(+), 65 deletions(-) diff --git a/ganv/Canvas.hpp b/ganv/Canvas.hpp index e017d70..477277d 100644 --- a/ganv/Canvas.hpp +++ b/ganv/Canvas.hpp @@ -111,10 +111,8 @@ public: RW_PROPERTY(GanvDirection, direction); - typedef void (*NodeFunction)(GanvNode* node, void* data); - - void for_each_node(NodeFunction f, void* data); - void for_each_selected_node(NodeFunction f, void* data); + void for_each_node(GanvNodeFunction f, void* data); + void for_each_selected_node(GanvNodeFunction f, void* data); typedef void (*EdgePtrFunction)(GanvEdge* edge, void* data); diff --git a/ganv/Module.hpp b/ganv/Module.hpp index b734ba2..9b294c9 100644 --- a/ganv/Module.hpp +++ b/ganv/Module.hpp @@ -43,8 +43,7 @@ public: const std::string& name, double x = 0, double y = 0, - bool show_title = true, - bool show_port_labels = true) + bool show_title = true) : Box(&canvas, GANV_BOX( ganv_item_new( GANV_ITEM(canvas.root()), @@ -120,7 +119,7 @@ public: guint num_ports() const { return ganv_module_num_ports(gobj()); } RW_PROPERTY(gboolean, stacked) - RW_PROPERTY(gboolean, show_port_labels) + METHODRET0(ganv_module, double, get_empty_port_breadth) METHODRET0(ganv_module, double, get_empty_port_depth) diff --git a/ganv/canvas.h b/ganv/canvas.h index bbf6b97..352c13c 100644 --- a/ganv/canvas.h +++ b/ganv/canvas.h @@ -97,11 +97,27 @@ ganv_canvas_get_font_size(const GanvCanvas* canvas); void ganv_canvas_set_font_size(GanvCanvas* canvas, double points); +void +ganv_canvas_set_direction(GanvCanvas* canvas, GanvDirection dir); + void ganv_canvas_clear_selection(GanvCanvas* canvas); +typedef void (*GanvNodeFunction)(GanvNode* node, void* data); + typedef void (*GanvEdgeFunction)(GanvEdge* edge); +/** + * ganv_canvas_for_each_node: + * @canvas: The canvas. + * @f: (scope call): A function to call on every node on @canvas. + * @data: Data to pass to @f. + */ +void +ganv_canvas_for_each_node(GanvCanvas* canvas, + GanvNodeFunction f, + void* data); + /** * ganv_canvas_for_each_edge_from: * @canvas: The canvas. diff --git a/ganv/module.h b/ganv/module.h index 16c5258..de36f4e 100644 --- a/ganv/module.h +++ b/ganv/module.h @@ -75,6 +75,10 @@ void ganv_module_embed(GanvModule* module, GtkWidget* widget); +void +ganv_module_set_direction(GanvModule* module, + GanvDirection direction); + /** * ganv_module_for_each_port: * @module: The module. diff --git a/ganv/node.h b/ganv/node.h index a18a361..9150945 100644 --- a/ganv/node.h +++ b/ganv/node.h @@ -134,6 +134,7 @@ GanvNode* ganv_node_get_partner(const GanvNode* node); void ganv_node_set_label(GanvNode* node, const char* str); +void ganv_node_set_show_label(GanvNode* node, gboolean show); void ganv_node_move(GanvNode* node, diff --git a/ganv/port.h b/ganv/port.h index 402c67a..af5cc6b 100644 --- a/ganv/port.h +++ b/ganv/port.h @@ -48,6 +48,10 @@ ganv_port_new(GanvModule* module, gboolean is_input, const char* first_prop_name, ...); +void +ganv_port_set_direction(GanvPort* port, + GanvDirection direction); + void ganv_port_show_control(GanvPort* port); diff --git a/src/Canvas.cpp b/src/Canvas.cpp index c383654..f42997c 100644 --- a/src/Canvas.cpp +++ b/src/Canvas.cpp @@ -164,6 +164,7 @@ struct GanvCanvasImpl { void resize(double width, double height); + void for_each_node(GanvNodeFunction f, void* data); void for_each_edge_from(const GanvNode* tail, GanvEdgeFunction f); void for_each_edge_to(const GanvNode* head, GanvEdgeFunction f); void for_each_edge_on(const GanvNode* node, GanvEdgeFunction f); @@ -520,9 +521,10 @@ GanvCanvasImpl::layout_dot(bool use_length_hints, const std::string& filename) agsafeset(pnode, (char*)"shape", (char*)"box", NULL); agsafeset(pnode, (char*)"margin", (char*)"0", NULL); agsafeset(pnode, (char*)"pin", (char*)"true", NULL); - agsafeset(pnode, (char*)"label", - (char*)ganv_node_get_label(GANV_NODE(port)), - NULL); + const char* port_label = ganv_node_get_label(GANV_NODE(port)); + if (_gcanvas->direction == GANV_DIRECTION_RIGHT && port_label) { + agsafeset(pnode, (char*)"label", (char*)port_label, NULL); + } // Fix position (we don't want ports to be arranged) // (TODO: I don't think dot actually supports this...) @@ -1287,6 +1289,15 @@ GanvCanvasImpl::move_contents_to_internal(double x, double y, double min_x, doub } } +void +GanvCanvasImpl::for_each_node(GanvNodeFunction f, + void* data) +{ + FOREACH_ITEM(_items, i) { + f(*i, data); + } +} + void GanvCanvasImpl::for_each_edge_from(const GanvNode* tail, GanvEdgeFunction f) @@ -1663,7 +1674,7 @@ Canvas::resize(double width, double height) } void -Canvas::for_each_node(NodeFunction f, void* data) +Canvas::for_each_node(GanvNodeFunction f, void* data) { FOREACH_ITEM(impl()->_items, i) { f(*i, data); @@ -1671,7 +1682,7 @@ Canvas::for_each_node(NodeFunction f, void* data) } void -Canvas::for_each_selected_node(NodeFunction f, void* data) +Canvas::for_each_selected_node(GanvNodeFunction f, void* data) { FOREACH_ITEM(impl()->_selected_items, i) { f(*i, data); @@ -1791,6 +1802,9 @@ ganv_canvas_set_property(GObject* object, case PROP_HEIGHT: ganv_canvas_resize(canvas, canvas->width, g_value_get_double(value)); break; + case PROP_DIRECTION: + ganv_canvas_set_direction(canvas, (GanvDirection)g_value_get_enum(value)); + break; case PROP_LOCKED: { const gboolean tmp = g_value_get_boolean(value); if (canvas->locked != tmp) { @@ -1947,6 +1961,23 @@ ganv_canvas_set_font_size(GanvCanvas* canvas, double points) g_object_set(canvas, "font-size", points, NULL); } +static void +set_node_direction(GanvNode* node, void* data) +{ + if (GANV_IS_MODULE(node)) { + ganv_module_set_direction(GANV_MODULE(node), *(GanvDirection*)data); + } +} + +void +ganv_canvas_set_direction(GanvCanvas* canvas, GanvDirection dir) +{ + if (canvas->direction != dir) { + canvas->direction = dir; + ganv_canvas_for_each_node(canvas, set_node_direction, &dir); + } +} + void ganv_canvas_clear_selection(GanvCanvas* canvas) { @@ -2040,6 +2071,14 @@ ganv_canvas_unselect_edge(GanvCanvas* canvas, canvas->impl->unselect_edge(edge); } +void +ganv_canvas_for_each_node(GanvCanvas* canvas, + GanvNodeFunction f, + void* data) +{ + canvas->impl->for_each_node(f, data); +} + void ganv_canvas_for_each_edge_from(GanvCanvas* canvas, const GanvNode* tail, diff --git a/src/edge.c b/src/edge.c index d1586c0..2668c41 100644 --- a/src/edge.c +++ b/src/edge.c @@ -273,10 +273,10 @@ ganv_edge_update(GanvItem* item, int flags) coords->handle_x = coords->x1 + (dx / 2.0); coords->handle_y = coords->y1 + (dy / 2.0); - coords->cx1 = coords->x1 + (coords->cx1 * (ceilf(fabs(dx)) / 4.0)); - coords->cy1 += coords->y1; - coords->cx2 = coords->x2 + (coords->cx2 * (ceilf(fabs(dx)) / 4.0)); - coords->cy2 += coords->y2; + coords->cx1 = coords->x1 + (coords->cx1 * (ceilf(fabs(dx)) / 4.0)); + coords->cy1 = coords->y1 + (coords->cy1 * (ceilf(fabs(dy)) / 4.0)); + coords->cx2 = coords->x2 + (coords->cx2 * (ceilf(fabs(dx)) / 4.0)); + coords->cy2 = coords->y2 + (coords->cy2 * (ceilf(fabs(dy)) / 4.0)); // Update old coordinates impl->old_coords = impl->coords; diff --git a/src/ganv-private.h b/src/ganv-private.h index 35943e0..485e2f0 100644 --- a/src/ganv-private.h +++ b/src/ganv-private.h @@ -92,7 +92,6 @@ struct _GanvModuleImpl int embed_height; double widest_input; double widest_output; - gboolean show_port_labels; gboolean must_resize; }; @@ -111,6 +110,7 @@ struct _GanvNodeImpl { gboolean selected; gboolean highlighted; gboolean draggable; + gboolean show_label; }; /* Port */ diff --git a/src/ganv_bench.cpp b/src/ganv_bench.cpp index c962c6a..b4bda63 100644 --- a/src/ganv_bench.cpp +++ b/src/ganv_bench.cpp @@ -40,7 +40,6 @@ make_module(Canvas* canvas) Module* m(new Module(*canvas, name, rand() % (int)canvas->get_width(), rand() % (int)canvas->get_height(), - true, true)); int n_ins = rand() % MAX_NUM_PORTS; diff --git a/src/module.c b/src/module.c index b441d72..3dfcd13 100644 --- a/src/module.c +++ b/src/module.c @@ -43,7 +43,6 @@ static GanvBoxClass* parent_class; enum { PROP_0, - PROP_SHOW_PORT_LABELS }; static void @@ -64,7 +63,6 @@ ganv_module_init(GanvModule* module) impl->embed_height = 0; impl->widest_input = 0.0; impl->widest_output = 0.0; - impl->show_port_labels = FALSE; impl->must_resize = TRUE; } @@ -99,23 +97,7 @@ ganv_module_set_property(GObject* object, g_return_if_fail(object != NULL); g_return_if_fail(GANV_IS_MODULE(object)); - GanvModule* module = GANV_MODULE(object); - GanvModuleImpl* impl = module->impl; - switch (prop_id) { - case PROP_SHOW_PORT_LABELS: { - const gboolean tmp = g_value_get_boolean(value); - if (impl->show_port_labels != tmp) { - impl->show_port_labels = tmp; - impl->must_resize = TRUE; - /* FIXME - FOREACH_PORT_CONST(gobj()->ports, p) { - (*p)->show_label(b); - }*/ - ganv_item_request_update(GANV_ITEM(object)); - } - break; - } default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -131,11 +113,7 @@ ganv_module_get_property(GObject* object, g_return_if_fail(object != NULL); g_return_if_fail(GANV_IS_MODULE(object)); - GanvModule* module = GANV_MODULE(object); - GanvModuleImpl* impl = module->impl; - switch (prop_id) { - GET_CASE(SHOW_PORT_LABELS, boolean, impl->show_port_labels); default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -217,7 +195,7 @@ measure(GanvModule* module, Metrics* m) m->input_width = impl->widest_input; m->output_width = impl->widest_output; double expand_w = (m->horiz ? (m->width / 2.0) : m->width) - hor_pad; - if (impl->show_port_labels && !impl->embed_item) { + if (!impl->embed_item) { m->input_width = MAX(impl->widest_input, expand_w); m->output_width = MAX(impl->widest_output, expand_w); } @@ -256,25 +234,26 @@ measure(GanvModule* module, Metrics* m) static void place_title(GanvModule* module, GanvDirection dir) { - GanvBox* box = GANV_BOX(module); + GanvBox* box = GANV_BOX(module); + GanvText* canvas_title = GANV_NODE(module)->impl->label; + GanvModuleImpl* impl = module->impl; double title_w, title_h; title_size(module, &title_w, &title_h); - GanvText* canvas_title = GANV_NODE(module)->impl->label; - GanvModuleImpl* impl = module->impl; - if (!canvas_title) { return; } else if (dir == GANV_DIRECTION_RIGHT) { if (impl->icon_box) { ganv_item_set(GANV_ITEM(canvas_title), "x", MODULE_ICON_SIZE + 1.0, + "y", 2.0, NULL); } else { ganv_item_set(GANV_ITEM(canvas_title), "x", ((ganv_box_get_width(box) / 2.0) - (title_w / 2.0)), + "y", 2.0, NULL); } } else { @@ -877,6 +856,17 @@ ganv_module_embed(GanvModule* module, ganv_item_request_update(GANV_ITEM(module)); } +void +ganv_module_set_direction(GanvModule* module, + GanvDirection direction) +{ + FOREACH_PORT(module->impl->ports, p) { + ganv_port_set_direction(*p, direction); + } + module->impl->must_resize = TRUE; + ganv_module_resize(GANV_NODE(module)); +} + void ganv_module_for_each_port(GanvModule* module, GanvPortFunction f, diff --git a/src/node.c b/src/node.c index a8db7c4..25afd90 100644 --- a/src/node.c +++ b/src/node.c @@ -34,6 +34,7 @@ enum { PROP_CANVAS, PROP_PARTNER, PROP_LABEL, + PROP_SHOW_LABEL, PROP_DASH_LENGTH, PROP_DASH_OFFSET, PROP_BORDER_WIDTH, @@ -66,6 +67,7 @@ ganv_node_init(GanvNode* node) impl->selected = FALSE; impl->highlighted = FALSE; impl->draggable = FALSE; + impl->show_label = TRUE; } static void @@ -151,7 +153,9 @@ ganv_node_set_property(GObject* object, break; case PROP_LABEL: ganv_node_set_label(node, g_value_get_string(value)); - ganv_item_request_update(GANV_ITEM(object)); + break; + case PROP_SHOW_LABEL: + ganv_node_set_show_label(node, g_value_get_boolean(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -259,7 +263,7 @@ void ganv_node_set_label(GanvNode* node, const char* str) { GanvNodeImpl* impl = node->impl; - if (str[0] == '\0' || !str) { + if (!str || str[0] == '\0') { if (impl->label) { gtk_object_destroy(GTK_OBJECT(impl->label)); impl->label = NULL; @@ -276,10 +280,28 @@ ganv_node_set_label(GanvNode* node, const char* str) NULL)); } - GanvNodeClass* klass = GANV_NODE_GET_CLASS(node); - if (klass->resize) { - klass->resize(node); + if (impl->show_label) { + GanvNodeClass* klass = GANV_NODE_GET_CLASS(node); + if (klass->resize) { + klass->resize(node); + } + + ganv_item_request_update(GANV_ITEM(node)); + } +} + +void +ganv_node_set_show_label(GanvNode* node, gboolean show) +{ + if (node->impl->label) { + if (show) { + ganv_item_show(GANV_ITEM(node->impl->label)); + } else { + ganv_item_hide(GANV_ITEM(node->impl->label)); + } } + node->impl->show_label = show; + ganv_item_request_update(GANV_ITEM(node)); } static void @@ -495,6 +517,14 @@ ganv_node_class_init(GanvNodeClass* class) NULL, G_PARAM_READWRITE)); + g_object_class_install_property( + gobject_class, PROP_SHOW_LABEL, g_param_spec_boolean( + "show-label", + _("Show label"), + _("Whether or not to show the label."), + 0, + G_PARAM_READWRITE)); + g_object_class_install_property( gobject_class, PROP_DASH_LENGTH, g_param_spec_double( "dash-length", diff --git a/src/port.c b/src/port.c index 6ce37d0..5e9d13e 100644 --- a/src/port.c +++ b/src/port.c @@ -137,7 +137,10 @@ ganv_port_draw(GanvItem* item, GanvNode* node = GANV_NODE(item); if (node->impl->label) { GanvItem* label_item = GANV_ITEM(node->impl->label); - GANV_ITEM_GET_CLASS(label_item)->draw(label_item, cr, cx, cy, width, height); + if (label_item->object.flags & GANV_ITEM_VISIBLE) { + GANV_ITEM_GET_CLASS(label_item)->draw( + label_item, cr, cx, cy, width, height); + } } } @@ -149,15 +152,26 @@ ganv_port_tail_vector(const GanvNode* self, double* dx, double* dy) { - GanvPort* port = GANV_PORT(self); + GanvPort* port = GANV_PORT(self); + GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(self)->canvas); double px, py; g_object_get(G_OBJECT(self), "x", &px, "y", &py, NULL); - *x = px + ganv_box_get_width(&port->box); - *y = py + ganv_box_get_height(&port->box) / 2.0; - *dx = 1.0; - *dy = 0.0; + switch (canvas->direction) { + case GANV_DIRECTION_RIGHT: + *x = px + ganv_box_get_width(&port->box); + *y = py + ganv_box_get_height(&port->box) / 2.0; + *dx = 1.0; + *dy = 0.0; + break; + case GANV_DIRECTION_DOWN: + *x = px + ganv_box_get_width(&port->box) / 2.0; + *y = py + ganv_box_get_height(&port->box); + *dx = 0.0; + *dy = 1.0; + break; + } ganv_item_i2w(GANV_ITEM(self)->parent, x, y); } @@ -170,15 +184,26 @@ ganv_port_head_vector(const GanvNode* self, double* dx, double* dy) { - GanvPort* port = GANV_PORT(self); + GanvPort* port = GANV_PORT(self); + GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(self)->canvas); double px, py; g_object_get(G_OBJECT(self), "x", &px, "y", &py, NULL); - *x = px; - *y = py + ganv_box_get_height(&port->box) / 2.0; - *dx = -1.0; - *dy = 0.0; + switch (canvas->direction) { + case GANV_DIRECTION_RIGHT: + *x = px; + *y = py + ganv_box_get_height(&port->box) / 2.0; + *dx = -1.0; + *dy = 0.0; + break; + case GANV_DIRECTION_DOWN: + *x = px + ganv_box_get_width(&port->box) / 2.0; + *y = 0.0; + *dx = 0.0; + *dy = -1.0; + break; + } ganv_item_i2w(GANV_ITEM(self)->parent, x, y); } @@ -186,10 +211,11 @@ ganv_port_head_vector(const GanvNode* self, static void ganv_port_resize(GanvNode* self) { - GanvPort* port = GANV_PORT(self); - GanvNode* node = GANV_NODE(self); + GanvPort* port = GANV_PORT(self); + GanvNode* node = GANV_NODE(self); + GanvText* label = node->impl->label; - if (node->impl->label) { + if (label && GANV_ITEM(label)->object.flags & GANV_ITEM_VISIBLE) { double label_w, label_h; g_object_get(node->impl->label, "width", &label_w, @@ -323,9 +349,37 @@ ganv_port_new(GanvModule* module, node->impl->draggable = FALSE; node->impl->border_width = 1.0; + GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(port)->canvas); + ganv_port_set_direction(port, canvas->direction); + return port; } +void +ganv_port_set_direction(GanvPort* port, + GanvDirection direction) +{ + GanvNode* node = GANV_NODE(port); + GanvBox* box = GANV_BOX(port); + gboolean is_input = port->impl->is_input; + switch (direction) { + case GANV_DIRECTION_RIGHT: + box->impl->radius_tl = (is_input ? 0.0 : 4.0); + box->impl->radius_tr = (is_input ? 4.0 : 0.0); + box->impl->radius_br = (is_input ? 4.0 : 0.0); + box->impl->radius_bl = (is_input ? 0.0 : 4.0); + break; + case GANV_DIRECTION_DOWN: + box->impl->radius_tl = (is_input ? 0.0 : 4.0); + box->impl->radius_tr = (is_input ? 0.0 : 4.0); + box->impl->radius_br = (is_input ? 4.0 : 0.0); + box->impl->radius_bl = (is_input ? 4.0 : 0.0); + break; + } + ganv_node_set_show_label(node, direction == GANV_DIRECTION_RIGHT); + ganv_node_resize(node); +} + void ganv_port_show_control(GanvPort* port) { @@ -450,9 +504,10 @@ double ganv_port_get_natural_width(const GanvPort* port) { GanvCanvas* const canvas = GANV_CANVAS(GANV_ITEM(port)->canvas); + GanvText* const label = port->box.node.impl->label; if (canvas->direction == GANV_DIRECTION_DOWN) { return ganv_module_get_empty_port_breadth(ganv_port_get_module(port)); - } else if (port->box.node.impl->label) { + } else if (label && (GANV_ITEM(label)->object.flags & GANV_ITEM_VISIBLE)) { double label_w; g_object_get(port->box.node.impl->label, "width", &label_w, NULL); return label_w + (PORT_LABEL_HPAD * 2.0); -- cgit v1.2.1