Re: GtkTreeView Refactoring Considerations [was Re: Private types inside GTK+]



On Mon, 2010-11-01 at 12:15 +0900, Tristan Van Berkom wrote:
> On Sun, 2010-10-31 at 17:45 +0100, Kristian Rietveld wrote:
> > On Sun, Oct 31, 2010 at 3:17 PM, Tristan Van Berkom
> > <tristanvb openismus com> wrote:
> > > Whew, ok I implemented GtkCellArea->render for GtkCellAreaBox for the
> > > most part, however I'm still missing the GtkCellRendererState flags ;-)
> > >
> > > So for this part I was thinking it might make more sense to create
> > > a new GtkCellAreaStateFlags type with just per-row states (and add that
> > > as an argument to GtkCellArea->render() and also GtkCellArea->event())
> > 
> > Most of the states in GtkCellRendererState are actually per-row states
> > already (selected, focused, etc.) and are toggled by GtkTreeView and
> > GtkTreeViewColumn when rendering the cells.  Though one state,
> > "sorted", is obviously per-column.  Did you mean to have a new
> > GtkCellAreaStateFlags that will have flags per *cell area* and thus
> > per *column*?
> 
> Ah no I meant per row, I was just seeing how treeviewcolumn does
> some hackery around the FOCUS flag (i.e. when treeview column
> receives the focus flag at render time, it immediately unflags
> that and then re-applies the FOCUS bit to the renderer flags
> for actual renderers it decided were to be passed the focus
> flag).
> 
> I suppose that the "sorted" flag also spans the whole column
> and not a single cell... since a column can be composed of
> one cell area (or even potentially more than one, but lets just 
> consider one area per column)... I suppose that all of the flags 
> defined by GtkCellAreaStateFlags are interesting to pass along 
> to the cell area at render/event time.
> 
> > 
> > > and then somehow tidy up the code that in GtkTreeViewColumn is
> > > currently:
> > >
> > >  _gtk_tree_view_column_count_special_cells (tree_column)
> > 
> > This function is part of implementing the key navigation behavior.  A
> > "special" cell is one that is editable or activatable.  The rule is
> > that if there's a single special cell in a column, a focus rectangle
> > is drawn spanning all cells in that column.  If there is more than one
> > than the focus rectangle will be drawn around single cells.  This
> > works fine in many cases, but can of course be awkward in a few
> > situations, so perhaps we want to make this configurable in the
> > future.  The same likely holds for a situation where you have a check
> > box cell renderer and text cell renderer next to each other in a
> > column:
> > 
> >    [x] [my label in a text renderer]
> > 
> > Akin to a GtkCheckButton, you would want the check to toggle when the
> > text renderer is clicked.  And it would be natural if the focus
> > rectangle spans the check box and the text renderer. But in other
> > situations, with different cell renderers, you do not want this.  This
> > is also something to think about and improve for the future.
> > 
> 
> Ah ok this clarifies things... I suppose if cell is activatable
> or editable then it CAN_FOCUS :)
> 
> I'll look into this ... I guess the treeview itself will have
> to (and already does) I'll look into how cell areas can handle
> their own internal focus chaining... probably they have to 
> notify the caller (treeview/column) that focus should be passed 
> to a leading or following column (or cell area), track the
> currently focused cell etc.

Ok I've ironed out some API for focus handling in the cell area.

However there's one problem which I was still unable to come
up with a solution for, it's kindof corner case and admittedly
it wont be an issue for the initial refactor but for perfectionism's
sake would be really nice to get right.

First I'll present the api I've come up with so far:


/* Grab focus comes with a "direction" parameter to tell
 * the area "from where" the focus is coming from, 
 * the ->grab_focus() vfunc should be implemented by
 * subclasses so that they can set focus on the appropriate
 * cell (top/bottom/left or right cell depending on the
 * cell areas type of layout and "direction" were moving
 * focus from).
 */
void gtk_cell_area_grab_focus (GtkCellArea        *area,
			       GtkDirectionType    direction);

/* This fires a signal on the GtkCellArea telling the owning
 * layout widget that focus should leave the cell for the
 * row indicated by "path", and that it should leave in the
 * indicated "direction".
 *
 * GtkCellLayout implementations should fire this signal when
 * handling key events for a given row, when there are no more
 * focusable cells and a keystroke would indicate a focus change.
 *
 * Then parent cell layouting widgets can trap this signal and move
 * focus along to another adjacent area... or to the same area and
 * move the cursor_row to the next treerow.
 */
void gtk_cell_area_focus_leave (GtkCellArea        *area,
				GtkDirectionType    direction,
				gchar              *path);



/* set_can_focus() should be set by implementing classes such as
 * GtkCellAreaBox while renderers are added/removed.
 */
void     gtk_cell_area_set_can_focus (GtkCellArea        *area,
				      gboolean            can_focus);

/* This can be consulted by cell layouting widgets to see if it's
 * appropriate to call grab_focus() for this area or not.
 */
