Blender V4.5
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
135 friend class TreeViewBuilder;
138
139 public:
140 /* virtual */ ~AbstractTreeView() override = default;
141
142 void draw_overlays(const ARegion &region, const uiBlock &block) const override;
143
145 void foreach_root_item(ItemIterFn iter_fn) const;
146
147 bool is_fully_visible() const override;
148 void scroll(ViewScrollDirection direction) override;
149
153 AbstractTreeViewItem *find_hovered(const ARegion &region, const int2 &xy);
154
159 void set_default_rows(int default_rows);
160
161 protected:
162 virtual void build_tree() = 0;
163
164 std::optional<uiViewState> persistent_state() const override;
165 void persistent_state_apply(const uiViewState &state) override;
166
167 private:
168 void foreach_view_item(FunctionRef<void(AbstractViewItem &)> iter_fn) const final;
169 void update_children_from_old(const AbstractView &old_view) override;
170 static void update_children_from_old_recursive(const TreeViewOrItem &new_items,
171 const TreeViewOrItem &old_items);
172 static AbstractTreeViewItem *find_matching_child(
173 const AbstractTreeViewItem &lookup_item, const Span<AbstractTreeViewItem *> possible_items);
174 std::optional<int> tot_visible_row_count() const;
175
176 bool supports_scrolling() const override;
177
178 void draw_hierarchy_lines(const ARegion &region, const uiBlock &block) const;
179 void get_hierarchy_lines(const ARegion &region,
180 const TreeViewOrItem &parent,
181 const float aspect,
182 Vector<std::pair<int2, int2>> &lines,
183 int &visible_item_index) const;
184
185 int count_visible_descendants(const AbstractTreeViewItem &parent) const;
186};
187
189
190/* ---------------------------------------------------------------------- */
193
201class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContainer {
202 friend class AbstractTreeView;
204 /* Higher-level API. */
206
207 private:
208 bool is_open_ = false;
209
210 protected:
212 std::string label_;
213
214 public:
215 /* virtual */ ~AbstractTreeViewItem() override = default;
216
217 virtual void build_row(uiLayout &row) = 0;
218
219 /* virtual */ std::optional<std::string> debug_name() const override;
220
221 std::unique_ptr<DropTargetInterface> create_item_drop_target() final;
223
229 std::optional<rctf> get_win_rect(const ARegion &region) const;
230
232
239 bool toggle_collapsed();
246 virtual bool set_collapsed(bool collapsed);
253 virtual void on_collapse_change(bContext &C, bool is_collapsed);
258 virtual std::optional<bool> should_be_collapsed() const;
259
267
272 bool is_collapsed() const;
273 bool is_collapsible() const;
274
275 int count_parents() const;
276
277 protected:
279 /* virtual */ StringRef get_rename_string() const override;
281 /* virtual */ bool rename(const bContext &C, StringRefNull new_name) override;
282
287 virtual bool supports_collapsing() const;
288
293
295
297 /* virtual */ bool matches(const AbstractViewItem &other) const override;
298
300 /* virtual */ void update_from_old(const AbstractViewItem &old) override;
301
312 virtual bool matches_single(const AbstractTreeViewItem &other) const;
313
319 bool is_hovered() const;
320
322
323 private:
324 static void tree_row_click_fn(bContext *, void *, void *);
325 static void collapse_chevron_click_fn(bContext *, void *but_arg1, void *);
326
331 bool set_state_active() final;
332
333 void add_treerow_button(uiBlock &block);
334 int indent_width() const;
335 void add_indent(uiLayout &row) const;
336 void add_collapse_chevron(uiBlock &block) const;
337 void add_rename_button(uiLayout &row);
338
339 bool has_active_child() const;
340};
341
343
344/* ---------------------------------------------------------------------- */
349
354 public:
355 using IsActiveFn = std::function<bool()>;
356 using ActivateFn = std::function<void(bContext &C, BasicTreeViewItem &new_active)>;
358
359 explicit BasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE);
360
361 void build_row(uiLayout &row) override;
362 void add_label(uiLayout &layout, StringRefNull label_override = "");
367 void set_is_active_fn(IsActiveFn is_active_fn);
368
369 protected:
375
377
378 private:
379 static void tree_row_click_fn(bContext *C, void *arg1, void *arg2);
380
381 std::optional<bool> should_be_active() const override;
382 void on_activate(bContext &C) override;
383};
384
386
387/* ---------------------------------------------------------------------- */
390
401 protected:
404
405 public:
408
409 std::optional<DropLocation> choose_drop_location(const ARegion &region,
410 const wmEvent &event) const override;
411
414 template<class ViewType> inline ViewType &get_view() const;
415};
416
418
419/* ---------------------------------------------------------------------- */
422
424 public:
425 static void build_tree_view(const bContext &C,
426 AbstractTreeView &tree_view,
427 uiLayout &layout,
428 std::optional<StringRef> search_string = {},
429 bool add_box = true);
430
431 private:
432 static void ensure_min_rows_items(AbstractTreeView &tree_view);
433};
434
436
437/* ---------------------------------------------------------------------- */
438
439template<class ItemT, typename... Args>
440inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
441{
442 static_assert(std::is_base_of_v<AbstractTreeViewItem, ItemT>,
443 "Type must derive from and implement the AbstractTreeViewItem interface");
444
445 return dynamic_cast<ItemT &>(
446 add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
447}
448
449template<class ViewType> ViewType &TreeViewItemDropTarget::get_view() const
450{
451 static_assert(std::is_base_of_v<AbstractTreeView, ViewType>,
452 "Type must derive from and implement the ui::AbstractTreeView interface");
453 return dynamic_cast<ViewType &>(view_item_.get_tree_view());
454}
455
456} // namespace blender::ui
#define final(a, b, c)
Definition BLI_hash.h:19
#define ENUM_OPERATORS(_type, _max)
int BIFIconID
Definition ED_asset.hh:29
#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:625
void update_from_old(const AbstractViewItem &old) override
Definition tree_view.cc:592
AbstractTreeView & get_tree_view() const
Definition tree_view.cc:620
std::unique_ptr< DropTargetInterface > create_item_drop_target() final
Definition tree_view.cc:605
StringRef get_rename_string() const override
Definition tree_view.cc:579
virtual void build_row(uiLayout &row)=0
bool matches(const AbstractViewItem &other) const override
Definition tree_view.cc:755
void toggle_collapsed_from_view(bContext &C)
Definition tree_view.cc:684
virtual std::unique_ptr< TreeViewItemDropTarget > create_drop_target()
Definition tree_view.cc:610
virtual void on_collapse_change(bContext &C, bool is_collapsed)
Definition tree_view.cc:704
~AbstractTreeViewItem() override=default
virtual std::optional< bool > should_be_collapsed() const
Definition tree_view.cc:709
virtual bool set_collapsed(bool collapsed)
Definition tree_view.cc:691
virtual bool matches_single(const AbstractTreeViewItem &other) const
Definition tree_view.cc:600
std::optional< std::string > debug_name() const override
Definition tree_view.cc:615
virtual bool supports_collapsing() const
Definition tree_view.cc:574
bool rename(const bContext &C, StringRefNull new_name) override
Definition tree_view.cc:584
AbstractTreeViewItem * find_hovered(const ARegion &region, const int2 &xy)
Definition tree_view.cc:120
void scroll(ViewScrollDirection direction) override
Definition tree_view.cc:383
void foreach_root_item(ItemIterFn iter_fn) const
Definition tree_view.cc:113
bool is_fully_visible() const override
Definition tree_view.cc:378
void persistent_state_apply(const uiViewState &state) override
Definition tree_view.cc:162
void draw_overlays(const ARegion &region, const uiBlock &block) const override
Definition tree_view.cc:309
~AbstractTreeView() override=default
void foreach_item(ItemIterFn iter_fn, IterOptions options=IterOptions::None) const
Definition tree_view.cc:108
std::optional< uiViewState > persistent_state() const override
Definition tree_view.cc:144
void set_default_rows(int default_rows)
Definition tree_view.cc:139
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, std::optional< StringRef > search_string={}, bool add_box=true)
Definition tree_view.cc:980
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:72
Vector< std::unique_ptr< AbstractTreeViewItem > > children_
void foreach_parent(ItemIterFn iter_fn) const
Definition tree_view.cc:92
FunctionRef< void(AbstractTreeViewItem &)> ItemIterFn
AbstractTreeViewItem & view_item_
TreeViewItemDropTarget(AbstractTreeViewItem &view_item, DropBehavior behavior=DropBehavior::Insert)
Definition tree_view.cc:394
std::optional< DropLocation > choose_drop_location(const ARegion &region, const wmEvent &event) const override
Definition tree_view.cc:400
CCL_NAMESPACE_BEGIN struct Options options
#define class
#define public
static ulong state[N]
TreeViewItemContainer TreeViewOrItem
VecBase< int32_t, 2 > int2
int xy[2]
Definition wm_draw.cc:174
bool override
Definition wm_files.cc:1184