app: Up/Down in GimpContainerTreeView should select items "visually".

layers-select-next/layers-select-previous don't work well as up/down
arrow behavior because they only work within each selected layer's
level. But historically (and that's what makes the most sense IMO, and
is the most expected behavior), up/down arrows would walk through the
layer list visually. I.e. that it would select next whatever is the next
layer displayed in the Layers dockable, even if it means selecting
children or going down one layer group level.

The 2 new actions "layers-select-flattened-previous" and
"layers-select-flattened-next" do this. Say you have this tree:

Layer 1
Layer 2
 | - Layer 3
 | - Layer 4
Layer 5

With the "flattened" actions, after Layer 2, there is Layer 3, and after
Layer 4, there is Layer 5… unless… Layer 2 (layer group) is collapsed.
In which case, after Layer 2 is Layer 5. This selection movement indeed
takes into account the state of the layer group expanders.

This makes the Up/Down arrows work similarly to how they used to work
with default GtkTreeView implementation, except that the logic now also
works well with multiple selected items.
This commit is contained in:
Jehan 2024-08-13 15:48:06 +02:00
parent aee55ab25c
commit 576554a0af
6 changed files with 137 additions and 14 deletions

View File

@ -36,7 +36,9 @@ typedef enum
GIMP_ACTION_SELECT_SKIP_PREVIOUS = -8,
GIMP_ACTION_SELECT_SKIP_NEXT = -9,
GIMP_ACTION_SELECT_PERCENT_PREVIOUS = -10,
GIMP_ACTION_SELECT_PERCENT_NEXT = -11
GIMP_ACTION_SELECT_PERCENT_NEXT = -11,
GIMP_ACTION_SELECT_FLAT_PREVIOUS = -12,
GIMP_ACTION_SELECT_FLAT_NEXT = -13,
} GimpActionSelectType;
typedef enum

View File

@ -28,6 +28,7 @@
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
#include "core/gimpitem.h"
#include "core/gimptooloptions.h"
#include "core/gimptoolinfo.h"
@ -729,6 +730,91 @@ action_select_object (GimpActionSelectType select_type,
select_index = gimp_container_get_child_index (container, current) + 10;
break;
case GIMP_ACTION_SELECT_FLAT_PREVIOUS:
/* XXX We only support this case and the next for GimpItem
* containers.
*/
g_return_val_if_fail (GIMP_IS_ITEM (current), NULL);
select_index = gimp_container_get_child_index (container, current) - 1;
if (select_index < 0)
{
GimpItem *parent = gimp_item_get_parent (GIMP_ITEM (current));
if (parent)
return GIMP_OBJECT (parent);
else
return current;
}
else
{
GimpObject *prev;
GimpContainer *prev_container;
prev = gimp_container_get_child_by_index (container, select_index);
while ((prev_container = gimp_viewable_get_children (GIMP_VIEWABLE (prev))) != NULL)
{
if (gimp_viewable_get_expanded (GIMP_VIEWABLE (prev)))
{
gint n_prev_children;
n_prev_children = gimp_container_get_n_children (prev_container);
if (n_prev_children > 0)
{
select_index = n_prev_children - 1;
container = prev_container;
prev = gimp_container_get_child_by_index (container, select_index);
continue;
}
}
break;
}
}
break;
case GIMP_ACTION_SELECT_FLAT_NEXT:
{
GimpContainer *current_container;
g_return_val_if_fail (GIMP_IS_ITEM (current), NULL);
if ((current_container = gimp_viewable_get_children (GIMP_VIEWABLE (current))) != NULL &&
gimp_viewable_get_expanded (GIMP_VIEWABLE (current)) &&
gimp_container_get_n_children (current_container) > 0)
{
select_index = 0;
container = current_container;
}
else
{
select_index = gimp_container_get_child_index (container, current) + 1;
if (select_index >= n_children)
{
while (TRUE)
{
GimpItem *parent;
GimpContainer *parent_container;
gint n_parent_children;
parent = gimp_item_get_parent (GIMP_ITEM (current));
if (parent == NULL)
break;
parent_container = gimp_item_get_container (parent);
n_parent_children = gimp_container_get_n_children (parent_container);
if (gimp_container_get_child_index (parent_container, GIMP_OBJECT (parent)) + 1 < n_parent_children)
{
container = parent_container;
select_index = gimp_container_get_child_index (parent_container, GIMP_OBJECT (parent)) + 1;
break;
}
current = GIMP_OBJECT (parent);
}
}
}
}
break;
default:
if ((gint) select_type >= 0)
select_index = (gint) select_type;
@ -737,6 +823,7 @@ action_select_object (GimpActionSelectType select_type,
break;
}
n_children = gimp_container_get_n_children (container);
select_index = CLAMP (select_index, 0, n_children - 1);
return gimp_container_get_child_by_index (container, select_index);

View File

@ -528,14 +528,30 @@ static const GimpEnumActionEntry layers_select_actions[] =
{ "layers-select-previous", NULL,
NC_("layers-action", "Select _Previous Layers"), NULL, { "Prior", NULL },
NC_("layers-action", "Select the layers above each currently selected layer"),
NC_("layers-action",
"Select the layers above each currently selected layer. "
"Layers will not be selected outside their current group level."),
GIMP_ACTION_SELECT_PREVIOUS, FALSE,
GIMP_HELP_LAYER_PREVIOUS },
{ "layers-select-next", NULL,
NC_("layers-action", "Select _Next Layers"), NULL, { "Next", NULL },
NC_("layers-action", "Select the layers below each currently selected layer"),
NC_("layers-action",
"Select the layers below each currently selected layer. "
"Layers will not be selected outside their current group level."),
GIMP_ACTION_SELECT_NEXT, FALSE,
GIMP_HELP_LAYER_NEXT },
{ "layers-select-flattened-previous", NULL,
NC_("layers-action", "Select Previous Layers (flattened view)"), NULL, { NULL },
NC_("layers-action", "Select the layers above each currently selected layer"),
GIMP_ACTION_SELECT_FLAT_PREVIOUS, FALSE,
GIMP_HELP_LAYER_PREVIOUS },
{ "layers-select-flattened-next", NULL,
NC_("layers-action", "Select Next Layers (flattened view)"), NULL, { NULL },
NC_("layers-action", "Select the layers below each currently selected layer"),
GIMP_ACTION_SELECT_FLAT_NEXT, FALSE,
GIMP_HELP_LAYER_NEXT }
};

