summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Canvas.cpp117
-rw-r--r--src/box.c197
-rw-r--r--src/circle.c59
-rw-r--r--src/edge.c193
-rw-r--r--src/ganv-private.h130
-rw-r--r--src/module.c282
-rw-r--r--src/node.c237
-rw-r--r--src/port.c191
-rw-r--r--src/text.c118
9 files changed, 973 insertions, 551 deletions
diff --git a/src/Canvas.cpp b/src/Canvas.cpp
index d0c307e..c969f31 100644
--- a/src/Canvas.cpp
+++ b/src/Canvas.cpp
@@ -112,16 +112,18 @@ static const uint32_t SELECT_RECT_BORDER_COLOUR = 0x2E4445FF;
/** Order edges by (tail, head) */
struct TailHeadOrder {
inline bool operator()(const GanvEdge* a, const GanvEdge* b) const {
- return ((a->tail < b->tail)
- || (a->tail == b->tail && a->head < b->head));
+ return ((a->impl->tail < b->impl->tail)
+ || (a->impl->tail == b->impl->tail
+ && a->impl->head < b->impl->head));
}
};
/** Order edges by (head, tail) */
struct HeadTailOrder {
inline bool operator()(const GanvEdge* a, const GanvEdge* b) const {
- return ((a->head < b->head)
- || (a->head == b->head && a->tail < b->tail));
+ return ((a->impl->head < b->impl->head)
+ || (a->impl->head == b->impl->head
+ && a->impl->tail < b->impl->tail));
}
};
@@ -259,28 +261,37 @@ struct GanvCanvasImpl {
GdkCursor* _move_cursor;
};
-static GanvEdge
-make_edge_search_key(const GanvNode* tail, const GanvNode* head)
+typedef struct {
+ GnomeCanvasItem item;
+ GanvEdgeImpl* impl;
+ GanvEdgeImpl impl_data;
+} GanvEdgeKey;
+
+static void
+make_edge_search_key(GanvEdgeKey* key,
+ const GanvNode* tail,
+ const GanvNode* head)
{
- GanvEdge key;
- memset(&key, '\0', sizeof(GanvEdge));
- key.tail = const_cast<GanvNode*>(tail);
- key.head = const_cast<GanvNode*>(head);
- return key;
+ memset(key, '\0', sizeof(GanvEdgeKey));
+ key->impl = &key->impl_data;
+ key->impl->tail = const_cast<GanvNode*>(tail);
+ key->impl->head = const_cast<GanvNode*>(head);
}
GanvCanvasImpl::Edges::const_iterator
GanvCanvasImpl::first_edge_from(const GanvNode* tail)
{
- GanvEdge key = make_edge_search_key(tail, NULL);
- return _edges.lower_bound(&key);
+ GanvEdgeKey key;
+ make_edge_search_key(&key, tail, NULL);
+ return _edges.lower_bound((GanvEdge*)&key);
}
GanvCanvasImpl::DstEdges::const_iterator
GanvCanvasImpl::first_edge_to(const GanvNode* head)
{
- GanvEdge key = make_edge_search_key(NULL, head);
- return _dst_edges.lower_bound(&key);
+ GanvEdgeKey key;
+ make_edge_search_key(&key, NULL, head);
+ return _dst_edges.lower_bound((GanvEdge*)&key);
}
void
@@ -318,10 +329,11 @@ GanvCanvasImpl::selection_move_finished()
static void
select_if_tail_is_selected(GanvEdge* edge)
{
- gboolean selected;
- g_object_get(edge->tail, "selected", &selected, NULL);
- if (!selected && GANV_IS_PORT(edge->tail)) {
- g_object_get(ganv_port_get_module(GANV_PORT(edge->tail)),
+ GanvNode* tail = edge->impl->tail;
+ gboolean selected;
+ g_object_get(tail, "selected", &selected, NULL);
+ if (!selected && GANV_IS_PORT(tail)) {
+ g_object_get(ganv_port_get_module(GANV_PORT(tail)),
"selected", &selected, NULL);
}
@@ -333,10 +345,11 @@ select_if_tail_is_selected(GanvEdge* edge)
static void
select_if_head_is_selected(GanvEdge* edge)
{
- gboolean selected;
- g_object_get(edge->head, "selected", &selected, NULL);
- if (!selected && GANV_IS_PORT(edge->head)) {
- g_object_get(ganv_port_get_module(GANV_PORT(edge->head)),
+ GanvNode* head = edge->impl->head;
+ gboolean selected;
+ g_object_get(head, "selected", &selected, NULL);
+ if (!selected && GANV_IS_PORT(head)) {
+ g_object_get(ganv_port_get_module(GANV_PORT(head)),
"selected", &selected, NULL);
}
@@ -349,7 +362,7 @@ static void
select_edges(GanvPort* port, void* data)
{
GanvCanvasImpl* impl = (GanvCanvasImpl*)data;
- if (port->is_input) {
+ if (port->impl->is_input) {
impl->for_each_edge_to(GANV_NODE(port),
select_if_tail_is_selected);
} else {
@@ -381,8 +394,7 @@ GanvCanvasImpl::remove_item(GanvNode* item)
if (GANV_IS_MODULE(item)) {
GanvModule* const module = GANV_MODULE(item);
for (unsigned i = 0; i < ganv_module_num_ports(module); ++i) {
- unselect_port((GanvPort*)g_ptr_array_index(
- module->ports, i));
+ unselect_port(ganv_module_get_port(module, i));
}
}
@@ -411,7 +423,7 @@ static void
unselect_edges(GanvPort* port, void* data)
{
GanvCanvasImpl* impl = (GanvCanvasImpl*)data;
- if (port->is_input) {
+ if (port->impl->is_input) {
impl->for_each_edge_to(GANV_NODE(port),
ganv_edge_unselect);
} else {
@@ -499,7 +511,7 @@ GanvCanvasImpl::layout_dot(bool use_length_hints, const std::string& filename)
if (label) {
agsafeset(node, (char*)"label", (char*)label, NULL);
double width, height;
- g_object_get((*i)->label, "width", &width, "height", &height, NULL);
+ g_object_get((*i)->impl->label, "width", &width, "height", &height, NULL);
gv_set(node, "width", width / dpi);
gv_set(node, "height", height / dpi);
}
@@ -507,8 +519,8 @@ GanvCanvasImpl::layout_dot(bool use_length_hints, const std::string& filename)
// Make a node in the subgraph for each port on this module
GanvModule* const m = GANV_MODULE(*i);
- for (size_t i = 0; i < m->ports->len; ++i) {
- GanvPort* port = (GanvPort*)g_ptr_array_index(m->ports, i);
+ for (size_t i = 0; i < ganv_module_num_ports(m); ++i) {
+ GanvPort* port = ganv_module_get_port(m, i);
ss.str("");
ss << "p" << id++;
Agnode_t* pnode = agnode(subg, (char*)ss.str().c_str());
@@ -551,8 +563,8 @@ GanvCanvasImpl::layout_dot(bool use_length_hints, const std::string& filename)
FOREACH_EDGE(_edges, i) {
const GanvEdge* const edge = *i;
- GVNodes::iterator tail_i = nodes.find(edge->tail);
- GVNodes::iterator head_i = nodes.find(edge->head);
+ GVNodes::iterator tail_i = nodes.find(edge->impl->tail);
+ GVNodes::iterator head_i = nodes.find(edge->impl->head);
if (tail_i != nodes.end() && head_i != nodes.end()) {
agedge(G, tail_i->second, head_i->second);
@@ -609,8 +621,9 @@ bool
GanvCanvasImpl::are_connected(const GanvNode* tail,
const GanvNode* head)
{
- GanvEdge key = make_edge_search_key(tail, head);
- return (_edges.find(&key) != _edges.end());
+ GanvEdgeKey key;
+ make_edge_search_key(&key, tail, head);
+ return (_edges.find((GanvEdge*)&key) != _edges.end());
}
void
@@ -644,13 +657,13 @@ GanvCanvasImpl::select_port_toggle(GanvPort* port, int mod_state)
GanvPort* old_last_selected = _last_selected_port;
GanvPort* first = NULL;
bool done = false;
- for (size_t i = 0; i < m->ports->len; ++i) {
- GanvPort* const p = (GanvPort*)g_ptr_array_index(m->ports, i);
+ for (size_t i = 0; i < ganv_module_num_ports(m); ++i) {
+ GanvPort* const p = ganv_module_get_port(m, i);
if (!first && !done && (p == _last_selected_port || p == port)) {
first = p;
}
- if (first && !done && p->is_input == first->is_input) {
+ if (first && !done && p->impl->is_input == first->impl->is_input) {
select_port(p, false);
} else {
unselect_port(p);
@@ -702,7 +715,7 @@ GanvCanvasImpl::join_selection()
vector<GanvPort*> inputs;
vector<GanvPort*> outputs;
FOREACH_SELECTED_PORT(i) {
- if ((*i)->is_input) {
+ if ((*i)->impl->is_input) {
inputs.push_back(*i);
} else {
outputs.push_back(*i);
@@ -981,7 +994,7 @@ GanvCanvasImpl::connect_drag_handler(GdkEvent* event)
_gcanvas,
GANV_NODE(_connect_port),
drag_node,
- "color", GANV_NODE(_connect_port)->fill_color,
+ "color", GANV_NODE(_connect_port)->impl->fill_color,
"curved", TRUE,
"ghost", TRUE,
NULL);
@@ -1071,9 +1084,9 @@ switch (event->type) {
case GDK_BUTTON_PRESS:
if (event->button.button == 1) {
GanvModule* const module = ganv_port_get_module(port);
- if (module && port->is_input && port->control) {
- if (port->control->is_toggle) {
- if (port->control->value >= 0.5) {
+ if (module && port->impl->is_input && port->impl->control) {
+ if (port->impl->control->is_toggle) {
+ if (port->impl->control->value >= 0.5) {
ganv_port_set_control_value(port, 0.0);
} else {
ganv_port_set_control_value(port, 1.0);
@@ -1085,7 +1098,7 @@ switch (event->type) {
control_start_value = ganv_port_get_control_value(port);
}
return true;
- } else if (!port->is_input) {
+ } else if (!port->impl->is_input) {
port_dragging = true;
return true;
}
@@ -1114,8 +1127,8 @@ switch (event->type) {
const double dy = drag_dy / range_y;
const double value_range = (drag_dx > 0)
- ? port->control->max - control_start_value
- : control_start_value - port->control->min;
+ ? port->impl->control->max - control_start_value
+ : control_start_value - port->impl->control->min;
const double sens = fmaxf(1.0 - fabs(dy), value_range / range_x);
@@ -1133,7 +1146,7 @@ switch (event->type) {
unselect_ports();
} else {
bool modded = event->button.state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK);
- if (!modded && _last_selected_port && _last_selected_port->is_input != port->is_input) {
+ if (!modded && _last_selected_port && _last_selected_port->impl->is_input != port->impl->is_input) {
selection_joined_with(port);
unselect_ports();
} else {
@@ -1193,10 +1206,10 @@ GanvCanvasImpl::ports_joined(GanvPort* port1, GanvPort* port2)
GanvNode* src_node;
GanvNode* dst_node;
- if (port2->is_input && !port1->is_input) {
+ if (port2->impl->is_input && !port1->impl->is_input) {
src_node = GANV_NODE(port1);
dst_node = GANV_NODE(port2);
- } else if (!port2->is_input && port1->is_input) {
+ } else if (!port2->impl->is_input && port1->impl->is_input) {
src_node = GANV_NODE(port2);
dst_node = GANV_NODE(port1);
} else {
@@ -1255,7 +1268,7 @@ GanvCanvasImpl::for_each_edge_from(const GanvNode* tail,
GanvEdgeFunction f)
{
for (GanvCanvasImpl::Edges::const_iterator i = first_edge_from(tail);
- i != _edges.end() && (*i)->tail == tail;) {
+ i != _edges.end() && (*i)->impl->tail == tail;) {
GanvCanvasImpl::Edges::const_iterator next = i;
++next;
f((*i));
@@ -1268,7 +1281,7 @@ GanvCanvasImpl::for_each_edge_to(const GanvNode* head,
GanvEdgeFunction f)
{
for (GanvCanvasImpl::Edges::const_iterator i = first_edge_to(head);
- i != _dst_edges.end() && (*i)->head == head;) {
+ i != _dst_edges.end() && (*i)->impl->head == head;) {
GanvCanvasImpl::Edges::const_iterator next = i;
++next;
f((*i));
@@ -1521,8 +1534,8 @@ Edge*
Canvas::get_edge(Node* tail, Node* head) const
{
FOREACH_EDGE(impl()->_edges, i) {
- const GanvNode* const t = (*i)->tail;
- const GanvNode* const h = (*i)->head;
+ const GanvNode* const t = (*i)->impl->tail;
+ const GanvNode* const h = (*i)->impl->head;
if (t == tail->gobj() && h == head->gobj())
return Glib::wrap(*i);
diff --git a/src/box.c b/src/box.c
index 20a5eaf..2b4f5ef 100644
--- a/src/box.c
+++ b/src/box.c
@@ -23,6 +23,7 @@
#include "./boilerplate.h"
#include "./color.h"
#include "./gettext.h"
+#include "./ganv-private.h"
static const double STACKED_OFFSET = 4.0;
@@ -46,14 +47,16 @@ enum {
static void
ganv_box_init(GanvBox* box)
{
- memset(&box->coords, '\0', sizeof(GanvBoxCoords));
- box->coords.border_width = box->node.border_width;
-
- box->old_coords = box->coords;
- box->radius_tl = 0.0;
- box->radius_tr = 0.0;
- box->radius_br = 0.0;
- box->radius_bl = 0.0;
+ box->impl = GANV_BOX_GET_PRIVATE(box);
+
+ memset(&box->impl->coords, '\0', sizeof(GanvBoxCoords));
+ box->impl->coords.border_width = box->node.impl->border_width;
+
+ box->impl->old_coords = box->impl->coords;
+ box->impl->radius_tl = 0.0;
+ box->impl->radius_tr = 0.0;
+ box->impl->radius_br = 0.0;
+ box->impl->radius_bl = 0.0;
}
static void
@@ -77,17 +80,18 @@ ganv_box_set_property(GObject* object,
g_return_if_fail(GANV_IS_BOX(object));
GanvBox* box = GANV_BOX(object);
- GanvBoxCoords* coords = &box->coords;
+ GanvBoxImpl* impl = box->impl;
+ GanvBoxCoords* coords = &impl->coords;
switch (prop_id) {
SET_CASE(X1, double, coords->x1);
SET_CASE(Y1, double, coords->y1);
SET_CASE(X2, double, coords->x2);
SET_CASE(Y2, double, coords->y2);
- SET_CASE(RADIUS_TL, double, box->radius_tl);
- SET_CASE(RADIUS_TR, double, box->radius_tr);
- SET_CASE(RADIUS_BR, double, box->radius_br);
- SET_CASE(RADIUS_BL, double, box->radius_bl);
+ SET_CASE(RADIUS_TL, double, impl->radius_tl);
+ SET_CASE(RADIUS_TR, double, impl->radius_tr);
+ SET_CASE(RADIUS_BR, double, impl->radius_br);
+ SET_CASE(RADIUS_BL, double, impl->radius_bl);
SET_CASE(STACKED, boolean, coords->stacked);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -104,18 +108,20 @@ ganv_box_get_property(GObject* object,
g_return_if_fail(object != NULL);
g_return_if_fail(GANV_IS_BOX(object));
- GanvBox* box = GANV_BOX(object);
+ GanvBox* box = GANV_BOX(object);
+ GanvBoxImpl* impl = box->impl;
+ GanvBoxCoords* coords = &impl->coords;
switch (prop_id) {
- GET_CASE(X1, double, box->coords.x1);
- GET_CASE(X2, double, box->coords.x2);
- GET_CASE(Y1, double, box->coords.y1);
- GET_CASE(Y2, double, box->coords.y2);
- GET_CASE(RADIUS_TL, double, box->radius_tl);
- GET_CASE(RADIUS_TR, double, box->radius_tr);
- GET_CASE(RADIUS_BR, double, box->radius_br);
- GET_CASE(RADIUS_BL, double, box->radius_bl);
- GET_CASE(STACKED, boolean, box->coords.stacked);
+ GET_CASE(X1, double, coords->x1);
+ GET_CASE(X2, double, coords->x2);
+ GET_CASE(Y1, double, coords->y1);
+ GET_CASE(Y2, double, coords->y2);
+ GET_CASE(RADIUS_TL, double, impl->radius_tl);
+ GET_CASE(RADIUS_TR, double, impl->radius_tr);
+ GET_CASE(RADIUS_BR, double, impl->radius_br);
+ GET_CASE(RADIUS_BL, double, impl->radius_bl);
+ GET_CASE(STACKED, boolean, impl->coords.stacked);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -170,7 +176,7 @@ ganv_box_bounds(GnomeCanvasItem* item,
{
// Note this will not be correct if children are outside the box bounds
GanvBox* box = GANV_BOX(item);
- ganv_box_bounds_item(&box->coords, x1, y1, x2, y2);
+ ganv_box_bounds_item(&box->impl->coords, x1, y1, x2, y2);
gnome_canvas_item_i2w(item, x1, y1);
gnome_canvas_item_i2w(item, x2, y2);
}
@@ -181,19 +187,20 @@ ganv_box_update(GnomeCanvasItem* item,
ArtSVP* clip_path,
int flags)
{
- GanvBox* box = GANV_BOX(item);
- box->coords.border_width = box->node.border_width;
+ GanvBox* box = GANV_BOX(item);
+ GanvBoxImpl* impl = box->impl;
+ impl->coords.border_width = box->node.impl->border_width;
// Request redraw of old location
- request_redraw(item, &box->old_coords, TRUE);
+ request_redraw(item, &impl->old_coords, TRUE);
GnomeCanvasItemClass* item_class = GNOME_CANVAS_ITEM_CLASS(parent_class);
item_class->update(item, affine, clip_path, flags);
// Store old coordinates in world relative coordinates in case the
// group we are in moves between now and the next update
- box->old_coords = box->coords;
- coords_i2w(item, &box->old_coords);
+ impl->old_coords = impl->coords;
+ coords_i2w(item, &impl->old_coords);
// Get bounding box
double x1, x2, y1, y2;
@@ -204,7 +211,7 @@ ganv_box_update(GnomeCanvasItem* item,
gnome_canvas_w2c_d(GNOME_CANVAS(item->canvas), x2, y2, &item->x2, &item->y2);
// Request redraw of new location
- request_redraw(item, &box->coords, FALSE);
+ request_redraw(item, &impl->coords, FALSE);
}
@@ -221,48 +228,49 @@ ganv_box_draw(GnomeCanvasItem* item,
int cx, int cy,
int width, int height)
{
- GanvBox* me = GANV_BOX(item);
- cairo_t* cr = gdk_cairo_create(drawable);
-
- double x1 = me->coords.x1;
- double y1 = me->coords.y1;
- double x2 = me->coords.x2;
- double y2 = me->coords.y2;
+ GanvBox* box = GANV_BOX(item);
+ GanvBoxImpl* impl = box->impl;
+ cairo_t* cr = gdk_cairo_create(drawable);
+
+ double x1 = impl->coords.x1;
+ double y1 = impl->coords.y1;
+ double x2 = impl->coords.x2;
+ double y2 = impl->coords.y2;
gnome_canvas_item_i2w(item, &x1, &y1);
gnome_canvas_item_i2w(item, &x2, &y2);
double dash_length, border_color, fill_color;
ganv_node_get_draw_properties(
- &me->node, &dash_length, &border_color, &fill_color);
+ &box->node, &dash_length, &border_color, &fill_color);
double r, g, b, a;
double degrees = M_PI / 180.0;
- for (int i = (me->coords.stacked ? 1 : 0); i >= 0; --i) {
+ for (int i = (impl->coords.stacked ? 1 : 0); i >= 0; --i) {
const int x = cx - (STACKED_OFFSET * i);
const int y = cy - (STACKED_OFFSET * i);
- if (me->radius_tl == 0.0 && me->radius_tr == 0.0
- && me->radius_br == 0.0 && me->radius_bl == 0.0) {
+ if (impl->radius_tl == 0.0 && impl->radius_tr == 0.0
+ && impl->radius_br == 0.0 && impl->radius_bl == 0.0) {
// Simple rectangle
cairo_rectangle(cr, x1 - x, y1 - y, x2 - x1, y2 - y1);
} else {
// Rounded rectangle
cairo_new_sub_path(cr);
cairo_arc(cr,
- x2 - x - me->radius_tr,
- y1 - y + me->radius_tr,
- me->radius_tr, -90 * degrees, 0 * degrees);
+ x2 - x - impl->radius_tr,
+ y1 - y + impl->radius_tr,
+ impl->radius_tr, -90 * degrees, 0 * degrees);
cairo_arc(cr,
- x2 - x - me->radius_br, y2 - y - me->radius_br,
- me->radius_br, 0 * degrees, 90 * degrees);
+ x2 - x - impl->radius_br, y2 - y - impl->radius_br,
+ impl->radius_br, 0 * degrees, 90 * degrees);
cairo_arc(cr,
- x1 - x + me->radius_bl, y2 - y - me->radius_bl,
- me->radius_bl, 90 * degrees, 180 * degrees);
+ x1 - x + impl->radius_bl, y2 - y - impl->radius_bl,
+ impl->radius_bl, 90 * degrees, 180 * degrees);
cairo_arc(cr,
- x1 - x + me->radius_tl, y1 - y + me->radius_tl,
- me->radius_tl, 180 * degrees, 270 * degrees);
+ x1 - x + impl->radius_tl, y1 - y + impl->radius_tl,
+ impl->radius_tl, 180 * degrees, 270 * degrees);
cairo_close_path(cr);
}
@@ -272,12 +280,12 @@ ganv_box_draw(GnomeCanvasItem* item,
cairo_fill_preserve(cr);
// Border
- if (me->coords.border_width > 0.0) {
+ if (impl->coords.border_width > 0.0) {
color_to_rgba(border_color, &r, &g, &b, &a);
cairo_set_source_rgba(cr, r, g, b, a);
- cairo_set_line_width(cr, me->coords.border_width);
+ cairo_set_line_width(cr, impl->coords.border_width);
if (dash_length > 0) {
- cairo_set_dash(cr, &dash_length, 1, me->node.dash_offset);
+ cairo_set_dash(cr, &dash_length, 1, box->node.impl->dash_offset);
}
}
cairo_stroke(cr);
@@ -295,12 +303,13 @@ ganv_box_point(GnomeCanvasItem* item,
int cx, int cy,
GnomeCanvasItem** actual_item)
{
- GanvBox* box = GANV_BOX(item);
+ GanvBox* box = GANV_BOX(item);
+ GanvBoxImpl* impl = box->impl;
*actual_item = NULL;
double x1, y1, x2, y2;
- ganv_box_bounds_item(&box->coords, &x1, &y1, &x2, &y2);
+ ganv_box_bounds_item(&impl->coords, &x1, &y1, &x2, &y2);
// Point is inside the box (distance 0)
if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
@@ -390,6 +399,8 @@ ganv_box_class_init(GanvBoxClass* class)
parent_class = GANV_NODE_CLASS(g_type_class_peek_parent(class));
+ g_type_class_add_private(class, sizeof(GanvBoxImpl));
+
gobject_class->set_property = ganv_box_set_property;
gobject_class->get_property = ganv_box_get_property;
@@ -490,13 +501,71 @@ ganv_box_class_init(GanvBoxClass* class)
void
ganv_box_normalize(GanvBox* box)
{
- const double x1 = box->coords.x1;
- const double y1 = box->coords.y1;
- const double x2 = box->coords.x2;
- const double y2 = box->coords.y2;
-
- box->coords.x1 = MIN(x1, x2);
- box->coords.y1 = MIN(y1, y2);
- box->coords.x2 = MAX(x1, x2);
- box->coords.y2 = MAX(y1, y2);
+ GanvBoxCoords* coords = &box->impl->coords;
+
+ const double x1 = coords->x1;
+ const double y1 = coords->y1;
+ const double x2 = coords->x2;
+ const double y2 = coords->y2;
+
+ coords->x1 = MIN(x1, x2);
+ coords->y1 = MIN(y1, y2);
+ coords->x2 = MAX(x1, x2);
+ coords->y2 = MAX(y1, y2);
+}
+
+double
+ganv_box_get_x1(const GanvBox* box)
+{
+ return box->impl->coords.x1;
+}
+
+double
+ganv_box_get_y1(const GanvBox* box)
+{
+ return box->impl->coords.y1;
+}
+
+double
+ganv_box_get_x2(const GanvBox* box)
+{
+ return box->impl->coords.x2;
+}
+
+double
+ganv_box_get_y2(const GanvBox* box)
+{
+ return box->impl->coords.y2;
+}
+
+double
+ganv_box_get_width(const GanvBox* box)
+{
+ return box->impl->coords.x2 - box->impl->coords.x1;
+}
+
+void
+ganv_box_set_width(GanvBox* box,
+ double width)
+{
+ GANV_BOX_GET_CLASS(box)->set_width(box, width);
+}
+
+double
+ganv_box_get_height(const GanvBox* box)
+{
+ return box->impl->coords.y2 - box->impl->coords.y1;
+}
+
+void
+ganv_box_set_height(GanvBox* box,
+ double height)
+{
+ GANV_BOX_GET_CLASS(box)->set_height(box, height);
+}
+
+double
+ganv_box_get_border_width(const GanvBox* box)
+{
+ return box->impl->coords.border_width;
}
diff --git a/src/circle.c b/src/circle.c
index d067b29..c04e2d1 100644
--- a/src/circle.c
+++ b/src/circle.c
@@ -21,6 +21,7 @@
#include "./color.h"
#include "./boilerplate.h"
#include "./gettext.h"
+#include "./ganv-private.h"
G_DEFINE_TYPE(GanvCircle, ganv_circle, GANV_TYPE_NODE)
@@ -34,10 +35,12 @@ enum {
static void
ganv_circle_init(GanvCircle* circle)
{
- memset(&circle->coords, '\0', sizeof(GanvCircleCoords));
- circle->coords.radius = 8.0;
- circle->coords.width = 2.0;
- circle->old_coords = circle->coords;
+ circle->impl = GANV_CIRCLE_GET_PRIVATE(circle);
+
+ memset(&circle->impl->coords, '\0', sizeof(GanvCircleCoords));
+ circle->impl->coords.radius = 8.0;
+ circle->impl->coords.width = 2.0;
+ circle->impl->old_coords = circle->impl->coords;
}
static void
@@ -63,7 +66,7 @@ ganv_circle_set_property(GObject* object,
GanvCircle* circle = GANV_CIRCLE(object);
switch (prop_id) {
- SET_CASE(RADIUS, double, circle->coords.radius);
+ SET_CASE(RADIUS, double, circle->impl->coords.radius);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -82,7 +85,7 @@ ganv_circle_get_property(GObject* object,
GanvCircle* circle = GANV_CIRCLE(object);
switch (prop_id) {
- GET_CASE(RADIUS, double, circle->coords.radius);
+ GET_CASE(RADIUS, double, circle->impl->coords.radius);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -91,10 +94,10 @@ ganv_circle_get_property(GObject* object,
static gboolean
ganv_circle_is_within(const GanvNode* self,
- double x1,
- double y1,
- double x2,
- double y2)
+ double x1,
+ double y1,
+ double x2,
+ double y2)
{
double x, y;
g_object_get(G_OBJECT(self), "x", &x, "y", &y, NULL);
@@ -144,7 +147,7 @@ ganv_circle_head_vector(const GanvNode* self,
const double h = sqrt((xdist * xdist) + (ydist * ydist));
const double theta = asin(xdist / (h + DBL_EPSILON));
const double y_mod = (cy < tail_y) ? 1 : -1;
- const double ret_h = h - circle->coords.radius;
+ const double ret_h = h - circle->impl->coords.radius;
const double ret_x = tail_x - sin(theta) * ret_h;
const double ret_y = tail_y - cos(theta) * ret_h * y_mod;
@@ -190,7 +193,7 @@ ganv_circle_bounds_item(GnomeCanvasItem* item,
double* x2, double* y2)
{
const GanvCircle* circle = GANV_CIRCLE(item);
- const GanvCircleCoords* coords = &circle->coords;
+ const GanvCircleCoords* coords = &circle->impl->coords;
*x1 = coords->x - coords->radius - coords->width;
*y1 = coords->y - coords->radius - coords->width;
*x2 = coords->x + coords->radius + coords->width;
@@ -213,7 +216,8 @@ ganv_circle_update(GnomeCanvasItem* item,
ArtSVP* clip_path,
int flags)
{
- GanvCircle* circle = GANV_CIRCLE(item);
+ GanvCircle* circle = GANV_CIRCLE(item);
+ GanvCircleImpl* impl = circle->impl;
GnomeCanvasItemClass* item_class = GNOME_CANVAS_ITEM_CLASS(parent_class);
if (item_class->update) {
@@ -221,12 +225,12 @@ ganv_circle_update(GnomeCanvasItem* item,
}
// Request redraw of old location
- request_redraw(item, &circle->old_coords, TRUE);
+ request_redraw(item, &impl->old_coords, TRUE);
// Store old coordinates in world relative coordinates in case the
// group we are in moves between now and the next update
- circle->old_coords = circle->coords;
- coords_i2w(item, &circle->old_coords);
+ impl->old_coords = impl->coords;
+ coords_i2w(item, &impl->old_coords);
// Get bounding circle
double x1, x2, y1, y2;
@@ -237,7 +241,7 @@ ganv_circle_update(GnomeCanvasItem* item,
gnome_canvas_w2c_d(GNOME_CANVAS(item->canvas), x2, y2, &item->x2, &item->y2);
// Request redraw of new location
- request_redraw(item, &circle->coords, FALSE);
+ request_redraw(item, &impl->coords, FALSE);
}
static void
@@ -253,23 +257,24 @@ ganv_circle_draw(GnomeCanvasItem* item,
int x, int y,
int width, int height)
{
- GanvCircle* me = GANV_CIRCLE(item);
- cairo_t* cr = gdk_cairo_create(drawable);
+ GanvCircle* circle = GANV_CIRCLE(item);
+ GanvCircleImpl* impl = circle->impl;
+ cairo_t* cr = gdk_cairo_create(drawable);
double r, g, b, a;
- double cx = me->coords.x;
- double cy = me->coords.y;
+ double cx = impl->coords.x;
+ double cy = impl->coords.y;
gnome_canvas_item_i2w(item, &cx, &cy);
double dash_length, border_color, fill_color;
ganv_node_get_draw_properties(
- &me->node, &dash_length, &border_color, &fill_color);
+ &circle->node, &dash_length, &border_color, &fill_color);
cairo_arc(cr,
cx - x,
cy - y,
- me->coords.radius,
+ impl->coords.radius,
0, 2 * M_PI);
// Fill
@@ -280,9 +285,9 @@ ganv_circle_draw(GnomeCanvasItem* item,
// Border
color_to_rgba(border_color, &r, &g, &b, &a);
cairo_set_source_rgba(cr, r, g, b, a);
- cairo_set_line_width(cr, me->coords.width);
+ cairo_set_line_width(cr, impl->coords.width);
if (dash_length > 0) {
- cairo_set_dash(cr, &dash_length, 1, me->node.dash_offset);
+ cairo_set_dash(cr, &dash_length, 1, circle->node.impl->dash_offset);
}
cairo_stroke(cr);
@@ -296,7 +301,7 @@ ganv_circle_point(GnomeCanvasItem* item,
GnomeCanvasItem** actual_item)
{
const GanvCircle* circle = GANV_CIRCLE(item);
- const GanvCircleCoords* coords = &circle->coords;
+ const GanvCircleCoords* coords = &circle->impl->coords;
*actual_item = item;
@@ -323,6 +328,8 @@ ganv_circle_class_init(GanvCircleClass* class)
parent_class = GANV_NODE_CLASS(g_type_class_peek_parent(class));
+ g_type_class_add_private(class, sizeof(GanvCircleImpl));
+
gobject_class->set_property = ganv_circle_set_property;
gobject_class->get_property = ganv_circle_get_property;
diff --git a/src/edge.c b/src/edge.c
index 63b853e..89c99fa 100644
--- a/src/edge.c
+++ b/src/edge.c
@@ -59,19 +59,22 @@ static GnomeCanvasItemClass* parent_class;
static void
ganv_edge_init(GanvEdge* edge)
{
- edge->tail = NULL;
- edge->head = NULL;
-
- memset(&edge->coords, '\0', sizeof(GanvEdgeCoords));
- edge->coords.width = 2.0;
- edge->coords.handle_radius = 4.0;
- edge->coords.curved = FALSE;
- edge->coords.arrowhead = FALSE;
-
- edge->old_coords = edge->coords;
- edge->dash_length = 0.0;
- edge->dash_offset = 0.0;
- edge->color = 0xA0A0A0FF;
+ GanvEdgeImpl* impl = GANV_EDGE_GET_PRIVATE(edge);
+ edge->impl = impl;
+
+ impl->tail = NULL;
+ impl->head = NULL;
+
+ memset(&impl->coords, '\0', sizeof(GanvEdgeCoords));
+ impl->coords.width = 2.0;
+ impl->coords.handle_radius = 4.0;
+ impl->coords.curved = FALSE;
+ impl->coords.arrowhead = FALSE;
+
+ impl->old_coords = impl->coords;
+ impl->dash_length = 0.0;
+ impl->dash_offset = 0.0;
+ impl->color = 0xA0A0A0FF;
}
static void
@@ -82,7 +85,7 @@ ganv_edge_destroy(GtkObject* object)
GanvEdge* edge = GANV_EDGE(object);
GanvCanvas* canvas = GANV_CANVAS(edge->item.canvas);
- if (canvas && !edge->ghost) {
+ if (canvas && !edge->impl->ghost) {
ganv_canvas_remove_edge(canvas, edge);
edge->item.canvas = NULL;
}
@@ -103,21 +106,22 @@ ganv_edge_set_property(GObject* object,
g_return_if_fail(GANV_IS_EDGE(object));
GanvEdge* edge = GANV_EDGE(object);
- GanvEdgeCoords* coords = &edge->coords;
+ GanvEdgeImpl* impl = edge->impl;
+ GanvEdgeCoords* coords = &impl->coords;
switch (prop_id) {
- SET_CASE(TAIL, object, edge->tail);
- SET_CASE(HEAD, object, edge->head);
+ SET_CASE(TAIL, object, impl->tail);
+ SET_CASE(HEAD, object, impl->head);
SET_CASE(WIDTH, double, coords->width);
SET_CASE(HANDLE_RADIUS, double, coords->handle_radius);
- SET_CASE(DASH_LENGTH, double, edge->dash_length);
- SET_CASE(DASH_OFFSET, double, edge->dash_offset);
- SET_CASE(COLOR, uint, edge->color);
- SET_CASE(CURVED, boolean, edge->coords.curved);
- SET_CASE(ARROWHEAD, boolean, edge->coords.arrowhead);
- SET_CASE(SELECTED, boolean, edge->selected);
- SET_CASE(HIGHLIGHTED, boolean, edge->highlighted);
- SET_CASE(GHOST, boolean, edge->ghost);
+ SET_CASE(DASH_LENGTH, double, impl->dash_length);
+ SET_CASE(DASH_OFFSET, double, impl->dash_offset);
+ SET_CASE(COLOR, uint, impl->color);
+ SET_CASE(CURVED, boolean, impl->coords.curved);
+ SET_CASE(ARROWHEAD, boolean, impl->coords.arrowhead);
+ SET_CASE(SELECTED, boolean, impl->selected);
+ SET_CASE(HIGHLIGHTED, boolean, impl->highlighted);
+ SET_CASE(GHOST, boolean, impl->ghost);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -133,21 +137,22 @@ ganv_edge_get_property(GObject* object,
g_return_if_fail(object != NULL);
g_return_if_fail(GANV_IS_EDGE(object));
- GanvEdge* edge = GANV_EDGE(object);
+ GanvEdge* edge = GANV_EDGE(object);
+ GanvEdgeImpl* impl = edge->impl;
switch (prop_id) {
- GET_CASE(TAIL, object, edge->tail);
- GET_CASE(HEAD, object, edge->head);
- GET_CASE(WIDTH, double, edge->coords.width);
- SET_CASE(HANDLE_RADIUS, double, edge->coords.handle_radius);
- GET_CASE(DASH_LENGTH, double, edge->dash_length);
- GET_CASE(DASH_OFFSET, double, edge->dash_offset);
- GET_CASE(COLOR, uint, edge->color);
- GET_CASE(CURVED, boolean, edge->coords.curved);
- GET_CASE(ARROWHEAD, boolean, edge->coords.arrowhead);
- GET_CASE(SELECTED, boolean, edge->selected);
- GET_CASE(HIGHLIGHTED, boolean, edge->highlighted);
- SET_CASE(GHOST, boolean, edge->ghost);
+ GET_CASE(TAIL, object, impl->tail);
+ GET_CASE(HEAD, object, impl->head);
+ GET_CASE(WIDTH, double, impl->coords.width);
+ SET_CASE(HANDLE_RADIUS, double, impl->coords.handle_radius);
+ GET_CASE(DASH_LENGTH, double, impl->dash_length);
+ GET_CASE(DASH_OFFSET, double, impl->dash_offset);
+ GET_CASE(COLOR, uint, impl->color);
+ GET_CASE(CURVED, boolean, impl->coords.curved);
+ GET_CASE(ARROWHEAD, boolean, impl->coords.arrowhead);
+ GET_CASE(SELECTED, boolean, impl->selected);
+ GET_CASE(HIGHLIGHTED, boolean, impl->highlighted);
+ SET_CASE(GHOST, boolean, impl->ghost);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -219,13 +224,14 @@ ganv_edge_bounds(GnomeCanvasItem* item,
double* x1, double* y1,
double* x2, double* y2)
{
- GanvEdge* edge = GANV_EDGE(item);
+ GanvEdge* edge = GANV_EDGE(item);
+ GanvEdgeImpl* impl = edge->impl;
// TODO: This is not correct for curved edges
- *x1 = MIN(edge->coords.x1, edge->coords.x2);
- *y1 = MIN(edge->coords.y1, edge->coords.y2);
- *x2 = MAX(edge->coords.x1, edge->coords.x2);
- *y2 = MAX(edge->coords.y1, edge->coords.y2);
+ *x1 = MIN(impl->coords.x1, impl->coords.x2);
+ *y1 = MIN(impl->coords.y1, impl->coords.y2);
+ *x2 = MAX(impl->coords.x1, impl->coords.x2);
+ *y2 = MAX(impl->coords.y1, impl->coords.y2);
}
static void
@@ -234,22 +240,23 @@ ganv_edge_update(GnomeCanvasItem* item,
ArtSVP* clip_path,
int flags)
{
- GanvEdge* edge = GANV_EDGE(item);
+ GanvEdge* edge = GANV_EDGE(item);
+ GanvEdgeImpl* impl = edge->impl;
if (parent_class->update) {
(*parent_class->update)(item, affine, clip_path, flags);
}
// Request redraw of old location
- request_redraw(item->canvas, &edge->old_coords);
+ request_redraw(item->canvas, &impl->old_coords);
// Calculate new coordinates from tail and head
- GanvEdgeCoords* coords = &edge->coords;
- GANV_NODE_GET_CLASS(edge->tail)->tail_vector(
- edge->tail, edge->head,
+ GanvEdgeCoords* coords = &impl->coords;
+ GANV_NODE_GET_CLASS(impl->tail)->tail_vector(
+ impl->tail, impl->head,
&coords->x1, &coords->y1, &coords->cx1, &coords->cy1);
- GANV_NODE_GET_CLASS(edge->head)->head_vector(
- edge->head, edge->tail,
+ GANV_NODE_GET_CLASS(impl->head)->head_vector(
+ impl->head, impl->tail,
&coords->x2, &coords->y2, &coords->cx2, &coords->cy2);
const double dx = coords->x2 - coords->x1;
@@ -263,7 +270,7 @@ ganv_edge_update(GnomeCanvasItem* item,
coords->cy2 += coords->y2;
// Update old coordinates
- edge->old_coords = edge->coords;
+ impl->old_coords = impl->coords;
// Get bounding box
double x1, x2, y1, y2;
@@ -282,7 +289,7 @@ ganv_edge_update(GnomeCanvasItem* item,
gnome_canvas_w2c_d(GNOME_CANVAS(item->canvas), x2, y2, &item->x2, &item->y2);
// Request redraw of new location
- request_redraw(item->canvas, &edge->coords);
+ request_redraw(item->canvas, &impl->coords);
}
static void
@@ -298,56 +305,52 @@ ganv_edge_draw(GnomeCanvasItem* item,
int x, int y,
int width, int height)
{
- GanvEdge* me = GANV_EDGE(item);
- cairo_t* cr = gdk_cairo_create(drawable);
+ GanvEdge* edge = GANV_EDGE(item);
+ GanvEdgeImpl* impl = edge->impl;
+ cairo_t* cr = gdk_cairo_create(drawable);
- double src_x = me->coords.x1 - x;
- double src_y = me->coords.y1 - y;
- //double src_cx = me->coords.cx1 - x;
- //double src_cy = me->coords.cy1 - y;
- double dst_x = me->coords.x2 - x;
- double dst_y = me->coords.y2 - y;
- //double dst_cx = me->coords.cx2 - x;
- //double dst_cy = me->coords.cy2 - y;
-
- double dx = src_x - dst_x;
- double dy = src_y - dst_y;
+ double src_x = impl->coords.x1 - x;
+ double src_y = impl->coords.y1 - y;
+ double dst_x = impl->coords.x2 - x;
+ double dst_y = impl->coords.y2 - y;
+ double dx = src_x - dst_x;
+ double dy = src_y - dst_y;
double r, g, b, a;
- if (me->highlighted) {
- color_to_rgba(highlight_color(me->color, 0x20), &r, &g, &b, &a);
+ if (impl->highlighted) {
+ color_to_rgba(highlight_color(impl->color, 0x20), &r, &g, &b, &a);
} else {
- color_to_rgba(me->color, &r, &g, &b, &a);
+ color_to_rgba(impl->color, &r, &g, &b, &a);
}
cairo_set_source_rgba(cr, r, g, b, a);
- cairo_set_line_width(cr, me->coords.width);
+ cairo_set_line_width(cr, impl->coords.width);
cairo_move_to(cr, src_x, src_y);
- const double dash_length = (me->selected ? 4.0 : me->dash_length);
+ const double dash_length = (impl->selected ? 4.0 : impl->dash_length);
if (dash_length > 0.0) {
double dashed[2] = { dash_length, dash_length };
- cairo_set_dash(cr, dashed, 2, me->dash_offset);
+ cairo_set_dash(cr, dashed, 2, impl->dash_offset);
}
const double join_x = (src_x + dst_x) / 2.0;
const double join_y = (src_y + dst_y) / 2.0;
- if (me->coords.curved) {
+ if (impl->coords.curved) {
// Curved line as 2 paths which join at the middle point
// Path 1 (src_x, src_y) -> (join_x, join_y)
// Control point 1
- const double src_x1 = me->coords.cx1 - x;
- const double src_y1 = me->coords.cy1 - y;
+ const double src_x1 = impl->coords.cx1 - x;
+ const double src_y1 = impl->coords.cy1 - y;
// Control point 2
const double src_x2 = (join_x + src_x1) / 2.0;
const double src_y2 = (join_y + src_y1) / 2.0;
// Path 2, (join_x, join_y) -> (dst_x, dst_y)
// Control point 1
- const double dst_x1 = me->coords.cx2 - x;
- const double dst_y1 = me->coords.cy2 - y;
+ const double dst_x1 = impl->coords.cx2 - x;
+ const double dst_y1 = impl->coords.cy2 - y;
// Control point 2
const double dst_x2 = (join_x + dst_x1) / 2.0;
const double dst_y2 = (join_y + dst_y1) / 2.0;
@@ -356,7 +359,7 @@ ganv_edge_draw(GnomeCanvasItem* item,
cairo_curve_to(cr, src_x1, src_y1, src_x2, src_y2, join_x, join_y);
cairo_curve_to(cr, dst_x2, dst_y2, dst_x1, dst_y1, dst_x, dst_y);
- if (me->coords.arrowhead) {
+ if (impl->coords.arrowhead) {
cairo_line_to(cr, dst_x - 12, dst_y - 4);
cairo_move_to(cr, dst_x, dst_y);
cairo_line_to(cr, dst_x - 12, dst_y + 4);
@@ -390,7 +393,7 @@ ganv_edge_draw(GnomeCanvasItem* item,
cairo_move_to(cr, src_x, src_y);
cairo_line_to(cr, dst_x, dst_y);
- if (me->coords.arrowhead) {
+ if (impl->coords.arrowhead) {
const double ah = sqrt(dx * dx + dy * dy);
const double adx = dx / ah * 10.0;
const double ady = dy / ah * 10.0;
@@ -408,7 +411,7 @@ ganv_edge_draw(GnomeCanvasItem* item,
cairo_stroke(cr);
cairo_move_to(cr, join_x, join_y);
- cairo_arc(cr, join_x, join_y, me->coords.handle_radius, 0, 2 * M_PI);
+ cairo_arc(cr, join_x, join_y, impl->coords.handle_radius, 0, 2 * M_PI);
cairo_fill(cr);
cairo_destroy(cr);
@@ -421,7 +424,7 @@ ganv_edge_point(GnomeCanvasItem* item,
GnomeCanvasItem** actual_item)
{
const GanvEdge* edge = GANV_EDGE(item);
- const GanvEdgeCoords* coords = &edge->coords;
+ const GanvEdgeCoords* coords = &edge->impl->coords;
const double dx = fabs(x - coords->handle_x);
const double dy = fabs(y - coords->handle_y);
@@ -445,8 +448,8 @@ ganv_edge_is_within(const GanvEdge* edge,
double x2,
double y2)
{
- const double handle_x = edge->coords.handle_x;
- const double handle_y = edge->coords.handle_y;
+ const double handle_x = edge->impl->coords.handle_x;
+ const double handle_y = edge->impl->coords.handle_y;
return handle_x >= x1
&& handle_x <= x2
@@ -463,6 +466,8 @@ ganv_edge_class_init(GanvEdgeClass* class)
parent_class = GNOME_CANVAS_ITEM_CLASS(g_type_class_peek_parent(class));
+ g_type_class_add_private(class, sizeof(GanvEdgeImpl));
+
gobject_class->set_property = ganv_edge_set_property;
gobject_class->get_property = ganv_edge_get_property;
@@ -592,10 +597,10 @@ ganv_edge_new(GanvCanvas* canvas,
first_prop_name, args);
va_end(args);
- edge->tail = tail;
- edge->head = head;
+ edge->impl->tail = tail;
+ edge->impl->head = head;
- if (!edge->ghost) {
+ if (!edge->impl->ghost) {
ganv_canvas_add_edge(canvas, edge);
}
return edge;
@@ -624,7 +629,7 @@ ganv_edge_unselect(GanvEdge* edge)
void
ganv_edge_highlight(GanvEdge* edge)
{
- edge->highlighted = TRUE;
+ edge->impl->highlighted = TRUE;
gnome_canvas_item_raise_to_top(GNOME_CANVAS_ITEM(edge));
gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(edge));
}
@@ -632,7 +637,7 @@ ganv_edge_highlight(GanvEdge* edge)
void
ganv_edge_unhighlight(GanvEdge* edge)
{
- edge->highlighted = FALSE;
+ edge->impl->highlighted = FALSE;
gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(edge));
}
@@ -648,9 +653,21 @@ ganv_edge_tick(GanvEdge* edge,
void
ganv_edge_remove(GanvEdge* edge)
{
- if (!edge->ghost) {
+ if (!edge->impl->ghost) {
ganv_canvas_remove_edge(
GANV_CANVAS(edge->item.canvas),
edge);
}
}
+
+GanvNode*
+ganv_edge_get_tail(const GanvEdge* edge)
+{
+ return edge->impl->tail;
+}
+
+GanvNode*
+ganv_edge_get_head(const GanvEdge* edge)
+{
+ return edge->impl->head;
+}
diff --git a/src/ganv-private.h b/src/ganv-private.h
index b7e6eae..2f5b90b 100644
--- a/src/ganv-private.h
+++ b/src/ganv-private.h
@@ -19,9 +19,137 @@
#ifdef __cplusplus
extern "C" {
#endif
-
+
+#include <cairo.h>
+
+#include "ganv/types.h"
+
extern guint signal_moved;
+/* Box */
+
+typedef struct {
+ double x1, y1, x2, y2;
+ double border_width;
+ gboolean stacked;
+} GanvBoxCoords;
+
+struct _GanvBoxImpl {
+ GanvBoxCoords coords;
+ GanvBoxCoords old_coords;
+ double radius_tl;
+ double radius_tr;
+ double radius_br;
+ double radius_bl;
+};
+
+/* Circle */
+
+typedef struct {
+ double x, y, radius;
+ double width;
+} GanvCircleCoords;
+
+struct _GanvCircleImpl {
+ GanvCircleCoords coords;
+ GanvCircleCoords old_coords;
+};
+
+/* Edge */
+
+typedef struct {
+ double x1, y1, x2, y2;
+ double cx1, cy1, cx2, cy2;
+ double handle_x, handle_y, handle_radius;
+ double width;
+ gboolean curved;
+ gboolean arrowhead;
+} GanvEdgeCoords;
+
+struct _GanvEdgeImpl
+{
+ GanvNode* tail;
+ GanvNode* head;
+ GanvEdgeCoords coords;
+ GanvEdgeCoords old_coords;
+ double dash_length;
+ double dash_offset;
+ guint color;
+ gboolean selected;
+ gboolean highlighted;
+ gboolean ghost;
+};
+
+/* Module */
+
+struct _GanvModuleImpl
+{
+ GPtrArray* ports;
+ GnomeCanvasItem* icon_box;
+ GnomeCanvasItem* embed_item;
+ int embed_width;
+ int embed_height;
+ double widest_input;
+ double widest_output;
+ gboolean show_port_labels;
+ gboolean must_resize;
+ gboolean port_size_changed;
+};
+
+/* Node */
+
+struct _GanvNodeImpl {
+ struct _GanvNode* partner;
+ GanvText* label;
+ double dash_length;
+ double dash_offset;
+ double border_width;
+ guint fill_color;
+ guint border_color;
+ gboolean can_tail;
+ gboolean can_head;
+ gboolean selected;
+ gboolean highlighted;
+ gboolean draggable;
+};
+
+/* Port */
+
+typedef struct {
+ GanvBox* rect;
+ float value;
+ float min;
+ float max;
+ gboolean is_toggle;
+} GanvPortControl;
+
+struct _GanvPortImpl {
+ GanvPortControl* control;
+ gboolean is_input;
+};
+
+/* Text */
+
+typedef struct
+{
+ double x;
+ double y;
+ double width;
+ double height;
+} GanvTextCoords;
+
+struct _GanvTextImpl
+{
+ cairo_surface_t* surface;
+ char* text;
+ GanvTextCoords coords;
+ GanvTextCoords old_coords;
+ guint color;
+ gboolean needs_layout;
+};
+
+/* Canvas */
+
void
ganv_canvas_add_node(GanvCanvas* canvas,
GanvNode* node);
diff --git a/src/module.c b/src/module.c
index 2f0fa20..ac8cc58 100644
--- a/src/module.c
+++ b/src/module.c
@@ -22,6 +22,7 @@
#include "./color.h"
#include "./boilerplate.h"
#include "./gettext.h"
+#include "./ganv-private.h"
#define FOREACH_PORT(ports, i) \
for (GanvPort** i = (GanvPort**)ports->pdata; \
@@ -46,19 +47,22 @@ enum {
static void
ganv_module_init(GanvModule* module)
{
- GANV_NODE(module)->can_head = FALSE;
- GANV_NODE(module)->can_tail = FALSE;
-
- module->ports = g_ptr_array_new();
- module->icon_box = NULL;
- module->embed_item = NULL;
- module->embed_width = 0;
- module->embed_height = 0;
- module->widest_input = 0.0;
- module->widest_output = 0.0;
- module->show_port_labels = FALSE;
- module->must_resize = TRUE;
- module->port_size_changed = FALSE;
+ GanvModuleImpl* impl = GANV_MODULE_GET_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->icon_box = NULL;
+ impl->embed_item = NULL;
+ impl->embed_width = 0;
+ impl->embed_height = 0;
+ impl->widest_input = 0.0;
+ impl->widest_output = 0.0;
+ impl->show_port_labels = FALSE;
+ impl->must_resize = TRUE;
+ impl->port_size_changed = FALSE;
}
static void
@@ -67,14 +71,15 @@ ganv_module_destroy(GtkObject* object)
g_return_if_fail(object != NULL);
g_return_if_fail(GANV_IS_MODULE(object));
- GanvModule* module = GANV_MODULE(object);
+ GanvModule* module = GANV_MODULE(object);
+ GanvModuleImpl* impl = module->impl;
- if (module->ports) {
- FOREACH_PORT(module->ports, p) {
+ if (impl->ports) {
+ FOREACH_PORT(impl->ports, p) {
gtk_object_destroy(GTK_OBJECT(*p));
}
- g_ptr_array_free(module->ports, TRUE);
- module->ports = NULL;
+ g_ptr_array_free(impl->ports, TRUE);
+ impl->ports = NULL;
}
if (GTK_OBJECT_CLASS(parent_class)->destroy) {
@@ -91,15 +96,16 @@ 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);
+ 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 (module->show_port_labels != tmp) {
- module->show_port_labels = tmp;
- module->port_size_changed = TRUE;
- module->must_resize = TRUE;
+ if (impl->show_port_labels != tmp) {
+ impl->show_port_labels = tmp;
+ impl->port_size_changed = TRUE;
+ impl->must_resize = TRUE;
/* FIXME
FOREACH_PORT_CONST(gobj()->ports, p) {
(*p)->show_label(b);
@@ -123,10 +129,11 @@ 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);
+ GanvModule* module = GANV_MODULE(object);
+ GanvModuleImpl* impl = module->impl;
switch (prop_id) {
- GET_CASE(SHOW_PORT_LABELS, boolean, module->show_port_labels);
+ GET_CASE(SHOW_PORT_LABELS, boolean, impl->show_port_labels);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -145,8 +152,8 @@ typedef struct {
static void
title_size(GanvModule* module, double* w, double* h)
{
- if (module->box.node.label) {
- g_object_get(G_OBJECT(module->box.node.label),
+ if (module->box.node.impl->label) {
+ g_object_get(G_OBJECT(module->box.node.impl->label),
"width", w,
"height", h,
NULL);
@@ -163,19 +170,18 @@ measure(GanvModule* module, Metrics* m)
double title_w, title_h;
title_size(module, &title_w, &title_h);
- GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
- GanvText* canvas_title = module->box.node.label;
+ GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
+ GanvText* canvas_title = GANV_NODE(module)->impl->label;
+ GanvModuleImpl* impl = module->impl;
- GanvDirection direction = canvas->direction;
-
- if (direction == GANV_DIRECTION_DOWN) {
+ if (canvas->direction == GANV_DIRECTION_DOWN) {
static const double PAD = 2.0;
double contents_width = PAD;
if (canvas_title) {
contents_width += title_w;
}
- if (module->icon_box) {
+ if (impl->icon_box) {
contents_width += MODULE_ICON_SIZE + PAD;
}
@@ -183,10 +189,10 @@ measure(GanvModule* module, Metrics* m)
m->input_width = ganv_module_get_empty_port_breadth(module);
m->output_width = ganv_module_get_empty_port_breadth(module);
- const double ports_width = PAD + ((m->input_width + PAD) * module->ports->len);
+ const double ports_width = PAD + ((m->input_width + PAD) * impl->ports->len);
m->width = MAX(contents_width, ports_width);
- m->width = MAX(m->width, module->embed_width);
+ m->width = MAX(m->width, impl->embed_width);
return;
}
@@ -198,35 +204,35 @@ measure(GanvModule* module, Metrics* m)
? title_w + 10.0
: 1.0;
- if (module->icon_box)
+ if (impl->icon_box)
m->width += MODULE_ICON_SIZE + 2;
// Title is wide, put inputs and outputs beside each other
- m->horiz = (module->widest_input + module->widest_output + 10.0
- < MAX(m->width, module->embed_width));
+ m->horiz = (impl->widest_input + impl->widest_output + 10.0
+ < MAX(m->width, impl->embed_width));
// Fit ports to module (or vice-versa)
- m->input_width = module->widest_input;
- m->output_width = module->widest_output;
+ 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 (module->show_port_labels && !module->embed_item) {
- m->input_width = MAX(module->widest_input, expand_w);
- m->output_width = MAX(module->widest_output, expand_w);
+ if (impl->show_port_labels && !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 (module->embed_item) {
+ 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
- + module->embed_width));
+ + impl->embed_width));
- above_w = MAX(above_w, module->embed_width);
+ above_w = MAX(above_w, impl->embed_width);
// Decide where to place embedded widget if necessary)
- if (module->embed_width < module->embed_height * 2.0) {
+ if (impl->embed_width < impl->embed_height * 2.0) {
m->embed_between = TRUE;
m->width = between_w;
m->embed_x = m->input_width;
@@ -236,8 +242,8 @@ measure(GanvModule* module, Metrics* m)
}
}
- if (!canvas_title && (module->widest_input == 0.0
- || module->widest_output == 0.0)) {
+ if (!canvas_title && (impl->widest_input == 0.0
+ || impl->widest_output == 0.0)) {
m->width += 10.0;
}
@@ -253,12 +259,13 @@ place_title(GanvModule* module, GanvDirection dir)
double title_w, title_h;
title_size(module, &title_w, &title_h);
- GanvText* canvas_title = module->box.node.label;
+ GanvText* canvas_title = GANV_NODE(module)->impl->label;
+ GanvModuleImpl* impl = module->impl;
if (!canvas_title) {
return;
} else if (dir == GANV_DIRECTION_RIGHT) {
- if (module->icon_box) {
+ if (impl->icon_box) {
gnome_canvas_item_set(GNOME_CANVAS_ITEM(canvas_title),
"x", MODULE_ICON_SIZE + 1.0,
NULL);
@@ -280,7 +287,8 @@ place_title(GanvModule* module, GanvDirection dir)
static void
resize_horiz(GanvModule* module)
{
- GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
+ GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
+ GanvModuleImpl* impl = module->impl;
Metrics m;
measure(module, &m);
@@ -293,8 +301,8 @@ resize_horiz(GanvModule* module)
double height = header_height;
- if (module->embed_item) {
- gnome_canvas_item_set(module->embed_item,
+ if (impl->embed_item) {
+ gnome_canvas_item_set(impl->embed_item,
"x", (double)m.embed_x,
NULL);
}
@@ -304,7 +312,7 @@ resize_horiz(GanvModule* module)
// Offset ports below embedded widget
if (!m.embed_between) {
- header_height += module->embed_height;
+ header_height += impl->embed_height;
}
// Move ports to appropriate locations
@@ -312,13 +320,13 @@ resize_horiz(GanvModule* module)
gboolean last_was_input = FALSE;
double y = 0.0;
double h = 0.0;
- FOREACH_PORT(module->ports, pi) {
+ FOREACH_PORT(impl->ports, pi) {
GanvPort* const p = (*pi);
GanvBox* const pbox = GANV_BOX(p);
GanvNode* const pnode = GANV_NODE(p);
h = ganv_box_get_height(pbox);
- if (p->is_input) {
+ if (p->impl->is_input) {
y = header_height + (i * (h + 1.0));
++i;
ganv_box_set_width(pbox, m.input_width);
@@ -343,15 +351,15 @@ resize_horiz(GanvModule* module)
}
}
- if (module->ports->len == 0) {
+ if (impl->ports->len == 0) {
h += header_height;
}
height = y + h + 4.0;
- if (module->embed_item && m.embed_between)
- height = MAX(height, module->embed_height + header_height + 2.0);
+ if (impl->embed_item && m.embed_between)
+ height = MAX(height, impl->embed_height + header_height + 2.0);
- ganv_box_set_height(&module->box, height);
+ ganv_box_set_height(GANV_BOX(module), height);
place_title(module, GANV_DIRECTION_RIGHT);
}
@@ -359,7 +367,8 @@ resize_horiz(GanvModule* module)
static void
resize_vert(GanvModule* module)
{
- GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
+ GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
+ GanvModuleImpl* impl = module->impl;
Metrics m;
measure(module, &m);
@@ -372,27 +381,27 @@ resize_vert(GanvModule* module)
const double port_depth = ganv_module_get_empty_port_depth(module);
const double port_breadth = ganv_module_get_empty_port_breadth(module);
- if (module->embed_item) {
- gnome_canvas_item_set(module->embed_item,
+ if (impl->embed_item) {
+ gnome_canvas_item_set(impl->embed_item,
"x", (double)m.embed_x,
"y", port_depth + title_h,
NULL);
}
const double height = PAD + title_h
- + module->embed_height + (port_depth * 2.0);
+ + impl->embed_height + (port_depth * 2.0);
// Move ports to appropriate locations
int i = 0;
gboolean last_was_input = FALSE;
double x = 0.0;
- FOREACH_PORT(module->ports, pi) {
+ 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);
- if (p->is_input) {
+ if (p->impl->is_input) {
x = PAD + (i * (port_breadth + PAD));
++i;
ganv_node_move_to(pnode, x, 0);
@@ -424,18 +433,20 @@ resize_vert(GanvModule* module)
static void
measure_ports(GanvModule* module)
{
- module->widest_input = 0.0;
- module->widest_output = 0.0;
- FOREACH_PORT_CONST(module->ports, pi) {
+ GanvModuleImpl* 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->is_input) {
- if (w > module->widest_input) {
- module->widest_input = w;
+ 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 > module->widest_output) {
- module->widest_output = w;
+ if (w > impl->widest_output) {
+ impl->widest_output = w;
}
}
}
@@ -444,25 +455,26 @@ measure_ports(GanvModule* module)
static void
layout(GanvNode* self)
{
- GanvModule* module = GANV_MODULE(self);
- GanvNode* node = GANV_NODE(self);
- GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
+ GanvModule* module = GANV_MODULE(self);
+ GanvModuleImpl* impl = module->impl;
+ GanvNode* node = GANV_NODE(self);
+ GanvCanvas* canvas = GANV_CANVAS(GNOME_CANVAS_ITEM(module)->canvas);
double label_w = 0.0;
double label_h = 0.0;
- if (node->label) {
- g_object_get(node->label,
+ if (node->impl->label) {
+ g_object_get(node->impl->label,
"width", &label_w,
"height", &label_h,
NULL);
}
- ganv_box_set_width(&module->box, label_w + (MODULE_LABEL_PAD * 2.0));
- ganv_box_set_height(&module->box, label_h);
+ ganv_box_set_width(GANV_BOX(module), label_w + (MODULE_LABEL_PAD * 2.0));
+ ganv_box_set_height(GANV_BOX(module), label_h);
- if (module->port_size_changed) {
+ if (impl->port_size_changed) {
measure_ports(module);
- module->port_size_changed = FALSE;
+ impl->port_size_changed = FALSE;
}
switch (canvas->direction) {
@@ -474,7 +486,7 @@ layout(GanvNode* self)
break;
}
- module->must_resize = FALSE;
+ impl->must_resize = FALSE;
}
static void
@@ -482,7 +494,7 @@ ganv_module_resize(GanvNode* self)
{
GanvModule* module = GANV_MODULE(self);
- if (module->must_resize) {
+ if (module->impl->must_resize) {
layout(self);
}
@@ -499,7 +511,7 @@ ganv_module_update(GnomeCanvasItem* item,
{
GanvNode* node = GANV_NODE(item);
GanvModule* module = GANV_MODULE(item);
- if (module->must_resize) {
+ if (module->impl->must_resize) {
layout(node);
}
@@ -514,7 +526,7 @@ ganv_module_move_to(GanvNode* node,
{
GanvModule* module = GANV_MODULE(node);
GANV_NODE_CLASS(parent_class)->move_to(node, x, y);
- FOREACH_PORT(module->ports, p) {
+ FOREACH_PORT(module->impl->ports, p) {
ganv_node_move(GANV_NODE(*p), 0.0, 0.0);
}
}
@@ -526,7 +538,7 @@ ganv_module_move(GanvNode* node,
{
GanvModule* module = GANV_MODULE(node);
GANV_NODE_CLASS(parent_class)->move(node, dx, dy);
- FOREACH_PORT(module->ports, p) {
+ FOREACH_PORT(module->impl->ports, p) {
ganv_node_move(GANV_NODE(*p), 0.0, 0.0);
}
}
@@ -541,6 +553,8 @@ ganv_module_class_init(GanvModuleClass* class)
parent_class = GANV_BOX_CLASS(g_type_class_peek_parent(class));
+ g_type_class_add_private(class, sizeof(GanvModuleImpl));
+
gobject_class->set_property = ganv_module_set_property;
gobject_class->get_property = ganv_module_get_property;
@@ -571,20 +585,29 @@ ganv_module_new(GanvCanvas* canvas,
guint
ganv_module_num_ports(const GanvModule* module)
{
- return module->ports ? module->ports->len : 0;
+ return module->impl->ports ? module->impl->ports->len : 0;
+}
+
+GanvPort*
+ganv_module_get_port(GanvModule* module,
+ guint index)
+{
+ return g_ptr_array_index(module->impl->ports, index);
}
void
ganv_module_add_port(GanvModule* module,
GanvPort* port)
{
+ GanvModuleImpl* impl = module->impl;
+
const double width = ganv_port_get_natural_width(port);
- if (port->is_input && width > module->widest_input) {
- module->widest_input = width;
- module->must_resize = TRUE;
- } else if (!port->is_input && width > module->widest_output) {
- module->widest_output = width;
- module->must_resize = TRUE;
+ if (port->impl->is_input && width > impl->widest_input) {
+ impl->widest_input = width;
+ impl->must_resize = TRUE;
+ } else if (!port->impl->is_input && width > impl->widest_output) {
+ impl->widest_output = width;
+ impl->must_resize = TRUE;
}
#if 0
@@ -629,9 +652,9 @@ ganv_module_add_port(GanvModule* module,
place_title();
#endif
- module->must_resize = TRUE;
+ impl->must_resize = TRUE;
- g_ptr_array_add(module->ports, port);
+ g_ptr_array_add(impl->ports, port);
//if (canvas()->direction() == Canvas::HORIZONTAL) {
// set_height(p->get_y() + p->get_height() + 1);
//}
@@ -647,6 +670,7 @@ void
ganv_module_remove_port(GanvModule* module,
GanvPort* port)
{
+ printf("FIXME: remove port\n");
#if 0
gboolean removed = g_ptr_array_remove(gobj()->ports, port->gobj());
if (removed) {
@@ -694,15 +718,17 @@ ganv_module_get_empty_port_depth(const GanvModule* module)
void
ganv_module_set_icon(GanvModule* module,
- GdkPixbuf* icon)
+ GdkPixbuf* icon)
{
- if (module->icon_box) {
- gtk_object_destroy(GTK_OBJECT(module->icon_box));
- module->icon_box = NULL;
+ GanvModuleImpl* impl = module->impl;
+
+ if (impl->icon_box) {
+ gtk_object_destroy(GTK_OBJECT(impl->icon_box));
+ impl->icon_box = NULL;
}
if (icon) {
- module->icon_box = gnome_canvas_item_new(
+ impl->icon_box = gnome_canvas_item_new(
GNOME_CANVAS_GROUP(module),
gnome_canvas_pixbuf_get_type(),
"x", 8.0,
@@ -719,11 +745,11 @@ ganv_module_set_icon(GanvModule* module,
scale, 0.0, 0.0
};
- gnome_canvas_item_affine_relative(module->icon_box, scale_trans);
- gnome_canvas_item_raise_to_top(module->icon_box);
- gnome_canvas_item_show(module->icon_box);
+ gnome_canvas_item_affine_relative(impl->icon_box, scale_trans);
+ gnome_canvas_item_raise_to_top(impl->icon_box);
+ gnome_canvas_item_show(impl->icon_box);
}
- module->must_resize = TRUE;
+ impl->must_resize = TRUE;
}
static void
@@ -731,22 +757,23 @@ on_embed_size_request(GtkWidget* widget,
GtkRequisition* r,
void* user_data)
{
- GanvModule* module = GANV_MODULE(user_data);
- if (module->embed_width == r->width && module->embed_height == r->height) {
+ GanvModule* module = GANV_MODULE(user_data);
+ GanvModuleImpl* impl = module->impl;
+ if (impl->embed_width == r->width && impl->embed_height == r->height) {
return;
}
- module->embed_width = r->width;
- module->embed_height = r->height;
+ impl->embed_width = r->width;
+ impl->embed_height = r->height;
- module->must_resize = TRUE;
+ impl->must_resize = TRUE;
GtkAllocation allocation;
allocation.width = r->width;
allocation.height = r->width;
gtk_widget_size_allocate(widget, &allocation);
- gnome_canvas_item_set(module->embed_item,
+ gnome_canvas_item_set(impl->embed_item,
"width", (double)r->width,
"height", (double)r->height,
NULL);
@@ -756,15 +783,17 @@ void
ganv_module_embed(GanvModule* module,
GtkWidget* widget)
{
- if (module->embed_item) {
- gtk_object_destroy(GTK_OBJECT(module->embed_item));
- module->embed_item = NULL;
+ GanvModuleImpl* impl = module->impl;
+
+ if (impl->embed_item) {
+ gtk_object_destroy(GTK_OBJECT(impl->embed_item));
+ impl->embed_item = NULL;
}
if (!widget) {
- module->embed_width = 0;
- module->embed_height = 0;
- module->must_resize = TRUE;
+ impl->embed_width = 0;
+ impl->embed_height = 0;
+ impl->must_resize = TRUE;
return;
}
@@ -772,7 +801,7 @@ ganv_module_embed(GanvModule* module,
title_size(module, &title_w, &title_h);
const double y = 4.0 + title_h;
- module->embed_item = gnome_canvas_item_new(
+ impl->embed_item = gnome_canvas_item_new(
GNOME_CANVAS_GROUP(module),
gnome_canvas_widget_get_type(),
"x", 2.0,
@@ -786,8 +815,8 @@ ganv_module_embed(GanvModule* module,
gtk_widget_size_request(widget, &r);
on_embed_size_request(widget, &r, module);
- gnome_canvas_item_show(module->embed_item);
- gnome_canvas_item_raise_to_top(module->embed_item);
+ gnome_canvas_item_show(impl->embed_item);
+ gnome_canvas_item_raise_to_top(impl->embed_item);
g_signal_connect(widget, "size-request",
G_CALLBACK(on_embed_size_request), module);
@@ -801,9 +830,10 @@ ganv_module_for_each_port(GanvModule* module,
GanvPortFunction f,
void* data)
{
- const int len = module->ports->len;
- GanvPort** copy = (GanvPort**)malloc(sizeof(GanvPort*) * len);
- memcpy(copy, module->ports->pdata, sizeof(GanvPort*) * len);
+ GanvModuleImpl* 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);
diff --git a/src/node.c b/src/node.c
index b9efb42..5dabd2a 100644
--- a/src/node.c
+++ b/src/node.c
@@ -55,18 +55,21 @@ on_event(GanvNode* node, GdkEvent* event)
static void
ganv_node_init(GanvNode* node)
{
- node->partner = NULL;
- node->label = NULL;
- node->dash_length = 0.0;
- node->dash_offset = 0.0;
- node->border_width = 2.0;
- node->fill_color = DEFAULT_FILL_COLOR;
- node->border_color = DEFAULT_BORDER_COLOR;
- node->can_tail = FALSE;
- node->can_head = FALSE;
- node->selected = FALSE;
- node->highlighted = FALSE;
- node->draggable = FALSE;
+ GanvNodeImpl* impl = GANV_NODE_GET_PRIVATE(node);
+ node->impl = impl;
+
+ impl->partner = NULL;
+ impl->label = NULL;
+ impl->dash_length = 0.0;
+ impl->dash_offset = 0.0;
+ impl->border_width = 2.0;
+ impl->fill_color = DEFAULT_FILL_COLOR;
+ impl->border_color = DEFAULT_BORDER_COLOR;
+ impl->can_tail = FALSE;
+ impl->can_head = FALSE;
+ impl->selected = FALSE;
+ impl->highlighted = FALSE;
+ impl->draggable = FALSE;
g_signal_connect(G_OBJECT(node),
"event", G_CALLBACK(on_event), node);
@@ -86,10 +89,11 @@ ganv_node_destroy(GtkObject* object)
g_return_if_fail(object != NULL);
g_return_if_fail(GANV_IS_NODE(object));
- GanvNode* node = GANV_NODE(object);
- if (node->label) {
- gtk_object_destroy(GTK_OBJECT(node->label));
- node->label = NULL;
+ GanvNode* node = GANV_NODE(object);
+ GanvNodeImpl* impl = node->impl;
+ if (impl->label) {
+ gtk_object_destroy(GTK_OBJECT(impl->label));
+ impl->label = NULL;
}
GnomeCanvasItem* item = GNOME_CANVAS_ITEM(object);
@@ -99,7 +103,7 @@ ganv_node_destroy(GtkObject* object)
item->canvas = NULL;
}
- node->partner = NULL;
+ impl->partner = NULL;
if (GTK_OBJECT_CLASS(parent_class)->destroy) {
(*GTK_OBJECT_CLASS(parent_class)->destroy)(object);
@@ -116,20 +120,21 @@ ganv_node_set_property(GObject* object,
g_return_if_fail(GANV_IS_NODE(object));
GanvNode* node = GANV_NODE(object);
+ GanvNodeImpl* impl = node->impl;
GnomeCanvasItem* item = GNOME_CANVAS_ITEM(object);
switch (prop_id) {
- SET_CASE(PARTNER, object, node->partner);
- SET_CASE(DASH_LENGTH, double, node->dash_length);
- SET_CASE(DASH_OFFSET, double, node->dash_offset);
- SET_CASE(BORDER_WIDTH, double, node->border_width);
- SET_CASE(FILL_COLOR, uint, node->fill_color);
- SET_CASE(BORDER_COLOR, uint, node->border_color);
- SET_CASE(CAN_TAIL, boolean, node->can_tail);
- SET_CASE(CAN_HEAD, boolean, node->can_head);
- SET_CASE(SELECTED, boolean, node->selected);
- SET_CASE(HIGHLIGHTED, boolean, node->highlighted);
- SET_CASE(DRAGGABLE, boolean, node->draggable);
+ SET_CASE(PARTNER, object, impl->partner);
+ SET_CASE(DASH_LENGTH, double, impl->dash_length);
+ SET_CASE(DASH_OFFSET, double, impl->dash_offset);
+ SET_CASE(BORDER_WIDTH, double, impl->border_width);
+ SET_CASE(FILL_COLOR, uint, impl->fill_color);
+ SET_CASE(BORDER_COLOR, uint, impl->border_color);
+ SET_CASE(CAN_TAIL, boolean, impl->can_tail);
+ SET_CASE(CAN_HEAD, boolean, impl->can_head);
+ SET_CASE(SELECTED, boolean, impl->selected);
+ SET_CASE(HIGHLIGHTED, boolean, impl->highlighted);
+ SET_CASE(DRAGGABLE, boolean, impl->draggable);
case PROP_CANVAS:
if (!item->parent) {
GnomeCanvas* canvas = GNOME_CANVAS(g_value_get_object(value));
@@ -159,23 +164,24 @@ ganv_node_get_property(GObject* object,
g_return_if_fail(GANV_IS_NODE(object));
GanvNode* node = GANV_NODE(object);
+ GanvNodeImpl* impl = node->impl;
GnomeCanvasItem* item = GNOME_CANVAS_ITEM(object);
typedef char* gstring;
switch (prop_id) {
- GET_CASE(PARTNER, object, node->partner);
- GET_CASE(LABEL, string, node->label->text);
- GET_CASE(DASH_LENGTH, double, node->dash_length);
- GET_CASE(DASH_OFFSET, double, node->dash_offset);
- GET_CASE(BORDER_WIDTH, double, node->border_width);
- GET_CASE(FILL_COLOR, uint, node->fill_color);
- GET_CASE(BORDER_COLOR, uint, node->border_color);
- GET_CASE(CAN_TAIL, boolean, node->can_tail);
- GET_CASE(CAN_HEAD, boolean, node->can_head);
- GET_CASE(SELECTED, boolean, node->selected);
- GET_CASE(HIGHLIGHTED, boolean, node->highlighted);
- GET_CASE(DRAGGABLE, boolean, node->draggable);
+ GET_CASE(PARTNER, object, impl->partner);
+ GET_CASE(LABEL, string, impl->label->impl->text);
+ GET_CASE(DASH_LENGTH, double, impl->dash_length);
+ GET_CASE(DASH_OFFSET, double, impl->dash_offset);
+ GET_CASE(BORDER_WIDTH, double, impl->border_width);
+ GET_CASE(FILL_COLOR, uint, impl->fill_color);
+ GET_CASE(BORDER_COLOR, uint, impl->border_color);
+ GET_CASE(CAN_TAIL, boolean, impl->can_tail);
+ GET_CASE(CAN_HEAD, boolean, impl->can_head);
+ GET_CASE(SELECTED, boolean, impl->selected);
+ GET_CASE(HIGHLIGHTED, boolean, impl->highlighted);
+ GET_CASE(DRAGGABLE, boolean, impl->draggable);
case PROP_CANVAS:
g_value_set_object(value, item->canvas);
break;
@@ -227,41 +233,38 @@ ganv_node_get_draw_properties(const GanvNode* node,
double* border_color,
double* fill_color)
{
- *dash_length = node->dash_length;
- *border_color = node->border_color;
- *fill_color = node->fill_color;
+ GanvNodeImpl* impl = node->impl;
- if (node->selected) {
+ *dash_length = impl->dash_length;
+ *border_color = impl->border_color;
+ *fill_color = impl->fill_color;
+
+ if (impl->selected) {
*dash_length = 4.0;
- *border_color = highlight_color(node->border_color, 0x20);
+ *border_color = highlight_color(impl->border_color, 0x20);
}
- if (node->highlighted) {
- *fill_color = highlight_color(node->fill_color, 0x20);
- *border_color = highlight_color(node->border_color, 0x20);
+ if (impl->highlighted) {
+ *fill_color = highlight_color(impl->fill_color, 0x20);
+ *border_color = highlight_color(impl->border_color, 0x20);
}
}
-const char*
-ganv_node_get_label(const GanvNode* node)
-{
- return node->label ? node->label->text : NULL;
-}
-
void
ganv_node_set_label(GanvNode* node, const char* str)
{
+ GanvNodeImpl* impl = node->impl;
if (str[0] == '\0' || !str) {
- if (node->label) {
- gtk_object_destroy(GTK_OBJECT(node->label));
- node->label = NULL;
+ if (impl->label) {
+ gtk_object_destroy(GTK_OBJECT(impl->label));
+ impl->label = NULL;
}
- } else if (node->label) {
- gnome_canvas_item_set(GNOME_CANVAS_ITEM(node->label),
+ } else if (impl->label) {
+ gnome_canvas_item_set(GNOME_CANVAS_ITEM(impl->label),
"text", str,
NULL);
} else {
- node->label = GANV_TEXT(gnome_canvas_item_new(
+ impl->label = GANV_TEXT(gnome_canvas_item_new(
GNOME_CANVAS_GROUP(node),
ganv_text_get_type(),
"text", str,
@@ -277,10 +280,10 @@ ganv_node_set_label(GanvNode* node, const char* str)
static void
ganv_node_default_tick(GanvNode* self,
- double seconds)
+ double seconds)
{
GanvNode* node = GANV_NODE(self);
- node->dash_offset = seconds * 8.0;
+ node->impl->dash_offset = seconds * 8.0;
gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(self));
}
@@ -315,10 +318,10 @@ ganv_node_default_move_to(GanvNode* node,
"x", x,
"y", y,
NULL);
- if (node->can_tail) {
+ if (node->impl->can_tail) {
ganv_canvas_for_each_edge_from(
canvas, node, ganv_edge_update_location);
- } else if (node->can_head) {
+ } else if (node->impl->can_head) {
ganv_canvas_for_each_edge_to(
canvas, node, ganv_edge_update_location);
}
@@ -357,7 +360,7 @@ ganv_node_default_on_event(GanvNode* node,
drag_start_y = event->button.y;
last_x = event->button.x;
last_y = event->button.y;
- if (!canvas->locked && node->draggable && event->button.button == 1) {
+ if (!canvas->locked && node->impl->draggable && event->button.button == 1) {
gnome_canvas_item_grab(
GNOME_CANVAS_ITEM(node),
GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_PRESS_MASK,
@@ -444,6 +447,8 @@ ganv_node_class_init(GanvNodeClass* class)
parent_class = GNOME_CANVAS_GROUP_CLASS(g_type_class_peek_parent(class));
+ g_type_class_add_private(class, sizeof(GanvNodeImpl));
+
gobject_class->set_property = ganv_node_set_property;
gobject_class->get_property = ganv_node_get_property;
@@ -583,3 +588,105 @@ to its partner."),
class->head_vector = ganv_node_default_head_vector;
class->on_event = ganv_node_default_on_event;
}
+gboolean
+ganv_node_can_tail(const GanvNode* self)
+{
+ return self->impl->can_tail;
+}
+
+gboolean
+ganv_node_can_head(const GanvNode* self)
+{
+ return self->impl->can_head;
+}
+
+gboolean
+ganv_node_is_within(const GanvNode* self,
+ double x1,
+ double y1,
+ double x2,
+ double y2)
+{
+ return GANV_NODE_GET_CLASS(self)->is_within(
+ self, x1, y1, x2, y2);
+}
+
+void
+ganv_node_tick(GanvNode* self,
+ double seconds)
+{
+ GanvNodeClass* klass = GANV_NODE_GET_CLASS(self);
+ if (klass->tick) {
+ klass->tick(self, seconds);
+ }
+}
+
+void
+ganv_node_tail_vector(const GanvNode* self,
+ const GanvNode* head,
+ double* x1,
+ double* y1,
+ double* x2,
+ double* y2)
+{
+ GANV_NODE_GET_CLASS(self)->tail_vector(
+ self, head, x1, y1, x2, y2);
+}
+
+void
+ganv_node_head_vector(const GanvNode* self,
+ const GanvNode* tail,
+ double* x1,
+ double* y1,
+ double* x2,
+ double* y2)
+{
+ GANV_NODE_GET_CLASS(self)->head_vector(
+ self, tail, x1, y1, x2, y2);
+}
+
+const char*
+ganv_node_get_label(const GanvNode* node)
+{
+ return node->impl->label ? node->impl->label->impl->text : NULL;
+}
+
+GanvNode*
+ganv_node_get_partner(const GanvNode* node)
+{
+ return node->impl->partner;
+}
+
+void ganv_node_set_label(GanvNode* node,
+ const char* str);
+
+void
+ganv_node_move(GanvNode* node,
+ double dx,
+ double dy)
+{
+ GANV_NODE_GET_CLASS(node)->move(node, dx, dy);
+}
+
+void
+ganv_node_move_to(GanvNode* node,
+ double x,
+ double y)
+{
+ GANV_NODE_GET_CLASS(node)->move_to(node, x, y);
+}
+
+void
+ganv_node_resize(GanvNode* node)
+{
+ GanvNodeClass* klass = GANV_NODE_GET_CLASS(node);
+ if (klass->resize) {
+ klass->resize(node);
+ }
+}
+
+void
+ganv_node_disconnect(GanvNode* node)
+{
+ GANV_NODE_GET_CLASS(node)->disconnect(node);
+}
diff --git a/src/port.c b/src/port.c
index f260662..dc4aed7 100644
--- a/src/port.c
+++ b/src/port.c
@@ -38,7 +38,8 @@ enum {
static void
ganv_port_init(GanvPort* port)
{
- port->is_input = TRUE;
+ port->impl = GANV_PORT_GET_PRIVATE(port);
+ port->impl->is_input = TRUE;
}
static void
@@ -47,17 +48,20 @@ 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);
+ GnomeCanvasItem* item = GNOME_CANVAS_ITEM(object);
+ GanvPort* port = GANV_PORT(object);
+ GanvCanvas* canvas = GANV_CANVAS(item->canvas);
+ if (canvas) {
+ if (port->impl->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);
+ }
+ item->canvas = NULL;
}
if (GTK_OBJECT_CLASS(parent_class)->destroy) {
@@ -77,7 +81,7 @@ ganv_port_set_property(GObject* object,
GanvPort* port = GANV_PORT(object);
switch (prop_id) {
- SET_CASE(IS_INPUT, boolean, port->is_input);
+ SET_CASE(IS_INPUT, boolean, port->impl->is_input);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -96,7 +100,7 @@ ganv_port_get_property(GObject* object,
GanvPort* port = GANV_PORT(object);
switch (prop_id) {
- GET_CASE(IS_INPUT, boolean, port->is_input);
+ GET_CASE(IS_INPUT, boolean, port->impl->is_input);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -152,7 +156,7 @@ ganv_port_resize(GanvNode* self)
GanvNode* node = GANV_NODE(self);
double label_w, label_h;
- g_object_get(node->label,
+ g_object_get(node->impl->label,
"width", &label_w,
"height", &label_h,
NULL);
@@ -160,7 +164,7 @@ ganv_port_resize(GanvNode* self)
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),
+ gnome_canvas_item_set(GNOME_CANVAS_ITEM(node->impl->label),
"x", PORT_LABEL_HPAD,
"y", PORT_LABEL_VPAD,
NULL);
@@ -176,8 +180,8 @@ ganv_port_set_width(GanvBox* box,
{
GanvPort* port = GANV_PORT(box);
parent_class->set_width(box, width);
- if (port->control) {
- ganv_port_set_control_value(port, port->control->value);
+ if (port->impl->control) {
+ ganv_port_set_control_value(port, port->impl->control->value);
}
}
@@ -187,10 +191,10 @@ ganv_port_set_height(GanvBox* box,
{
GanvPort* port = GANV_PORT(box);
parent_class->set_height(box, height);
- if (port->control) {
+ if (port->impl->control) {
double control_y1;
- g_object_get(port->control->rect, "y1", &control_y1, NULL);
- gnome_canvas_item_set(GNOME_CANVAS_ITEM(port->control->rect),
+ g_object_get(port->impl->control->rect, "y1", &control_y1, NULL);
+ gnome_canvas_item_set(GNOME_CANVAS_ITEM(port->impl->control->rect),
"y2", control_y1 + height,
NULL);
}
@@ -215,6 +219,8 @@ ganv_port_class_init(GanvPortClass* class)
parent_class = GANV_BOX_CLASS(g_type_class_peek_parent(class));
+ g_type_class_add_private(class, sizeof(GanvPortImpl));
+
gobject_class->set_property = ganv_port_set_property;
gobject_class->get_property = ganv_port_get_property;
@@ -253,21 +259,21 @@ ganv_port_new(GanvModule* module,
first_prop_name, args);
va_end(args);
- port->is_input = is_input;
+ port->impl->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);
+ 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);
GanvNode* node = GANV_NODE(port);
- node->can_tail = !is_input;
- node->can_head = is_input;
- node->draggable = FALSE;
+ node->impl->can_tail = !is_input;
+ node->impl->can_head = is_input;
+ node->impl->draggable = FALSE;
GanvCanvas* canvas = GANV_CANVAS(item->canvas);
- if (!node->label) {
+ if (!node->impl->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_DIRECTION_RIGHT) {
@@ -286,39 +292,41 @@ ganv_port_new(GanvModule* module,
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));
+ GanvPortControl* control = (GanvPortControl*)malloc(sizeof(GanvPortControl));
+ port->impl->control = control;
+
+ control->value = 0.0f;
+ control->min = 0.0f;
+ control->max = 0.0f;
+ control->is_toggle = FALSE;
+ 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(control->rect));
}
void
ganv_port_hide_control(GanvPort* port)
{
- gtk_object_destroy(GTK_OBJECT(port->control->rect));
- free(port->control);
- port->control = NULL;
+ gtk_object_destroy(GTK_OBJECT(port->impl->control->rect));
+ free(port->impl->control);
+ port->impl->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);
+ if (port->impl->control) {
+ port->impl->control->is_toggle = is_toggle;
+ ganv_port_set_control_value(port, port->impl->control->value);
}
}
@@ -326,60 +334,61 @@ void
ganv_port_set_control_value(GanvPort* port,
float value)
{
- if (!port->control) {
+ GanvPortImpl* impl = port->impl;
+ if (!impl->control) {
return;
}
- if (port->control->is_toggle) {
+ if (impl->control->is_toggle) {
if (value != 0.0) {
- value = port->control->max;
+ value = impl->control->max;
} else {
- value = port->control->min;
+ value = impl->control->min;
}
}
- if (value < port->control->min) {
- port->control->min = value;
+ if (value < impl->control->min) {
+ impl->control->min = value;
}
- if (value > port->control->max) {
- port->control->max = value;
+ if (value > impl->control->max) {
+ impl->control->max = value;
}
- if (port->control->max == port->control->min) {
- port->control->max = port->control->min + 1.0;
+ if (impl->control->max == impl->control->min) {
+ impl->control->max = impl->control->min + 1.0;
}
const int inf = isinf(value);
if (inf == -1) {
- value = port->control->min;
+ value = impl->control->min;
} else if (inf == 1) {
- value = port->control->max;
+ value = impl->control->max;
}
- const double w = (value - port->control->min)
- / (port->control->max - port->control->min)
+ const double w = (value - impl->control->min)
+ / (impl->control->max - impl->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));
+ ganv_box_set_width(impl->control->rect, MAX(0.0, w - 1.0));
#if 0
if (signal && _control->value == value)
signal = false;
#endif
- port->control->value = value;
+ impl->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);
+ if (port->impl->control) {
+ port->impl->control->min = min;
+ ganv_port_set_control_value(port, port->impl->control->value);
}
}
@@ -387,9 +396,9 @@ 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);
+ if (port->impl->control) {
+ port->impl->control->max = max;
+ ganv_port_set_control_value(port, port->impl->control->value);
}
}
@@ -401,9 +410,9 @@ ganv_port_get_natural_width(const GanvPort* port)
if (canvas->direction() == Canvas::VERTICAL) {
return _module->empty_port_breadth();
} else*/
- if (port->box.node.label) {
+ if (port->box.node.impl->label) {
double label_w;
- g_object_get(port->box.node.label, "width", &label_w, NULL);
+ g_object_get(port->box.node.impl->label, "width", &label_w, NULL);
return label_w + (PORT_LABEL_HPAD * 2.0);
} else {
//return _module->empty_port_depth();
@@ -416,3 +425,33 @@ ganv_port_get_module(const GanvPort* port)
{
return GANV_MODULE(GNOME_CANVAS_ITEM(port)->parent);
}
+
+float
+ganv_port_get_control_value(const GanvPort* port)
+{
+ return port->impl->control ? port->impl->control->value : 0.0f;
+}
+
+float
+ganv_port_get_control_min(const GanvPort* port)
+{
+ return port->impl->control ? port->impl->control->min : 0.0f;
+}
+
+float
+ganv_port_get_control_max(const GanvPort* port)
+{
+ return port->impl->control ? port->impl->control->max : 0.0f;
+}
+
+gboolean
+ganv_port_is_input(const GanvPort* port)
+{
+ return port->impl->is_input;
+}
+
+gboolean
+ganv_port_is_output(const GanvPort* port)
+{
+ return !port->impl->is_input;
+}
diff --git a/src/text.c b/src/text.c
index 0b1def7..98fc471 100644
--- a/src/text.c
+++ b/src/text.c
@@ -26,6 +26,7 @@
#include "./color.h"
#include "./boilerplate.h"
#include "./gettext.h"
+#include "./ganv-private.h"
G_DEFINE_TYPE(GanvText, ganv_text, GNOME_TYPE_CANVAS_ITEM)
@@ -44,15 +45,18 @@ enum {
static void
ganv_text_init(GanvText* text)
{
- memset(&text->coords, '\0', sizeof(GanvTextCoords));
- text->coords.width = 1.0;
- text->coords.height = 1.0;
- text->old_coords = text->coords;
-
- text->surface = NULL;
- text->text = NULL;
- text->color = 0xFFFFFFFF;
- text->needs_layout = FALSE;
+ GanvTextImpl* impl = GANV_TEXT_GET_PRIVATE(text);
+ text->impl = impl;
+
+ memset(&impl->coords, '\0', sizeof(GanvTextCoords));
+ impl->coords.width = 1.0;
+ impl->coords.height = 1.0;
+ impl->old_coords = impl->coords;
+
+ impl->surface = NULL;
+ impl->text = NULL;
+ impl->color = 0xFFFFFFFF;
+ impl->needs_layout = FALSE;
}
static void
@@ -61,16 +65,17 @@ ganv_text_destroy(GtkObject* object)
g_return_if_fail(object != NULL);
g_return_if_fail(GANV_IS_TEXT(object));
- GanvText* text = GANV_TEXT(object);
+ GanvText* text = GANV_TEXT(object);
+ GanvTextImpl* impl = text->impl;
- if (text->text) {
- g_free(text->text);
- text->text = NULL;
+ if (impl->text) {
+ g_free(impl->text);
+ impl->text = NULL;
}
- if (text->surface) {
- cairo_surface_destroy(text->surface);
- text->surface = NULL;
+ if (impl->surface) {
+ cairo_surface_destroy(impl->surface);
+ impl->surface = NULL;
}
if (GTK_OBJECT_CLASS(parent_class)->destroy) {
@@ -81,6 +86,7 @@ ganv_text_destroy(GtkObject* object)
static void
ganv_text_layout(GanvText* text)
{
+ GanvTextImpl* impl = text->impl;
GnomeCanvasItem* item = GNOME_CANVAS_ITEM(text);
GanvCanvas* canvas = GANV_CANVAS(item->canvas);
GtkWidget* widget = GTK_WIDGET(canvas);
@@ -89,7 +95,7 @@ ganv_text_layout(GanvText* text)
GtkStyle* style = gtk_rc_get_style(widget);
PangoFontDescription* font = pango_font_description_copy(style->font_desc);
- PangoLayout* layout = gtk_widget_create_pango_layout(widget, text->text);
+ PangoLayout* layout = gtk_widget_create_pango_layout(widget, impl->text);
PangoContext* context = pango_layout_get_context(layout);
cairo_font_options_t* options = cairo_font_options_copy(
pango_cairo_context_get_font_options(context));
@@ -107,17 +113,17 @@ ganv_text_layout(GanvText* text)
int width, height;
pango_layout_get_pixel_size(layout, &width, &height);
- text->coords.width = width;
- text->coords.height = height;
+ impl->coords.width = width;
+ impl->coords.height = height;
- if (text->surface) {
- cairo_surface_destroy(text->surface);
+ if (impl->surface) {
+ cairo_surface_destroy(impl->surface);
}
- text->surface = cairo_image_surface_create(
+ impl->surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, width, height);
- cairo_t* cr = cairo_create(text->surface);
+ cairo_t* cr = cairo_create(impl->surface);
double r, g, b, a;
color_to_rgba(color, &r, &g, &b, &a);
@@ -130,7 +136,7 @@ ganv_text_layout(GanvText* text)
g_object_unref(layout);
pango_font_description_free(font);
- text->needs_layout = FALSE;
+ impl->needs_layout = FALSE;
gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(text));
}
@@ -143,18 +149,19 @@ ganv_text_set_property(GObject* object,
g_return_if_fail(object != NULL);
g_return_if_fail(GANV_IS_TEXT(object));
- GanvText* text = GANV_TEXT(object);
+ GanvText* text = GANV_TEXT(object);
+ GanvTextImpl* impl = text->impl;
switch (prop_id) {
- SET_CASE(X, double, text->coords.x);
- SET_CASE(Y, double, text->coords.y);
- SET_CASE(WIDTH, double, text->coords.width);
- SET_CASE(HEIGHT, double, text->coords.height);
- SET_CASE(COLOR, uint, text->color)
+ SET_CASE(X, double, impl->coords.x);
+ SET_CASE(Y, double, impl->coords.y);
+ SET_CASE(WIDTH, double, impl->coords.width);
+ SET_CASE(HEIGHT, double, impl->coords.height);
+ SET_CASE(COLOR, uint, impl->color)
case PROP_TEXT:
- free(text->text);
- text->text = g_value_dup_string(value);
- text->needs_layout = TRUE;
+ free(impl->text);
+ impl->text = g_value_dup_string(value);
+ impl->needs_layout = TRUE;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -171,20 +178,21 @@ ganv_text_get_property(GObject* object,
g_return_if_fail(object != NULL);
g_return_if_fail(GANV_IS_TEXT(object));
- GanvText* text = GANV_TEXT(object);
+ GanvText* text = GANV_TEXT(object);
+ GanvTextImpl* impl = text->impl;
- if (text->needs_layout && (prop_id == PROP_WIDTH
+ if (impl->needs_layout && (prop_id == PROP_WIDTH
|| prop_id == PROP_HEIGHT)) {
ganv_text_layout(text);
}
switch (prop_id) {
- GET_CASE(TEXT, string, text->text);
- GET_CASE(X, double, text->coords.x);
- GET_CASE(Y, double, text->coords.y);
- GET_CASE(WIDTH, double, text->coords.width);
- GET_CASE(HEIGHT, double, text->coords.height);
- GET_CASE(COLOR, uint, text->color);
+ GET_CASE(TEXT, string, impl->text);
+ GET_CASE(X, double, impl->coords.x);
+ GET_CASE(Y, double, impl->coords.y);
+ GET_CASE(WIDTH, double, impl->coords.width);
+ GET_CASE(HEIGHT, double, impl->coords.height);
+ GET_CASE(COLOR, uint, impl->color);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -196,16 +204,17 @@ ganv_text_bounds_item(GnomeCanvasItem* item,
double* x1, double* y1,
double* x2, double* y2)
{
- GanvText* text = GANV_TEXT(item);
+ GanvText* text = GANV_TEXT(item);
+ GanvTextImpl* impl = text->impl;
- if (text->needs_layout) {
+ if (impl->needs_layout) {
ganv_text_layout(text);
}
- *x1 = MIN(text->coords.x, text->coords.x + text->coords.width);
- *y1 = MIN(text->coords.y, text->coords.y + text->coords.height);
- *x2 = MAX(text->coords.x, text->coords.x + text->coords.width);
- *y2 = MAX(text->coords.y, text->coords.y + text->coords.height);
+ *x1 = MIN(impl->coords.x, impl->coords.x + impl->coords.width);
+ *y1 = MIN(impl->coords.y, impl->coords.y + impl->coords.height);
+ *x2 = MAX(impl->coords.x, impl->coords.x + impl->coords.width);
+ *y2 = MAX(impl->coords.y, impl->coords.y + impl->coords.height);
}
static void
@@ -238,7 +247,7 @@ ganv_text_update(GnomeCanvasItem* item,
}
static double
-ganv_text_point(GnomeCanvasItem* item,
+ganv_text_point(GnomeCanvasItem* item,
double x, double y,
int cx, int cy,
GnomeCanvasItem** actual_item)
@@ -288,18 +297,19 @@ ganv_text_draw(GnomeCanvasItem* item,
int x, int y,
int width, int height)
{
- GanvText* text = GANV_TEXT(item);
- cairo_t* cr = gdk_cairo_create(drawable);
+ GanvText* text = GANV_TEXT(item);
+ GanvTextImpl* impl = text->impl;
+ cairo_t* cr = gdk_cairo_create(drawable);
- double wx = text->coords.x;
- double wy = text->coords.y;
+ double wx = impl->coords.x;
+ double wy = impl->coords.y;
gnome_canvas_item_i2w(item, &wx, &wy);
// Round to the nearest pixel so text isn't blurry
wx = lrint(wx - x);
wy = lrint(wy - y);
- cairo_set_source_surface(cr, text->surface, wx, wy);
+ cairo_set_source_surface(cr, impl->surface, wx, wy);
cairo_paint(cr);
cairo_destroy(cr);
@@ -314,6 +324,8 @@ ganv_text_class_init(GanvTextClass* class)
parent_class = GNOME_CANVAS_ITEM_CLASS(g_type_class_peek_parent(class));
+ g_type_class_add_private(class, sizeof(GanvTextImpl));
+
gobject_class->set_property = ganv_text_set_property;
gobject_class->get_property = ganv_text_get_property;