From e6ce564de45a8fbc14a384412da10df186a4516f Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Sun, 26 Sep 2010 14:12:54 +0200 Subject: [PATCH] app: add an infrastructure that allows to stroke multiple items at once In order to avoid visually overlapping lines: - GimpCanvasItem got a "suspend_stroking" API that allows to skip stroking and instead starts a new sub-path - GimpCanvasGroup got a "group_stroking" API that sets suspend_stroking on all its children and does one stroke after calling all items' draw(). --- app/display/gimpcanvasgroup.c | 58 ++++++++++++++++++++++++++++++++--- app/display/gimpcanvasgroup.h | 13 +++++--- app/display/gimpcanvasitem.c | 51 ++++++++++++++++++++++++++---- app/display/gimpcanvasitem.h | 31 ++++++++++--------- 4 files changed, 125 insertions(+), 28 deletions(-) diff --git a/app/display/gimpcanvasgroup.c b/app/display/gimpcanvasgroup.c index 6b4d465b84..95b50a8dc7 100644 --- a/app/display/gimpcanvasgroup.c +++ b/app/display/gimpcanvasgroup.c @@ -35,7 +35,8 @@ enum { - PROP_0 + PROP_0, + PROP_GROUP_STROKING }; @@ -43,7 +44,8 @@ typedef struct _GimpCanvasGroupPrivate GimpCanvasGroupPrivate; struct _GimpCanvasGroupPrivate { - GList *items; + GList *items; + gboolean group_stroking; }; #define GET_PRIVATE(group) \ @@ -88,6 +90,12 @@ gimp_canvas_group_class_init (GimpCanvasGroupClass *klass) item_class->draw = gimp_canvas_group_draw; item_class->get_extents = gimp_canvas_group_get_extents; + g_object_class_install_property (object_class, PROP_GROUP_STROKING, + g_param_spec_boolean ("group-stroking", + NULL, NULL, + FALSE, + GIMP_PARAM_READWRITE)); + g_type_class_add_private (klass, sizeof (GimpCanvasGroupPrivate)); } @@ -117,10 +125,14 @@ gimp_canvas_group_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - /* GimpCanvasGroupPrivate *private = GET_PRIVATE (object); */ + GimpCanvasGroupPrivate *private = GET_PRIVATE (object); switch (property_id) { + case PROP_GROUP_STROKING: + private->group_stroking = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -133,10 +145,14 @@ gimp_canvas_group_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - /* GimpCanvasGroupPrivate *private = GET_PRIVATE (object); */ + GimpCanvasGroupPrivate *private = GET_PRIVATE (object); switch (property_id) { + case PROP_GROUP_STROKING: + g_value_set_boolean (value, private->group_stroking); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -157,6 +173,9 @@ gimp_canvas_group_draw (GimpCanvasItem *item, gimp_canvas_item_draw (sub_item, shell, cr); } + + if (private->group_stroking) + _gimp_canvas_item_stroke (item, shell, cr); } static GdkRegion * @@ -205,5 +224,36 @@ gimp_canvas_group_add_item (GimpCanvasGroup *group, private = GET_PRIVATE (group); + if (private->group_stroking) + gimp_canvas_item_suspend_stroking (item); + private->items = g_list_append (private->items, g_object_ref (item)); } + +void +gimp_canvas_group_remove_item (GimpCanvasGroup *group, + GimpCanvasItem *item) +{ + GimpCanvasGroupPrivate *private; + + g_return_if_fail (GIMP_IS_CANVAS_GROUP (group)); + g_return_if_fail (GIMP_IS_CANVAS_ITEM (item)); + + private = GET_PRIVATE (group); + + g_return_if_fail (g_list_find (private->items, item)); + + private->items = g_list_remove (private->items, item); + g_object_unref (item); +} + +void +gimp_canvas_group_set_group_stroking (GimpCanvasGroup *group, + gboolean group_stroking) +{ + g_return_if_fail (GIMP_IS_CANVAS_GROUP (group)); + + g_object_set (group, + "group-stroking", group_stroking ? TRUE : FALSE, + NULL); +} diff --git a/app/display/gimpcanvasgroup.h b/app/display/gimpcanvasgroup.h index 150bb54682..f0d10a46f0 100644 --- a/app/display/gimpcanvasgroup.h +++ b/app/display/gimpcanvasgroup.h @@ -47,12 +47,17 @@ struct _GimpCanvasGroupClass }; -GType gimp_canvas_group_get_type (void) G_GNUC_CONST; +GType gimp_canvas_group_get_type (void) G_GNUC_CONST; -GimpCanvasItem * gimp_canvas_group_new (void); +GimpCanvasItem * gimp_canvas_group_new (void); -void gimp_canvas_group_add_item (GimpCanvasGroup *group, - GimpCanvasItem *item); +void gimp_canvas_group_add_item (GimpCanvasGroup *group, + GimpCanvasItem *item); +void gimp_canvas_group_remove_item (GimpCanvasGroup *group, + GimpCanvasItem *item); + +void gimp_canvas_group_set_group_stroking (GimpCanvasGroup *group, + gboolean group_stroking); #endif /* __GIMP_CANVAS_GROUP_H__ */ diff --git a/app/display/gimpcanvasitem.c b/app/display/gimpcanvasitem.c index b6aeaee578..2bdf0561b0 100644 --- a/app/display/gimpcanvasitem.c +++ b/app/display/gimpcanvasitem.c @@ -37,6 +37,7 @@ typedef struct _GimpCanvasItemPrivate GimpCanvasItemPrivate; struct _GimpCanvasItemPrivate { gboolean highlight; + gint suspend_stroking; }; #define GET_PRIVATE(item) \ @@ -122,15 +123,43 @@ void gimp_canvas_item_set_highlight (GimpCanvasItem *item, gboolean highlight) { - GimpCanvasItemPrivate *private = GET_PRIVATE (item); + GimpCanvasItemPrivate *private; g_return_if_fail (GIMP_IS_CANVAS_ITEM (item)); + private = GET_PRIVATE (item); + private->highlight = highlight ? TRUE : FALSE; } +void +gimp_canvas_item_suspend_stroking (GimpCanvasItem *item) +{ + GimpCanvasItemPrivate *private; -/* protexted functions */ + g_return_if_fail (GIMP_IS_CANVAS_ITEM (item)); + + private = GET_PRIVATE (item); + + private->suspend_stroking++; +} + +void +gimp_canvas_item_resume_stroking (GimpCanvasItem *item) +{ + GimpCanvasItemPrivate *private; + + g_return_if_fail (GIMP_IS_CANVAS_ITEM (item)); + + private = GET_PRIVATE (item); + + g_return_if_fail (private->suspend_stroking > 0); + + private->suspend_stroking--; +} + + +/* protected functions */ void _gimp_canvas_item_stroke (GimpCanvasItem *item, @@ -139,11 +168,18 @@ _gimp_canvas_item_stroke (GimpCanvasItem *item, { GimpCanvasItemPrivate *private = GET_PRIVATE (item); - gimp_display_shell_set_tool_bg_style (shell, cr); - cairo_stroke_preserve (cr); + if (private->suspend_stroking == 0) + { + gimp_display_shell_set_tool_bg_style (shell, cr); + cairo_stroke_preserve (cr); - gimp_display_shell_set_tool_fg_style (shell, cr, private->highlight); - cairo_stroke (cr); + gimp_display_shell_set_tool_fg_style (shell, cr, private->highlight); + cairo_stroke (cr); + } + else + { + cairo_new_sub_path (cr); + } } void @@ -153,6 +189,9 @@ _gimp_canvas_item_fill (GimpCanvasItem *item, { GimpCanvasItemPrivate *private = GET_PRIVATE (item); + if (private->suspend_stroking > 0) + g_warning ("_gimp_canvas_item_fill() on an item that is in a stroking group"); + gimp_display_shell_set_tool_bg_style (shell, cr); cairo_set_line_width (cr, 2.0); cairo_stroke_preserve (cr); diff --git a/app/display/gimpcanvasitem.h b/app/display/gimpcanvasitem.h index 876d996944..fa14af68f7 100644 --- a/app/display/gimpcanvasitem.h +++ b/app/display/gimpcanvasitem.h @@ -52,26 +52,29 @@ struct _GimpCanvasItemClass }; -GType gimp_canvas_item_get_type (void) G_GNUC_CONST; +GType gimp_canvas_item_get_type (void) G_GNUC_CONST; -void gimp_canvas_item_draw (GimpCanvasItem *item, - GimpDisplayShell *shell, - cairo_t *cr); -GdkRegion * gimp_canvas_item_get_extents (GimpCanvasItem *item, - GimpDisplayShell *shell); +void gimp_canvas_item_draw (GimpCanvasItem *item, + GimpDisplayShell *shell, + cairo_t *cr); +GdkRegion * gimp_canvas_item_get_extents (GimpCanvasItem *item, + GimpDisplayShell *shell); -void gimp_canvas_item_set_highlight(GimpCanvasItem *item, - gboolean highlight); +void gimp_canvas_item_set_highlight (GimpCanvasItem *item, + gboolean highlight); + +void gimp_canvas_item_suspend_stroking (GimpCanvasItem *item); +void gimp_canvas_item_resume_stroking (GimpCanvasItem *item); /* protected */ -void _gimp_canvas_item_stroke (GimpCanvasItem *item, - GimpDisplayShell *shell, - cairo_t *cr); -void _gimp_canvas_item_fill (GimpCanvasItem *item, - GimpDisplayShell *shell, - cairo_t *cr); +void _gimp_canvas_item_stroke (GimpCanvasItem *item, + GimpDisplayShell *shell, + cairo_t *cr); +void _gimp_canvas_item_fill (GimpCanvasItem *item, + GimpDisplayShell *shell, + cairo_t *cr); #endif /* __GIMP_CANVAS_ITEM_H__ */