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