View File

@ -203,10 +203,12 @@ gimp_container_tree_view_class_init (GimpContainerTreeViewClass *klass)
klass->drop_component = NULL;
klass->drop_pixbuf = NULL;
klass->move_cursor_up_action = NULL;
klass->move_cursor_down_action = NULL;
klass->move_cursor_start_action = NULL;
klass->move_cursor_end_action = NULL;
klass->move_cursor_up_action = NULL;
klass->move_cursor_down_action = NULL;
klass->move_cursor_up_flat_action = NULL;
klass->move_cursor_down_flat_action = NULL;
klass->move_cursor_start_action = NULL;
klass->move_cursor_end_action = NULL;
tree_view_signals[EDIT_NAME] =
g_signal_new ("edit-name",
@ -1300,10 +1302,22 @@ gimp_container_tree_view_real_move_cursor (GimpContainerTreeView *tree_view,
switch (step)
{
case GTK_MOVEMENT_DISPLAY_LINES:
if (count > 0)
{
if (klass->move_cursor_down_flat_action)
action_name = klass->move_cursor_down_flat_action;
else
action_name = klass->move_cursor_down_action;
}
else
{
if (klass->move_cursor_up_flat_action)
action_name = klass->move_cursor_up_flat_action;
else
action_name = klass->move_cursor_up_action;
}
break;
case GTK_MOVEMENT_PAGES:
/* TODO: PageUp|Down should likely have a different behaviour that
* up/down arrows.
*/
if (count > 0)
action_name = klass->move_cursor_down_action;
else

View File

@ -106,6 +106,8 @@ struct _GimpContainerTreeViewClass
const gchar * move_cursor_up_action;
const gchar * move_cursor_down_action;
const gchar * move_cursor_up_flat_action;
const gchar * move_cursor_down_flat_action;
const gchar * move_cursor_start_action;
const gchar * move_cursor_end_action;
};

View File

@ -208,10 +208,12 @@ gimp_layer_tree_view_class_init (GimpLayerTreeViewClass *klass)
tree_view_class->drop_component = gimp_layer_tree_view_drop_component;
tree_view_class->drop_pixbuf = gimp_layer_tree_view_drop_pixbuf;
tree_view_class->move_cursor_up_action = "layers-select-previous";
tree_view_class->move_cursor_down_action = "layers-select-next";
tree_view_class->move_cursor_start_action = "layers-select-top";
tree_view_class->move_cursor_end_action = "layers-select-bottom";
tree_view_class->move_cursor_up_action = "layers-select-previous";
tree_view_class->move_cursor_down_action = "layers-select-next";
tree_view_class->move_cursor_up_flat_action = "layers-select-flattened-previous";
tree_view_class->move_cursor_down_flat_action = "layers-select-flattened-next";
tree_view_class->move_cursor_start_action = "layers-select-top";
tree_view_class->move_cursor_end_action = "layers-select-bottom";
item_view_class->item_type = GIMP_TYPE_LAYER;
item_view_class->signal_name = "selected-layers-changed";