app: respond to viewable expanded state changes in container views

Add an "expanded-changed" signal to GimpViewable, which should be
emitted by subclasses when the viewable's expanded state changes.
Emit this signal when the expanded state of group layers changes.
Respond to this signal in GimpContainerView, by calling a new
expand_item() virtual function.  Implement expand_item() in
GimpContainerTreeView, expanding or collapsing the item as
necessary.
This commit is contained in:
Ell 2017-10-22 11:50:37 -04:00
parent 06ef794977
commit d027a059ef
6 changed files with 112 additions and 4 deletions

View File

@ -438,9 +438,14 @@ static void
gimp_group_layer_set_expanded (GimpViewable *viewable,
gboolean expanded)
{
GimpGroupLayer *group = GIMP_GROUP_LAYER (viewable);
GimpGroupLayerPrivate *private = GET_PRIVATE (viewable);
GET_PRIVATE (group)->expanded = expanded;
if (private->expanded != expanded)
{
private->expanded = expanded;
gimp_viewable_expanded_changed (viewable);
}
}
static gboolean

View File

@ -54,6 +54,7 @@ enum
{
INVALIDATE_PREVIEW,
SIZE_CHANGED,
EXPANDED_CHANGED,
LAST_SIGNAL
};
@ -160,6 +161,15 @@ gimp_viewable_class_init (GimpViewableClass *klass)
gimp_marshal_VOID__VOID,
G_TYPE_NONE, 0);
viewable_signals[EXPANDED_CHANGED] =
g_signal_new ("expanded-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpViewableClass, expanded_changed),
NULL, NULL,
gimp_marshal_VOID__VOID,
G_TYPE_NONE, 0);
object_class->finalize = gimp_viewable_finalize;
object_class->get_property = gimp_viewable_get_property;
object_class->set_property = gimp_viewable_set_property;
@ -172,6 +182,7 @@ gimp_viewable_class_init (GimpViewableClass *klass)
klass->invalidate_preview = gimp_viewable_real_invalidate_preview;
klass->size_changed = NULL;
klass->expanded_changed = NULL;
klass->get_size = NULL;
klass->get_preview_size = gimp_viewable_real_get_preview_size;
@ -556,6 +567,22 @@ gimp_viewable_size_changed (GimpViewable *viewable)
g_signal_emit (viewable, viewable_signals[SIZE_CHANGED], 0);
}
/**
* gimp_viewable_expanded_changed:
* @viewable: a viewable object
*
* This function sends a signal that is handled at a lower level in the
* object hierarchy, and provides a mechanism by which objects derived
* from #GimpViewable can respond to expanded state changes.
**/
void
gimp_viewable_expanded_changed (GimpViewable *viewable)
{
g_return_if_fail (GIMP_IS_VIEWABLE (viewable));
g_signal_emit (viewable, viewable_signals[EXPANDED_CHANGED], 0);
}
/**
* gimp_viewable_calc_preview_size:
* @aspect_width: unscaled width of the preview for an item.

View File

@ -57,6 +57,7 @@ struct _GimpViewableClass
/* signals */
void (* invalidate_preview) (GimpViewable *viewable);
void (* size_changed) (GimpViewable *viewable);
void (* expanded_changed) (GimpViewable *viewable);
/* virtual functions */
gboolean (* get_size) (GimpViewable *viewable,
@ -107,6 +108,7 @@ GType gimp_viewable_get_type (void) G_GNUC_CONST;
void gimp_viewable_invalidate_preview (GimpViewable *viewable);
void gimp_viewable_size_changed (GimpViewable *viewable);
void gimp_viewable_expanded_changed (GimpViewable *viewable);
void gimp_viewable_calc_preview_size (gint aspect_width,
gint aspect_height,

View File

@ -86,6 +86,9 @@ static void gimp_container_tree_view_reorder_item (GimpContainerVi
static void gimp_container_tree_view_rename_item (GimpContainerView *view,
GimpViewable *viewable,
gpointer insert_data);
static void gimp_container_tree_view_expand_item (GimpContainerView *view,
GimpViewable *viewable,
gpointer insert_data);
static gboolean gimp_container_tree_view_select_item (GimpContainerView *view,
GimpViewable *viewable,
gpointer insert_data);
@ -203,6 +206,7 @@ gimp_container_tree_view_view_iface_init (GimpContainerViewInterface *iface)
iface->remove_item = gimp_container_tree_view_remove_item;
iface->reorder_item = gimp_container_tree_view_reorder_item;
iface->rename_item = gimp_container_tree_view_rename_item;
iface->expand_item = gimp_container_tree_view_expand_item;
iface->select_item = gimp_container_tree_view_select_item;
iface->clear_items = gimp_container_tree_view_clear_items;
iface->set_view_size = gimp_container_tree_view_set_view_size;
@ -767,6 +771,41 @@ gimp_container_tree_view_rename_item (GimpContainerView *view,
}
}
static void
gimp_container_tree_view_expand_item (GimpContainerView *view,
GimpViewable *viewable,
gpointer insert_data)
{
GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
GtkTreeIter *iter = (GtkTreeIter *) insert_data;
GimpViewRenderer *renderer;
gtk_tree_model_get (tree_view->model, iter,
GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
-1);
if (renderer)
{
GtkTreePath *path = gtk_tree_model_get_path (tree_view->model, iter);
g_signal_handlers_block_by_func (tree_view,
gimp_container_tree_view_row_expanded,
view);
if (gimp_viewable_get_expanded (renderer->viewable))
gtk_tree_view_expand_row (tree_view->view, path, FALSE);
else
gtk_tree_view_collapse_row (tree_view->view, path);
g_signal_handlers_unblock_by_func (tree_view,
gimp_container_tree_view_row_expanded,
view);
gtk_tree_path_free (path);
g_object_unref (renderer);
}
}
static gboolean
gimp_container_tree_view_select_item (GimpContainerView *view,
GimpViewable *viewable,

View File

@ -72,6 +72,7 @@ struct _GimpContainerViewPrivate
GtkWidget *dnd_widget;
GimpTreeHandler *name_changed_handler;
GimpTreeHandler *expanded_changed_handler;
};
@ -117,6 +118,8 @@ static void gimp_container_view_thaw (GimpContainerView *view,
GimpContainer *container);
static void gimp_container_view_name_changed (GimpViewable *viewable,
GimpContainerView *view);
static void gimp_container_view_expanded_changed (GimpViewable *viewable,
GimpContainerView *view);
static void gimp_container_view_connect_context (GimpContainerView *view);
static void gimp_container_view_disconnect_context (GimpContainerView *view);
@ -217,6 +220,7 @@ gimp_container_view_iface_base_init (GimpContainerViewInterface *view_iface)
view_iface->remove_item = NULL;
view_iface->reorder_item = NULL;
view_iface->rename_item = NULL;
view_iface->expand_item = NULL;
view_iface->clear_items = gimp_container_view_real_clear_items;
view_iface->set_view_size = NULL;
view_iface->get_selected = gimp_container_view_real_get_selected;
@ -980,6 +984,15 @@ gimp_container_view_add_container (GimpContainerView *view,
G_CALLBACK (gimp_container_view_name_changed),
view);
if (GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->expand_item)
{
private->expanded_changed_handler =
gimp_tree_handler_connect (container,
"expanded-changed",
G_CALLBACK (gimp_container_view_expanded_changed),
view);
}
g_type_class_unref (viewable_class);
}
@ -1088,8 +1101,10 @@ gimp_container_view_remove_container (GimpContainerView *view,
if (container == private->container)
{
gimp_tree_handler_disconnect (private->name_changed_handler);
private->name_changed_handler = NULL;
g_clear_pointer (&private->name_changed_handler,
gimp_tree_handler_disconnect);
g_clear_pointer (&private->expanded_changed_handler,
gimp_tree_handler_disconnect);
/* optimization: when the toplevel container gets removed, call
* clear_items() which will get rid of all view widget stuff
@ -1212,6 +1227,23 @@ gimp_container_view_name_changed (GimpViewable *viewable,
}
}
static void
gimp_container_view_expanded_changed (GimpViewable *viewable,
GimpContainerView *view)
{
GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
gpointer insert_data;
insert_data = g_hash_table_lookup (private->item_hash, viewable);
if (insert_data)
{
GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->expand_item (view,
viewable,
insert_data);
}
}
static void
gimp_container_view_connect_context (GimpContainerView *view)
{

View File

@ -83,6 +83,9 @@ struct _GimpContainerViewInterface
void (* rename_item) (GimpContainerView *view,
GimpViewable *object,
gpointer insert_data);
void (* expand_item) (GimpContainerView *view,
GimpViewable *object,
gpointer insert_data);
void (* clear_items) (GimpContainerView *view);
void (* set_view_size) (GimpContainerView *view);
gint (* get_selected) (GimpContainerView *view,