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

On Sep 23, 2010, at 10:56 AM, Tristan Van Berkom wrote:
> So to help stay on track without straying too too much, these
> are (my perceived) reasons for the said refactoring work:
>  - Code sharing: A good refactoring of cell layouting logic 
>    into some classes that can be (more) easily reused by the 
>    major candidates GtkTreeView, GtkIconView and GtkComboBox[Menu]. 
>  - Adaptation for height-for-width support (currently only
>    the GtkComboBox uses hfw'ness of cell renderers, big patch
>    pending on treeviews could be better written based on the
>    refactored code).
>  - Alignment of GtkComboBox menu renderers currently cant be
>    done as described in bug 629133.
>  - While we're on the topic of refactoring the cell layouting
>    code, I'd personally like to open up new avenues for rendering
>    cell layouts in more dynamic ways (as I'll describe in more 
>    detail below); Rationale for this is if we're going to give this
>    a go at all, we better be ambitious and awesome about it.

Layouting cells in more dynamic ways is one reason; for me another big reason is to also make column/row layouting (thus the layouting of cell layouts ;) more flexible.  Think of:

 - Making it easier to create widgets such as icon view, Windows-style columnary list view, etc.  Basically, you only want to write the algorithm laying out the rows and re-use the algorithms that layout cells.

 - For list and tree views, make row and column spanning possible.

 - Proper implementations of separator rows, group headings or other custom content.  (More on that below).

 - Possibly embedding non-cell content in list/tree views, such as custom widgets.  Most notably, for example a button (see mobile platforms).

> GtkCellArea
> -----------
>   A GtkCellArea would be an abstract class which implements 
> GtkCellLayout and acts as a collection of cells which are rendered 
> in a completely undefined way, GtkCellArea classes would be responsible 
> for handling all geometric tasks in the laying out of cells:
>  - Allocation of cell positions inside the area 
>  - Returning overall bounderies that the cells take up inside an
>    area as well as returning the bountries of a single cell inside
>    the area.
>    This is important for widgets like TreeView and IconView
>    who want to draw focus around a cell, a column or an entire row.
>  - Returning the cell at a specified coordinate inside the area for
>    a given treemodel row.
>    This is needed for the sake of handling mouse-clicks so that the 
>    owner of the CellArea can go on to start editing a given cell, or
>    activate an icon in a given cell.
>  - Responding to height-for-width/width-for-height apis for a 
>    collection of cells for a given treemodel row.
>  - Actually render the GtkCellArea for a given row into a given 
>    space/GdkRectangle.
> Conceptually, the GtkCellArea is for a cell renderer what a 
> GtkContainer is for a GtkWidget. The main bonus of keeping the 
> GtkCellArea as an abstract class and responding to some generalized 
> apis is it opens up avenues for more complex implementations such as 
> a tabular CellArea, or a cell-wrapping CellArea which could be more 
> easily implemented in the future.

At first, I thought this would be an entity for rendering one "row", so one set of cells (basically, what cell view does currently).  But I think you mean to have GtkCellArea manage multiple rows?  I leave whether or not GtkCellArea should manage one or more rows in the middle below.

An "object" that handles cell layout for a single row is what I kind of ended up with in a previous refactoring.  This was not really an object, as it was a set of internal functions.  What I did was refactoring the cell layouting code in gtktreeviewcolumn.c into a manageable set of functions that implemented an iteratable interface over a list of cells.  Turning something like this into a stand-alone class (and enable subclassing) sounds like a good idea to me.

One of my original ideas was to introduce the concept of a "row renderer".  This would be an abstract class with several subclasses.  One row renderer subclass for rendering a row consisting out of cell renderers, re-using the original cell layouting code.  Other "row renderers" for embedding widgets, separators, group headings, etc.  Layouting row renderers would then give you your full-featured tree view, icon view, etc.  (Though combining an icon view and a group heading row renderer would mean combining tabular and "list" layout -- another puzzle to solve but an interesting feature).

