Blender V5.0
UI_tree_view.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#pragma once
13
14#include <functional>
15#include <memory>
16#include <string>
17
18#include "BLI_function_ref.hh"
20#include "BLI_vector.hh"
21
22#include "UI_abstract_view.hh"
23#include "UI_resources.hh"
24
25struct bContext;
26struct uiBlock;
27struct uiLayout;
28
29namespace blender::ui {
30
34
35/* ---------------------------------------------------------------------- */
40
49class TreeViewItemContainer {
50 friend class AbstractTreeView;
52
53 /* Private constructor, so only the friends above can create this! */
54 TreeViewItemContainer() = default;
55
56 protected:
59 TreeViewItemContainer *root_ = nullptr;
62
67 bool is_flat_ = false;
68
69 public:
70 enum class IterOptions {
71 None = 0,
72 SkipCollapsed = 1 << 0,
73 SkipFiltered = 1 << 1,
74
75 /* Keep ENUM_OPERATORS() below updated! */
76 };
78
92 template<class ItemT, typename... Args> inline ItemT &add_tree_item(Args &&...args);
97 AbstractTreeViewItem &add_tree_item(std::unique_ptr<AbstractTreeViewItem> item);
98
99 protected:
101 void foreach_parent(ItemIterFn iter_fn) const;
102};
103
106
113
115
116/* ---------------------------------------------------------------------- */
119
120class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
121 /* Shared pointer so the pointer can be kept persistent over redraws. The grip button gets a
122 * pointer to modify the value on resizing, and it uses it to identify the button over redraws.
123 */
124 /* TODO support region zoom. */
125 std::shared_ptr<int> custom_height_ = nullptr;
128 std::shared_ptr<int> scroll_value_ = nullptr;
132 int last_tot_items_ = 0;
133
134 bool scroll_active_into_view_on_draw_ = false;
135 std::shared_ptr<char> show_display_options_ = std::make_shared<char>(0);
136 /* `char[UI_MAX_NAME_STR]` wrapped in shared pointer, to keep a stable pointer over
137 * reconstruction that can be passed to buttons. */
138 std::shared_ptr<char[]> search_string_{new char[256 /*UI_MAX_NAME_STR*/]{}};
139
141 friend class TreeViewBuilder;
144
145 public:
146 /* virtual */ ~AbstractTreeView() override = default;
147
148 void draw_overlays(const ARegion &region, const uiBlock &block) const override;
149
151 void foreach_root_item(ItemIterFn iter_fn) const;
152
153 bool is_fully_visible() const override;
154 void scroll(ViewScrollDirection direction) override;
155 /* Scroll to the active element when state is changed. */
156
160 AbstractTreeViewItem *find_hovered(const ARegion &region, const int2 &xy);
161
169 void set_default_rows(int default_rows);
170
171 protected:
172 virtual void build_tree() = 0;
173
174 std::optional<uiViewState> persistent_state() const override;
175 void persistent_state_apply(const uiViewState &state) override;
176
177 private:
178 void foreach_view_item(FunctionRef<void(AbstractViewItem &)> iter_fn) const final;
179 void update_children_from_old(const AbstractView &old_view) override;
180 static void update_children_from_old_recursive(const TreeViewOrItem &new_items,
181 const TreeViewOrItem &old_items);
182 static AbstractTreeViewItem *find_matching_child(
183 const AbstractTreeViewItem &lookup_item, const Span<AbstractTreeViewItem *> possible_items);
184 std::optional<int> tot_visible_row_count() const;
185
186 bool supports_scrolling() const override;
187
188 void draw_hierarchy_lines(const ARegion &region, const uiBlock &block) const;
189 void get_hierarchy_lines(const ARegion &region,
190 const TreeViewOrItem &parent,
191 const float aspect,
192 Vector<std::pair<int2, int2>> &lines,
193 int &visible_item_index) const;
194
195 int count_visible_descendants(const AbstractTreeViewItem &parent) const;
196 void scroll_active_into_view();
197};
198
200
201/* ---------------------------------------------------------------------- */
204
212class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContainer {
213 friend class AbstractTreeView;
215 /* Higher-level API. */
217
218 private:
219 bool is_open_ = false;
220
221 protected:
223 std::string label_;
224
225 public:
226 /* virtual */ ~AbstractTreeViewItem() override = default;
227
228 virtual void build_row(uiLayout &row) = 0;
229
230 /* virtual */ std::optional<std::string> debug_name() const override;
231
232 std::unique_ptr<DropTargetInterface> create_item_drop_target() final;
234
240 std::optional<rctf> get_win_rect(const ARegion &region) const;
241
243
250 bool toggle_collapsed();
257 virtual bool set_collapsed(bool collapsed);
264 virtual void on_collapse_change(bContext &C, bool is_collapsed);
269 virtual std::optional<bool> should_be_collapsed() const;
270
278
283 bool is_collapsed() const;
284 bool is_collapsible() const;
285
286 int count_parents() const;
287
289
290 protected:
292 /* virtual */ StringRef get_rename_string() const override;
294 /* virtual */ bool rename(const bContext &C, StringRefNull new_name) override;
295
300 virtual bool supports_collapsing() const;
301
306
308
310 /* virtual */ bool matches(const AbstractViewItem &other) const override;
311
313 /* virtual */ void update_from_old(const AbstractViewItem &old) override;
314
325 virtual bool matches_single(const AbstractTreeViewItem &other) const;
326
332 bool is_hovered() const;
333
335
336 private:
337 static void collapse_chevron_click_fn(bContext *, void *but_arg1, void *);
338
343 bool set_state_active() final;
344
345 void add_treerow_button(uiBlock &block);
346 int indent_width() const;
347 void add_indent(uiLayout &row) const;
348 void add_collapse_chevron(uiBlock &block) const;
349 void add_rename_button(uiLayout &row);
350
351 bool has_active_child() const;
352};
353
355
356/* ---------------------------------------------------------------------- */
361
366 public:
367 using IsActiveFn = std::function<bool()>;
368 using ActivateFn = std::function<void(bContext &C, BasicTreeViewItem &new_active)>;
370
371 explicit BasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE);
372
373 void build_row(uiLayout &row) override;
374 void add_label(uiLayout &layout, StringRefNull label_override = "");
379 void set_is_active_fn(IsActiveFn is_active_fn);
380
381 protected:
387
389
390 private:
391 std::optional<bool> should_be_active() const override;
392 void on_activate(bContext &C) override;
393};
394
396
397/* ---------------------------------------------------------------------- */
400
411 protected:
414
415 public:
418
419 std::optional<DropLocation> choose_drop_location(const ARegion &region,
420 const wmEvent &event) const override;
421
424 template<class ViewType> inline ViewType &get_view() const;
425};
426
428
429/* ---------------------------------------------------------------------- */
432
434 public:
435 static void build_tree_view(const bContext &C,
436 AbstractTreeView &tree_view,
437 uiLayout &layout,
438 bool add_box = true);
439
440 private:
441 static void ensure_min_rows_items(AbstractTreeView &tree_view);
442};
443
445
446/* ---------------------------------------------------------------------- */
447
448template<class ItemT, typename... Args>
449inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
450{
451 static_assert(std::is_base_of_v<AbstractTreeViewItem, ItemT>,
452 "Type must derive from and implement the AbstractTreeViewItem interface");
453
454 return dynamic_cast<ItemT &>(
455 add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
456}
457
458template<class ViewType> ViewType &TreeViewItemDropTarget::get_view() const
459{
460 static_assert(std::is_base_of_v<AbstractTreeView, ViewType>,
461 "Type must derive from and implement the ui::AbstractTreeView interface");
462 return dynamic_cast<ViewType &>(view_item_.get_tree_view());
463}
464
465} // namespace blender::ui
#define final(a, b, c)
Definition BLI_hash.h:19
#define ENUM_OPERATORS(_type, _max)
int BIFIconID
Definition ED_asset.hh:28
#define C
Definition RandGen.cpp:29
Abstract base class for defining a customizable tree-view item.
std::optional< rctf > get_win_rect(const ARegion &region) const
Definition tree_view.cc:649
void update_from_old(const AbstractViewItem &old) override
Definition tree_view.cc:616
AbstractTreeView & get_tree_view() const
Definition tree_view.cc:644
std::unique_ptr< DropTargetInterface > create_item_drop_target() final
Definition tree_view.cc:629
StringRef get_rename_string() const override
Definition tree_view.cc:603
virtual void build_row(uiLayout &row)=0
bool matches(const AbstractViewItem &other) const override
Definition tree_view.cc:784
void toggle_collapsed_from_view(bContext &C)
Definition tree_view.cc:708
virtual std::unique_ptr< TreeViewItemDropTarget > create_drop_target()
Definition tree_view.cc:634
virtual void on_collapse_change(bContext &C, bool is_collapsed)
Definition tree_view.cc:728
~AbstractTreeViewItem() override=default
virtual std::optional< bool > should_be_collapsed() const
Definition tree_view.cc:733
virtual bool set_collapsed(bool collapsed)
Definition tree_view.cc:715
virtual bool matches_single(const AbstractTreeViewItem &other) const
Definition tree_view.cc:624
std::optional< std::string > debug_name() const override
Definition tree_view.cc:639
virtual bool supports_collapsing() const
Definition tree_view.cc:598
bool rename(const bContext &C, StringRefNull new_name) override
Definition tree_view.cc:608
AbstractTreeViewItem * find_hovered(const ARegion &region, const int2 &xy)
Definition tree_view.cc:122
void scroll(ViewScrollDirection direction) override
Definition tree_view.cc:396
void foreach_root_item(ItemIterFn iter_fn) const
Definition tree_view.cc:115
bool is_fully_visible() const override
Definition tree_view.cc:391
void persistent_state_apply(const uiViewState &state) override
Definition tree_view.cc:170
void draw_overlays(const ARegion &region, const uiBlock &block) const override
Definition tree_view.cc:321
~AbstractTreeView() override=default
void foreach_item(ItemIterFn iter_fn, IterOptions options=IterOptions::None) const
Definition tree_view.cc:110
std::optional< uiViewState > persistent_state() const override
Definition tree_view.cc:149
void set_default_rows(int default_rows)
Definition tree_view.cc:141
virtual void on_activate(bContext &C)
virtual std::optional< bool > should_be_active() const
virtual bool supports_scrolling() const
BasicTreeViewItem(StringRef label, BIFIconID icon=ICON_NONE)
std::function< bool()> IsActiveFn
std::function< void(bContext &C, BasicTreeViewItem &new_active)> ActivateFn
void add_label(uiLayout &layout, StringRefNull label_override="")
void set_is_active_fn(IsActiveFn is_active_fn)
void set_on_activate_fn(ActivateFn fn)
static void build_tree_view(const bContext &C, AbstractTreeView &tree_view, uiLayout &layout, bool add_box=true)
ItemT & add_tree_item(Args &&...args)
AbstractTreeViewItem * parent_
TreeViewItemContainer * root_
void foreach_item_recursive(ItemIterFn iter_fn, IterOptions options=IterOptions::None) const
Definition tree_view.cc:74
Vector< std::unique_ptr< AbstractTreeViewItem > > children_
void foreach_parent(ItemIterFn iter_fn) const
Definition tree_view.cc:94
FunctionRef< void(AbstractTreeViewItem &)> ItemIterFn
AbstractTreeViewItem & view_item_
TreeViewItemDropTarget(AbstractTreeViewItem &view_item, DropBehavior behavior=DropBehavior::Insert)
Definition tree_view.cc:437
std::optional< DropLocation > choose_drop_location(const ARegion &region, const wmEvent &event) const override
Definition tree_view.cc:443
CCL_NAMESPACE_BEGIN struct Options options
static ulong state[N]
TreeViewItemContainer TreeViewOrItem
VecBase< int32_t, 2 > int2
int xy[2]
Definition wm_draw.cc:178
bool override
Definition wm_files.cc:1192