Blender V4.3
abstract_view_item.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
9#include "BKE_context.hh"
10
11#include "BLI_listbase.h"
12
13#include "WM_api.hh"
14
15#include "UI_interface.hh"
16#include "interface_intern.hh"
17
18#include "UI_abstract_view.hh"
19
20#include <stdexcept>
21
22namespace blender::ui {
23
24/* ---------------------------------------------------------------------- */
34
37/* ---------------------------------------------------------------------- */
42{
43 /* Do nothing by default. */
44}
45
46std::optional<bool> AbstractViewItem::should_be_active() const
47{
48 return std::nullopt;
49}
50
52{
53 BLI_assert_msg(get_view().is_reconstructed(),
54 "Item activation can't be done until reconstruction is completed");
55
56 if (!is_activatable_) {
57 return false;
58 }
59 if (is_active()) {
60 return false;
61 }
62
63 /* Deactivate other items in the view. */
64 this->get_view().foreach_view_item([](auto &item) { item.deactivate(); });
65
66 is_active_ = true;
67 return true;
68}
69
71{
72 if (set_state_active()) {
73 on_activate(C);
74 }
75}
76
78{
79 is_active_ = false;
80}
81
84/* ---------------------------------------------------------------------- */
89{
90 if (const std::optional<bool> should_be_active = this->should_be_active()) {
91 if (*should_be_active) {
92 /* Don't call #activate() here, since this reflects an external state change and therefore
93 * shouldn't call #on_activate(). */
95 }
96 else {
97 is_active_ = false;
98 }
99 }
100}
101
104/* ---------------------------------------------------------------------- */
109{
110 /* No renaming by default. */
111 return false;
112}
113bool AbstractViewItem::rename(const bContext & /*C*/, StringRefNull /*new_name*/)
114{
115 /* No renaming by default. */
116 return false;
117}
118
120{
121 /* No rename string by default. */
122 return {};
123}
124
126{
127 return is_renaming_;
128}
129
131{
132 AbstractView &view = this->get_view();
133 if (view.is_renaming() || !supports_renaming()) {
134 return;
135 }
136
137 if (view.begin_renaming()) {
138 is_renaming_ = true;
139 }
140
141 StringRef initial_str = this->get_rename_string();
142 std::copy(std::begin(initial_str), std::end(initial_str), std::begin(view.get_rename_buffer()));
143}
144
146{
147 const AbstractView &view = this->get_view();
148 rename(C, view.get_rename_buffer().data());
149 end_renaming();
150}
151
153{
154 if (!is_renaming()) {
155 return;
156 }
157
158 is_renaming_ = false;
159
160 AbstractView &view = this->get_view();
161 view.end_renaming();
162}
163
165{
166 /* A minimal sanity check, can't do much more here. */
167 BLI_assert(rename_but.type == UI_BTYPE_TEXT && rename_but.poin);
168
169 LISTBASE_FOREACH (uiBut *, but, &rename_but.block->buttons) {
170 if (but->type != UI_BTYPE_VIEW_ITEM) {
171 continue;
172 }
173
174 uiButViewItem *view_item_but = (uiButViewItem *)but;
175 AbstractViewItem *item = reinterpret_cast<AbstractViewItem *>(view_item_but->view_item);
176 const AbstractView &view = item->get_view();
177
178 if (item->is_renaming() && (view.get_rename_buffer().data() == rename_but.poin)) {
179 return item;
180 }
181 }
182
183 return nullptr;
184}
185
186static void rename_button_fn(bContext *C, void *arg, char * /*origstr*/)
187{
188 const uiBut *rename_but = static_cast<uiBut *>(arg);
190 BLI_assert(item);
191 item->rename_apply(*C);
192}
193
195{
196 AbstractView &view = this->get_view();
197 uiBut *rename_but = uiDefBut(&block,
199 1,
200 "",
201 0,
202 0,
203 UI_UNIT_X * 10,
204 UI_UNIT_Y,
205 view.get_rename_buffer().data(),
206 1.0f,
207 view.get_rename_buffer().size(),
208 "");
209
210 /* Gotta be careful with what's passed to the `arg1` here. Any view data will be freed once the
211 * callback is executed. */
212 UI_but_func_rename_set(rename_but, rename_button_fn, rename_but);
213 UI_but_flag_disable(rename_but, UI_BUT_UNDO);
214
215 const bContext *evil_C = reinterpret_cast<bContext *>(block.evil_C);
216 ARegion *region = CTX_wm_region(evil_C);
217 /* Returns false if the button was removed. */
218 if (UI_but_active_only(evil_C, region, &block, rename_but) == false) {
219 end_renaming();
220 }
221}
222
225/* ---------------------------------------------------------------------- */
230{
231 /* No context menu by default. */
232}
233
236/* ---------------------------------------------------------------------- */
241{
242 return true;
243}
244
246{
247 BLI_assert(get_view().needs_filtering_ == false);
249}
250
253/* ---------------------------------------------------------------------- */
257std::unique_ptr<AbstractViewItemDragController> AbstractViewItem::create_drag_controller() const
258{
259 /* There's no drag controller (and hence no drag support) by default. */
260 return nullptr;
261}
262
263std::unique_ptr<DropTargetInterface> AbstractViewItem::create_item_drop_target()
264{
265 /* There's no drop target (and hence no drop support) by default. */
266 return nullptr;
267}
268
269std::optional<std::string> AbstractViewItem::debug_name() const
270{
271 return {};
272}
273
275
277{
278 /* Do nothing by default. */
279}
280
283/* ---------------------------------------------------------------------- */
288{
289 if (UNLIKELY(!view_)) {
290 throw std::runtime_error(
291 "Invalid state, item must be registered through AbstractView::register_item()");
292 }
293 return *view_;
294}
295
300
305
310
312{
313 return is_interactive_;
314}
315
317{
318 BLI_assert_msg(this->get_view().is_reconstructed(),
319 "State can't be queried until reconstruction is completed");
320 return is_active_;
321}
322
327
330} // namespace blender::ui
331
332/* ---------------------------------------------------------------------- */
336namespace blender::ui {
337
343 public:
344 static bool matches(const AbstractViewItem &a, const AbstractViewItem &b)
345 {
346 if (typeid(a) != typeid(b)) {
347 return false;
348 }
349 /* TODO should match the view as well. */
350 return a.matches(b);
351 }
352
354 {
355 std::swap(a.view_item_but_, b.view_item_but_);
356 }
357};
358
359} // namespace blender::ui
360
361using namespace blender::ui;
362
367
372
374{
375 const AbstractView &view = item.get_view();
376 return !view.is_renaming() && item.supports_renaming();
377}
378
383
385{
386 return item.create_drag_controller() != nullptr;
387}
388
390{
391 return item.get_view().get_popup_keep_open();
392}
393
395{
396 const std::unique_ptr<AbstractViewItemDragController> drag_controller =
398 if (!drag_controller) {
399 return false;
400 }
401
403 ICON_NONE,
404 drag_controller->get_drag_type(),
405 drag_controller->create_drag_data(),
407 drag_controller->on_drag_start();
408
409 return true;
410}
411
ARegion * CTX_wm_region(const bContext *C)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define LISTBASE_FOREACH(type, var, list)
#define UNLIKELY(x)
void UI_but_flag_disable(uiBut *but, int flag)
bool UI_view_item_can_rename(const blender::ui::AbstractViewItem &item)
#define UI_UNIT_Y
bool UI_view_item_popup_keep_open(const blender::ui::AbstractViewItem &item)
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
bool UI_view_item_drag_start(bContext &C, const blender::ui::AbstractViewItem &item)
void UI_view_item_begin_rename(blender::ui::AbstractViewItem &item)
void UI_but_func_rename_set(uiBut *but, uiButHandleRenameFunc func, void *arg1)
bool UI_view_item_matches(const blender::ui::AbstractViewItem &a, const blender::ui::AbstractViewItem &b)
bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBut *but)
bool UI_view_item_supports_drag(const blender::ui::AbstractViewItem &item)
#define UI_UNIT_X
@ UI_BTYPE_TEXT
@ UI_BTYPE_VIEW_ITEM
@ UI_BUT_UNDO
@ WM_DRAG_FREE_DATA
Definition WM_types.hh:1181
virtual void update_from_old(const AbstractViewItem &old)
void add_rename_button(uiBlock &block)
virtual bool should_be_filtered_visible(StringRefNull filter_string) const
virtual void on_activate(bContext &C)
virtual std::unique_ptr< DropTargetInterface > create_item_drop_target()
virtual bool supports_renaming() const
uiButViewItem * view_item_button() const
virtual std::optional< bool > should_be_active() const
virtual bool rename(const bContext &C, StringRefNull new_name)
virtual void build_context_menu(bContext &C, uiLayout &column) const
virtual StringRef get_rename_string() const
void rename_apply(const bContext &C)
virtual std::unique_ptr< AbstractViewItemDragController > create_drag_controller() const
virtual std::optional< std::string > debug_name() const
virtual void foreach_view_item(FunctionRef< void(AbstractViewItem &)> iter_fn) const =0
static bool matches(const AbstractViewItem &a, const AbstractViewItem &b)
static void swap_button_pointers(AbstractViewItem &a, AbstractViewItem &b)
local_group_size(16, 16) .push_constant(Type b
void ui_view_item_swap_button_pointers(blender::ui::AbstractViewItem &a, blender::ui::AbstractViewItem &b)
static void rename_button_fn(bContext *C, void *arg, char *)
static AbstractViewItem * find_item_from_rename_button(const uiBut &rename_but)
struct bContext::@80 data
ListBase buttons
blender::ui::AbstractViewItem * view_item
eButType type
uiBlock * block
void WM_event_start_drag(bContext *C, int icon, eWM_DragDataType type, void *poin, uint flags)