diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Canvas.cpp | 117 | ||||
-rw-r--r-- | src/box.c | 197 | ||||
-rw-r--r-- | src/circle.c | 59 | ||||
-rw-r--r-- | src/edge.c | 193 | ||||
-rw-r--r-- | src/ganv-private.h | 130 | ||||
-rw-r--r-- | src/module.c | 282 | ||||
-rw-r--r-- | src/node.c | 237 | ||||
-rw-r--r-- | src/port.c | 191 | ||||
-rw-r--r-- | src/text.c | 118 |
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); @@ -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; @@ -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); @@ -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); +} @@ -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; +} @@ -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; |