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



On Mon, 2010-11-01 at 15:15 +0900, Tristan Van Berkom wrote:
> 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);
> 

Gah, I just realized that these apis also have to depend on the
currently set row-data, since the same cell can be editable
in one row but not editable in the next (or even visible for
that matter).

Need to put a bit more thought into this... I'll come up with
something further thought out soon.

> -----------------------------------------------------------------
> 
> 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
> 
> 
> _______________________________________________
> 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]