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
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
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/* -------------------------------------------------------------------- */
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
1494/* -------------------------------------------------------------------- */
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
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/* -------------------------------------------------------------------- */
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
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;
1919 return ui_but_context_poll_operator_ex(C, but, &params);
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);
1927 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(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
1936 UI_block_update_from_old(C, block);
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
1983 ui_menu_block_set_keymaps(C, block);
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,
2115 region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE);
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
3722void UI_blocklist_free(const bContext *C, ARegion *region)
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);
3779 BLI_ghash_reinsert(region->runtime.block_name_map,
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 */
3805 STRNCPY(block->display_device, scene->display_settings.display_device);
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;
4420 but->drawflag &= ~UI_BUT_ICON_LEFT;
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) {
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
5032static int findBitIndex(uint x)
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);
6281 but->drawflag &= ~UI_BUT_ICON_LEFT;
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) {
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
6550{
6552}
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_TYPE_TEMPORARY
@ RGN_TYPE_HUD
@ RGN_FLAG_SEARCH_FILTER_ACTIVE
@ 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
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)
@ 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
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
@ 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
#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)
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
int(*)(bContext *C, char *str, void *arg) uiButCompleteFunc
@ UI_BUT_DRAG_FULL_BUT
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)
void(*)(bContext *C, ARegion *butregion, uiBut *but) uiButHandleHoldFunc
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)
@ 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
@ 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
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
@ KM_NOTHING
Definition WM_types.hh:283
@ KM_PRESS
Definition WM_types.hh:284
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_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)]
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
void activate(bool forceActivation=false) const
unsigned int U
Definition btGjkEpa3.h:78
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
const Depsgraph * depsgraph
#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)
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
@ UI_SELECT_DRAW
@ UI_HIDDEN
@ UI_HOVER
@ UI_SCROLLED
@ UI_HAS_ICON
@ UI_SELECT
@ UI_BUT_ACTIVE_OVERRIDE
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 void error(const char *str)
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRefNull prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
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
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
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
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
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
PropertyRNA * prop
Definition WM_types.hh:1092
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