After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 343492 - arrow key navigation inside GtkIconView
arrow key navigation inside GtkIconView
Status: RESOLVED OBSOLETE
Product: gtk+
Classification: Platform
Component: Widget: GtkIconView
2.6.x
Other All
: Normal minor
: ---
Assigned To: gtk-bugs
gtk-bugs
: 607071 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2006-05-31 10:15 UTC by gang
Modified: 2018-02-10 03:29 UTC
See Also:
GNOME target: ---
GNOME version: 2.7/2.8


Attachments
the patch file (2.67 KB, patch)
2006-05-31 10:17 UTC, gang
none Details | Review
Cleaned up patch (2.34 KB, patch)
2007-05-27 21:48 UTC, Philip Withnall
needs-work Details | Review
Patch to implement column wrapping for any offset size (1.70 KB, patch)
2010-01-22 00:23 UTC, Jérôme
none Details | Review
Patch to implement column wrapping for any offset size, v2 (1.58 KB, patch)
2010-01-22 12:55 UTC, Jérôme
none Details | Review

Description gang 2006-05-31 10:15:05 UTC
1. When the focused item is the last item of a line and right is pressed, the focus will be moved to the first item of the line immediately below.
2. When the focused item is the first item of a line and left is pressed, the focus will be moved to the last item of the line immediately above.
3. When the focused item is on the last row and down is pressed, the focus will be moved to the widget below the GtkIconView.
4. When the focused item is on the first row and up is pressed, the focus will be moved to the widget above the GtkIconView.

