Blender V4.3
interface_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
20#include <memory>
21#include <type_traits>
22#include <variant>
23
24#include "DNA_screen_types.h"
25
26#include "BKE_screen.hh"
27
28#include "BLI_listbase.h"
29#include "BLI_map.hh"
30
31#include "ED_screen.hh"
32
33#include "interface_intern.hh"
34
35#include "UI_interface.hh"
36
37#include "UI_abstract_view.hh"
38#include "UI_grid_view.hh"
39#include "UI_tree_view.hh"
40
41using namespace blender;
42using namespace blender::ui;
43
47struct ViewLink : public Link {
48 std::string idname;
49 std::unique_ptr<AbstractView> view;
50
51 static void views_bounds_calc(const uiBlock &block);
52};
53
54template<class T>
56 StringRef idname,
57 std::unique_ptr<AbstractView> view)
58{
59 ViewLink *view_link = MEM_new<ViewLink>(__func__);
60 BLI_addtail(&block.views, view_link);
61
62 view_link->view = std::move(view);
63 view_link->idname = idname;
64
65 return dynamic_cast<T *>(view_link->view.get());
66}
67
69 StringRef idname,
70 std::unique_ptr<AbstractGridView> grid_view)
71{
72 return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(grid_view));
73}
74
76 StringRef idname,
77 std::unique_ptr<AbstractTreeView> tree_view)
78{
79 return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
80}
81
83{
84 LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
85 MEM_delete(link);
86 }
87}
88
90{
91 Map<AbstractView *, rcti> views_bounds;
92
93 rcti minmax;
94 BLI_rcti_init_minmax(&minmax);
95 LISTBASE_FOREACH (ViewLink *, link, &block.views) {
96 views_bounds.add(link->view.get(), minmax);
97 }
98
99 LISTBASE_FOREACH (uiBut *, but, &block.buttons) {
100 if (but->type != UI_BTYPE_VIEW_ITEM) {
101 continue;
102 }
103 uiButViewItem *view_item_but = static_cast<uiButViewItem *>(but);
104 if (!view_item_but->view_item) {
105 continue;
106 }
107
108 /* Get the view from the button. */
109 AbstractViewItem &view_item = reinterpret_cast<AbstractViewItem &>(*view_item_but->view_item);
110 AbstractView &view = view_item.get_view();
111
112 rcti &bounds = views_bounds.lookup(&view);
113 rcti but_rcti{};
114 BLI_rcti_rctf_copy_round(&but_rcti, &view_item_but->rect);
115 BLI_rcti_do_minmax_rcti(&bounds, &but_rcti);
116 }
117
118 for (const auto item : views_bounds.items()) {
119 const rcti &bounds = item.value;
120 if (BLI_rcti_is_empty(&bounds)) {
121 continue;
122 }
123
124 AbstractView &view = *item.key;
125 view.bounds_ = bounds;
126 }
127}
128
130{
132}
133
134void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
135{
136 ARegion *region = listener_params->region;
137
138 LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
139 if (view_link->view->listen(*listener_params->notifier)) {
140 ED_region_tag_redraw(region);
141 }
142 }
143}
144
145void ui_block_views_draw_overlays(const ARegion *region, const uiBlock *block)
146{
147 LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
148 view_link->view->draw_overlays(*region, *block);
149 }
150}
151
153 const int xy[2],
154 const int pad)
155{
156 /* NOTE: Similar to #ui_but_find_mouse_over_ex(). */
157
158 if (!ui_region_contains_point_px(region, xy)) {
159 return nullptr;
160 }
161 LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
162 float mx = xy[0], my = xy[1];
163 ui_window_to_block_fl(region, block, &mx, &my);
164
165 LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
166 std::optional<rcti> bounds = view_link->view->get_bounds();
167 if (!bounds) {
168 continue;
169 }
170
171 rcti padded_bounds = *bounds;
172 if (pad) {
173 BLI_rcti_pad(&padded_bounds, pad, pad);
174 }
175 if (BLI_rcti_isect_pt(&padded_bounds, mx, my)) {
176 return view_link->view.get();
177 }
178 }
179 }
180
181 return nullptr;
182}
183
185{
187 if (!item_but) {
188 return nullptr;
189 }
190
191 return item_but->view_item;
192}
193
195{
197 if (!item_but) {
198 return nullptr;
199 }
200
201 return item_but->view_item;
202}
203
208
210{
211 LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
212 LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
213 view_link->view->clear_search_highlight();
214 }
215 }
216}
217
218namespace blender::ui {
219
220std::unique_ptr<DropTargetInterface> region_views_find_drop_target_at(const ARegion *region,
221 const int xy[2])
222{
224 if (std::unique_ptr<DropTargetInterface> target = item->create_item_drop_target()) {
225 return target;
226 }
227 }
228
229 /* Get style for some sensible padding around the view items. */
230 const uiStyle *style = UI_style_get_dpi();
231 if (AbstractView *view = UI_region_view_find_at(region, xy, style->buttonspacex)) {
232 if (std::unique_ptr<DropTargetInterface> target = view->create_drop_target()) {
233 return target;
234 }
235 }
236
237 return nullptr;
238}
239
240} // namespace blender::ui
241
243{
244 /* First get the idname the of the view we're looking for. */
245 LISTBASE_FOREACH (ViewLink *, view_link, &block.views) {
246 if (view_link->view.get() == &view) {
247 return view_link->idname;
248 }
249 }
250
251 return {};
252}
253
254template<class T>
256 const T &new_view)
257{
258 uiBlock *old_block = new_block.oldblock;
259 if (!old_block) {
260 return nullptr;
261 }
262
263 StringRef idname = ui_block_view_find_idname(new_block, new_view);
264 if (idname.is_empty()) {
265 return nullptr;
266 }
267
268 LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
269 if (old_view_link->idname == idname) {
270 return dynamic_cast<T *>(old_view_link->view.get());
271 }
272 }
273
274 return nullptr;
275}
276
282
284 const uiBlock &new_block, const ui::AbstractViewItem &new_item)
285{
286 uiBlock *old_block = new_block.oldblock;
287 if (!old_block) {
288 return nullptr;
289 }
290
292 new_block, new_item.get_view());
293 if (!old_view) {
294 return nullptr;
295 }
296
297 LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
298 if (old_but->type != UI_BTYPE_VIEW_ITEM) {
299 continue;
300 }
301 uiButViewItem *old_item_but = (uiButViewItem *)old_but;
302 if (!old_item_but->view_item) {
303 continue;
304 }
305 AbstractViewItem &old_item = *reinterpret_cast<AbstractViewItem *>(old_item_but->view_item);
306 /* Check if the item is from the expected view. */
307 if (&old_item.get_view() != old_view) {
308 continue;
309 }
310
311 if (UI_view_item_matches(new_item, old_item)) {
312 return old_item_but;
313 }
314 }
315
316 return nullptr;
317}
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_rcti_init_minmax(struct rcti *rect)
Definition rct.c:478
void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src)
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y)
Definition rct.c:623
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
bool BLI_rcti_is_empty(const struct rcti *rect)
void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
blender::ui::AbstractView * UI_region_view_find_at(const ARegion *region, const int xy[2], int pad)
const uiStyle * UI_style_get_dpi()
bool UI_view_item_matches(const blender::ui::AbstractViewItem &a, const blender::ui::AbstractViewItem &b)
@ UI_BTYPE_VIEW_ITEM
blender::ui::AbstractViewItem * UI_region_views_find_item_at(const ARegion &region, const int xy[2])
int pad[32 - sizeof(int)]
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
ItemIterator items() const
Definition BLI_map.hh:864
constexpr bool is_empty() const
void ui_window_to_block_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
Definition interface.cc:184
uiBut uiBut * ui_view_item_find_active(const ARegion *region)
uiBut * ui_view_item_find_mouse_over(const ARegion *region, const int xy[2]) ATTR_NONNULL(1
bool ui_region_contains_point_px(const ARegion *region, const int xy[2]) ATTR_NONNULL(1
void UI_region_views_clear_search_highlight(const ARegion *region)
blender::ui::AbstractView * UI_region_view_find_at(const ARegion *region, const int xy[2], const int pad)
void ui_block_views_draw_overlays(const ARegion *region, const uiBlock *block)
uiButViewItem * ui_block_view_find_matching_view_item_but_in_old_block(const uiBlock &new_block, const ui::AbstractViewItem &new_item)
static T * ui_block_view_find_matching_in_old_block_impl(const uiBlock &new_block, const T &new_view)
AbstractGridView * UI_block_add_view(uiBlock &block, StringRef idname, std::unique_ptr< AbstractGridView > grid_view)
void ui_block_free_views(uiBlock *block)
blender::ui::AbstractView * ui_block_view_find_matching_in_old_block(const uiBlock &new_block, const blender::ui::AbstractView &new_view)
ui::AbstractViewItem * UI_region_views_find_item_at(const ARegion &region, const int xy[2])
static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractView &view)
ui::AbstractViewItem * UI_region_views_find_active_item(const ARegion *region)
void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
static T * ui_block_add_view_impl(uiBlock &block, StringRef idname, std::unique_ptr< AbstractView > view)
void ui_block_views_bounds_calc(const uiBlock *block)
uiBut * UI_region_views_find_active_item_but(const ARegion *region)
std::unique_ptr< DropTargetInterface > region_views_find_drop_target_at(const ARegion *region, const int xy[2])
uiBlock * oldblock
ListBase buttons
ListBase views
blender::ui::AbstractViewItem * view_item
const wmNotifier * notifier
int xy[2]
Definition wm_draw.cc:170