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