diff options
Diffstat (limited to 'src/module.c')
-rw-r--r-- | src/module.c | 859 |
1 files changed, 0 insertions, 859 deletions
diff --git a/src/module.c b/src/module.c deleted file mode 100644 index bad930b..0000000 --- a/src/module.c +++ /dev/null @@ -1,859 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <string.h> - -#include "ganv/canvas.h" -#include "ganv/module.h" -#include "ganv/port.h" -#include "ganv/widget.h" - -#include "./color.h" -#include "./boilerplate.h" -#include "./gettext.h" -#include "./ganv-private.h" - -#define FOREACH_PORT(ports, i) \ - for (GanvPort** i = (GanvPort**)ports->pdata; \ - i != (GanvPort**)ports->pdata + ports->len; ++i) - -#define FOREACH_PORT_CONST(ports, i) \ - for (const GanvPort** i = (const GanvPort**)ports->pdata; \ - i != (const GanvPort**)ports->pdata + ports->len; ++i) - -static const double PAD = 2.0; -static const double EDGE_PAD = 5.0; -static const double MODULE_LABEL_PAD = 2.0; - -G_DEFINE_TYPE_WITH_CODE(GanvModule, ganv_module, GANV_TYPE_BOX, - G_ADD_PRIVATE(GanvModule)) - -static GanvBoxClass* parent_class; - -enum { - PROP_0 -}; - -static void -ganv_module_init(GanvModule* module) -{ - GanvModulePrivate* impl = ganv_module_get_instance_private(module); - - module->impl = impl; - - GANV_NODE(module)->impl->can_head = FALSE; - GANV_NODE(module)->impl->can_tail = FALSE; - - impl->ports = g_ptr_array_new(); - impl->embed_item = NULL; - impl->embed_width = 0; - impl->embed_height = 0; - impl->widest_input = 0.0; - impl->widest_output = 0.0; - impl->must_reorder = FALSE; -} - -static void -ganv_module_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_MODULE(object)); - - GanvModule* module = GANV_MODULE(object); - GanvModulePrivate* impl = module->impl; - - if (impl->ports) { - FOREACH_PORT(impl->ports, p) { - g_object_unref(GTK_OBJECT(*p)); - } - g_ptr_array_free(impl->ports, TRUE); - impl->ports = NULL; - } - - if (impl->embed_item) { - g_object_unref(GTK_OBJECT(impl->embed_item)); - impl->embed_item = NULL; - } - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -ganv_module_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_MODULE(object)); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_module_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_MODULE(object)); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -typedef struct { - double embed_x; - double width; - double input_width; - double output_width; - gboolean horiz; - gboolean embed_between; -} Metrics; - -static void -title_size(GanvModule* module, double* w, double* h) -{ - if (module->box.node.impl->label) { - g_object_get(G_OBJECT(module->box.node.impl->label), - "width", w, - "height", h, - NULL); - } else { - *w = *h = 0.0; - } -} - -static void -measure(GanvModule* module, Metrics* m) -{ - memset(m, '\0', sizeof(Metrics)); - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - GanvText* canvas_title = GANV_NODE(module)->impl->label; - GanvModulePrivate* impl = module->impl; - - if (ganv_canvas_get_direction(canvas) == GANV_DIRECTION_DOWN) { - double contents_width = 0.0; - if (canvas_title) { - contents_width += title_w + (2.0 * PAD); - } - - m->embed_x = 0; - m->input_width = ganv_module_get_empty_port_breadth(module); - m->output_width = ganv_module_get_empty_port_breadth(module); - - // TODO: cache this or merge with resize_right - unsigned n_inputs = 0; - unsigned n_outputs = 0; - FOREACH_PORT(impl->ports, pi) { - if ((*pi)->impl->is_input) { - ++n_inputs; - } else { - ++n_outputs; - } - } - - const unsigned hor_ports = MAX(1, MAX(n_inputs, n_outputs)); - const double ports_width = (2 * EDGE_PAD) + - ((m->input_width) * hor_ports) + - ((PAD + 1.0) * (hor_ports - 1)); - - m->width = MAX(contents_width, ports_width); - m->width = MAX(m->width, impl->embed_width); - - if (impl->embed_item) { - m->width = MAX(impl->embed_width + 2.0 * PAD, m->width); - m->embed_x = PAD; - } - return; - } - - // The amount of space between a port edge and the module edge (on the - // side that the port isn't right on the edge). - const double hor_pad = (canvas_title ? 10.0 : 20.0); - - m->width = (canvas_title) ? title_w + 10.0 : 1.0; - - // Title is wide or there is an embedded widget, - // put inputs and outputs beside each other - m->horiz = (impl->embed_item || - (impl->widest_input + impl->widest_output + 10.0 - < MAX(m->width, impl->embed_width))); - - // Fit ports to module (or vice-versa) - 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->embed_item) { - m->input_width = MAX(impl->widest_input, expand_w); - m->output_width = MAX(impl->widest_output, expand_w); - } - - const double widest = MAX(m->input_width, m->output_width); - - if (impl->embed_item) { - double above_w = MAX(m->width, widest + hor_pad); - double between_w = MAX(m->width, - (m->input_width - + m->output_width - + impl->embed_width)); - - above_w = MAX(above_w, impl->embed_width); - - // Decide where to place embedded widget if necessary) - if (impl->embed_width < impl->embed_height * 2.0) { - m->embed_between = TRUE; - m->width = between_w; - m->embed_x = m->input_width; - } else { - m->width = above_w; - m->embed_x = 2.0; - } - } - - if (!canvas_title && (impl->widest_input == 0.0 - || impl->widest_output == 0.0)) { - m->width += 10.0; - } - - m->width += 4.0; - m->width = MAX(m->width, widest + hor_pad); -} - -static void -place_title(GanvModule* module, GanvDirection dir) -{ - GanvBox* box = GANV_BOX(module); - GanvText* canvas_title = GANV_NODE(module)->impl->label; - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - if (!canvas_title) { - return; - } - - GanvItem* t = GANV_ITEM(canvas_title); - if (dir == GANV_DIRECTION_RIGHT) { - t->impl->x = (ganv_box_get_width(box) - title_w) / 2.0; - t->impl->y = 1.0; - } else { - t->impl->x = (ganv_box_get_width(box) - title_w) / 2.0; - t->impl->y = ganv_module_get_empty_port_depth(module) + 1.0; - } -} - -static void -resize_right(GanvModule* module) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - GanvModulePrivate* impl = module->impl; - - Metrics m; - measure(module, &m); - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - // Basic height contains title - double header_height = title_h ? (3.0 + title_h) : EDGE_PAD; - - if (impl->embed_item) { - ganv_item_set(impl->embed_item, - "x", (double)m.embed_x, - "y", header_height, - NULL); - } - - // Actually set width and height - ganv_box_set_width(GANV_BOX(module), m.width); - - // Offset ports below embedded widget - if (!m.embed_between) { - header_height += impl->embed_height; - } - - // Move ports to appropriate locations - double in_y = header_height; - double out_y = header_height; - FOREACH_PORT(impl->ports, pi) { - GanvPort* const p = (*pi); - GanvBox* const pbox = GANV_BOX(p); - GanvNode* const pnode = GANV_NODE(p); - const double h = ganv_box_get_height(pbox); - - // Offset to shift ports to make borders line up - const double border_off = (GANV_NODE(module)->impl->border_width - - pnode->impl->border_width) / 2.0; - - if (p->impl->is_input) { - ganv_node_move_to(pnode, -border_off, in_y + 1.0); - ganv_box_set_width(pbox, m.input_width); - in_y += h + pnode->impl->border_width + 1.0; - - ganv_canvas_for_each_edge_to( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } else { - ganv_node_move_to(pnode, m.width - m.output_width + border_off, out_y + 1.0); - ganv_box_set_width(pbox, m.output_width); - out_y += h + pnode->impl->border_width + 1.0; - - ganv_canvas_for_each_edge_from( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } - - if (!m.horiz) { - in_y = MAX(in_y, out_y); - out_y = MAX(in_y, out_y); - } - } - - double height = MAX(in_y, out_y) + EDGE_PAD; - if (impl->embed_item && m.embed_between) - height = MAX(height, impl->embed_height + header_height + 2.0); - - ganv_box_set_height(GANV_BOX(module), height); - - place_title(module, GANV_DIRECTION_RIGHT); -} - -static void -resize_down(GanvModule* module) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - GanvModulePrivate* impl = module->impl; - - Metrics m; - measure(module, &m); - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - const double port_depth = ganv_module_get_empty_port_depth(module); - const double port_breadth = ganv_module_get_empty_port_breadth(module); - - if (impl->embed_item) { - ganv_item_set(impl->embed_item, - "x", (double)m.embed_x, - "y", port_depth + title_h, - NULL); - } - - const double height = PAD + title_h - + impl->embed_height + (port_depth * 2.0); - - // Move ports to appropriate locations - guint in_count = 0; - guint out_count = 0; - double in_x = 0.0; - double out_x = 0.0; - FOREACH_PORT(impl->ports, pi) { - GanvPort* const p = (*pi); - GanvBox* const pbox = GANV_BOX(p); - GanvNode* const pnode = GANV_NODE(p); - ganv_box_set_width(pbox, port_breadth); - ganv_box_set_height(pbox, port_depth); - - // Offset to shift ports to make borders line up - const double border_off = (GANV_NODE(module)->impl->border_width - - pnode->impl->border_width) / 2.0; - - if (p->impl->is_input) { - in_x = EDGE_PAD + (in_count++ * (port_breadth + PAD + 1.0)); - ganv_node_move_to(pnode, in_x, -border_off); - ganv_canvas_for_each_edge_to( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } else { - out_x = EDGE_PAD + (out_count++ * (port_breadth + PAD + 1.0)); - ganv_node_move_to(pnode, out_x, height - port_depth + border_off); - ganv_canvas_for_each_edge_from( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } - } - - ganv_box_set_height(GANV_BOX(module), height); - ganv_box_set_width(GANV_BOX(module), m.width); - place_title(module, GANV_DIRECTION_DOWN); -} - -static void -measure_ports(GanvModule* module) -{ - GanvModulePrivate* impl = module->impl; - - impl->widest_input = 0.0; - impl->widest_output = 0.0; - FOREACH_PORT_CONST(impl->ports, pi) { - const GanvPort* const p = (*pi); - const double w = ganv_port_get_natural_width(p); - if (p->impl->is_input) { - if (w > impl->widest_input) { - impl->widest_input = w; - } - } else { - if (w > impl->widest_output) { - impl->widest_output = w; - } - } - } -} - -static void -ganv_module_resize(GanvNode* self) -{ - GanvModule* module = GANV_MODULE(self); - GanvNode* node = GANV_NODE(self); - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - - double label_w = 0.0; - double label_h = 0.0; - if (node->impl->label) { - g_object_get(node->impl->label, - "width", &label_w, - "height", &label_h, - NULL); - } - - measure_ports(module); - - ganv_box_set_width(GANV_BOX(module), label_w + (MODULE_LABEL_PAD * 2.0)); - ganv_box_set_height(GANV_BOX(module), label_h); - - switch (ganv_canvas_get_direction(canvas)) { - case GANV_DIRECTION_RIGHT: - resize_right(module); - break; - case GANV_DIRECTION_DOWN: - resize_down(module); - break; - } - - if (GANV_NODE_CLASS(parent_class)->resize) { - GANV_NODE_CLASS(parent_class)->resize(self); - } -} - -static void -ganv_module_redraw_text(GanvNode* self) -{ - FOREACH_PORT(GANV_MODULE(self)->impl->ports, p) { - ganv_node_redraw_text(GANV_NODE(*p)); - } - - if (parent_class->parent_class.redraw_text) { - parent_class->parent_class.redraw_text(self); - } -} - -static void -ganv_module_add_port(GanvModule* module, - GanvPort* port) -{ - GanvModulePrivate* impl = module->impl; - - // Update widest input/output measurements if necessary - const double width = ganv_port_get_natural_width(port); - if (port->impl->is_input && width > impl->widest_input) { - impl->widest_input = width; - } else if (!port->impl->is_input && width > impl->widest_output) { - impl->widest_output = width; - } - - // Add to port array - g_ptr_array_add(impl->ports, port); - - // Request update with resize and reorder - GANV_NODE(module)->impl->must_resize = TRUE; - impl->must_reorder = TRUE; -} - -static void -ganv_module_remove_port(GanvModule* module, - GanvPort* port) -{ - gboolean removed = g_ptr_array_remove(module->impl->ports, port); - if (removed) { - const double width = ganv_box_get_width(GANV_BOX(port)); - // Find new widest input or output, if necessary - if (port->impl->is_input && width >= module->impl->widest_input) { - module->impl->widest_input = 0; - FOREACH_PORT_CONST(module->impl->ports, i) { - const GanvPort* const p = (*i); - const double w = ganv_box_get_width(GANV_BOX(p)); - if (p->impl->is_input && w >= module->impl->widest_input) { - module->impl->widest_input = w; - } - } - } else if (!port->impl->is_input && width >= module->impl->widest_output) { - module->impl->widest_output = 0; - FOREACH_PORT_CONST(module->impl->ports, i) { - const GanvPort* const p = (*i); - const double w = ganv_box_get_width(GANV_BOX(p)); - if (!p->impl->is_input && w >= module->impl->widest_output) { - module->impl->widest_output = w; - } - } - } - - GANV_NODE(module)->impl->must_resize = TRUE; - } else { - fprintf(stderr, "Failed to find port to remove\n"); - } -} - -static void -ganv_module_add(GanvItem* item, GanvItem* child) -{ - if (GANV_IS_PORT(child)) { - ganv_module_add_port(GANV_MODULE(item), GANV_PORT(child)); - } - ganv_item_request_update(item); - if (GANV_ITEM_CLASS(parent_class)->add) { - GANV_ITEM_CLASS(parent_class)->add(item, child); - } -} - -static void -ganv_module_remove(GanvItem* item, GanvItem* child) -{ - if (GANV_IS_PORT(child)) { - ganv_module_remove_port(GANV_MODULE(item), GANV_PORT(child)); - } - ganv_item_request_update(item); - if (GANV_ITEM_CLASS(parent_class)->remove) { - GANV_ITEM_CLASS(parent_class)->remove(item, child); - } -} - -static int -ptr_sort(const GanvPort** a, const GanvPort** b, const PortOrderCtx* ctx) -{ - return ctx->port_cmp(*a, *b, ctx->data); -} - -static void -ganv_module_update(GanvItem* item, int flags) -{ - GanvModule* module = GANV_MODULE(item); - GanvCanvas* canvas = ganv_item_get_canvas(item); - - if (module->impl->must_reorder) { - // Sort ports array - PortOrderCtx ctx = ganv_canvas_get_port_order(canvas); - if (ctx.port_cmp) { - g_ptr_array_sort_with_data(module->impl->ports, - (GCompareDataFunc)ptr_sort, - - &ctx); - } - module->impl->must_reorder = FALSE; - } - - if (module->impl->embed_item) { - // Kick the embedded item to update position if we have moved - ganv_item_move(GANV_ITEM(module->impl->embed_item), 0.0, 0.0); - } - - FOREACH_PORT(module->impl->ports, p) { - ganv_item_invoke_update(GANV_ITEM(*p), flags); - } - - if (module->impl->embed_item) { - ganv_item_invoke_update(GANV_ITEM(module->impl->embed_item), flags); - } - - GANV_ITEM_CLASS(parent_class)->update(item, flags); -} - -static void -ganv_module_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvNode* node = GANV_NODE(item); - GanvModule* module = GANV_MODULE(item); - - // Draw box - if (GANV_ITEM_CLASS(parent_class)->draw) { - (*GANV_ITEM_CLASS(parent_class)->draw)(item, cr, cx, cy, cw, ch); - } - - // Draw label - if (node->impl->label) { - GanvItem* label_item = GANV_ITEM(node->impl->label); - GANV_ITEM_GET_CLASS(label_item)->draw(label_item, cr, cx, cy, cw, ch); - } - - // Draw ports - FOREACH_PORT(module->impl->ports, p) { - GANV_ITEM_GET_CLASS(GANV_ITEM(*p))->draw( - GANV_ITEM(*p), cr, cx, cy, cw, ch); - } - - // Draw embed item - if (module->impl->embed_item) { - GANV_ITEM_GET_CLASS(module->impl->embed_item)->draw( - module->impl->embed_item, cr, cx, cy, cw, ch); - } -} - -static void -ganv_module_move_to(GanvNode* node, - double x, - double y) -{ - GanvModule* module = GANV_MODULE(node); - GANV_NODE_CLASS(parent_class)->move_to(node, x, y); - FOREACH_PORT(module->impl->ports, p) { - ganv_node_move(GANV_NODE(*p), 0.0, 0.0); - } - if (module->impl->embed_item) { - ganv_item_move(GANV_ITEM(module->impl->embed_item), 0.0, 0.0); - } -} - -static void -ganv_module_move(GanvNode* node, - double dx, - double dy) -{ - GanvModule* module = GANV_MODULE(node); - GANV_NODE_CLASS(parent_class)->move(node, dx, dy); - FOREACH_PORT(module->impl->ports, p) { - ganv_node_move(GANV_NODE(*p), 0.0, 0.0); - } - if (module->impl->embed_item) { - ganv_item_move(GANV_ITEM(module->impl->embed_item), 0.0, 0.0); - } -} - -static double -ganv_module_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - GanvModule* module = GANV_MODULE(item); - - double d = GANV_ITEM_CLASS(parent_class)->point(item, x, y, actual_item); - - if (!*actual_item) { - // Point is not inside module at all, no point in checking children - return d; - } - - FOREACH_PORT(module->impl->ports, p) { - GanvItem* const port = GANV_ITEM(*p); - - *actual_item = NULL; - d = GANV_ITEM_GET_CLASS(port)->point( - port, x - port->impl->x, y - port->impl->y, actual_item); - - if (*actual_item) { - // Point is inside a port - return d; - } - } - - // Point is inside module, but not a child port - *actual_item = item; - return 0.0; -} - -static void -ganv_module_class_init(GanvModuleClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - GanvNodeClass* node_class = (GanvNodeClass*)klass; - - parent_class = GANV_BOX_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_module_set_property; - gobject_class->get_property = ganv_module_get_property; - - object_class->destroy = ganv_module_destroy; - - item_class->add = ganv_module_add; - item_class->remove = ganv_module_remove; - item_class->update = ganv_module_update; - item_class->draw = ganv_module_draw; - item_class->point = ganv_module_point; - - node_class->move = ganv_module_move; - node_class->move_to = ganv_module_move_to; - node_class->resize = ganv_module_resize; - node_class->redraw_text = ganv_module_redraw_text; -} - -GanvModule* -ganv_module_new(GanvCanvas* canvas, - const char* first_property_name, ...) -{ - GanvModule* module = GANV_MODULE( - g_object_new(ganv_module_get_type(), "canvas", canvas, NULL)); - - va_list args; - va_start(args, first_property_name); - g_object_set_valist(G_OBJECT(module), first_property_name, args); - va_end(args); - - return module; -} - -guint -ganv_module_num_ports(const GanvModule* module) -{ - return module->impl->ports ? module->impl->ports->len : 0; -} - -GanvPort* -ganv_module_get_port(GanvModule* module, - guint index) -{ - return (GanvPort*)g_ptr_array_index(module->impl->ports, index); -} - -double -ganv_module_get_empty_port_breadth(const GanvModule* module) -{ - return ganv_module_get_empty_port_depth(module) * 2.0; -} - -double -ganv_module_get_empty_port_depth(const GanvModule* module) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - - return ganv_canvas_get_font_size(canvas) * 1.1; -} - -static void -on_embed_size_request(GtkWidget* widget, - GtkRequisition* r, - void* user_data) -{ - GanvModule* module = GANV_MODULE(user_data); - GanvModulePrivate* impl = module->impl; - if (impl->embed_width == r->width && impl->embed_height == r->height) { - return; - } - - impl->embed_width = r->width; - impl->embed_height = r->height; - GANV_NODE(module)->impl->must_resize = TRUE; - - GtkAllocation allocation; - allocation.width = r->width; - allocation.height = r->width; - - gtk_widget_size_allocate(widget, &allocation); - ganv_item_set(impl->embed_item, - "width", (double)r->width, - "height", (double)r->height, - NULL); -} - -void -ganv_module_embed(GanvModule* module, - GtkWidget* widget) -{ - GanvModulePrivate* impl = module->impl; - if (!widget && !impl->embed_item) { - return; - } - - if (impl->embed_item) { - // Free existing embedded widget - gtk_object_destroy(GTK_OBJECT(impl->embed_item)); - impl->embed_item = NULL; - } - - if (!widget) { - // Removing an existing embedded widget - impl->embed_width = 0; - impl->embed_height = 0; - GANV_NODE(module)->impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(module)); - return; - } - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - impl->embed_item = ganv_item_new( - GANV_ITEM(module), - ganv_widget_get_type(), - "x", 2.0, - "y", 4.0 + title_h, - "widget", widget, - NULL); - - GtkRequisition r; - gtk_widget_show_all(widget); - gtk_widget_size_request(widget, &r); - on_embed_size_request(widget, &r, module); - ganv_item_show(impl->embed_item); - - g_signal_connect(widget, "size-request", - G_CALLBACK(on_embed_size_request), module); - - GANV_NODE(module)->impl->must_resize = TRUE; - 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); - } - GANV_NODE(module)->impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(module)); -} - -void -ganv_module_for_each_port(GanvModule* module, - GanvPortFunc f, - void* data) -{ - GanvModulePrivate* impl = module->impl; - const int len = impl->ports->len; - GanvPort** copy = (GanvPort**)malloc(sizeof(GanvPort*) * len); - memcpy(copy, impl->ports->pdata, sizeof(GanvPort*) * len); - - for (int i = 0; i < len; ++i) { - f(copy[i], data); - } - - free(copy); -} |