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().
This commit is contained in:
Michael Natterer
2010-09-26 14:12:54 +02:00
parent ea5190e630
commit e6ce564de4
4 changed files with 125 additions and 28 deletions

View File

@ -35,7 +35,8 @@
enum enum
{ {
PROP_0 PROP_0,
PROP_GROUP_STROKING
}; };
@ -43,7 +44,8 @@ typedef struct _GimpCanvasGroupPrivate GimpCanvasGroupPrivate;
struct _GimpCanvasGroupPrivate struct _GimpCanvasGroupPrivate
{ {
GList *items; GList *items;
gboolean group_stroking;
}; };
#define GET_PRIVATE(group) \ #define GET_PRIVATE(group) \
@ -88,6 +90,12 @@ gimp_canvas_group_class_init (GimpCanvasGroupClass *klass)
item_class->draw = gimp_canvas_group_draw; item_class->draw = gimp_canvas_group_draw;
item_class->get_extents = gimp_canvas_group_get_extents; 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)); g_type_class_add_private (klass, sizeof (GimpCanvasGroupPrivate));
} }
@ -117,10 +125,14 @@ gimp_canvas_group_set_property (GObject *object,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
/* GimpCanvasGroupPrivate *private = GET_PRIVATE (object); */ GimpCanvasGroupPrivate *private = GET_PRIVATE (object);
switch (property_id) switch (property_id)
{ {
case PROP_GROUP_STROKING:
private->group_stroking = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break; break;
@ -133,10 +145,14 @@ gimp_canvas_group_get_property (GObject *object,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
/* GimpCanvasGroupPrivate *private = GET_PRIVATE (object); */ GimpCanvasGroupPrivate *private = GET_PRIVATE (object);
switch (property_id) switch (property_id)
{ {
case PROP_GROUP_STROKING:
g_value_set_boolean (value, private->group_stroking);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break; break;
@ -157,6 +173,9 @@ gimp_canvas_group_draw (GimpCanvasItem *item,
gimp_canvas_item_draw (sub_item, shell, cr); gimp_canvas_item_draw (sub_item, shell, cr);
} }
if (private->group_stroking)
_gimp_canvas_item_stroke (item, shell, cr);
} }
static GdkRegion * static GdkRegion *
@ -205,5 +224,36 @@ gimp_canvas_group_add_item (GimpCanvasGroup *group,
private = GET_PRIVATE (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)); 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);
}

View File

@ -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, void gimp_canvas_group_add_item (GimpCanvasGroup *group,
GimpCanvasItem *item); 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__ */ #endif /* __GIMP_CANVAS_GROUP_H__ */

View File

@ -37,6 +37,7 @@ typedef struct _GimpCanvasItemPrivate GimpCanvasItemPrivate;
struct _GimpCanvasItemPrivate struct _GimpCanvasItemPrivate
{ {
gboolean highlight; gboolean highlight;
gint suspend_stroking;
}; };
#define GET_PRIVATE(item) \ #define GET_PRIVATE(item) \
@ -122,15 +123,43 @@ void
gimp_canvas_item_set_highlight (GimpCanvasItem *item, gimp_canvas_item_set_highlight (GimpCanvasItem *item,
gboolean highlight) gboolean highlight)
{ {
GimpCanvasItemPrivate *private = GET_PRIVATE (item); GimpCanvasItemPrivate *private;
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item)); g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
private = GET_PRIVATE (item);
private->highlight = highlight ? TRUE : FALSE; 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 void
_gimp_canvas_item_stroke (GimpCanvasItem *item, _gimp_canvas_item_stroke (GimpCanvasItem *item,
@ -139,11 +168,18 @@ _gimp_canvas_item_stroke (GimpCanvasItem *item,
{ {
GimpCanvasItemPrivate *private = GET_PRIVATE (item); GimpCanvasItemPrivate *private = GET_PRIVATE (item);
gimp_display_shell_set_tool_bg_style (shell, cr); if (private->suspend_stroking == 0)
cairo_stroke_preserve (cr); {
gimp_display_shell_set_tool_bg_style (shell, cr);
cairo_stroke_preserve (cr);
gimp_display_shell_set_tool_fg_style (shell, cr, private->highlight); gimp_display_shell_set_tool_fg_style (shell, cr, private->highlight);
cairo_stroke (cr); cairo_stroke (cr);
}
else
{
cairo_new_sub_path (cr);
}
} }
void void
@ -153,6 +189,9 @@ _gimp_canvas_item_fill (GimpCanvasItem *item,
{ {
GimpCanvasItemPrivate *private = GET_PRIVATE (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); gimp_display_shell_set_tool_bg_style (shell, cr);
cairo_set_line_width (cr, 2.0); cairo_set_line_width (cr, 2.0);
cairo_stroke_preserve (cr); cairo_stroke_preserve (cr);

View File

@ -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, void gimp_canvas_item_draw (GimpCanvasItem *item,
GimpDisplayShell *shell, GimpDisplayShell *shell,
cairo_t *cr); cairo_t *cr);
GdkRegion * gimp_canvas_item_get_extents (GimpCanvasItem *item, GdkRegion * gimp_canvas_item_get_extents (GimpCanvasItem *item,
GimpDisplayShell *shell); GimpDisplayShell *shell);
void gimp_canvas_item_set_highlight(GimpCanvasItem *item, void gimp_canvas_item_set_highlight (GimpCanvasItem *item,
gboolean highlight); gboolean highlight);
void gimp_canvas_item_suspend_stroking (GimpCanvasItem *item);
void gimp_canvas_item_resume_stroking (GimpCanvasItem *item);
/* protected */ /* protected */
void _gimp_canvas_item_stroke (GimpCanvasItem *item, void _gimp_canvas_item_stroke (GimpCanvasItem *item,
GimpDisplayShell *shell, GimpDisplayShell *shell,
cairo_t *cr); cairo_t *cr);
void _gimp_canvas_item_fill (GimpCanvasItem *item, void _gimp_canvas_item_fill (GimpCanvasItem *item,
GimpDisplayShell *shell, GimpDisplayShell *shell,
cairo_t *cr); cairo_t *cr);
#endif /* __GIMP_CANVAS_ITEM_H__ */ #endif /* __GIMP_CANVAS_ITEM_H__ */