Other information:
Comment 1 gang 2006-05-31 10:17:17 UTC
Created attachment 66517 [details] [review]
the patch file
Comment 2 Matthias Clasen 2006-12-31 03:58:17 UTC
We probably need some comparative analysis how similar widgets on other platforms behave keynav-wise. 
Comment 3 Claudio Saavedra 2007-01-16 13:47:00 UTC
Windows Explorer Icon View doesn't do any of these actions, and simply maintains the selection.
Comment 4 Matthias Clasen 2007-01-16 15:36:11 UTC
The arrow navigation in the icon view is very similar to the tree view. 
I think that is an advantage.
Comment 5 Björn Lindqvist 2007-02-05 00:56:10 UTC
(In reply to comment #3)
> Windows Explorer Icon View doesn't do any of these actions, and simply
> maintains the selection.

But it does have one little feature that I think would be useful. When you are on the last icon on the last row of the IconView, and when that icon is not a leftmost icon, and you press the right arrow key, then the leftmost icon of the previous line is focused. 

Also you can "jump diagonally" to the last item from the item one step above and to the right of it by pressing down.

Comment 6 gang 2007-02-25 09:45:45 UTC
this patch can enable the behaviours desired:

--- /data/zzz/gtk-2.6/gtk+-2.6.10/gtk/gtkiconview.c     2005-08-18 22:10:58.000000000 +0800
+++ gtk/gtkiconview.c   2006-08-30 17:29:15.797308964 +0800
@@ -2678,10 +2678,85 @@ find_item (GtkIconView     *icon_view,

   /* FIXME: this could be more efficient
    */
-  row = current->row + row_ofs;
-  col = current->col + col_ofs;
+  int columns;
+  if (icon_view->priv->columns > 0) //the column number was explicitly set by gtk_icon_view_set_columns()
+  {
+    if (g_list_length (icon_view->priv->items) >= icon_view->priv->columns)
+    {
+      columns = icon_view->priv->columns;
+    }
+    else
+    {
+      columns = g_list_length (icon_view->priv->items);
+    }
+  }
+  else
+    columns = (icon_view->priv->width - icon_view->priv->margin * 2 + icon_view->priv->column_spacing) / (icon_view->priv->column_spacing + current->width);

-  for (items = icon_view->priv->items; items; items = items->next)
+  int rows = g_list_length (icon_view->priv->items) / columns;
+  if (g_list_length (icon_view->priv->items) % columns > 0)
+    rows++;
+  items = g_list_last(icon_view->priv->items);
+  item = items->data;
+  if (col_ofs == 1) //right is pressed
+  {
+    if (current->col == item->col && current->row == (rows - 1)) //the current item is the last one, wrap to the first item
+    {
+      row = 0;
+      col = 0;
+    }
+    else if (current->col == (columns - 1)) //the current item is the rightmost one
+    {
+      row = current->row + row_ofs + 1;
+      col = 0;
+    }
+    else
+    {
+      row = current->row + row_ofs;
+      col = current->col + col_ofs;
+    }
+  }
+  else if (col_ofs == -1) //left is pressed
+  {
+    if (current->col == 0) //the current item is the leftmost one
+    {
+      if (current->row == 0) //the current item is the first one, wrap to the last item
+      {
+        row = rows - 1;
+        col = item->col;
+      }
+      else
+      {
+        row = current->row + row_ofs - 1;
+        col = columns - 1;
+      }
+    }
+    else
+    {
+      row = current->row + row_ofs;
+      col = current->col + col_ofs;
+    }
+  }
+  else if (row_ofs == 1) //down is pressed
+  {
+    if (current->row == (rows - 2) && item->col < current->col)// at the second last row
+    {
+      row = current->row + row_ofs;
+      col = 0;
+    }
+    else
+    {
+      row = current->row + row_ofs;
+      col = current->col + col_ofs;
+    }
+  }
+  else //up is pressed
+  {
+    row = current->row + row_ofs;
+    col = current->col + col_ofs;
+  }
+
+   for (items = icon_view->priv->items; items; items = items->next)
     {
       item = items->data;
       if (item->row == row && item->col == col)
@@ -2819,8 +2894,10 @@ gtk_icon_view_move_cursor_up_down (GtkIc
                      count, 0);
   if (!item)
+  {
+    gtk_widget_child_focus (gtk_widget_get_toplevel (GTK_WIDGET(icon_view)), count > 0 ? GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD);
     return;
-
+  }
   if (icon_view->priv->ctrl_pressed ||
       !icon_view->priv->shift_pressed ||
       !icon_view->priv->anchor_item ||
Comment 7 Philip Withnall 2007-05-27 21:48:52 UTC
Created attachment 88911 [details] [review]
Cleaned up patch

I've cleaned up the patch to adhere to the coding standards, and I've also removed the code to focus the widget below/above the iconview if you use the down/up arrow on the top or bottom rows (respectively), as I don't think this is intuitive --- people can use the tab key to do that, and arrow navigation should stay inside one widget.

I think this is a suitable candidate for inclusion into GTK+, and there's not much to lose by putting it in anyway.
Comment 8 gang 2007-06-19 09:43:18 UTC
Thanks, Philip!

But as to arrow navigation staying inside GtkIconView, I think on a mobile phone, a up/down press bringing the focus switch is quite handy and necessary since we don't have tab keys.

Comment 9 Johan (not receiving bugmail) Dahlin 2008-03-03 01:18:44 UTC
Comment on attachment 88911 [details] [review]
Cleaned up patch

>Index: gtk/gtkiconview.c

>   /* FIXME: this could be more efficient 
>    */
>-  row = current->row + row_ofs;
>-  col = current->col + col_ofs;
>+  int columns = (icon_view->priv->width - icon_view->priv->margin * 2 + icon_view->priv->column_spacing) / (icon_view->priv->column_spacing + current->width);
>+  int rows = g_list_length (icon_view->priv->items) / columns;

Declare the variables at the beginning of the function, next to the others.

Try to keep the width down, ideally below 79 characters.

>+  if (g_list_length (icon_view->priv->items) % columns > 0)	
>+    rows++;

g_list_length() is O(N), so it would be better if you could call it only once.

>+  items = g_list_last (icon_view->priv->items);
>+  item = items->data;  

>+          row = current->row + row_ofs;
>+          col = current->col + col_ofs;      

This is repeated 4 times, is that possible to avoid?

>+  else if (col_ofs == -1) /* Left pressed */

Put comments on the line before, not on the same line.
Comment 10 Paolo Bacchilega 2010-01-21 12:32:14 UTC
*** Bug 607071 has been marked as a duplicate of this bug. ***
Comment 11 Paolo Bacchilega 2010-01-21 12:37:34 UTC
(In reply to comment #2)
> We probably need some comparative analysis how similar widgets on other
> platforms behave keynav-wise.

the Nautilus icon view works this way, at least for the first two points described above.
Comment 12 Jérôme 2010-01-21 12:44:47 UTC
So does thunar icon view, for the first two points as well.

For the two latter, the tab key is probably best suited. The mobile phone issue could be treated in another bug if there is no obvious solution to it.
Comment 13 Jérôme 2010-01-21 23:05:48 UTC
As far as I understand, proposed patch (attachment 88911 [details] [review]) does more than points 1 and 2 described above.

/* The current item is the last one; wrap to the first item */

This is not what is described in the bug description. And I am not sure it is what we want here. If I keep the arrow key pressed, I expect the cursor to reach the last item, ultimately, not to loop forever. Besides it is not thunar's default behaviour, for instance.
Comment 14 Jérôme 2010-01-22 00:21:27 UTC
I might be mistaken, but function find_item() is designed to handle all kinds of offests, not only (1 row, 0 column) or (0 row, 1 column) ones. I feel weird about patching it to treat specifically the case we're dealing with here. I mean : shouldn't all offsets be wrapped around ?

As far as I understand, the original code just ignores an offset request that is out of bounds. (Like asking for an offset of (0 rows, 5 columns) when only 3 columns exist, for instance.)

While trying to clean the patch as per Comment 9, I did the modifications to handle all kinds of offsets. I'm attaching the patch.

It is meant to wrap around columns on any offset, and return first or last element if the result is out of bounds.

Please note that :
- if my understanding is correct, this patch modifies current behaviour on big offsets, which is out of the scope of this bug
- it is not tested, not even compiled (I don't have any setup here to do that, but I kinda which I had the time)
- it may contain stupid errors (it's getting late)
- I don't know the coding standards, nor do I know how to submit a proper patch...

Anyway, I'm not sure it is worth spending more time coding before agreeing on the design : what is the expected behaviour 
- as regards to 1 step offset wrapping as described in the bug description ?
- as regards to bigger offsets ?

Also, my proposition shouldn't be completely useless since at least I improved the calculation of the number of rows to make it more efficient, as requested by Johan Dalin in Comment 9. This could be imported in attachment 88911 [details] [review].
Comment 15 Jérôme 2010-01-22 00:23:12 UTC
Created attachment 151979 [details] [review]
Patch to implement column wrapping for any offset size
Comment 16 Jérôme 2010-01-22 08:36:28 UTC
Just realized what I did does something more, that was not written in the bug description. Here's an example :

1 2 3 4 
5 6 7 8
9

When 7 is selected and down arrow is pressed, current behaviour is "do nothing". If my code works as I expect it to, 9 will be selected, which I think is not that bad. I would say it's better, but unfortunately, it does not match thunar's behaviour...
Comment 17 Jérôme 2010-01-22 12:55:21 UTC
Created attachment 152008 [details] [review]
Patch to implement column wrapping for any offset size, v2

I checked in thunar, and in case of big row offset yielding a row beyond the last row (pressing page down on the row just before the last row) or before the first, the row is bounded to last or first but the column is kept, therefore, it is not the last of first element that is selected but the lower or upper element in the same column.

Example :

1 2 3 4 
5 6 7 8
9 a b c
d e f g

f is selected. I press page up, 7 is selected. I press page up again, 3 is selected, not 1.

I assume this is what we want to happen in GtkIconView as well.

I can't think of any use case involving a big column offset (like a "page right" key would do). There are two ways of dealing with such a case. We can either wrap around columns and move to next rows or stop at last column, just like we do with page down offsets. On the same example, assuming 5 is selected, a 2-step offset on the right would move to 7 and then either 9 (first way) or 8 (second way). Again, I don't know if this use case actually exists and I couldn't find any documentation on fonction find_item(), so I don't know what the caller expects from it.

I assumed we want it first way, which is wrapping around columns.

This leads me to a new version of my former patch, which is actually even simpler.
Comment 18 Jérôme 2010-03-29 13:28:20 UTC
This bug has been opened almost 4 years ago. It does not seem to be actively treated. I'd like to push it but I don't know what to do about it.

Is it a matter of requirement ? Don't we agree on the behaviour to expect from GtkIconView ?

Or is it a matter of coding/testing, therefore a matter of time (and skills) ?
Comment 19 Matthias Clasen 2018-02-10 03:29:38 UTC
We're moving to gitlab! As part of this move, we are closing bugs that haven't seen activity in more than 5 years. If this issue is still imporant to you and
still relevant with GTK+ 3.22 or master, please consider creating a gitlab issue
for it.