summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-03-30 20:12:48 +0000
committerDavid Robillard <d@drobilla.net>2014-03-30 20:12:48 +0000
commite477fba7331b8a874b00a567defb09a888590aea (patch)
treea9a1626aae2137072e42fe48779f0b43f8d0c42d
parent7bf9f530dbdfcaa8151424908d492ef7c6c05e79 (diff)
downloadganv-e477fba7331b8a874b00a567defb09a888590aea.tar.gz
ganv-e477fba7331b8a874b00a567defb09a888590aea.tar.bz2
ganv-e477fba7331b8a874b00a567defb09a888590aea.zip
Reimplement canvas zoom.
Make select rectangle translucent. Make ctrl+scroll wheel zoom, not change font size. Add separate controls in Patchage for zoom (scale) and font size. Banish canvas coordinates from item implementations. git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@5345 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--ganv/Canvas.hpp2
-rw-r--r--ganv/canvas.h2
-rw-r--r--ganv/item.h21
-rw-r--r--src/Canvas.cpp92
-rw-r--r--src/box.c24
-rw-r--r--src/circle.c35
-rw-r--r--src/edge.c51
-rw-r--r--src/ganv-private.h16
-rw-r--r--src/group.c67
-rw-r--r--src/item.c29
-rw-r--r--src/module.c25
-rw-r--r--src/node.c4
-rw-r--r--src/port.c10
-rw-r--r--src/text.c26
-rw-r--r--src/widget.c7
15 files changed, 166 insertions, 245 deletions
diff --git a/ganv/Canvas.hpp b/ganv/Canvas.hpp
index b3281ad..2139e93 100644
--- a/ganv/Canvas.hpp
+++ b/ganv/Canvas.hpp
@@ -58,7 +58,7 @@ public:
METHOD0(ganv_canvas, clear);
METHOD0(ganv_canvas, clear_selection);
METHOD0(ganv_canvas, select_all);
- METHOD0(ganv_canvas, get_zoom);
+ METHODRET0(ganv_canvas, double, get_zoom);
METHOD1(ganv_canvas, set_zoom, double, pix_per_unit);
METHOD1(ganv_canvas, set_font_size, double, points);
METHOD0(ganv_canvas, zoom_full);
diff --git a/ganv/canvas.h b/ganv/canvas.h
index 57781dc..a3444dc 100644
--- a/ganv/canvas.h
+++ b/ganv/canvas.h
@@ -501,7 +501,7 @@ ganv_canvas_select_all(GanvCanvas* canvas);
* Return the current zoom factor (pixels per unit).
*/
double
-ganv_canvas_get_zoom(GanvCanvas* canvas);
+ganv_canvas_get_zoom(const GanvCanvas* canvas);
/**
* ganv_canvas_set_zoom:
diff --git a/ganv/item.h b/ganv/item.h
index 25d2985..83b5f3c 100644
--- a/ganv/item.h
+++ b/ganv/item.h
@@ -63,7 +63,7 @@ struct _GanvItem {
/* Position in parent-relative coordinates. */
double x, y;
- /* Bounding box for this item (in canvas coordinates) */
+ /* Bounding box for this item (in world coordinates) */
double x1, y1, x2, y2;
/* True if parent manages this item (don't call add/remove) */
@@ -102,28 +102,25 @@ struct _GanvItemClass {
/* Draw an item of this type.
*
- * (x, y) are the upper-left canvas pixel coordinates of the drawable.
- * (width, height) are the dimensions of the drawable.
+ * (cx, cy) and (width, height) describe the rectangle being drawn in
+ * world-relative coordinates.
*/
void (*draw)(GanvItem* item,
cairo_t* cr,
- int x,
- int y,
- int width,
- int height);
+ double cx,
+ double cy,
+ double cw,
+ double ch);
/* Calculate the distance from an item to the specified point.
*
* It also returns a canvas item which is actual item the point is within,
- * which may not be equal to @item if @item has children. (cx, cy) are the
- * canvas pixel coordinates that correspond to the item-relative
- * coordinates (x, y).
+ * which may not be equal to @item if @item has children.
+ * (x, y) are item-relative coordinates.
*/
double (*point)(GanvItem* item,
double x,
double y,
- int cx,
- int cy,
GanvItem** actual_item);
/* Fetch the item's bounding box (need not be exactly tight).
diff --git a/src/Canvas.cpp b/src/Canvas.cpp
index 7ab8577..de18e98 100644
--- a/src/Canvas.cpp
+++ b/src/Canvas.cpp
@@ -151,7 +151,7 @@ public:
};
#endif
-static const uint32_t SELECT_RECT_FILL_COLOUR = 0x0E2425FF;
+static const uint32_t SELECT_RECT_FILL_COLOUR = 0x2E444577;
static const uint32_t SELECT_RECT_BORDER_COLOUR = 0x2E4445FF;
/** Order edges by (tail, head) */
@@ -237,7 +237,7 @@ struct GanvCanvasImpl {
this->state = 0;
this->grabbed_event_mask = 0;
- this->center_scroll_region = TRUE;
+ this->center_scroll_region = FALSE;
this->need_update = FALSE;
this->need_redraw = FALSE;
this->need_repick = TRUE;
@@ -1118,12 +1118,12 @@ GanvCanvasImpl::on_event(GdkEvent* event)
case GDK_SCROLL:
if ((event->scroll.state & GDK_CONTROL_MASK)) {
- const double font_size = ganv_canvas_get_font_size(_gcanvas);
+ const double zoom = ganv_canvas_get_zoom(_gcanvas);
if (event->scroll.direction == GDK_SCROLL_UP) {
- ganv_canvas_set_font_size(_gcanvas, font_size * 1.25);
+ ganv_canvas_set_zoom(_gcanvas, zoom * 1.25);
return true;
} else if (event->scroll.direction == GDK_SCROLL_DOWN) {
- ganv_canvas_set_font_size(_gcanvas, font_size * 0.75);
+ ganv_canvas_set_zoom(_gcanvas, zoom * 0.75);
return true;
}
}
@@ -2017,6 +2017,8 @@ ganv_canvas_set_zoom(GanvCanvas* canvas, double zoom)
ganv_canvas_scroll_to(canvas, x1, y1);
ganv_canvas_request_update(canvas);
+ gtk_widget_queue_draw(GTK_WIDGET(canvas));
+
canvas->impl->need_repick = TRUE;
}
@@ -2286,7 +2288,7 @@ ganv_canvas_remove_edge(GanvCanvas* canvas,
canvas->impl->_selected_edges.erase(edge);
canvas->impl->_edges.erase(edge);
canvas->impl->_dst_edges.erase(edge);
- ganv_edge_request_redraw(GANV_ITEM(edge)->canvas, &edge->impl->coords);
+ ganv_edge_request_redraw(GANV_ITEM(edge), &edge->impl->coords);
gtk_object_destroy(GTK_OBJECT(edge));
ganv_canvas_contents_changed(canvas);
}
@@ -2448,7 +2450,7 @@ ganv_canvas_select_all(GanvCanvas* canvas)
}
double
-ganv_canvas_get_zoom(GanvCanvas* canvas)
+ganv_canvas_get_zoom(const GanvCanvas* canvas)
{
return canvas->impl->pixels_per_unit;
}
@@ -3196,22 +3198,17 @@ ganv_canvas_get_zoom_offsets(GanvCanvas* canvas, int* x, int* y)
static int
pick_current_item(GanvCanvas* canvas, GdkEvent* event)
{
- int button_down;
- double x, y;
- int cx, cy;
- int retval;
-
- retval = FALSE;
+ int retval = FALSE;
/* If a button is down, we'll perform enter and leave events on the
* current item, but not enter on any other item. This is more or less
* like X pointer grabbing for canvas items.
*/
- button_down = canvas->impl->state & (GDK_BUTTON1_MASK
- | GDK_BUTTON2_MASK
- | GDK_BUTTON3_MASK
- | GDK_BUTTON4_MASK
- | GDK_BUTTON5_MASK);
+ int button_down = canvas->impl->state & (GDK_BUTTON1_MASK
+ | GDK_BUTTON2_MASK
+ | GDK_BUTTON3_MASK
+ | GDK_BUTTON4_MASK
+ | GDK_BUTTON5_MASK);
if (!button_down) {
canvas->impl->left_grabbed_item = FALSE;
}
@@ -3261,6 +3258,7 @@ pick_current_item(GanvCanvas* canvas, GdkEvent* event)
if (canvas->impl->pick_event.type != GDK_LEAVE_NOTIFY) {
/* these fields don't have the same offsets in both types of events */
+ double x, y;
if (canvas->impl->pick_event.type == GDK_ENTER_NOTIFY) {
x = canvas->impl->pick_event.crossing.x - canvas->impl->zoom_xofs;
y = canvas->impl->pick_event.crossing.y - canvas->impl->zoom_yofs;
@@ -3269,11 +3267,6 @@ pick_current_item(GanvCanvas* canvas, GdkEvent* event)
y = canvas->impl->pick_event.motion.y - canvas->impl->zoom_yofs;
}
- /* canvas pixel coords */
-
- cx = (int)(x + 0.5);
- cy = (int)(y + 0.5);
-
/* world coords */
x = canvas->impl->scroll_x1 + x / canvas->impl->pixels_per_unit;
@@ -3285,7 +3278,6 @@ pick_current_item(GanvCanvas* canvas, GdkEvent* event)
GANV_ITEM_GET_CLASS(canvas->impl->root)->point(
canvas->impl->root,
x - canvas->impl->root->x, y - canvas->impl->root->y,
- cx, cy,
&canvas->impl->new_current_item);
} else {
canvas->impl->new_current_item = NULL;
@@ -3573,15 +3565,18 @@ ganv_canvas_paint_rect(GanvCanvas* canvas, gint x0, gint y0, gint x1, gint y1)
cairo_t* cr = gdk_cairo_create(canvas->layout.bin_window);
- double wx, wy;
- ganv_canvas_window_to_world(canvas, 0, 0, &wx, &wy);
- cairo_translate(cr, -wx, -wy);
+ double win_x, win_y;
+ ganv_canvas_window_to_world(canvas, 0, 0, &win_x, &win_y);
+ cairo_translate(cr, -win_x, -win_y);
+ cairo_scale(cr, canvas->impl->pixels_per_unit, canvas->impl->pixels_per_unit);
if (canvas->impl->root->object.flags & GANV_ITEM_VISIBLE) {
+ double wx1, wy1, ww, wh;
+ ganv_canvas_c2w(canvas, draw_x1, draw_y1, &wx1, &wy1);
+ ganv_canvas_c2w(canvas, draw_width, draw_height, &ww, &wh);
(*GANV_ITEM_GET_CLASS(canvas->impl->root)->draw)(
canvas->impl->root, cr,
- draw_x1, draw_y1,
- draw_width, draw_height);
+ wx1, wy1, ww, wh);
}
cairo_destroy(cr);
@@ -3610,7 +3605,7 @@ ganv_canvas_expose(GtkWidget* widget, GdkEventExpose* event)
if (canvas->impl->need_update || canvas->impl->need_redraw) {
/* Update or drawing is scheduled, so just mark exposed area as dirty */
- ganv_canvas_request_redraw(canvas, clip.x, clip.y, x2, y2);
+ ganv_canvas_request_redraw_c(canvas, clip.x, clip.y, x2, y2);
} else {
/* No pending updates, draw exposed area immediately */
ganv_canvas_paint_rect(canvas, clip.x, clip.y, x2, y2);
@@ -3838,18 +3833,14 @@ ganv_canvas_get_scroll_offsets(const GanvCanvas* canvas, int* cx, int* cy)
GanvItem*
ganv_canvas_get_item_at(GanvCanvas* canvas, double x, double y)
{
- GanvItem* item;
- double dist;
- int cx, cy;
g_return_val_if_fail(GANV_IS_CANVAS(canvas), NULL);
- ganv_canvas_w2c(canvas, x, y, &cx, &cy);
-
- dist = GANV_ITEM_GET_CLASS(canvas->impl->root)->point(
+ GanvItem* item = NULL;
+ double dist = GANV_ITEM_GET_CLASS(canvas->impl->root)->point(
canvas->impl->root,
- x - canvas->impl->root->x, y - canvas->impl->root->y,
- cx, cy,
+ x - canvas->impl->root->x,
+ y - canvas->impl->root->y,
&item);
if ((int)(dist * canvas->impl->pixels_per_unit + 0.5) <= GANV_CLOSE_ENOUGH) {
return item;
@@ -3896,19 +3887,9 @@ rect_is_visible(GanvCanvas* canvas, const IRect* r)
return rect_overlaps(&rect, r);
}
-/**
- * ganv_canvas_request_redraw:
- * @canvas: A canvas.
- * @x1: Leftmost coordinate of the rectangle to be redrawn.
- * @y1: Upper coordinate of the rectangle to be redrawn.
- * @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1.
- * @y2: Lower coordinate of the rectangle to be redrawn, plus 1.
- *
- * Informs a canvas that the specified area needs to be repainted. To be used
- * only by item implementations.
- **/
void
-ganv_canvas_request_redraw(GanvCanvas* canvas, int x1, int y1, int x2, int y2)
+ganv_canvas_request_redraw_c(GanvCanvas* canvas,
+ int x1, int y1, int x2, int y2)
{
g_return_if_fail(GANV_IS_CANVAS(canvas));
@@ -3933,6 +3914,17 @@ ganv_canvas_request_redraw(GanvCanvas* canvas, int x1, int y1, int x2, int y2)
}
}
+/* Request a redraw of the specified rectangle in world coordinates */
+void
+ganv_canvas_request_redraw_w(GanvCanvas* canvas,
+ double x1, double y1, double x2, double y2)
+{
+ int cx1, cx2, cy1, cy2;
+ ganv_canvas_w2c(canvas, x1, y1, &cx1, &cy1);
+ ganv_canvas_w2c(canvas, x2, y2, &cx2, &cy2);
+ ganv_canvas_request_redraw_c(canvas, cx1, cy1, cx2, cy2);
+}
+
void
ganv_canvas_w2c_affine(GanvCanvas* canvas, cairo_matrix_t* matrix)
{
diff --git a/src/box.c b/src/box.c
index 381eb9c..08ab8da 100644
--- a/src/box.c
+++ b/src/box.c
@@ -153,7 +153,7 @@ ganv_box_request_redraw(GanvItem* item,
ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2);
}
- ganv_canvas_request_redraw(item->canvas, x1, y1, x2, y2);
+ ganv_canvas_request_redraw_w(item->canvas, x1, y1, x2, y2);
}
static void
@@ -192,14 +192,9 @@ ganv_box_update(GanvItem* item, int flags)
ganv_box_normalize(box);
- // Get bounding box
- double x1, x2, y1, y2;
- ganv_box_bounds(item, &x1, &y1, &x2, &y2);
- ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2);
-
- // Update item canvas coordinates
- ganv_canvas_w2c_d(item->canvas, x1, y1, &item->x1, &item->y1);
- ganv_canvas_w2c_d(item->canvas, x2, y2, &item->x2, &item->y2);
+ // Update world-relative bounding box
+ ganv_box_bounds(item, &item->x1, &item->y1, &item->x2, &item->y2);
+ ganv_item_i2w_pair(item, &item->x1, &item->y1, &item->x2, &item->y2);
// Request redraw of new location
ganv_box_request_redraw(item, &impl->coords, FALSE);
@@ -207,9 +202,7 @@ ganv_box_update(GanvItem* item, int flags)
static void
ganv_box_draw(GanvItem* item,
- cairo_t* cr,
- int cx, int cy,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
GanvBox* box = GANV_BOX(item);
GanvBoxImpl* impl = box->impl;
@@ -275,14 +268,11 @@ ganv_box_draw(GanvItem* item,
}
GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class);
- item_class->draw(item, cr, cx, cy, width, height);
+ item_class->draw(item, cr, cx, cy, cw, ch);
}
static double
-ganv_box_point(GanvItem* item,
- double x, double y,
- int cx, int cy,
- GanvItem** actual_item)
+ganv_box_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
GanvBox* box = GANV_BOX(item);
GanvBoxImpl* impl = box->impl;
diff --git a/src/circle.c b/src/circle.c
index c37d78c..789ebb0 100644
--- a/src/circle.c
+++ b/src/circle.c
@@ -232,8 +232,7 @@ request_redraw(GanvItem* item,
ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2);
}
- ganv_canvas_request_redraw(item->canvas, x1, y1, x2, y2);
- ganv_canvas_request_redraw(item->canvas, 0, 0, 10000, 10000);
+ ganv_canvas_request_redraw_w(item->canvas, x1, y1, x2, y2);
}
static void
@@ -283,14 +282,9 @@ ganv_circle_update(GanvItem* item, int flags)
impl->old_coords = impl->coords;
coords_i2w(item, &impl->old_coords);
- // Get bounding box
- double x1, x2, y1, y2;
- ganv_circle_bounds(item, &x1, &y1, &x2, &y2);
- ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2);
-
- // Update item canvas coordinates
- ganv_canvas_w2c_d(item->canvas, x1, y1, &item->x1, &item->y1);
- ganv_canvas_w2c_d(item->canvas, x2, y2, &item->x2, &item->y2);
+ // Update world-relative bounding box
+ ganv_circle_bounds(item, &item->x1, &item->y1, &item->x2, &item->y2);
+ ganv_item_i2w_pair(item, &item->x1, &item->y1, &item->x2, &item->y2);
// Request redraw of new location
request_redraw(item, &impl->coords, FALSE);
@@ -298,9 +292,7 @@ ganv_circle_update(GanvItem* item, int flags)
static void
ganv_circle_draw(GanvItem* item,
- cairo_t* cr,
- int x, int y,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
GanvNode* node = GANV_NODE(item);
GanvCircle* circle = GANV_CIRCLE(item);
@@ -308,17 +300,17 @@ ganv_circle_draw(GanvItem* item,
double r, g, b, a;
- double cx = impl->coords.x;
- double cy = impl->coords.y;
- ganv_item_i2w(item, &cx, &cy);
+ double x = impl->coords.x;
+ double y = impl->coords.y;
+ ganv_item_i2w(item, &x, &y);
double dash_length, border_color, fill_color;
ganv_node_get_draw_properties(
&circle->node, &dash_length, &border_color, &fill_color);
cairo_arc(cr,
- cx,
- cy,
+ x,
+ y,
impl->coords.radius,
0, 2 * G_PI);
@@ -344,16 +336,13 @@ ganv_circle_draw(GanvItem* item,
if (label_item->object.flags & GANV_ITEM_VISIBLE) {
GANV_ITEM_GET_CLASS(label_item)->draw(
- label_item, cr, cx, cy, width, height);
+ label_item, cr, cx, cy, cw, ch);
}
}
}
static double
-ganv_circle_point(GanvItem* item,
- double x, double y,
- int cx, int cy,
- GanvItem** actual_item)
+ganv_circle_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
const GanvCircle* circle = GANV_CIRCLE(item);
const GanvCircleCoords* coords = &circle->impl->coords;
diff --git a/src/edge.c b/src/edge.c
index 8f557b7..79d82c5 100644
--- a/src/edge.c
+++ b/src/edge.c
@@ -163,9 +163,10 @@ ganv_edge_get_property(GObject* object,
}
void
-ganv_edge_request_redraw(GanvCanvas* canvas,
+ganv_edge_request_redraw(GanvItem* item,
const GanvEdgeCoords* coords)
{
+ GanvCanvas* canvas = item->canvas;
const double w = coords->width;
if (coords->curved) {
const double src_x = coords->x1;
@@ -183,17 +184,17 @@ ganv_edge_request_redraw(GanvCanvas* canvas,
const double r1y1 = MIN(MIN(src_y, join_y), src_y1);
const double r1x2 = MAX(MAX(src_x, join_x), src_x1);
const double r1y2 = MAX(MAX(src_y, join_y), src_y1);
- ganv_canvas_request_redraw(canvas,
- r1x1 - w, r1y1 - w,
- r1x2 + w, r1y2 + w);
+ ganv_canvas_request_redraw_w(canvas,
+ r1x1 - w, r1y1 - w,
+ r1x2 + w, r1y2 + w);
const double r2x1 = MIN(MIN(dst_x, join_x), dst_x1);
const double r2y1 = MIN(MIN(dst_y, join_y), dst_y1);
const double r2x2 = MAX(MAX(dst_x, join_x), dst_x1);
const double r2y2 = MAX(MAX(dst_y, join_y), dst_y1);
- ganv_canvas_request_redraw(canvas,
- r2x1 - w, r2y1 - w,
- r2x2 + w, r2y2 + w);
+ ganv_canvas_request_redraw_w(canvas,
+ r2x1 - w, r2y1 - w,
+ r2x2 + w, r2y2 + w);
} else {
const double x1 = MIN(coords->x1, coords->x2);
@@ -201,13 +202,13 @@ ganv_edge_request_redraw(GanvCanvas* canvas,
const double x2 = MAX(coords->x1, coords->x2);
const double y2 = MAX(coords->y1, coords->y2);
- ganv_canvas_request_redraw(canvas,
- x1 - w, y1 - w,
- x2 + w, y2 + w);
+ ganv_canvas_request_redraw_w(canvas,
+ x1 - w, y1 - w,
+ x2 + w, y2 + w);
}
if (coords->handle_radius > 0.0) {
- ganv_canvas_request_redraw(
+ ganv_canvas_request_redraw_w(
canvas,
coords->handle_x - coords->handle_radius - w,
coords->handle_y - coords->handle_radius - w,
@@ -216,7 +217,7 @@ ganv_edge_request_redraw(GanvCanvas* canvas,
}
if (coords->arrowhead) {
- ganv_canvas_request_redraw(
+ ganv_canvas_request_redraw_w(
canvas,
coords->x2 - ARROW_DEPTH,
coords->y2 - ARROW_BREADTH,
@@ -286,7 +287,7 @@ ganv_edge_update(GanvItem* item, int flags)
}
// Request redraw of old location
- ganv_edge_request_redraw(item->canvas, &impl->old_coords);
+ ganv_edge_request_redraw(item, &impl->old_coords);
// Calculate new coordinates from tail and head
ganv_edge_get_coords(edge, &impl->coords);
@@ -306,19 +307,20 @@ ganv_edge_update(GanvItem* item, int flags)
y2 += 1.0;
}
- // Update item canvas coordinates
- ganv_canvas_w2c_d(item->canvas, x1, y1, &item->x1, &item->y1);
- ganv_canvas_w2c_d(item->canvas, x2, y2, &item->x2, &item->y2);
+ // Update world-relative bounding box
+ item->x1 = x1;
+ item->y1 = y1;
+ item->x2 = x2;
+ item->y2 = y2;
+ ganv_item_i2w_pair(item, &item->x1, &item->y1, &item->x2, &item->y2);
// Request redraw of new location
- ganv_edge_request_redraw(item->canvas, &impl->coords);
+ ganv_edge_request_redraw(item, &impl->coords);
}
static void
ganv_edge_draw(GanvItem* item,
- cairo_t* cr,
- int x, int y,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
GanvEdge* edge = GANV_EDGE(item);
GanvEdgeImpl* impl = edge->impl;
@@ -443,10 +445,7 @@ ganv_edge_draw(GanvItem* item,
}
static double
-ganv_edge_point(GanvItem* item,
- double x, double y,
- int cx, int cy,
- GanvItem** actual_item)
+ganv_edge_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
const GanvEdge* edge = GANV_EDGE(item);
const GanvEdgeCoords* coords = &edge->impl->coords;
@@ -657,14 +656,14 @@ void
ganv_edge_highlight(GanvEdge* edge)
{
edge->impl->highlighted = TRUE;
- ganv_edge_request_redraw(GANV_ITEM(edge)->canvas, &edge->impl->coords);
+ ganv_edge_request_redraw(GANV_ITEM(edge), &edge->impl->coords);
}
void
ganv_edge_unhighlight(GanvEdge* edge)
{
edge->impl->highlighted = FALSE;
- ganv_edge_request_redraw(GANV_ITEM(edge)->canvas, &edge->impl->coords);
+ ganv_edge_request_redraw(GANV_ITEM(edge), &edge->impl->coords);
}
void
diff --git a/src/ganv-private.h b/src/ganv-private.h
index 7110657..870dcec 100644
--- a/src/ganv-private.h
+++ b/src/ganv-private.h
@@ -258,13 +258,15 @@ ganv_canvas_grab_item(GanvItem* item, guint event_mask, GdkCursor* cursor, guint
void
ganv_canvas_ungrab_item(GanvItem* item, guint32 etime);
-/* For use only by item type implementations. Request that the canvas
- * eventually redraw the specified region, specified in canvas pixel
- * coordinates. The region contains (x1, y1) but not (x2, y2).
- */
+/* Request a redraw of the specified rectangle in canvas coordinates */
+void
+ganv_canvas_request_redraw_c(GanvCanvas* canvas,
+ int x1, int y1, int x2, int y2);
+
+/* Request a redraw of the specified rectangle in world coordinates */
void
-ganv_canvas_request_redraw(GanvCanvas* canvas,
- int x1, int y1, int x2, int y2);
+ganv_canvas_request_redraw_w(GanvCanvas* canvas,
+ double x1, double y1, double x2, double y2);
/* Edge */
@@ -272,7 +274,7 @@ void
ganv_edge_get_coords(const GanvEdge* edge, GanvEdgeCoords* coords);
void
-ganv_edge_request_redraw(GanvCanvas* canvas,
+ganv_edge_request_redraw(GanvItem* item,
const GanvEdgeCoords* coords);
/* Box */
diff --git a/src/group.c b/src/group.c
index 607adcf..fdcb1f6 100644
--- a/src/group.c
+++ b/src/group.c
@@ -196,90 +196,71 @@ ganv_group_unmap(GanvItem* item)
}
static void
-ganv_group_draw(GanvItem* item, cairo_t* cr,
- int x, int y, int width, int height)
+ganv_group_draw(GanvItem* item,
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
- GanvGroup* group;
- GList* list;
+ GanvGroup* group = GANV_GROUP(item);
GanvItem* child = NULL;
- group = GANV_GROUP(item);
-
// Draw background
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
- cairo_rectangle(cr, x, y, width, height);
+ cairo_rectangle(cr, cx, cy, cw, ch);
cairo_fill(cr);
// TODO: Layered drawing
- for (list = group->item_list; list; list = list->next) {
+ for (GList* list = group->item_list; list; list = list->next) {
child = (GanvItem*)list->data;
if (((child->object.flags & GANV_ITEM_VISIBLE)
- && ((child->x1 < (x + width))
- && (child->y1 < (y + height))
- && (child->x2 > x)
- && (child->y2 > y)))) {
+ && ((child->x1 < (cx + cw))
+ && (child->y1 < (cy + ch))
+ && (child->x2 > cx)
+ && (child->y2 > cy)))) {
if (GANV_ITEM_GET_CLASS(child)->draw) {
(*GANV_ITEM_GET_CLASS(child)->draw)(
- child, cr, x, y, width, height);
+ child, cr, cx, cy, cw, ch);
}
}
}
}
static double
-ganv_group_point(GanvItem* item, double x, double y, int cx, int cy,
- GanvItem** actual_item)
+ganv_group_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
- GanvGroup* group;
- GList* list;
- GanvItem* child, * point_item;
- int x1, y1, x2, y2;
- double gx, gy;
- double dist, best;
- int has_point;
+ GanvGroup* group = GANV_GROUP(item);
- group = GANV_GROUP(item);
+ const double x1 = x - GANV_CLOSE_ENOUGH;
+ const double y1 = y - GANV_CLOSE_ENOUGH;
+ const double x2 = x + GANV_CLOSE_ENOUGH;
+ const double y2 = y + GANV_CLOSE_ENOUGH;
- x1 = cx - GANV_CLOSE_ENOUGH;
- y1 = cy - GANV_CLOSE_ENOUGH;
- x2 = cx + GANV_CLOSE_ENOUGH;
- y2 = cy + GANV_CLOSE_ENOUGH;
+ double dist = 0.0;
+ double best = 0.0;
- best = 0.0;
*actual_item = NULL;
- gx = x;
- gy = y;
-
- dist = 0.0; /* keep gcc happy */
-
- for (list = group->item_list; list; list = list->next) {
- child = (GanvItem*)list->data;
-
+ for (GList* list = group->item_list; list; list = list->next) {
+ GanvItem* child = (GanvItem*)list->data;
if ((child->x1 > x2) || (child->y1 > y2) || (child->x2 < x1) || (child->y2 < y1)) {
continue;
}
- point_item = NULL; /* cater for incomplete item implementations */
+ GanvItem* point_item = NULL;
+ int has_point = FALSE;
if ((child->object.flags & GANV_ITEM_VISIBLE)
&& GANV_ITEM_GET_CLASS(child)->point) {
dist = GANV_ITEM_GET_CLASS(child)->point(
child,
- gx - child->x, gy - child->y,
- cx, cy,
+ x - child->x, y - child->y,
&point_item);
has_point = TRUE;
- } else {
- has_point = FALSE;
}
if (has_point
&& point_item
- && ((int)(dist * ganv_canvas_get_zoom(item->canvas) + 0.5)
- <= GANV_CLOSE_ENOUGH)) {
+ && ((int)(dist + 0.5) <= GANV_CLOSE_ENOUGH)) {
best = dist;
*actual_item = point_item;
}
diff --git a/src/item.c b/src/item.c
index 0bcdbf8..1bc6de0 100644
--- a/src/item.c
+++ b/src/item.c
@@ -126,9 +126,9 @@ item_post_create_setup(GanvItem* item)
g_warning("item added to non-parent item\n");
}
}
- ganv_canvas_request_redraw(item->canvas,
- item->x1, item->y1,
- item->x2 + 1, item->y2 + 1);
+ ganv_canvas_request_redraw_w(item->canvas,
+ item->x1, item->y1,
+ item->x2 + 1, item->y2 + 1);
ganv_canvas_set_need_repick(item->canvas);
}
@@ -230,9 +230,9 @@ static void
redraw_if_visible(GanvItem* item)
{
if (item->object.flags & GANV_ITEM_VISIBLE) {
- ganv_canvas_request_redraw(item->canvas,
- item->x1, item->y1,
- item->x2 + 1, item->y2 + 1);
+ ganv_canvas_request_redraw_w(item->canvas,
+ item->x1, item->y1,
+ item->x2 + 1, item->y2 + 1);
}
}
@@ -315,10 +315,7 @@ ganv_item_update(GanvItem* item, int flags)
/* Point handler for canvas items */
static double
-ganv_item_point(GanvItem* item,
- double x, double y,
- int cx, int cy,
- GanvItem** actual_item)
+ganv_item_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
*actual_item = NULL;
return G_MAXDOUBLE;
@@ -431,9 +428,9 @@ ganv_item_show(GanvItem* item)
if (!(item->object.flags & GANV_ITEM_VISIBLE)) {
item->object.flags |= GANV_ITEM_VISIBLE;
- ganv_canvas_request_redraw(item->canvas,
- item->x1, item->y1,
- item->x2 + 1, item->y2 + 1);
+ ganv_canvas_request_redraw_w(item->canvas,
+ item->x1, item->y1,
+ item->x2 + 1, item->y2 + 1);
ganv_canvas_set_need_repick(item->canvas);
}
}
@@ -452,9 +449,9 @@ ganv_item_hide(GanvItem* item)
if (item->object.flags & GANV_ITEM_VISIBLE) {
item->object.flags &= ~GANV_ITEM_VISIBLE;
- ganv_canvas_request_redraw(item->canvas,
- item->x1, item->y1,
- item->x2 + 1, item->y2 + 1);
+ ganv_canvas_request_redraw_w(item->canvas,
+ item->x1, item->y1,
+ item->x2 + 1, item->y2 + 1);
ganv_canvas_set_need_repick(item->canvas);
}
}
diff --git a/src/module.c b/src/module.c
index 5434fc8..c8da4d2 100644
--- a/src/module.c
+++ b/src/module.c
@@ -564,34 +564,32 @@ ganv_module_update(GanvItem* item, int flags)
static void
ganv_module_draw(GanvItem* item,
- cairo_t* cr,
- int cx, int cy,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
GanvNode* node = GANV_NODE(item);
GanvModule* module = GANV_MODULE(item);
// Draw box
if (GANV_ITEM_CLASS(parent_class)->draw) {
- (*GANV_ITEM_CLASS(parent_class)->draw)(item, cr, cx, cy, width, height);
+ (*GANV_ITEM_CLASS(parent_class)->draw)(item, cr, cx, cy, cw, ch);
}
// Draw label
if (node->impl->label) {
GanvItem* label_item = GANV_ITEM(node->impl->label);
- GANV_ITEM_GET_CLASS(label_item)->draw(label_item, cr, cx, cy, width, height);
+ GANV_ITEM_GET_CLASS(label_item)->draw(label_item, cr, cx, cy, cw, ch);
}
// Draw ports
FOREACH_PORT(module->impl->ports, p) {
GANV_ITEM_GET_CLASS(GANV_ITEM(*p))->draw(
- GANV_ITEM(*p), cr, cx, cy, width, height);
+ GANV_ITEM(*p), cr, cx, cy, cw, ch);
}
// Draw embed item
if (module->impl->embed_item) {
GANV_ITEM_GET_CLASS(module->impl->embed_item)->draw(
- module->impl->embed_item, cr, cx, cy, width, height);
+ module->impl->embed_item, cr, cx, cy, cw, ch);
}
}
@@ -626,15 +624,11 @@ ganv_module_move(GanvNode* node,
}
static double
-ganv_module_point(GanvItem* item,
- double x, double y,
- int cx, int cy,
- GanvItem** actual_item)
+ganv_module_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
GanvModule* module = GANV_MODULE(item);
- double d = GANV_ITEM_CLASS(parent_class)->point(
- item, x, y, cx, cy, actual_item);
+ double d = GANV_ITEM_CLASS(parent_class)->point(item, x, y, actual_item);
if (!*actual_item) {
// Point is not inside module at all, no point in checking children
@@ -646,10 +640,7 @@ ganv_module_point(GanvItem* item,
*actual_item = NULL;
d = GANV_ITEM_GET_CLASS(port)->point(
- port,
- x - port->x, y - port->y,
- cx, cy,
- actual_item);
+ port, x - port->x, y - port->y, actual_item);
if (*actual_item) {
// Point is inside a port
diff --git a/src/node.c b/src/node.c
index 331ac86..acfa9df 100644
--- a/src/node.c
+++ b/src/node.c
@@ -117,9 +117,7 @@ ganv_node_destroy(GtkObject* object)
static void
ganv_node_draw(GanvItem* item,
- cairo_t* cr,
- int cx, int cy,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
/* TODO: Label is not drawn here because ports need to draw control
rects then the label on top. I can't see a way of solving this since
diff --git a/src/port.c b/src/port.c
index e6bf649..2f7b2b5 100644
--- a/src/port.c
+++ b/src/port.c
@@ -127,20 +127,18 @@ ganv_port_get_property(GObject* object,
static void
ganv_port_draw(GanvItem* item,
- cairo_t* cr,
- int cx, int cy,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
GanvPort* port = GANV_PORT(item);
GanvCanvas* canvas = GANV_CANVAS(item->canvas);
// Draw Box
GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class);
- item_class->draw(item, cr, cx, cy, width, height);
+ item_class->draw(item, cr, cx, cy, cw, ch);
if (port->impl->control) {
GanvItem* const rect = GANV_ITEM(port->impl->control->rect);
- GANV_ITEM_GET_CLASS(rect)->draw(rect, cr, cx, cy, width, height);
+ GANV_ITEM_GET_CLASS(rect)->draw(rect, cr, cx, cy, cw, ch);
}
if (ganv_canvas_get_direction(canvas) == GANV_DIRECTION_DOWN ||
@@ -155,7 +153,7 @@ ganv_port_draw(GanvItem* item,
for (int i = 0; i < 2; ++i) {
if (labels[i] && (labels[i]->object.flags & GANV_ITEM_VISIBLE)) {
GANV_ITEM_GET_CLASS(labels[i])->draw(
- labels[i], cr, cx, cy, width, height);
+ labels[i], cr, cx, cy, cw, ch);
}
}
}
diff --git a/src/text.c b/src/text.c
index 3d3f938..c36aefa 100644
--- a/src/text.c
+++ b/src/text.c
@@ -233,26 +233,18 @@ ganv_text_bounds(GanvItem* item,
static void
ganv_text_update(GanvItem* item, int flags)
{
- double x1, y1, x2, y2;
- ganv_text_bounds(item, &x1, &y1, &x2, &y2);
- ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2);
-
- // I have no idea why this is necessary
- item->x1 = x1;
- item->y1 = y1;
- item->x2 = x2;
- item->y2 = y2;
-
parent_class->update(item, flags);
- ganv_canvas_request_redraw(item->canvas, x1, y1, x2, y2);
+ // Update world-relative bounding box
+ ganv_text_bounds(item, &item->x1, &item->y1, &item->x2, &item->y2);
+ ganv_item_i2w_pair(item, &item->x1, &item->y1, &item->x2, &item->y2);
+
+ ganv_canvas_request_redraw_w(
+ item->canvas, item->x1, item->y1, item->x2, item->y2);
}
static double
-ganv_text_point(GanvItem* item,
- double x, double y,
- int cx, int cy,
- GanvItem** actual_item)
+ganv_text_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
*actual_item = NULL;
@@ -288,9 +280,7 @@ ganv_text_point(GanvItem* item,
static void
ganv_text_draw(GanvItem* item,
- cairo_t* cr,
- int x, int y,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
GanvText* text = GANV_TEXT(item);
GanvTextImpl* impl = text->impl;
diff --git a/src/widget.c b/src/widget.c
index 1442237..ca391d6 100644
--- a/src/widget.c
+++ b/src/widget.c
@@ -317,9 +317,7 @@ ganv_widget_update(GanvItem* item, int flags)
static void
ganv_widget_draw(GanvItem* item,
- cairo_t* cr,
- int x, int y,
- int width, int height)
+ cairo_t* cr, double cx, double cy, double cw, double ch)
{
GanvWidget* witem = GANV_WIDGET(item);
@@ -329,8 +327,7 @@ ganv_widget_draw(GanvItem* item,
}
static double
-ganv_widget_point(GanvItem* item, double x, double y,
- int cx, int cy, GanvItem** actual_item)
+ganv_widget_point(GanvItem* item, double x, double y, GanvItem** actual_item)
{
GanvWidget* witem = GANV_WIDGET(item);