summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2015-02-21 23:32:24 +0000
committerDavid Robillard <d@drobilla.net>2015-02-21 23:32:24 +0000
commitef71a1da33a3c68cad782029cacbc1d01328b4d6 (patch)
treef5bb6f29c467bf91c0ab8ca5072a81408522a311
parent23682cbf1f98f35d4341efe354bee6f770d482e2 (diff)
downloadganv-ef71a1da33a3c68cad782029cacbc1d01328b4d6.tar.gz
ganv-ef71a1da33a3c68cad782029cacbc1d01328b4d6.tar.bz2
ganv-ef71a1da33a3c68cad782029cacbc1d01328b4d6.zip
Add API to specify module port order.
Also fix various redundant resize/update issues, improve performance. git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@5592 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--NEWS6
-rw-r--r--ganv/Canvas.hpp16
-rw-r--r--ganv/Item.hpp3
-rw-r--r--ganv/canvas.h33
-rw-r--r--ganv/item.h4
-rw-r--r--ganv/wrap.hpp9
-rw-r--r--src/Canvas.cpp48
-rw-r--r--src/box.c21
-rw-r--r--src/circle.c7
-rw-r--r--src/edge.c6
-rw-r--r--src/ganv-private.h14
-rw-r--r--src/group.c4
-rw-r--r--src/item.c30
-rw-r--r--src/module.c123
-rw-r--r--src/node.c50
-rw-r--r--src/port.c22
-rw-r--r--src/text.c40
-rw-r--r--wscript2
18 files changed, 289 insertions, 149 deletions
diff --git a/NEWS b/NEWS
index bf7bda2..b20cc3a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-ganv (1.5.1) unstable;
+ganv (1.5.2) unstable;
* Fix positioning of embedded widgets when changing layout.
* Fix unexpected node jumping when dragging new connections.
@@ -7,12 +7,14 @@ ganv (1.5.1) unstable;
* Distinguish edge color from port color slighly.
* Add support for PDF and PS export.
* Improve text rendering at high zoom.
+ * Improve update performance.
+ * Add API to specify module port order.
* Fix various minor visual alignment/sizing issues.
* Fix size of vertical flow modules.
* Fix compilation with --no-fdgl (patch from Vlad Glagolev).
* Fix crash when destroying canvas.
- -- David Robillard <d@drobilla.net> Fri, 20 Feb 2015 09:00:29 -0500
+ -- David Robillard <d@drobilla.net> Sat, 21 Feb 2015 17:21:25 -0500
ganv (1.4.2) stable;
diff --git a/ganv/Canvas.hpp b/ganv/Canvas.hpp
index e22c691..46c2d5e 100644
--- a/ganv/Canvas.hpp
+++ b/ganv/Canvas.hpp
@@ -25,8 +25,6 @@
#include "ganv/canvas.h"
#include "ganv/wrap.hpp"
-GANV_GLIB_WRAP(Canvas)
-
/** Ganv namespace, everything is defined under this.
*
* @ingroup Ganv
@@ -121,6 +119,10 @@ public:
RW_PROPERTY(double, height)
RW_PROPERTY(GanvDirection, direction);
+ void set_port_order(GanvPortOrderFunc port_cmp, void* data) {
+ ganv_canvas_set_port_order(gobj(), port_cmp, data);
+ }
+
Gtk::Layout& widget() {
return *Glib::wrap(&_gobj->layout);
}
@@ -143,4 +145,14 @@ private:
} // namespace Ganv
+namespace Glib {
+
+static inline Ganv::Canvas*
+wrap(GanvCanvas* canvas)
+{
+ return (Ganv::Canvas*)ganv_canvas_get_wrapper(canvas);
+}
+
+} // namespace Glib
+
#endif // GANV_CANVAS_HPP
diff --git a/ganv/Item.hpp b/ganv/Item.hpp
index fb2667d..a2dbadc 100644
--- a/ganv/Item.hpp
+++ b/ganv/Item.hpp
@@ -40,9 +40,8 @@ public:
Item(GanvItem* gobj)
: _gobj(gobj)
{
- GQuark wrapper_key = g_quark_from_string("ganvmm");
+ ganv_item_set_wrapper(gobj, this);
if (gobj && ganv_item_get_parent(gobj)) {
- g_object_set_qdata(G_OBJECT(_gobj), wrapper_key, this);
g_signal_connect(
G_OBJECT(_gobj), "event", G_CALLBACK(on_item_event), this);
}
diff --git a/ganv/canvas.h b/ganv/canvas.h
index e923f65..e2a9867 100644
--- a/ganv/canvas.h
+++ b/ganv/canvas.h
@@ -91,6 +91,8 @@ typedef void (*GanvEdgeFunc)(GanvEdge* edge, void* data);
*/
typedef void (*GanvNodeFunc)(GanvNode* node, void* data);
+typedef int (*GanvPortOrderFunc)(const GanvPort*, const GanvPort*, void* data);
+
/**
* ganv_canvas_new:
*
@@ -100,6 +102,22 @@ GanvCanvas*
ganv_canvas_new(double width, double height);
/**
+ * ganv_canvas_set_wrapper:
+ *
+ * Set the opaque wrapper object for the canvas.
+ */
+void
+ganv_canvas_set_wrapper(GanvCanvas* canvas, void* wrapper);
+
+/**
+ * ganv_canvas_get_wrapper:
+ *
+ * Return an opaque pointer to the wrapper for the canvas.
+ */
+void*
+ganv_canvas_get_wrapper(GanvCanvas* canvas);
+
+/**
* ganv_canvas_clear:
*
* Remove all items from the canvas.
@@ -592,6 +610,21 @@ ganv_canvas_get_move_cursor(const GanvCanvas* canvas);
void
ganv_canvas_move_contents_to(GanvCanvas* canvas, double x, double y);
+/**
+ * ganv_canvas_set_port_order:
+ * @canvas The canvas to set the default port order on.
+ * @port_cmp Port comparison function.
+ * @data Data to be passed to order.
+ *
+ * Set a comparator function to use as the default order for ports on modules.
+ * If left unset, ports are shown in the order they are added.
+ */
+void
+ganv_canvas_set_port_order(GanvCanvas* canvas,
+ GanvPortOrderFunc port_cmp,
+ void* data);
+
+
G_END_DECLS
#endif /* GANV_CANVAS_H */
diff --git a/ganv/item.h b/ganv/item.h
index d6e9cc5..c538e5a 100644
--- a/ganv/item.h
+++ b/ganv/item.h
@@ -175,6 +175,10 @@ void ganv_item_get_bounds(GanvItem* item,
void ganv_item_request_update(GanvItem* item);
+void ganv_item_set_wrapper(GanvItem* item, void* wrapper);
+
+void* ganv_item_get_wrapper(GanvItem* item);
+
G_END_DECLS
#endif /* GANV_ITEM_H */
diff --git a/ganv/wrap.hpp b/ganv/wrap.hpp
index f907dea..c444e00 100644
--- a/ganv/wrap.hpp
+++ b/ganv/wrap.hpp
@@ -115,12 +115,17 @@ private: \
wrap(Ganv##Name* gobj) \
{ \
if (gobj) { \
- GQuark key = g_quark_from_string("ganvmm"); \
- return (Ganv::Name*)g_object_get_qdata(G_OBJECT(gobj), key); \
+ return (Ganv::Name*)ganv_item_get_wrapper(GANV_ITEM(gobj)); \
} else { \
return NULL; \
} \
} \
+ /** Return a Ganv::CPPType wrapper for a CType. */ \
+ static inline const Ganv::Name* \
+ wrap(const Ganv##Name* gobj) \
+ { \
+ return wrap((Ganv##Name*)gobj); \
+ } \
}
#endif // GANV_WRAP_HPP
diff --git a/src/Canvas.cpp b/src/Canvas.cpp
index daacc1d..3dbf8df 100644
--- a/src/Canvas.cpp
+++ b/src/Canvas.cpp
@@ -186,6 +186,7 @@ panic_root_destroyed(GtkObject* object, gpointer data)
struct GanvCanvasImpl {
GanvCanvasImpl(GanvCanvas* canvas)
: _gcanvas(canvas)
+ , _wrapper(NULL)
, _connect_port(NULL)
, _last_selected_port(NULL)
, _drag_edge(NULL)
@@ -255,10 +256,12 @@ struct GanvCanvasImpl {
_animate_idle_id = 0;
+ _port_order.port_cmp = NULL;
+ _port_order.data = NULL;
+
gtk_layout_set_hadjustment(GTK_LAYOUT(canvas), NULL);
gtk_layout_set_vadjustment(GTK_LAYOUT(canvas), NULL);
- _wrapper_key = g_quark_from_string("ganvmm");
_move_cursor = gdk_cursor_new(GDK_FLEUR);
}
@@ -327,7 +330,8 @@ struct GanvCanvasImpl {
void move_contents_to_internal(double x, double y, double min_x, double min_y);
- GanvCanvas* _gcanvas;
+ GanvCanvas* _gcanvas;
+ Ganv::Canvas* _wrapper;
Items _items; ///< Items on this canvas
Edges _edges; ///< Edges ordered (src, dst)
@@ -348,10 +352,11 @@ struct GanvCanvasImpl {
enum DragState { NOT_DRAGGING, EDGE, SCROLL, SELECT };
DragState _drag_state;
- GQuark _wrapper_key;
GdkCursor* _move_cursor;
guint _animate_idle_id;
+ PortOrderCtx _port_order;
+
/* Root canvas item */
GanvItem* root;
@@ -1693,7 +1698,7 @@ on_disconnect(GanvCanvas* canvas, GanvNode* tail, GanvNode* head, void* data)
Canvas::Canvas(double width, double height)
: _gobj(GANV_CANVAS(ganv_canvas_new(width, height)))
{
- g_object_set_qdata(G_OBJECT(_gobj->impl->_gcanvas), wrapper_key(), this);
+ ganv_canvas_set_wrapper(_gobj, this);
g_signal_connect_after(ganv_canvas_root(_gobj), "event",
G_CALLBACK(on_event_after), this);
@@ -1743,12 +1748,6 @@ Canvas::get_edge(Node* tail, Node* head) const
return NULL;
}
-GQuark
-Canvas::wrapper_key()
-{
- return _gobj->impl->_wrapper_key;
-}
-
} // namespace Ganv
extern "C" {
@@ -2758,6 +2757,18 @@ ganv_canvas_new(double width, double height)
return canvas;
}
+void
+ganv_canvas_set_wrapper(GanvCanvas* canvas, void* wrapper)
+{
+ canvas->impl->_wrapper = (Ganv::Canvas*)wrapper;
+}
+
+void*
+ganv_canvas_get_wrapper(GanvCanvas* canvas)
+{
+ return canvas->impl->_wrapper;
+}
+
/* Map handler for the canvas */
static void
ganv_canvas_map(GtkWidget* widget)
@@ -4103,4 +4114,21 @@ ganv_canvas_world_to_window(GanvCanvas* canvas, double worldx, double worldy,
}
}
+void
+ganv_canvas_set_port_order(GanvCanvas* canvas,
+ GanvPortOrderFunc port_cmp,
+ void* data)
+{
+ g_return_if_fail(GANV_IS_CANVAS(canvas));
+
+ canvas->impl->_port_order.port_cmp = port_cmp;
+ canvas->impl->_port_order.data = data;
+}
+
+PortOrderCtx
+ganv_canvas_get_port_order(GanvCanvas* canvas)
+{
+ return canvas->impl->_port_order;
+}
+
} // extern "C"
diff --git a/src/box.c b/src/box.c
index 1210104..a1a9315 100644
--- a/src/box.c
+++ b/src/box.c
@@ -182,9 +182,6 @@ ganv_box_update(GanvItem* item, int flags)
// Request redraw of old location
ganv_box_request_redraw(item, &impl->old_coords, TRUE);
- GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class);
- item_class->update(item, flags);
-
// Store old coordinates in world relative coordinates in case the
// group we are in moves between now and the next update
impl->old_coords = impl->coords;
@@ -198,6 +195,8 @@ ganv_box_update(GanvItem* item, int flags)
// Request redraw of new location
ganv_box_request_redraw(item, &impl->coords, FALSE);
+
+ GANV_ITEM_CLASS(parent_class)->update(item, flags);
}
void
@@ -343,21 +342,17 @@ ganv_box_is_within(const GanvNode* self,
}
static void
-ganv_box_default_set_width(GanvBox* box,
- double width)
+ganv_box_default_set_width(GanvBox* box, double width)
{
- ganv_item_set(GANV_ITEM(box),
- "x2", ganv_box_get_x1(box) + width,
- NULL);
+ box->impl->coords.x2 = ganv_box_get_x1(box) + width;
+ ganv_item_request_update(GANV_ITEM(box));
}
static void
-ganv_box_default_set_height(GanvBox* box,
- double height)
+ganv_box_default_set_height(GanvBox* box, double height)
{
- ganv_item_set(GANV_ITEM(box),
- "y2", ganv_box_get_y1(box) + height,
- NULL);
+ box->impl->coords.y2 = ganv_box_get_y1(box) + height;
+ ganv_item_request_update(GANV_ITEM(box));
}
static void
diff --git a/src/circle.c b/src/circle.c
index 7230abb..fe2a54b 100644
--- a/src/circle.c
+++ b/src/circle.c
@@ -260,11 +260,6 @@ ganv_circle_update(GanvItem* item, int flags)
GanvCircleImpl* impl = circle->impl;
impl->coords.width = circle->node.impl->border_width;
- GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class);
- if (item_class->update) {
- (*item_class->update)(item, flags);
- }
-
// Request redraw of old location
request_redraw(item, &impl->old_coords, TRUE);
@@ -279,6 +274,8 @@ ganv_circle_update(GanvItem* item, int flags)
// Request redraw of new location
request_redraw(item, &impl->coords, FALSE);
+
+ GANV_ITEM_CLASS(parent_class)->update(item, flags);
}
static void
diff --git a/src/edge.c b/src/edge.c
index 449f884..d2833e4 100644
--- a/src/edge.c
+++ b/src/edge.c
@@ -282,10 +282,6 @@ ganv_edge_update(GanvItem* item, int flags)
GanvEdge* edge = GANV_EDGE(item);
GanvEdgeImpl* impl = edge->impl;
- if (parent_class->update) {
- (*parent_class->update)(item, flags);
- }
-
// Request redraw of old location
ganv_edge_request_redraw(item, &impl->old_coords);
@@ -316,6 +312,8 @@ ganv_edge_update(GanvItem* item, int flags)
// Request redraw of new location
ganv_edge_request_redraw(item, &impl->coords);
+
+ parent_class->update(item, flags);
}
static void
diff --git a/src/ganv-private.h b/src/ganv-private.h
index eefeaa8..4d892d9 100644
--- a/src/ganv-private.h
+++ b/src/ganv-private.h
@@ -95,7 +95,7 @@ struct _GanvModuleImpl
int embed_height;
double widest_input;
double widest_output;
- gboolean must_resize;
+ gboolean must_reorder;
};
/* Node */
@@ -123,6 +123,7 @@ struct _GanvNodeImpl {
gboolean draggable;
gboolean show_label;
gboolean grabbed;
+ gboolean must_resize;
#ifdef GANV_FDGL
Vector force;
Vector vel;
@@ -162,6 +163,9 @@ struct _GanvItemImpl {
/* Parent for this item */
GanvItem* parent;
+ /* Wrapper object for this item, if any */
+ void* wrapper;
+
/* Layer (z order), higher values are on top */
guint layer;
@@ -248,6 +252,11 @@ struct _GanvTextImpl
/* Canvas */
+typedef struct {
+ GanvPortOrderFunc port_cmp;
+ void* data;
+} PortOrderCtx;
+
void
ganv_canvas_move_selected_items(GanvCanvas* canvas,
double dx,
@@ -342,6 +351,9 @@ void
ganv_canvas_request_redraw_w(GanvCanvas* canvas,
double x1, double y1, double x2, double y2);
+PortOrderCtx
+ganv_canvas_get_port_order(GanvCanvas* canvas);
+
/* Edge */
void
diff --git a/src/group.c b/src/group.c
index e867cef..3a37c80 100644
--- a/src/group.c
+++ b/src/group.c
@@ -94,8 +94,6 @@ ganv_group_update(GanvItem* item, int flags)
{
GanvGroup* group = GANV_GROUP(item);
- (*group_parent_class->update)(item, flags);
-
double min_x = 0.0;
double min_y = 0.0;
double max_x = 0.0;
@@ -115,6 +113,8 @@ ganv_group_update(GanvItem* item, int flags)
item->impl->y1 = min_y;
item->impl->x2 = max_x;
item->impl->y2 = max_y;
+
+ (*group_parent_class->update)(item, flags);
}
static void
diff --git a/src/item.c b/src/item.c
index f931e94..d645e23 100644
--- a/src/item.c
+++ b/src/item.c
@@ -78,6 +78,7 @@ ganv_item_init(GanvItem* item)
item->object.flags |= GANV_ITEM_VISIBLE;
item->impl = impl;
item->impl->managed = FALSE;
+ item->impl->wrapper = NULL;
}
/**
@@ -218,9 +219,10 @@ ganv_item_construct(GanvItem* item, GanvItem* parent,
{
g_return_if_fail(GANV_IS_ITEM(item));
- item->impl->parent = parent;
- item->impl->canvas = item->impl->parent->impl->canvas;
- item->impl->layer = 0;
+ item->impl->parent = parent;
+ item->impl->wrapper = NULL;
+ item->impl->canvas = item->impl->parent->impl->canvas;
+ item->impl->layer = 0;
g_object_set_valist(G_OBJECT(item), first_arg_name, args);
@@ -343,6 +345,7 @@ ganv_item_invoke_update(GanvItem* item, int flags)
if (child_flags & GCI_UPDATE_MASK) {
if (GANV_ITEM_GET_CLASS(item)->update) {
GANV_ITEM_GET_CLASS(item)->update(item, child_flags);
+ g_assert(!(GTK_OBJECT_FLAGS(item) & GANV_ITEM_NEED_UPDATE));
}
}
}
@@ -595,12 +598,6 @@ ganv_item_get_bounds(GanvItem* item, double* x1, double* y1, double* x2, double*
void
ganv_item_request_update(GanvItem* item)
{
- /* Note: At some point, if this short-circuit was enabled, the canvas stopped
- updating items entirely when connected modules are removed. */
- if (item->object.flags & GANV_ITEM_NEED_UPDATE) {
- return;
- }
-
if (!item->impl->canvas) {
/* Item is being / has been destroyed, ignore */
return;
@@ -608,7 +605,8 @@ ganv_item_request_update(GanvItem* item)
item->object.flags |= GANV_ITEM_NEED_UPDATE;
- if (item->impl->parent != NULL) {
+ if (item->impl->parent != NULL &&
+ !(item->impl->parent->object.flags & GANV_ITEM_NEED_UPDATE)) {
/* Recurse up the tree */
ganv_item_request_update(item->impl->parent);
} else {
@@ -617,6 +615,18 @@ ganv_item_request_update(GanvItem* item)
}
}
+void
+ganv_item_set_wrapper(GanvItem* item, void* wrapper)
+{
+ item->impl->wrapper = wrapper;
+}
+
+void*
+ganv_item_get_wrapper(GanvItem* item)
+{
+ return item->impl->wrapper;
+}
+
static gboolean
boolean_handled_accumulator(GSignalInvocationHint* ihint,
GValue* return_accu,
diff --git a/src/module.c b/src/module.c
index 550ee48..46cdfff 100644
--- a/src/module.c
+++ b/src/module.c
@@ -63,7 +63,7 @@ ganv_module_init(GanvModule* module)
impl->embed_height = 0;
impl->widest_input = 0.0;
impl->widest_output = 0.0;
- impl->must_resize = TRUE;
+ impl->must_reorder = FALSE;
}
static void
@@ -256,16 +256,15 @@ place_title(GanvModule* module, GanvDirection dir)
if (!canvas_title) {
return;
- } else if (dir == GANV_DIRECTION_RIGHT) {
- ganv_item_set(GANV_ITEM(canvas_title),
- "x", (ganv_box_get_width(box) - title_w) / 2.0,
- "y", 1.0,
- NULL);
+ }
+
+ GanvItem* t = GANV_ITEM(canvas_title);
+ if (dir == GANV_DIRECTION_RIGHT) {
+ t->impl->x = (ganv_box_get_width(box) - title_w) / 2.0;
+ t->impl->y = 1.0;
} else {
- ganv_item_set(GANV_ITEM(canvas_title),
- "x", (ganv_box_get_width(box) - title_w) / 2.0,
- "y", ganv_module_get_empty_port_depth(module) + 1.0,
- NULL);
+ t->impl->x = (ganv_box_get_width(box) - title_w) / 2.0;
+ t->impl->y = ganv_module_get_empty_port_depth(module) + 1.0;
}
}
@@ -392,7 +391,7 @@ resize_down(GanvModule* module)
// Offset to shift ports to make borders line up
const double border_off = (GANV_NODE(module)->impl->border_width -
pnode->impl->border_width) / 2.0;
-
+
if (p->impl->is_input) {
in_x = EDGE_PAD + (in_count++ * (port_breadth + PAD + 1.0));
ganv_node_move_to(pnode, in_x, -border_off);
@@ -436,12 +435,11 @@ measure_ports(GanvModule* module)
}
static void
-layout(GanvNode* self)
+ganv_module_resize(GanvNode* self)
{
- GanvModule* module = GANV_MODULE(self);
- GanvModuleImpl* impl = module->impl;
- GanvNode* node = GANV_NODE(self);
- GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module));
+ GanvModule* module = GANV_MODULE(self);
+ GanvNode* node = GANV_NODE(self);
+ GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module));
double label_w = 0.0;
double label_h = 0.0;
@@ -466,16 +464,8 @@ layout(GanvNode* self)
break;
}
- impl->must_resize = FALSE;
-}
-
-static void
-ganv_module_resize(GanvNode* self)
-{
- layout(self);
-
- if (parent_class->parent_class.resize) {
- parent_class->parent_class.resize(self);
+ if (GANV_NODE_CLASS(parent_class)->resize) {
+ GANV_NODE_CLASS(parent_class)->resize(self);
}
}
@@ -495,9 +485,9 @@ static void
ganv_module_add_port(GanvModule* module,
GanvPort* port)
{
- GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module));
- GanvModuleImpl* impl = module->impl;
+ GanvModuleImpl* impl = module->impl;
+ // Update widest input/output measurements if necessary
const double width = ganv_port_get_natural_width(port);
if (port->impl->is_input && width > impl->widest_input) {
impl->widest_input = width;
@@ -505,11 +495,12 @@ ganv_module_add_port(GanvModule* module,
impl->widest_output = width;
}
- impl->must_resize = TRUE;
-
+ // Add to port array
g_ptr_array_add(impl->ports, port);
- place_title(module, ganv_canvas_get_direction(canvas));
- ganv_item_request_update(GANV_ITEM(module));
+
+ // Request update with resize and reorder
+ GANV_NODE(module)->impl->must_resize = TRUE;
+ impl->must_reorder = TRUE;
}
static void
@@ -540,8 +531,7 @@ ganv_module_remove_port(GanvModule* module,
}
}
- module->impl->must_resize = TRUE;
- ganv_item_request_update(GANV_ITEM(module));
+ GANV_NODE(module)->impl->must_resize = TRUE;
} else {
fprintf(stderr, "Failed to find port to remove\n");
}
@@ -553,6 +543,10 @@ ganv_module_add(GanvItem* item, GanvItem* child)
if (GANV_IS_PORT(child)) {
ganv_module_add_port(GANV_MODULE(item), GANV_PORT(child));
}
+ ganv_item_request_update(item);
+ if (GANV_ITEM_CLASS(parent_class)->add) {
+ GANV_ITEM_CLASS(parent_class)->add(item, child);
+ }
}
static void
@@ -561,16 +555,34 @@ ganv_module_remove(GanvItem* item, GanvItem* child)
if (GANV_IS_PORT(child)) {
ganv_module_remove_port(GANV_MODULE(item), GANV_PORT(child));
}
+ ganv_item_request_update(item);
+ if (GANV_ITEM_CLASS(parent_class)->remove) {
+ GANV_ITEM_CLASS(parent_class)->remove(item, child);
+ }
+}
+
+static int
+ptr_sort(const GanvPort** a, const GanvPort** b, const PortOrderCtx* ctx)
+{
+ return ctx->port_cmp(*a, *b, ctx->data);
}
static void
ganv_module_update(GanvItem* item, int flags)
{
- GanvNode* node = GANV_NODE(item);
GanvModule* module = GANV_MODULE(item);
+ GanvCanvas* canvas = ganv_item_get_canvas(item);
+
+ if (module->impl->must_reorder) {
+ // Sort ports array
+ PortOrderCtx ctx = ganv_canvas_get_port_order(canvas);
+ if (ctx.port_cmp) {
+ g_ptr_array_sort_with_data(module->impl->ports,
+ (GCompareDataFunc)ptr_sort,
- if (module->impl->must_resize) {
- layout(node);
+ &ctx);
+ }
+ module->impl->must_reorder = FALSE;
}
if (module->impl->embed_item) {
@@ -578,9 +590,6 @@ ganv_module_update(GanvItem* item, int flags)
ganv_item_move(GANV_ITEM(module->impl->embed_item), 0.0, 0.0);
}
- GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class);
- item_class->update(item, flags);
-
FOREACH_PORT(module->impl->ports, p) {
ganv_item_invoke_update(GANV_ITEM(*p), flags);
}
@@ -588,6 +597,8 @@ ganv_module_update(GanvItem* item, int flags)
if (module->impl->embed_item) {
ganv_item_invoke_update(GANV_ITEM(module->impl->embed_item), flags);
}
+
+ GANV_ITEM_CLASS(parent_class)->update(item, flags);
}
static void
@@ -763,10 +774,9 @@ on_embed_size_request(GtkWidget* widget,
return;
}
- impl->embed_width = r->width;
- impl->embed_height = r->height;
-
- impl->must_resize = TRUE;
+ impl->embed_width = r->width;
+ impl->embed_height = r->height;
+ GANV_NODE(module)->impl->must_resize = TRUE;
GtkAllocation allocation;
allocation.width = r->width;
@@ -784,43 +794,46 @@ ganv_module_embed(GanvModule* module,
GtkWidget* widget)
{
GanvModuleImpl* impl = module->impl;
+ if (!widget && !impl->embed_item) {
+ return;
+ }
if (impl->embed_item) {
+ // Free existing embedded widget
gtk_object_destroy(GTK_OBJECT(impl->embed_item));
impl->embed_item = NULL;
}
if (!widget) {
- impl->embed_width = 0;
- impl->embed_height = 0;
- impl->must_resize = TRUE;
+ // Removing an existing embedded widget
+ impl->embed_width = 0;
+ impl->embed_height = 0;
+ GANV_NODE(module)->impl->must_resize = TRUE;
+ ganv_item_request_update(GANV_ITEM(module));
return;
}
double title_w, title_h;
title_size(module, &title_w, &title_h);
- const double y = 4.0 + title_h;
impl->embed_item = ganv_item_new(
GANV_ITEM(module),
ganv_widget_get_type(),
"x", 2.0,
- "y", y,
+ "y", 4.0 + title_h,
"widget", widget,
NULL);
- gtk_widget_show_all(widget);
-
GtkRequisition r;
+ gtk_widget_show_all(widget);
gtk_widget_size_request(widget, &r);
on_embed_size_request(widget, &r, module);
-
ganv_item_show(impl->embed_item);
g_signal_connect(widget, "size-request",
G_CALLBACK(on_embed_size_request), module);
- layout(GANV_NODE(module));
+ GANV_NODE(module)->impl->must_resize = TRUE;
ganv_item_request_update(GANV_ITEM(module));
}
@@ -831,8 +844,8 @@ ganv_module_set_direction(GanvModule* module,
FOREACH_PORT(module->impl->ports, p) {
ganv_port_set_direction(*p, direction);
}
- module->impl->must_resize = TRUE;
- ganv_module_resize(GANV_NODE(module));
+ GANV_NODE(module)->impl->must_resize = TRUE;
+ ganv_item_request_update(GANV_ITEM(module));
}
void
diff --git a/src/node.c b/src/node.c
index 5a4f727..e77ded3 100644
--- a/src/node.c
+++ b/src/node.c
@@ -71,6 +71,7 @@ ganv_node_init(GanvNode* node)
impl->draggable = FALSE;
impl->show_label = TRUE;
impl->grabbed = FALSE;
+ impl->must_resize = FALSE;
#ifdef GANV_FDGL
impl->force.x = 0.0;
impl->force.y = 0.0;
@@ -115,6 +116,22 @@ ganv_node_destroy(GtkObject* object)
}
static void
+ganv_node_update(GanvItem* item, int flags)
+{
+ GanvNode* node = GANV_NODE(item);
+ if (node->impl->must_resize) {
+ ganv_node_resize(node);
+ node->impl->must_resize = FALSE;
+ }
+
+ if (node->impl->label) {
+ ganv_item_invoke_update(GANV_ITEM(node->impl->label), flags);
+ }
+
+ GANV_ITEM_CLASS(parent_class)->update(item, flags);
+}
+
+static void
ganv_node_draw(GanvItem* item,
cairo_t* cr, double cx, double cy, double cw, double ch)
{
@@ -319,14 +336,8 @@ ganv_node_set_label(GanvNode* node, const char* str)
NULL));
}
- if (impl->show_label) {
- GanvNodeClass* klass = GANV_NODE_GET_CLASS(node);
- if (klass->resize) {
- klass->resize(node);
- }
-
- ganv_item_request_update(GANV_ITEM(node));
- }
+ impl->must_resize = TRUE;
+ ganv_item_request_update(GANV_ITEM(node));
}
void
@@ -371,6 +382,7 @@ ganv_node_default_move(GanvNode* node,
ganv_item_move(GANV_ITEM(node), dx, dy);
ganv_canvas_for_each_edge_on(
canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL);
+ ganv_item_request_update(GANV_ITEM(node));
}
static void
@@ -378,11 +390,10 @@ ganv_node_default_move_to(GanvNode* node,
double x,
double y)
{
- GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(node));
- ganv_item_set(GANV_ITEM(node),
- "x", x,
- "y", y,
- NULL);
+ GanvItem* item = GANV_ITEM(node);
+ GanvCanvas* canvas = ganv_item_get_canvas(item);
+ item->impl->x = x;
+ item->impl->y = y;
if (node->impl->can_tail) {
ganv_canvas_for_each_edge_from(
canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL);
@@ -390,6 +401,7 @@ ganv_node_default_move_to(GanvNode* node,
ganv_canvas_for_each_edge_to(
canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL);
}
+ ganv_item_request_update(GANV_ITEM(node));
}
static void
@@ -399,6 +411,7 @@ ganv_node_default_resize(GanvNode* node)
if (GANV_IS_NODE(item->impl->parent)) {
ganv_node_resize(GANV_NODE(item->impl->parent));
}
+ node->impl->must_resize = FALSE;
}
static void
@@ -406,7 +419,8 @@ ganv_node_default_redraw_text(GanvNode* node)
{
if (node->impl->label) {
ganv_text_layout(node->impl->label);
- ganv_node_resize(node);
+ node->impl->must_resize = TRUE;
+ ganv_item_request_update(GANV_ITEM(node));
}
}
@@ -425,12 +439,14 @@ ganv_node_default_event(GanvItem* item,
switch (event->type) {
case GDK_ENTER_NOTIFY:
ganv_item_raise(GANV_ITEM(node));
- ganv_item_set(GANV_ITEM(node), "highlighted", TRUE, NULL);
+ node->impl->highlighted = TRUE;
+ ganv_item_request_update(item);
return TRUE;
case GDK_LEAVE_NOTIFY:
ganv_item_lower(GANV_ITEM(node));
- ganv_item_set(GANV_ITEM(node), "highlighted", FALSE, NULL);
+ node->impl->highlighted = FALSE;
+ ganv_item_request_update(item);
return TRUE;
case GDK_BUTTON_PRESS:
@@ -685,6 +701,7 @@ ganv_node_class_init(GanvNodeClass* klass)
item_class->realize = ganv_node_realize;
item_class->event = ganv_node_default_event;
+ item_class->update = ganv_node_update;
item_class->draw = ganv_node_draw;
klass->disconnect = ganv_node_default_disconnect;
@@ -856,6 +873,7 @@ void
ganv_node_resize(GanvNode* node)
{
GANV_NODE_GET_CLASS(node)->resize(node);
+ node->impl->must_resize = FALSE;
}
void
diff --git a/src/port.c b/src/port.c
index 9a97e0b..7f4df2d 100644
--- a/src/port.c
+++ b/src/port.c
@@ -133,8 +133,13 @@ ganv_port_update(GanvItem* item, int flags)
if (impl->control) {
const double border_width = GANV_NODE(item)->impl->border_width;
impl->control->rect->impl->coords.border_width = border_width;
+ ganv_item_invoke_update(GANV_ITEM(impl->control->rect), flags);
}
+ if (impl->value_label) {
+ ganv_item_invoke_update(GANV_ITEM(port->impl->value_label), flags);
+ }
+
GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class);
item_class->update(item, flags);
}
@@ -316,14 +321,12 @@ ganv_port_resize(GanvNode* self)
ganv_box_set_width(&port->box, labels_w);
ganv_box_set_height(&port->box,
MAX(label_h, vlabel_h) + (PORT_LABEL_VPAD * 2.0));
- ganv_item_set(GANV_ITEM(node->impl->label),
- "x", PORT_LABEL_HPAD,
- "y", PORT_LABEL_VPAD,
- NULL);
+
+ ganv_port_place_labels(port);
}
- if (parent_class->parent_class.resize) {
- parent_class->parent_class.resize(self);
+ if (GANV_NODE_CLASS(parent_class)->resize) {
+ GANV_NODE_CLASS(parent_class)->resize(self);
}
}
@@ -486,7 +489,9 @@ ganv_port_set_direction(GanvPort* port,
box->impl->radius_bl = (is_input ? 4.0 : 0.0);
break;
}
- ganv_node_resize(node);
+
+ node->impl->must_resize = TRUE;
+ ganv_item_request_update(GANV_ITEM(node));
}
void
@@ -552,7 +557,6 @@ ganv_port_set_value_label(GanvPort* port,
"color", 0xFFFFFFAA,
"managed", TRUE,
NULL));
- ganv_port_resize(GANV_NODE(port));
}
}
@@ -582,7 +586,7 @@ ganv_port_update_control_slider(GanvPort* port, float value, gboolean force)
if (value > impl->control->max) {
value = impl->control->max;
}
-
+
if (!force && value == impl->control->value) {
return; // No change, do nothing
}
diff --git a/src/text.c b/src/text.c
index bfc7d0b..04c991c 100644
--- a/src/text.c
+++ b/src/text.c
@@ -140,24 +140,34 @@ ganv_text_set_property(GObject* object,
GanvTextImpl* impl = text->impl;
switch (prop_id) {
- 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)
- SET_CASE(FONT_SIZE, double, impl->font_size)
+ case PROP_X:
+ impl->coords.x = g_value_get_double(value);
+ break;
+ case PROP_Y:
+ impl->coords.y = g_value_get_double(value);
+ break;
+ case PROP_COLOR:
+ impl->color = g_value_get_uint(value);
+ break;
+ case PROP_FONT_SIZE:
+ impl->font_size = g_value_get_double(value);
+ impl->needs_layout = TRUE;
+ break;
case PROP_TEXT:
free(impl->text);
- impl->text = g_value_dup_string(value);
+ impl->text = g_value_dup_string(value);
impl->needs_layout = TRUE;
- if (GANV_IS_NODE(GANV_ITEM(text)->impl->parent)) {
- ganv_node_resize(GANV_NODE(GANV_ITEM(text)->impl->parent));
- }
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
+ return;
}
+ if (impl->needs_layout) {
+ if (GANV_IS_NODE(GANV_ITEM(text)->impl->parent)) {
+ GANV_NODE(GANV_ITEM(text)->impl->parent)->impl->must_resize = TRUE;
+ }
+ }
+ ganv_item_request_update(GANV_ITEM(text));
}
static void
@@ -219,14 +229,14 @@ ganv_text_bounds(GanvItem* item,
static void
ganv_text_update(GanvItem* item, int flags)
{
- parent_class->update(item, flags);
-
// Update world-relative bounding box
ganv_text_bounds(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2);
ganv_item_i2w_pair(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2);
ganv_canvas_request_redraw_w(
item->impl->canvas, item->impl->x1, item->impl->y1, item->impl->x2, item->impl->y2);
+
+ parent_class->update(item, flags);
}
static double
@@ -334,7 +344,7 @@ ganv_text_class_init(GanvTextClass* klass)
_("The current width of the text."),
-G_MAXDOUBLE, G_MAXDOUBLE,
1.0,
- G_PARAM_READWRITE));
+ G_PARAM_READABLE));
g_object_class_install_property(
gobject_class, PROP_HEIGHT, g_param_spec_double(
@@ -343,7 +353,7 @@ ganv_text_class_init(GanvTextClass* klass)
_("The current height of the text."),
-G_MAXDOUBLE, G_MAXDOUBLE,
1.0,
- G_PARAM_READWRITE));
+ G_PARAM_READABLE));
g_object_class_install_property(
gobject_class, PROP_COLOR, g_param_spec_uint(
diff --git a/wscript b/wscript
index 3c78a9e..f50f03d 100644
--- a/wscript
+++ b/wscript
@@ -8,7 +8,7 @@ import waflib.extras.autowaf as autowaf
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
-GANV_VERSION = '1.5.1'
+GANV_VERSION = '1.5.2'
GANV_MAJOR_VERSION = '1'
# Mandatory waf variables