Commit 10111126 authored by Michael Natterer's avatar Michael Natterer 😴

app: add a "visible" property and API to GimpCanvasItem

and use it to set visibility of guides and sample points, so this
reression is fixed.

- return NULL extents for invisible items and never draw them
- do nothing for invisible items in more places, like the group

While hacking this, it turned out that it was a braino to collect an
item's region before and after a change in
dispatch_properties_changed(), so a new update had to be devised:

- add a "change count" and new API begin_change()/end_change()
- in begin_change(), remember the item's extents before the change
- in end_change(), combine old and current extents and emit "update"
- add some protected function to emit "update", and to figure if
  it makes sense at all to emit "update" on an item.
parent f0d01f61
......@@ -230,7 +230,8 @@ gimp_canvas_group_child_update (GimpCanvasItem *item,
GdkRegion *region,
GimpCanvasGroup *group)
{
g_signal_emit_by_name (group, "update", region);
if (_gimp_canvas_item_needs_update (GIMP_CANVAS_ITEM (group)))
_gimp_canvas_item_update (GIMP_CANVAS_ITEM (group), region);
}
......@@ -251,7 +252,6 @@ gimp_canvas_group_add_item (GimpCanvasGroup *group,
GimpCanvasItem *item)
{
GimpCanvasGroupPrivate *private;
GdkRegion *region;
g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
......@@ -267,12 +267,15 @@ gimp_canvas_group_add_item (GimpCanvasGroup *group,
private->items = g_list_append (private->items, g_object_ref (item));
region = gimp_canvas_item_get_extents (item);
if (region)
if (_gimp_canvas_item_needs_update (GIMP_CANVAS_ITEM (group)))
{
g_signal_emit_by_name (group, "update", region);
gdk_region_destroy (region);
GdkRegion *region = gimp_canvas_item_get_extents (item);
if (region)
{
_gimp_canvas_item_update (GIMP_CANVAS_ITEM (group), region);
gdk_region_destroy (region);
}
}
g_signal_connect (item, "update",
......@@ -285,7 +288,6 @@ gimp_canvas_group_remove_item (GimpCanvasGroup *group,
GimpCanvasItem *item)
{
GimpCanvasGroupPrivate *private;
GdkRegion *region;
g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
......@@ -296,12 +298,15 @@ gimp_canvas_group_remove_item (GimpCanvasGroup *group,
private->items = g_list_remove (private->items, item);
region = gimp_canvas_item_get_extents (item);
if (region)
if (_gimp_canvas_item_needs_update (GIMP_CANVAS_ITEM (group)))
{
g_signal_emit_by_name (group, "update", region);
gdk_region_destroy (region);
GdkRegion *region = gimp_canvas_item_get_extents (item);
if (region)
{
_gimp_canvas_item_update (GIMP_CANVAS_ITEM (group), region);
gdk_region_destroy (region);
}
}
g_signal_handlers_disconnect_by_func (item,
......
......@@ -38,6 +38,7 @@ enum
{
PROP_0,
PROP_SHELL,
PROP_VISIBLE,
PROP_LINE_CAP,
PROP_HIGHLIGHT
};
......@@ -54,10 +55,13 @@ typedef struct _GimpCanvasItemPrivate GimpCanvasItemPrivate;
struct _GimpCanvasItemPrivate
{
GimpDisplayShell *shell;
gboolean visible;
cairo_line_cap_t line_cap;
gboolean highlight;
gint suspend_stroking;
gint suspend_filling;
gint change_count;
GdkRegion *change_region;
};
#define GET_PRIVATE(item) \
......@@ -136,6 +140,12 @@ gimp_canvas_item_class_init (GimpCanvasItemClass *klass)
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_VISIBLE,
g_param_spec_boolean ("visible",
NULL, NULL,
TRUE,
GIMP_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_LINE_CAP,
g_param_spec_int ("line-cap",
NULL, NULL,
......@@ -159,10 +169,13 @@ gimp_canvas_item_init (GimpCanvasItem *item)
GimpCanvasItemPrivate *private = GET_PRIVATE (item);
private->shell = NULL;
private->visible = TRUE;
private->line_cap = CAIRO_LINE_CAP_ROUND;
private->highlight = FALSE;
private->suspend_stroking = 0;
private->suspend_filling = 0;
private->change_count = 1; /* avoid emissions during construction */
private->change_region = NULL;
}
static void
......@@ -172,6 +185,8 @@ gimp_canvas_item_constructed (GObject *object)
g_assert (GIMP_IS_DISPLAY_SHELL (private->shell));
private->change_count = 0; /* undo hack from init() */
if (G_OBJECT_CLASS (parent_class)->constructed)
G_OBJECT_CLASS (parent_class)->constructed (object);
}
......@@ -189,6 +204,9 @@ gimp_canvas_item_set_property (GObject *object,
case PROP_SHELL:
private->shell = g_value_get_object (value); /* don't ref */
break;
case PROP_VISIBLE:
private->visible = g_value_get_boolean (value);
break;
case PROP_LINE_CAP:
private->line_cap = g_value_get_int (value);
break;
......@@ -215,6 +233,9 @@ gimp_canvas_item_get_property (GObject *object,
case PROP_SHELL:
g_value_set_object (value, private->shell);
break;
case PROP_VISIBLE:
g_value_set_boolean (value, private->visible);
break;
case PROP_LINE_CAP:
g_value_set_int (value, private->line_cap);
break;
......@@ -235,28 +256,13 @@ gimp_canvas_item_dispatch_properties_changed (GObject *object,
{
GimpCanvasItem *item = GIMP_CANVAS_ITEM (object);
if (g_signal_has_handler_pending (object, item_signals[UPDATE], 0, FALSE))
{
GdkRegion *before;
GdkRegion *region;
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
n_pspecs,
pspecs);
before = gimp_canvas_item_get_extents (item);
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
n_pspecs,
pspecs);
region = gimp_canvas_item_get_extents (item);
if (! region)
{
region = before;
}
else if (before)
{
gdk_region_union (region, before);
gdk_region_destroy (before);
}
if (_gimp_canvas_item_needs_update (item))
{
GdkRegion *region = gimp_canvas_item_get_extents (item);
if (region)
{
......@@ -265,12 +271,6 @@ gimp_canvas_item_dispatch_properties_changed (GObject *object,
gdk_region_destroy (region);
}
}
else
{
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
n_pspecs,
pspecs);
}
}
static void
......@@ -333,11 +333,12 @@ gimp_canvas_item_draw (GimpCanvasItem *item,
private = GET_PRIVATE (item);
cairo_save (cr);
GIMP_CANVAS_ITEM_GET_CLASS (item)->draw (item, private->shell, cr);
cairo_restore (cr);
if (private->visible)
{
cairo_save (cr);
GIMP_CANVAS_ITEM_GET_CLASS (item)->draw (item, private->shell, cr);
cairo_restore (cr);
}
}
GdkRegion *
......@@ -349,7 +350,42 @@ gimp_canvas_item_get_extents (GimpCanvasItem *item)
private = GET_PRIVATE (item);
return GIMP_CANVAS_ITEM_GET_CLASS (item)->get_extents (item, private->shell);
if (private->visible)
return GIMP_CANVAS_ITEM_GET_CLASS (item)->get_extents (item, private->shell);
return NULL;
}
void
gimp_canvas_item_set_visible (GimpCanvasItem *item,
gboolean visible)
{
GimpCanvasItemPrivate *private;
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
private = GET_PRIVATE (item);
if (private->visible != visible)
{
gimp_canvas_item_begin_change (item);
g_object_set (G_OBJECT (item),
"visible", visible,
NULL);
gimp_canvas_item_end_change (item);
}
}
gboolean
gimp_canvas_item_get_visible (GimpCanvasItem *item)
{
GimpCanvasItemPrivate *private;
g_return_val_if_fail (GIMP_IS_CANVAS_ITEM (item), FALSE);
private = GET_PRIVATE (item);
return private->visible;
}
void
......@@ -362,14 +398,13 @@ gimp_canvas_item_set_line_cap (GimpCanvasItem *item,
private = GET_PRIVATE (item);
line_cap = CLAMP (line_cap,
CAIRO_LINE_CAP_BUTT,
CAIRO_LINE_CAP_SQUARE);
if (private->line_cap != line_cap)
{
private->line_cap = line_cap;
g_object_notify (G_OBJECT (item), "line-cap");
gimp_canvas_item_begin_change (item);
g_object_set (G_OBJECT (item),
"line-cap", line_cap,
NULL);
gimp_canvas_item_end_change (item);
}
}
......@@ -383,12 +418,11 @@ gimp_canvas_item_set_highlight (GimpCanvasItem *item,
private = GET_PRIVATE (item);
highlight = highlight ? TRUE : FALSE;
if (private->highlight != highlight)
{
private->highlight = highlight;
g_object_notify (G_OBJECT (item), "highlight");
g_object_set (G_OBJECT (item),
"highlight", highlight,
NULL);
}
}
......@@ -404,6 +438,63 @@ gimp_canvas_item_get_highlight (GimpCanvasItem *item)
return private->highlight;
}
void
gimp_canvas_item_begin_change (GimpCanvasItem *item)
{
GimpCanvasItemPrivate *private;
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
private = GET_PRIVATE (item);
private->change_count++;
if (private->change_count == 1 &&
g_signal_has_handler_pending (item, item_signals[UPDATE], 0, FALSE))
{
private->change_region = gimp_canvas_item_get_extents (item);
}
}
void
gimp_canvas_item_end_change (GimpCanvasItem *item)
{
GimpCanvasItemPrivate *private;
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
private = GET_PRIVATE (item);
g_return_if_fail (private->change_count > 0);
private->change_count--;
if (private->change_count == 0 &&
g_signal_has_handler_pending (item, item_signals[UPDATE], 0, FALSE))
{
GdkRegion *region = gimp_canvas_item_get_extents (item);
if (! region)
{
region = private->change_region;
}
else if (private->change_region)
{
gdk_region_union (region, private->change_region);
gdk_region_destroy (private->change_region);
}
private->change_region = NULL;
if (region)
{
g_signal_emit (item, item_signals[UPDATE], 0,
region);
gdk_region_destroy (region);
}
}
}
void
gimp_canvas_item_suspend_stroking (GimpCanvasItem *item)
{
......@@ -459,6 +550,23 @@ gimp_canvas_item_resume_filling (GimpCanvasItem *item)
/* protected functions */
void
_gimp_canvas_item_update (GimpCanvasItem *item,
GdkRegion *region)
{
g_signal_emit (item, item_signals[UPDATE], 0,
region);
}
gboolean
_gimp_canvas_item_needs_update (GimpCanvasItem *item)
{
GimpCanvasItemPrivate *private = GET_PRIVATE (item);
return (private->change_count == 0 &&
g_signal_has_handler_pending (item, item_signals[UPDATE], 0, FALSE));
}
void
_gimp_canvas_item_stroke (GimpCanvasItem *item,
cairo_t *cr)
......
......@@ -70,6 +70,10 @@ void gimp_canvas_item_draw (GimpCanvasItem *item,
cairo_t *cr);
GdkRegion * gimp_canvas_item_get_extents (GimpCanvasItem *item);
void gimp_canvas_item_set_visible (GimpCanvasItem *item,
gboolean visible);
gboolean gimp_canvas_item_get_visible (GimpCanvasItem *item);
void gimp_canvas_item_set_line_cap (GimpCanvasItem *item,
cairo_line_cap_t line_cap);
......@@ -77,6 +81,9 @@ void gimp_canvas_item_set_highlight (GimpCanvasItem *item,
gboolean highlight);
gboolean gimp_canvas_item_get_highlight (GimpCanvasItem *item);
void gimp_canvas_item_begin_change (GimpCanvasItem *item);
void gimp_canvas_item_end_change (GimpCanvasItem *item);
void gimp_canvas_item_suspend_stroking (GimpCanvasItem *item);
void gimp_canvas_item_resume_stroking (GimpCanvasItem *item);
......@@ -86,6 +93,9 @@ void gimp_canvas_item_resume_filling (GimpCanvasItem *item);
/* protected */
void _gimp_canvas_item_update (GimpCanvasItem *item,
GdkRegion *region);
gboolean _gimp_canvas_item_needs_update (GimpCanvasItem *item);
void _gimp_canvas_item_stroke (GimpCanvasItem *item,
cairo_t *cr);
void _gimp_canvas_item_fill (GimpCanvasItem *item,
......
......@@ -40,6 +40,7 @@
#include "widgets/gimpwidgets-utils.h"
#include "gimpcanvas.h"
#include "gimpcanvasitem.h"
#include "gimpdisplay.h"
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-appearance.h"
......@@ -295,7 +296,6 @@ gimp_display_shell_set_show_guides (GimpDisplayShell *shell,
gboolean show)
{
GimpDisplayOptions *options;
GimpImage *image;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
......@@ -303,12 +303,7 @@ gimp_display_shell_set_show_guides (GimpDisplayShell *shell,
g_object_set (options, "show-guides", show, NULL);
image = gimp_display_get_image (shell->display);
if (image && gimp_image_get_guides (image))
{
gimp_display_shell_expose_full (shell);
}
gimp_canvas_item_set_visible (shell->guides, show);
appearance_set_action_active (shell, "view-show-guides", show);
}
......@@ -357,7 +352,6 @@ gimp_display_shell_set_show_sample_points (GimpDisplayShell *shell,
gboolean show)
{
GimpDisplayOptions *options;
GimpImage *image;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
......@@ -365,12 +359,7 @@ gimp_display_shell_set_show_sample_points (GimpDisplayShell *shell,
g_object_set (options, "show-sample-points", show, NULL);
image = gimp_display_get_image (shell->display);
if (image && gimp_image_get_sample_points (image))
{
gimp_display_shell_expose_full (shell);
}
gimp_canvas_item_set_visible (shell->sample_points, show);
appearance_set_action_active (shell, "view-show-sample-points", show);
}
......
......@@ -572,10 +572,12 @@ gimp_display_shell_guide_move_handler (GimpImage *image,
item = gimp_canvas_proxy_group_get_item (group, guide);
gimp_canvas_item_begin_change (item);
g_object_set (item,
"orientation", gimp_guide_get_orientation (guide),
"position", gimp_guide_get_position (guide),
NULL);
gimp_canvas_item_end_change (item);
}
static void
......@@ -647,10 +649,12 @@ gimp_display_shell_sample_point_move_handler (GimpImage *image,
item = gimp_canvas_proxy_group_get_item (group, sample_point);
gimp_canvas_item_begin_change (item);
g_object_set (item,
"x", sample_point->x,
"y", sample_point->y,
NULL);
gimp_canvas_item_end_change (item);
}
static void
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment