Blender V5.0
abstract_view.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "interface_intern.hh"
10
11#include "UI_abstract_view.hh"
12
13using namespace blender;
14
15namespace blender::ui {
16
18{
19 /* Actually modifies the item, not the view. But for the public API it "feels" a bit nicer to
20 * have the view base class register the items, rather than setting the view on the item. */
21 item.view_ = this;
22}
23
24/* ---------------------------------------------------------------------- */
27
29{
30 return is_reconstructed_;
31}
32
34{
35 const AbstractViewItem *found_item = nullptr;
36
37 this->foreach_view_item([&](const AbstractViewItem &item) {
38 if (!found_item && item.is_search_highlight()) {
39 found_item = &item;
40 }
41 });
42 return found_item;
43}
44
46{
47 uiBlock *old_block = new_block.oldblock;
48 if (!old_block) {
49 is_reconstructed_ = true;
50 return;
51 }
52
53 AbstractView *old_view = ui_block_view_find_matching_in_old_block(new_block, *this);
54 if (old_view == nullptr) {
55 /* Initial construction, nothing to update. */
56 is_reconstructed_ = true;
57 return;
58 }
59
60 /* Update own persistent data. */
61 prev_filter_string_ = old_view->prev_filter_string_;
62 /* Keep the rename buffer persistent while renaming! The rename button uses the buffer's
63 * pointer to identify itself over redraws. */
64 rename_buffer_ = std::move(old_view->rename_buffer_);
65 old_view->rename_buffer_ = nullptr;
66
67 this->update_children_from_old(*old_view);
68
69 /* Finished (re-)constructing the tree. */
70 is_reconstructed_ = true;
71}
72
74
75/* ---------------------------------------------------------------------- */
78
80{
82 this->is_reconstructed(),
83 "These state changes are supposed to be delayed until reconstruction is completed");
84
85/* Debug-only sanity check: Ensure only one item requests to be active. */
86#ifndef NDEBUG
87 bool has_active = false;
88 foreach_view_item([&has_active](AbstractViewItem &item) {
89 if (item.should_be_active().value_or(false)) {
91 !has_active,
92 "Only one view item should ever return true for its `should_be_active()` method");
93 has_active = true;
94 }
95 });
96#endif
97
98 this->foreach_view_item([](AbstractViewItem &item) { item.change_state_delayed(); });
99}
100
102
103/* ---------------------------------------------------------------------- */
106
107std::unique_ptr<DropTargetInterface> AbstractView::create_drop_target()
108{
109 /* There's no drop target (and hence no drop support) by default. */
110 return nullptr;
111}
112
113bool AbstractView::listen(const wmNotifier & /*notifier*/) const
114{
115 /* Nothing by default. */
116 return false;
117}
118
120{
121 return false;
122}
123
124void AbstractView::draw_overlays(const ARegion & /*region*/, const uiBlock & /*block*/) const
125{
126 /* Nothing by default. */
127}
128
130{
131 return false;
132}
133
135{
136 return false;
137}
138
140{
141 BLI_assert_msg(false, "Unsupported for this view type");
142}
143
144std::optional<uiViewState> AbstractView::persistent_state() const
145{
146 return {};
147}
148
150
152
153/* ---------------------------------------------------------------------- */
156
157void AbstractView::filter(std::optional<StringRef> filter_str)
158{
159 needs_filtering_ = false;
160
161 if (!filter_str) {
162 return;
163 }
164
165 const bool is_empty = filter_str->is_empty();
166 const bool filter_changed = filter_str != prev_filter_string_;
167 prev_filter_string_ = *filter_str;
168
169 bool has_search_highlight = false;
170 this->foreach_view_item([&](AbstractViewItem &item) {
171 item.is_filtered_visible_ = is_empty ||
172 item.should_be_filtered_visible(StringRefNull(*filter_str));
173
174 if (!is_empty) {
175 /* Allow view types to hook into the filtering. For example tree views ensure matching
176 * children have their parents visible and uncollapsed. If the search query is empty, all
177 * items are visible by default, and nothing has to be done. */
178 item.on_filter_change();
179 }
180
181 if (filter_changed) {
182 item.is_highlighted_search_ = false;
183 /* On new filtering input, force the first visible item to be highlighted and in view, so
184 * enter activates it. */
185 if (item.is_filtered_visible_ && !has_search_highlight) {
186 item.is_highlighted_search_ = true;
187 has_search_highlight = true;
188 }
189 }
190 });
191}
192
193/* ---------------------------------------------------------------------- */
196
198{
199 return rename_buffer_ != nullptr;
200}
201
203{
204 if (this->is_renaming()) {
205 return false;
206 }
207
208 rename_buffer_ = std::make_unique<decltype(rename_buffer_)::element_type>();
209 return true;
210}
211
213{
215 rename_buffer_ = nullptr;
216}
217
219{
220 return *rename_buffer_;
221}
223{
224 return *rename_buffer_;
225}
226
227std::optional<rcti> AbstractView::get_bounds() const
228{
229 return bounds_;
230}
231
233{
234 return context_menu_title;
235}
236
237void AbstractView::set_context_menu_title(const std::string &title)
238{
239 context_menu_title = title;
240}
241
243{
244 return popup_keep_open_;
245}
246
248{
249 popup_keep_open_ = true;
250}
251
256
258{
259 is_multiselect_supported_ = true;
260}
261
263{
264 return is_multiselect_supported_;
265}
266
267
268} // namespace blender::ui
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
virtual bool should_be_filtered_visible(StringRefNull filter_string) const
virtual std::optional< bool > should_be_active() const
virtual bool supports_scrolling() const
virtual void draw_overlays(const ARegion &region, const uiBlock &block) const
virtual bool is_fully_visible() const
const AbstractViewItem * search_highlight_item() const
virtual void persistent_state_apply(const uiViewState &state)
bool is_multiselect_supported() const
virtual bool listen(const wmNotifier &) const
std::optional< rcti > get_bounds() const
void update_from_old(uiBlock &new_block)
virtual void change_state_delayed()
virtual std::unique_ptr< DropTargetInterface > create_drop_target()
virtual void foreach_view_item(FunctionRef< void(AbstractViewItem &)> iter_fn) const =0
virtual bool begin_filtering(const bContext &C) const
virtual void scroll(ViewScrollDirection direction)
virtual void update_children_from_old(const AbstractView &old_view)=0
void register_item(AbstractViewItem &item)
Span< char > get_rename_buffer() const
virtual std::optional< uiViewState > persistent_state() const
std::string get_context_menu_title() const
void filter(std::optional< StringRef > filter_str)
void set_context_menu_title(const std::string &title)
blender::ui::AbstractView * ui_block_view_find_matching_in_old_block(const uiBlock &new_block, const blender::ui::AbstractView &new_view)
uiBlock * oldblock