Blender V4.5
interface.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cctype>
11#include <cfloat>
12#include <climits>
13#include <cmath>
14#include <cstddef> /* `offsetof()` */
15#include <cstring>
16
17#include <fmt/format.h>
18
19#include "MEM_guardedalloc.h"
20
21#include "DNA_object_types.h"
22#include "DNA_scene_types.h"
23#include "DNA_screen_types.h"
24#include "DNA_userdef_types.h"
25
26#include "BLI_listbase.h"
27#include "BLI_rect.h"
28#include "BLI_set.hh"
29#include "BLI_string.h"
30#include "BLI_string_utf8.h"
31#include "BLI_vector.hh"
32
33#include "BLI_utildefines.h"
34
35#include "BKE_animsys.h"
36#include "BKE_context.hh"
37#include "BKE_idprop.hh"
38#include "BKE_report.hh"
39#include "BKE_scene.hh"
40#include "BKE_screen.hh"
41#include "BKE_unit.hh"
42
43#include "GPU_matrix.hh"
44#include "GPU_state.hh"
45
46#include "BLF_api.hh"
47#include "BLT_translation.hh"
48
49#include "UI_abstract_view.hh"
50#include "UI_interface.hh"
51#include "UI_interface_icons.hh"
52#include "UI_string_search.hh"
53#include "UI_view2d.hh"
54
55#include "IMB_imbuf.hh"
56
57#include "WM_api.hh"
58#include "WM_message.hh"
59#include "WM_types.hh"
60
61#include "RNA_access.hh"
62#include "RNA_enum_types.hh"
63
64#ifdef WITH_PYTHON
65# include "BPY_extern_run.hh"
66#endif
67
68#include "ED_numinput.hh"
69#include "ED_screen.hh"
70
72
73#include "interface_intern.hh"
74
77using blender::Vector;
78
79/* prototypes. */
80static void ui_def_but_rna__menu(bContext *C, uiLayout *layout, void *but_p);
81static void ui_def_but_rna__panel_type(bContext * /*C*/, uiLayout *layout, void *arg);
82static void ui_def_but_rna__menu_type(bContext * /*C*/, uiLayout *layout, void *but_p);
83
84/* avoid unneeded calls to ui_but_value_get */
85#define UI_BUT_VALUE_UNSET DBL_MAX
86#define UI_GET_BUT_VALUE_INIT(_but, _value) \
87 if (_value == DBL_MAX) { \
88 (_value) = ui_but_value_get(_but); \
89 } \
90 ((void)0)
91
92#define B_NOP -1
93
100
101static void ui_but_free(const bContext *C, uiBut *but);
102
103static bool ui_but_is_unit_radians_ex(const UnitSettings *unit, const int unit_type)
104{
105 return (unit->system_rotation == USER_UNIT_ROT_RADIANS && unit_type == PROP_UNIT_ROTATION);
106}
107
108static bool ui_but_is_unit_radians(const uiBut *but)
109{
110 const UnitSettings *unit = but->block->unit;
111 const int unit_type = UI_but_unit_type_get(but);
112
113 return ui_but_is_unit_radians_ex(unit, unit_type);
114}
115
116/* ************* window matrix ************** */
117
118void ui_block_to_region_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
119{
120 const int getsizex = BLI_rcti_size_x(&region->winrct) + 1;
121 const int getsizey = BLI_rcti_size_y(&region->winrct) + 1;
122
123 float gx = *x;
124 float gy = *y;
125
126 if (block->panel) {
127 gx += block->panel->ofsx;
128 gy += block->panel->ofsy;
129 }
130
131 *x = float(getsizex) *
132 (0.5f + 0.5f * (gx * block->winmat[0][0] + gy * block->winmat[1][0] + block->winmat[3][0]));
133 *y = float(getsizey) *
134 (0.5f + 0.5f * (gx * block->winmat[0][1] + gy * block->winmat[1][1] + block->winmat[3][1]));
135}
136
137void ui_block_to_window_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
138{
139 ui_block_to_region_fl(region, block, x, y);
140 *x += region->winrct.xmin;
141 *y += region->winrct.ymin;
142}
143
144void ui_block_to_window(const ARegion *region, const uiBlock *block, int *x, int *y)
145{
146 float fx = *x;
147 float fy = *y;
148
149 ui_block_to_window_fl(region, block, &fx, &fy);
150
151 *x = int(lround(fx));
152 *y = int(lround(fy));
153}
154
156 const uiBlock *block,
157 rctf *rct_dst,
158 const rctf *rct_src)
159{
160 *rct_dst = *rct_src;
161 ui_block_to_region_fl(region, block, &rct_dst->xmin, &rct_dst->ymin);
162 ui_block_to_region_fl(region, block, &rct_dst->xmax, &rct_dst->ymax);
163}
164
166 const uiBlock *block,
167 rctf *rct_dst,
168 const rctf *rct_src)
169{
170 *rct_dst = *rct_src;
171 ui_block_to_window_fl(region, block, &rct_dst->xmin, &rct_dst->ymin);
172 ui_block_to_window_fl(region, block, &rct_dst->xmax, &rct_dst->ymax);
173}
174
175float ui_block_to_window_scale(const ARegion *region, const uiBlock *block)
176{
177 /* We could have function for this to avoid dummy arg. */
178 float min_y = 0, max_y = 1;
179 float dummy_x = 0.0f;
180 ui_block_to_window_fl(region, block, &dummy_x, &min_y);
181 dummy_x = 0.0f;
182 ui_block_to_window_fl(region, block, &dummy_x, &max_y);
183 return max_y - min_y;
184}
185
186void ui_window_to_block_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
187{
188 const int getsizex = BLI_rcti_size_x(&region->winrct) + 1;
189 const int getsizey = BLI_rcti_size_y(&region->winrct) + 1;
190 const int sx = region->winrct.xmin;
191 const int sy = region->winrct.ymin;
192
193 const float a = 0.5f * float(getsizex) * block->winmat[0][0];
194 const float b = 0.5f * float(getsizex) * block->winmat[1][0];
195 const float c = 0.5f * float(getsizex) * (1.0f + block->winmat[3][0]);
196
197 const float d = 0.5f * float(getsizey) * block->winmat[0][1];
198 const float e = 0.5f * float(getsizey) * block->winmat[1][1];
199 const float f = 0.5f * float(getsizey) * (1.0f + block->winmat[3][1]);
200
201 const float px = *x - sx;
202 const float py = *y - sy;
203
204 *y = (a * (py - f) + d * (c - px)) / (a * e - d * b);
205 *x = (px - b * (*y) - c) / a;
206
207 if (block->panel) {
208 *x -= block->panel->ofsx;
209 *y -= block->panel->ofsy;
210 }
211}
212
214 const uiBlock *block,
215 rctf *rct_dst,
216 const rctf *rct_src)
217{
218 *rct_dst = *rct_src;
219 ui_window_to_block_fl(region, block, &rct_dst->xmin, &rct_dst->ymin);
220 ui_window_to_block_fl(region, block, &rct_dst->xmax, &rct_dst->ymax);
221}
222
223void ui_window_to_block(const ARegion *region, const uiBlock *block, int *x, int *y)
224{
225 float fx = *x;
226 float fy = *y;
227
228 ui_window_to_block_fl(region, block, &fx, &fy);
229
230 *x = int(lround(fx));
231 *y = int(lround(fy));
232}
233
234void ui_window_to_region(const ARegion *region, int *x, int *y)
235{
236 *x -= region->winrct.xmin;
237 *y -= region->winrct.ymin;
238}
239
240void ui_window_to_region_rcti(const ARegion *region, rcti *rect_dst, const rcti *rct_src)
241{
242 rect_dst->xmin = rct_src->xmin - region->winrct.xmin;
243 rect_dst->xmax = rct_src->xmax - region->winrct.xmin;
244 rect_dst->ymin = rct_src->ymin - region->winrct.ymin;
245 rect_dst->ymax = rct_src->ymax - region->winrct.ymin;
246}
247
248void ui_window_to_region_rctf(const ARegion *region, rctf *rect_dst, const rctf *rct_src)
249{
250 rect_dst->xmin = rct_src->xmin - region->winrct.xmin;
251 rect_dst->xmax = rct_src->xmax - region->winrct.xmin;
252 rect_dst->ymin = rct_src->ymin - region->winrct.ymin;
253 rect_dst->ymax = rct_src->ymax - region->winrct.ymin;
254}
255
256void ui_region_to_window(const ARegion *region, int *x, int *y)
257{
258 *x += region->winrct.xmin;
259 *y += region->winrct.ymin;
260}
261
262int uiBlock::but_index(const uiBut *but) const
263{
264 BLI_assert(!buttons.is_empty() && but);
265 auto index = std::distance(
266 buttons.begin(),
267 std::find_if(buttons.begin(), buttons.end(), [but](const std::unique_ptr<uiBut> &test) {
268 return test.get() == but;
269 }));
270 BLI_assert(index != std::distance(buttons.begin(), buttons.end()));
271 return index;
272}
273
274uiBut *uiBlock::next_but(const uiBut *but) const
275{
276 const int idx = this->but_index(but) + 1;
277 return idx < this->buttons.size() ? this->buttons[idx].get() : nullptr;
278}
279
280uiBut *uiBlock::prev_but(const uiBut *but) const
281{
282 const int idx = this->but_index(but) - 1;
283 return idx >= 0 ? this->buttons[idx].get() : nullptr;
284}
285
287{
288 int64_t target_index = this->but_index(but);
289 this->buttons.remove(target_index);
290}
291
293{
294 return !this->buttons.is_empty() ? this->buttons.first().get() : nullptr;
295}
296
298{
299 return !this->buttons.is_empty() ? this->buttons.last().get() : nullptr;
300}
301
302static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
303{
304 int sepr_flex_len = 0;
305 for (const std::unique_ptr<uiBut> &but : block->buttons) {
306 if (but->type == UI_BTYPE_SEPR_SPACER) {
307 sepr_flex_len++;
308 }
309 }
310
311 if (sepr_flex_len == 0) {
312 return;
313 }
314
315 rcti rect;
316 ui_but_to_pixelrect(&rect, region, block, block->buttons.last().get());
317 const float buttons_width = std::ceil(float(rect.xmax) + UI_HEADER_OFFSET);
318 const float region_width = float(region->winx);
319
320 if (region_width <= buttons_width) {
321 return;
322 }
323
324 /* We could get rid of this loop if we agree on a max number of spacer */
325 Vector<int, 8> spacers_pos;
326 for (const std::unique_ptr<uiBut> &but : block->buttons) {
327 if (but->type == UI_BTYPE_SEPR_SPACER) {
328 ui_but_to_pixelrect(&rect, region, block, but.get());
329 spacers_pos.append(rect.xmax + UI_HEADER_OFFSET);
330 }
331 }
332
333 const float view_scale_x = UI_view2d_scale_get_x(&region->v2d);
334 const float segment_width = region_width / float(sepr_flex_len);
335 float offset = 0, remaining_space = region_width - buttons_width;
336 int i = 0;
337 for (const std::unique_ptr<uiBut> &but : block->buttons) {
338 BLI_rctf_translate(&but->rect, std::floor(offset / view_scale_x), 0.0f);
339 if (but->type == UI_BTYPE_SEPR_SPACER) {
340 /* How much the next block overlap with the current segment */
341 int overlap = ((i == sepr_flex_len - 1) ? buttons_width - spacers_pos[i] :
342 (spacers_pos[i + 1] - spacers_pos[i]) / 2);
343 const int segment_end = segment_width * (i + 1);
344 const int spacer_end = segment_end - overlap;
345 const int spacer_sta = spacers_pos[i] + offset;
346 if (spacer_end > spacer_sta) {
347 const float step = min_ff(remaining_space, spacer_end - spacer_sta);
348 remaining_space -= step;
349 offset += step;
350 }
351 i++;
352 }
353 }
355}
356
357static void ui_update_window_matrix(const wmWindow *window, const ARegion *region, uiBlock *block)
358{
359 /* window matrix and aspect */
360 if (region && region->runtime->visible) {
361 /* Get projection matrix which includes View2D translation and zoom. */
363 block->aspect = 2.0f / fabsf(region->winx * block->winmat[0][0]);
364 }
365 else {
366 /* No sub-window created yet, for menus for example, so we use the main
367 * window instead, since buttons are created there anyway. */
368 const blender::int2 win_size = WM_window_native_pixel_size(window);
369 const rcti winrct = {0, win_size[0] - 1, 0, win_size[1] - 1};
370
371 wmGetProjectionMatrix(block->winmat, &winrct);
372 block->aspect = 2.0f / fabsf(win_size[0] * block->winmat[0][0]);
373 }
374}
375
376void ui_region_winrct_get_no_margin(const ARegion *region, rcti *r_rect)
377{
378 uiBlock *block = static_cast<uiBlock *>(region->runtime->uiblocks.first);
379 if (block && (block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_PIE_MENU) == 0) {
380 BLI_rcti_rctf_copy_floor(r_rect, &block->rect);
381 BLI_rcti_translate(r_rect, region->winrct.xmin, region->winrct.ymin);
382 }
383 else {
384 *r_rect = region->winrct;
385 }
386}
387
388/* ******************* block calc ************************* */
389
390void UI_block_translate(uiBlock *block, float x, float y)
391{
392 for (const std::unique_ptr<uiBut> &but : block->buttons) {
393 BLI_rctf_translate(&but->rect, x, y);
394 }
395
396 BLI_rctf_translate(&block->rect, x, y);
397}
398
399static bool ui_but_is_row_alignment_group(const uiBut *left, const uiBut *right)
400{
401 const bool is_same_align_group = (left->alignnr && (left->alignnr == right->alignnr));
402 return is_same_align_group && (left->rect.xmin < right->rect.xmin);
403}
404
405static void ui_block_bounds_calc_text(uiBlock *block, float offset)
406{
407 if (block->buttons.is_empty()) {
408 return;
409 }
410 const uiStyle *style = UI_style_get();
411 std::unique_ptr<uiBut> *col_bt;
412 int i = 0, j, x1addval = offset;
413
414 UI_fontstyle_set(&style->widget);
415 std::unique_ptr<uiBut> *end = block->buttons.end();
416
417 std::unique_ptr<uiBut> *init_col_bt = block->buttons.begin();
418 for (std::unique_ptr<uiBut> *bt = init_col_bt; bt < end; bt++) {
420 j = BLF_width(style->widget.uifont_id, (*bt)->drawstr.c_str(), (*bt)->drawstr.size());
421
422 i = std::max(j, i);
423 }
424
425 /* Skip all buttons that are in a horizontal alignment group.
426 * We don't want to split them apart (but still check the row's width and apply current
427 * offsets). */
428 if (bt + 1 < end && ui_but_is_row_alignment_group((*bt).get(), bt[1].get())) {
429 int width = 0;
430 const int alignnr = (*bt)->alignnr;
431 for (col_bt = bt; col_bt < end && (*col_bt)->alignnr == alignnr; col_bt++) {
432 width += BLI_rctf_size_x(&(*col_bt)->rect);
433 (*col_bt)->rect.xmin += x1addval;
434 (*col_bt)->rect.xmax += x1addval;
435 }
436 i = std::max(width, i);
437 /* Give the following code the last button in the alignment group, there might have to be a
438 * split immediately after. */
439 bt = col_bt != end ? col_bt-- : nullptr;
440 }
441
442 if (bt < end && (bt + 1 < end) && (*bt)->rect.xmin < bt[1]->rect.xmin) {
443 /* End of this column, and it's not the last one. */
444 for (col_bt = init_col_bt; (col_bt - 1) != bt; col_bt++) {
445 (*col_bt)->rect.xmin = x1addval;
446 (*col_bt)->rect.xmax = x1addval + i + block->bounds;
447
448 ui_but_update((*col_bt).get()); /* clips text again */
449 }
450
451 /* And we prepare next column. */
452 x1addval += i + block->bounds;
453 i = 0;
454 init_col_bt = col_bt;
455 }
456 }
457
458 /* Last column. */
459 for (col_bt = init_col_bt; col_bt < end; col_bt++) {
460 /* Recognize a horizontally arranged alignment group and skip its items. */
461 if ((col_bt + 1 < end) && ui_but_is_row_alignment_group((*col_bt).get(), col_bt[1].get())) {
462 const int alignnr = (*col_bt)->alignnr;
463 for (; col_bt < end && (*col_bt)->alignnr == alignnr; col_bt++) {
464 /* pass */
465 }
466 }
467 if (col_bt == end) {
468 break;
469 }
470
471 (*col_bt)->rect.xmin = x1addval;
472 (*col_bt)->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
473
474 ui_but_update((*col_bt).get()); /* clips text again */
475 }
476}
477
479{
480 if (block->buttons.is_empty()) {
481 if (block->panel) {
482 block->rect.xmin = 0.0;
483 block->rect.xmax = block->panel->sizex;
484 block->rect.ymin = 0.0;
485 block->rect.ymax = block->panel->sizey;
486 }
487 }
488 else {
489
490 BLI_rctf_init_minmax(&block->rect);
491
492 for (const std::unique_ptr<uiBut> &bt : block->buttons) {
493 BLI_rctf_union(&block->rect, &bt->rect);
494 }
495
496 block->rect.xmin -= block->bounds;
497 block->rect.ymin -= block->bounds;
498 block->rect.xmax += block->bounds;
499 block->rect.ymax += block->bounds;
500 }
501
502 block->rect.xmax = block->rect.xmin + max_ff(BLI_rctf_size_x(&block->rect), block->minbounds);
503
504 /* hardcoded exception... but that one is annoying with larger safety */
505 uiBut *bt = block->first_but();
506 const int xof = ((bt && STRPREFIX(bt->str.c_str(), "ERROR")) ? 10 : 40) * UI_SCALE_FAC;
507
508 block->safety.xmin = block->rect.xmin - xof;
509 block->safety.ymin = block->rect.ymin - xof;
510 block->safety.xmax = block->rect.xmax + xof;
511 block->safety.ymax = block->rect.ymax + xof;
512}
513
515{
516 /* NOTE: this is used for the splash where window bounds event has not been
517 * updated by ghost, get the window bounds from ghost directly */
518
519 /* Clamp to the window size. */
520 const blender::int2 win_size = WM_window_native_pixel_size(window);
521
523
524 const int width = BLI_rctf_size_x(&block->rect);
525 const int height = BLI_rctf_size_y(&block->rect);
526
527 const int startx = (win_size[0] * 0.5f) - (width * 0.5f);
528 const int starty = (win_size[1] * 0.5f) - (height * 0.5f);
529
530 UI_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
531
532 /* now recompute bounds and safety */
534}
535
537{
538 const blender::int2 xy(block->handle->region->winrct.xmin, block->handle->region->winrct.ymin);
539 const int margin = int(12.0f * UI_SCALE_FAC);
541 UI_block_translate(block, xy[0] - block->rect.xmin + margin, xy[1] - block->rect.ymin + margin);
543}
544
546{
547 const int xy[2] = {
548 int(block->pie_data.pie_center_spawned[0]),
549 int(block->pie_data.pie_center_spawned[1]),
550 };
551
552 UI_block_translate(block, xy[0], xy[1]);
553
554 /* now recompute bounds and safety */
556}
557
559 wmWindow *window, uiBlock *block, eBlockBoundsCalc bounds_calc, const int xy[2], int r_xy[2])
560{
561 const int oldbounds = block->bounds;
562
563 /* compute mouse position with user defined offset */
565
566 /* Clamp to the window size. */
567 const blender::int2 win_size = WM_window_native_pixel_size(window);
568
569 int oldwidth = BLI_rctf_size_x(&block->rect);
570 int oldheight = BLI_rctf_size_y(&block->rect);
571
572 /* first we ensure wide enough text bounds */
573 if (bounds_calc == UI_BLOCK_BOUNDS_POPUP_MENU) {
574 if (block->flag & UI_BLOCK_LOOP) {
575 block->bounds = 2.5f * UI_UNIT_X;
576 ui_block_bounds_calc_text(block, block->rect.xmin);
577 }
578 }
579
580 /* next we recompute bounds */
581 block->bounds = oldbounds;
583
584 /* and we adjust the position to fit within window */
585 const int width = BLI_rctf_size_x(&block->rect);
586 const int height = BLI_rctf_size_y(&block->rect);
587
588 /* avoid divide by zero below, caused by calling with no UI, but better not crash */
589 oldwidth = oldwidth > 0 ? oldwidth : std::max(1, width);
590 oldheight = oldheight > 0 ? oldheight : std::max(1, height);
591
592 /* offset block based on mouse position, user offset is scaled
593 * along in case we resized the block in ui_block_bounds_calc_text */
594 rcti rect;
595 const int raw_x = rect.xmin = xy[0] + block->rect.xmin +
596 (block->bounds_offset[0] * width) / oldwidth;
597 int raw_y = rect.ymin = xy[1] + block->rect.ymin +
598 (block->bounds_offset[1] * height) / oldheight;
599 rect.xmax = rect.xmin + width;
600 rect.ymax = rect.ymin + height;
601
602 rcti rect_bounds;
603 const int margin = UI_SCREEN_MARGIN;
604 rect_bounds.xmin = margin;
605 rect_bounds.ymin = margin;
606 rect_bounds.xmax = win_size[0] - margin;
607 rect_bounds.ymax = win_size[1] - UI_POPUP_MENU_TOP;
608
609 int ofs_dummy[2];
610 BLI_rcti_clamp(&rect, &rect_bounds, ofs_dummy);
611 UI_block_translate(block, rect.xmin - block->rect.xmin, rect.ymin - block->rect.ymin);
612
613 /* now recompute bounds and safety */
615
616 /* If given, adjust input coordinates such that they would generate real final popup position.
617 * Needed to handle correctly floating panels once they have been dragged around,
618 * see #52999. */
619 if (r_xy) {
620 r_xy[0] = xy[0] + block->rect.xmin - raw_x;
621 r_xy[1] = xy[1] + block->rect.ymin - raw_y;
622 }
623}
624
625void UI_block_bounds_set_normal(uiBlock *block, int addval)
626{
627 if (block == nullptr) {
628 return;
629 }
630
631 block->bounds = addval;
633}
634
635void UI_block_bounds_set_text(uiBlock *block, int addval)
636{
637 block->bounds = addval;
639}
640
641void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
642{
643 block->bounds = addval;
645 if (bounds_offset != nullptr) {
646 block->bounds_offset[0] = bounds_offset[0];
647 block->bounds_offset[1] = bounds_offset[1];
648 }
649 else {
650 block->bounds_offset[0] = 0;
651 block->bounds_offset[1] = 0;
652 }
653}
654
655void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2])
656{
657 block->bounds = addval;
659 if (bounds_offset != nullptr) {
660 copy_v2_v2_int(block->bounds_offset, bounds_offset);
661 }
662 else {
664 }
665}
666
667void UI_block_bounds_set_centered(uiBlock *block, int addval)
668{
669 block->bounds = addval;
671}
672
673void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy)
674{
675 block->rect.xmin = minx;
676 block->rect.ymin = miny;
677 block->rect.xmax = maxx;
678 block->rect.ymax = maxy;
680}
681
683{
684 if (but->type == UI_BTYPE_NUM) {
685 return ((uiButNumber *)but)->precision;
686 }
687 if (but->type == UI_BTYPE_NUM_SLIDER) {
688 return ((uiButNumberSlider *)but)->precision;
689 }
691 return 1.0f;
692}
693
695{
696 if (but->type == UI_BTYPE_NUM) {
697 return ((uiButNumber *)but)->step_size;
698 }
699 if (but->type == UI_BTYPE_NUM_SLIDER) {
700 return ((uiButNumberSlider *)but)->step_size;
701 }
703 return 1.0f;
704}
705
706static bool ui_but_hide_fraction(uiBut *but, double value)
707{
708 /* Hide the fraction if both the value and the step are exact integers. */
709 if (floor(value) == value) {
711
712 if (floorf(step) == step) {
713 /* Don't hide if it has any unit except frame count. */
714 switch (UI_but_unit_type_get(but)) {
715 case PROP_UNIT_NONE:
716 case PROP_UNIT_TIME:
717 return true;
718
719 default:
720 return false;
721 }
722 }
723 }
724
725 return false;
726}
727
728static int ui_but_calc_float_precision(uiBut *but, double value)
729{
730 if (ui_but_hide_fraction(but, value)) {
731 return 0;
732 }
733
734 int prec = int(ui_but_get_float_precision(but));
735
736 /* first check for various special cases:
737 * * If button is radians, we want additional precision (see #39861).
738 * * If prec is not set, we fall back to a simple default */
739 if (ui_but_is_unit_radians(but) && prec < 5) {
740 prec = 5;
741 }
742 else if (prec == -1) {
743 prec = (but->hardmax < 10.001f) ? 3 : 2;
744 }
745 else {
747 }
748
749 return UI_calc_float_precision(prec, value);
750}
751
752/* ************** BLOCK ENDING FUNCTION ************* */
753
754bool ui_but_rna_equals(const uiBut *a, const uiBut *b)
755{
756 return ui_but_rna_equals_ex(a, &b->rnapoin, b->rnaprop, b->rnaindex);
757}
758
760 const PointerRNA *ptr,
761 const PropertyRNA *prop,
762 int index)
763{
764 if (but->rnapoin.data != ptr->data) {
765 return false;
766 }
767 if (but->rnaprop != prop || but->rnaindex != index) {
768 return false;
769 }
770
771 return true;
772}
773
774/* NOTE: if `but->poin` is allocated memory for every `uiDefBut*`, things fail. */
775static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
776{
777 if (but->type != oldbut->type) {
778 return false;
779 }
780
781 if (but->identity_cmp_func) {
782 /* If the buttons have their own identity comparator callbacks (and they match), use this to
783 * determine equality. */
784 if (but->identity_cmp_func && (but->type == oldbut->type) &&
785 (but->identity_cmp_func == oldbut->identity_cmp_func))
786 {
787 /* Test if the comparison is symmetrical (if a == b then b == a), may help catch some issues.
788 */
789 BLI_assert(but->identity_cmp_func(but, oldbut) == but->identity_cmp_func(oldbut, but));
790
791 return but->identity_cmp_func(but, oldbut);
792 }
793 }
794
795 /* various properties are being compared here, hopefully sufficient
796 * to catch all cases, but it is simple to add more checks later */
797 if (but->retval != oldbut->retval) {
798 return false;
799 }
800 if (!ui_but_rna_equals(but, oldbut)) {
801 return false;
802 }
803 if (but->func != oldbut->func) {
804 return false;
805 }
806 /* Compares the contained function pointers. Buttons with different apply functions can be
807 * considered to do different things, and as such do not equal each other. */
808 if (but->apply_func.target<void(bContext &)>() != oldbut->apply_func.target<void(bContext &)>())
809 {
810 return false;
811 }
812 if (but->funcN != oldbut->funcN) {
813 return false;
814 }
815 if (!ELEM(oldbut->func_arg1, oldbut, but->func_arg1)) {
816 return false;
817 }
818 if (!ELEM(oldbut->func_arg2, oldbut, but->func_arg2)) {
819 return false;
820 }
821 if (but->block_create_func != oldbut->block_create_func) {
822 return false;
823 }
824 if (!but->funcN && ((but->poin != oldbut->poin && (uiBut *)oldbut->poin != oldbut) ||
825 (but->pointype != oldbut->pointype)))
826 {
827 return false;
828 }
829 if (but->optype != oldbut->optype) {
830 return false;
831 }
832 if (but->dragtype != oldbut->dragtype) {
833 return false;
834 }
835
836 if (but->type == UI_BTYPE_VIEW_ITEM) {
837 uiButViewItem *but_item = (uiButViewItem *)but;
838 uiButViewItem *oldbut_item = (uiButViewItem *)oldbut;
839 if (!but_item->view_item || !oldbut_item->view_item ||
840 !UI_view_item_matches(*but_item->view_item, *oldbut_item->view_item))
841 {
842 return false;
843 }
844 }
845
846 return true;
847}
848
849static uiBut *ui_but_find_old(uiBlock *block_old,
850 const uiBut *but_new,
851 const blender::Set<const uiBut *> &ignore_old_buttons)
852{
853 for (const std::unique_ptr<uiBut> &but : block_old->buttons) {
854 if (!ignore_old_buttons.contains(but.get()) && ui_but_equals_old(but_new, but.get())) {
855 return but.get();
856 }
857 }
858 return nullptr;
859}
860
861uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new)
862{
863 return ui_but_find_old(block_old, but_new, {});
864}
865
866static std::optional<int64_t> ui_but_find_old_idx(
867 uiBlock *block_old,
868 const uiBut *but_new,
869 const blender::Set<const uiBut *> &ignore_old_buttons = {})
870{
871 int64_t i = 0;
872 for (const std::unique_ptr<uiBut> &but : block_old->buttons) {
873 if (!ignore_old_buttons.contains(but.get()) && ui_but_equals_old(but_new, but.get())) {
874 return i;
875 }
876 i++;
877 }
878 return std::nullopt;
879}
880
881uiBut *ui_but_find_new(uiBlock *block_new, const uiBut *but_old)
882{
883 for (const std::unique_ptr<uiBut> &but : block_new->buttons) {
884 if (ui_but_equals_old(but.get(), but_old)) {
885 return but.get();
886 }
887 }
888 return nullptr;
889}
890
891static bool ui_but_extra_icons_equals_old(const uiButExtraOpIcon *new_extra_icon,
892 const uiButExtraOpIcon *old_extra_icon)
893{
894 return (new_extra_icon->optype_params->optype == old_extra_icon->optype_params->optype) &&
895 (new_extra_icon->icon == old_extra_icon->icon);
896}
897
899 const uiBut *old_but)
900{
901 LISTBASE_FOREACH (uiButExtraOpIcon *, op_icon, &old_but->extra_op_icons) {
902 if (ui_but_extra_icons_equals_old(new_extra_icon, op_icon)) {
903 return op_icon;
904 }
905 }
906 return nullptr;
907}
908
909static void ui_but_extra_icons_update_from_old_but(const uiBut *new_but, const uiBut *old_but)
910{
911 /* Specifically for keeping some state info for the active button. */
912 BLI_assert(old_but->active || old_but->semi_modal_state);
913
914 LISTBASE_FOREACH (uiButExtraOpIcon *, new_extra_icon, &new_but->extra_op_icons) {
915 uiButExtraOpIcon *old_extra_icon = ui_but_extra_icon_find_old(new_extra_icon, old_but);
916 /* Keep the highlighting state, and let handling update it later. */
917 if (old_extra_icon) {
918 new_extra_icon->highlighted = old_extra_icon->highlighted;
919 }
920 }
921}
922
934{
935 BLI_assert(oldbut->active || oldbut->semi_modal_state);
936
937 /* flags from the buttons we want to refresh, may want to add more here... */
938 const int flag_copy = UI_BUT_REDALERT | UI_HAS_ICON | UI_SELECT_DRAW;
939 const int drawflag_copy = UI_BUT_HAS_QUICK_TOOLTIP;
940
941 /* still stuff needs to be copied */
942 oldbut->rect = but->rect;
943 oldbut->context = but->context; /* set by Layout */
944
945 /* drawing */
946 oldbut->icon = but->icon;
947 oldbut->iconadd = but->iconadd;
948 oldbut->alignnr = but->alignnr;
949
950 /* typically the same pointers, but not on undo/redo */
951 /* XXX some menu buttons store button itself in but->poin. Ugly */
952 if (oldbut->poin != (char *)oldbut) {
953 std::swap(oldbut->poin, but->poin);
954 std::swap(oldbut->func_argN, but->func_argN);
955 }
956
957 std::swap(oldbut->rename_full_func, but->rename_full_func);
958 std::swap(oldbut->pushed_state_func, but->pushed_state_func);
959
960 /* Move tooltip from new to old. */
961 std::swap(oldbut->tip_func, but->tip_func);
962 std::swap(oldbut->tip_arg, but->tip_arg);
963 std::swap(oldbut->tip_custom_func, but->tip_custom_func);
964 std::swap(oldbut->tip_arg_free, but->tip_arg_free);
965 std::swap(oldbut->tip_quick_func, but->tip_quick_func);
966
967 oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy);
968 oldbut->drawflag = (oldbut->drawflag & ~drawflag_copy) | (but->drawflag & drawflag_copy);
969
971 std::swap(but->extra_op_icons, oldbut->extra_op_icons);
972
973 if (oldbut->type == UI_BTYPE_SEARCH_MENU) {
974 uiButSearch *search_oldbut = (uiButSearch *)oldbut, *search_but = (uiButSearch *)but;
975
976 std::swap(search_oldbut->arg_free_fn, search_but->arg_free_fn);
977 std::swap(search_oldbut->arg, search_but->arg);
978 }
979
980 /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position
981 * when scrolling without moving mouse (see #28432) */
982 if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
983 oldbut->hardmax = but->hardmax;
984 }
985
986 switch (oldbut->type) {
987 case UI_BTYPE_PROGRESS: {
988 uiButProgress *progress_oldbut = (uiButProgress *)oldbut;
989 uiButProgress *progress_but = (uiButProgress *)but;
990 progress_oldbut->progress_factor = progress_but->progress_factor;
991 break;
992 }
993 case UI_BTYPE_SEPR_LINE: {
994 uiButSeparatorLine *line_oldbut = (uiButSeparatorLine *)oldbut;
995 uiButSeparatorLine *line_but = (uiButSeparatorLine *)but;
996 line_oldbut->is_vertical = line_but->is_vertical;
997 break;
998 }
999 case UI_BTYPE_LABEL: {
1000 uiButLabel *label_oldbut = (uiButLabel *)oldbut;
1001 uiButLabel *label_but = (uiButLabel *)but;
1002 label_oldbut->alpha_factor = label_but->alpha_factor;
1003 break;
1004 }
1005 case UI_BTYPE_SCROLL: {
1006 uiButScrollBar *scroll_oldbut = (uiButScrollBar *)oldbut;
1007 uiButScrollBar *scroll_but = (uiButScrollBar *)but;
1008 scroll_oldbut->visual_height = scroll_but->visual_height;
1009 break;
1010 }
1011 case UI_BTYPE_VIEW_ITEM: {
1012 uiButViewItem *view_item_oldbut = (uiButViewItem *)oldbut;
1013 uiButViewItem *view_item_newbut = (uiButViewItem *)but;
1015 *view_item_oldbut->view_item);
1016 std::swap(view_item_newbut->view_item, view_item_oldbut->view_item);
1017 break;
1018 }
1019 default:
1020 break;
1021 }
1022
1023 /* move/copy string from the new button to the old */
1024 /* needed for alt+mouse wheel over enums */
1025 std::swap(but->str, oldbut->str);
1026
1027 if (but->dragpoin) {
1028 std::swap(but->dragpoin, oldbut->dragpoin);
1029 }
1030 if (but->imb) {
1031 std::swap(but->imb, oldbut->imb);
1032 }
1033
1034 /* NOTE: if layout hasn't been applied yet, it uses old button pointers... */
1035}
1036
1061 blender::Set<const uiBut *> &matched_old_buttons,
1062 std::unique_ptr<uiBut> *but_uptr,
1063 std::optional<int64_t> *but_old_idx)
1064{
1065 uiBlock *oldblock = block->oldblock;
1066 uiBut *but = but_uptr->get();
1067
1068#if 0
1069 /* Simple method - search every time. Keep this for easy testing of the "fast path." */
1070 uiBut *oldbut = ui_but_find_old(oldblock, but, matched_old_buttons);
1071 UNUSED_VARS(but_old_p);
1072#else
1073 BLI_assert(!but_old_idx->has_value() || oldblock->buttons.index_range().contains(**but_old_idx));
1074
1075 /* As long as old and new buttons are aligned, avoid loop-in-loop (calling #ui_but_find_old). */
1076 std::unique_ptr<uiBut> *oldbut_uptr;
1077 if (LIKELY(but_old_idx->has_value() &&
1078 /* Ignore previously matched buttons. */
1079 !matched_old_buttons.contains(oldblock->buttons[**but_old_idx].get()) &&
1080 ui_but_equals_old(but, oldblock->buttons[**but_old_idx].get())))
1081 {
1082 oldbut_uptr = &oldblock->buttons[**but_old_idx];
1083 }
1084 else {
1085 /* Fall back to block search. */
1086 *but_old_idx = ui_but_find_old_idx(oldblock, but, matched_old_buttons);
1087 oldbut_uptr = but_old_idx->has_value() ? &oldblock->buttons[**but_old_idx] : nullptr;
1088 }
1089 /* Increase for next iteration. */
1090 *but_old_idx = (but_old_idx->has_value() &&
1091 (but_old_idx->value() + 1 < oldblock->buttons.size())) ?
1092 std::optional{but_old_idx->value() + 1} :
1093 std::nullopt;
1094#endif
1095
1096 bool found_active = false;
1097
1098 if (!oldbut_uptr) {
1099 return false;
1100 }
1101 uiBut *oldbut = oldbut_uptr->get();
1102
1103 BLI_assert(!matched_old_buttons.contains(oldbut));
1104
1105 if (oldbut->active || oldbut->semi_modal_state) {
1106 /* Move button over from oldblock to new block. */
1107 oldbut_uptr->swap(*but_uptr);
1108 BLI_assert(but_uptr->get() == oldbut);
1109 /* `but` was moved to oldblock, taking oldbut place. */
1110 BLI_assert(!matched_old_buttons.contains(but));
1111 matched_old_buttons.add(but);
1112
1113 /* Add the old button to the button groups in the new block. */
1114 ui_button_group_replace_but_ptr(block, but, oldbut);
1115 oldbut->block = block;
1116
1118
1119 if (!BLI_listbase_is_empty(&block->butstore)) {
1120 UI_butstore_register_update(block, oldbut, but);
1121 }
1122
1123 found_active = true;
1124 }
1125 else {
1126 matched_old_buttons.add(oldbut);
1127 int flag_copy = UI_BUT_DRAG_MULTI;
1128
1129 /* Stupid special case: The active button may be inside (as in, overlapped on top) a row
1130 * button which we also want to keep highlighted then. */
1132 flag_copy |= UI_HOVER;
1133 }
1134
1135 but->flag = (but->flag & ~flag_copy) | (oldbut->flag & flag_copy);
1136 }
1137
1138 return found_active;
1139}
1140
1142 const bContext *C, ARegion *region, uiBlock *block, uiBut *but, const bool remove_on_failure)
1143{
1144 bool activate = false, found = false, isactive = false;
1145
1146 uiBlock *oldblock = block->oldblock;
1147 if (!oldblock) {
1148 activate = true;
1149 }
1150 else {
1151 uiBut *oldbut = ui_but_find_old(oldblock, but);
1152 if (oldbut) {
1153 found = true;
1154
1155 if (oldbut->active) {
1156 isactive = true;
1157 }
1158 }
1159 }
1160 if ((activate == true) || (found == false)) {
1161 /* There might still be another active button. */
1162 uiBut *old_active = ui_region_find_active_but(region);
1163 if (old_active) {
1164 ui_but_active_free(C, old_active);
1165 }
1166
1167 ui_but_activate_event((bContext *)C, region, but);
1168 }
1169 else if ((found == true) && (isactive == false)) {
1170 if (remove_on_failure) {
1171 if (but->layout) {
1172 ui_layout_remove_but(but->layout, but);
1173 }
1174 ui_but_free(C, but);
1175 block->remove_but(but);
1176 }
1177 return false;
1178 }
1179
1180 return true;
1181}
1182
1183bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBut *but)
1184{
1185 return UI_but_active_only_ex(C, region, block, but, true);
1186}
1187
1189{
1190 /* Running this command before end-block has run, means buttons that open menus
1191 * won't have those menus correctly positioned, see #83539. */
1192 BLI_assert(block->endblock);
1193
1194 bool done = false;
1195 for (const std::unique_ptr<uiBut> &but : block->buttons) {
1196 if (but->flag & UI_BUT_ACTIVATE_ON_INIT) {
1197 but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
1198 if (ui_but_is_editable(but.get())) {
1199 if (UI_but_active_only_ex(C, region, block, but.get(), false)) {
1200 done = true;
1201 break;
1202 }
1203 }
1204 }
1205 }
1206
1207 if (done) {
1208 /* Run this in a second pass since it's possible activating the button
1209 * removes the buttons being looped over. */
1210 for (const std::unique_ptr<uiBut> &but : block->buttons) {
1211 but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
1212 }
1213 }
1214
1215 return done;
1216}
1217
1218void UI_but_execute(const bContext *C, ARegion *region, uiBut *but)
1219{
1220 void *active_back;
1221 ui_but_execute_begin((bContext *)C, region, but, &active_back);
1222 /* Value is applied in begin. No further action required. */
1223 ui_but_execute_end((bContext *)C, region, but, active_back);
1224}
1225
1226/* use to check if we need to disable undo, but don't make any changes
1227 * returns false if undo needs to be disabled. */
1228static bool ui_but_is_rna_undo(const uiBut *but)
1229{
1230 if (but->rnaprop == nullptr) {
1231 return true;
1232 }
1233
1234 /* No owner or type known. Assume we do not undo push as it may be a property from
1235 * the preferences stored outside datablocks. */
1236 if (but->rnapoin.owner_id == nullptr || but->rnapoin.type == nullptr) {
1237 return false;
1238 }
1239
1241}
1242
1243/* assigns automatic keybindings to menu items for fast access
1244 * (underline key in menu) */
1246{
1247 uint menu_key_mask = 0;
1248 int tot_missing = 0;
1249
1250 /* only do it before bounding */
1251 if (block->rect.xmin != block->rect.xmax) {
1252 return;
1253 }
1254
1255 for (int pass = 0; pass < 2; pass++) {
1256 /* 2 Passes: One for first letter only, second for any letter if the first pass fails.
1257 * Run first pass on all buttons so first word chars always get first priority. */
1258
1259 for (const std::unique_ptr<uiBut> &but : block->buttons) {
1260 if (!ELEM(but->type,
1268
1269 /* For PIE-menus. */
1270 UI_BTYPE_ROW) ||
1271 (but->flag & UI_HIDDEN))
1272 {
1273 continue;
1274 }
1275
1276 if (pass == 0 && ELEM(but->type, UI_BTYPE_ICON_TOGGLE, UI_BTYPE_ICON_TOGGLE_N)) {
1277 /* Until 4.4, toggles did not get accelerator keys. Ignore them on the first pass to keep
1278 * the most-used accelerator keys (those on the first letter) the same. In general it seems
1279 * more desired to give operators priority over toggles. #134492 */
1280 continue;
1281 }
1282
1283 if (but->menu_key != '\0') {
1284 continue;
1285 }
1286
1287 if (but->str.empty()) {
1288 continue;
1289 }
1290
1291 const char *str_pt = but->str.c_str();
1292 uchar menu_key;
1293 do {
1294 menu_key = tolower(*str_pt);
1295 if ((menu_key >= 'a' && menu_key <= 'z') && !(menu_key_mask & 1 << (menu_key - 'a'))) {
1296 menu_key_mask |= 1 << (menu_key - 'a');
1297 break;
1298 }
1299
1300 if (pass == 0) {
1301 /* Skip to next delimiter on first pass (be picky) */
1302 while (isalpha(*str_pt)) {
1303 str_pt++;
1304 }
1305
1306 if (*str_pt) {
1307 str_pt++;
1308 }
1309 }
1310 else {
1311 /* just step over every char second pass and find first usable key */
1312 str_pt++;
1313 }
1314 } while (*str_pt);
1315
1316 if (*str_pt) {
1317 but->menu_key = menu_key;
1318 }
1319 else {
1320 /* run second pass */
1321 tot_missing++;
1322 }
1323
1324 /* if all keys have been used just exit, unlikely */
1325 if (menu_key_mask == (1 << 26) - 1) {
1326 return;
1327 }
1328 }
1329
1330 /* check if second pass is needed */
1331 if (!tot_missing) {
1332 break;
1333 }
1334 }
1335}
1336
1337void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip)
1338{
1339 if (do_strip && (but->flag & UI_BUT_HAS_SEP_CHAR)) {
1340 const size_t sep_index = but->str.find_first_of(UI_SEP_CHAR);
1341 if (sep_index != std::string::npos) {
1342 but->str = but->str.substr(0, sep_index);
1343 }
1344 but->flag &= ~UI_BUT_HAS_SEP_CHAR;
1345 }
1346
1347 /* without this, just allow stripping of the shortcut */
1348 if (shortcut_str == nullptr) {
1349 return;
1350 }
1351
1352 but->str = fmt::format("{}" UI_SEP_CHAR_S "{}", but->str, shortcut_str);
1353 but->flag |= UI_BUT_HAS_SEP_CHAR;
1354 ui_but_update(but);
1355}
1356
1357/* -------------------------------------------------------------------- */
1363
1364static std::optional<std::string> ui_but_event_operator_string_from_operator(
1365 const bContext *C, wmOperatorCallParams *op_call_params)
1366{
1367 BLI_assert(op_call_params->optype != nullptr);
1368 IDProperty *prop = op_call_params->opptr ?
1369 static_cast<IDProperty *>(op_call_params->opptr->data) :
1370 nullptr;
1371
1373 C, op_call_params->optype->idname, op_call_params->opcontext, prop, true);
1374}
1375
1376static std::optional<std::string> ui_but_event_operator_string_from_menu(const bContext *C,
1377 uiBut *but)
1378{
1379 MenuType *mt = UI_but_menutype_get(but);
1380 BLI_assert(mt != nullptr);
1381
1382 /* Dummy, name is unimportant. */
1383 IDProperty *prop_menu = blender::bke::idprop::create_group(__func__).release();
1384 IDP_AddToGroup(prop_menu, IDP_NewStringMaxSize(mt->idname, sizeof(mt->idname), "name"));
1385
1386 const std::optional<std::string> result = WM_key_event_operator_string(
1387 C, "WM_OT_call_menu", WM_OP_INVOKE_REGION_WIN, prop_menu, true);
1388
1389 IDP_FreeProperty(prop_menu);
1390 return result;
1391}
1392
1393static std::optional<std::string> ui_but_event_operator_string_from_panel(const bContext *C,
1394 uiBut *but)
1395{
1396 using namespace blender;
1399 BLI_assert(pt != nullptr);
1400
1401 /* Dummy, name is unimportant. */
1402 IDProperty *prop_panel = bke::idprop::create_group(__func__).release();
1403 IDP_AddToGroup(prop_panel, IDP_NewStringMaxSize(pt->idname, sizeof(pt->idname), "name"));
1404 IDP_AddToGroup(prop_panel, bke::idprop::create("space_type", pt->space_type).release());
1405 IDP_AddToGroup(prop_panel, bke::idprop::create("region_type", pt->region_type).release());
1406 BLI_SCOPED_DEFER([&]() { IDP_FreeProperty(prop_panel); });
1407
1408 for (int i = 0; i < 2; i++) {
1409 /* FIXME(@ideasman42): We can't reasonably search all configurations - long term. */
1410 IDP_ReplaceInGroup(prop_panel, bke::idprop::create("keep_open", i).release());
1411 if (std::optional<std::string> result = WM_key_event_operator_string(
1412 C, "WM_OT_call_panel", WM_OP_INVOKE_REGION_WIN, prop_panel, true))
1413 {
1414 return result;
1415 }
1416 }
1417
1418 return std::nullopt;
1419}
1420
1421static std::optional<std::string> ui_but_event_operator_string(const bContext *C, uiBut *but)
1422{
1423 if (but->optype != nullptr) {
1425 params.optype = but->optype;
1426 params.opptr = but->opptr;
1427 params.opcontext = but->opcontext;
1429 }
1430 if (UI_but_menutype_get(but) != nullptr) {
1432 }
1433 if (UI_but_paneltype_get(but) != nullptr) {
1435 }
1436
1437 return std::nullopt;
1438}
1439
1440static std::optional<std::string> ui_but_extra_icon_event_operator_string(
1441 const bContext *C, const uiButExtraOpIcon *extra_icon)
1442{
1443 wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon);
1444
1445 if (extra_icon_optype) {
1447 }
1448
1449 return std::nullopt;
1450}
1451
1452static std::optional<std::string> ui_but_event_property_operator_string(const bContext *C,
1453 uiBut *but)
1454{
1455 using namespace blender;
1456 /* Context toggle operator names to check. */
1457
1458 /* NOTE(@ideasman42): This function could use a refactor to generalize button type to operator
1459 * relationship as well as which operators use properties. */
1460 const char *ctx_toggle_opnames[] = {
1461 "WM_OT_context_toggle",
1462 "WM_OT_context_toggle_enum",
1463 "WM_OT_context_cycle_int",
1464 "WM_OT_context_cycle_enum",
1465 "WM_OT_context_cycle_array",
1466 "WM_OT_context_menu_enum",
1467 nullptr,
1468 };
1469
1470 const char *ctx_enum_opnames[] = {
1471 "WM_OT_context_set_enum",
1472 nullptr,
1473 };
1474
1475 const char *ctx_enum_opnames_for_Area_ui_type[] = {
1476 "SCREEN_OT_space_type_set_or_cycle",
1477 nullptr,
1478 };
1479
1480 const char **opnames = ctx_toggle_opnames;
1481 int opnames_len = ARRAY_SIZE(ctx_toggle_opnames);
1482
1483 int prop_enum_value = -1;
1484 bool prop_enum_value_ok = false;
1485 bool prop_enum_value_is_int = false;
1486 const char *prop_enum_value_id = "value";
1487 PointerRNA *ptr = &but->rnapoin;
1488 PropertyRNA *prop = but->rnaprop;
1489 int prop_index = but->rnaindex;
1490 if ((but->type == UI_BTYPE_BUT_MENU) && (but->block->handle != nullptr)) {
1491 uiBut *but_parent = but->block->handle->popup_create_vars.but;
1492 if ((but_parent && but_parent->rnaprop) &&
1493 (RNA_property_type(but_parent->rnaprop) == PROP_ENUM) &&
1494 ELEM(but_parent->menu_create_func,
1498 {
1499 prop_enum_value = int(but->hardmin);
1500 ptr = &but_parent->rnapoin;
1501 prop = but_parent->rnaprop;
1502 prop_enum_value_ok = true;
1503
1504 opnames = ctx_enum_opnames;
1505 opnames_len = ARRAY_SIZE(ctx_enum_opnames);
1506 }
1507 }
1508 /* Don't use the button again. */
1509 but = nullptr;
1510
1511 if (prop == nullptr) {
1512 return std::nullopt;
1513 }
1514
1515 /* This version is only for finding hotkeys for properties.
1516 * These are set via a data-path which is appended to the context,
1517 * manipulated using operators (see #ctx_toggle_opnames). */
1518
1519 if (ptr->owner_id) {
1520 ID *id = ptr->owner_id;
1521
1522 if (GS(id->name) == ID_SCR) {
1523 if (RNA_struct_is_a(ptr->type, &RNA_Area)) {
1524 /* data should be directly on here... */
1525 const char *prop_id = RNA_property_identifier(prop);
1526 /* Hack since keys access 'type', UI shows 'ui_type'. */
1527 if (STREQ(prop_id, "ui_type")) {
1528 prop_id = "type";
1529 prop_enum_value >>= 16;
1530 prop = RNA_struct_find_property(ptr, prop_id);
1531 prop_index = -1;
1532
1533 if (prop_enum_value == -1) {
1534 /* Get the current value for Editor menu. #100652 */
1535 prop_enum_value = RNA_property_enum_get(ptr, prop);
1536 prop_enum_value_ok = (prop_enum_value != -1);
1537 }
1538
1539 opnames = ctx_enum_opnames_for_Area_ui_type;
1540 opnames_len = ARRAY_SIZE(ctx_enum_opnames_for_Area_ui_type);
1541 prop_enum_value_id = "space_type";
1542 prop_enum_value_is_int = true;
1543 }
1544 }
1545 }
1546 }
1547
1548 /* There may be multiple data-paths to the same properties,
1549 * support different variations so key bindings are properly detected no matter which are used.
1550 */
1551 Vector<std::string, 2> data_path_variations;
1552
1553 {
1554 std::optional<std::string> data_path = WM_context_path_resolve_property_full(
1555 C, ptr, prop, prop_index);
1556
1557 /* Always iterate once, even if data-path isn't set. */
1558 data_path_variations.append(data_path.value_or(""));
1559
1560 if (data_path.has_value()) {
1561 StringRef data_path_ref = StringRef(data_path.value());
1562 if (data_path_ref.startswith("scene.tool_settings.")) {
1563 data_path_variations.append(data_path_ref.drop_known_prefix("scene."));
1564 }
1565 }
1566 }
1567
1568 /* We have a data-path! */
1569 for (int data_path_index = 0; data_path_index < data_path_variations.size(); data_path_index++) {
1570 const StringRefNull data_path = data_path_variations[data_path_index];
1571 if (!data_path.is_empty() || (prop_enum_value_ok && prop_enum_value_id)) {
1572 /* Create a property to host the "data_path" property we're sending to the operators. */
1573 IDProperty *prop_path = blender::bke::idprop::create_group(__func__).release();
1574 BLI_SCOPED_DEFER([&]() { IDP_FreeProperty(prop_path); });
1575 if (!data_path.is_empty()) {
1576 IDP_AddToGroup(prop_path, bke::idprop::create("data_path", data_path).release());
1577 }
1578 if (prop_enum_value_ok) {
1579 const EnumPropertyItem *item;
1580 bool free;
1581 RNA_property_enum_items((bContext *)C, ptr, prop, &item, nullptr, &free);
1582 const int index = RNA_enum_from_value(item, prop_enum_value);
1583 if (index != -1) {
1584 IDProperty *prop_value;
1585 if (prop_enum_value_is_int) {
1586 const int value = item[index].value;
1587 prop_value = bke::idprop::create(prop_enum_value_id, value).release();
1588 }
1589 else {
1590 prop_value = bke::idprop::create(prop_enum_value_id, item[index].identifier).release();
1591 }
1592 IDP_AddToGroup(prop_path, prop_value);
1593 }
1594 else {
1595 opnames_len = 0; /* Do nothing. */
1596 }
1597 if (free) {
1598 MEM_freeN(item);
1599 }
1600 }
1601
1602 /* check each until one works... */
1603
1604 for (int i = 0; (i < opnames_len) && (opnames[i]); i++) {
1605 if (const std::optional<std::string> str = WM_key_event_operator_string(
1606 C, opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false))
1607 {
1608 return str;
1609 }
1610 }
1611 }
1612 }
1613
1614 return std::nullopt;
1615}
1616
1618
1619/* -------------------------------------------------------------------- */
1646
1647const char ui_radial_dir_order[8] = {
1656};
1657
1658const char ui_radial_dir_to_numpad[8] = {8, 9, 6, 3, 2, 1, 4, 7};
1659const short ui_radial_dir_to_angle[8] = {90, 45, 0, 315, 270, 225, 180, 135};
1660
1661static std::string ui_but_pie_direction_string(const uiBut *but)
1662{
1664 return fmt::to_string(int(ui_radial_dir_to_numpad[but->pie_dir]));
1665}
1666
1668
1669static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
1670{
1672
1673 /* only do it before bounding */
1674 if (block->rect.xmin != block->rect.xmax) {
1675 return;
1676 }
1677 if (block->name == "splash") {
1678 return;
1679 }
1680
1681 if (block->flag & UI_BLOCK_PIE_MENU) {
1682 for (const std::unique_ptr<uiBut> &but : block->buttons) {
1683 if (but->pie_dir != UI_RADIAL_NONE) {
1684 const std::string str = ui_but_pie_direction_string(but.get());
1685 ui_but_add_shortcut(but.get(), str.c_str(), false);
1686 }
1687 }
1688 }
1689 else {
1690 for (const std::unique_ptr<uiBut> &but : block->buttons) {
1691 if (block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) {
1692 /* Skip icon-only buttons (as used in the toolbar). */
1693 if (but->drawstr[0] == '\0') {
1694 continue;
1695 }
1696 if (((block->flag & UI_BLOCK_POPOVER) == 0) && UI_but_is_tool(but.get())) {
1697 /* For non-popovers, shown in shortcut only
1698 * (has special shortcut handling code). */
1699 continue;
1700 }
1701 }
1702 else if (but->emboss != blender::ui::EmbossType::Pulldown) {
1703 continue;
1704 }
1705
1706 if (const std::optional<std::string> str = ui_but_event_operator_string(C, but.get())) {
1707 ui_but_add_shortcut(but.get(), str->c_str(), false);
1708 }
1709 else if (const std::optional<std::string> str = ui_but_event_property_operator_string(
1710 C, but.get()))
1711 {
1712 ui_but_add_shortcut(but.get(), str->c_str(), false);
1713 }
1714 }
1715 }
1716}
1717
1719{
1720 const uint override_status = RNA_property_override_library_status(
1721 bmain, &but->rnapoin, but->rnaprop, but->rnaindex);
1722
1723 if (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN) {
1724 but->flag |= UI_BUT_OVERRIDDEN;
1725 }
1726 else {
1727 but->flag &= ~UI_BUT_OVERRIDDEN;
1728 }
1729}
1730
1731/* -------------------------------------------------------------------- */
1739
1749
1751 wmOperatorType *optype,
1752 wmOperatorCallContext opcontext,
1753 int icon)
1754{
1755 uiButExtraOpIcon *extra_op_icon = MEM_callocN<uiButExtraOpIcon>(__func__);
1756
1757 extra_op_icon->icon = icon;
1758 extra_op_icon->optype_params = MEM_callocN<wmOperatorCallParams>(__func__);
1759 extra_op_icon->optype_params->optype = optype;
1760 extra_op_icon->optype_params->opptr = MEM_new<PointerRNA>(__func__);
1762 extra_op_icon->optype_params->optype);
1763 extra_op_icon->optype_params->opcontext = opcontext;
1764 extra_op_icon->highlighted = false;
1765 extra_op_icon->disabled = false;
1766
1767 BLI_addtail(&but->extra_op_icons, extra_op_icon);
1768
1769 return extra_op_icon->optype_params->opptr;
1770}
1771
1773{
1775 MEM_delete(extra_icon->optype_params->opptr);
1776 MEM_freeN(extra_icon->optype_params);
1777 MEM_freeN(extra_icon);
1778}
1779
1787
1789 const StringRefNull opname,
1790 wmOperatorCallContext opcontext,
1791 int icon)
1792{
1793 wmOperatorType *optype = WM_operatortype_find(opname.c_str(), false);
1794
1795 if (optype) {
1796 return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon);
1797 }
1798
1799 return nullptr;
1800}
1801
1803{
1804 return extra_icon ? extra_icon->optype_params->optype : nullptr;
1805}
1806
1808{
1809 return extra_icon->optype_params->opptr;
1810}
1811
1813{
1814 BLI_assert(but->type == UI_BTYPE_TEXT);
1815 return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
1816}
1817
1819{
1821 return ((but->editstr == nullptr) && (but->drawstr[0] != '\0') &&
1822 (but->flag & UI_BUT_VALUE_CLEAR));
1823}
1824
1826{
1828
1829 if (but->rnaprop == nullptr) {
1830 return false;
1831 }
1832
1834 const short idcode = RNA_type_to_ID_code(type);
1835
1836 return ((but->editstr == nullptr) && (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
1837}
1838
1840{
1841 if (but->type != UI_BTYPE_SEARCH_MENU || !(but->flag & UI_BUT_VALUE_CLEAR)) {
1842 return false;
1843 }
1844 if (but->editstr != nullptr) {
1845 return false;
1846 }
1848 return false;
1849 }
1850 uiButSearch *search_but = (uiButSearch *)but;
1851 if (!search_but->rnasearchprop) {
1852 return false;
1853 }
1854 const StructRNA *type = RNA_property_pointer_type(&search_but->rnasearchpoin,
1855 search_but->rnasearchprop);
1856 return type == &RNA_Bone || type == &RNA_EditBone;
1857}
1858
1860{
1861 switch (but->type) {
1862 case UI_BTYPE_TEXT:
1865 }
1866 break;
1868 if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
1869 /* pass */
1870 }
1873 }
1876 }
1879 }
1880 break;
1881 default:
1882 break;
1883 }
1884
1886}
1887
1894{
1895 const PredefinedExtraOpIconType extra_icon = ui_but_icon_extra_get(but);
1896 wmOperatorType *optype = nullptr;
1897 BIFIconID icon = ICON_NONE;
1898
1899 switch (extra_icon) {
1901 static wmOperatorType *id_eyedropper_ot = nullptr;
1902 if (!id_eyedropper_ot) {
1903 id_eyedropper_ot = WM_operatortype_find("UI_OT_eyedropper_id", false);
1904 }
1905 BLI_assert(id_eyedropper_ot);
1906
1907 optype = id_eyedropper_ot;
1908 icon = ICON_EYEDROPPER;
1909
1910 break;
1911 }
1913 static wmOperatorType *id_eyedropper_ot = nullptr;
1914 if (!id_eyedropper_ot) {
1915 id_eyedropper_ot = WM_operatortype_find("UI_OT_eyedropper_bone", false);
1916 }
1917 BLI_assert(id_eyedropper_ot);
1918
1919 optype = id_eyedropper_ot;
1920 icon = ICON_EYEDROPPER;
1921 break;
1922 }
1924 static wmOperatorType *clear_ot = nullptr;
1925 if (!clear_ot) {
1926 clear_ot = WM_operatortype_find("UI_OT_button_string_clear", false);
1927 }
1928 BLI_assert(clear_ot);
1929
1930 optype = clear_ot;
1931 icon = ICON_PANEL_CLOSE;
1932
1933 break;
1934 }
1935 default:
1936 break;
1937 }
1938
1939 if (optype) {
1941 if ((op_icon->optype_params->optype == optype) && (op_icon->icon == icon)) {
1942 /* Don't add the same operator icon twice (happens if button is kept alive while active).
1943 */
1944 return;
1945 }
1946 }
1948 }
1949}
1950
1952
1954{
1955 if (!block->oldblock) {
1956 return;
1957 }
1958
1959 if (BLI_listbase_is_empty(&block->oldblock->butstore) == false) {
1960 UI_butstore_update(block);
1961 }
1962
1963 std::optional<int64_t> but_old_idx = block->oldblock->buttons.is_empty() ? std::nullopt :
1964 std::optional{0};
1965 blender::Set<const uiBut *> matched_old_buttons;
1966 matched_old_buttons.reserve(block->oldblock->buttons.size());
1967 for (std::unique_ptr<uiBut> &but : block->buttons) {
1968 if (ui_but_update_from_old_block(block, matched_old_buttons, &but, &but_old_idx)) {
1969 ui_but_update(but.get());
1970
1971 /* redraw dynamic tooltip if we have one open */
1972 if (but->tip_func) {
1973 UI_but_tooltip_refresh((bContext *)C, but.get());
1974 }
1975 }
1976 }
1977 for (const std::unique_ptr<uiBut> &but : block->oldblock->buttons) {
1978 ui_but_free(C, but.get());
1979 }
1981
1982 block->auto_open = block->oldblock->auto_open;
1983 block->auto_open_last = block->oldblock->auto_open_last;
1984 block->tooltipdisabled = block->oldblock->tooltipdisabled;
1986
1987 block->oldblock = nullptr;
1988}
1989
1990#ifndef NDEBUG
1994static void ui_but_validate(const uiBut *but)
1995{
1996 /* Number buttons must have a click-step,
1997 * assert instead of correcting the value to ensure the caller knows what they're doing. */
1998 if (but->type == UI_BTYPE_NUM) {
1999 uiButNumber *number_but = (uiButNumber *)but;
2000
2002 BLI_assert(int(number_but->step_size) > 0);
2003 }
2004 }
2005}
2006#endif
2007
2009 const uiBut *but,
2010 const wmOperatorCallParams *optype_params)
2011{
2012 bool result;
2013 int old_but_flag = 0;
2014
2015 const bContextStore *previous_ctx = CTX_store_get(C);
2016 if (but) {
2017 old_but_flag = but->flag;
2018
2019 /* Temporarily make this button override the active one, in case the poll acts on the active
2020 * button. */
2021 const_cast<uiBut *>(but)->flag |= UI_BUT_ACTIVE_OVERRIDE;
2022
2023 if (but->context) {
2024 CTX_store_set(C, but->context);
2025 }
2026 }
2027
2028 result = WM_operator_poll_context(C, optype_params->optype, optype_params->opcontext);
2029
2030 if (but) {
2032 (old_but_flag & ~UI_BUT_ACTIVE_OVERRIDE),
2033 "Operator polls shouldn't change button flags");
2034
2035 const_cast<uiBut *>(but)->flag = old_but_flag;
2036
2037 if (but->context) {
2038 CTX_store_set(C, previous_ctx);
2039 }
2040 }
2041
2042 return result;
2043}
2044
2046{
2047 const wmOperatorCallContext opcontext = but ? but->opcontext : WM_OP_INVOKE_DEFAULT;
2049 params.optype = ot;
2050 params.opcontext = opcontext;
2052}
2053
2055 Main *bmain,
2056 wmWindow *window,
2057 Scene *scene,
2058 ARegion *region,
2059 Depsgraph *depsgraph,
2060 uiBlock *block,
2061 const int xy[2],
2062 int r_xy[2])
2063{
2064 BLI_assert(block->active);
2065
2066 /* Extend button data. This needs to be done before the block updating. */
2067 for (const std::unique_ptr<uiBut> &but : block->buttons) {
2069 }
2070
2072
2073 /* inherit flags from 'old' buttons that was drawn here previous, based
2074 * on matching buttons, we need this to make button event handling non
2075 * blocking, while still allowing buttons to be remade each redraw as it
2076 * is expected by blender code */
2077 for (const std::unique_ptr<uiBut> &but : block->buttons) {
2078 /* temp? Proper check for graying out */
2079 if (but->optype) {
2080 wmOperatorType *ot = but->optype;
2081
2082 if (ot == nullptr || !ui_but_context_poll_operator((bContext *)C, ot, but.get())) {
2083 but->flag |= UI_BUT_DISABLED;
2084 }
2085 }
2086
2087 LISTBASE_FOREACH (uiButExtraOpIcon *, op_icon, &but->extra_op_icons) {
2088 if (!ui_but_context_poll_operator_ex((bContext *)C, but.get(), op_icon->optype_params)) {
2089 op_icon->disabled = true;
2090 }
2091 }
2092
2094 depsgraph, (scene) ? BKE_scene_frame_get(scene) : 0.0f);
2095 ui_but_anim_flag(but.get(), &anim_eval_context);
2096 ui_but_override_flag(bmain, but.get());
2097 if (UI_but_is_decorator(but)) {
2099 }
2100
2101#ifndef NDEBUG
2102 ui_but_validate(but.get());
2103#endif
2104 }
2105
2106 /* handle pending stuff */
2107 if (block->layouts.first) {
2108 UI_block_layout_resolve(block, nullptr, nullptr);
2109 }
2110 ui_block_align_calc(block, region);
2111 if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT) &&
2112 (block->flag & UI_BLOCK_NO_ACCELERATOR_KEYS) == 0)
2113 {
2114 ui_menu_block_set_keyaccels(block); /* could use a different flag to check */
2115 }
2116
2119 }
2120
2121 /* after keymaps! */
2122 switch (block->bounds_type) {
2124 break;
2125 case UI_BLOCK_BOUNDS:
2126 ui_block_bounds_calc(block);
2127 break;
2129 ui_block_bounds_calc_text(block, 0.0f);
2130 break;
2132 if (block->handle->grab_xy_prev[0] == 0 && block->handle->grab_xy_prev[1] == 0) {
2133 ui_block_bounds_calc_centered(window, block);
2134 }
2135 else {
2137 }
2138 break;
2141 break;
2142
2143 /* fallback */
2146 ui_block_bounds_calc_popup(window, block, block->bounds_type, xy, r_xy);
2147 break;
2148 }
2149
2150 /* Update bounds of all views in this block. If this block is a panel, this will be done later in
2151 * #UI_panels_end(), because buttons are offset there. */
2152 if (!block->panel) {
2153 ui_block_views_end(region, block);
2154 }
2155
2156 if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
2158 }
2159 if (block->flag & UI_BUT_ALIGN) {
2160 UI_block_align_end(block);
2161 }
2162
2163 ui_update_flexible_spacing(region, block);
2164
2165 block->endblock = true;
2166}
2167
2168void UI_block_end(const bContext *C, uiBlock *block)
2169{
2170 wmWindow *window = CTX_wm_window(C);
2171
2174 window,
2178 block,
2179 window->eventstate->xy,
2180 nullptr);
2181}
2182
2183/* ************** BLOCK DRAWING FUNCTION ************* */
2184
2185void ui_fontscale(float *points, float aspect)
2186{
2187 *points /= aspect;
2188}
2189
2190void ui_but_to_pixelrect(rcti *rect, const ARegion *region, const uiBlock *block, const uiBut *but)
2191{
2192 *rect = ui_to_pixelrect(region, block, (but) ? &but->rect : &block->rect);
2193}
2194
2195rcti ui_to_pixelrect(const ARegion *region, const uiBlock *block, const rctf *src_rect)
2196{
2197 rctf rectf;
2198 ui_block_to_window_rctf(region, block, &rectf, src_rect);
2199 rcti recti;
2200 BLI_rcti_rctf_copy_round(&recti, &rectf);
2201 BLI_rcti_translate(&recti, -region->winrct.xmin, -region->winrct.ymin);
2202 return recti;
2203}
2204
2205static bool ui_but_pixelrect_in_view(const ARegion *region, const rcti *rect)
2206{
2207 rcti rect_winspace = *rect;
2208 BLI_rcti_translate(&rect_winspace, region->winrct.xmin, region->winrct.ymin);
2209 return BLI_rcti_isect(&region->winrct, &rect_winspace, nullptr);
2210}
2211
2212void UI_block_draw(const bContext *C, uiBlock *block)
2213{
2214 uiStyle style = *UI_style_get_dpi(); /* XXX pass on as arg */
2215
2216 /* get menu region or area region */
2217 ARegion *region = CTX_wm_region_popup(C);
2218 if (!region) {
2219 region = CTX_wm_region(C);
2220 }
2221
2222 if (!block->endblock) {
2223 UI_block_end(C, block);
2224 }
2225
2226 /* we set this only once */
2228
2229 /* scale fonts */
2230 ui_fontscale(&style.paneltitle.points, block->aspect);
2231 ui_fontscale(&style.grouplabel.points, block->aspect);
2232 ui_fontscale(&style.widget.points, block->aspect);
2233 ui_fontscale(&style.tooltip.points, block->aspect);
2234
2235 /* scale block min/max to rect */
2236 rcti rect;
2237 ui_but_to_pixelrect(&rect, region, block, nullptr);
2238
2239 /* pixel space for AA widgets */
2243
2245
2246 /* back */
2247 if (block->flag & UI_BLOCK_PIE_MENU) {
2248 ui_draw_pie_center(block);
2249 }
2250 else if (block->flag & UI_BLOCK_POPOVER) {
2251 ui_draw_popover_back(region, &style, block, &rect);
2252 }
2253 else if (block->flag & UI_BLOCK_LOOP) {
2254 ui_draw_menu_back(&style, block, &rect);
2255 }
2256 else if (block->panel) {
2257 ui_draw_aligned_panel(region,
2258 &style,
2259 block,
2260 &rect,
2264 }
2265 /* Shared layout panel backdrop style between redo region and popups. */
2266 if (block->panel && ELEM(region->regiontype, RGN_TYPE_HUD, RGN_TYPE_TEMPORARY)) {
2267 /* TODO: Add as theme color. */
2268 float subpanel_backcolor[4]{0.2f, 0.3f, 0.33f, 0.05f};
2269 const bTheme *btheme = UI_GetTheme();
2270 const float aspect = block->panel->runtime->block->aspect;
2271 const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f / aspect;
2272 ui_draw_layout_panels_backdrop(region, block->panel, radius, subpanel_backcolor);
2273 }
2274
2277
2278 /* widgets */
2279 for (const std::unique_ptr<uiBut> &but : block->buttons) {
2280 if (but->flag & (UI_HIDDEN | UI_SCROLLED)) {
2281 continue;
2282 }
2283
2284 ui_but_to_pixelrect(&rect, region, block, but.get());
2285 /* Optimization: Don't draw buttons that are not visible (outside view bounds). */
2286 if (!ui_but_pixelrect_in_view(region, &rect)) {
2287 continue;
2288 }
2289
2290 /* XXX: figure out why invalid coordinates happen when closing render window */
2291 /* and material preview is redrawn in main window (temp fix for bug #23848) */
2292 if (rect.xmin < rect.xmax && rect.ymin < rect.ymax) {
2293 ui_draw_but(C, region, &style, but.get(), &rect);
2294 }
2295 }
2296
2299
2300 ui_block_views_draw_overlays(region, block);
2301
2302 /* restore matrix */
2305}
2306
2307static void ui_block_message_subscribe(ARegion *region, wmMsgBus *mbus, uiBlock *block)
2308{
2309 uiBut *but_prev = nullptr;
2310 /* possibly we should keep the region this block is contained in? */
2311 for (const std::unique_ptr<uiBut> &but : block->buttons) {
2312 if (but->rnapoin.type && but->rnaprop) {
2313 /* quick check to avoid adding buttons representing a vector, multiple times. */
2314 if ((but_prev && (but_prev->rnaprop == but->rnaprop) &&
2315 (but_prev->rnapoin.type == but->rnapoin.type) &&
2316 (but_prev->rnapoin.data == but->rnapoin.data) &&
2317 (but_prev->rnapoin.owner_id == but->rnapoin.owner_id)) == false)
2318 {
2319 /* TODO: could make this into utility function. */
2320 wmMsgSubscribeValue value = {};
2321 value.owner = region;
2322 value.user_data = region;
2324 WM_msg_subscribe_rna(mbus, &but->rnapoin, but->rnaprop, &value, __func__);
2325 but_prev = but.get();
2326 }
2327 }
2328 }
2329}
2330
2332{
2333 LISTBASE_FOREACH (uiBlock *, block, &region->runtime->uiblocks) {
2334 ui_block_message_subscribe(region, mbus, block);
2335 }
2336}
2337
2338/* ************* EVENTS ************* */
2339
2340int ui_but_is_pushed_ex(uiBut *but, double *value)
2341{
2342 int is_push = 0;
2343 if (but->pushed_state_func) {
2344 return but->pushed_state_func(*but);
2345 }
2346
2347 if (but->bit) {
2348 const bool state = !ELEM(
2350 int lvalue;
2351 UI_GET_BUT_VALUE_INIT(but, *value);
2352 lvalue = int(*value);
2353 if (UI_BITBUT_TEST(lvalue, (but->bitnr))) {
2354 is_push = state;
2355 }
2356 else {
2357 is_push = !state;
2358 }
2359 }
2360 else {
2361 switch (but->type) {
2362 case UI_BTYPE_BUT:
2364 case UI_BTYPE_KEY_EVENT:
2365 case UI_BTYPE_COLOR:
2366 case UI_BTYPE_DECORATOR:
2367 is_push = -1;
2368 break;
2370 case UI_BTYPE_TOGGLE:
2372 case UI_BTYPE_CHECKBOX:
2373 UI_GET_BUT_VALUE_INIT(but, *value);
2374 if (*value != double(but->hardmin)) {
2375 is_push = true;
2376 }
2377 break;
2379 case UI_BTYPE_TOGGLE_N:
2381 UI_GET_BUT_VALUE_INIT(but, *value);
2382 if (*value == 0.0) {
2383 is_push = true;
2384 }
2385 break;
2386 case UI_BTYPE_ROW:
2387 case UI_BTYPE_LISTROW:
2388 case UI_BTYPE_TAB:
2389 if ((but->type == UI_BTYPE_TAB) && but->rnaprop && but->custom_data) {
2390 /* uiBut.custom_data points to data this tab represents (e.g. workspace).
2391 * uiBut.rnapoin/prop store an active value (e.g. active workspace). */
2392 if (RNA_property_type(but->rnaprop) == PROP_POINTER) {
2393 const PointerRNA active_ptr = RNA_property_pointer_get(&but->rnapoin, but->rnaprop);
2394 if (active_ptr.data == but->custom_data) {
2395 is_push = true;
2396 }
2397 }
2398 break;
2399 }
2400 else if (but->optype) {
2401 break;
2402 }
2403
2404 UI_GET_BUT_VALUE_INIT(but, *value);
2405 /* support for rna enum buts */
2406 if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) {
2407 if (int(*value) & int(but->hardmax)) {
2408 is_push = true;
2409 }
2410 }
2411 else {
2412 if (*value == double(but->hardmax)) {
2413 is_push = true;
2414 }
2415 }
2416 break;
2417 case UI_BTYPE_VIEW_ITEM: {
2418 const uiButViewItem *view_item_but = (const uiButViewItem *)but;
2419
2420 is_push = -1;
2421 if (view_item_but->view_item) {
2422 is_push = view_item_but->view_item->is_active();
2423 }
2424 break;
2425 }
2426 default:
2427 is_push = -1;
2428 break;
2429 }
2430 }
2431
2432 if ((but->drawflag & UI_BUT_CHECKBOX_INVERT) && (is_push != -1)) {
2433 is_push = !bool(is_push);
2434 }
2435 return is_push;
2436}
2438{
2439 double value = UI_BUT_VALUE_UNSET;
2440 return ui_but_is_pushed_ex(but, &value);
2441}
2442
2443static void ui_but_update_select_flag(uiBut *but, double *value)
2444{
2445 switch (ui_but_is_pushed_ex(but, value)) {
2446 case true:
2447 but->flag |= UI_SELECT;
2448 break;
2449 case false:
2450 but->flag &= ~UI_SELECT;
2451 break;
2452 }
2453}
2454
2455/* ************************************************ */
2456
2457void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr)
2458{
2459 if (val) {
2460 block->lock = val;
2461 block->lockstr = lockstr;
2462 }
2463}
2464
2466{
2467 block->lock = false;
2468 block->lockstr = nullptr;
2469}
2470
2471/* *********************** data get/set ***********************
2472 * this either works with the pointed to data, or can work with
2473 * an edit override pointer while dragging for example */
2474
2475void ui_but_v3_get(uiBut *but, float vec[3])
2476{
2477 if (but->editvec) {
2478 copy_v3_v3(vec, but->editvec);
2479 }
2480
2481 if (but->rnaprop) {
2482 PropertyRNA *prop = but->rnaprop;
2483
2484 zero_v3(vec);
2485
2486 if (RNA_property_type(prop) == PROP_FLOAT) {
2488 RNA_property_float_get_array_at_most(&but->rnapoin, prop, vec, 3);
2489 }
2490 }
2491 else if (but->pointype == UI_BUT_POIN_CHAR) {
2492 const char *cp = but->poin;
2493 vec[0] = float(cp[0]) / 255.0f;
2494 vec[1] = float(cp[1]) / 255.0f;
2495 vec[2] = float(cp[2]) / 255.0f;
2496 }
2497 else if (but->pointype == UI_BUT_POIN_FLOAT) {
2498 const float *fp = reinterpret_cast<float *>(but->poin);
2499 copy_v3_v3(vec, fp);
2500 }
2501 else {
2502 if (but->editvec == nullptr) {
2503 fprintf(stderr, "%s: can't get color, should never happen\n", __func__);
2504 zero_v3(vec);
2505 }
2506 }
2507
2508 if (but->type == UI_BTYPE_UNITVEC) {
2509 normalize_v3(vec);
2510 }
2511}
2512
2513void ui_but_v3_set(uiBut *but, const float vec[3])
2514{
2515 if (but->editvec) {
2516 copy_v3_v3(but->editvec, vec);
2517 }
2518
2519 if (but->rnaprop) {
2520 PropertyRNA *prop = but->rnaprop;
2521
2522 if (RNA_property_type(prop) == PROP_FLOAT) {
2524 RNA_property_float_set_array_at_most(&but->rnapoin, prop, vec, 3);
2525 }
2526 }
2527 else if (but->pointype == UI_BUT_POIN_CHAR) {
2528 char *cp = but->poin;
2529 cp[0] = char(lround(vec[0] * 255.0f));
2530 cp[1] = char(lround(vec[1] * 255.0f));
2531 cp[2] = char(lround(vec[2] * 255.0f));
2532 }
2533 else if (but->pointype == UI_BUT_POIN_FLOAT) {
2534 float *fp = reinterpret_cast<float *>(but->poin);
2535 copy_v3_v3(fp, vec);
2536 }
2537}
2538
2539void ui_but_v4_get(uiBut *but, float vec[4])
2540{
2541 if (but->editvec) {
2542 copy_v4_v4(vec, but->editvec);
2543 }
2544
2545 if (but->rnaprop) {
2546 PropertyRNA *prop = but->rnaprop;
2547
2548 zero_v4(vec);
2549
2550 if (RNA_property_type(prop) == PROP_FLOAT) {
2552 RNA_property_float_get_array_at_most(&but->rnapoin, prop, vec, 4);
2553 }
2554 }
2555 else if (but->pointype == UI_BUT_POIN_CHAR) {
2556 const char *cp = but->poin;
2557 vec[0] = float(cp[0]) / 255.0f;
2558 vec[1] = float(cp[1]) / 255.0f;
2559 vec[2] = float(cp[2]) / 255.0f;
2560 vec[3] = float(cp[3]) / 255.0f;
2561 }
2562 else if (but->pointype == UI_BUT_POIN_FLOAT) {
2563 const float *fp = reinterpret_cast<float *>(but->poin);
2564 copy_v4_v4(vec, fp);
2565 }
2566 else {
2567 if (but->editvec == nullptr) {
2568 fprintf(stderr, "%s: can't get color, should never happen\n", __func__);
2569 zero_v4(vec);
2570 }
2571 }
2572}
2573
2574void ui_but_v4_set(uiBut *but, const float vec[4])
2575{
2576 if (but->editvec) {
2577 copy_v4_v4(but->editvec, vec);
2578 }
2579
2580 if (but->rnaprop) {
2581 PropertyRNA *prop = but->rnaprop;
2582
2583 if (RNA_property_type(prop) == PROP_FLOAT) {
2585 RNA_property_float_set_array_at_most(&but->rnapoin, prop, vec, 4);
2586 }
2587 }
2588 else if (but->pointype == UI_BUT_POIN_CHAR) {
2589 char *cp = but->poin;
2590 cp[0] = char(lround(vec[0] * 255.0f));
2591 cp[1] = char(lround(vec[1] * 255.0f));
2592 cp[2] = char(lround(vec[2] * 255.0f));
2593 cp[3] = char(lround(vec[3] * 255.0f));
2594 }
2595 else if (but->pointype == UI_BUT_POIN_FLOAT) {
2596 float *fp = reinterpret_cast<float *>(but->poin);
2597 copy_v4_v4(fp, vec);
2598 }
2599}
2600
2601bool ui_but_is_float(const uiBut *but)
2602{
2603 if (but->pointype == UI_BUT_POIN_FLOAT && but->poin) {
2604 return true;
2605 }
2606
2607 if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_FLOAT) {
2608 return true;
2609 }
2610
2611 return false;
2612}
2613
2615{
2616 if (but->rnaprop) {
2617 return RNA_property_ui_scale(but->rnaprop);
2618 }
2619 return PROP_SCALE_LINEAR;
2620}
2621
2622bool ui_but_is_bool(const uiBut *but)
2623{
2624 if (ELEM(but->type,
2632 UI_BTYPE_TAB))
2633 {
2634 return true;
2635 }
2636
2637 if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN) {
2638 return true;
2639 }
2640
2641 if ((but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM) &&
2642 (but->type == UI_BTYPE_ROW))
2643 {
2644 return true;
2645 }
2646
2647 return false;
2648}
2649
2650bool ui_but_is_unit(const uiBut *but)
2651{
2652 const UnitSettings *unit = but->block->unit;
2653 const int unit_type = UI_but_unit_type_get(but);
2654
2655 if (unit_type == PROP_UNIT_NONE) {
2656 return false;
2657 }
2658
2659#if 1 /* removed so angle buttons get correct snapping */
2660 if (ui_but_is_unit_radians_ex(unit, unit_type)) {
2661 return false;
2662 }
2663#endif
2664
2665 /* for now disable time unit conversion */
2666 if (unit_type == PROP_UNIT_TIME) {
2667 return false;
2668 }
2669
2670 if (unit->system == USER_UNIT_NONE) {
2671 /* These types have units irrespective of scene units. */
2673 return false;
2674 }
2675 }
2676
2677 return true;
2678}
2679
2680bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b)
2681{
2682 if (but_a->type != but_b->type) {
2683 return false;
2684 }
2685 if (but_a->pointype != but_b->pointype) {
2686 return false;
2687 }
2688
2689 if (but_a->rnaprop) {
2690 /* skip 'rnapoin.data', 'rnapoin.owner_id'
2691 * allow different data to have the same props edited at once */
2692 if (but_a->rnapoin.type != but_b->rnapoin.type) {
2693 return false;
2694 }
2695 if (RNA_property_type(but_a->rnaprop) != RNA_property_type(but_b->rnaprop)) {
2696 return false;
2697 }
2699 return false;
2700 }
2701 }
2702
2703 return true;
2704}
2705
2707{
2708 if (but->rnaprop == nullptr || RNA_struct_contains_property(&but->rnapoin, but->rnaprop)) {
2709 return true;
2710 }
2711 printf("property removed %s: %p\n", but->drawstr.c_str(), but->rnaprop);
2712 return false;
2713}
2714
2716{
2718 (but->type == UI_BTYPE_MENU && ui_but_menu_step_poll(but)) ||
2719 (but->type == UI_BTYPE_COLOR && ((uiButColor *)but)->is_pallete_color) ||
2720 (but->menu_step_func != nullptr));
2721}
2722
2724{
2725 double value = 0.0;
2726
2727 if (but->editval) {
2728 return *(but->editval);
2729 }
2730 if (but->poin == nullptr && but->rnapoin.data == nullptr) {
2731 return 0.0;
2732 }
2733
2734 if (but->rnaprop) {
2735 PropertyRNA *prop = but->rnaprop;
2736
2737 BLI_assert(but->rnaindex != -1);
2738
2739 switch (RNA_property_type(prop)) {
2740 case PROP_BOOLEAN:
2741 if (RNA_property_array_check(prop)) {
2742 value = double(RNA_property_boolean_get_index(&but->rnapoin, prop, but->rnaindex));
2743 }
2744 else {
2745 value = double(RNA_property_boolean_get(&but->rnapoin, prop));
2746 }
2747 break;
2748 case PROP_INT:
2749 if (RNA_property_array_check(prop)) {
2750 value = RNA_property_int_get_index(&but->rnapoin, prop, but->rnaindex);
2751 }
2752 else {
2753 value = RNA_property_int_get(&but->rnapoin, prop);
2754 }
2755 break;
2756 case PROP_FLOAT:
2757 if (RNA_property_array_check(prop)) {
2758 value = RNA_property_float_get_index(&but->rnapoin, prop, but->rnaindex);
2759 }
2760 else {
2761 value = RNA_property_float_get(&but->rnapoin, prop);
2762 }
2763 break;
2764 case PROP_ENUM:
2765 value = RNA_property_enum_get(&but->rnapoin, prop);
2766 break;
2767 default:
2768 value = 0.0;
2769 break;
2770 }
2771 }
2772 else if (but->pointype == UI_BUT_POIN_CHAR) {
2773 value = *(char *)but->poin;
2774 }
2775 else if (but->pointype == UI_BUT_POIN_SHORT) {
2776 value = *(short *)but->poin;
2777 }
2778 else if (but->pointype == UI_BUT_POIN_INT) {
2779 value = *(int *)but->poin;
2780 }
2781 else if (but->pointype == UI_BUT_POIN_FLOAT) {
2782 value = *(float *)but->poin;
2783 }
2784
2785 return value;
2786}
2787
2788void ui_but_value_set(uiBut *but, double value)
2789{
2790 /* Value is a HSV value: convert to RGB. */
2791 if (but->rnaprop) {
2792 PropertyRNA *prop = but->rnaprop;
2793
2794 if (RNA_property_editable(&but->rnapoin, prop)) {
2795 switch (RNA_property_type(prop)) {
2796 case PROP_BOOLEAN:
2797 if (RNA_property_array_check(prop)) {
2798 RNA_property_boolean_set_index(&but->rnapoin, prop, but->rnaindex, value);
2799 }
2800 else {
2801 RNA_property_boolean_set(&but->rnapoin, prop, value);
2802 }
2803 break;
2804 case PROP_INT:
2805 if (RNA_property_array_check(prop)) {
2806 RNA_property_int_set_index(&but->rnapoin, prop, but->rnaindex, int(value));
2807 }
2808 else {
2809 RNA_property_int_set(&but->rnapoin, prop, int(value));
2810 }
2811 break;
2812 case PROP_FLOAT:
2813 if (RNA_property_array_check(prop)) {
2814 RNA_property_float_set_index(&but->rnapoin, prop, but->rnaindex, value);
2815 }
2816 else {
2817 RNA_property_float_set(&but->rnapoin, prop, value);
2818 }
2819 break;
2820 case PROP_ENUM:
2821 if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
2822 int ivalue = int(value);
2823 /* toggle for enum/flag buttons */
2824 ivalue ^= RNA_property_enum_get(&but->rnapoin, prop);
2825 RNA_property_enum_set(&but->rnapoin, prop, ivalue);
2826 }
2827 else {
2828 RNA_property_enum_set(&but->rnapoin, prop, value);
2829 }
2830 break;
2831 default:
2832 break;
2833 }
2834 }
2835
2836 /* we can't be sure what RNA set functions actually do,
2837 * so leave this unset */
2838 value = UI_BUT_VALUE_UNSET;
2839 }
2840 else if (but->pointype == 0) {
2841 /* pass */
2842 }
2843 else {
2844 /* first do rounding */
2845 if (but->pointype == UI_BUT_POIN_CHAR) {
2846 value = round_db_to_uchar_clamp(value);
2847 }
2848 else if (but->pointype == UI_BUT_POIN_SHORT) {
2849 value = round_db_to_short_clamp(value);
2850 }
2851 else if (but->pointype == UI_BUT_POIN_INT) {
2852 value = round_db_to_int_clamp(value);
2853 }
2854 else if (but->pointype == UI_BUT_POIN_FLOAT) {
2855 float fval = float(value);
2856 if (fval >= -0.00001f && fval <= 0.00001f) {
2857 /* prevent negative zero */
2858 fval = 0.0f;
2859 }
2860 value = fval;
2861 }
2862
2863 /* then set value with possible edit override */
2864 if (but->editval) {
2865 value = *but->editval = value;
2866 }
2867 else if (but->pointype == UI_BUT_POIN_CHAR) {
2868 value = *((char *)but->poin) = char(value);
2869 }
2870 else if (but->pointype == UI_BUT_POIN_SHORT) {
2871 value = *((short *)but->poin) = short(value);
2872 }
2873 else if (but->pointype == UI_BUT_POIN_INT) {
2874 value = *((int *)but->poin) = int(value);
2875 }
2876 else if (but->pointype == UI_BUT_POIN_FLOAT) {
2877 value = *((float *)but->poin) = float(value);
2878 }
2879 }
2880
2881 ui_but_update_select_flag(but, &value);
2882}
2883
2885{
2887 return but->hardmax;
2888 }
2889 return UI_MAX_DRAW_STR;
2890}
2891
2893{
2894 uiBut *return_but = nullptr;
2895
2897
2898 for (const std::unique_ptr<uiBut> &but_iter : but->block->buttons) {
2899 if (but_iter->editstr) {
2900 return_but = but_iter.get();
2901 break;
2902 }
2903 }
2904
2905 return return_but;
2906}
2907
2908static double ui_get_but_scale_unit(uiBut *but, double value)
2909{
2910 const UnitSettings *unit = but->block->unit;
2911 const int unit_type = UI_but_unit_type_get(but);
2912
2913 /* Time unit is a bit special, not handled by #BKE_unit_value_scale() for now. */
2914 if (unit_type == PROP_UNIT_TIME) { /* WARNING: using evil_C :| */
2915 Scene *scene = CTX_data_scene(static_cast<const bContext *>(but->block->evil_C));
2916 return FRA2TIME(value);
2917 }
2918 return BKE_unit_value_scale(*unit, RNA_SUBTYPE_UNIT_VALUE(unit_type), value);
2919}
2920
2921void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t str_maxncpy)
2922{
2923 if (!ui_but_is_unit(but)) {
2924 return;
2925 }
2926
2927 const UnitSettings *unit = but->block->unit;
2928 const int unit_type = UI_but_unit_type_get(but);
2929 char *orig_str;
2930
2931 orig_str = BLI_strdup(str);
2932
2934 str, str_maxncpy, orig_str, unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
2935
2936 MEM_freeN(orig_str);
2937}
2938
2943 uiBut *but, char *str, int str_maxncpy, double value, bool pad, int float_precision)
2944{
2945 const UnitSettings *unit = but->block->unit;
2946 const int unit_type = UI_but_unit_type_get(but);
2947 int precision;
2948
2949 BLI_assert(unit->scale_length > 0.0f);
2950
2951 /* Use precision override? */
2952 if (float_precision == -1) {
2953 /* Sanity checks */
2954 precision = int(ui_but_get_float_precision(but));
2955 if (precision > UI_PRECISION_FLOAT_MAX) {
2956 precision = UI_PRECISION_FLOAT_MAX;
2957 }
2958 else if (precision == -1) {
2959 precision = 2;
2960 }
2961 }
2962 else {
2963 precision = float_precision;
2964 }
2965
2967 str_maxncpy,
2968 ui_get_but_scale_unit(but, value),
2969 precision,
2970 RNA_SUBTYPE_UNIT_VALUE(unit_type),
2971 *unit,
2972 pad);
2973}
2974
2975static float ui_get_but_step_unit(uiBut *but, float step_default)
2976{
2977 const int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
2978 const double step_orig = double(step_default) * double(UI_PRECISION_FLOAT_SCALE);
2979 /* Scaling up 'step_orig ' here is a bit arbitrary,
2980 * its just giving better scales from user POV */
2981 const double scale_step = ui_get_but_scale_unit(but, step_orig * 10);
2982 const double step = BKE_unit_closest_scalar(scale_step, but->block->unit->system, unit_type);
2983
2984 /* -1 is an error value */
2985 if (step == -1.0f) {
2986 return step_default;
2987 }
2988
2989 const double scale_unit = ui_get_but_scale_unit(but, 1.0);
2990 const double step_unit = BKE_unit_closest_scalar(
2991 scale_unit, but->block->unit->system, unit_type);
2992 double step_final;
2993
2994 BLI_assert(step > 0.0);
2995
2996 step_final = (step / scale_unit) / double(UI_PRECISION_FLOAT_SCALE);
2997
2998 if (step == step_unit) {
2999 /* Logic here is to scale by the original 'step_orig'
3000 * only when the unit step matches the scaled step.
3001 *
3002 * This is needed for units that don't have a wide range of scales (degrees for eg.).
3003 * Without this we can't select between a single degree, or a 10th of a degree.
3004 */
3005 step_final *= step_orig;
3006 }
3007
3008 return float(step_final);
3009}
3010
3012 char *str,
3013 const size_t str_maxncpy,
3014 const int float_precision,
3015 const bool use_exp_float,
3016 bool *r_use_exp_float)
3017{
3018 if (r_use_exp_float) {
3019 *r_use_exp_float = false;
3020 }
3021
3023 const PropertyType type = RNA_property_type(but->rnaprop);
3024
3025 int buf_len;
3026 const char *buf = nullptr;
3027 if ((but->type == UI_BTYPE_TAB) && (but->custom_data)) {
3028 StructRNA *ptr_type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
3029
3030 /* uiBut.custom_data points to data this tab represents (e.g. workspace).
3031 * uiBut.rnapoin/prop store an active value (e.g. active workspace). */
3033 but->rnapoin.owner_id, ptr_type, but->custom_data);
3034 buf = RNA_struct_name_get_alloc(&ptr, str, str_maxncpy, &buf_len);
3035 }
3036 else if (type == PROP_STRING) {
3037 /* RNA string */
3038 buf = RNA_property_string_get_alloc(&but->rnapoin, but->rnaprop, str, str_maxncpy, &buf_len);
3039 }
3040 else if (type == PROP_ENUM) {
3041 /* RNA enum */
3042 const int value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
3043 if (RNA_property_enum_name(static_cast<bContext *>(but->block->evil_C),
3044 &but->rnapoin,
3045 but->rnaprop,
3046 value,
3047 &buf))
3048 {
3049 BLI_strncpy(str, buf, str_maxncpy);
3050 buf = str;
3051 }
3052 }
3053 else if (type == PROP_POINTER) {
3054 /* RNA pointer */
3056 buf = RNA_struct_name_get_alloc(&ptr, str, str_maxncpy, &buf_len);
3057 }
3058 else {
3059 BLI_assert(0);
3060 }
3061
3062 if (buf == nullptr) {
3063 str[0] = '\0';
3064 }
3065 else if (buf != str) {
3066 BLI_assert(str_maxncpy <= buf_len + 1);
3067 /* string was too long, we have to truncate */
3068 if (UI_but_is_utf8(but)) {
3069 BLI_strncpy_utf8(str, buf, str_maxncpy);
3070 }
3071 else {
3072 BLI_strncpy(str, buf, str_maxncpy);
3073 }
3074 MEM_freeN(buf);
3075 }
3076 }
3077 else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
3078 /* string */
3079 BLI_strncpy(str, but->poin, str_maxncpy);
3080 return;
3081 }
3082 else if (ui_but_anim_expression_get(but, str, str_maxncpy)) {
3083 /* driver expression */
3084 }
3085 else {
3086 /* number editing */
3087 const double value = ui_but_value_get(but);
3088
3089 PropertySubType subtype = PROP_NONE;
3090 if (but->rnaprop) {
3091 subtype = RNA_property_subtype(but->rnaprop);
3092 }
3093
3094 if (ui_but_is_float(but)) {
3095 int prec = float_precision;
3096
3097 if (float_precision == -1) {
3098 prec = ui_but_calc_float_precision(but, value);
3099 }
3100 else if (!use_exp_float && ui_but_hide_fraction(but, value)) {
3101 prec = 0;
3102 }
3103
3104 if (ui_but_is_unit(but)) {
3105 ui_get_but_string_unit(but, str, str_maxncpy, value, false, prec);
3106 }
3107 else if (subtype == PROP_FACTOR) {
3108 if (U.factor_display_type == USER_FACTOR_AS_FACTOR) {
3109 BLI_snprintf(str, str_maxncpy, "%.*f", prec, value);
3110 }
3111 else {
3112 BLI_snprintf(str, str_maxncpy, "%.*f", std::max(0, prec - 2), value * 100);
3113 }
3114 }
3115 else {
3116 const int int_digits_num = integer_digits_f(value);
3117 if (use_exp_float) {
3118 if (int_digits_num < -6 || int_digits_num > 12) {
3119 BLI_snprintf(str, str_maxncpy, "%.*g", prec, value);
3120 if (r_use_exp_float) {
3121 *r_use_exp_float = true;
3122 }
3123 }
3124 else {
3125 prec -= int_digits_num;
3126 CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX);
3127 BLI_snprintf(str, str_maxncpy, "%.*f", prec, value);
3128 }
3129 }
3130 else {
3131 prec -= int_digits_num;
3132 CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX);
3133 BLI_snprintf(str, str_maxncpy, "%.*f", prec, value);
3134 }
3135 }
3136 }
3137 else {
3138 BLI_snprintf(str, str_maxncpy, "%d", int(value));
3139 }
3140 }
3141}
3142void ui_but_string_get(uiBut *but, char *str, const size_t str_maxncpy)
3143{
3144 ui_but_string_get_ex(but, str, str_maxncpy, -1, false, nullptr);
3145}
3146
3147char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
3148{
3149 char *str = nullptr;
3150 *r_str_size = 1;
3151
3152 if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
3153 const PropertyType type = RNA_property_type(but->rnaprop);
3154
3155 if (type == PROP_STRING) {
3156 /* RNA string */
3157 str = RNA_property_string_get_alloc(&but->rnapoin, but->rnaprop, nullptr, 0, r_str_size);
3158 (*r_str_size) += 1;
3159 }
3160 else if (type == PROP_ENUM) {
3161 /* RNA enum */
3162 const int value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
3163 const char *value_id;
3164 if (!RNA_property_enum_name(static_cast<bContext *>(but->block->evil_C),
3165 &but->rnapoin,
3166 but->rnaprop,
3167 value,
3168 &value_id))
3169 {
3170 value_id = "";
3171 }
3172
3173 *r_str_size = strlen(value_id) + 1;
3174 str = BLI_strdupn(value_id, *r_str_size);
3175 }
3176 else if (type == PROP_POINTER) {
3177 /* RNA pointer */
3179 str = RNA_struct_name_get_alloc(&ptr, nullptr, 0, r_str_size);
3180 (*r_str_size) += 1;
3181 }
3182 else {
3183 BLI_assert(0);
3184 }
3185 }
3186 else {
3187 BLI_assert(0);
3188 }
3189
3190 if (UNLIKELY(str == nullptr)) {
3191 /* should never happen, paranoid check */
3192 *r_str_size = 1;
3193 str = BLI_strdup("");
3194 BLI_assert(0);
3195 }
3196
3197 return str;
3198}
3199
3204#define UI_NUMBER_EVAL_ERROR_PREFIX RPT_("Error evaluating number, see Info editor for details")
3205
3207 bContext *C, const char *str, const int unit_type, const UnitSettings *unit, double *r_value)
3208{
3209 char *error = nullptr;
3210 const bool ok = user_string_to_number(C, str, *unit, unit_type, r_value, true, &error);
3211 if (error) {
3215 }
3216 return ok;
3217}
3218
3220 const char *str,
3221 const uiBut *but,
3222 double *r_value)
3223{
3224 const int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
3225 const UnitSettings *unit = but->block->unit;
3226 return ui_number_from_string_units(C, str, unit_type, unit, r_value);
3227}
3228
3229static bool ui_number_from_string(bContext *C, const char *str, double *r_value)
3230{
3231 bool ok;
3232#ifdef WITH_PYTHON
3233 BPy_RunErrInfo err_info = {};
3234 err_info.reports = CTX_wm_reports(C);
3236 ok = BPY_run_string_as_number(C, nullptr, str, &err_info, r_value);
3237#else
3238 UNUSED_VARS(C);
3239 *r_value = atof(str);
3240 ok = true;
3241#endif
3242 return ok;
3243}
3244
3245static bool ui_number_from_string_factor(bContext *C, const char *str, double *r_value)
3246{
3247 const int len = strlen(str);
3248 if (BLI_strn_endswith(str, "%", len)) {
3249 char *str_new = BLI_strdupn(str, len - 1);
3250 const bool success = ui_number_from_string(C, str_new, r_value);
3251 MEM_freeN(str_new);
3252 *r_value /= 100.0;
3253 return success;
3254 }
3255 if (!ui_number_from_string(C, str, r_value)) {
3256 return false;
3257 }
3258 if (U.factor_display_type == USER_FACTOR_AS_PERCENTAGE) {
3259 *r_value /= 100.0;
3260 }
3261 return true;
3262}
3263
3264static bool ui_number_from_string_percentage(bContext *C, const char *str, double *r_value)
3265{
3266 const int len = strlen(str);
3267 if (BLI_strn_endswith(str, "%", len)) {
3268 char *str_new = BLI_strdupn(str, len - 1);
3269 const bool success = ui_number_from_string(C, str_new, r_value);
3270 MEM_freeN(str_new);
3271 return success;
3272 }
3273 return ui_number_from_string(C, str, r_value);
3274}
3275
3276bool ui_but_string_eval_number(bContext *C, const uiBut *but, const char *str, double *r_value)
3277{
3278 if (str[0] == '\0') {
3279 *r_value = 0.0;
3280 return true;
3281 }
3282
3283 PropertySubType subtype = PROP_NONE;
3284 if (but->rnaprop) {
3285 subtype = RNA_property_subtype(but->rnaprop);
3286 }
3287
3288 if (ui_but_is_float(but)) {
3289 if (ui_but_is_unit(but)) {
3290 return ui_number_from_string_units_with_but(C, str, but, r_value);
3291 }
3292 if (subtype == PROP_FACTOR) {
3293 return ui_number_from_string_factor(C, str, r_value);
3294 }
3295 if (subtype == PROP_PERCENTAGE) {
3296 return ui_number_from_string_percentage(C, str, r_value);
3297 }
3298 return ui_number_from_string(C, str, r_value);
3299 }
3300 return ui_number_from_string(C, str, r_value);
3301}
3302
3303bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
3304{
3305 if (but->rnaprop && but->rnapoin.data && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
3306 if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
3307 const PropertyType type = RNA_property_type(but->rnaprop);
3308
3309 if (type == PROP_STRING) {
3310 /* RNA string, only set it if full rename callback is not defined, otherwise just store the
3311 * user-defined new name to call the callback later. */
3312 if (but->rename_full_func) {
3313 but->rename_full_new = str;
3314 }
3315 else {
3317 }
3318 return true;
3319 }
3320
3321 if (type == PROP_POINTER) {
3322 if (str[0] == '\0') {
3324 return true;
3325 }
3326
3327 uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but :
3328 nullptr;
3329 /* RNA pointer */
3330 PointerRNA rptr;
3331
3332 /* This is kind of hackish, in theory think we could only ever use the second member of
3333 * this if/else, since #ui_searchbox_apply() is supposed to always set that pointer when
3334 * we are storing pointers... But keeping str search first for now,
3335 * to try to break as little as possible existing code. All this is band-aids anyway.
3336 * Fact remains, using `editstr` as main 'reference' over whole search button thingy
3337 * is utterly weak and should be redesigned IMHO, but that's not a simple task. */
3338 if (search_but && search_but->rnasearchprop &&
3340 &search_but->rnasearchpoin, search_but->rnasearchprop, str, &rptr))
3341 {
3342 RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, nullptr);
3343 }
3344 else if (search_but && search_but->item_active != nullptr) {
3346 nullptr,
3348 search_but->item_active);
3349 RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, nullptr);
3350 }
3351
3352 return true;
3353 }
3354
3355 if (type == PROP_ENUM) {
3356 int value;
3357 if (RNA_property_enum_value(static_cast<bContext *>(but->block->evil_C),
3358 &but->rnapoin,
3359 but->rnaprop,
3360 str,
3361 &value))
3362 {
3363 RNA_property_enum_set(&but->rnapoin, but->rnaprop, value);
3364 return true;
3365 }
3366 return false;
3367 }
3368 BLI_assert(0);
3369 }
3370 }
3371 else if (but->type == UI_BTYPE_TAB) {
3372 if (but->rnaprop && but->custom_data) {
3373 StructRNA *ptr_type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
3374 PropertyRNA *prop;
3375
3376 /* uiBut.custom_data points to data this tab represents (e.g. workspace).
3377 * uiBut.rnapoin/prop store an active value (e.g. active workspace). */
3379 but->rnapoin.owner_id, ptr_type, but->custom_data);
3380 prop = RNA_struct_name_property(ptr_type);
3381 if (RNA_property_editable(&ptr, prop)) {
3383 }
3384 }
3385 }
3386 else if (but->type == UI_BTYPE_TEXT) {
3387 /* string */
3388 if (!but->poin) {
3389 str = "";
3390 }
3391 else if (UI_but_is_utf8(but)) {
3392 BLI_strncpy_utf8(but->poin, str, but->hardmax);
3393 }
3394 else {
3395 BLI_strncpy(but->poin, str, but->hardmax);
3396 }
3397
3398 return true;
3399 }
3400 else if (but->type == UI_BTYPE_SEARCH_MENU) {
3401 /* string */
3402 BLI_strncpy(but->poin, str, but->hardmax);
3403 return true;
3404 }
3405 else if (ui_but_anim_expression_set(but, str)) {
3406 /* driver expression */
3407 return true;
3408 }
3409 else if (str[0] == '#') {
3410 /* Shortcut to create new driver expression (versus immediate Python-execution). */
3411 return ui_but_anim_expression_create(but, str + 1);
3412 }
3413 else {
3414 /* number editing */
3415 double value;
3416
3417 if (ui_but_string_eval_number(C, but, str, &value) == false) {
3419 return false;
3420 }
3421
3422 if (!ui_but_is_float(but)) {
3423 value = floor(value + 0.5);
3424 }
3425
3426 /* not that we use hard limits here */
3427 if (value < double(but->hardmin)) {
3428 value = but->hardmin;
3429 }
3430 if (value > double(but->hardmax)) {
3431 value = but->hardmax;
3432 }
3433
3434 ui_but_value_set(but, value);
3435 return true;
3436 }
3437
3438 return false;
3439}
3440
3441static double soft_range_round_up(double value, double max)
3442{
3443 /* round up to .., 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, ..
3444 * checking for 0.0 prevents floating point exceptions */
3445 const double newmax = (value != 0.0) ? pow(10.0, ceil(log(value) / M_LN10)) : 0.0;
3446
3447 if (newmax * 0.2 >= max && newmax * 0.2 >= value) {
3448 return newmax * 0.2;
3449 }
3450 if (newmax * 0.5 >= max && newmax * 0.5 >= value) {
3451 return newmax * 0.5;
3452 }
3453 return newmax;
3454}
3455
3456static double soft_range_round_down(double value, double max)
3457{
3458 /* round down to .., 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, ..
3459 * checking for 0.0 prevents floating point exceptions */
3460 const double newmax = (value != 0.0) ? pow(10.0, floor(log(value) / M_LN10)) : 0.0;
3461
3462 if (newmax * 5.0 <= max && newmax * 5.0 <= value) {
3463 return newmax * 5.0;
3464 }
3465 if (newmax * 2.0 <= max && newmax * 2.0 <= value) {
3466 return newmax * 2.0;
3467 }
3468 return newmax;
3469}
3470
3472{
3473 if (but->rnaprop == nullptr) {
3474 return;
3475 }
3476
3477 const PropertyType type = RNA_property_type(but->rnaprop);
3478
3479 if (type == PROP_INT) {
3480 int imin, imax;
3481 RNA_property_int_range(&but->rnapoin, but->rnaprop, &imin, &imax);
3482 but->hardmin = imin;
3483 but->hardmax = imax;
3484 }
3485 else if (type == PROP_FLOAT) {
3486 float fmin, fmax;
3487 RNA_property_float_range(&but->rnapoin, but->rnaprop, &fmin, &fmax);
3488 but->hardmin = fmin;
3489 but->hardmax = fmax;
3490 }
3491}
3492
3494{
3495 /* This could be split up into functions which handle arrays and not. */
3496
3497 /* Ideally we would not limit this, but practically it's more than
3498 * enough. Worst case is very long vectors won't use a smart soft-range,
3499 * which isn't so bad. */
3500
3501 if (but->rnaprop) {
3502 const PropertyType type = RNA_property_type(but->rnaprop);
3503 const PropertySubType subtype = RNA_property_subtype(but->rnaprop);
3504 double softmin, softmax;
3505 // double step, precision; /* UNUSED. */
3506 double value_min;
3507 double value_max;
3508
3509 /* clamp button range to something reasonable in case
3510 * we get -inf/inf from RNA properties */
3511 if (type == PROP_INT) {
3512 const bool is_array = RNA_property_array_check(but->rnaprop);
3513 int imin, imax, istep;
3514
3515 RNA_property_int_ui_range(&but->rnapoin, but->rnaprop, &imin, &imax, &istep);
3516 softmin = std::max(imin, INT_MIN);
3517 softmax = std::min(imax, INT_MAX);
3518 // step = istep; /* UNUSED */
3519 // precision = 1; /* UNUSED */
3520
3521 if (is_array) {
3522 int value_range[2];
3523 RNA_property_int_get_array_range(&but->rnapoin, but->rnaprop, value_range);
3524 value_min = double(value_range[0]);
3525 value_max = double(value_range[1]);
3526 }
3527 else {
3528 value_min = value_max = ui_but_value_get(but);
3529 }
3530 }
3531 else if (type == PROP_FLOAT) {
3532 const bool is_array = RNA_property_array_check(but->rnaprop);
3533 float fmin, fmax, fstep, fprecision;
3534
3535 RNA_property_float_ui_range(&but->rnapoin, but->rnaprop, &fmin, &fmax, &fstep, &fprecision);
3536 softmin = (fmin == -FLT_MAX) ? float(-1e4) : fmin;
3537 softmax = (fmax == FLT_MAX) ? float(1e4) : fmax;
3538 // step = fstep; /* UNUSED */
3539 // precision = fprecision; /* UNUSED */
3540
3541 /* Use shared min/max for array values, except for color alpha. */
3542 if (is_array && !(subtype == PROP_COLOR && but->rnaindex == 3)) {
3543 float value_range[2];
3544 RNA_property_float_get_array_range(&but->rnapoin, but->rnaprop, value_range);
3545 value_min = double(value_range[0]);
3546 value_max = double(value_range[1]);
3547 }
3548 else {
3549 value_min = value_max = ui_but_value_get(but);
3550 }
3551 }
3552 else {
3553 return;
3554 }
3555
3556 /* if the value goes out of the soft/max range, adapt the range */
3557 if (value_min + 1e-10 < softmin) {
3558 if (value_min < 0.0) {
3559 softmin = -soft_range_round_up(-value_min, -softmin);
3560 }
3561 else {
3562 softmin = soft_range_round_down(value_min, softmin);
3563 }
3564
3565 softmin = std::max(softmin, double(but->hardmin));
3566 }
3567 if (value_max - 1e-10 > softmax) {
3568 if (value_max < 0.0) {
3569 softmax = -soft_range_round_down(-value_max, -softmax);
3570 }
3571 else {
3572 softmax = soft_range_round_up(value_max, softmax);
3573 }
3574
3575 if (softmax > double(but->hardmax)) {
3576 softmax = but->hardmax;
3577 }
3578 }
3579
3580 but->softmin = softmin;
3581 but->softmax = softmax;
3582 }
3583 else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) {
3584 float value = ui_but_value_get(but);
3585 if (isfinite(value)) {
3586 CLAMP(value, but->hardmin, but->hardmax);
3587 but->softmin = min_ff(but->softmin, value);
3588 but->softmax = max_ff(but->softmax, value);
3589 }
3590 }
3591}
3592
3593/* ******************* Free ********************/
3594
3601{
3602 switch (but->type) {
3603 case UI_BTYPE_SEARCH_MENU: {
3604 uiButSearch *search_but = (uiButSearch *)but;
3605 MEM_SAFE_FREE(search_but->item_active_str);
3606
3607 if (search_but->arg_free_fn) {
3608 search_but->arg_free_fn(search_but->arg);
3609 search_but->arg = nullptr;
3610 }
3611 break;
3612 }
3613 default:
3614 break;
3615 }
3616}
3617
3623static void ui_but_free(const bContext *C, uiBut *but)
3624{
3625 if (but->opptr) {
3627 MEM_delete(but->opptr);
3628 }
3629
3630 if (but->func_argN) {
3631 but->func_argN_free_fn(but->func_argN);
3632 }
3633
3634 if (but->tip_arg_free) {
3635 but->tip_arg_free(but->tip_arg);
3636 }
3637
3638 if (but->hold_argN) {
3639 MEM_freeN(but->hold_argN);
3640 }
3641
3642 if (but->placeholder) {
3643 MEM_freeN(but->placeholder);
3644 }
3645
3647
3648 if (but->semi_modal_state && but->semi_modal_state != but->active) {
3649 if (C) {
3650 /* XXX without this we're stuck in modal state with text edit cursor after closing popup.
3651 * Should exit active buttons as part of popup closing. */
3653 }
3654 else {
3656 }
3657 }
3658 if (but->active) {
3659 /* XXX solve later, buttons should be free-able without context ideally,
3660 * however they may have open tooltips or popup windows, which need to
3661 * be closed using a context pointer */
3662 if (C) {
3663 ui_but_active_free(C, but);
3664 }
3665 else {
3667 }
3668 }
3669
3670 if ((but->type == UI_BTYPE_IMAGE) && but->poin) {
3671 IMB_freeImBuf((ImBuf *)but->poin);
3672 }
3673
3674 ui_but_drag_free(but);
3676
3677 BLI_assert(UI_butstore_is_registered(but->block, but) == false);
3678}
3679
3681{
3682 if (block->ui_operator_free) {
3683 /* This assumes the operator instance owns the pointer. This is not
3684 * true for all operators by default, but it can be copied when needed. */
3685 MEM_delete(block->ui_operator->ptr);
3686 MEM_freeN(block->ui_operator);
3687 }
3688
3689 block->ui_operator_free = false;
3690 block->ui_operator = nullptr;
3691}
3692
3694{
3695 if (op != block->ui_operator) {
3697
3698 block->ui_operator = op;
3699 block->ui_operator_free = free;
3700 }
3701}
3702
3703void UI_block_free(const bContext *C, uiBlock *block)
3704{
3705 UI_butstore_clear(block);
3706
3707 for (const std::unique_ptr<uiBut> &but : block->buttons) {
3708 ui_but_free(C, but.get());
3709 }
3710 block->buttons.clear();
3711
3712 if (block->unit) {
3713 MEM_freeN(block->unit);
3714 }
3715
3716 if (block->func_argN) {
3717 block->func_argN_free_fn(block->func_argN);
3718 }
3719
3721
3722 BLI_freelistN(&block->saferct);
3725
3726 ui_block_free_views(block);
3727
3728 MEM_delete(block);
3729}
3730
3731void UI_block_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
3732{
3733 /* Note that #uiBlock.active shouldn't be checked here, since notifier listening happens before
3734 * drawing, so there are no active blocks at this point. */
3735
3737 listener->listener_func(listener_params);
3738 }
3739
3740 ui_block_views_listen(block, listener_params);
3741}
3742
3744{
3745 ARegion *region = CTX_wm_region(C);
3746 wmWindow *window = CTX_wm_window(C);
3747
3748 LISTBASE_FOREACH (uiBlock *, block, lb) {
3749 if (block->active) {
3750 ui_update_window_matrix(window, region, block);
3751 }
3752 }
3753}
3754
3756{
3757 LISTBASE_FOREACH (uiBlock *, block, lb) {
3758 if (block->active) {
3760 }
3761 }
3762}
3763
3764void UI_blocklist_draw(const bContext *C, const ListBase *lb)
3765{
3766 LISTBASE_FOREACH (uiBlock *, block, lb) {
3767 if (block->active) {
3768 UI_block_draw(C, block);
3769 }
3770 }
3771}
3772
3774{
3775 ListBase *lb = &region->runtime->uiblocks;
3776 while (uiBlock *block = static_cast<uiBlock *>(BLI_pophead(lb))) {
3777 UI_block_free(C, block);
3778 }
3779 region->runtime->block_name_map.clear();
3780}
3781
3783{
3784 ListBase *lb = &region->runtime->uiblocks;
3785
3786 LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) {
3787 if (!block->handle) {
3788 if (block->active) {
3789 block->active = false;
3790 }
3791 else {
3792 if (region->runtime->block_name_map.lookup_default(block->name, nullptr) == block) {
3793 region->runtime->block_name_map.remove_as(block->name);
3794 }
3795 BLI_remlink(lb, block);
3796 UI_block_free(C, block);
3797 }
3798 }
3799 }
3800}
3801
3803{
3804 ListBase *lb = &region->runtime->uiblocks;
3805 uiBlock *oldblock = nullptr;
3806
3807 /* each listbase only has one block with this name, free block
3808 * if is already there so it can be rebuilt from scratch */
3809 if (lb) {
3810 oldblock = region->runtime->block_name_map.lookup_default(block->name, nullptr);
3811
3812 if (oldblock) {
3813 oldblock->active = false;
3814 oldblock->panel = nullptr;
3815 oldblock->handle = nullptr;
3816 }
3817
3818 /* at the beginning of the list! for dynamical menus/blocks */
3819 BLI_addhead(lb, block);
3820 region->runtime->block_name_map.add_overwrite_as(block->name, block);
3821 }
3822
3823 block->oldblock = oldblock;
3824}
3825
3827 Scene *scene,
3828 wmWindow *window,
3829 ARegion *region,
3830 std::string name,
3832{
3833 uiBlock *block = MEM_new<uiBlock>(__func__);
3834 block->active = true;
3835 block->emboss = emboss;
3836 block->evil_C = (void *)C; /* XXX */
3837
3838 if (scene) {
3839 /* store display device name, don't lookup for transformations yet
3840 * block could be used for non-color displays where looking up for transformation
3841 * would slow down redraw, so only lookup for actual transform when it's indeed
3842 * needed
3843 */
3845
3846 /* Copy to avoid crash when scene gets deleted with UI still open. */
3847 UnitSettings *unit = MEM_callocN<UnitSettings>(__func__);
3848 memcpy(unit, &scene->unit, sizeof(scene->unit));
3849 block->unit = unit;
3850 }
3851 else {
3853 }
3854
3855 block->name = std::move(name);
3856
3857 if (region) {
3858 UI_block_region_set(block, region);
3859 }
3860
3861 /* Prevent reallocations on redraw, most of the time blocks layout will be the same. */
3862 if (block->oldblock) {
3863 block->buttons.reserve(block->oldblock->buttons.size());
3864 }
3865
3866 /* Set window matrix and aspect for region and OpenGL state. */
3867 ui_update_window_matrix(window, region, block);
3868
3869 /* Tag as popup menu if not created within a region. */
3870 if (!(region && region->runtime->visible)) {
3871 block->auto_open = true;
3872 block->flag |= UI_BLOCK_LOOP;
3873 }
3874
3875 return block;
3876}
3877
3879 ARegion *region,
3880 std::string name,
3882{
3883 return UI_block_begin(C, CTX_data_scene(C), CTX_wm_window(C), region, std::move(name), emboss);
3884}
3885
3887 void (*listener_func)(const wmRegionListenerParams *params))
3888{
3889 uiBlockDynamicListener *listener = static_cast<uiBlockDynamicListener *>(
3890 MEM_mallocN(sizeof(*listener), __func__));
3891 listener->listener_func = listener_func;
3892 BLI_addtail(&block->dynamic_listeners, listener);
3893}
3894
3896{
3897 return block->emboss;
3898}
3899
3901{
3902 block->emboss = emboss;
3903}
3904
3905void UI_block_theme_style_set(uiBlock *block, char theme_style)
3906{
3907 block->theme_style = theme_style;
3908}
3909
3911{
3912 return block->flag & UI_BLOCK_SEARCH_ONLY;
3913}
3914
3915void UI_block_set_search_only(uiBlock *block, bool search_only)
3916{
3917 SET_FLAG_FROM_TEST(block->flag, search_only, UI_BLOCK_SEARCH_ONLY);
3918}
3919
3920static void ui_but_build_drawstr_float(uiBut *but, double value)
3921{
3922 PropertySubType subtype = PROP_NONE;
3923 if (but->rnaprop) {
3924 subtype = RNA_property_subtype(but->rnaprop);
3925 }
3926
3927 /* Change negative zero to regular zero, without altering anything else. */
3928 value += +0.0f;
3929
3930 if (value >= double(UI_FLOAT_VALUE_DISPLAY_MAX)) {
3931 but->drawstr = but->str + "inf";
3932 }
3933 else if (value <= double(UI_FLOAT_VALUE_DISPLAY_MIN)) {
3934 but->drawstr = but->str + "-inf";
3935 }
3936 else if (subtype == PROP_PERCENTAGE) {
3937 const int prec = ui_but_calc_float_precision(but, value);
3938 but->drawstr = fmt::format("{}{:.{}f}%", but->str, value, prec);
3939 }
3940 else if (subtype == PROP_PIXEL) {
3941 const int prec = ui_but_calc_float_precision(but, value);
3942 but->drawstr = fmt::format("{}{:.{}f} px", but->str, value, prec);
3943 }
3944 else if (subtype == PROP_FACTOR) {
3945 const int precision = ui_but_calc_float_precision(but, value);
3946
3947 if (U.factor_display_type == USER_FACTOR_AS_FACTOR) {
3948 but->drawstr = fmt::format("{}{:.{}f}", but->str, value, precision);
3949 }
3950 else {
3951 but->drawstr = fmt::format("{}{:.{}f}", but->str, value * 100, std::max(0, precision - 2));
3952 }
3953 }
3954 else if (ui_but_is_unit(but)) {
3955 char new_str[UI_MAX_DRAW_STR];
3956 ui_get_but_string_unit(but, new_str, sizeof(new_str), value, true, -1);
3957 but->drawstr = but->str + new_str;
3958 }
3959 else {
3960 const int prec = ui_but_calc_float_precision(but, value);
3961 but->drawstr = fmt::format("{}{:.{}f}", but->str, value, prec);
3962 }
3963}
3964
3965static void ui_but_build_drawstr_int(uiBut *but, int value)
3966{
3967 PropertySubType subtype = PROP_NONE;
3968 if (but->rnaprop) {
3969 subtype = RNA_property_subtype(but->rnaprop);
3970 }
3971
3972 but->drawstr = but->str + std::to_string(value);
3973
3974 if (subtype == PROP_PERCENTAGE) {
3975 but->drawstr += "%";
3976 }
3977 else if (subtype == PROP_PIXEL) {
3978 but->drawstr += " px";
3979 }
3980}
3981
3987static void ui_but_update_ex(uiBut *but, const bool validate)
3988{
3989 /* if something changed in the button */
3990 double value = UI_BUT_VALUE_UNSET;
3991
3992 ui_but_update_select_flag(but, &value);
3993
3994 /* only update soft range while not editing */
3995 if (!ui_but_is_editing(but)) {
3996 if ((but->rnaprop != nullptr) || (but->poin && (but->pointype & UI_BUT_POIN_TYPES))) {
3998 }
3999 }
4000
4001 /* test for min and max, icon sliders, etc */
4002 switch (but->type) {
4003 case UI_BTYPE_NUM:
4004 case UI_BTYPE_SCROLL:
4006 if (validate) {
4007 UI_GET_BUT_VALUE_INIT(but, value);
4008 if (value < double(but->hardmin)) {
4009 ui_but_value_set(but, but->hardmin);
4010 }
4011 else if (value > double(but->hardmax)) {
4012 ui_but_value_set(but, but->hardmax);
4013 }
4014
4015 /* max must never be smaller than min! Both being equal is allowed though */
4016 BLI_assert(but->softmin <= but->softmax && but->hardmin <= but->hardmax);
4017 }
4018 break;
4019
4022 if ((but->rnaprop == nullptr) || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE))
4023 {
4026 }
4027
4028 but->iconadd = (but->flag & UI_SELECT) ? 1 : 0;
4029 }
4030 break;
4031
4032 /* quiet warnings for unhandled types */
4033 default:
4034 break;
4035 }
4036
4037 switch (but->type) {
4038 case UI_BTYPE_MENU:
4039 if (BLI_rctf_size_x(&but->rect) >= (UI_UNIT_X * 2)) {
4040 /* only needed for menus in popup blocks that don't recreate buttons on redraw */
4041 if (but->block->flag & UI_BLOCK_LOOP) {
4042 if (but->rnaprop && (RNA_property_type(but->rnaprop) == PROP_ENUM)) {
4043 const int value_enum = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
4044
4045 EnumPropertyItem item;
4047 static_cast<bContext *>(but->block->evil_C),
4048 &but->rnapoin,
4049 but->rnaprop,
4050 value_enum,
4051 &item))
4052 {
4053 but->str = item.name;
4054 but->icon = item.icon;
4055 }
4056 }
4057 }
4058 but->drawstr = but->str;
4059 }
4060 break;
4061
4062 case UI_BTYPE_NUM:
4064 if (but->editstr) {
4065 break;
4066 }
4067 UI_GET_BUT_VALUE_INIT(but, value);
4068 if (ui_but_is_float(but)) {
4069 ui_but_build_drawstr_float(but, value);
4070 }
4071 else {
4072 ui_but_build_drawstr_int(but, int(value));
4073 }
4074 break;
4075
4076 case UI_BTYPE_LABEL:
4077 if (ui_but_is_float(but)) {
4078 UI_GET_BUT_VALUE_INIT(but, value);
4079 const int prec = ui_but_calc_float_precision(but, value);
4080 but->drawstr = fmt::format("{}{:.{}f}", but->str, value, prec);
4081 }
4082 else {
4083 but->drawstr = but->str;
4084 }
4085
4086 break;
4087
4088 case UI_BTYPE_TEXT:
4090 if (!but->editstr) {
4091 char str[UI_MAX_DRAW_STR];
4093 but->drawstr = fmt::format("{}{}", but->str, str);
4094 }
4095 break;
4096
4097 case UI_BTYPE_KEY_EVENT: {
4098 const char *str;
4099 if (but->flag & UI_SELECT) {
4100 str = IFACE_("Press a key");
4101 }
4102 else {
4103 UI_GET_BUT_VALUE_INIT(but, value);
4104 str = WM_key_event_string(short(value), false);
4105 }
4106 but->drawstr = fmt::format("{}{}", but->str, str);
4107 break;
4108 }
4110 if (but->flag & UI_SELECT) {
4111 const uiButHotkeyEvent *hotkey_but = (uiButHotkeyEvent *)but;
4112
4113 if (hotkey_but->modifier_key) {
4114 /* Rely on #KM_NOTHING being zero for `type`, `val` ... etc. */
4115 wmKeyMapItem kmi_dummy = {nullptr};
4116 kmi_dummy.shift = (hotkey_but->modifier_key & KM_SHIFT) ? KM_MOD_HELD : KM_NOTHING;
4117 kmi_dummy.ctrl = (hotkey_but->modifier_key & KM_CTRL) ? KM_MOD_HELD : KM_NOTHING;
4118 kmi_dummy.alt = (hotkey_but->modifier_key & KM_ALT) ? KM_MOD_HELD : KM_NOTHING;
4119 kmi_dummy.oskey = (hotkey_but->modifier_key & KM_OSKEY) ? KM_MOD_HELD : KM_NOTHING;
4120 kmi_dummy.hyper = (hotkey_but->modifier_key & KM_HYPER) ? KM_MOD_HELD : KM_NOTHING;
4121
4122 but->drawstr = WM_keymap_item_to_string(&kmi_dummy, true).value_or("");
4123 }
4124 else {
4125 but->drawstr = IFACE_("Press a key");
4126 }
4127 }
4128 else {
4129 but->drawstr = but->str;
4130 }
4131
4132 break;
4133
4134 case UI_BTYPE_HSVCUBE:
4135 case UI_BTYPE_HSVCIRCLE:
4136 break;
4137 default:
4138 but->drawstr = but->str;
4139 break;
4140 }
4141
4142 /* if we are doing text editing, this will override the drawstr */
4143 if (but->editstr) {
4144 but->drawstr.clear();
4145 }
4146
4147 /* text clipping moved to widget drawing code itself */
4148}
4149
4151{
4152 ui_but_update_ex(but, false);
4153}
4154
4156{
4157 ui_but_update_ex(but, true);
4158}
4159
4161{
4162 /* if other align was active, end it */
4163 if (block->flag & UI_BUT_ALIGN) {
4164 UI_block_align_end(block);
4165 }
4166
4167 block->flag |= UI_BUT_ALIGN_DOWN;
4168 block->alignnr++;
4169
4170 /* Buttons declared after this call will get this `alignnr`. */ /* XXX flag? */
4171}
4172
4174{
4175 block->flag &= ~UI_BUT_ALIGN; /* all 4 flags */
4176}
4177
4182
4183void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3])
4184{
4185 const ColorManagedDisplay *display = ui_block_cm_display_get(block);
4186
4188}
4189
4193static std::unique_ptr<uiBut> ui_but_new(const eButType type)
4194{
4195 std::unique_ptr<uiBut> but{};
4196
4197 switch (type) {
4198 case UI_BTYPE_NUM:
4199 but = std::make_unique<uiButNumber>();
4200 break;
4202 but = std::make_unique<uiButNumberSlider>();
4203 break;
4204 case UI_BTYPE_COLOR:
4205 but = std::make_unique<uiButColor>();
4206 break;
4207 case UI_BTYPE_DECORATOR:
4208 but = std::make_unique<uiButDecorator>();
4209 break;
4210 case UI_BTYPE_TAB:
4211 but = std::make_unique<uiButTab>();
4212 break;
4214 but = std::make_unique<uiButSearch>();
4215 break;
4216 case UI_BTYPE_PROGRESS:
4217 but = std::make_unique<uiButProgress>();
4218 break;
4219 case UI_BTYPE_SEPR_LINE:
4220 but = std::make_unique<uiButSeparatorLine>();
4221 break;
4222 case UI_BTYPE_HSVCUBE:
4223 but = std::make_unique<uiButHSVCube>();
4224 break;
4225 case UI_BTYPE_COLORBAND:
4226 but = std::make_unique<uiButColorBand>();
4227 break;
4228 case UI_BTYPE_CURVE:
4229 but = std::make_unique<uiButCurveMapping>();
4230 break;
4232 but = std::make_unique<uiButCurveProfile>();
4233 break;
4235 but = std::make_unique<uiButHotkeyEvent>();
4236 break;
4237 case UI_BTYPE_VIEW_ITEM:
4238 but = std::make_unique<uiButViewItem>();
4239 break;
4240 case UI_BTYPE_LABEL:
4241 but = std::make_unique<uiButLabel>();
4242 break;
4243 case UI_BTYPE_SCROLL:
4244 but = std::make_unique<uiButScrollBar>();
4245 break;
4246 default:
4247 but = std::make_unique<uiBut>();
4248 break;
4249 }
4250
4251 but->type = type;
4252 return but;
4253}
4254
4256{
4257 if (but->type == new_type) {
4258 /* Nothing to do. */
4259 return but;
4260 }
4261
4262 const int64_t but_index = but->block->but_index(but);
4263
4264 /* Remove old button address */
4265 std::unique_ptr<uiBut> old_but_ptr = std::move(but->block->buttons[but_index]);
4266
4267 /* Button may have pointer to a member within itself, this will have to be updated. */
4268 const bool has_poin_ptr_to_self = but->poin == (char *)but;
4269
4270 /* Copy construct button with the new type. */
4271 but->block->buttons[but_index] = ui_but_new(new_type);
4272 but = but->block->buttons[but_index].get();
4273 *but = *old_but_ptr;
4274 /* We didn't mean to override this :) */
4275 but->type = new_type;
4276 if (has_poin_ptr_to_self) {
4277 but->poin = (char *)but;
4278 }
4279
4280 if (but->layout) {
4281 const bool found_layout = ui_layout_replace_but_ptr(but->layout, old_but_ptr.get(), but);
4282 BLI_assert(found_layout);
4283 UNUSED_VARS_NDEBUG(found_layout);
4284 ui_button_group_replace_but_ptr(uiLayoutGetBlock(but->layout), old_but_ptr.get(), but);
4285 }
4286#ifdef WITH_PYTHON
4288 UI_editsource_but_replace(old_but_ptr.get(), but);
4289 }
4290#endif
4291
4292 return but;
4293}
4294
4299static uiBut *ui_def_but(uiBlock *block,
4300 int type,
4301 int retval,
4302 const StringRef str,
4303 int x,
4304 int y,
4305 short width,
4306 short height,
4307 void *poin,
4308 float min,
4309 float max,
4310 const std::optional<StringRef> tip)
4311{
4312 /* Allow negative separators. */
4313 BLI_assert((width >= 0 && height >= 0) || (type == UI_BTYPE_SEPR));
4314
4315 if (type & UI_BUT_POIN_TYPES) { /* a pointer is required */
4316 if (poin == nullptr) {
4317 BLI_assert(0);
4318 return nullptr;
4319 }
4320 }
4321
4322 block->buttons.append(ui_but_new((eButType)(type & BUTTYPE)));
4323 uiBut *but = block->buttons.last().get();
4324
4326 but->bit = type & UI_BUT_POIN_BIT;
4327 but->bitnr = type & 31;
4328
4329 but->retval = retval;
4330
4331 but->str = str;
4332
4333 but->rect.xmin = x;
4334 but->rect.ymin = y;
4335 but->rect.xmax = but->rect.xmin + width;
4336 but->rect.ymax = but->rect.ymin + height;
4337
4338 but->poin = (char *)poin;
4339 but->hardmin = but->softmin = min;
4340 but->hardmax = but->softmax = max;
4341 but->tip = tip.value_or("");
4342
4343 but->disabled_info = block->lockstr;
4344 but->emboss = block->emboss;
4345
4346 but->block = block; /* pointer back, used for front-buffer status, and picker. */
4347
4348 if ((block->flag & UI_BUT_ALIGN) && ui_but_can_align(but)) {
4349 but->alignnr = block->alignnr;
4350 }
4351
4352 but->func = block->func;
4353 but->func_arg1 = block->func_arg1;
4354 but->func_arg2 = block->func_arg2;
4355
4356 but->funcN = block->funcN;
4357 if (block->func_argN) {
4358 but->func_argN = block->func_argN_copy_fn(block->func_argN);
4361 }
4362
4363 but->pos = -1; /* cursor invisible */
4364
4365 if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* add a space to name */
4366 if (!but->str.empty() && but->str.size() < UI_MAX_NAME_STR - 2) {
4367 if (but->str[but->str.size() - 1] != ' ') {
4368 but->str += ' ';
4369 }
4370 }
4371 }
4372
4373 if (block->flag & UI_BLOCK_PIE_MENU) {
4374 but->drawflag |= UI_BUT_TEXT_LEFT;
4375 if (!but->str.empty()) {
4376 but->drawflag |= UI_BUT_ICON_LEFT;
4377 }
4378 }
4379 else if (((block->flag & UI_BLOCK_LOOP) && !ui_block_is_popover(block) &&
4380 !(block->flag & UI_BLOCK_QUICK_SETUP)) ||
4381 ELEM(but->type,
4389 {
4391 }
4392#ifdef USE_NUMBUTS_LR_ALIGN
4393 else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
4394 if (!but->str.empty()) {
4395 but->drawflag |= UI_BUT_TEXT_LEFT;
4396 }
4397 }
4398#endif
4399
4400 but->drawflag |= (block->flag & UI_BUT_ALIGN);
4401
4402 if (block->lock == true) {
4403 but->flag |= UI_BUT_DISABLED;
4404 }
4405
4406 /* Keep track of `UI_interface_c.hh`. */
4407 if (ELEM(but->type,
4421 (but->type >= UI_BTYPE_SEARCH_MENU))
4422 {
4423 /* pass */
4424 }
4425 else {
4426 but->flag |= UI_BUT_UNDO;
4427 }
4428
4429 if (ELEM(but->type, UI_BTYPE_COLOR)) {
4431 }
4432
4433 if (block->curlayout) {
4434 ui_layout_add_but(block->curlayout, but);
4435 }
4436
4437#ifdef WITH_PYTHON
4438 /* If the `UI_OT_editsource` is running, extract the source info from the button. */
4441 }
4442#endif
4443
4444 return but;
4445}
4446
4447void ui_def_but_icon(uiBut *but, const int icon, const int flag)
4448{
4449 if (icon) {
4450 ui_icon_ensure_deferred(static_cast<const bContext *>(but->block->evil_C),
4451 icon,
4452 (flag & UI_BUT_ICON_PREVIEW) != 0);
4453 }
4454 but->icon = icon;
4455 but->flag |= flag;
4456
4457 if (!but->str.empty()) {
4458 but->drawflag |= UI_BUT_ICON_LEFT;
4459 }
4460}
4461
4463{
4464 but->icon = ICON_NONE;
4465 but->flag &= ~UI_HAS_ICON;
4467}
4468
4469static void ui_def_but_rna__menu(bContext *C, uiLayout *layout, void *but_p)
4470{
4471 uiBlock *block = uiLayoutGetBlock(layout);
4472 uiPopupBlockHandle *handle = block->handle;
4473 uiBut *but = (uiBut *)but_p;
4474 const int current_value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
4475
4476 /* see comment in ui_item_enum_expand, re: `uiname`. */
4477 const EnumPropertyItem *item_array;
4478
4480
4481 bool free;
4482 RNA_property_enum_items_gettexted(static_cast<bContext *>(block->evil_C),
4483 &but->rnapoin,
4484 but->rnaprop,
4485 &item_array,
4486 nullptr,
4487 &free);
4488
4489 /* We don't want nested rows, cols in menus. */
4490 UI_block_layout_set_current(block, layout);
4491
4492 int totitems = 0;
4493 int categories = 0;
4494 bool has_item_with_icon = false;
4495 int columns = 1;
4496 int rows = 0;
4497
4498 const wmWindow *win = CTX_wm_window(C);
4499
4500 /* Calculate the maximum number of rows that can fit in half the height of this window. */
4501 const float row_height = float(UI_UNIT_Y) / but->block->aspect;
4502 const float vertical_space = (float(WM_window_native_pixel_y(win)) / 2.0f) - (UI_UNIT_Y * 3.0f);
4503 const int max_rows = std::max(int(vertical_space / row_height) - 1, 1);
4504
4505 float text_width = 0.0f;
4506 BLF_size(BLF_default(), UI_style_get()->widget.points * UI_SCALE_FAC);
4507 int col_rows = 0;
4508 float col_width = 0.0f;
4509
4510 for (const EnumPropertyItem *item = item_array; item->identifier; item++, totitems++) {
4511 col_rows++;
4512 if (col_rows > 1 && (col_rows > max_rows || (!item->identifier[0] && item->name))) {
4513 columns++;
4514 text_width += col_width;
4515 col_width = 0;
4516 col_rows = 0;
4517 }
4518 if (!item->identifier[0] && item->name) {
4519 categories++;
4520 /* The category name adds to the column length. */
4521 col_rows++;
4522 }
4523 if (item->icon) {
4524 has_item_with_icon = true;
4525 }
4526 if (item->name && item->name[0]) {
4527 float item_width = BLF_width(BLF_default(), item->name, BLF_DRAW_STR_DUMMY_MAX);
4528 col_width = std::max(col_width, item_width + (100.0f * UI_SCALE_FAC));
4529 }
4530 rows = std::max(rows, col_rows);
4531 }
4532 text_width += col_width;
4533 text_width /= but->block->aspect;
4534
4535 if (categories == 0) {
4536 /* Long lists without categories (section titles) can be wrapped
4537 * to any nice combination of columns and rows. First use (long-
4538 * standing) code that wraps most lists pleasantly. */
4539 columns = std::max((totitems + 20) / 20, 1);
4540 if (columns > 8) {
4541 columns = (totitems + 25) / 25;
4542 }
4543 /* If above results in more rows than can fit in available vertical
4544 * space, then break it into columns of rows of maximum length. */
4545 if ((totitems / columns) > max_rows) {
4546 columns = std::max((totitems + col_rows) / max_rows, 1);
4547 }
4548 rows = std::max(totitems / columns, 1);
4549 while (rows * columns < totitems) {
4550 rows++;
4551 }
4552 }
4553
4554 /* If the estimated width of the menu is wider than the width of
4555 * this window, then we have to collapse it to a single column. */
4556 if (columns > 1 && text_width > WM_window_native_pixel_x(win)) {
4557 columns = 1;
4558 rows = totitems;
4559 }
4560
4561 const char *title = RNA_property_ui_name(but->rnaprop);
4562
4563 /* Is there a non-blank label before this button on the same row? */
4564 uiBut *but_prev = but->block->prev_but(but);
4565 const bool prior_label = but_prev && but_prev->type == UI_BTYPE_LABEL && but_prev->str[0] &&
4566 but_prev->alignnr == but->alignnr;
4567
4568 /* When true, store a copy of the description and use the tool-tip callback to return that copy.
4569 * This way, further calls to #EnumPropertyRNA::item_fn which occur when evaluating shortcuts
4570 * don't cause strings to be freed. See #ui_but_event_property_operator_string, see: #129151.
4571 *
4572 * - This is *not* a generic fix for #126541,
4573 * references to strings still need to be held by Python.
4574 *
4575 * - Duplicating descriptions in most UI logic should be avoided.
4576 * Make an exception for menus as they aren't typically refreshed during animation
4577 * playback or other situations where the overhead would be noticeable.
4578 */
4579 const bool use_enum_copy_description = free &&
4580 ((RNA_property_is_idprop(but->rnaprop) == false) &&
4581 (RNA_property_py_data_get(but->rnaprop) != nullptr));
4582
4583 if (title && title[0] && (categories == 0) && (!but->str[0] || !prior_label)) {
4584 /* Show title when no categories and calling button has no text or prior label. */
4585 uiDefBut(
4586 block, UI_BTYPE_LABEL, 0, title, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, nullptr, 0.0, 0.0, "");
4587 layout->separator();
4588 }
4589
4590 /* NOTE: `item_array[...]` is reversed on access. */
4591
4592 /* create items */
4593 uiLayout *split = &layout->split(0.0f, false);
4594
4595 bool new_column;
4596
4597 int column_end = 0;
4598 uiLayout *column = nullptr;
4599 for (int a = 0; a < totitems; a++) {
4600 new_column = (a == column_end);
4601 if (new_column) {
4602 /* start new column, and find out where it ends in advance, so we
4603 * can flip the order of items properly per column */
4604 column_end = totitems;
4605
4606 for (int b = a + 1; b < totitems; b++) {
4607 const EnumPropertyItem *item = &item_array[b];
4608
4609 /* new column on N rows or on separation label */
4610 if (((b - a) % rows == 0) || (columns > 1 && !item->identifier[0] && item->name)) {
4611 column_end = b;
4612 break;
4613 }
4614 }
4615
4616 column = &split->column(false);
4617 }
4618
4619 const EnumPropertyItem *item = &item_array[a];
4620
4621 if (new_column && (categories > 0) && (columns > 1) && item->identifier[0]) {
4622 column->label("", ICON_NONE);
4623 column->separator();
4624 }
4625
4626 if (!item->identifier[0]) {
4627 if (item->name || columns > 1) {
4628 if (item->icon) {
4629 column->label(item->name, item->icon);
4630 }
4631 else if (item->name) {
4632 /* Do not use uiLayout::label here, as our root layout is a menu one,
4633 * it will add a fake blank icon! */
4634 uiDefBut(block,
4636 0,
4637 item->name,
4638 0,
4639 0,
4640 UI_UNIT_X * 5,
4641 UI_UNIT_Y,
4642 nullptr,
4643 0.0,
4644 0.0,
4645 "");
4646 }
4647 }
4648 column->separator();
4649 }
4650 else {
4651 int icon = item->icon;
4652 std::optional<StringRef> description_static;
4653 if (!use_enum_copy_description) {
4654 description_static = item->description;
4655 }
4656
4657 /* Use blank icon if there is none for this item (but for some other one) to make sure labels
4658 * align. */
4659 if (icon == ICON_NONE && has_item_with_icon) {
4660 icon = ICON_BLANK1;
4661 }
4662
4663 uiBut *item_but;
4664 if (icon) {
4665 item_but = uiDefIconTextButI(block,
4667 B_NOP,
4668 icon,
4669 item->name,
4670 0,
4671 0,
4672 UI_UNIT_X * 5,
4673 UI_UNIT_Y,
4674 &handle->retvalue,
4675 item->value,
4676 0.0,
4677 description_static);
4678 }
4679 else {
4680 item_but = uiDefButI(block,
4682 B_NOP,
4683 item->name,
4684 0,
4685 0,
4686 UI_UNIT_X * 5,
4687 UI_UNIT_X,
4688 &handle->retvalue,
4689 item->value,
4690 0.0,
4691 description_static);
4692 }
4693 if (item->value == current_value) {
4694 item_but->flag |= UI_SELECT_DRAW;
4695 }
4696
4697 if (use_enum_copy_description) {
4698 if (item->description && item->description[0]) {
4699 char *description_copy = BLI_strdup(item->description);
4701 item_but,
4702 [](bContext * /*C*/, void *argN, const StringRef /*tip*/) -> std::string {
4703 return static_cast<const char *>(argN);
4704 },
4705 description_copy,
4706 MEM_freeN);
4707 }
4708 }
4709 }
4710 }
4711
4712 UI_block_layout_set_current(block, layout);
4713
4714 if (free) {
4715 MEM_freeN(item_array);
4716 }
4717}
4718
4719static void ui_def_but_rna__panel_type(bContext *C, uiLayout *layout, void *arg)
4720{
4721 PanelType *panel_type = static_cast<PanelType *>(arg);
4722 if (panel_type) {
4723 ui_item_paneltype_func(C, layout, panel_type);
4724 }
4725 else {
4726 layout->label(RPT_("Missing Panel"), ICON_NONE);
4727 }
4728}
4729
4730void ui_but_rna_menu_convert_to_panel_type(uiBut *but, const char *panel_type)
4731{
4733 // BLI_assert(but->menu_create_func == ui_def_but_rna__menu);
4734 // BLI_assert((void *)but->poin == but);
4736 but->func_argN = BLI_strdup(panel_type);
4739}
4740
4742{
4744}
4745
4746static void ui_def_but_rna__menu_type(bContext *C, uiLayout *layout, void *but_p)
4747{
4748 uiBut *but = static_cast<uiBut *>(but_p);
4749 const char *menu_type = static_cast<const char *>(but->func_argN);
4750 MenuType *mt = WM_menutype_find(menu_type, true);
4751 if (mt) {
4752 ui_item_menutype_func(C, layout, mt);
4753 }
4754 else {
4755 char msg[256];
4756 SNPRINTF(msg, RPT_("Missing Menu: %s"), menu_type);
4757 layout->label(msg, ICON_NONE);
4758 }
4759}
4760
4761void ui_but_rna_menu_convert_to_menu_type(uiBut *but, const char *menu_type)
4762{
4763 BLI_assert(but->type == UI_BTYPE_MENU);
4765 BLI_assert((void *)but->poin == but);
4767
4768 if (but->func_argN && but->func_argN_free_fn) {
4769 but->func_argN_free_fn(but->func_argN);
4770 }
4773 but->func_argN = BLI_strdup(menu_type);
4774}
4775
4776static void ui_but_submenu_enable(uiBlock *block, uiBut *but)
4777{
4778 but->flag |= UI_BUT_ICON_SUBMENU;
4780}
4781
4791 int type,
4792 int retval,
4793 std::optional<StringRef> str,
4794 int x,
4795 int y,
4796 short width,
4797 short height,
4798 PointerRNA *ptr,
4799 PropertyRNA *prop,
4800 int index,
4801 float min,
4802 float max,
4803 std::optional<StringRef> tip)
4804{
4805 const PropertyType proptype = RNA_property_type(prop);
4806 int icon = 0;
4807 uiMenuCreateFunc func = nullptr;
4808
4810 BLI_assert(index == -1);
4811 }
4812
4813 /* use rna values if parameters are not specified */
4814 if ((proptype == PROP_ENUM) && ELEM(type, UI_BTYPE_MENU, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
4815 bool free;
4816 const EnumPropertyItem *item;
4818 static_cast<bContext *>(block->evil_C), ptr, prop, &item, nullptr, &free);
4819
4820 int value;
4821 /* UI_BTYPE_MENU is handled a little differently here */
4822 if (type == UI_BTYPE_MENU) {
4823 value = RNA_property_enum_get(ptr, prop);
4824 }
4825 else {
4826 value = int(max);
4827 }
4828
4829 const int i = RNA_enum_from_value(item, value);
4830 if (i != -1) {
4831
4832 if (!str) {
4833 str = item[i].name;
4834#ifdef WITH_INTERNATIONAL
4836#endif
4837 }
4838
4839 icon = item[i].icon;
4840 }
4841 else {
4842 if (!str) {
4843 if (type == UI_BTYPE_MENU) {
4844 str = "";
4845 }
4846 else {
4847 str = RNA_property_ui_name(prop);
4848 }
4849 }
4850 }
4851
4852 if (type == UI_BTYPE_MENU) {
4853 func = ui_def_but_rna__menu;
4854 }
4855
4856 if (free) {
4857 MEM_freeN(item);
4858 }
4859 }
4860 else {
4861 if (!str) {
4862 str = RNA_property_ui_name(prop);
4863 }
4864 icon = RNA_property_ui_icon(prop);
4865 }
4866
4867 if (!tip && proptype != PROP_ENUM) {
4868 tip = RNA_property_ui_description(prop);
4869 }
4870
4871 float step = -1.0f;
4872 float precision = -1.0f;
4873 if (proptype == PROP_INT) {
4874 int hardmin, hardmax, softmin, softmax, int_step;
4875
4876 RNA_property_int_range(ptr, prop, &hardmin, &hardmax);
4877 RNA_property_int_ui_range(ptr, prop, &softmin, &softmax, &int_step);
4878
4879 if (!ELEM(type, UI_BTYPE_ROW, UI_BTYPE_LISTROW) && min == max) {
4880 min = hardmin;
4881 max = hardmax;
4882 }
4883 step = int_step;
4884 precision = 0;
4885 }
4886 else if (proptype == PROP_FLOAT) {
4887 float hardmin, hardmax, softmin, softmax;
4888
4889 RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
4890 RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
4891
4892 if (!ELEM(type, UI_BTYPE_ROW, UI_BTYPE_LISTROW) && min == max) {
4893 min = hardmin;
4894 max = hardmax;
4895 }
4896 }
4897 else if (proptype == PROP_STRING) {
4898 min = 0;
4900 /* NOTE: 'max' may be zero (code for dynamically resized array). */
4901 }
4902
4903 /* now create button */
4904 uiBut *but = ui_def_but(block, type, retval, *str, x, y, width, height, nullptr, min, max, tip);
4905
4906 if (but->type == UI_BTYPE_NUM) {
4907 /* Set default values, can be overridden later. */
4909 UI_but_number_precision_set(but, precision);
4910 }
4911 else if (but->type == UI_BTYPE_NUM_SLIDER) {
4912 /* Set default values, can be overridden later. */
4914 UI_but_number_slider_precision_set(but, precision);
4915 }
4916
4917 but->rnapoin = *ptr;
4918 but->rnaprop = prop;
4919
4921 but->rnaindex = index;
4922 }
4923 else {
4924 but->rnaindex = 0;
4925 }
4926
4927 if (icon) {
4928 ui_def_but_icon(but, icon, UI_HAS_ICON);
4929 }
4930
4931 if (type == UI_BTYPE_MENU) {
4933 ui_but_submenu_enable(block, but);
4934 }
4935 }
4936 else if (type == UI_BTYPE_SEARCH_MENU) {
4937 if (proptype == PROP_POINTER) {
4938 /* Search buttons normally don't get undo, see: #54580. */
4939 but->flag |= UI_BUT_UNDO;
4940 }
4941 }
4942
4943 const char *info;
4944 if (but->rnapoin.data && !RNA_property_editable_info(&but->rnapoin, prop, &info)) {
4945 UI_but_disable(but, info);
4946 }
4947
4948 if (proptype == PROP_POINTER) {
4949 /* If the button shows an ID, automatically set it as focused in context so operators can
4950 * access it. */
4951 const PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
4952 if (pptr.data && RNA_struct_is_ID(pptr.type)) {
4953 but->context = CTX_store_add(block->contexts, "id", &pptr);
4954 }
4955 }
4956
4957 if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) {
4958 but->flag &= ~UI_BUT_UNDO;
4959 }
4960
4961 /* If this button uses units, calculate the step from this */
4962 if ((proptype == PROP_FLOAT) && ui_but_is_unit(but)) {
4963 if (type == UI_BTYPE_NUM) {
4964 uiButNumber *number_but = (uiButNumber *)but;
4965 number_but->step_size = ui_get_but_step_unit(but, number_but->step_size);
4966 }
4967 if (type == UI_BTYPE_NUM_SLIDER) {
4968 uiButNumberSlider *number_but = (uiButNumberSlider *)but;
4969 number_but->step_size = ui_get_but_step_unit(but, number_but->step_size);
4970 }
4971 }
4972
4973 if (func) {
4974 but->menu_create_func = func;
4975 but->poin = (char *)but;
4976 }
4977
4978 return but;
4979}
4980
4982 int type,
4983 int retval,
4984 std::optional<StringRef> str,
4985 int x,
4986 int y,
4987 short width,
4988 short height,
4989 PointerRNA *ptr,
4990 const StringRefNull propname,
4991 int index,
4992 float min,
4993 float max,
4994 const std::optional<StringRef> tip)
4995{
4996 PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
4997
4998 uiBut *but;
4999 if (prop) {
5000 but = ui_def_but_rna(
5001 block, type, retval, str, x, y, width, height, ptr, prop, index, min, max, tip);
5002 }
5003 else {
5004 but = ui_def_but(block, type, retval, propname, x, y, width, height, nullptr, min, max, tip);
5005
5006 UI_but_disable(but, N_("Unknown Property"));
5007 }
5008
5009 return but;
5010}
5011
5013 int type,
5015 wmOperatorCallContext opcontext,
5016 const StringRef str,
5017 int x,
5018 int y,
5019 short width,
5020 short height,
5021 std::optional<StringRef> tip)
5022{
5023 if ((!tip || tip->is_empty()) && ot && ot->srna && !ot->get_description) {
5024 tip = RNA_struct_ui_description(ot->srna);
5025 }
5026
5027 uiBut *but = ui_def_but(block, type, -1, str, x, y, width, height, nullptr, 0, 0, tip);
5028 UI_but_operator_set(but, ot, opcontext);
5029
5030 /* Enable quick tooltip label if this is a tool button without a label. */
5031 if (str.is_empty() && !ui_block_is_popover(block) && UI_but_is_tool(but)) {
5033 }
5034
5035 if (!ot) {
5036 UI_but_disable(but, "");
5037 }
5038
5039 return but;
5040}
5041
5043 int type,
5044 int retval,
5045 const StringRef str,
5046 int x,
5047 int y,
5048 short width,
5049 short height,
5050 void *poin,
5051 float min,
5052 float max,
5053 const std::optional<StringRef> tip)
5054{
5055 uiBut *but = ui_def_but(block, type, retval, str, x, y, width, height, poin, min, max, tip);
5056
5057 ui_but_update(but);
5058
5059 return but;
5060}
5061
5063 uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4])
5064{
5065 uiBut *but = ui_def_but(block, UI_BTYPE_IMAGE, 0, "", x, y, width, height, imbuf, 0, 0, "");
5066 if (color) {
5067 copy_v4_v4_uchar(but->col, color);
5068 }
5069 else {
5070 but->col[0] = 255;
5071 but->col[1] = 255;
5072 but->col[2] = 255;
5073 but->col[3] = 255;
5074 }
5075 ui_but_update(but);
5076 return but;
5077}
5078
5079uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short /*height*/)
5080{
5081 ImBuf *ibuf = UI_icon_alert_imbuf_get((eAlertIcon)icon, float(width));
5082 if (ibuf) {
5083 bTheme *btheme = UI_GetTheme();
5084 return uiDefButImage(block, ibuf, x, y, ibuf->x, ibuf->y, btheme->tui.wcol_menu_back.text);
5085 }
5086 return nullptr;
5087}
5088
5099{
5100 if (!x || !is_power_of_2_i(x)) { /* is_power_of_2_i(x) strips lowest bit */
5101 return -1;
5102 }
5103 int idx = 0;
5104
5105 if (x & 0xFFFF0000) {
5106 idx += 16;
5107 x >>= 16;
5108 }
5109 if (x & 0xFF00) {
5110 idx += 8;
5111 x >>= 8;
5112 }
5113 if (x & 0xF0) {
5114 idx += 4;
5115 x >>= 4;
5116 }
5117 if (x & 0xC) {
5118 idx += 2;
5119 x >>= 2;
5120 }
5121 if (x & 0x2) {
5122 idx += 1;
5123 }
5124
5125 return idx;
5126}
5127
5128/* Auto-complete helper functions. */
5130 size_t maxncpy;
5133 const char *startname;
5134};
5135
5136AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxncpy)
5137{
5138 AutoComplete *autocpl;
5139
5140 autocpl = MEM_callocN<AutoComplete>(__func__);
5141 autocpl->maxncpy = maxncpy;
5142 autocpl->matches = 0;
5143 autocpl->truncate = MEM_calloc_arrayN<char>(maxncpy, __func__);
5144 autocpl->startname = startname;
5145
5146 return autocpl;
5147}
5148
5150{
5151 char *truncate = autocpl->truncate;
5152 const char *startname = autocpl->startname;
5153 int match_index = 0;
5154 for (int a = 0; a < autocpl->maxncpy - 1; a++) {
5155 if (startname[a] == 0 || startname[a] != name[a]) {
5156 match_index = a;
5157 break;
5158 }
5159 }
5160
5161 /* found a match */
5162 if (startname[match_index] == 0) {
5163 autocpl->matches++;
5164 /* first match */
5165 if (truncate[0] == 0) {
5166 name.copy_utf8_truncated(truncate, autocpl->maxncpy);
5167 }
5168 else {
5169 /* remove from truncate what is not in bone->name */
5170 for (int a = 0; a < std::min<size_t>(name.size(), autocpl->maxncpy) - 1; a++) {
5171 if (name[a] == 0) {
5172 truncate[a] = 0;
5173 break;
5174 }
5175 if (truncate[a] != name[a]) {
5176 truncate[a] = 0;
5177 }
5178 }
5179 }
5180 }
5181}
5182
5183int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
5184{
5185 int match = AUTOCOMPLETE_NO_MATCH;
5186 if (autocpl->truncate[0]) {
5187 if (autocpl->matches == 1) {
5189 }
5190 else {
5192 }
5193 BLI_strncpy(autoname, autocpl->truncate, autocpl->maxncpy);
5194 }
5195 else {
5196 if (autoname != autocpl->startname) { /* don't copy a string over itself */
5197 BLI_strncpy(autoname, autocpl->startname, autocpl->maxncpy);
5198 }
5199 }
5200
5201 MEM_freeN(autocpl->truncate);
5202 MEM_freeN(autocpl);
5203 return match;
5204}
5205
5206#define PREVIEW_TILE_PAD (0.225f * UI_UNIT_X)
5207
5208int UI_preview_tile_size_x(const int size_px)
5209{
5210 const float pad = PREVIEW_TILE_PAD;
5211 return round_fl_to_int((size_px / 20.0f) * UI_UNIT_X + 2.0f * pad);
5212}
5213
5214int UI_preview_tile_size_y(const int size_px)
5215{
5216 const float font_height = UI_UNIT_Y;
5217 /* Add some extra padding to make things less tight vertically. */
5218 const float pad = PREVIEW_TILE_PAD;
5219
5220 return round_fl_to_int(UI_preview_tile_size_y_no_label(size_px) + font_height + pad);
5221}
5222
5224{
5225 const float pad = PREVIEW_TILE_PAD;
5226 return round_fl_to_int((size_px / 20.0f) * UI_UNIT_Y + 2.0f * pad);
5227}
5228
5229#undef PREVIEW_TILE_PAD
5230
5231static void ui_but_update_and_icon_set(uiBut *but, int icon)
5232{
5233 if (icon) {
5234 ui_def_but_icon(but, icon, UI_HAS_ICON);
5235 }
5236
5237 ui_but_update(but);
5238}
5239
5241 int type,
5242 int bit,
5243 int retval,
5244 const StringRef str,
5245 int x,
5246 int y,
5247 short width,
5248 short height,
5249 void *poin,
5250 float min,
5251 float max,
5252 const std::optional<StringRef> tip)
5253{
5254 const int bitIdx = findBitIndex(bit);
5255 if (bitIdx == -1) {
5256 return nullptr;
5257 }
5258 return uiDefBut(block,
5259 type | UI_BUT_POIN_BIT | bitIdx,
5260 retval,
5261 str,
5262 x,
5263 y,
5264 width,
5265 height,
5266 poin,
5267 min,
5268 max,
5269 tip);
5270}
5272 int type,
5273 int retval,
5274 const StringRef str,
5275 int x,
5276 int y,
5277 short width,
5278 short height,
5279 float *poin,
5280 float min,
5281 float max,
5282 const std::optional<StringRef> tip)
5283{
5284 return uiDefBut(block,
5285 type | UI_BUT_POIN_FLOAT,
5286 retval,
5287 str,
5288 x,
5289 y,
5290 width,
5291 height,
5292 (void *)poin,
5293 min,
5294 max,
5295 tip);
5296}
5298 int type,
5299 int retval,
5300 const StringRef str,
5301 int x,
5302 int y,
5303 short width,
5304 short height,
5305 int *poin,
5306 float min,
5307 float max,
5308 const std::optional<StringRef> tip)
5309{
5310 return uiDefBut(block,
5311 type | UI_BUT_POIN_INT,
5312 retval,
5313 str,
5314 x,
5315 y,
5316 width,
5317 height,
5318 (void *)poin,
5319 min,
5320 max,
5321 tip);
5322}
5324 int type,
5325 int bit,
5326 int retval,
5327 const StringRef str,
5328 int x,
5329 int y,
5330 short width,
5331 short height,
5332 int *poin,
5333 float min,
5334 float max,
5335 const std::optional<StringRef> tip)
5336{
5337 return uiDefButBit(block,
5338 type | UI_BUT_POIN_INT,
5339 bit,
5340 retval,
5341 str,
5342 x,
5343 y,
5344 width,
5345 height,
5346 (void *)poin,
5347 min,
5348 max,
5349 tip);
5350}
5352 int type,
5353 int retval,
5354 const StringRef str,
5355 int x,
5356 int y,
5357 short width,
5358 short height,
5359 short *poin,
5360 float min,
5361 float max,
5362 const std::optional<StringRef> tip)
5363{
5364 return uiDefBut(block,
5365 type | UI_BUT_POIN_SHORT,
5366 retval,
5367 str,
5368 x,
5369 y,
5370 width,
5371 height,
5372 (void *)poin,
5373 min,
5374 max,
5375 tip);
5376}
5378 int type,
5379 int bit,
5380 int retval,
5381 const StringRef str,
5382 int x,
5383 int y,
5384 short width,
5385 short height,
5386 short *poin,
5387 float min,
5388 float max,
5389 const std::optional<StringRef> tip)
5390{
5391 return uiDefButBit(block,
5392 type | UI_BUT_POIN_SHORT,
5393 bit,
5394 retval,
5395 str,
5396 x,
5397 y,
5398 width,
5399 height,
5400 (void *)poin,
5401 min,
5402 max,
5403 tip);
5404}
5406 int type,
5407 int retval,
5408 const StringRef str,
5409 int x,
5410 int y,
5411 short width,
5412 short height,
5413 char *poin,
5414 float min,
5415 float max,
5416 const std::optional<StringRef> tip)
5417{
5418 return uiDefBut(block,
5419 type | UI_BUT_POIN_CHAR,
5420 retval,
5421 str,
5422 x,
5423 y,
5424 width,
5425 height,
5426 (void *)poin,
5427 min,
5428 max,
5429 tip);
5430}
5432 int type,
5433 int bit,
5434 int retval,
5435 const StringRef str,
5436 int x,
5437 int y,
5438 short width,
5439 short height,
5440 char *poin,
5441 float min,
5442 float max,
5443 const std::optional<StringRef> tip)
5444{
5445 return uiDefButBit(block,
5446 type | UI_BUT_POIN_CHAR,
5447 bit,
5448 retval,
5449 str,
5450 x,
5451 y,
5452 width,
5453 height,
5454 (void *)poin,
5455 min,
5456 max,
5457 tip);
5458}
5460 int type,
5461 int retval,
5462 const std::optional<StringRef> str,
5463 int x,
5464 int y,
5465 short width,
5466 short height,
5467 PointerRNA *ptr,
5468 const StringRefNull propname,
5469 int index,
5470 float min,
5471 float max,
5472 const std::optional<StringRef> tip)
5473{
5475 block, type, retval, str, x, y, width, height, ptr, propname, index, min, max, tip);
5476 ui_but_update(but);
5477 return but;
5478}
5480 int type,
5481 int retval,
5482 const std::optional<StringRef> str,
5483 int x,
5484 int y,
5485 short width,
5486 short height,
5487 PointerRNA *ptr,
5488 PropertyRNA *prop,
5489 int index,
5490 float min,
5491 float max,
5492 const std::optional<StringRef> tip)
5493{
5494 uiBut *but = ui_def_but_rna(
5495 block, type, retval, str, x, y, width, height, ptr, prop, index, min, max, tip);
5496 ui_but_update(but);
5497 return but;
5498}
5499
5501 int type,
5503 wmOperatorCallContext opcontext,
5504 const StringRef str,
5505 int x,
5506 int y,
5507 short width,
5508 short height,
5509 const std::optional<StringRef> tip)
5510{
5511 uiBut *but = ui_def_but_operator_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
5512 ui_but_update(but);
5513 return but;
5514}
5516 int type,
5517 const StringRefNull opname,
5518 wmOperatorCallContext opcontext,
5519 std::optional<StringRef> str,
5520 int x,
5521 int y,
5522 short width,
5523 short height,
5524 const std::optional<StringRef> tip)
5525{
5526 wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false);
5527 if (!str && ot == nullptr) {
5528 str = opname;
5529 }
5530 return uiDefButO_ptr(block, type, ot, opcontext, *str, x, y, width, height, tip);
5531}
5532
5534 int type,
5535 int retval,
5536 int icon,
5537 int x,
5538 int y,
5539 short width,
5540 short height,
5541 void *poin,
5542 float min,
5543 float max,
5544 const std::optional<StringRef> tip)
5545{
5546 uiBut *but = ui_def_but(block, type, retval, "", x, y, width, height, poin, min, max, tip);
5547 ui_but_update_and_icon_set(but, icon);
5548 return but;
5549}
5551 int type,
5552 int retval,
5553 int icon,
5554 int x,
5555 int y,
5556 short width,
5557 short height,
5558 void *poin,
5559 float min,
5560 float max,
5561 const std::optional<StringRef> tip)
5562{
5563 uiBut *but = ui_def_but(block, type, retval, "", x, y, width, height, poin, min, max, tip);
5564 if (icon) {
5566
5567 /* Use the exact button size for the preview. Or do we need to let the caller control this? */
5570 }
5571
5572 ui_but_update(but);
5573 return but;
5574}
5576 int type,
5577 int bit,
5578 int retval,
5579 int icon,
5580 int x,
5581 int y,
5582 short width,
5583 short height,
5584 void *poin,
5585 float min,
5586 float max,
5587 const std::optional<StringRef> tip)
5588{
5589 const int bitIdx = findBitIndex(bit);
5590 if (bitIdx == -1) {
5591 return nullptr;
5592 }
5593 return uiDefIconBut(block,
5594 type | UI_BUT_POIN_BIT | bitIdx,
5595 retval,
5596 icon,
5597 x,
5598 y,
5599 width,
5600 height,
5601 poin,
5602 min,
5603 max,
5604 tip);
5605}
5606
5608 int type,
5609 int retval,
5610 int icon,
5611 int x,
5612 int y,
5613 short width,
5614 short height,
5615 int *poin,
5616 float min,
5617 float max,
5618 const std::optional<StringRef> tip)
5619{
5620 return uiDefIconBut(block,
5621 type | UI_BUT_POIN_INT,
5622 retval,
5623 icon,
5624 x,
5625 y,
5626 width,
5627 height,
5628 (void *)poin,
5629 min,
5630 max,
5631 tip);
5632}
5634 int type,
5635 int bit,
5636 int retval,
5637 int icon,
5638 int x,
5639 int y,
5640 short width,
5641 short height,
5642 int *poin,
5643 float min,
5644 float max,
5645 const std::optional<StringRef> tip)
5646{
5647 return uiDefIconButBit(block,
5648 type | UI_BUT_POIN_INT,
5649 bit,
5650 retval,
5651 icon,
5652 x,
5653 y,
5654 width,
5655 height,
5656 (void *)poin,
5657 min,
5658 max,
5659 tip);
5660}
5662 int type,
5663 int retval,
5664 int icon,
5665 int x,
5666 int y,
5667 short width,
5668 short height,
5669 short *poin,
5670 float min,
5671 float max,
5672 const std::optional<StringRef> tip)
5673{
5674 return uiDefIconBut(block,
5675 type | UI_BUT_POIN_SHORT,
5676 retval,
5677 icon,
5678 x,
5679 y,
5680 width,
5681 height,
5682 (void *)poin,
5683 min,
5684 max,
5685 tip);
5686}
5688 int type,
5689 int bit,
5690 int retval,
5691 int icon,
5692 int x,
5693 int y,
5694 short width,
5695 short height,
5696 short *poin,
5697 float min,
5698 float max,
5699 const std::optional<StringRef> tip)
5700{
5701 return uiDefIconButBit(block,
5702 type | UI_BUT_POIN_SHORT,
5703 bit,
5704 retval,
5705 icon,
5706 x,
5707 y,
5708 width,
5709 height,
5710 (void *)poin,
5711 min,
5712 max,
5713 tip);
5714}
5716 int type,
5717 int bit,
5718 int retval,
5719 int icon,
5720 int x,
5721 int y,
5722 short width,
5723 short height,
5724 char *poin,
5725 float min,
5726 float max,
5727 const std::optional<StringRef> tip)
5728{
5729 return uiDefIconButBit(block,
5730 type | UI_BUT_POIN_CHAR,
5731 bit,
5732 retval,
5733 icon,
5734 x,
5735 y,
5736 width,
5737 height,
5738 (void *)poin,
5739 min,
5740 max,
5741 tip);
5742}
5744 int type,
5745 int retval,
5746 int icon,
5747 int x,
5748 int y,
5749 short width,
5750 short height,
5751 PointerRNA *ptr,
5752 const StringRefNull propname,
5753 int index,
5754 float min,
5755 float max,
5756 const std::optional<StringRef> tip)
5757{
5759 block, type, retval, "", x, y, width, height, ptr, propname, index, min, max, tip);
5760 ui_but_update_and_icon_set(but, icon);
5761 return but;
5762}
5764 int type,
5765 int retval,
5766 int icon,
5767 int x,
5768 int y,
5769 short width,
5770 short height,
5771 PointerRNA *ptr,
5772 PropertyRNA *prop,
5773 int index,
5774 float min,
5775 float max,
5776 const std::optional<StringRef> tip)
5777{
5778 uiBut *but = ui_def_but_rna(
5779 block, type, retval, "", x, y, width, height, ptr, prop, index, min, max, tip);
5780 ui_but_update_and_icon_set(but, icon);
5781 return but;
5782}
5783
5785 int type,
5787 wmOperatorCallContext opcontext,
5788 int icon,
5789 int x,
5790 int y,
5791 short width,
5792 short height,
5793 const std::optional<StringRef> tip)
5794{
5795 uiBut *but = ui_def_but_operator_ptr(block, type, ot, opcontext, "", x, y, width, height, tip);
5796 ui_but_update_and_icon_set(but, icon);
5797 return but;
5798}
5800 int type,
5801 const StringRefNull opname,
5802 wmOperatorCallContext opcontext,
5803 int icon,
5804 int x,
5805 int y,
5806 short width,
5807 short height,
5808 const std::optional<StringRef> tip)
5809{
5810 wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false);
5811 return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
5812}
5813
5815 int type,
5816 int retval,
5817 int icon,
5818 const StringRef str,
5819 int x,
5820 int y,
5821 short width,
5822 short height,
5823 void *poin,
5824 float min,
5825 float max,
5826 const std::optional<StringRef> tip)
5827{
5828 uiBut *but = ui_def_but(block, type, retval, str, x, y, width, height, poin, min, max, tip);
5829 ui_but_update_and_icon_set(but, icon);
5830 but->drawflag |= UI_BUT_ICON_LEFT;
5831 return but;
5832}
5834 int type,
5835 int retval,
5836 int icon,
5837 const StringRef str,
5838 int x,
5839 int y,
5840 short width,
5841 short height,
5842 int *poin,
5843 float min,
5844 float max,
5845 const std::optional<StringRef> tip)
5846{
5847 return uiDefIconTextBut(block,
5848 type | UI_BUT_POIN_INT,
5849 retval,
5850 icon,
5851 str,
5852 x,
5853 y,
5854 width,
5855 height,
5856 (void *)poin,
5857 min,
5858 max,
5859 tip);
5860}
5862 int type,
5863 int retval,
5864 int icon,
5865 const StringRef str,
5866 int x,
5867 int y,
5868 short width,
5869 short height,
5870 short *poin,
5871 float min,
5872 float max,
5873 const std::optional<StringRef> tip)
5874{
5875 return uiDefIconTextBut(block,
5876 type | UI_BUT_POIN_SHORT,
5877 retval,
5878 icon,
5879 str,
5880 x,
5881 y,
5882 width,
5883 height,
5884 (void *)poin,
5885 min,
5886 max,
5887 tip);
5888}
5889
5891 int type,
5892 int retval,
5893 int icon,
5894 const std::optional<StringRefNull> str,
5895 int x,
5896 int y,
5897 short width,
5898 short height,
5899 PointerRNA *ptr,
5900 blender::StringRefNull propname,
5901 int index,
5902 float min,
5903 float max,
5904 const std::optional<StringRef> tip)
5905{
5907 block, type, retval, str, x, y, width, height, ptr, propname, index, min, max, tip);
5908 ui_but_update_and_icon_set(but, icon);
5909 but->drawflag |= UI_BUT_ICON_LEFT;
5910 return but;
5911}
5913 int type,
5914 int retval,
5915 int icon,
5916 const std::optional<blender::StringRef> str,
5917 int x,
5918 int y,
5919 short width,
5920 short height,
5921 PointerRNA *ptr,
5922 PropertyRNA *prop,
5923 int index,
5924 float min,
5925 float max,
5926 const std::optional<StringRef> tip)
5927{
5928 uiBut *but = ui_def_but_rna(
5929 block, type, retval, str, x, y, width, height, ptr, prop, index, min, max, tip);
5930 ui_but_update_and_icon_set(but, icon);
5931 but->drawflag |= UI_BUT_ICON_LEFT;
5932 return but;
5933}
5935 int type,
5937 wmOperatorCallContext opcontext,
5938 int icon,
5939 const StringRef str,
5940 int x,
5941 int y,
5942 short width,
5943 short height,
5944 const std::optional<StringRef> tip)
5945{
5946 uiBut *but = ui_def_but_operator_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
5947 ui_but_update_and_icon_set(but, icon);
5948 but->drawflag |= UI_BUT_ICON_LEFT;
5949 return but;
5950}
5952 int type,
5953 const StringRefNull opname,
5954 wmOperatorCallContext opcontext,
5955 int icon,
5956 const StringRef str,
5957 int x,
5958 int y,
5959 short width,
5960 short height,
5961 const std::optional<StringRef> tip)
5962{
5963 wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false);
5964 if (str.is_empty()) {
5965 return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
5966 }
5967 return uiDefIconTextButO_ptr(block, type, ot, opcontext, icon, str, x, y, width, height, tip);
5968}
5969
5971 wmOperatorType *optype,
5972 wmOperatorCallContext opcontext,
5973 const PointerRNA *opptr)
5974{
5975 but->optype = optype;
5976 but->opcontext = opcontext;
5977 but->flag &= ~UI_BUT_UNDO; /* no need for ui_but_is_rna_undo(), we never need undo here */
5978
5979 if (but->opptr) {
5980 MEM_delete(but->opptr);
5981 but->opptr = nullptr;
5982 }
5983 if (opptr) {
5984 but->opptr = MEM_new<PointerRNA>(__func__, *opptr);
5985 }
5986}
5987
5989{
5990 but->operator_never_call = true;
5991}
5992
5993/* END Button containing both string label and icon */
5994
5995/* cruft to make uiBlock and uiBut private */
5996
5998{
5999 int min = 0;
6000
6001 LISTBASE_FOREACH (uiBlock *, block, lb) {
6002 if (block == lb->first || block->rect.ymin < min) {
6003 min = block->rect.ymin;
6004 }
6005 }
6006
6007 return min;
6008}
6009
6010void UI_block_direction_set(uiBlock *block, char direction)
6011{
6012 block->direction = direction;
6013}
6014
6016{
6017 block->flag |= flag;
6018}
6019
6021{
6022 block->flag &= ~flag;
6023}
6024
6026{
6027 but->flag |= flag;
6028}
6029
6031{
6032 but->flag2 |= flag;
6033}
6034
6036{
6037 but->flag &= ~flag;
6038}
6039
6041{
6042 return (but->flag & flag) != 0;
6043}
6044
6046{
6047 but->drawflag |= flag;
6048}
6049
6051{
6052 but->drawflag &= ~flag;
6053}
6054
6056{
6057 but->dragflag |= flag;
6058}
6059
6061{
6062 but->dragflag &= ~flag;
6063}
6064
6065void UI_but_disable(uiBut *but, const char *disabled_hint)
6066{
6068
6069 /* Only one disabled hint at a time currently. Don't override the previous one here. */
6070 if (but->disabled_info && but->disabled_info[0]) {
6071 return;
6072 }
6073
6074 but->disabled_info = disabled_hint;
6075}
6076
6077void UI_but_color_set(uiBut *but, const uchar color[4])
6078{
6079 copy_v4_v4_uchar(but->col, color);
6080}
6081
6082void UI_but_placeholder_set(uiBut *but, const StringRef placeholder_text)
6083{
6085 if (placeholder_text.is_empty()) {
6086 but->placeholder = nullptr;
6087 }
6088 else {
6089 but->placeholder = BLI_strdupn(placeholder_text.data(), placeholder_text.size());
6090 }
6091}
6092
6094{
6095 const char *placeholder = (but->placeholder) ? but->placeholder : nullptr;
6096
6097 if (!placeholder && but->rnaprop) {
6098 if (but->type == UI_BTYPE_SEARCH_MENU) {
6100 const short idcode = RNA_type_to_ID_code(type);
6101 if (idcode != 0) {
6102 RNA_enum_name(rna_enum_id_type_items, idcode, &placeholder);
6103 placeholder = CTX_IFACE_(BLT_I18NCONTEXT_ID_ID, placeholder);
6104 }
6105 else if (type && !STREQ(RNA_struct_identifier(type), "UnknownType")) {
6106 placeholder = RNA_struct_ui_name(type);
6107 }
6108 }
6109 else if (but->type == UI_BTYPE_TEXT && but->icon == ICON_VIEWZOOM) {
6110 placeholder = CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Search");
6111 }
6112 }
6113
6114 return placeholder;
6115}
6116
6124
6126{
6127 return but->retval;
6128}
6129
6131{
6132 if (but->optype && !but->opptr) {
6133 but->opptr = MEM_new<PointerRNA>(__func__);
6135 }
6136
6137 return but->opptr;
6138}
6139
6141 uiBut *but,
6142 const StringRef name,
6143 const PointerRNA *ptr)
6144{
6145 bContextStore *ctx = CTX_store_add(block->contexts, name, ptr);
6146 ctx->used = true;
6147 but->context = ctx;
6148}
6149
6150void UI_but_context_int_set(uiBlock *block, uiBut *but, const StringRef name, const int64_t value)
6151{
6152 bContextStore *ctx = CTX_store_add(block->contexts, name, value);
6153 ctx->used = true;
6154 but->context = ctx;
6155}
6156
6158 const StringRef name,
6159 const StructRNA *type)
6160{
6161 return CTX_store_ptr_lookup(but->context, name, type);
6162}
6163
6164std::optional<blender::StringRefNull> UI_but_context_string_get(const uiBut *but,
6165 const StringRef name)
6166{
6167 if (!but->context) {
6168 return {};
6169 }
6170 return CTX_store_string_lookup(but->context, name);
6171}
6172
6173std::optional<int64_t> UI_but_context_int_get(const uiBut *but, const StringRef name)
6174{
6175 if (!but->context) {
6176 return {};
6177 }
6178 return CTX_store_int_lookup(but->context, name);
6179}
6180
6182{
6183 return but->context;
6184}
6185
6186void UI_but_unit_type_set(uiBut *but, const int unit_type)
6187{
6188 but->unit_type = uchar(RNA_SUBTYPE_UNIT_VALUE(unit_type));
6189}
6190
6192{
6193 const int ownUnit = int(but->unit_type);
6194
6195 /* own unit define always takes precedence over RNA provided, allowing for overriding
6196 * default value provided in RNA in a few special cases (i.e. Active Keyframe in Graph Edit)
6197 */
6198 /* XXX: this doesn't allow clearing unit completely, though the same could be said for icons */
6199 if ((ownUnit != 0) || (but->rnaprop == nullptr)) {
6200 return ownUnit << 16;
6201 }
6203}
6204
6206{
6207 block->handle_func = func;
6208 block->handle_func_arg = arg;
6209}
6210
6211void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2)
6212{
6213 block->func = func;
6214 block->func_arg1 = arg1;
6215 block->func_arg2 = arg2;
6216}
6217
6219 uiButHandleNFunc funcN,
6220 void *argN,
6221 void *arg2,
6222 uiButArgNFree func_argN_free_fn,
6223 uiButArgNCopy func_argN_copy_fn)
6224{
6225 if (block->func_argN) {
6226 block->func_argN_free_fn(block->func_argN);
6227 }
6228
6229 block->funcN = funcN;
6230 block->func_argN = argN;
6231 block->func_argN_free_fn = func_argN_free_fn;
6232 block->func_argN_copy_fn = func_argN_copy_fn;
6233 block->func_arg2 = arg2;
6234}
6235
6237{
6238 but->rename_func = func;
6239 but->rename_arg1 = arg1;
6240}
6241
6243 std::function<void(std::string &new_name)> rename_full_func)
6244{
6245 but->rename_full_func = rename_full_func;
6246}
6247
6249 std::function<void(const bContext *C, rcti *rect)> func)
6250{
6251 block->drawextra = func;
6252}
6253
6254void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
6255{
6256 but->func = func;
6257 but->func_arg1 = arg1;
6258 but->func_arg2 = arg2;
6259}
6260
6261void UI_but_func_set(uiBut *but, std::function<void(bContext &)> func)
6262{
6263 but->apply_func = std::move(func);
6264}
6265
6267 uiButHandleNFunc funcN,
6268 void *argN,
6269 void *arg2,
6270 uiButArgNFree func_argN_free_fn,
6271 uiButArgNCopy func_argN_copy_fn)
6272{
6273 if (but->func_argN) {
6274 but->func_argN_free_fn(but->func_argN);
6275 }
6276
6277 but->funcN = funcN;
6278 but->func_argN = argN;
6279 but->func_argN_free_fn = func_argN_free_fn;
6280 but->func_argN_copy_fn = func_argN_copy_fn;
6281 but->func_arg2 = arg2;
6282}
6283
6285{
6286 but->autocomplete_func = func;
6287 but->autofunc_arg = arg;
6288}
6289
6291{
6292 but->menu_step_func = func;
6293}
6294
6296{
6297 but->menu_no_hover_open = true;
6298}
6299
6300void UI_but_func_quick_tooltip_set(uiBut *but, std::function<std::string(const uiBut *but)> func)
6301{
6302 but->tip_quick_func = std::move(func);
6304}
6305
6307{
6308 but->tip_func = func;
6309 if (but->tip_arg_free) {
6310 but->tip_arg_free(but->tip_arg);
6311 }
6312 but->tip_arg = arg;
6313 but->tip_arg_free = free_arg;
6314}
6315
6318 void *arg,
6319 uiFreeArgFunc free_arg)
6320{
6321 but->tip_custom_func = func;
6322 if (but->tip_arg_free) {
6323 but->tip_arg_free(but->tip_arg);
6324 }
6325 but->tip_arg = arg;
6326 but->tip_arg_free = free_arg;
6327}
6328
6329void UI_but_func_pushed_state_set(uiBut *but, std::function<bool(const uiBut &)> func)
6330{
6331 but->pushed_state_func = func;
6332 ui_but_update(but);
6333}
6334
6336 uiBlockCreateFunc func,
6337 void *arg,
6338 const StringRef str,
6339 int x,
6340 int y,
6341 short width,
6342 short height,
6343 const std::optional<StringRef> tip)
6344{
6345 uiBut *but = ui_def_but(block, UI_BTYPE_BLOCK, 0, str, x, y, width, height, arg, 0.0, 0.0, tip);
6346 but->block_create_func = func;
6347 ui_but_update(but);
6348 return but;
6349}
6350
6352 uiBlockCreateFunc func,
6353 void *argN,
6354 const StringRef str,
6355 int x,
6356 int y,
6357 short width,
6358 short height,
6359 const std::optional<StringRef> tip,
6360 uiButArgNFree func_argN_free_fn,
6361 uiButArgNCopy func_argN_copy_fn)
6362{
6363 uiBut *but = ui_def_but(
6364 block, UI_BTYPE_BLOCK, 0, str, x, y, width, height, nullptr, 0.0, 0.0, tip);
6365 but->block_create_func = func;
6366 if (but->func_argN) {
6367 but->func_argN_free_fn(but->func_argN);
6368 }
6369 but->func_argN = argN;
6370 but->func_argN_free_fn = func_argN_free_fn;
6371 but->func_argN_copy_fn = func_argN_copy_fn;
6372 ui_but_update(but);
6373 return but;
6374}
6375
6377 uiMenuCreateFunc func,
6378 void *arg,
6379 const StringRef str,
6380 int x,
6381 int y,
6382 short width,
6383 short height,
6384 const std::optional<StringRef> tip)
6385{
6386 uiBut *but = ui_def_but(
6387 block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, tip);
6388 but->menu_create_func = func;
6389 ui_but_update(but);
6390 return but;
6391}
6392
6394 uiMenuCreateFunc func,
6395 void *arg,
6396 int icon,
6397 const StringRef str,
6398 int x,
6399 int y,
6400 short width,
6401 short height,
6402 const std::optional<StringRef> tip)
6403{
6404 uiBut *but = ui_def_but(
6405 block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, tip);
6406
6407 ui_def_but_icon(but, icon, UI_HAS_ICON);
6408
6409 but->drawflag |= UI_BUT_ICON_LEFT;
6410 ui_but_submenu_enable(block, but);
6411
6412 but->menu_create_func = func;
6413 ui_but_update(but);
6414
6415 return but;
6416}
6417
6419 uiMenuCreateFunc func,
6420 void *arg,
6421 int icon,
6422 int x,
6423 int y,
6424 short width,
6425 short height,
6426 const std::optional<StringRef> tip)
6427{
6428 uiBut *but = ui_def_but(
6429 block, UI_BTYPE_PULLDOWN, 0, "", x, y, width, height, arg, 0.0, 0.0, tip);
6430
6431 ui_def_but_icon(but, icon, UI_HAS_ICON);
6433
6434 but->menu_create_func = func;
6435 ui_but_update(but);
6436
6437 return but;
6438}
6439
6441 uiBlockCreateFunc func,
6442 void *arg,
6443 int retval,
6444 int icon,
6445 int x,
6446 int y,
6447 short width,
6448 short height,
6449 const std::optional<StringRef> tip)
6450{
6451 uiBut *but = ui_def_but(
6452 block, UI_BTYPE_BLOCK, retval, "", x, y, width, height, arg, 0.0, 0.0, tip);
6453
6454 ui_def_but_icon(but, icon, UI_HAS_ICON);
6455
6456 but->drawflag |= UI_BUT_ICON_LEFT;
6457
6458 but->block_create_func = func;
6459 ui_but_update(but);
6460
6461 return but;
6462}
6463
6465 void *arg,
6466 int retval,
6467 int icon,
6468 int maxncpy,
6469 int x,
6470 int y,
6471 short width,
6472 short height,
6473 const std::optional<StringRef> tip)
6474{
6475 uiBut *but = ui_def_but(
6476 block, UI_BTYPE_SEARCH_MENU, retval, "", x, y, width, height, arg, 0.0, maxncpy, tip);
6477
6478 ui_def_but_icon(but, icon, UI_HAS_ICON);
6479
6481
6482 ui_but_update(but);
6483
6484 return but;
6485}
6486
6488 uiButSearchCreateFn search_create_fn,
6489 uiButSearchUpdateFn search_update_fn,
6490 void *arg,
6491 const bool free_arg,
6492 uiFreeArgFunc search_arg_free_fn,
6493 uiButHandleFunc search_exec_fn,
6494 void *active)
6495{
6496 uiButSearch *search_but = (uiButSearch *)but;
6497
6499
6500 /* needed since callers don't have access to internal functions
6501 * (as an alternative we could expose it) */
6502 if (search_create_fn == nullptr) {
6503 search_create_fn = ui_searchbox_create_generic;
6504 }
6505
6506 if (search_but->arg_free_fn != nullptr) {
6507 search_but->arg_free_fn(search_but->arg);
6508 search_but->arg = nullptr;
6509 }
6510
6511 search_but->popup_create_fn = search_create_fn;
6512 search_but->items_update_fn = search_update_fn;
6513 search_but->item_active = active;
6514
6515 search_but->arg = arg;
6516 search_but->arg_free_fn = search_arg_free_fn;
6517
6518 if (search_exec_fn) {
6519#ifndef NDEBUG
6520 if (but->func) {
6521 /* watch this, can be cause of much confusion, see: #47691 */
6522 printf("%s: warning, overwriting button callback with search function callback!\n",
6523 __func__);
6524 }
6525#endif
6526 /* Handling will pass the active item as arg2 later, so keep it nullptr here. */
6527 if (free_arg) {
6528 UI_but_funcN_set(but, search_exec_fn, search_but->arg, nullptr);
6529 }
6530 else {
6531 UI_but_func_set(but, search_exec_fn, search_but->arg, nullptr);
6532 }
6533 }
6534
6535 /* search buttons show red-alert if item doesn't exist, not for menus. Don't do this for
6536 * buttons where any result is valid anyway, since any string will be valid anyway. */
6537 if (0 == (but->block->flag & UI_BLOCK_LOOP) && !search_but->results_are_suggestions) {
6538 /* skip empty buttons, not all buttons need input, we only show invalid */
6539 if (!but->drawstr.empty()) {
6540 ui_but_search_refresh(search_but);
6541 }
6542 }
6543}
6544
6546{
6547 uiButSearch *but_search = (uiButSearch *)but;
6549
6550 but_search->item_context_menu_fn = context_menu_fn;
6551}
6552
6553void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
6554{
6555 uiButSearch *but_search = (uiButSearch *)but;
6557
6558 but_search->item_sep_string = search_sep_string;
6559}
6560
6562{
6563 uiButSearch *but_search = (uiButSearch *)but;
6565
6566 but_search->item_tooltip_fn = tooltip_fn;
6567}
6568
6570{
6571 uiButSearch *but_search = (uiButSearch *)but;
6573 but_search->listen_fn = listen_fn;
6574}
6575
6577{
6578 uiButSearch *but_search = (uiButSearch *)but;
6580
6581 but_search->results_are_suggestions = value;
6582}
6583
6584/* Callbacks for operator search button. */
6586 const bContext *C, void *but, const char *str, uiSearchItems *items, const bool /*is_first*/)
6587{
6588 wmOperatorType *ot = ((uiBut *)but)->optype;
6589 PropertyRNA *prop = ot->prop;
6590
6591 if (prop == nullptr) {
6592 printf("%s: %s has no enum property set\n", __func__, ot->idname);
6593 }
6594 else if (RNA_property_type(prop) != PROP_ENUM) {
6595 printf("%s: %s \"%s\" is not an enum property\n",
6596 __func__,
6597 ot->idname,
6599 }
6600 else {
6601 /* Will create it if needed! */
6602 PointerRNA *ptr = UI_but_operator_ptr_ensure(static_cast<uiBut *>(but));
6603
6604 bool do_free;
6605 const EnumPropertyItem *all_items;
6606 RNA_property_enum_items_gettexted((bContext *)C, ptr, prop, &all_items, nullptr, &do_free);
6607
6609
6610 for (const EnumPropertyItem *item = all_items; item->identifier; item++) {
6611 search.add(item->name, item);
6612 }
6613
6614 const blender::Vector<const EnumPropertyItem *> filtered_items = search.query(str);
6615 for (const EnumPropertyItem *item : filtered_items) {
6616 /* NOTE: need to give the index rather than the
6617 * identifier because the enum can be freed */
6618 if (!UI_search_item_add(items, item->name, POINTER_FROM_INT(item->value), item->icon, 0, 0))
6619 {
6620 break;
6621 }
6622 }
6623
6624 if (do_free) {
6625 MEM_freeN(all_items);
6626 }
6627 }
6628}
6629
6630static void operator_enum_search_exec_fn(bContext * /*C*/, void *but, void *arg2)
6631{
6632 wmOperatorType *ot = ((uiBut *)but)->optype;
6633 /* Will create it if needed! */
6634 PointerRNA *opptr = UI_but_operator_ptr_ensure(static_cast<uiBut *>(but));
6635
6636 if (ot) {
6637 if (ot->prop) {
6638 RNA_property_enum_set(opptr, ot->prop, POINTER_AS_INT(arg2));
6639 /* We do not call op from here, will be called by button code.
6640 * ui_apply_but_funcs_after() (in `interface_handlers.cc`)
6641 * called this func before checking operators,
6642 * because one of its parameters is the button itself! */
6643 }
6644 else {
6645 printf("%s: op->prop for '%s' is nullptr\n", __func__, ot->idname);
6646 }
6647 }
6648}
6649
6652 IDProperty *properties,
6653 void *arg,
6654 int retval,
6655 int icon,
6656 int maxncpy,
6657 int x,
6658 int y,
6659 short width,
6660 short height,
6661 const std::optional<StringRef> tip)
6662{
6663 uiBut *but = uiDefSearchBut(block, arg, retval, icon, maxncpy, x, y, width, height, tip);
6667 but,
6668 false,
6669 nullptr,
6671 nullptr);
6672
6673 but->optype = ot;
6675
6676 if (properties) {
6678 /* Copy id-properties. */
6679 ptr->data = IDP_CopyProperty(properties);
6680 }
6681
6682 return but;
6683}
6684
6685void UI_but_hint_drawstr_set(uiBut *but, const char *string)
6686{
6687 ui_but_add_shortcut(but, string, false);
6688}
6689
6690void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number)
6691{
6693}
6694
6695void UI_but_icon_indicator_set(uiBut *but, const char *string)
6696{
6697 STRNCPY(but->icon_overlay_text.text, string);
6698}
6699
6704
6705void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
6706{
6707 but->flag |= UI_BUT_NODE_LINK;
6708 but->custom_data = socket;
6709 rgba_float_to_uchar(but->col, draw_color);
6710}
6711
6712void UI_but_number_step_size_set(uiBut *but, float step_size)
6713{
6714 uiButNumber *but_number = (uiButNumber *)but;
6715 BLI_assert(but->type == UI_BTYPE_NUM);
6716
6717 but_number->step_size = step_size;
6718 BLI_assert(step_size > 0);
6719}
6720
6721void UI_but_number_precision_set(uiBut *but, float precision)
6722{
6723 uiButNumber *but_number = (uiButNumber *)but;
6724 BLI_assert(but->type == UI_BTYPE_NUM);
6725
6726 but_number->precision = precision;
6727 /* -1 is a valid value, UI code figures out an appropriate precision then. */
6728 BLI_assert(precision > -2);
6729}
6730
6732{
6733 uiButNumberSlider *but_number = (uiButNumberSlider *)but;
6735
6736 but_number->step_size = step_size;
6737 BLI_assert(step_size > 0);
6738}
6739
6741{
6742 uiButNumberSlider *but_number = (uiButNumberSlider *)but;
6744
6745 but_number->precision = precision;
6746 /* -1 is a valid value, UI code figures out an appropriate precision then. */
6747 BLI_assert(precision > -2);
6748}
6749
6750void UI_but_label_alpha_factor_set(uiBut *but, const float alpha_factor)
6751{
6752 uiButLabel *but_label = reinterpret_cast<uiButLabel *>(but);
6754 but_label->alpha_factor = alpha_factor;
6755}
6756
6757void UI_but_search_preview_grid_size_set(uiBut *but, int rows, int cols)
6758{
6760 uiButSearch *but_search = reinterpret_cast<uiButSearch *>(but);
6761 but_search->preview_rows = rows;
6762 but_search->preview_cols = cols;
6763}
6764
6766 const std::optional<int> draw_width,
6767 const std::optional<int> draw_height)
6768{
6770 uiButViewItem *but_view_item = reinterpret_cast<uiButViewItem *>(but);
6771 but_view_item->draw_width = draw_width.value_or(0);
6772 but_view_item->draw_height = draw_height.value_or(0);
6773}
6774
6776{
6777 wmEvent event;
6778 wm_event_init_from_window(win, &event);
6779
6780 event.type = EVT_BUT_OPEN;
6781 event.val = KM_PRESS;
6782 event.flag = static_cast<eWM_EventFlag>(0);
6783 event.customdata = but;
6784 event.customdata_free = false;
6785
6786 WM_event_add(win, &event);
6787}
6788
6790{
6791 but->hold_func = func;
6792 but->hold_argN = argN;
6793}
6794
6795std::optional<EnumPropertyItem> UI_but_rna_enum_item_get(bContext &C, uiBut &but)
6796{
6797 PointerRNA *ptr = nullptr;
6798 PropertyRNA *prop = nullptr;
6799 int value = 0;
6800 if (but.rnaprop && RNA_property_type(but.rnaprop) == PROP_ENUM) {
6801 ptr = &but.rnapoin;
6802 prop = but.rnaprop;
6803 value = ELEM(but.type, UI_BTYPE_ROW, UI_BTYPE_TAB) ? int(but.hardmax) :
6804 int(ui_but_value_get(&but));
6805 }
6806 else if (but.optype) {
6807 wmOperatorType *ot = but.optype;
6808
6809 /* So the context is passed to `itemf` functions. */
6811 WM_operator_properties_sanitize(opptr, false);
6812
6813 /* If the default property of the operator is an enum and is set, fetch the tooltip of the
6814 * selected value so that "Snap" and "Mirror" operator menus in the Animation Editors will
6815 * show tooltips for the different operations instead of the meaningless generic tooltip. */
6816 if (ot->prop && RNA_property_type(ot->prop) == PROP_ENUM) {
6817 if (RNA_struct_contains_property(opptr, ot->prop)) {
6818 ptr = opptr;
6819 prop = ot->prop;
6820 value = RNA_property_enum_get(opptr, ot->prop);
6821 }
6822 }
6823 }
6824
6825 if (!ptr || !prop) {
6826 return std::nullopt;
6827 }
6828
6829 EnumPropertyItem item;
6830 if (!RNA_property_enum_item_from_value_gettexted(&C, ptr, prop, value, &item)) {
6831 return std::nullopt;
6832 }
6833
6834 return item;
6835}
6836
6838{
6839 if (!but.rnaprop) {
6840 return {};
6841 }
6842 return RNA_property_identifier(but.rnaprop);
6843}
6844
6846{
6847 if (but.rnaprop && but.rnapoin.data) {
6849 }
6850 if (but.optype) {
6851 return but.optype->idname;
6852 }
6854 if (MenuType *mt = UI_but_menutype_get(&but)) {
6855 return mt->idname;
6856 }
6857 }
6858 if (but.type == UI_BTYPE_POPOVER) {
6859 if (PanelType *pt = UI_but_paneltype_get(&but)) {
6860 return pt->idname;
6861 }
6862 }
6863 return {};
6864}
6865
6867{
6868 if (!but.str.empty()) {
6869 size_t str_len = but.str.size();
6870 if (but.flag & UI_BUT_HAS_SEP_CHAR) {
6871 const size_t sep_index = but.str.find_first_of(UI_SEP_CHAR);
6872 if (sep_index != std::string::npos) {
6873 str_len = sep_index;
6874 }
6875 }
6876 return but.str.substr(0, str_len);
6877 }
6878
6879 return UI_but_string_get_rna_label(but);
6880}
6881
6883{
6884 if (but.type == UI_BTYPE_VIEW_ITEM) {
6885 const uiButViewItem &view_item_but = static_cast<const uiButViewItem &>(but);
6886 if (view_item_but.view_item == nullptr) {
6887 return "";
6888 }
6889 const blender::ui::AbstractView &tree_view = view_item_but.view_item->get_view();
6890 return IFACE_(tree_view.get_context_menu_title());
6891 }
6892 return UI_but_string_get_label(but);
6893}
6894
6896{
6897 if (!but.tip_quick_func) {
6898 return {};
6899 }
6900 return but.tip_quick_func(&but);
6901}
6902
6904{
6905 if (but.rnaprop) {
6906 return RNA_property_ui_name(but.rnaprop);
6907 }
6908 if (but.optype) {
6910 return WM_operatortype_name(but.optype, opptr);
6911 }
6913 if (MenuType *mt = UI_but_menutype_get(&but)) {
6914 return CTX_TIP_(mt->translation_context, mt->label);
6915 }
6916
6918 return WM_operatortype_name(ot, nullptr);
6919 }
6920
6921 if (PanelType *pt = UI_but_paneltype_get(&but)) {
6922 return CTX_TIP_(pt->translation_context, pt->label);
6923 }
6924 }
6925 return {};
6926}
6927
6929{
6930 if (but.rnaprop) {
6932 }
6933 if (but.optype) {
6935 }
6937 if (MenuType *mt = UI_but_menutype_get(&but)) {
6938 return RNA_struct_translation_context(mt->rna_ext.srna);
6939 }
6940 }
6942}
6943
6945{
6946 if (but.tip_func) {
6947 return but.tip_func(&C, but.tip_arg, but.tip);
6948 }
6949 if (!but.tip.is_empty()) {
6950 return but.tip;
6951 }
6952 return UI_but_string_get_rna_tooltip(C, but);
6953}
6954
6956{
6957 if (but.rnaprop) {
6958 const char *t = RNA_property_ui_description(but.rnaprop);
6959 if (t && t[0]) {
6960 return t;
6961 }
6962 }
6963 else if (but.optype) {
6965 const bContextStore *previous_ctx = CTX_store_get(&C);
6966 CTX_store_set(&C, but.context);
6967 std::string tmp = WM_operatortype_description(&C, but.optype, opptr);
6968 CTX_store_set(&C, previous_ctx);
6969 return tmp;
6970 }
6972 if (MenuType *mt = UI_but_menutype_get(&but)) {
6973 /* Not all menus are from Python. */
6974 if (mt->rna_ext.srna) {
6975 const char *t = RNA_struct_ui_description(mt->rna_ext.srna);
6976 if (t && t[0]) {
6977 return t;
6978 }
6979 }
6980 }
6981
6983 return WM_operatortype_description(&C, ot, nullptr);
6984 }
6985 }
6986
6987 return {};
6988}
6989
6991{
6992 return ui_but_event_operator_string(&C, &but).value_or("");
6993}
6994
6996{
6997 return ui_but_event_property_operator_string(&C, &but).value_or("");
6998}
6999
7001{
7004 return WM_operatortype_name(optype, opptr);
7005}
7006
7008{
7011 return WM_operatortype_description(&C, optype, opptr);
7012}
7013
7015 const uiButExtraOpIcon &extra_icon)
7016{
7017 return ui_but_extra_icon_event_operator_string(&C, &extra_icon).value_or("");
7018}
7019
7020/* Program Init/Exit */
7021
7023{
7025}
7026
7028{
7029 /* Initialize UI variables from values set in the preferences. */
7030 uiStyleInit();
7031}
7032
7034{
7035 uiStyleInit();
7036}
7037
7039{
7040 if (BLF_has_variable_weight(0)) {
7041 return;
7042 }
7043
7044 uiStyle *style = static_cast<uiStyle *>(U.uistyles.first);
7045 const int weight = BLF_default_weight(0);
7046 style->paneltitle.character_weight = weight;
7047 style->grouplabel.character_weight = weight;
7048 style->widget.character_weight = weight;
7049 style->tooltip.character_weight = weight;
7050}
7051
7053{
7056}
7057
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:735
std::optional< blender::StringRefNull > CTX_store_string_lookup(const bContextStore *store, blender::StringRef name)
ReportList * CTX_wm_reports(const bContext *C)
ARegion * CTX_wm_region_popup(const bContext *C)
bContextStore * CTX_store_add(blender::Vector< std::unique_ptr< bContextStore > > &contexts, blender::StringRef name, const PointerRNA *ptr)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
std::optional< int64_t > CTX_store_int_lookup(const bContextStore *store, blender::StringRef name)
const PointerRNA * CTX_store_ptr_lookup(const bContextStore *store, blender::StringRef name, const StructRNA *type=nullptr)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
const bContextStore * CTX_store_get(const bContext *C)
void CTX_store_set(bContext *C, const bContextStore *store)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1243
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:725
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:873
IDProperty * IDP_NewStringMaxSize(const char *st, size_t st_maxncpy, blender::StringRef name, eIDPropertyFlag flags={}) ATTR_WARN_UNUSED_RESULT
Definition idprop.cc:355
void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:672
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2381
void BKE_unit_name_to_alt(char *str, int str_maxncpy, const char *orig_str, int system, int type)
Definition unit.cc:2441
size_t BKE_unit_value_as_string(char *str, int str_maxncpy, double value, int prec, int type, const UnitSettings &settings, bool pad)
Definition unit.cc:1876
double BKE_unit_value_scale(const UnitSettings &settings, int unit_type, double value)
Definition unit.cc:1901
double BKE_unit_closest_scalar(double value, int system, int type)
Definition unit.cc:2482
void BLF_size(int fontid, float size)
Definition blf.cc:440
int BLF_default_weight(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:352
void BLF_batch_draw_begin()
Definition blf.cc:531
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:468
int BLF_default()
void BLF_batch_draw_end()
Definition blf.cc:544
blender::ocio::Display ColorManagedDisplay
Definition BLF_api.hh:35
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:805
bool BLF_has_variable_weight(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:361
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
void BLI_kdtree_nd_ free(KDTree *tree)
void void void BLI_movelisttolist(ListBase *dst, ListBase *src) ATTR_NONNULL(1
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:252
MINLINE int integer_digits_f(float f)
MINLINE int round_fl_to_int(float a)
MINLINE short round_db_to_short_clamp(double a)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE int round_db_to_int_clamp(double a)
MINLINE int is_power_of_2_i(int n)
MINLINE unsigned char round_db_to_uchar_clamp(double a)
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
#define M_LN10
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v4(float r[4])
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v3(float n[3])
#define BLI_SCOPED_DEFER(function_to_defer)
void BLI_rctf_translate(struct rctf *rect, float x, float y)
Definition rct.cc:573
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b)
void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src)
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src)
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.cc:566
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2])
void BLI_rctf_init_minmax(struct rctf *rect)
Definition rct.cc:480
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
int bool bool bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t str_len) ATTR_NONNULL(1
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define STRPREFIX(a, b)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define LIKELY(x)
#define BLT_I18NCONTEXT_ID_WINDOWMANAGER
#define RPT_(msgid)
#define BLT_I18NCONTEXT_ID_ID
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define CTX_TIP_(context, msgid)
bool BPY_run_string_as_number(bContext *C, const char *imports[], const char *expr, BPy_RunErrInfo *err_info, double *r_value) ATTR_NONNULL(1
@ ID_SCR
@ ID_OB
Object is a sort of wrapper for general info.
#define OB_DATA_SUPPORT_ID(_id_type)
@ USER_UNIT_NONE
@ USER_UNIT_ROT_RADIANS
#define FRA2TIME(a)
@ RGN_TYPE_TEMPORARY
@ RGN_TYPE_HUD
@ RGN_FLAG_SEARCH_FILTER_ACTIVE
#define UI_SCALE_FAC
@ USER_FACTOR_AS_FACTOR
@ USER_FACTOR_AS_PERCENTAGE
int BIFIconID
Definition ED_asset.hh:29
bool user_string_to_number(bContext *C, const char *str, const UnitSettings &unit, int type, double *r_value, bool use_single_line_error, char **r_error)
Definition numinput.cc:265
void ED_region_do_msg_notify_tag_redraw(bContext *C, wmMsgSubscribeKey *msg_key, wmMsgSubscribeValue *msg_val)
Definition area.cc:384
static void split(const char *text, const char *seps, char ***str, int *count)
void GPU_matrix_identity_set()
void GPU_matrix_push()
void GPU_matrix_push_projection()
void GPU_matrix_pop_projection()
#define GPU_matrix_projection_get(x)
void GPU_matrix_pop()
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
const ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
const char * IMB_colormanagement_display_get_default_name()
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], const ColorManagedDisplay *display)
void IMB_freeImBuf(ImBuf *ibuf)
Read Guarded memory(de)allocation.
@ RNA_OVERRIDE_STATUS_OVERRIDDEN
short RNA_type_to_ID_code(const StructRNA *type)
PropertyScaleType
Definition RNA_types.hh:191
@ PROP_SCALE_LINEAR
Definition RNA_types.hh:193
#define RNA_SUBTYPE_UNIT_VALUE(subtype)
Definition RNA_types.hh:208
PropertyType
Definition RNA_types.hh:149
@ PROP_FLOAT
Definition RNA_types.hh:152
@ PROP_BOOLEAN
Definition RNA_types.hh:150
@ PROP_ENUM
Definition RNA_types.hh:154
@ PROP_INT
Definition RNA_types.hh:151
@ PROP_STRING
Definition RNA_types.hh:153
@ PROP_POINTER
Definition RNA_types.hh:155
@ PROP_UNIT_ROTATION
Definition RNA_types.hh:166
@ PROP_UNIT_NONE
Definition RNA_types.hh:161
@ PROP_UNIT_TIME
Definition RNA_types.hh:167
@ PROP_UNIT_TIME_ABSOLUTE
Definition RNA_types.hh:168
#define RNA_SUBTYPE_UNIT(subtype)
Definition RNA_types.hh:206
@ PROP_ENUM_FLAG
Definition RNA_types.hh:378
@ PROP_ICONS_CONSECUTIVE
Definition RNA_types.hh:315
@ PROP_ICONS_REVERSE
Definition RNA_types.hh:316
PropertySubType
Definition RNA_types.hh:220
@ PROP_COLOR
Definition RNA_types.hh:248
@ PROP_PIXEL
Definition RNA_types.hh:236
@ PROP_NONE
Definition RNA_types.hh:221
@ PROP_PERCENTAGE
Definition RNA_types.hh:238
@ PROP_FACTOR
Definition RNA_types.hh:239
#define C
Definition RandGen.cpp:29
#define UI_UNIT_Y
#define UI_SEP_CHAR_S
#define AUTOCOMPLETE_FULL_MATCH
#define UI_SEP_CHAR
void(*)(bContext *C, void *arg, char *origstr) uiButHandleRenameFunc
MenuType * UI_but_menutype_get(const uiBut *but)
bool UI_but_is_utf8(const uiBut *but)
const uiStyle * UI_style_get_dpi()
#define UI_BUT_POIN_TYPES
#define AUTOCOMPLETE_PARTIAL_MATCH
bool UI_panel_category_is_visible(const ARegion *region)
bool UI_editsource_enable_check()
#define AUTOCOMPLETE_NO_MATCH
void UI_widgetbase_draw_cache_end()
void UI_butstore_update(uiBlock *block)
#define UI_PRECISION_FLOAT_MAX
#define UI_PRECISION_FLOAT_SCALE
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
void *(*)(const void *argN) uiButArgNCopy
void(*)(void *argN) uiButArgNFree
#define UI_HEADER_OFFSET
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src)
void(*)(bContext *C, void *arg, int event) uiBlockHandleFunc
bool UI_search_item_add(uiSearchItems *items, blender::StringRef name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
void UI_editsource_active_but_test(uiBut *but)
const uiStyle * UI_style_get()
bool UI_panel_should_show_background(const ARegion *region, const PanelType *panel_type)
void UI_fontstyle_set(const uiFontStyle *fs)
eBlockBoundsCalc
@ UI_BLOCK_BOUNDS_PIE_CENTER
@ UI_BLOCK_BOUNDS_POPUP_MOUSE
@ UI_BLOCK_BOUNDS_POPUP_CENTER
@ UI_BLOCK_BOUNDS_POPUP_MENU
@ UI_BLOCK_BOUNDS_TEXT
@ UI_BLOCK_BOUNDS
@ UI_BLOCK_BOUNDS_NONE
int(*)(bContext *C, char *str, void *arg) uiButCompleteFunc
bool UI_view_item_matches(const blender::ui::AbstractViewItem &a, const blender::ui::AbstractViewItem &b)
#define BUTTYPE
bool(*)(bContext *C, void *arg, void *active, const wmEvent *event) uiButSearchContextMenuFn
bool UI_butstore_is_registered(uiBlock *block, uiBut *but)
PanelType * UI_but_paneltype_get(const uiBut *but)
@ UI_BUT_TEXT_RIGHT
@ UI_BUT_ICON_LEFT
@ UI_BUT_HAS_QUICK_TOOLTIP
@ UI_BUT_ALIGN_DOWN
@ UI_BUT_ALIGN
@ UI_BUT_CHECKBOX_INVERT
@ UI_BUT_NO_PREVIEW_PADDING
@ UI_BUT_TEXT_LEFT
@ UI_BUT_ICON_REVERSE
void UI_butstore_clear(uiBlock *block)
void(*)(bContext *C, ARegion *butregion, uiBut *but) uiButHandleHoldFunc
#define UI_FLOAT_VALUE_DISPLAY_MAX
void(*)(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first) uiButSearchUpdateFn
void(*)(bContext *C, void *argN, void *arg2) uiButHandleNFunc
ARegion *(*)(bContext *C, ARegion *region, const rcti *item_rect, void *arg, void *active) uiButSearchTooltipFn
void UI_but_tooltip_refresh(bContext *C, uiBut *but)
@ UI_BUT_DRAG_FULL_BUT
void(*)(bContext *C, void *arg1, void *arg2) uiButHandleFunc
#define UI_SCREEN_MARGIN
ARegion *(*)(bContext *C, ARegion *butregion, uiButSearch *search_but) uiButSearchCreateFn
eButPointerType
@ UI_BUT_POIN_SHORT
@ UI_BUT_POIN_INT
@ UI_BUT_POIN_BIT
@ UI_BUT_POIN_CHAR
@ UI_BUT_POIN_FLOAT
#define UI_UNIT_X
uiBlock *(*)(bContext *C, ARegion *region, void *arg1) uiBlockCreateFunc
@ UI_BTYPE_BUT
@ UI_BTYPE_TOGGLE
@ UI_BTYPE_PROGRESS
@ UI_BTYPE_TAB
@ UI_BTYPE_HOTKEY_EVENT
@ UI_BTYPE_LISTBOX
@ UI_BTYPE_SEPR_SPACER
@ UI_BTYPE_ROUNDBOX
@ UI_BTYPE_COLORBAND
@ UI_BTYPE_BUT_MENU
@ UI_BTYPE_TOGGLE_N
@ UI_BTYPE_BLOCK
@ UI_BTYPE_NUM_SLIDER
@ UI_BTYPE_HSVCIRCLE
@ UI_BTYPE_LISTROW
@ UI_BTYPE_TEXT
@ UI_BTYPE_BUT_TOGGLE
@ UI_BTYPE_VIEW_ITEM
@ UI_BTYPE_HSVCUBE
@ UI_BTYPE_LABEL
@ UI_BTYPE_CURVE
@ UI_BTYPE_ICON_TOGGLE_N
@ UI_BTYPE_DECORATOR
@ UI_BTYPE_ROW
@ UI_BTYPE_SEARCH_MENU
@ UI_BTYPE_UNITVEC
@ UI_BTYPE_SEPR_LINE
@ UI_BTYPE_KEY_EVENT
@ UI_BTYPE_POPOVER
@ UI_BTYPE_CHECKBOX_N
@ UI_BTYPE_SEPR
@ UI_BTYPE_NUM
@ UI_BTYPE_PULLDOWN
@ UI_BTYPE_CURVEPROFILE
@ UI_BTYPE_COLOR
@ UI_BTYPE_CHECKBOX
@ UI_BTYPE_GRIP
@ UI_BTYPE_MENU
@ UI_BTYPE_ICON_TOGGLE
@ UI_BTYPE_IMAGE
@ UI_BTYPE_SCROLL
@ UI_BUT_REDALERT
@ UI_BUT_UNDO
@ UI_BUT_ACTIVATE_ON_INIT
@ UI_BUT_DISABLED
@ UI_BUT_OVERRIDDEN
@ UI_BUT_HAS_SEP_CHAR
@ UI_BUT_NODE_LINK
@ UI_BUT_ICON_PREVIEW
@ UI_BUT_DRAG_MULTI
@ UI_BUT_ICON_SUBMENU
@ UI_BUT_VALUE_CLEAR
int UI_calc_float_precision(int prec, double value)
@ UI_BLOCK_SEARCH_ONLY
@ UI_BLOCK_NUMSELECT
@ UI_BLOCK_LOOP
@ UI_BLOCK_MOVEMOUSE_QUIT
@ UI_BLOCK_NO_ACCELERATOR_KEYS
@ UI_BLOCK_PIE_MENU
@ UI_BLOCK_SHOW_SHORTCUT_ALWAYS
@ UI_BLOCK_POPOVER
@ UI_BLOCK_QUICK_SETUP
bool UI_but_is_tool(const uiBut *but)
void UI_widgetbase_draw_cache_begin()
#define UI_FLOAT_VALUE_DISPLAY_MIN
void(*)(bContext &C, uiTooltipData &data, void *argN) uiButToolTipCustomFunc
void(*)(const wmRegionListenerParams *params, void *arg) uiButSearchListenFn
wmOperatorType * UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
#define UI_but_is_decorator(but)
void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay, const int icon_indicator_number)
ImBuf * UI_icon_alert_imbuf_get(eAlertIcon icon, float size)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
void(*)(void *arg) uiFreeArgFunc
void(*)(bContext *C, uiLayout *layout, void *arg1) uiMenuCreateFunc
std::string(*)(bContext *C, void *argN, blender::StringRef tip) uiButToolTipFunc
#define UI_MAX_DRAW_STR
bool(*)(bContext *C, int direction, void *arg1) uiMenuStepFunc
#define UI_MAX_NAME_STR
bTheme * UI_GetTheme()
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1920
@ KM_CTRL
Definition WM_types.hh:276
@ KM_ALT
Definition WM_types.hh:277
@ KM_HYPER
Definition WM_types.hh:289
@ KM_OSKEY
Definition WM_types.hh:279
@ KM_SHIFT
Definition WM_types.hh:275
eWM_EventFlag
Definition WM_types.hh:668
@ KM_NOTHING
Definition WM_types.hh:307
@ KM_PRESS
Definition WM_types.hh:308
ReportList * reports
Definition WM_types.hh:1025
wmOperatorCallContext
Definition WM_types.hh:236
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:239
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
#define KM_MOD_HELD
Definition WM_types.hh:323
int pad[32 - sizeof(int)]
#define U
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
BPy_StructRNA * depsgraph
void activate(bool forceActivation=false) const
long long int int64_t
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
IndexRange index_range() const
void reserve(const int64_t min_capacity)
T * end()
T * begin()
void clear()
void clear_and_shrink()
constexpr bool contains(int64_t value) const
void reserve(const int64_t n)
Definition BLI_set.hh:637
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr bool is_empty() const
constexpr bool startswith(StringRef prefix) const
constexpr int64_t size() const
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
constexpr const char * data() const
constexpr const char * c_str() const
constexpr StringRef drop_known_prefix(StringRef prefix) const
int64_t size() const
void append(const T &value)
void add(const StringRef str, T *user_data, const int weight=0)
Vector< T * > query(const StringRef query) const
std::string get_context_menu_title() const
#define floorf(x)
#define fabsf(x)
#define str(s)
#define log
#define active
#define pow
#define floor
#define ceil
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
#define printf(...)
#define ID_CHECK_UNDO(id)
#define MEM_SAFE_FREE(v)
#define GS(a)
void ui_but_v4_get(uiBut *but, float vec[4])
void UI_block_update_from_old(const bContext *C, uiBlock *block)
const ColorManagedDisplay * ui_block_cm_display_get(uiBlock *block)
uiBut * uiDefButBitS(uiBlock *block, int type, int bit, int retval, const StringRef str, int x, int y, short width, short height, short *poin, float min, float max, const std::optional< StringRef > tip)
void UI_but_flag_disable(uiBut *but, int flag)
void UI_but_disable(uiBut *but, const char *disabled_hint)
uiBut * ui_but_drag_multi_edit_get(uiBut *but)
void ui_but_v4_set(uiBut *but, const float vec[4])
static void ui_but_predefined_extra_operator_icons_add(uiBut *but)
void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, const std::optional< StringRef > tip)
bool ui_but_is_unit(const uiBut *but)
static PredefinedExtraOpIconType ui_but_icon_extra_get(uiBut *but)
void ui_but_range_set_hard(uiBut *but)
void ui_but_extra_operator_icons_free(uiBut *but)
static float ui_but_get_float_precision(uiBut *but)
Definition interface.cc:682
PointerRNA * UI_but_extra_operator_icon_add(uiBut *but, const StringRefNull opname, wmOperatorCallContext opcontext, int icon)
uiBut * uiDefIconButO(uiBlock *block, int type, const StringRefNull opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, const std::optional< StringRef > tip)
uiBut * uiDefBlockButN(uiBlock *block, uiBlockCreateFunc func, void *argN, const StringRef str, int x, int y, short width, short height, const std::optional< StringRef > tip, uiButArgNFree func_argN_free_fn, uiButArgNCopy func_argN_copy_fn)
uiBut * ui_but_find_new(uiBlock *block_new, const uiBut *but_old)
Definition interface.cc:881
uiBut * uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, int x, int y, short width, short height, const std::optional< StringRef > tip)
static void ui_but_free_type_specific(uiBut *but)
bool UI_but_active_only_ex(const bContext *C, ARegion *region, uiBlock *block, uiBut *but, const bool remove_on_failure)
bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b)
void UI_init_userdef()
void UI_block_emboss_set(uiBlock *block, blender::ui::EmbossType emboss)
static double soft_range_round_down(double value, double max)
void ui_window_to_block(const ARegion *region, const uiBlock *block, int *x, int *y)
Definition interface.cc:223
const short ui_radial_dir_to_angle[8]
void UI_block_theme_style_set(uiBlock *block, char theme_style)
void UI_init()
void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
static bool ui_number_from_string_units_with_but(bContext *C, const char *str, const uiBut *but, double *r_value)
int UI_preview_tile_size_y_no_label(const int size_px)
void UI_but_func_drawextra_set(uiBlock *block, std::function< void(const bContext *C, rcti *rect)> func)
void UI_but_func_tooltip_custom_set(uiBut *but, uiButToolTipCustomFunc func, void *arg, uiFreeArgFunc free_arg)
std::string UI_but_string_get_property_keymap(bContext &C, uiBut &but)
static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
Definition interface.cc:933
static void ui_block_bounds_calc_popup(wmWindow *window, uiBlock *block, eBlockBoundsCalc bounds_calc, const int xy[2], int r_xy[2])
Definition interface.cc:558
static bool ui_but_is_unit_radians(const uiBut *but)
Definition interface.cc:108
void ui_but_string_get_ex(uiBut *but, char *str, const size_t str_maxncpy, const int float_precision, const bool use_exp_float, bool *r_use_exp_float)
void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number)
void ui_but_range_set_soft(uiBut *but)
void ui_but_update(uiBut *but)
void UI_but_func_rename_full_set(uiBut *but, std::function< void(std::string &new_name)> rename_full_func)
uiBut * uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const StringRef str, int x, int y, short width, short height, const std::optional< StringRef > tip)
void UI_blocklist_free(const bContext *C, ARegion *region)
uiBut * uiDefBut(uiBlock *block, int type, int retval, const StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const std::optional< StringRef > tip)
uiBut * uiDefIconButS(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, short *poin, float min, float max, const std::optional< StringRef > tip)
uiBut * uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short)
static std::optional< std::string > ui_but_event_operator_string_from_panel(const bContext *C, uiBut *but)
void UI_but_color_set(uiBut *but, const uchar color[4])
uiBut * uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, int *poin, float min, float max, const std::optional< StringRef > tip)
std::string UI_but_string_get_rna_label_context(const uiBut &but)
static uiBut * uiDefIconButBit(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, const std::optional< StringRef > tip)
void UI_block_lock_clear(uiBlock *block)
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg)
static bool ui_but_is_row_alignment_group(const uiBut *left, const uiBut *right)
Definition interface.cc:399
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
Definition interface.cc:641
void UI_interface_tag_script_reload()
static uiBut * ui_but_find_old(uiBlock *block_old, const uiBut *but_new, const blender::Set< const uiBut * > &ignore_old_buttons)
Definition interface.cc:849
static std::optional< int64_t > ui_but_find_old_idx(uiBlock *block_old, const uiBut *but_new, const blender::Set< const uiBut * > &ignore_old_buttons={})
Definition interface.cc:866
int UI_but_unit_type_get(const uiBut *but)
uiBut * uiDefButR(uiBlock *block, int type, int retval, const std::optional< StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, const StringRefNull propname, int index, float min, float max, const std::optional< StringRef > tip)
static uiBut * ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *ot, wmOperatorCallContext opcontext, const StringRef str, int x, int y, short width, short height, std::optional< StringRef > tip)
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, const bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
void ui_def_but_icon_clear(uiBut *but)
void UI_but_menu_disable_hover_open(uiBut *but)
void UI_block_bounds_set_normal(uiBlock *block, int addval)
Definition interface.cc:625
static bool ui_number_from_string_percentage(bContext *C, const char *str, double *r_value)
uiBut * uiDefIconTextButR_prop(uiBlock *block, int type, int retval, int icon, const std::optional< blender::StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, const std::optional< StringRef > tip)
int ui_but_is_pushed(uiBut *but)
bool ui_but_is_float(const uiBut *but)
bool ui_but_context_poll_operator_ex(bContext *C, const uiBut *but, const wmOperatorCallParams *optype_params)
uiBut * uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, wmOperatorCallContext opcontext, int icon, const StringRef str, int x, int y, short width, short height, const std::optional< StringRef > tip)
void ui_block_add_dynamic_listener(uiBlock *block, void(*listener_func)(const wmRegionListenerParams *params))
uiBut * uiDefIconPreviewBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, const std::optional< StringRef > tip)
static int ui_but_calc_float_precision(uiBut *but, double value)
Definition interface.cc:728
void UI_but_view_item_draw_size_set(uiBut *but, const std::optional< int > draw_width, const std::optional< int > draw_height)
void UI_blocklist_update_view_for_buttons(const bContext *C, const ListBase *lb)
void UI_but_label_alpha_factor_set(uiBut *but, const float alpha_factor)
PropertyScaleType ui_but_scale_type(const uiBut *but)
void ui_block_to_region_rctf(const ARegion *region, const uiBlock *block, rctf *rct_dst, const rctf *rct_src)
Definition interface.cc:155
uiBut * uiDefButO(uiBlock *block, int type, const StringRefNull opname, wmOperatorCallContext opcontext, std::optional< StringRef > str, int x, int y, short width, short height, const std::optional< StringRef > tip)
void UI_but_func_menu_step_set(uiBut *but, uiMenuStepFunc func)
const char * ui_but_placeholder_get(uiBut *but)
static void ui_but_extra_operator_icon_free(uiButExtraOpIcon *extra_icon)
static int findBitIndex(uint x)
static void ui_update_window_matrix(const wmWindow *window, const ARegion *region, uiBlock *block)
Definition interface.cc:357
void ui_block_bounds_calc(uiBlock *block)
Definition interface.cc:478
void UI_block_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
void UI_block_translate(uiBlock *block, float x, float y)
Definition interface.cc:390
static void ui_but_update_and_icon_set(uiBut *but, int icon)
void UI_block_flag_disable(uiBlock *block, int flag)
uiBut * uiDefButI(uiBlock *block, int type, int retval, const StringRef str, int x, int y, short width, short height, int *poin, float min, float max, const std::optional< StringRef > tip)
std::optional< EnumPropertyItem > UI_but_rna_enum_item_get(bContext &C, uiBut &but)
void ui_but_override_flag(Main *bmain, uiBut *but)
static void ui_block_message_subscribe(ARegion *region, wmMsgBus *mbus, uiBlock *block)
std::string UI_but_context_menu_title_from_button(uiBut &but)
void UI_but_drawflag_enable(uiBut *but, int flag)
void UI_but_context_ptr_set(uiBlock *block, uiBut *but, const StringRef name, const PointerRNA *ptr)
static void ui_but_validate(const uiBut *but)
static void ui_block_bounds_calc_centered(wmWindow *window, uiBlock *block)
Definition interface.cc:514
int UI_but_return_value_get(uiBut *but)
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
static void ui_block_free_active_operator(uiBlock *block)
PointerRNA * UI_but_extra_operator_icon_opptr_get(const uiButExtraOpIcon *extra_icon)
uiBut * uiDefBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const StringRef str, int x, int y, short width, short height, const std::optional< StringRef > tip)
void UI_but_flag2_enable(uiBut *but, int flag)
void UI_but_context_int_set(uiBlock *block, uiBut *but, const StringRef name, const int64_t value)
double ui_but_value_get(uiBut *but)
uiBut * uiDefButBitI(uiBlock *block, int type, int bit, int retval, const StringRef str, int x, int y, short width, short height, int *poin, float min, float max, const std::optional< StringRef > tip)
rcti ui_to_pixelrect(const ARegion *region, const uiBlock *block, const rctf *src_rect)
void UI_reinit_font()
float ui_block_to_window_scale(const ARegion *region, const uiBlock *block)
Definition interface.cc:175
void UI_but_number_step_size_set(uiBut *but, float step_size)
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
uiBut * uiDefIconButR_prop(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, const std::optional< StringRef > tip)
void ui_def_but_icon(uiBut *but, const int icon, const int flag)
std::string UI_but_string_get_operator_keymap(bContext &C, uiBut &but)
std::string UI_but_string_get_rna_tooltip(bContext &C, uiBut &but)
void ui_window_to_region_rcti(const ARegion *region, rcti *rect_dst, const rcti *rct_src)
Definition interface.cc:240
uiBut * uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int retval, int icon, int x, int y, short width, short height, const std::optional< StringRef > tip)
uiBut * uiDefSearchButO_ptr(uiBlock *block, wmOperatorType *ot, IDProperty *properties, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, const std::optional< StringRef > tip)
bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, uiBlock *block)
std::string UI_but_string_get_label(uiBut &but)
std::string UI_but_string_get_rna_label(uiBut &but)
int ui_but_is_pushed_ex(uiBut *but, double *value)
uiBlock * UI_block_begin(const bContext *C, Scene *scene, wmWindow *window, ARegion *region, std::string name, blender::ui::EmbossType emboss)
#define PREVIEW_TILE_PAD
static std::optional< std::string > ui_but_event_operator_string_from_operator(const bContext *C, wmOperatorCallParams *op_call_params)
static void ui_but_extra_icons_update_from_old_but(const uiBut *new_but, const uiBut *old_but)
Definition interface.cc:909
void ui_but_string_get(uiBut *but, char *str, const size_t str_maxncpy)
void UI_but_execute(const bContext *C, ARegion *region, uiBut *but)
const char ui_radial_dir_to_numpad[8]
void ui_region_to_window(const ARegion *region, int *x, int *y)
Definition interface.cc:256
static void ui_menu_block_set_keyaccels(uiBlock *block)
void UI_update_text_styles()
void UI_region_message_subscribe(ARegion *region, wmMsgBus *mbus)
void ui_window_to_region(const ARegion *region, int *x, int *y)
Definition interface.cc:234
void ui_window_to_block_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
Definition interface.cc:186
static bool ui_but_pixelrect_in_view(const ARegion *region, const rcti *rect)
int UI_preview_tile_size_x(const int size_px)
static void operator_enum_search_update_fn(const bContext *C, void *but, const char *str, uiSearchItems *items, const bool)
void UI_but_number_slider_precision_set(uiBut *but, float precision)
int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
static std::optional< std::string > ui_but_event_property_operator_string(const bContext *C, uiBut *but)
bool ui_but_rna_equals(const uiBut *a, const uiBut *b)
Definition interface.cc:754
void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3])
#define UI_BUT_VALUE_UNSET
Definition interface.cc:85
bool ui_but_is_rna_valid(uiBut *but)
void UI_but_dragflag_enable(uiBut *but, int flag)
uiBut * uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const StringRef str, int x, int y, short width, short height, const std::optional< StringRef > tip)
static void ui_block_bounds_calc_text(uiBlock *block, float offset)
Definition interface.cc:405
bool UI_block_is_search_only(const uiBlock *block)
uiBut * uiDefButF(uiBlock *block, int type, int retval, const StringRef str, int x, int y, short width, short height, float *poin, float min, float max, const std::optional< StringRef > tip)
void UI_but_type_set_menu_from_pulldown(uiBut *but)
static uiBut * ui_def_but_rna_propname(uiBlock *block, int type, int retval, std::optional< StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, const StringRefNull propname, int index, float min, float max, const std::optional< StringRef > tip)
bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
static bool ui_but_icon_extra_is_visible_bone_eyedropper(uiBut *but)
bool ui_but_menu_draw_as_popover(const uiBut *but)
void ui_but_value_set(uiBut *but, double value)
#define B_NOP
Definition interface.cc:92
static void ui_but_update_ex(uiBut *but, const bool validate)
bool ui_but_rna_equals_ex(const uiBut *but, const PointerRNA *ptr, const PropertyRNA *prop, int index)
Definition interface.cc:759
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
static uiButExtraOpIcon * ui_but_extra_icon_find_old(const uiButExtraOpIcon *new_extra_icon, const uiBut *old_but)
Definition interface.cc:898
void UI_block_funcN_set(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn, uiButArgNCopy func_argN_copy_fn)
void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2)
#define UI_GET_BUT_VALUE_INIT(_but, _value)
Definition interface.cc:86
void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn)
static float ui_but_get_float_step_size(uiBut *but)
Definition interface.cc:694
static bool ui_but_hide_fraction(uiBut *but, double value)
Definition interface.cc:706
static bool ui_number_from_string_units(bContext *C, const char *str, const int unit_type, const UnitSettings *unit, double *r_value)
void UI_but_number_slider_step_size_set(uiBut *but, float step_size)
static std::unique_ptr< uiBut > ui_but_new(const eButType type)
void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2])
Definition interface.cc:655
void UI_but_func_rename_set(uiBut *but, uiButHandleRenameFunc func, void *arg1)
std::string UI_but_string_get_rna_property_identifier(const uiBut &but)
void UI_but_unit_type_set(uiBut *but, const int unit_type)
uiBut * uiDefIconButBitC(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, char *poin, float min, float max, const std::optional< StringRef > tip)
void UI_but_drawflag_disable(uiBut *but, int flag)
void ui_block_to_region_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
Definition interface.cc:118
void UI_block_draw(const bContext *C, uiBlock *block)
static void ui_def_but_rna__menu_type(bContext *, uiLayout *layout, void *but_p)
void UI_but_dragflag_disable(uiBut *but, int flag)
static uiBut * ui_def_but(uiBlock *block, int type, int retval, const StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const std::optional< StringRef > tip)
std::string UI_but_extra_icon_string_get_tooltip(bContext &C, const uiButExtraOpIcon &extra_icon)
static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
void UI_exit()
void UI_block_bounds_set_text(uiBlock *block, int addval)
Definition interface.cc:635
static bool ui_but_is_rna_undo(const uiBut *but)
void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
static bool ui_number_from_string(bContext *C, const char *str, double *r_value)
void UI_block_align_begin(uiBlock *block)
void ui_but_to_pixelrect(rcti *rect, const ARegion *region, const uiBlock *block, const uiBut *but)
static PointerRNA * ui_but_extra_operator_icon_add_ptr(uiBut *but, wmOperatorType *optype, wmOperatorCallContext opcontext, int icon)
void ui_but_rna_menu_convert_to_panel_type(uiBut *but, const char *panel_type)
uiBut * uiDefButR_prop(uiBlock *block, int type, int retval, const std::optional< StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, const std::optional< StringRef > tip)
PredefinedExtraOpIconType
@ PREDEFINED_EXTRA_OP_ICON_CLEAR
@ PREDEFINED_EXTRA_OP_ICON_EYEDROPPER
@ PREDEFINED_EXTRA_OP_ICON_BONE_EYEDROPPER
@ PREDEFINED_EXTRA_OP_ICON_NONE
char * ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
void UI_blocklist_free_inactive(const bContext *C, ARegion *region)
uiBut * uiDefButBitC(uiBlock *block, int type, int bit, int retval, const StringRef str, int x, int y, short width, short height, char *poin, float min, float max, const std::optional< StringRef > tip)
void ui_window_to_region_rctf(const ARegion *region, rctf *rect_dst, const rctf *rct_src)
Definition interface.cc:248
void ui_window_to_block_rctf(const ARegion *region, const uiBlock *block, rctf *rct_dst, const rctf *rct_src)
Definition interface.cc:213
void ui_block_to_window_rctf(const ARegion *region, const uiBlock *block, rctf *rct_dst, const rctf *rct_src)
Definition interface.cc:165
void ui_but_update_edited(uiBut *but)
static void ui_but_build_drawstr_float(uiBut *but, double value)
static void ui_def_but_rna__menu(bContext *C, uiLayout *layout, void *but_p)
uiBut * uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, const StringRef str, int x, int y, short width, short height, int *poin, float min, float max, const std::optional< StringRef > tip)
void ui_but_v3_set(uiBut *but, const float vec[3])
static bool ui_but_update_from_old_block(uiBlock *block, blender::Set< const uiBut * > &matched_old_buttons, std::unique_ptr< uiBut > *but_uptr, std::optional< int64_t > *but_old_idx)
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn, uiButArgNCopy func_argN_copy_fn)
void UI_but_icon_indicator_set(uiBut *but, const char *string)
void ui_but_v3_get(uiBut *but, float vec[3])
static double ui_get_but_scale_unit(uiBut *but, double value)
void UI_block_end_ex(const bContext *C, Main *bmain, wmWindow *window, Scene *scene, ARegion *region, Depsgraph *depsgraph, uiBlock *block, const int xy[2], int r_xy[2])
void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value)
#define UI_NUMBER_EVAL_ERROR_PREFIX
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
uiBut * ui_but_change_type(uiBut *but, eButType new_type)
static uiBut * ui_def_but_rna(uiBlock *block, int type, int retval, std::optional< StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, std::optional< StringRef > tip)
wmOperatorType * UI_but_extra_operator_icon_optype_get(const uiButExtraOpIcon *extra_icon)
void UI_but_operator_set_never_call(uiBut *but)
static void ui_but_build_drawstr_int(uiBut *but, int value)
blender::ui::EmbossType UI_block_emboss_get(uiBlock *block)
int ui_but_string_get_maxncpy(uiBut *but)
void UI_blocklist_draw(const bContext *C, const ListBase *lb)
int UI_blocklist_min_y_get(ListBase *lb)
uiBut * uiDefIconTextButS(uiBlock *block, int type, int retval, int icon, const StringRef str, int x, int y, short width, short height, short *poin, float min, float max, const std::optional< StringRef > tip)
static void ui_def_but_rna__panel_type(bContext *, uiLayout *layout, void *arg)
uiBut * uiDefButImage(uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4])
void UI_but_number_precision_set(uiBut *but, float precision)
void UI_block_bounds_set_centered(uiBlock *block, int addval)
Definition interface.cc:667
uiBut * uiDefIconButO_ptr(uiBlock *block, int type, wmOperatorType *ot, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, const std::optional< StringRef > tip)
bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBut *but)
bool ui_but_string_eval_number(bContext *C, const uiBut *but, const char *str, double *r_value)
void ui_fontscale(float *points, float aspect)
void UI_but_func_pushed_state_set(uiBut *but, std::function< bool(const uiBut &)> func)
static void ui_get_but_string_unit(uiBut *but, char *str, int str_maxncpy, double value, bool pad, int float_precision)
void ui_block_to_window(const ARegion *region, const uiBlock *block, int *x, int *y)
Definition interface.cc:144
void ui_block_to_window_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
Definition interface.cc:137
static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
uiBut * uiDefIconButI(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, int *poin, float min, float max, const std::optional< StringRef > tip)
std::string UI_but_extra_icon_string_get_label(const uiButExtraOpIcon &extra_icon)
void UI_block_free(const bContext *C, uiBlock *block)
static std::optional< std::string > ui_but_event_operator_string(const bContext *C, uiBut *but)
static uiBut * uiDefButBit(uiBlock *block, int type, int bit, int retval, const StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const std::optional< StringRef > tip)
void UI_but_placeholder_set(uiBut *but, const StringRef placeholder_text)
void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t str_maxncpy)
void UI_block_region_set(uiBlock *block, ARegion *region)
uiBut * uiDefIconTextButO(uiBlock *block, int type, const StringRefNull opname, wmOperatorCallContext opcontext, int icon, const StringRef str, int x, int y, short width, short height, const std::optional< StringRef > tip)
void UI_block_direction_set(uiBlock *block, char direction)
static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
Definition interface.cc:302
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN)
int UI_preview_tile_size_y(const int size_px)
static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
static void ui_block_bounds_calc_centered_pie(uiBlock *block)
Definition interface.cc:545
void UI_but_operator_set(uiBut *but, wmOperatorType *optype, wmOperatorCallContext opcontext, const PointerRNA *opptr)
void UI_block_set_active_operator(uiBlock *block, wmOperator *op, const bool free)
void UI_but_icon_indicator_color_set(uiBut *but, const uchar color[4])
void UI_but_func_complete_set(uiBut *but, uiButCompleteFunc func, void *arg)
uiBut * uiDefIconTextButR(uiBlock *block, int type, int retval, int icon, const std::optional< StringRefNull > str, int x, int y, short width, short height, PointerRNA *ptr, blender::StringRefNull propname, int index, float min, float max, const std::optional< StringRef > tip)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, const std::optional< StringRef > tip)
std::optional< int64_t > UI_but_context_int_get(const uiBut *but, const StringRef name)
void UI_autocomplete_update_name(AutoComplete *autocpl, const StringRef name)
void UI_but_func_search_set_listen(uiBut *but, uiButSearchListenFn listen_fn)
static void operator_enum_search_exec_fn(bContext *, void *but, void *arg2)
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip)
std::string UI_but_string_get_tooltip_label(const uiBut &but)
std::string UI_but_string_get_tooltip(bContext &C, uiBut &but)
static bool ui_number_from_string_factor(bContext *C, const char *str, double *r_value)
void UI_block_flag_enable(uiBlock *block, int flag)
std::string UI_but_string_get_rna_struct_identifier(const uiBut &but)
const bContextStore * UI_but_context_get(const uiBut *but)
void ui_but_rna_menu_convert_to_menu_type(uiBut *but, const char *menu_type)
static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
Definition interface.cc:775
const PointerRNA * UI_but_context_ptr_get(const uiBut *but, const StringRef name, const StructRNA *type)
static void ui_block_bounds_calc_post_centered(uiBlock *block)
Definition interface.cc:536
static void ui_but_update_select_flag(uiBut *but, double *value)
static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
const char ui_radial_dir_order[8]
static bool ui_but_is_unit_radians_ex(const UnitSettings *unit, const int unit_type)
Definition interface.cc:103
static std::optional< std::string > ui_but_event_operator_string_from_menu(const bContext *C, uiBut *but)
std::string UI_but_extra_icon_string_get_operator_keymap(const bContext &C, const uiButExtraOpIcon &extra_icon)
uiBut * uiDefButO_ptr(uiBlock *block, int type, wmOperatorType *ot, wmOperatorCallContext opcontext, const StringRef str, int x, int y, short width, short height, const std::optional< StringRef > tip)
static void ui_but_free(const bContext *C, uiBut *but)
std::optional< blender::StringRefNull > UI_but_context_string_get(const uiBut *but, const StringRef name)
static std::optional< std::string > ui_but_extra_icon_event_operator_string(const bContext *C, const uiButExtraOpIcon *extra_icon)
uiBut * uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, short *poin, float min, float max, const std::optional< StringRef > tip)
static void ui_but_submenu_enable(uiBlock *block, uiBut *but)
void UI_block_end(const bContext *C, uiBlock *block)
uiBut * uiDefButC(uiBlock *block, int type, int retval, const StringRef str, int x, int y, short width, short height, char *poin, float min, float max, const std::optional< StringRef > tip)
void UI_but_search_preview_grid_size_set(uiBut *but, int rows, int cols)
void UI_block_set_search_only(uiBlock *block, bool search_only)
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr)
AutoComplete * UI_autocomplete_begin(const char *startname, size_t maxncpy)
void UI_but_func_quick_tooltip_set(uiBut *but, std::function< std::string(const uiBut *but)> func)
static float ui_get_but_step_unit(uiBut *but, float step_default)
void UI_but_flag_enable(uiBut *but, int flag)
void ui_region_winrct_get_no_margin(const ARegion *region, rcti *r_rect)
Definition interface.cc:376
bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *but)
static bool ui_but_extra_icons_equals_old(const uiButExtraOpIcon *new_extra_icon, const uiButExtraOpIcon *old_extra_icon)
Definition interface.cc:891
bool ui_but_supports_cycling(const uiBut *but)
static double soft_range_round_up(double value, double max)
uiBut * uiDefIconButR(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, PointerRNA *ptr, const StringRefNull propname, int index, float min, float max, const std::optional< StringRef > tip)
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const std::optional< StringRef > tip)
uiBut * uiDefButS(uiBlock *block, int type, int retval, const StringRef str, int x, int y, short width, short height, short *poin, float min, float max, const std::optional< StringRef > tip)
bool UI_but_flag_is_set(uiBut *but, int flag)
bool ui_but_is_bool(const uiBut *but)
static std::string ui_but_pie_direction_string(const uiBut *but)
void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy)
Definition interface.cc:673
void UI_block_align_end(uiBlock *block)
bool ui_but_can_align(const uiBut *but)
void ui_block_align_calc(uiBlock *block, const ARegion *region)
bool ui_but_anim_expression_create(uiBut *but, const char *str)
void ui_but_anim_decorate_update_from_flag(uiButDecorator *but)
void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t str_maxncpy)
bool ui_but_anim_expression_set(uiBut *but, const char *str)
void ui_button_group_replace_but_ptr(uiBlock *block, const uiBut *old_but_ptr, uiBut *new_but)
void ui_but_drag_free(uiBut *but)
bool ui_but_is_editing(const uiBut *but)
void ui_but_execute_end(bContext *C, ARegion *, uiBut *but, void *active_back)
void ui_but_active_free(const bContext *C, uiBut *but)
void ui_but_handle_data_free(uiHandleButtonData **data)
void ui_but_execute_begin(bContext *, ARegion *region, uiBut *but, void **active_back)
void ui_but_clipboard_free()
void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
void ui_but_update_view_for_active(const bContext *C, const uiBlock *block)
void ui_but_semi_modal_state_free(const bContext *C, uiBut *but)
void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
#define UI_POPUP_MENU_TOP
void ui_view_item_swap_button_pointers(blender::ui::AbstractViewItem &a, blender::ui::AbstractViewItem &b)
#define UI_BITBUT_TEST(a, b)
void ui_block_views_end(ARegion *region, const uiBlock *block)
bool ui_but_menu_step_poll(const uiBut *but)
void ui_block_views_draw_overlays(const ARegion *region, const uiBlock *block)
void ui_resources_free()
Definition resources.cc:51
@ UI_RADIAL_W
@ UI_RADIAL_E
@ UI_RADIAL_NONE
@ UI_RADIAL_N
@ UI_RADIAL_SE
@ UI_RADIAL_SW
@ UI_RADIAL_S
@ UI_RADIAL_NE
@ UI_RADIAL_NW
bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
void ui_but_search_refresh(uiButSearch *but)
void ui_draw_layout_panels_backdrop(const ARegion *region, const Panel *panel, const float radius, float subpanel_backcolor[4])
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
void ui_interface_tag_script_reload_queries()
ARegion * ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearch *search_but)
void uiStyleInit()
void ui_draw_menu_back(uiStyle *style, uiBlock *block, const rcti *rect)
void ui_block_free_views(uiBlock *block)
void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
void ui_draw_aligned_panel(const ARegion *region, const uiStyle *style, const uiBlock *block, const rcti *rect, bool show_pin, bool show_background, bool region_search_filter_active)
void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT
void ui_draw_popover_back(ARegion *region, uiStyle *style, uiBlock *block, const rcti *rect)
@ UI_BLOCK_CONTAINS_SUBMENU_BUT
uiBut * ui_region_find_active_but(ARegion *region) ATTR_WARN_UNUSED_RESULT
void ui_layout_remove_but(uiLayout *layout, const uiBut *but)
void ui_layout_add_but(uiLayout *layout, uiBut *but)
@ UI_SELECT_DRAW
@ UI_HIDDEN
@ UI_HOVER
@ UI_SCROLLED
@ UI_HAS_ICON
@ UI_SELECT
@ UI_BUT_ACTIVE_OVERRIDE
void ui_resources_init()
Definition resources.cc:46
void ui_draw_pie_center(uiBlock *block)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
MINLINE void zero_v2_int(int r[2])
static ulong state[N]
static int left
static void error(const char *str)
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRef prop_name, int32_t value, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_INT, set its name and value.
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRef prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
VecBase< int32_t, 2 > int2
const EnumPropertyItem rna_enum_id_type_items[]
Definition rna_ID.cc:29
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_enum_value(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value)
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_int_ui_range(PointerRNA *ptr, PropertyRNA *prop, int *softmin, int *softmax, int *step)
const char * RNA_property_ui_description(const PropertyRNA *prop)
bool RNA_property_array_check(PropertyRNA *prop)
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
PropertyScaleType RNA_property_ui_scale(PropertyRNA *prop)
bool RNA_struct_is_ID(const StructRNA *type)
int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_float_ui_range(PointerRNA *ptr, PropertyRNA *prop, float *softmin, float *softmax, float *step, float *precision)
void RNA_property_float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, float value)
int RNA_property_ui_icon(const PropertyRNA *prop)
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
char * RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len)
void RNA_property_float_range(PointerRNA *ptr, PropertyRNA *prop, float *hardmin, float *hardmax)
PropertyType RNA_property_type(PropertyRNA *prop)
const PointerRNA PointerRNA_NULL
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_get_array_at_most(PointerRNA *ptr, PropertyRNA *prop, float *values, int values_num)
bool RNA_struct_contains_property(PointerRNA *ptr, PropertyRNA *prop_test)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_get_array_range(PointerRNA *ptr, PropertyRNA *prop, float values[2])
const char * RNA_struct_identifier(const StructRNA *type)
void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, int value)
void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_translation_context(const PropertyRNA *prop)
void RNA_property_float_set_array_at_most(PointerRNA *ptr, PropertyRNA *prop, const float *values, int values_num)
void * RNA_property_py_data_get(PropertyRNA *prop)
int RNA_property_flag(PropertyRNA *prop)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
void RNA_property_int_get_array_range(PointerRNA *ptr, PropertyRNA *prop, int values[2])
const char * RNA_struct_ui_description(const StructRNA *type)
bool RNA_property_enum_item_from_value_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, EnumPropertyItem *r_item)
const char * RNA_struct_ui_name(const StructRNA *type)
bool RNA_struct_undo_check(const StructRNA *type)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_ui_name(const PropertyRNA *prop)
bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name)
bool RNA_property_is_idprop(const PropertyRNA *prop)
int RNA_property_string_maxlength(PropertyRNA *prop)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_enum_name(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_name)
bool RNA_property_editable_info(const PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
PropertyRNA * RNA_struct_name_property(const StructRNA *type)
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
void RNA_property_int_range(PointerRNA *ptr, PropertyRNA *prop, int *hardmin, int *hardmax)
bool RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr)
void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
const char * RNA_struct_translation_context(const StructRNA *type)
const char * RNA_property_identifier(const PropertyRNA *prop)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
eRNAOverrideStatus RNA_property_override_library_status(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const int index)
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
ARegionRuntimeHandle * runtime
const char * startname
char * truncate
const char * report_prefix
ReportList * reports
const char * identifier
Definition RNA_types.hh:623
const char * name
Definition RNA_types.hh:627
const char * description
Definition RNA_types.hh:629
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
void * first
char idname[BKE_ST_MAXNAME]
short region_type
char idname[BKE_ST_MAXNAME]
short space_type
uiBlock * block
struct PanelType * type
struct Panel_Runtime * runtime
float pie_center_spawned[2]
ID * owner_id
Definition RNA_types.hh:51
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
struct UnitSettings unit
ColorManagedDisplaySettings display_settings
uiWidgetColors wcol_menu_back
float panel_roundness
ThemeUI tui
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
void(* listener_func)(const wmRegionListenerParams *params)
float winmat[4][4]
blender::Vector< std::unique_ptr< uiBut > > buttons
char display_device[64]
ListBase layouts
PieMenuData pie_data
ListBase dynamic_listeners
uiButHandleNFunc funcN
void remove_but(const uiBut *but)
Definition interface.cc:286
ColorPickerData color_pickers
ListBase saferct
uiLayout * curlayout
uiBlock * oldblock
uiPopupBlockHandle * handle
uiButArgNFree func_argN_free_fn
uiButArgNCopy func_argN_copy_fn
uiBlockHandleFunc handle_func
double auto_open_last
uiBut * first_but() const
Definition interface.cc:292
blender::Vector< std::unique_ptr< bContextStore > > contexts
int bounds_offset[2]
int but_index(const uiBut *but) const
Definition interface.cc:262
blender::ui::EmbossType emboss
const char * lockstr
std::function< void(const bContext *, rcti *)> drawextra
eBlockBoundsCalc bounds_type
bool ui_operator_free
wmOperator * ui_operator
uiButHandleFunc func
void * handle_func_arg
short content_hints
const UnitSettings * unit
ListBase butstore
std::string name
uiBut * next_but(const uiBut *but) const
Definition interface.cc:274
uiBut * prev_but(const uiBut *but) const
Definition interface.cc:280
uiBut * last_but() const
Definition interface.cc:297
wmOperatorCallParams * optype_params
wmEventModifierFlag modifier_key
uiButSearchUpdateFn items_update_fn
PropertyRNA * rnasearchprop
uiButSearchListenFn listen_fn
PointerRNA rnasearchpoin
const char * item_sep_string
uiButSearchCreateFn popup_create_fn
uiFreeArgFunc arg_free_fn
uiButSearchTooltipFn item_tooltip_fn
uiButSearchContextMenuFn item_context_menu_fn
blender::ui::AbstractViewItem * view_item
wmOperatorCallContext opcontext
uiButCompleteFunc autocomplete_func
ListBase extra_op_icons
void * custom_data
uiButIdentityCompareFunc identity_cmp_func
uiButHandleNFunc funcN
void * func_arg2
std::function< void(bContext &)> apply_func
RadialDirection pie_dir
IconTextOverlay icon_overlay_text
blender::ui::EmbossType emboss
float * editvec
void * dragpoin
PropertyRNA * rnaprop
wmOperatorType * optype
const ImBuf * imb
bool menu_no_hover_open
char * editstr
eButType type
std::function< std::string(const uiBut *)> tip_quick_func
double * editval
bool operator_never_call
uiHandleButtonData * active
uiButHandleFunc func
eButPointerType pointype
const char * disabled_info
uchar unit_type
void * tip_arg
uiBlock * block
PointerRNA * opptr
uiMenuCreateFunc menu_create_func
std::function< void(std::string &new_name)> rename_full_func
std::string rename_full_new
const bContextStore * context
uiButToolTipFunc tip_func
std::string drawstr
uiButArgNFree func_argN_free_fn
void * func_arg1
std::function< bool(const uiBut &)> pushed_state_func
std::string str
uiButHandleHoldFunc hold_func
void * hold_argN
char * placeholder
BIFIconID icon
uiButHandleRenameFunc rename_func
uiBlockCreateFunc block_create_func
uiButArgNCopy func_argN_copy_fn
uiFreeArgFunc tip_arg_free
void * autofunc_arg
eWM_DragDataType dragtype
void * rename_arg1
PointerRNA rnapoin
uiMenuStepFunc menu_step_func
uiHandleButtonData * semi_modal_state
uiLayout * layout
blender::StringRef tip
uiButToolTipCustomFunc tip_custom_func
void * func_argN
uchar col[4]
void label(blender::StringRef name, int icon)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
uiLayout & split(float percentage, bool align)
uiPopupBlockCreate popup_create_vars
uiFontStyle tooltip
uiFontStyle paneltitle
uiFontStyle grouplabel
uiFontStyle widget
unsigned char text[4]
int xy[2]
Definition WM_types.hh:758
wmOperatorType * optype
Definition WM_types.hh:1162
wmOperatorCallContext opcontext
Definition WM_types.hh:1164
PointerRNA * opptr
Definition WM_types.hh:1163
const char * idname
Definition WM_types.hh:1032
StructRNA * srna
Definition WM_types.hh:1124
struct PointerRNA * ptr
struct wmEvent * eventstate
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len
#define N_(msgid)
int xy[2]
Definition wm_draw.cc:174
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
wmEvent * WM_event_add(wmWindow *win, const wmEvent *event_to_add)
void WM_report_banner_show(wmWindowManager *wm, wmWindow *win)
void wm_event_init_from_window(wmWindow *win, wmEvent *event)
@ EVT_BUT_OPEN
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
std::optional< std::string > WM_key_event_operator_string(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict)
std::optional< std::string > WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact)
const char * WM_key_event_string(const short type, const bool compact)
MenuType * WM_menutype_find(const StringRef idname, bool quiet)
void WM_msg_subscribe_rna(wmMsgBus *mbus, PointerRNA *ptr, const PropertyRNA *prop, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
std::string WM_operatortype_description(bContext *C, wmOperatorType *ot, PointerRNA *properties)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
std::optional< std::string > WM_context_path_resolve_property_full(const bContext *C, const PointerRNA *ptr, PropertyRNA *prop, int index)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
void wmGetProjectionMatrix(float mat[4][4], const rcti *winrct)
void wmOrtho2_region_pixelspace(const ARegion *region)
blender::int2 WM_window_native_pixel_size(const wmWindow *win)
int WM_window_native_pixel_y(const wmWindow *win)
int WM_window_native_pixel_x(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:139