gboolean gtk_cell_area_get_can_focus (GtkCellArea        *area);

/* Set/Get focus cell is mostly an internal thing, the focused cell
 * is set by a subclass like GtkCellAreaBox while it handles key
 * events that move the focus
 */
void             gtk_cell_area_set_focus_cell (GtkCellArea   *area,
				             GtkCellRenderer *renderer);

/* Get the focused cell can be accessed by the superclass GtkCellArea
 * to activate/start-editing cells that have focus when processing
 * a key event that indicates activate/start-editing (i.e. ENTER key).
 */
GtkCellRenderer *gtk_cell_area_get_focus_cell (GtkCellArea   *area);

-----------------------------------------------------------------

Now, the interesting problem lies in the grab_focus()/focus_leave()
semantics... I'm thinking tabular cell layouts here... imagine two
possible GtkCellAreaTable's placed side by side and rendered for 
multiple rows in a treeview:

Area A                                    Area B
+------------+--------------------------+ +------------------------+
| 1 [A Single| 2[ Some editable text ]  | |1[ Toggle | static text]|
| activatable| 3[ More editable text ]  | |2[ Editable text       ]|
| Icon]      | 4[ Toggle | static text ]| |3[ Editable text       ]|
+------------+--------------------------+ +------------------------+
(consider the activatable icon in area A as cell "A1", the toggle
with static text in area B is a single focusable area... I'll refer 
to that as "B1")

The problem here is that when transitioning focus from one area to
another we would need some more, possibly geometric context to do
it properly.

So in the above picture, consider that for "Area A", if cell A1 or 
A2 has focus and we hit the UP arrow key... it will generate
a GtkCellArea::focus-leave signal with the direction GTK_DIR_UP.

Then logically the treeview(or column) would move the cursor
row to the preceding visible row and call:

  gtk_cell_area_grab_focus(Area A, GTK_DIR_UP);

The GtkCellArea "Area A" would then have to decide whether
to give focus to A1, or to A4.

The desirable thing would be to transition from:
  A1 --> A1
  A2 --> A4

The same problem presents itself when we have a
"focus-leave" signal generated for GTK_DIR_RIGHT,

We would want to make the transitions:
  A2 --> B1
  A3 --> B2
  A4 --> B3

Well... as I've already said I havent figured out a
solution for this... I'm all ears.

Other than that I think it will be simple enough
to draw focus around "some but not all" cells
in a single cell area.

For instance if you have an area such as the area B above:
+------------------------+
|1[ Toggle | static text]|
|2[ Editable text       ]|
|3[ Editable text       ]|
+------------------------+

One would want to paint focus around the toggle renderer
and the static text beside it, even it there are other
focusable cells in the same GtkCellArea... this could
be achieved easily enough by adding some semantics
to set some "focus siblings" (I.e. above "static text"
becomes a "focus sibling" of "Toggle").

Cheers,
         -Tristan

> 
> 
> > I think the GtkCellArea will also allow us to get rid of
> > _gtk_tree_view_column_get_cell_at_pos(), which I have never really
> > liked for some reason.
> > 
> > 
> > > For focus handling and such I guess it will probably make sense to add:
> > >
> > >  GtkCellArea->set/get_focus_cell()
> > 
> > That could work if there is the possibility to set focus around all
> > cells in the GtkCellArea as well and to disable focus for a given row
> > (if there are no "special" cells in a row, then a focus rectangle is
> > drawn around the entire row).
> 
> Right, I think that the "focused cell" only needs to be called once
> and is a global state for all rows, however at ->render() and ->event()
> time the focus handling is ignored for 'flags' that dont contain
> the FOCUS bit.
> 
> The cell area itself should be smart enough to flag all the appropriate 
> cells with the FOCUS bit when rendering for a row (in other words things
> dont really change too much from how treeview column processes this,
> only that we have some added focus handling).
> 
> > > Which is currently missing... then I suppose from ->event() if the row
> > > for which an event is handled itself has focus, it will make sense to
> > > activate the focused cell.
> > 
> > I would follow the way GtkTreeViewColumn is currently handling this
> > for now.  Because when clicking on a check box renderer on a row that
> > does not have focus (and focus in tree view only really plays when you
> > are using key navigation), the click should likely activate the check
> > box renderer anyway.
> 
> Ah yes I was not so clear, I meant specifically for handling key
> events... the base GtkCellAreaClass would be responsible for
> activating a focused cell if present, when processing the ENTER 
> key on a focused row... if the base class did not do anything;
> the subclass GtkCellAreaBox will go ahead and process mouse events,
> thus activating the right renderer directly (as well as giving the
> appropriate cell "focus").
> 
> Thanks a lot for your insights and help !
> 
> Cheers,
>       -Tristan
> 
> 
> _______________________________________________
> gtk-devel-list mailing list
> gtk-devel-list gnome org
> http://mail.gnome.org/mailman/listinfo/gtk-devel-list




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]