diff options
author | David Robillard <d@drobilla.net> | 2011-12-06 21:01:38 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2011-12-06 21:01:38 +0000 |
commit | 0731f12beaa0cfc0de56dc05ca3814143fd394a5 (patch) | |
tree | d8a98ee48badba378172d3a1c46fba2f2e266d37 /src/port.c | |
download | ganv-0731f12beaa0cfc0de56dc05ca3814143fd394a5.tar.gz ganv-0731f12beaa0cfc0de56dc05ca3814143fd394a5.tar.bz2 ganv-0731f12beaa0cfc0de56dc05ca3814143fd394a5.zip |
FlowCanvas's successor is hereby dubbed Ganv.
git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@3820 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/port.c')
-rw-r--r-- | src/port.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/src/port.c b/src/port.c new file mode 100644 index 0000000..7316846 --- /dev/null +++ b/src/port.c @@ -0,0 +1,420 @@ +/* This file is part of Ganv. + * Copyright 2007-2011 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 (at your option) + * 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 <math.h> + +#include "ganv/canvas.h" +#include "ganv/port.h" +#include "ganv/module.h" + +#include "./boilerplate.h" +#include "./ganv-private.h" +#include "./gettext.h" + +static const double PORT_LABEL_HPAD = 4.0; +static const double PORT_LABEL_VPAD = 1.0; + +G_DEFINE_TYPE(GanvPort, ganv_port, GANV_TYPE_BOX) + +static GanvBoxClass* parent_class; + +enum { + PROP_0, + PROP_IS_INPUT +}; + +static void +ganv_port_init(GanvPort* port) +{ + port->is_input = TRUE; +} + +static void +ganv_port_destroy(GtkObject* object) +{ + g_return_if_fail(object != NULL); + g_return_if_fail(GANV_IS_PORT(object)); + + GnomeCanvasItem* item = GNOME_CANVAS_ITEM(object); + GanvPort* port = GANV_PORT(object); + GanvCanvas* canvas = GANV_CANVAS(item->canvas); + if (port->is_input) { + ganv_canvas_for_each_edge_to(canvas, + &port->box.node, + ganv_edge_remove); + } else { + ganv_canvas_for_each_edge_from(canvas, + &port->box.node, + ganv_edge_remove); + } + + if (GTK_OBJECT_CLASS(parent_class)->destroy) { + (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); + } +} + +static void +ganv_port_set_property(GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + g_return_if_fail(object != NULL); + g_return_if_fail(GANV_IS_PORT(object)); + + GanvPort* port = GANV_PORT(object); + + switch (prop_id) { + SET_CASE(IS_INPUT, boolean, port->is_input); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +ganv_port_get_property(GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + g_return_if_fail(object != NULL); + g_return_if_fail(GANV_IS_PORT(object)); + + GanvPort* port = GANV_PORT(object); + + switch (prop_id) { + GET_CASE(IS_INPUT, boolean, port->is_input); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +ganv_port_tail_vector(const GanvNode* self, + const GanvNode* head, + double* x, + double* y, + double* dx, + double* dy) +{ + GanvPort* port = GANV_PORT(self); + + 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; + + gnome_canvas_item_i2w(GNOME_CANVAS_ITEM(self)->parent, x, y); +} + +static void +ganv_port_head_vector(const GanvNode* self, + const GanvNode* tail, + double* x, + double* y, + double* dx, + double* dy) +{ + GanvPort* port = GANV_PORT(self); + + 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; + + gnome_canvas_item_i2w(GNOME_CANVAS_ITEM(self)->parent, x, y); +} + +static void +ganv_port_resize(GanvNode* self) +{ + GanvPort* port = GANV_PORT(self); + GanvNode* node = GANV_NODE(self); + + double label_w, label_h; + g_object_get(node->label, + "width", &label_w, + "height", &label_h, + NULL); + + ganv_box_set_width(&port->box, label_w + (PORT_LABEL_HPAD * 2.0)); + ganv_box_set_height(&port->box, label_h + (PORT_LABEL_VPAD * 2.0)); + + gnome_canvas_item_set(GNOME_CANVAS_ITEM(node->label), + "x", PORT_LABEL_HPAD, + "y", PORT_LABEL_VPAD, + NULL); + + if (parent_class->parent_class.resize) { + parent_class->parent_class.resize(self); + } +} + +static void +ganv_port_set_width(GanvBox* box, + double width) +{ + GanvPort* port = GANV_PORT(box); + parent_class->set_width(box, width); + if (port->control) { + ganv_port_set_control_value(port, port->control->value); + } +} + +static void +ganv_port_set_height(GanvBox* box, + double height) +{ + GanvPort* port = GANV_PORT(box); + parent_class->set_height(box, height); + if (port->control) { + double control_y1; + g_object_get(port->control->rect, "y1", &control_y1, NULL); + gnome_canvas_item_set(GNOME_CANVAS_ITEM(port->control->rect), + "y2", control_y1 + height, + NULL); + } +} + +static gboolean +on_event(GanvNode* node, GdkEvent* event) +{ + GnomeCanvasItem* item = GNOME_CANVAS_ITEM(node); + GanvCanvas* canvas = GANV_CANVAS(item->canvas); + + return ganv_canvas_port_event(canvas, GANV_PORT(node), event); +} + +static void +ganv_port_class_init(GanvPortClass* class) +{ + GObjectClass* gobject_class = (GObjectClass*)class; + GtkObjectClass* object_class = (GtkObjectClass*)class; + GanvNodeClass* node_class = (GanvNodeClass*)class; + GanvBoxClass* box_class = (GanvBoxClass*)class; + + parent_class = GANV_BOX_CLASS(g_type_class_peek_parent(class)); + + gobject_class->set_property = ganv_port_set_property; + gobject_class->get_property = ganv_port_get_property; + + g_object_class_install_property( + gobject_class, PROP_IS_INPUT, g_param_spec_boolean( + "is-input", + _("is input"), + _("whether this port is an input (or an output, if false)"), + 0, + G_PARAM_READWRITE)); + + object_class->destroy = ganv_port_destroy; + + node_class->on_event = on_event; + node_class->tail_vector = ganv_port_tail_vector; + node_class->head_vector = ganv_port_head_vector; + node_class->resize = ganv_port_resize; + + box_class->set_width = ganv_port_set_width; + box_class->set_height = ganv_port_set_height; +} + +GanvPort* +ganv_port_new(GanvModule* module, + gboolean is_input, + const char* first_prop_name, ...) +{ + GanvPort* port = GANV_PORT( + g_object_new(ganv_port_get_type(), NULL)); + + GnomeCanvasItem* item = GNOME_CANVAS_ITEM(port); + va_list args; + va_start(args, first_prop_name); + gnome_canvas_item_construct(item, + GNOME_CANVAS_GROUP(module), + first_prop_name, args); + va_end(args); + + port->is_input = is_input; + + GanvBox* box = GANV_BOX(port); + box->radius_tl = (is_input ? 0.0 : 4.0); + box->radius_tr = (is_input ? 4.0 : 0.0); + box->radius_br = (is_input ? 4.0 : 0.0); + box->radius_bl = (is_input ? 0.0 : 4.0); + + GanvNode* node = GANV_NODE(port); + node->can_tail = !is_input; + node->can_head = is_input; + node->draggable = FALSE; + + GanvCanvas* canvas = GANV_CANVAS(item->canvas); + if (!node->label) { + const double depth = ganv_module_get_empty_port_depth(module); + const double breadth = ganv_module_get_empty_port_breadth(module); + if (canvas->direction == GANV_HORIZONTAL) { + ganv_box_set_width(box, depth); + ganv_box_set_height(box, breadth); + } else { + ganv_box_set_width(box, breadth); + ganv_box_set_height(box, depth); + } + } + + ganv_module_add_port(module, port); + return port; +} + +void +ganv_port_show_control(GanvPort* port) +{ + port->control = (GanvPortControl*)malloc(sizeof(GanvPortControl)); + port->control->value = 0.0f; + port->control->min = 0.0f; + port->control->max = 0.0f; + port->control->is_toggle = FALSE; + port->control->rect = GANV_BOX(gnome_canvas_item_new( + GNOME_CANVAS_GROUP(port), + ganv_box_get_type(), + "x1", 0.0, + "y1", 0.0, + "x2", 0.0, + "y2", ganv_box_get_height(&port->box), + "fill-color", 0xFFFFFF80, + "border-width", 0.0, + NULL)); + gnome_canvas_item_show(GNOME_CANVAS_ITEM(port->control->rect)); +} + +void +ganv_port_hide_control(GanvPort* port) +{ + gtk_object_destroy(GTK_OBJECT(port->control->rect)); + free(port->control); + port->control = NULL; +} + +void +ganv_port_set_control_is_toggle(GanvPort* port, + gboolean is_toggle) +{ + if (port->control) { + port->control->is_toggle = is_toggle; + ganv_port_set_control_value(port, port->control->value); + } +} + +void +ganv_port_set_control_value(GanvPort* port, + float value) +{ + if (!port->control) { + return; + } + + if (port->control->is_toggle) { + if (value != 0.0) { + value = port->control->max; + } else { + value = port->control->min; + } + } + + if (value < port->control->min) { + port->control->min = value; + } + if (value > port->control->max) { + port->control->max = value; + } + + if (port->control->max == port->control->min) { + port->control->max = port->control->min + 1.0; + } + + const int inf = isinf(value); + if (inf == -1) { + value = port->control->min; + } else if (inf == 1) { + value = port->control->max; + } + + const double w = (value - port->control->min) + / (port->control->max - port->control->min) + * ganv_box_get_width(&port->box); + + if (isnan(w)) { + return; + } + + ganv_box_set_width(port->control->rect, MAX(0.0, w - 1.0)); +#if 0 + if (signal && _control->value == value) + signal = false; +#endif + + port->control->value = value; +} + +void +ganv_port_set_control_min(GanvPort* port, + float min) +{ + if (port->control) { + port->control->min = min; + ganv_port_set_control_value(port, port->control->value); + } +} + +void +ganv_port_set_control_max(GanvPort* port, + float max) +{ + if (port->control) { + port->control->max = max; + ganv_port_set_control_value(port, port->control->value); + } +} + +double +ganv_port_get_natural_width(const GanvPort* port) +{ + /* + Canvas* const canvas = _module->canvas(); + if (canvas->direction() == Canvas::VERTICAL) { + return _module->empty_port_breadth(); + } else*/ + if (port->box.node.label) { + double label_w; + g_object_get(port->box.node.label, "width", &label_w, NULL); + return label_w + (PORT_LABEL_HPAD * 2.0); + } else { + //return _module->empty_port_depth(); + return 4.0; + } +} + +GanvModule* +ganv_port_get_module(const GanvPort* port) +{ + return GANV_MODULE(GNOME_CANVAS_ITEM(port)->parent); +} |