To go back to the proposed GtkCellArea:

 - I am not yet sure if this should be tied to GtkTreeModel.  The main consideration is if you want to use GtkCellArea without a GtkTreeModel.  Though it seems cumbersome to provide some other means to populate the properties of the cell renderers in this case ...

  Another consideration is whether GtkCellArea will manage one or multiple rows.  If only one, then you might want to have another object set the data on the cell renderers (the data is "pushed" by another object).  If multiple, then directly accessing the model seems a better fit (GtkCellArea "pulls" the data by itself).

 - GtkCellArea (or a subclass) might also have to implement the custom "event-handling" and focus drawing code that is currently in GtkTreeViewColumn.

> The CellAlignment helps in general to optimize the overall size requests
> of treeview rows, however where performance is not an issue; the use of
> CellAlignment by the GtkCellAreaBox can be optional, in this way 
> allowing cell renderers to "flow naturally" across a GtkTreeView column

Yes, such natural flowing of cell renderers in a column should definitely be supported.

> GtkCellAreaManager
> ------------------
>   This would essentially be a cleaned up API and refactored version of
> the current GtkRBTree. The rbtree currently caches information about how
> a GtkTreeView is currently rendering a given model, it caches things
> such as which rows are expanded; the indentation level used by the
> treeview and most notably the variable height of rows.
> Some things that would change in the GtkCellAreaManager would be:
>  - Rip out GtkTreeView specific information such as expanded rows
>    and indentation.
>  - Add a client data pointer to be defined by the user which describes
>    what kind of data is cached in a row (all the treeview specific
>    row cached stuff comes back here)

I assume that such a pointer will be placed in GtkRBNode.  You mention the expanded rows and indentation as tree view specific stuff above.  Note that this data is not stored in the GtkRBNode fields.  Expanded rows are deduced from the RBTree structure, simply because collapsed rows are not present in the RBTree.  Indentation is calculated based on row depth (which is in turn taken from the RBTree structure again).  What is stored in the GtkRBNode, is the state of the expand/collapse animation (the expander animation).

What has been requested as feature in the past is to save the selection and expansion state of rows that are being collapsed.  For example, if you collapse a row and then expand it again, the selection will appear as it was before you collapsed the row.  The same for expansion state of child rows.  If we were to provide such a feature, RBTree would need to see changes.

>  - Provide a configurable iterative process for updating the cache,
>    this would be performed synchronously for all the visible rows and
>    then fall off into the background only updating a configurable
>    ~1000 rows at at time and then marking them "validated" for access.

This would basically be moving out as much of GtkTreeView's validation code as possible into this class.

> How does this all map to current GtkCellLayout implementations ?
> Most of the above text referrs to GtkTreeView, being the most
> complex configuration making use of these classes.

Whereas the RBTree works very well for lists and trees, are we sure that this will work nicely and performant for tabular layouts as well?  Or would a different data structure be a better choice?

If it is useful to re-use RBTree in several widgets, then we should likely do it in a similar way as you proposed with GtkCellAreaManager.  However, more study might be required as RBTree is quite a central element of the tree view.  Because it is so central, we should likely also take performance into account.

Have you given any thought to selection handling?  GtkTreeSelection is now only used by GtkTreeView, you would also want to generalize that.  Currently, selection state is stored in GtkRBTree, so GtkTreeSelection and GtkRBTree are again intertwined with each other.  Perhaps GtkCellAreaManager is also a good choice for placing the selection handling code, possibly made extensible/adaptable through a delegate object?

> Conclusion: There is a plethora of requirements relating to
> GtkTreeView in general, some of which I'm sure to have missed,
> some of which will surely present themselves as road-blocks
> while implementing the said refactoring.

It's a huge task, which I think is (unfortunately) impossible to get done before 3.0.  If we do something like this, I think  we also have to decide on some kind of compatibility with current GtkTreeView. Getting there throughout the 3.x releases would be cool though.

I will try to look for my notes on tree view refactoring which I wrote a long time ago and see if there were more ideas that could fit in nicely with what has been proposed so far.  While pencil and paper is great for brainstorming, paper has a tendency to get lost :)



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