diff options
author | Siddhartha Jejurkar <f20180617@goa.bits-pilani.ac.in> | 2021-12-17 16:01:32 +0300 |
---|---|---|
committer | Siddhartha Jejurkar <f20180617@goa.bits-pilani.ac.in> | 2021-12-17 16:01:32 +0300 |
commit | dbc41b30f88b96f7d8c6e995b17f5930eb55cc77 (patch) | |
tree | c6c495328443ea3621e5df2ef483b0e0dd504496 /source/blender/editors/include/UI_tree_view.hh | |
parent | 99a2af76d10e05a18987be5d554ada197b1ca086 (diff) | |
parent | 7c9e4099854a4fc8eab4db97173c1aacd25f9e08 (diff) |
Merge branch 'master' into soc-2021-uv-edge-select-supportsoc-2021-uv-edge-select-support
Diffstat (limited to 'source/blender/editors/include/UI_tree_view.hh')
-rw-r--r-- | source/blender/editors/include/UI_tree_view.hh | 195 |
1 files changed, 107 insertions, 88 deletions
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 0d18eedeac9..8208f8daf5d 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -17,8 +17,8 @@ /** \file * \ingroup editorui * - * API for simple creation of tree UIs supporting advanced features. - * https://wiki.blender.org/wiki/Source/Interface/Views + * API for simple creation of tree UIs supporting typically needed features. + * https://wiki.blender.org/wiki/Source/Interface/Views/Tree_Views */ #pragma once @@ -36,7 +36,6 @@ #include "UI_resources.h" struct bContext; -struct PointerRNA; struct uiBlock; struct uiBut; struct uiButTreeRow; @@ -53,14 +52,17 @@ class AbstractTreeViewItemDragController; /* ---------------------------------------------------------------------- */ /** \name Tree-View Item Container + * + * Base class for tree-view and tree-view items, so both can contain children. * \{ */ /** - * Helper base class to expose common child-item data and functionality to both #AbstractTreeView - * and #AbstractTreeViewItem. + * Both the tree-view (as the root of the tree) and the items can have children. This is the base + * class for both, to store and manage child items. Children are owned by their parent container + * (tree-view or item). * - * That means this type can be used whenever either a #AbstractTreeView or a - * #AbstractTreeViewItem is needed. + * That means this type can be used whenever either an #AbstractTreeView or an + * #AbstractTreeViewItem is needed, but the #TreeViewOrItem alias is a better name to use then. */ class TreeViewItemContainer { friend class AbstractTreeView; @@ -112,37 +114,10 @@ class TreeViewItemContainer { ENUM_OPERATORS(TreeViewItemContainer::IterOptions, TreeViewItemContainer::IterOptions::SkipCollapsed); -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Tree-View Builders - * \{ */ - -class TreeViewBuilder { - uiBlock &block_; - - public: - TreeViewBuilder(uiBlock &block); - - void build_tree_view(AbstractTreeView &tree_view); -}; - -class TreeViewLayoutBuilder { - uiBlock &block_; - - friend TreeViewBuilder; - - public: - void build_row(AbstractTreeViewItem &item) const; - uiBlock &block() const; - uiLayout *current_layout() const; - - private: - /* Created through #TreeViewBuilder. */ - TreeViewLayoutBuilder(uiBlock &block); - - static void polish_layout(const uiBlock &block); -}; +/** The container class is the base for both the tree-view and the items. This alias gives it a + * clearer name for handles that accept both. Use whenever something wants to act on child-items, + * irrespective of if they are stored at root level or as children of some other item. */ +using TreeViewOrItem = TreeViewItemContainer; /** \} */ @@ -151,8 +126,8 @@ class TreeViewLayoutBuilder { * \{ */ class AbstractTreeView : public TreeViewItemContainer { - friend AbstractTreeViewItem; - friend TreeViewBuilder; + friend class AbstractTreeViewItem; + friend class TreeViewBuilder; /** * Only one item can be renamed at a time. So the tree is informed about the renaming state to @@ -169,15 +144,16 @@ class AbstractTreeView : public TreeViewItemContainer { /** Only one item can be renamed at a time. */ bool is_renaming() const; + + protected: + virtual void build_tree() = 0; + /** * Check if the tree is fully (re-)constructed. That means, both #build_tree() and * #update_from_old() have finished. */ bool is_reconstructed() const; - protected: - virtual void build_tree() = 0; - private: /** * Match the tree-view against an earlier version of itself (if any) and copy the old UI state @@ -185,10 +161,10 @@ class AbstractTreeView : public TreeViewItemContainer { * #AbstractTreeViewItem.update_from_old(). */ void update_from_old(uiBlock &new_block); - static void update_children_from_old_recursive(const TreeViewItemContainer &new_items, - const TreeViewItemContainer &old_items); + static void update_children_from_old_recursive(const TreeViewOrItem &new_items, + const TreeViewOrItem &old_items); static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item, - const TreeViewItemContainer &items); + const TreeViewOrItem &items); /** * Items may want to do additional work when state changes. But these state changes can only be @@ -196,7 +172,6 @@ class AbstractTreeView : public TreeViewItemContainer { * the actual state changes are done in a delayed manner through this function. */ void change_state_delayed(); - void build_layout_from_tree(const TreeViewLayoutBuilder &builder); }; /** \} */ @@ -215,21 +190,18 @@ class AbstractTreeView : public TreeViewItemContainer { class AbstractTreeViewItem : public TreeViewItemContainer { friend class AbstractTreeView; friend class TreeViewLayoutBuilder; - - public: - using IsActiveFn = std::function<bool()>; + /* Higher-level API. */ + friend class TreeViewItemAPIWrapper; private: bool is_open_ = false; bool is_active_ = false; bool is_renaming_ = false; - IsActiveFn is_active_fn_; - protected: - /** This label is used for identifying an item (together with its parent's labels). */ + /** This label is used for identifying an item within its parent. */ std::string label_{}; - /** Every item gets a button of type during the layout building #UI_BTYPE_TREEROW. */ + /** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */ uiButTreeRow *tree_row_but_ = nullptr; public: @@ -238,33 +210,59 @@ class AbstractTreeViewItem : public TreeViewItemContainer { virtual void build_row(uiLayout &row) = 0; virtual void build_context_menu(bContext &C, uiLayout &column) const; + AbstractTreeView &get_tree_view() const; + + void begin_renaming(); + void toggle_collapsed(); + void set_collapsed(bool collapsed); + /** + * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we + * can't be sure about the item state. + */ + bool is_collapsed() const; + /** + * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we + * can't be sure about the item state. + */ + bool is_active() const; + + protected: + /** + * Called when the items state changes from inactive to active. + */ virtual void on_activate(); /** - * Set a custom callback to check if this item should be active. There's a version without - * arguments for checking if the item is currently in an active state. + * If the result is not empty, it controls whether the item should be active or not, + * usually depending on the data that the view represents. */ - virtual void is_active(IsActiveFn is_active_fn); + virtual std::optional<bool> should_be_active() const; /** * Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if * another item is already being renamed. */ - virtual bool can_rename() const; + virtual bool supports_renaming() const; /** * Try renaming the item, or the data it represents. Can assume - * #AbstractTreeViewItem::can_rename() returned true. Sub-classes that override this should - * usually call this, unless they have a custom #AbstractTreeViewItem.matches(). + * #AbstractTreeViewItem::supports_renaming() returned true. Sub-classes that override this + * should usually call this, unless they have a custom #AbstractTreeViewItem.matches(). * * \return True if the renaming was successful. */ virtual bool rename(StringRefNull new_name); /** + * Return whether the item can be collapsed. Used to disable collapsing for items with children. + */ + virtual bool supports_collapsing() const; + + /** * Copy persistent state (e.g. is-collapsed flag, selection, etc.) from a matching item of * the last redraw to this item. If sub-classes introduce more advanced state they should * override this and make it update their state accordingly. */ virtual void update_from_old(const AbstractTreeViewItem &old); + /** * Compare this item to \a other to check if they represent the same data. * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. @@ -288,47 +286,28 @@ class AbstractTreeViewItem : public TreeViewItemContainer { */ virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const; - void begin_renaming(); - void end_renaming(); - - AbstractTreeView &get_tree_view() const; - int count_parents() const; - void deactivate(); /** - * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we - * can't be sure about the item state. + * Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate() + * function and ensures this item's parents are not collapsed (so the item is visible). + * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the + * actual item state is unknown, possibly calling state-change update functions incorrectly. */ - bool is_active() const; + void activate(); + void deactivate(); + /** * Can be called from the #AbstractTreeViewItem::build_row() implementation, but not earlier. The * hovered state can't be queried reliably otherwise. * Note that this does a linear lookup in the old block, so isn't too great performance-wise. */ bool is_hovered() const; - void toggle_collapsed(); - /** - * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we - * can't be sure about the item state. - */ - bool is_collapsed() const; - void set_collapsed(bool collapsed); bool is_collapsible() const; bool is_renaming() const; void ensure_parents_uncollapsed(); - bool matches_including_parents(const AbstractTreeViewItem &other) const; uiButTreeRow *tree_row_button(); - protected: - /** - * Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate() - * function and ensures this item's parents are not collapsed (so the item is visible). - * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the - * actual item state is unknown, possibly calling state-change update functions incorrectly. - */ - void activate(); - private: static void rename_button_fn(bContext *, void *, char *); static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but); @@ -338,13 +317,16 @@ class AbstractTreeViewItem : public TreeViewItemContainer { /** See #AbstractTreeView::change_state_delayed() */ void change_state_delayed(); + void end_renaming(); void add_treerow_button(uiBlock &block); void add_indent(uiLayout &row) const; void add_collapse_chevron(uiBlock &block) const; void add_rename_button(uiLayout &row); + bool matches_including_parents(const AbstractTreeViewItem &other) const; bool has_active_child() const; + int count_parents() const; }; /** \} */ @@ -358,11 +340,18 @@ class AbstractTreeViewItem : public TreeViewItemContainer { * custom implementation of #AbstractTreeViewItem::create_drag_controller(). */ class AbstractTreeViewItemDragController { + protected: + AbstractTreeView &tree_view_; + public: + AbstractTreeViewItemDragController(AbstractTreeView &tree_view); virtual ~AbstractTreeViewItemDragController() = default; virtual int get_drag_type() const = 0; virtual void *create_drag_data() const = 0; + virtual void on_drag_start(); + + template<class TreeViewType> inline TreeViewType &tree_view() const; }; /** @@ -398,7 +387,7 @@ class AbstractTreeViewItemDropController { * Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this * controller is for. */ - virtual bool on_drop(const wmDrag &drag) = 0; + virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0; template<class TreeViewType> inline TreeViewType &tree_view() const; }; @@ -416,6 +405,7 @@ class AbstractTreeViewItemDropController { */ class BasicTreeViewItem : public AbstractTreeViewItem { public: + using IsActiveFn = std::function<bool()>; using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>; BIFIconID icon; @@ -423,7 +413,11 @@ class BasicTreeViewItem : public AbstractTreeViewItem { void build_row(uiLayout &row) override; void add_label(uiLayout &layout, StringRefNull label_override = ""); - void on_activate(ActivateFn fn); + void set_on_activate_fn(ActivateFn fn); + /** + * Set a custom callback to check if this item should be active. + */ + void set_is_active_fn(IsActiveFn fn); protected: /** @@ -433,15 +427,33 @@ class BasicTreeViewItem : public AbstractTreeViewItem { */ ActivateFn activate_fn_; + IsActiveFn is_active_fn_; + private: static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2); + std::optional<bool> should_be_active() const override; void on_activate() override; }; /** \} */ /* ---------------------------------------------------------------------- */ +/** \name Tree-View Builder + * \{ */ + +class TreeViewBuilder { + uiBlock &block_; + + public: + TreeViewBuilder(uiBlock &block); + + void build_tree_view(AbstractTreeView &tree_view); +}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ template<class ItemT, typename... Args> inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args) @@ -453,6 +465,13 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args) add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...))); } +template<class TreeViewType> TreeViewType &AbstractTreeViewItemDragController::tree_view() const +{ + static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value, + "Type must derive from and implement the AbstractTreeView interface"); + return static_cast<TreeViewType &>(tree_view_); +} + template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const { static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value, |