利用者:Julianeisel/Outliner Refactor

提供: wiki
移動先: 案内検索

Outliner Refactor

Why Refactor it?

Current outliner code has many issues: it's confusing to work in it, not easy to add new features, hard to understand, performance is neglected, ... It doesn't really follow any deeper design idea.

Not all of the outliner code needs to be rewritten though. Some parts are rather isolated and work just like everywhere else in Blender. Namely outliner operators, its editor type registration (space_outliner.c), the hash-based storage of permanent data (outliner_treehash.c) and some of the more recently added code. Also, quite some outliner data is also written to .blend files. It's important to keep that compatible.

So, instead of doing a full-blown rewrite, it should be enough to refactor quite a big part of it.

Managing Tree-Elements

There are many different types of elements to show in the outliner: objects, collections, scenes, RNA-properties, ... Yet, current code design doesn't support this versatility nicely. Instead of having any type-generic interface, it's bloated with long functions with if and else madness.

We can achieve greater type genericness with C-style polymorphism. We already do this in multiple places in Blender, for example for editors, operators, manipulators and nodes.

There would be something like a generic TreeElementType struct storing a set of callbacks that can be set for type specific behavior.

typedef struct TreeElementType {
    eTreeElementTypeID type; /* should match TreeStoreElem.type */

    /* Add elements of this type and their sub-trees */
    void (*build)(...);
    /* Define the buttons to draw in the name field of the table. */
    void (*draw_name)(...);
    ...
} TreeElementType;

Drawing the Tree

The current drawing of the outliner tree is written specifically for the outliner. It is basically a recursively generated table. It would make a lot of sense to have a generic API for creating, managing and drawing tables though. So the outliner refactor could be used to write this generic table API. For now, we call it uiTableView API.

Once the widget code eventually supports hierarchical lists of widgets, the uiTableView could become an own widget.

It is actually possible, that the uiTableView design makes the TreeElement struct redundant.

Generic Context Menu

The way we generate the context menu (right-click menu) right now is quite messy. Each tree element type defines its own operator to display a list of operations. The if/else madness is strong in this one.

The uiTableView API could allow registering a callback for each tree element type, which would return a list of "actions" and UI names for them. That info would be enough for the API to generate the context menu.

Adding the actions to show in the context menu would look something like this:

static uiTableItemActions element_type_object_actions_add_cb(void)
{
    uiTableItemActions actions; /* probably just linked list alias */
    UI_tableview_item_action_append(actions, object_select_cb, "Select");
    UI_tableview_item_action_append(actions, object_select_hierarchy_cb, "Select Hierarchy");
    UI_tableview_item_action_append(actions, object_delete_hierarchy_cb, "Delete Hierarchy");
    ...
}

Maybe it's better to use operators for this. Seems a bit too much to add operators for each of these actions though.

File Structure

Since above suggestions make the code more object oriented, it makes sense to make the file structure represent that. Each tree element type would have its own file. That makes it really easy to find code for a specific type. General code like utilities, managing storage, etc. can stay in regular files.

The structure would look something like this:

outliner_utils.c
outliner_view.c
space_outliner.c
treeelement_collection.c
treeelement_object.c
treeelement_view_layer.c

...