From e477fba7331b8a874b00a567defb09a888590aea Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 30 Mar 2014 20:12:48 +0000 Subject: 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 --- ganv/Canvas.hpp | 2 +- ganv/canvas.h | 2 +- ganv/item.h | 21 ++++++------- src/Canvas.cpp | 92 +++++++++++++++++++++++++----------------------------- src/box.c | 24 +++++--------- src/circle.c | 35 +++++++-------------- src/edge.c | 51 +++++++++++++++--------------- src/ganv-private.h | 16 +++++----- src/group.c | 67 ++++++++++++++------------------------- src/item.c | 29 ++++++++--------- src/module.c | 25 +++++---------- src/node.c | 4 +-- src/port.c | 10 +++--- src/text.c | 26 +++++---------- src/widget.c | 7 ++--- 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); -- cgit v1.2.1