summaryrefslogtreecommitdiffstats
path: root/src/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/module.c')
-rw-r--r--src/module.c859
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);
-}