[Bf-blender-cvs] [50f4e176960] temp-asset-browser-catalogs-ui: Support opening and collapsing tree-view items
Julian Eisel
noreply at git.blender.org
Fri Sep 10 21:41:39 CEST 2021
Commit: 50f4e176960d2bae5b402667d8b912dfaebb211d
Author: Julian Eisel
Date: Fri Sep 10 21:36:18 2021 +0200
Branches: temp-asset-browser-catalogs-ui
https://developer.blender.org/rB50f4e176960d2bae5b402667d8b912dfaebb211d
Support opening and collapsing tree-view items
For this to work, we need to support tree-view items with state that is
persistent over redraws. This is achieved by matching tree items to tree
items of a previous redraw, and copying the state if needed. This is
done in the tree-view API, so except for more advanced cases (with
custom item state or custom ways to match items), API users shouldn't
have to deal with this.
===================================================================
M source/blender/editors/include/UI_interface.h
M source/blender/editors/include/UI_tree_view.hh
M source/blender/editors/interface/interface.c
M source/blender/editors/interface/interface_handlers.c
M source/blender/editors/interface/interface_intern.h
M source/blender/editors/interface/interface_view.cc
M source/blender/editors/interface/tree_view.cc
M source/blender/editors/space_file/asset_catalog_tree_view.cc
===================================================================
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 683c39987de..2b8667aaca1 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -85,7 +85,9 @@ typedef struct uiBut uiBut;
typedef struct uiLayout uiLayout;
typedef struct uiPopupBlockHandle uiPopupBlockHandle;
/* C handle for C++ #uiAbstractTreeView type. */
-typedef struct uiAbstractTreeViewHandle uiAbstractTreeViewHandle;
+typedef struct uiTreeViewHandle uiTreeViewHandle;
+/* C handle for C++ #uiAbstractTreeViewItem type. */
+typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
/* Defines */
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index d715f58a52b..725975b2b8d 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -36,6 +36,7 @@ struct uiLayout;
namespace blender::ui {
+class uiAbstractTreeView;
class uiAbstractTreeViewItem;
/* ---------------------------------------------------------------------- */
@@ -83,29 +84,56 @@ class uiTreeViewItemContainer {
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name Tree-View Base Class
+/** \name Tree-View Builders
* \{ */
-class uiTreeViewLayoutBuilder {
+class uiTreeViewBuilder {
uiBlock &block_;
public:
- uiTreeViewLayoutBuilder(uiBlock &);
+ uiTreeViewBuilder(uiBlock &block);
+
+ void build_tree_view(uiAbstractTreeView &tree_view);
+};
+
+class uiTreeViewLayoutBuilder {
+ uiBlock &block_;
+ friend uiTreeViewBuilder;
+
+ public:
void build_row(uiAbstractTreeViewItem &item) const;
uiBlock &block() const;
uiLayout *current_layout() const;
+
+ private:
+ /* Created through #uiTreeViewBuilder. */
+ uiTreeViewLayoutBuilder(uiBlock &block);
};
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Tree-View Base Class
+ * \{ */
+
class uiAbstractTreeView : public uiTreeViewItemContainer {
+ friend uiTreeViewBuilder;
+ friend uiTreeViewLayoutBuilder;
+
public:
virtual ~uiAbstractTreeView() = default;
+ protected:
virtual void build_tree() = 0;
- void build_layout_from_tree(const uiTreeViewLayoutBuilder &builder);
-
private:
+ void update_from_old(uiBlock &new_block);
+ static void update_children_from_old_recursive(const uiTreeViewItemContainer &new_items,
+ const uiTreeViewItemContainer &old_items);
+ static uiAbstractTreeViewItem *find_matching_child(const uiAbstractTreeViewItem &lookup_item,
+ const uiTreeViewItemContainer &items);
+ void build_layout_from_tree(const uiTreeViewLayoutBuilder &builder);
void build_layout_from_tree_recursive(const uiTreeViewLayoutBuilder &builder,
const uiTreeViewItemContainer &items);
};
@@ -126,15 +154,26 @@ class uiAbstractTreeView : public uiTreeViewItemContainer {
class uiAbstractTreeViewItem : public uiTreeViewItemContainer {
friend class uiAbstractTreeView;
- bool is_open_;
+ bool is_open_ = false;
+
+ protected:
+ /** This label is used for identifying an item (together with its parents labels). */
+ std::string label_{};
public:
virtual ~uiAbstractTreeViewItem() = default;
virtual void build_row(uiLayout &row) = 0;
+ /** 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 update their state accordingly. */
+ virtual void update_from_old(uiAbstractTreeViewItem &old);
+
int count_parents() const;
void toggle_collapsed();
+ bool is_collapsed() const;
+ void set_collapsed(bool collapsed);
bool is_collapsible() const;
};
@@ -151,7 +190,6 @@ class uiAbstractTreeViewItem : public uiTreeViewItemContainer {
*/
class uiBasicTreeViewItem : public uiAbstractTreeViewItem {
public:
- std::string label;
BIFIconID icon;
uiBasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE);
@@ -161,7 +199,9 @@ class uiBasicTreeViewItem : public uiAbstractTreeViewItem {
protected:
/** Created in the #build() function. */
uiButTreeRow *tree_row_but_ = nullptr;
+
uiBut *button();
+ BIFIconID get_draw_icon() const;
};
/** \} */
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 4901e594174..e3c7b606ee4 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -856,10 +856,21 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
oldbut->hardmax = but->hardmax;
}
- if (oldbut->type == UI_BTYPE_PROGRESS_BAR) {
- uiButProgressbar *progress_oldbut = (uiButProgressbar *)oldbut;
- uiButProgressbar *progress_but = (uiButProgressbar *)but;
- progress_oldbut->progress = progress_but->progress;
+ switch (oldbut->type) {
+ case UI_BTYPE_PROGRESS_BAR: {
+ uiButProgressbar *progress_oldbut = (uiButProgressbar *)oldbut;
+ uiButProgressbar *progress_but = (uiButProgressbar *)but;
+ progress_oldbut->progress = progress_but->progress;
+ break;
+ }
+ case UI_BTYPE_TREEROW: {
+ uiButTreeRow *treerow_oldbut = (uiButTreeRow *)oldbut;
+ uiButTreeRow *treerow_newbut = (uiButTreeRow *)but;
+ SWAP(uiTreeViewItemHandle *, treerow_newbut->tree_item, treerow_oldbut->tree_item);
+ break;
+ }
+ default:
+ break;
}
/* move/copy string from the new button to the old */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5bc496c0a4e..e77a16b747e 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -384,6 +384,8 @@ typedef struct uiHandleButtonData {
/* booleans (could be made into flags) */
bool cancel, escapecancel;
bool applied, applied_interactive;
+ /* Button is being applied through an extra icon. */
+ bool apply_through_extra_icon;
bool changed_cursor;
wmTimer *flashtimer;
@@ -1156,6 +1158,16 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
data->applied = true;
}
+static void ui_apply_but_TREEROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
+{
+ if (data->apply_through_extra_icon) {
+ /* Don't apply this, it would cause unintended tree-row toggling when clicking on extra icons.
+ */
+ return;
+ }
+ ui_apply_but_ROW(C, block, but, data);
+}
+
/**
* \note Ownership of \a properties is moved here. The #uiAfterFunc owns it now.
*
@@ -2297,9 +2309,11 @@ static void ui_apply_but(
ui_apply_but_TOG(C, but, data);
break;
case UI_BTYPE_ROW:
- case UI_BTYPE_TREEROW:
ui_apply_but_ROW(C, block, but, data);
break;
+ case UI_BTYPE_TREEROW:
+ ui_apply_but_TREEROW(C, block, but, data);
+ break;
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
break;
@@ -4187,6 +4201,8 @@ static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtraOpIcon *op_icon)
{
+ but->active->apply_through_extra_icon = true;
+
if (but->active->interactive) {
ui_apply_but(C, but->block, but, but->active, true);
}
@@ -4729,7 +4745,7 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
/* Behave like other menu items. */
do_activate = (event->val == KM_RELEASE);
}
- else {
+ else if (!ui_do_but_extra_operator_icon(C, but, data, event)) {
/* Also use double-clicks to prevent fast clicks to leak to other handlers (T76481). */
do_activate = ELEM(event->val, KM_PRESS, KM_DBL_CLICK);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 9d5df53681e..0bcad3f6b1d 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -364,6 +364,7 @@ typedef struct uiButDatasetRow {
typedef struct uiButTreeRow {
uiBut but;
+ uiTreeViewItemHandle *tree_item;
int indentation;
} uiButTreeRow;
@@ -1288,6 +1289,8 @@ void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
void ui_block_free_views(struct uiBlock *block);
+uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
+ const uiTreeViewHandle *new_view);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index c7bf34d2098..b7b14b5ad64 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -16,6 +16,11 @@
/** \file
* \ingroup edinterface
+ *
+ * This part of the UI-View API is mostly needed to support persistent state of items within the
+ * view. Views are stored in #uiBlock's, and kept alive with it until after the next redraw. So we
+ * can compare the old view items with the new view items and keep state persistent for matching
+ * ones.
*/
#include <memory>
@@ -32,7 +37,8 @@ using namespace blender;
using namespace blender::ui;
/**
- * Wrapper to store views in a #ListBase.
+ * Wrapper to store views in a #ListBase. There's no `uiView` base class, we just store views as a
+ * #std::variant.
*/
struct uiViewLink : public Link {
using TreeViewPtr = std::unique_ptr<uiAbstractTreeView>;
@@ -42,6 +48,15 @@ struct uiViewLink : public Link {
std::variant<TreeViewPtr> view;
};
+template<class T> T *get_view_from_link(uiViewLink &link)
+{
+ auto *t_uptr = std::get_if<std::unique_ptr<T>>(&link.view);
+ return t_uptr ? t_uptr->get() : nullptr;
+}
+
+/**
+ * Override this for all available tree types available.
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list