GNOME Bugzilla – Bug 586458
Allow prelighting of a separate cell on hover
Last modified: 2018-02-10 03:21:41 UTC
This is the GTK part of bug "584846: "Eject/Unmount icon in Nautilus sidebar should have hover and click states". Now that we sometimes use GtkCellRendererPixbuf's as clickable icons, we need a way to give the usual feedback to the user, i.e. color changes on hover and click. From the comment I've posted there: I've tried to implement this some time ago, and the prelight-on-hover part is really tricky to get with the current design of GtkTreeView. We already have an option to highlight a renderer when the mouse pointer enters the row, but the tree view has no real concept of an independent button that would be a renderer (a cell, as opposed to a whole row). Signals about the pointer entering an area only get transmitted by the tree view on a row basis. Thus, you cannot know from the renderer POV when the mouse has entered your cell, only when it has entered your row. Clicks are transmitted to cell renderers because some computation of coordinates takes place when such an event occurs; this behavior should be replicated every time the pointer moves. What do maintainers think?
The joys of misusing the treeview in new ways... Your best bet is probably to look how prelighting is handled for expander arrows, and see if that can be generalized for cells in general.
Seems like this would also be useful to allow GtkCellRenderToggles to have a prelight state, just like normal check buttons and radio buttons do.
See do_prelight() in gtktreeview.c. GtkTreeView sets GTK_RBNODE_IS_PRELIT when a node (row) has the pointer on it, and this gets translated to GTK_CELL_RENDERER_PRELIT in gtk_tree_view_bin_expose(), which is the most scary function of the file. Once GtkTreeViewColumns are passed the GTK_CELL_RENDERER_PRELIT flag, they send it directly to their GtkCellRenderers. So the fix should go into the hardest part: GtkTreeView. The idea of prelighting of whole row should be changed to allow prelighting only a cell. do_prelight() already detects whether the pointer is over the arrow (expander) of the row, to prelight it separately. So it should also check what cell has the pointer, and set a different property that is passed to the rendering function. And in case a new GtkTreeView (e.g. 'cell-prelight') is set, GTK_RBNODE_IS_PRELIT would be ignored, only the corresponding cell/column would get GTK_CELL_RENDERER_PRELIT. So nice! ;-)
On a first thought, having a new kind of property on GtkTreeView as is proposed in comment 3, seems to make the most sense. The actual name of the property is still up for discussion. The implementation of this property should actually be quite trivial. I would leave setting/unsetting GTK_RBNODE_IS_PRELIT intact. The only thing that needs changing is propagating the GTK_RBNODE_IS_PRELIT setting to GTK_CELL_RENDERER_PRELIT on the cell renderers. This should then no longer be set on all cell renderers, but only on the one that has focus. I agree that this has a use for GtkCellRendererToggle as well, like mentioned in comment 2. However, I think an additional complication comes into play here. If you look at the actual GtkCheckButton (and related widgets): [x] This is a label Then both the check and the label are highlighted. Do we want to have the same behavior in GtkTreeView? If yes, then we will need a way to relate two (or more) cells to each other. It might be possible to re-use the keynav code for this, but that code has its limitations as well and does not work cross-column (unless there's only a single editable cell per row). The keynav code might actually benefit from such "cell relations" as well I think.
(In reply to comment #4) > On a first thought, having a new kind of property on GtkTreeView as is proposed > in comment 3, seems to make the most sense. The actual name of the property is > still up for discussion. The implementation of this property should actually > be quite trivial. I would leave setting/unsetting GTK_RBNODE_IS_PRELIT intact. > The only thing that needs changing is propagating the GTK_RBNODE_IS_PRELIT > setting to GTK_CELL_RENDERER_PRELIT on the cell renderers. This should then no > longer be set on all cell renderers, but only on the one that has focus. Actually, we have (re)started investigating this with Marcus Carlson yesterday, and this is the kind of solution we have. To be more precise, the current way of doings things is: - tree view checks where cursor is - if it notices cursor is on a given row, it marks the node with the GTK_RBNODE_IS_PRELIT flag - the GTK_CELL_RENDERER_PRELIT flag is passed on next rendering to all columns, so that they each prelight the cell on the corresponding row So our idea for now is to have a field in GtkTreeViewPrivate indicating with row the cursor is on. When our new property is TRUE, we would only pass GTK_CELL_RENDERER_PRELIT to the column that has the cursor. > I agree that this has a use for GtkCellRendererToggle as well, like mentioned > in comment 2. However, I think an additional complication comes into play > here. If you look at the actual GtkCheckButton (and related widgets): > > [x] This is a label > > Then both the check and the label are highlighted. Do we want to have the same > behavior in GtkTreeView? If yes, then we will need a way to relate two (or > more) cells to each other. It might be possible to re-use the keynav code for > this, but that code has its limitations as well and does not work cross-column > (unless there's only a single editable cell per row). The keynav code might > actually benefit from such "cell relations" as well I think. If there only are two columns in the tree view, then this is already possible setting the 'follow-state' property on the cell renderers. If not, I can't find what prevents you from packing two cell renderers in the same column, in which case with our solution they would both get prelit. Am I wrong?
(In reply to comment #5) > So our idea for now is to have a field in GtkTreeViewPrivate indicating with > row the cursor is on. When our new property is TRUE, we would only pass > GTK_CELL_RENDERER_PRELIT to the column that has the cursor. I meant "indicating which *COLUMN* the cursor is on", of course... ;-)
Created attachment 163592 [details] [review] [GtkTreeView] Allow per-cell prelighting Util now, prelighting was only possible for a whole row: do_prelight() was detecting what node the pointer was in, and gtk_tree_view_bin_expose() was passing to all columns the GTK_CELL_RENDERER_PRELIT flag on the corresponding renderers. Add a new 'cell-prelight' property that allows prelighting only the cell on the column where the pointer is. We detect this column in do_prelight(), and store it as a new member of GtkTreePrivate. It's then used in gtk_tree_view_bin_expose() to only set the flag on renderers of this column. Update tests/testtreeview so that the tree view uses this behavior, and have a cell render colorize in response to prelighting to test it. Note it's not visible with default GTK theme.
So here's the result of Marcus's work on this. It works fine and seems to be a simple solution, fitting well in the general model of the tree view. For some reason the default theme doesn't colorize pixbufs (even if the code seems to do this), so you have to install gtk-engines for your development version, and use something like: GTK2_RC_FILES=/opt/gnome/share/themes/Clearlooks/gtk-3.0/gtkrc tests/testtreeview But I'm sure you know this better than I do. ;-) Feedback wanted! Two points of discussion are: - I think this could be a nice default for 3.0, since I've yet to see a program using the old behavior of prelighting a whole row. Not a big deal in any sense, though. - I've removed direct accessors to set the function since this property is rarely used. And Marcus, I've changed guint cell_prelight : 1; to gboolean cell_prelight : 1; I think that was just a typo, but... BTW, I need a better e-mail address for the Author field...
guint is right there, since gboolean is signed and not what you want in a bitfield.
Created attachment 163664 [details] [review] Updated patch It seems sometimes one should check before assuming others are mistaken... :-p New patch brings back the guint. Comments on the core idea?
Since I saw this come up on the mailing list... and since these bug reports are just just old enough to predate GtkCellArea... better just leave a comment. I did not look over the patch in detail but saw that it adds a saved 'prelight column' and 'prelight cell'. General idea of how to implement this in 3.0 is: o GtkCellArea now handles 'events' in an abstract way, it's important that all the correct motion events are sent by the treeview to the GtkCellArea for the cell area to generate the enter/leave events properly (or just maintain a proper 'prelight' cellrenderer state). o Look at how GtkCellArea handles focus, as the cell area handles focus by listening to keyboard events, the GtkCellArea should also probably be responsable for driving the 'prelight cell' by handling the motion events o When rendering cells, the GtkCellArea adds the pseudo class for focused cells, it should also do so for the prelight cell. Now this following part I'm not 100% sure about, but... if the GtkTreeView already handles the prelight row that's great... the GtkTreeView still needs to remember the prelight row (as it does remember the focus row) so that the GtkCellArea can be told that it should be rendering the prelight row (this is done iirc by passing a flag through the GtkCellRendererState in gtk_cell_area_render()).
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.