Blender V4.3
interface_widgets.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10#include <climits>
11#include <cstdlib>
12#include <cstring>
13
14#include "DNA_brush_types.h"
15#include "DNA_screen_types.h"
16#include "DNA_userdef_types.h"
17
18#include "BLI_listbase.h"
19#include "BLI_math_color.h"
20#include "BLI_rect.h"
21#include "BLI_string.h"
22#include "BLI_string_utf8.h"
23#include "BLI_utildefines.h"
24
25#include "BKE_context.hh"
26
27#include "RNA_access.hh"
28
29#include "BLF_api.hh"
30
31#include "ED_node.hh"
32
33#include "UI_interface.hh"
34#include "UI_interface_icons.hh"
35#include "UI_view2d.hh"
36
37#include "interface_intern.hh"
38
39#include "GPU_batch.hh"
40#include "GPU_batch_presets.hh"
41#include "GPU_immediate.hh"
42#include "GPU_immediate_util.hh"
43#include "GPU_matrix.hh"
44#include "GPU_platform.hh"
45#include "GPU_state.hh"
46
47#ifdef WITH_INPUT_IME
48# include "WM_types.hh"
49#endif
50
51/* -------------------------------------------------------------------- */
55/* icons are 80% of height of button (16 pixels inside 20 height) */
56#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
57
58/* visual types for drawing */
59/* for time being separated from functional types */
111
126
128
131/* -------------------------------------------------------------------- */
135static void color_blend_v3_v3(uchar cp[3], const uchar cpstate[3], const float fac)
136{
137 if (fac != 0.0f) {
138 cp[0] = int((1.0f - fac) * cp[0] + fac * cpstate[0]);
139 cp[1] = int((1.0f - fac) * cp[1] + fac * cpstate[1]);
140 cp[2] = int((1.0f - fac) * cp[2] + fac * cpstate[2]);
141 }
142}
143
144static void color_blend_v4_v4v4(uchar r_col[4],
145 const uchar col1[4],
146 const uchar col2[4],
147 const float fac)
148{
149 const int faci = unit_float_to_uchar_clamp(fac);
150 const int facm = 255 - faci;
151
152 r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
153 r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
154 r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
155 r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
156}
157
158static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int contrast)
159{
160 BLI_assert(contrast > 0);
161 const int item_value = rgb_to_grayscale_byte(cp);
162 const int inner_value = rgb_to_grayscale_byte(cp_other);
163 const int delta = item_value - inner_value;
164 if (delta >= 0) {
165 if (contrast > delta) {
166 add_v3_uchar_clamped(cp, contrast - delta);
167 }
168 }
169 else {
170 if (contrast > -delta) {
171 add_v3_uchar_clamped(cp, -contrast - delta);
172 }
173 }
174}
175
176static void color_mul_hsl_v3(uchar ch[3], float h_factor, float s_factor, float l_factor)
177{
178 float rgb[3], hsl[3];
179 rgb_uchar_to_float(rgb, ch);
180 rgb_to_hsl_v(rgb, hsl);
181 hsl[0] *= h_factor;
182 hsl[1] *= s_factor;
183 hsl[2] *= l_factor;
184 hsl_to_rgb_v(hsl, rgb);
185 rgb_float_to_uchar(ch, rgb);
186}
187
190/* -------------------------------------------------------------------- */
207/* fill this struct with polygon info to draw AA'ed */
208/* it has outline, back, and two optional tria meshes */
209
212 int type;
213 float size, center[2];
214
215 float vec[16][2];
216 const uint (*index)[3];
217};
218
219/* max as used by round_box__edges */
220/* Make sure to change widget_base_vert.glsl accordingly. */
221#define WIDGET_CURVE_RESOLU 9
222#define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4)
223
225 /* TODO: remove these completely. */
230
232
235
236 /* Widget shader parameters, must match the shader layout. */
238};
239
245
246 /* pointer to theme color definition */
249
250 /* converted colors for state */
252
254 ATTR_NONNULL();
256 rcti *,
257 const uiWidgetStateInfo *,
258 int roundboxalign,
259 const float zoom) ATTR_NONNULL();
260 void (*custom)(uiBut *,
262 rcti *,
263 const uiWidgetStateInfo *,
264 int roundboxalign,
265 const float zoom) ATTR_NONNULL();
266 void (*draw_block)(
267 uiWidgetColors *, const rcti *, int block_flag, int roundboxalign, const float zoom);
268 void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
269};
270
273/* -------------------------------------------------------------------- */
277static const float cornervec[WIDGET_CURVE_RESOLU][2] = {
278 {0.0, 0.0},
279 {0.195, 0.02},
280 {0.383, 0.067},
281 {0.55, 0.169},
282 {0.707, 0.293},
283 {0.831, 0.45},
284 {0.924, 0.617},
285 {0.98, 0.805},
286 {1.0, 1.0},
287};
288
290 {0.468813, -0.481430},
291 {-0.155755, -0.352820},
292 {0.219306, -0.238501},
293 {-0.393286, -0.110949},
294 {-0.024699, 0.013908},
295 {0.343805, 0.147431},
296 {-0.272855, 0.269918},
297 {0.095909, 0.388710},
298};
299#define WIDGET_AA_JITTER UI_PIXEL_AA_JITTER
300#define jit ui_pixel_jitter
301
302static const float g_shape_preset_number_arrow_vert[3][2] = {
303 {-0.352077, 0.532607},
304 {-0.352077, -0.549313},
305 {0.330000, -0.008353},
306};
308 {0, 1, 2},
309};
310
311static const float g_shape_preset_scroll_circle_vert[16][2] = {
312 {0.382684, 0.923879},
313 {0.000001, 1.000000},
314 {-0.382683, 0.923880},
315 {-0.707107, 0.707107},
316 {-0.923879, 0.382684},
317 {-1.000000, 0.000000},
318 {-0.923880, -0.382684},
319 {-0.707107, -0.707107},
320 {-0.382683, -0.923880},
321 {0.000000, -1.000000},
322 {0.382684, -0.923880},
323 {0.707107, -0.707107},
324 {0.923880, -0.382684},
325 {1.000000, -0.000000},
326 {0.923880, 0.382683},
327 {0.707107, 0.707107},
328};
330 {0, 1, 2},
331 {2, 0, 3},
332 {3, 0, 15},
333 {3, 15, 4},
334 {4, 15, 14},
335 {4, 14, 5},
336 {5, 14, 13},
337 {5, 13, 6},
338 {6, 13, 12},
339 {6, 12, 7},
340 {7, 12, 11},
341 {7, 11, 8},
342 {8, 11, 10},
343 {8, 10, 9},
344};
345
346static const float g_shape_preset_menu_arrow_vert[6][2] = {
347 {-0.33, 0.16},
348 {0.33, 0.16},
349 {0, 0.82},
350 {0, -0.82},
351 {-0.33, -0.16},
352 {0.33, -0.16},
353};
354static const uint g_shape_preset_menu_arrow_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
355
356static const float g_shape_preset_checkmark_vert[6][2] = {
357 {-0.578579, 0.253369},
358 {-0.392773, 0.412794},
359 {-0.004241, -0.328551},
360 {-0.003001, 0.034320},
361 {1.055313, 0.864744},
362 {0.866408, 1.026895},
363};
364
366 {3, 2, 4},
367 {3, 4, 5},
368 {1, 0, 3},
369 {0, 2, 3},
370};
371
372#define OY (-0.2 / 2)
373#define SC (0.35 * 2)
374static const float g_shape_preset_hold_action_vert[6][2] = {
375 {-0.5 + SC, 1.0 + OY},
376 {0.5, 1.0 + OY},
377 {0.5, 0.0 + OY + SC},
378};
379static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
380#undef OY
381#undef SC
382
385/* -------------------------------------------------------------------- */
394static struct {
395 blender::gpu::Batch *roundbox_widget;
396 blender::gpu::Batch *roundbox_shadow;
397
398 /* TODO: remove. */
401} g_ui_batch_cache = {nullptr};
402
404{
405 if (g_ui_batch_cache.format.attr_len == 0) {
408 format, "vflag", GPU_COMP_U32, 1, GPU_FETCH_INT);
409 }
410 return g_ui_batch_cache.format;
411}
412
413#define INNER 0
414#define OUTLINE 1
415#define EMBOSS 2
416#define NO_AA 0
417
419{
420 uint32_t *data = static_cast<uint32_t *>(GPU_vertbuf_raw_step(vflag_step));
421 *data = d;
422}
423
425 int corner_id,
426 int corner_v,
427 int jit_v,
428 bool inner,
429 bool emboss,
430 int color)
431{
432 uint32_t *data = static_cast<uint32_t *>(GPU_vertbuf_raw_step(vflag_step));
433 *data = corner_id;
434 *data |= corner_v << 2;
435 *data |= jit_v << 6;
436 *data |= color << 12;
437 *data |= (inner) ? (1 << 10) : 0; /* is inner vert */
438 *data |= (emboss) ? (1 << 11) : 0; /* is emboss vert */
439 return *data;
440}
441
442blender::gpu::Batch *ui_batch_roundbox_widget_get()
443{
444 if (g_ui_batch_cache.roundbox_widget == nullptr) {
446
447 GPU_vertbuf_data_alloc(*vbo, 12);
448
450 GPU_indexbuf_init(&ibuf, GPU_PRIM_TRIS, 6, 12);
451 /* Widget */
452 GPU_indexbuf_add_tri_verts(&ibuf, 0, 1, 2);
453 GPU_indexbuf_add_tri_verts(&ibuf, 2, 1, 3);
454 /* Trias */
455 GPU_indexbuf_add_tri_verts(&ibuf, 4, 5, 6);
456 GPU_indexbuf_add_tri_verts(&ibuf, 6, 5, 7);
457
458 GPU_indexbuf_add_tri_verts(&ibuf, 8, 9, 10);
459 GPU_indexbuf_add_tri_verts(&ibuf, 10, 9, 11);
460
461 g_ui_batch_cache.roundbox_widget = GPU_batch_create_ex(
464 }
465 return g_ui_batch_cache.roundbox_widget;
466}
467
468blender::gpu::Batch *ui_batch_roundbox_shadow_get()
469{
470 if (g_ui_batch_cache.roundbox_shadow == nullptr) {
471 uint32_t last_data;
472 GPUVertBufRaw vflag_step;
474 const int vcount = (WIDGET_SIZE_MAX + 1) * 2 + 2 + WIDGET_SIZE_MAX;
475 GPU_vertbuf_data_alloc(*vbo, vcount);
476 GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
477
478 for (int c = 0; c < 4; c++) {
479 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
480 set_roundbox_vertex(&vflag_step, c, a, NO_AA, true, false, INNER);
481 set_roundbox_vertex(&vflag_step, c, a, NO_AA, false, false, INNER);
482 }
483 }
484 /* close loop */
485 last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
486 last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, false, false, INNER);
487 /* restart */
488 set_roundbox_vertex_data(&vflag_step, last_data);
489 set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
490 /* filled */
491 for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
492 for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU - 1; a2 >= 0; a1++, a2--) {
493 set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER);
494 set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER);
495 }
496 }
497 g_ui_batch_cache.roundbox_shadow = GPU_batch_create_ex(
500 }
501 return g_ui_batch_cache.roundbox_shadow;
502}
503
504#undef INNER
505#undef OUTLINE
506#undef EMBOSS
507#undef NO_AA
508
511/* -------------------------------------------------------------------- */
515static void draw_anti_tria(
516 float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
517{
518 const float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
519
520 float draw_color[4];
521 copy_v4_v4(draw_color, color);
522 /* NOTE: This won't give back the original color. */
523 draw_color[3] *= 1.0f / WIDGET_AA_JITTER;
524
526
530
531 immUniformColor4fv(draw_color);
533
534 /* for each AA step */
535 for (int j = 0; j < WIDGET_AA_JITTER; j++) {
536 immVertex2f(pos, tri_arr[0][0] + jit[j][0], tri_arr[0][1] + jit[j][1]);
537 immVertex2f(pos, tri_arr[1][0] + jit[j][0], tri_arr[1][1] + jit[j][1]);
538 immVertex2f(pos, tri_arr[2][0] + jit[j][0], tri_arr[2][1] + jit[j][1]);
539 }
540
541 immEnd();
542
544
546}
547
548void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
549{
550 const float f3 = 0.05 * U.widget_unit;
551 const float f5 = 0.15 * U.widget_unit;
552 const float f7 = 0.25 * U.widget_unit;
553
554 if (dir == 'h') {
555 draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
556 }
557 else if (dir == 't') {
558 draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
559 }
560 else { /* 'v' = vertical, down. */
561 draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
562 }
563}
564
565/* triangle 'icon' inside rect */
566static void draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
567{
568 if (dir == 'h') {
569 const float half = 0.5f * BLI_rctf_size_y(rect);
571 rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color);
572 }
573 else {
574 const float half = 0.5f * BLI_rctf_size_x(rect);
576 rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
577 }
578}
579
580static void widget_init(uiWidgetBase *wtb)
581{
582 wtb->totvert = wtb->halfwayvert = 0;
583 wtb->tria1.tot = 0;
584 wtb->tria2.tot = 0;
586 wtb->tria1.size = 0;
587 wtb->tria2.size = 0;
588
589 wtb->draw_inner = true;
590 wtb->draw_outline = true;
591 wtb->draw_emboss = true;
592
593 wtb->uniform_params.shade_dir = 1.0f;
594 wtb->uniform_params.alpha_discard = 1.0f;
595}
596
599/* -------------------------------------------------------------------- */
603/* this call has 1 extra arg to allow mask outline */
605 uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad, float radi)
606{
607 float vec[WIDGET_CURVE_RESOLU][2], veci[WIDGET_CURVE_RESOLU][2];
608 const float minx = rect->xmin, miny = rect->ymin, maxx = rect->xmax, maxy = rect->ymax;
609 const float minxi = minx + U.pixelsize; /* Bounding-box inner. */
610 const float maxxi = maxx - U.pixelsize;
611 const float minyi = miny + U.pixelsize;
612 const float maxyi = maxy - U.pixelsize;
613 /* for uv, can divide by zero */
614 const float facxi = (maxxi != minxi) ? 1.0f / (maxxi - minxi) : 0.0f;
615 const float facyi = (maxyi != minyi) ? 1.0f / (maxyi - minyi) : 0.0f;
616 int tot = 0;
617 const int hnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT)) ==
619 (roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) ==
621 1 :
622 2;
623 const int vnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)) ==
625 (roundboxalign & (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) ==
627 1 :
628 2;
629
630 const int minsize = min_ii(BLI_rcti_size_x(rect) * hnum, BLI_rcti_size_y(rect) * vnum);
631
632 if (2.0f * rad > minsize) {
633 rad = 0.5f * minsize;
634 }
635
636 if (2.0f * (radi + 1.0f) > minsize) {
637 radi = 0.5f * minsize - U.pixelsize;
638 }
639
640 wt->uniform_params.rad = rad;
641 wt->uniform_params.radi = radi;
642 wt->uniform_params.facxi = facxi;
643 wt->uniform_params.facyi = facyi;
644 wt->uniform_params.round_corners[0] = (roundboxalign & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f;
645 wt->uniform_params.round_corners[1] = (roundboxalign & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f;
646 wt->uniform_params.round_corners[2] = (roundboxalign & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f;
647 wt->uniform_params.round_corners[3] = (roundboxalign & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f;
649 BLI_rctf_init(&wt->uniform_params.recti, minxi, maxxi, minyi, maxyi);
650
651 /* Multiply by radius. */
652 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
653 veci[a][0] = radi * cornervec[a][0];
654 veci[a][1] = radi * cornervec[a][1];
655 vec[a][0] = rad * cornervec[a][0];
656 vec[a][1] = rad * cornervec[a][1];
657 }
658
659 /* corner left-bottom */
660 if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
661 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
662 wt->inner_v[tot][0] = minxi + veci[a][1];
663 wt->inner_v[tot][1] = minyi + radi - veci[a][0];
664
665 wt->outer_v[tot][0] = minx + vec[a][1];
666 wt->outer_v[tot][1] = miny + rad - vec[a][0];
667
668 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
669 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
670 }
671 }
672 else {
673 wt->inner_v[tot][0] = minxi;
674 wt->inner_v[tot][1] = minyi;
675
676 wt->outer_v[tot][0] = minx;
677 wt->outer_v[tot][1] = miny;
678
679 wt->inner_uv[tot][0] = 0.0f;
680 wt->inner_uv[tot][1] = 0.0f;
681
682 tot++;
683 }
684
685 /* corner right-bottom */
686 if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
687 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
688 wt->inner_v[tot][0] = maxxi - radi + veci[a][0];
689 wt->inner_v[tot][1] = minyi + veci[a][1];
690
691 wt->outer_v[tot][0] = maxx - rad + vec[a][0];
692 wt->outer_v[tot][1] = miny + vec[a][1];
693
694 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
695 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
696 }
697 }
698 else {
699 wt->inner_v[tot][0] = maxxi;
700 wt->inner_v[tot][1] = minyi;
701
702 wt->outer_v[tot][0] = maxx;
703 wt->outer_v[tot][1] = miny;
704
705 wt->inner_uv[tot][0] = 1.0f;
706 wt->inner_uv[tot][1] = 0.0f;
707
708 tot++;
709 }
710
711 wt->halfwayvert = tot;
712
713 /* corner right-top */
714 if (roundboxalign & UI_CNR_TOP_RIGHT) {
715 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
716 wt->inner_v[tot][0] = maxxi - veci[a][1];
717 wt->inner_v[tot][1] = maxyi - radi + veci[a][0];
718
719 wt->outer_v[tot][0] = maxx - vec[a][1];
720 wt->outer_v[tot][1] = maxy - rad + vec[a][0];
721
722 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
723 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
724 }
725 }
726 else {
727 wt->inner_v[tot][0] = maxxi;
728 wt->inner_v[tot][1] = maxyi;
729
730 wt->outer_v[tot][0] = maxx;
731 wt->outer_v[tot][1] = maxy;
732
733 wt->inner_uv[tot][0] = 1.0f;
734 wt->inner_uv[tot][1] = 1.0f;
735
736 tot++;
737 }
738
739 /* corner left-top */
740 if (roundboxalign & UI_CNR_TOP_LEFT) {
741 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
742 wt->inner_v[tot][0] = minxi + radi - veci[a][0];
743 wt->inner_v[tot][1] = maxyi - veci[a][1];
744
745 wt->outer_v[tot][0] = minx + rad - vec[a][0];
746 wt->outer_v[tot][1] = maxy - vec[a][1];
747
748 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
749 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
750 }
751 }
752 else {
753 wt->inner_v[tot][0] = minxi;
754 wt->inner_v[tot][1] = maxyi;
755
756 wt->outer_v[tot][0] = minx;
757 wt->outer_v[tot][1] = maxy;
758
759 wt->inner_uv[tot][0] = 0.0f;
760 wt->inner_uv[tot][1] = 1.0f;
761
762 tot++;
763 }
764
766
767 wt->totvert = tot;
768}
769
770static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad)
771{
772 round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
773}
774
777/* -------------------------------------------------------------------- */
781/* based on button rect, return scaled array of triangles */
783 const rcti *rect,
784 float triasize,
785 char where,
786 /* input data */
787 const float verts[][2],
788 const int verts_tot,
789 const uint tris[][3],
790 const int tris_tot)
791{
792 float sizex, sizey;
793 int i1 = 0, i2 = 1;
794
795 const float minsize = ELEM(where, 'r', 'l') ? BLI_rcti_size_y(rect) : BLI_rcti_size_x(rect);
796
797 /* center position and size */
798 float centx = float(rect->xmin) + 0.4f * minsize;
799 float centy = float(rect->ymin) + 0.5f * minsize;
800 tria->size = sizex = sizey = -0.5f * triasize * minsize;
801
802 if (where == 'r') {
803 centx = float(rect->xmax) - 0.4f * minsize;
804 sizex = -sizex;
805 }
806 else if (where == 't') {
807 centx = float(rect->xmin) + 0.5f * minsize;
808 centy = float(rect->ymax) - 0.5f * minsize;
809 sizey = -sizey;
810 i2 = 0;
811 i1 = 1;
812 }
813 else if (where == 'b') {
814 centx = float(rect->xmin) + 0.5f * minsize;
815 sizex = -sizex;
816 i2 = 0;
817 i1 = 1;
818 }
819
820 for (int a = 0; a < verts_tot; a++) {
821 tria->vec[a][0] = sizex * verts[a][i1] + centx;
822 tria->vec[a][1] = sizey * verts[a][i2] + centy;
823 }
824
825 tria->center[0] = centx;
826 tria->center[1] = centy;
827
828 tria->tot = tris_tot;
829 tria->index = tris;
830}
831
833 const rcti *rect,
834 float triasize,
835 char where)
836{
839 rect,
840 triasize,
841 where,
846}
847
849 const rcti *rect,
850 float triasize,
851 char where)
852{
854 /* With the current changes to use batches for widget drawing, the code
855 * below is doing almost nothing effectively. 'where' doesn't work either,
856 * shader is currently hardcoded to work for the button triangle pointing
857 * at the lower right. The same limitation applies to other trias as well.
858 * XXX Should be addressed. */
860 rect,
861 triasize,
862 where,
867}
868
870 const rcti *rect,
871 float triasize,
872 char where)
873{
876 rect,
877 triasize,
878 where,
883}
884
886 uint col,
887 GPUPrimType mode,
888 const float quads_pos[WIDGET_SIZE_MAX][2],
889 const uchar quads_col[WIDGET_SIZE_MAX][4],
890 uint totvert)
891{
892 immBegin(mode, totvert);
893 for (int i = 0; i < totvert; i++) {
894 if (quads_col) {
895 immAttr4ubv(col, quads_col[i]);
896 }
897 immVertex2fv(pos, quads_pos[i]);
898 }
899 immEnd();
900}
901
903{
904 const float width = BLI_rcti_size_x(rect);
905 const float height = BLI_rcti_size_y(rect);
906 float centx, centy, size;
907
908 tria->type = ROUNDBOX_TRIA_MENU;
909
910 /* Center position and size. */
911 tria->center[0] = centx = rect->xmin + 0.52f * BLI_rcti_size_y(rect);
912 tria->center[1] = centy = rect->ymin + 0.52f * BLI_rcti_size_y(rect);
913 tria->size = size = 0.4f * height;
914
915 if (width > height * 1.1f) {
916 /* For wider buttons align tighter to the right. */
917 tria->center[0] = centx = rect->xmax - 0.32f * height;
918 }
919
920 for (int a = 0; a < 6; a++) {
921 tria->vec[a][0] = size * g_shape_preset_menu_arrow_vert[a][0] + centx;
922 tria->vec[a][1] = size * g_shape_preset_menu_arrow_vert[a][1] + centy;
923 }
924
925 tria->tot = 2;
927}
928
930{
931 float centx, centy, size;
932
934
935 /* Center position and size. */
936 tria->center[0] = centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
937 tria->center[1] = centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
938 tria->size = size = 0.5f * BLI_rcti_size_y(rect);
939
940 for (int a = 0; a < 6; a++) {
941 tria->vec[a][0] = size * g_shape_preset_checkmark_vert[a][0] + centx;
942 tria->vec[a][1] = size * g_shape_preset_checkmark_vert[a][1] + centy;
943 }
944
945 tria->tot = 4;
947}
948
950{
951 tria->type = ROUNDBOX_TRIA_DASH;
952
953 /* Center position and size. */
954 tria->center[0] = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
955 tria->center[1] = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
956 tria->size = 0.5f * BLI_rcti_size_y(rect);
957}
958
961/* -------------------------------------------------------------------- */
965/* prepares shade colors */
966static void shadecolors4(
967 const uchar *color, short shadetop, short shadedown, uchar r_coltop[4], uchar r_coldown[4])
968{
969 r_coltop[0] = std::clamp(color[0] + shadetop, 0, 255);
970 r_coltop[1] = std::clamp(color[1] + shadetop, 0, 255);
971 r_coltop[2] = std::clamp(color[2] + shadetop, 0, 255);
972 r_coltop[3] = color[3];
973
974 r_coldown[0] = std::clamp(color[0] + shadedown, 0, 255);
975 r_coldown[1] = std::clamp(color[1] + shadedown, 0, 255);
976 r_coldown[2] = std::clamp(color[2] + shadedown, 0, 255);
977 r_coldown[3] = color[3];
978}
979
981 const int totvert,
982 float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
983{
984 int a;
985 for (a = 0; a < totvert; a++) {
986 copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[a]);
987 copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[a]);
988 }
989 copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[0]);
990 copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]);
991}
992
994{
995 float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
996 widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
997
999 pos, 0, GPU_PRIM_TRI_STRIP, triangle_strip, nullptr, wtb->totvert * 2 + 2);
1000}
1001
1003 const bool alpha_check,
1004 const float discard_factor)
1005{
1006 if (alpha_check) {
1007 wtb->uniform_params.alpha_discard = -discard_factor;
1008 }
1009 else {
1010 wtb->uniform_params.alpha_discard = discard_factor;
1011 }
1012}
1013
1014static void widgetbase_set_uniform_alpha_check(uiWidgetBase *wtb, const bool alpha_check)
1015{
1016 const float discard_factor = fabs(wtb->uniform_params.alpha_discard);
1017 widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
1018}
1019
1020static void widgetbase_set_uniform_discard_factor(uiWidgetBase *wtb, const float discard_factor)
1021{
1022 const bool alpha_check = wtb->uniform_params.alpha_discard < 0.0f;
1023 widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
1024}
1025
1027 const uchar *col1,
1028 const uchar *col2,
1029 const uchar *outline,
1030 const uchar *emboss,
1031 const uchar *tria,
1032 const bool alpha_check)
1033{
1034 widgetbase_set_uniform_alpha_check(wtb, alpha_check);
1035 rgba_float_args_set_ch(wtb->uniform_params.color_inner1, col1[0], col1[1], col1[2], col1[3]);
1036 rgba_float_args_set_ch(wtb->uniform_params.color_inner2, col2[0], col2[1], col2[2], col2[3]);
1038 wtb->uniform_params.color_outline, outline[0], outline[1], outline[2], outline[3]);
1040 wtb->uniform_params.color_emboss, emboss[0], emboss[1], emboss[2], emboss[3]);
1041 rgba_float_args_set_ch(wtb->uniform_params.color_tria, tria[0], tria[1], tria[2], tria[3]);
1042}
1043
1046/* -------------------------------------------------------------------- */
1050/* keep in sync with shader */
1051#define MAX_WIDGET_BASE_BATCH 6
1052#define MAX_WIDGET_PARAMETERS 12
1053
1054static struct {
1059
1061{
1062 const float checker_params[3] = {
1063 UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
1064
1065 if (g_widget_base_batch.count == 0) {
1066 return;
1067 }
1068
1069 blender::gpu::Batch *batch = ui_batch_roundbox_widget_get();
1070 if (g_widget_base_batch.count == 1) {
1071 /* draw single */
1074 batch, "parameters", MAX_WIDGET_PARAMETERS, (const float(*)[4])g_widget_base_batch.params);
1075 GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
1077 }
1078 else {
1081 "parameters",
1083 (float(*)[4])g_widget_base_batch.params);
1084 GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
1086 }
1087 g_widget_base_batch.count = 0;
1088}
1089
1091{
1092 BLI_assert(g_widget_base_batch.enabled == false);
1093 g_widget_base_batch.enabled = true;
1094}
1095
1097{
1098 BLI_assert(g_widget_base_batch.enabled == true);
1099 g_widget_base_batch.enabled = false;
1100
1102
1104
1106}
1107
1109{
1110 wtb->uniform_params.tria_type = wtb->tria1.type;
1111 wtb->uniform_params.tria1_size = wtb->tria1.size;
1112 wtb->uniform_params.tria2_size = wtb->tria2.size;
1115
1116 if (g_widget_base_batch.enabled) {
1118 g_widget_base_batch.count++;
1119
1122 }
1123 }
1124 else {
1125 const float checker_params[3] = {
1126 UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
1127 /* draw single */
1128 blender::gpu::Batch *batch = ui_batch_roundbox_widget_get();
1131 batch, "parameters", MAX_WIDGET_PARAMETERS, (float(*)[4]) & wtb->uniform_params);
1132 GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
1134 }
1135}
1136
1138 const uiWidgetColors *wcol,
1139 bool show_alpha_checkers)
1140{
1141 uchar inner_col1[4] = {0};
1142 uchar inner_col2[4] = {0};
1143 uchar emboss_col[4] = {0};
1144 uchar outline_col[4] = {0};
1145 uchar tria_col[4] = {0};
1146 /* For color widget. */
1147 if (wcol->shaded != 0) {
1148 show_alpha_checkers = false;
1149 }
1150
1151 /* backdrop non AA */
1152 if (wtb->draw_inner) {
1153 if (wcol->shaded == 0) {
1154 /* simple fill */
1155 inner_col1[0] = inner_col2[0] = wcol->inner[0];
1156 inner_col1[1] = inner_col2[1] = wcol->inner[1];
1157 inner_col1[2] = inner_col2[2] = wcol->inner[2];
1158 inner_col1[3] = inner_col2[3] = wcol->inner[3];
1159 }
1160 else {
1161 /* gradient fill */
1162 shadecolors4(wcol->inner, wcol->shadetop, wcol->shadedown, inner_col1, inner_col2);
1163 }
1164 }
1165
1166 if (wtb->draw_outline) {
1167 outline_col[0] = wcol->outline[0];
1168 outline_col[1] = wcol->outline[1];
1169 outline_col[2] = wcol->outline[2];
1170 outline_col[3] = wcol->outline[3];
1171
1172 /* Emboss shadow if enabled, and inner and outline colors are not fully transparent. */
1173 if ((wtb->draw_emboss) && (wcol->inner[3] != 0.0f || wcol->outline[3] != 0.0f)) {
1175 }
1176 }
1177
1178 if (wtb->tria1.type != ROUNDBOX_TRIA_NONE) {
1179 tria_col[0] = wcol->item[0];
1180 tria_col[1] = wcol->item[1];
1181 tria_col[2] = wcol->item[2];
1182 tria_col[3] = wcol->item[3];
1183 }
1184
1185 /* Draw everything in one draw-call. */
1186 if (inner_col1[3] || inner_col2[3] || outline_col[3] || emboss_col[3] || tria_col[3] ||
1187 show_alpha_checkers)
1188 {
1190 wtb, inner_col1, inner_col2, outline_col, emboss_col, tria_col, show_alpha_checkers);
1191
1195 }
1196}
1197
1198static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
1199{
1200 widgetbase_draw_ex(wtb, wcol, false);
1201}
1202
1205/* -------------------------------------------------------------------- */
1209#define UI_TEXT_CLIP_MARGIN (0.25f * U.widget_unit / but->block->aspect)
1210
1211#define PREVIEW_PAD (0.15f * UI_UNIT_X)
1212
1214{
1215 if (state->but_flag & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
1216 if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
1217 return 0.25f;
1218 }
1219 return 0.5f;
1220 }
1221
1222 if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
1223 return 0.5f;
1224 }
1225
1226 return 1.0f;
1227}
1228
1229static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
1230{
1231 if (icon == ICON_NONE) {
1232 return;
1233 }
1234
1235 const int w = BLI_rcti_size_x(rect);
1236 const int h = BLI_rcti_size_y(rect);
1237 const int size = std::min(w, h) - PREVIEW_PAD * 2;
1238
1239 if (size > 0) {
1240 const int x = rect->xmin + w / 2 - size / 2;
1241 const int y = rect->ymin + h / 2 - size / 2;
1242
1243 UI_icon_draw_preview(x, y, icon, 1.0f, alpha, size);
1244 }
1245}
1246
1248 const float aspect,
1249 const float alpha,
1250 const rcti *rect,
1251 const uchar mono_color[4])
1252{
1253 if (icon == ICON_NONE) {
1254 return;
1255 }
1256
1257 const float size = ICON_DEFAULT_HEIGHT / (aspect * UI_INV_SCALE_FAC);
1258
1259 if (size > 0) {
1260 const int x = BLI_rcti_cent_x(rect) - size / 2;
1261 const int y = BLI_rcti_cent_y(rect) - size / 2;
1262
1263 const bTheme *btheme = UI_GetTheme();
1264 const float desaturate = 1.0 - btheme->tui.icon_saturation;
1265 uchar color[4] = {mono_color[0], mono_color[1], mono_color[2], mono_color[3]};
1266 const bool has_theme = UI_icon_get_theme_color(int(icon), color);
1267 const bool outline = btheme->tui.icon_border_intensity > 0.0f && has_theme;
1268
1270 x, y, icon, aspect * UI_INV_SCALE_FAC, alpha, desaturate, color, outline, nullptr);
1271 }
1272}
1273
1274static int ui_but_draw_menu_icon(const uiBut *but)
1275{
1276 return (but->flag & UI_BUT_ICON_SUBMENU) && (but->emboss == UI_EMBOSS_PULLDOWN);
1277}
1278
1279/* icons have been standardized... and this call draws in untransformed coordinates */
1280
1282 const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const uchar mono_color[4])
1283{
1284 if (but->flag & UI_BUT_ICON_PREVIEW) {
1286 widget_draw_preview(icon, alpha, rect);
1288 return;
1289 }
1290
1291 /* this icon doesn't need draw... */
1292 if (icon == ICON_BLANK1 && (but->flag & UI_BUT_ICON_SUBMENU) == 0) {
1293 return;
1294 }
1295
1296 const float aspect = but->block->aspect * UI_INV_SCALE_FAC;
1297 const float height = ICON_DEFAULT_HEIGHT / aspect;
1298
1299 /* calculate blend color */
1301 if (but->flag & UI_SELECT) {
1302 /* pass */
1303 }
1304 else if (but->flag & UI_HOVER) {
1305 /* pass */
1306 }
1307 else {
1308 alpha = 0.75f;
1309 }
1310 }
1311 else if (but->type == UI_BTYPE_LABEL) {
1312 /* extra feature allows more alpha blending */
1313 const uiButLabel *but_label = reinterpret_cast<const uiButLabel *>(but);
1314 alpha *= but_label->alpha_factor;
1315 }
1316 else if (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR)) {
1318 state.but_flag = but->flag;
1319 state.but_drawflag = but->drawflag;
1320 alpha *= widget_alpha_factor(&state);
1321 }
1322
1324
1325 if (icon && icon != ICON_BLANK1) {
1326 const float ofs = 1.0f / aspect;
1327 float xs, ys;
1328
1329 if (but->drawflag & UI_BUT_ICON_LEFT) {
1330 /* special case - icon_only pie buttons */
1332 but->str.empty())
1333 {
1334 xs = rect->xmin + 2.0f * ofs;
1335 }
1336 else if (but->emboss == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL) {
1337 xs = rect->xmin + 2.0f * ofs;
1338 }
1339 else {
1340 xs = rect->xmin + 4.0f * ofs;
1341 }
1342 }
1343 else {
1344 xs = (rect->xmin + rect->xmax - height) / 2.0f;
1345 }
1346 ys = (rect->ymin + rect->ymax - height) / 2.0f;
1347
1348 /* force positions to integers, for zoom levels near 1. draws icons crisp. */
1349 if (aspect > 0.95f && aspect < 1.05f) {
1350 xs = roundf(xs);
1351 ys = roundf(ys);
1352 }
1353
1354 /* Get theme color. */
1355 uchar color[4] = {mono_color[0], mono_color[1], mono_color[2], mono_color[3]};
1356 const bTheme *btheme = UI_GetTheme();
1357 const bool has_theme = UI_icon_get_theme_color(int(icon), color);
1358 const bool outline = btheme->tui.icon_border_intensity > 0.0f && has_theme;
1359
1360 /* to indicate draggable */
1361 if (ui_but_drag_is_draggable(but) && (but->flag & UI_HOVER)) {
1362 UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, outline, &but->icon_overlay_text);
1363 }
1364 else if (but->flag & (UI_HOVER | UI_SELECT | UI_SELECT_DRAW)) {
1365 UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, outline, &but->icon_overlay_text);
1366 }
1367 else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) {
1368 if (has_theme) {
1369 alpha *= 0.8f;
1370 }
1371 UI_icon_draw_ex(xs,
1372 ys,
1373 icon,
1374 aspect,
1375 alpha,
1376 0.0f,
1377 color,
1378 outline,
1379 &but->icon_overlay_text,
1381 }
1382 else {
1383 const float desaturate = 1.0 - btheme->tui.icon_saturation;
1385 xs, ys, icon, aspect, alpha, desaturate, color, outline, &but->icon_overlay_text);
1386 }
1387 }
1388
1390}
1391
1392static void widget_draw_submenu_tria(const uiBut *but,
1393 const rcti *rect,
1394 const uiWidgetColors *wcol)
1395{
1396 const float aspect = but->block->aspect * UI_INV_SCALE_FAC;
1397 const int tria_height = int(ICON_DEFAULT_HEIGHT / aspect);
1398 const int tria_width = int(ICON_DEFAULT_WIDTH / aspect) - 2 * U.pixelsize;
1399 const int xs = rect->xmax - tria_width;
1400 const int ys = (rect->ymin + rect->ymax - tria_height) / 2.0f;
1401
1402 float col[4];
1404 col[3] *= 0.8f;
1405
1406 rctf tria_rect;
1407 BLI_rctf_init(&tria_rect, xs, xs + tria_width, ys, ys + tria_height);
1408 BLI_rctf_scale(&tria_rect, 0.4f);
1409
1413 draw_anti_tria_rect(&tria_rect, 'h', col);
1414}
1415
1416static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
1417{
1418 const char *prev_utf8 = BLI_str_find_prev_char_utf8(str + but->ofs, str);
1419 const int bytes = str + but->ofs - prev_utf8;
1420
1421 but->ofs -= bytes;
1422}
1423
1424static void ui_text_clip_give_next_off(uiBut *but, const char *str, const char *str_end)
1425{
1426 const char *next_utf8 = BLI_str_find_next_char_utf8(str + but->ofs, str_end);
1427 const int bytes = next_utf8 - (str + but->ofs);
1428
1429 but->ofs += bytes;
1430}
1431
1437static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
1438 char *str,
1439 const size_t max_len,
1440 const float okwidth,
1441 const char *sep,
1442 const int sep_len,
1443 const float sep_strwidth,
1444 size_t *r_final_len)
1445{
1446 BLI_assert(str[0]);
1447
1448 /* How many BYTES (not characters) of this utf-8 string can fit, along with appended ellipsis. */
1449 int l_end = BLF_width_to_strlen(
1450 fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, nullptr);
1451
1452 if (l_end > 0) {
1453 /* At least one character, so clip and add the ellipsis. */
1454 memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
1455 if (r_final_len) {
1456 *r_final_len = size_t(l_end) + sep_len;
1457 }
1458 }
1459 else {
1460 /* Otherwise fit as much as we can without adding an ellipsis. */
1461 l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, nullptr);
1462 str[l_end] = '\0';
1463 if (r_final_len) {
1464 *r_final_len = size_t(l_end);
1465 }
1466 }
1467}
1468
1470 char *str,
1471 float okwidth,
1472 const float minwidth,
1473 const size_t max_len,
1474 const char rpart_sep)
1475{
1476 BLI_assert(str[0]);
1477
1478 /* need to set this first */
1479 UI_fontstyle_set(fstyle);
1480
1481 float strwidth = BLF_width(fstyle->uifont_id, str, max_len);
1482
1483 if ((okwidth > 0.0f) && (strwidth > okwidth)) {
1484 const char sep[] = BLI_STR_UTF8_HORIZONTAL_ELLIPSIS;
1485 const int sep_len = sizeof(sep) - 1;
1486 const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
1487
1488 char *rpart = nullptr, rpart_buf[UI_MAX_DRAW_STR];
1489 float rpart_width = 0.0f;
1490 size_t rpart_len = 0;
1491 size_t final_lpart_len;
1492
1493 if (rpart_sep) {
1494 rpart = strrchr(str, rpart_sep);
1495
1496 if (rpart) {
1497 rpart_len = strlen(rpart);
1498 rpart_width = BLF_width(fstyle->uifont_id, rpart, rpart_len);
1499 okwidth -= rpart_width;
1500 strwidth -= rpart_width;
1501
1502 if (okwidth < 0.0f) {
1503 /* Not enough place for actual label, just display protected right part.
1504 * Here just for safety, should never happen in real life! */
1505 memmove(str, rpart, rpart_len + 1);
1506 rpart = nullptr;
1507 okwidth += rpart_width;
1508 strwidth = rpart_width;
1509 }
1510 }
1511 }
1512
1513 const float parts_strwidth = (okwidth - sep_strwidth) / 2.0f;
1514
1515 if (rpart) {
1516 STRNCPY(rpart_buf, rpart);
1517 *rpart = '\0';
1518 rpart = rpart_buf;
1519 }
1520
1521 const size_t l_end = BLF_width_to_strlen(
1522 fstyle->uifont_id, str, max_len, parts_strwidth, nullptr);
1523 if (l_end < 10 || min_ff(parts_strwidth, strwidth - okwidth) < minwidth) {
1524 /* If we really have no place, or we would clip a very small piece of string in the middle,
1525 * only show start of string.
1526 */
1528 fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
1529 }
1530 else {
1531 size_t r_offset, r_len;
1532
1533 r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, nullptr);
1534 r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */
1535
1536 if (l_end + sep_len + r_len + rpart_len > max_len) {
1537 /* Corner case, the str already takes all available mem,
1538 * and the ellipsis chars would actually add more chars.
1539 * Better to just trim one or two letters to the right in this case...
1540 * NOTE: with a single-char ellipsis, this should never happen! But better be safe
1541 * here...
1542 */
1544 fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
1545 }
1546 else {
1547 memmove(str + l_end + sep_len, str + r_offset, r_len);
1548 memcpy(str + l_end, sep, sep_len);
1549 /* -1 to remove trailing '\0'! */
1550 final_lpart_len = size_t(l_end + sep_len + r_len - 1);
1551
1552 while (BLF_width(fstyle->uifont_id, str, max_len) > okwidth) {
1553 /* This will happen because a lot of string width processing is done in integer pixels,
1554 * which can introduce a rather high error in the end (about 2 pixels or so).
1555 * Only one char removal shall ever be needed in real-life situation... */
1556 r_len--;
1557 final_lpart_len--;
1558 char *c = str + l_end + sep_len;
1559 memmove(c, c + 1, r_len);
1560 }
1561 }
1562 }
1563
1564 if (rpart) {
1565 /* Add back preserved right part to our shorten str. */
1566 memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */
1567 okwidth += rpart_width;
1568 }
1569
1570 strwidth = BLF_width(fstyle->uifont_id, str, max_len);
1571 }
1572
1573 /* The following assert is meant to catch code changes that break this function's result, but
1574 * some wriggle room is fine and needed. Just a couple pixels for large sizes and with some
1575 * settings like "Full" hinting which can move features both left and right a pixel. We could
1576 * probably reduce this to one pixel if we consolidate text output with length measuring. But
1577 * our text string lengths include the last character's right-side bearing anyway, so a string
1578 * can be longer by that amount and still fit visibly in the required space. */
1579 BLI_assert((strwidth <= (okwidth + 2)) || (okwidth <= 0.0f));
1580 UNUSED_VARS_NDEBUG(okwidth);
1581
1582 return strwidth;
1583}
1584
1588static void ui_text_clip_middle(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1589{
1590 /* No margin for labels! */
1591 const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU, UI_BTYPE_POPOVER) ?
1592 0 :
1593 int(UI_TEXT_CLIP_MARGIN + 0.5f);
1594 const float okwidth = float(max_ii(BLI_rcti_size_x(rect) - border, 0));
1595 const float minwidth = float(UI_ICON_SIZE) / but->block->aspect * 2.0f;
1596
1597 but->ofs = 0;
1598 char new_drawstr[UI_MAX_DRAW_STR];
1599 STRNCPY(new_drawstr, but->drawstr.c_str());
1600 const size_t max_len = sizeof(new_drawstr);
1601 but->strwidth = UI_text_clip_middle_ex(fstyle, new_drawstr, okwidth, minwidth, max_len, '\0');
1602 but->drawstr = new_drawstr;
1603}
1604
1612 uiBut *but,
1613 const rcti *rect,
1614 const char rsep)
1615{
1616 /* No margin for labels! */
1617 const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU, UI_BTYPE_POPOVER) ?
1618 0 :
1619 int(UI_TEXT_CLIP_MARGIN + 0.5f);
1620 const float okwidth = float(max_ii(BLI_rcti_size_x(rect) - border, 0));
1621 const float minwidth = float(UI_ICON_SIZE) / but->block->aspect * 2.0f;
1622
1623 but->ofs = 0;
1624 char new_drawstr[UI_MAX_DRAW_STR];
1625 STRNCPY(new_drawstr, but->drawstr.c_str());
1626 const size_t max_len = sizeof(new_drawstr);
1627 but->strwidth = UI_text_clip_middle_ex(fstyle, new_drawstr, okwidth, minwidth, max_len, rsep);
1628 but->drawstr = new_drawstr;
1629}
1630
1634static void ui_text_clip_cursor(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1635{
1636 const int border = int(UI_TEXT_CLIP_MARGIN + 0.5f);
1637 const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
1638
1639 BLI_assert(but->editstr && but->pos >= 0);
1640
1641 /* need to set this first */
1642 UI_fontstyle_set(fstyle);
1643
1644 /* define ofs dynamically */
1645 if (but->ofs > but->pos) {
1646 but->ofs = but->pos;
1647 }
1648
1649 if (BLF_width(fstyle->uifont_id, but->editstr, INT_MAX) <= okwidth) {
1650 but->ofs = 0;
1651 }
1652
1653 but->strwidth = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, INT_MAX);
1654
1655 if (but->strwidth > okwidth) {
1656 const int editstr_len = strlen(but->editstr);
1657 int len = editstr_len;
1658
1659 while (but->strwidth > okwidth) {
1660 float width;
1661
1662 /* string position of cursor */
1663 width = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, (but->pos - but->ofs));
1664
1665 /* if cursor is at 20 pixels of right side button we clip left */
1666 if (width > okwidth - 20) {
1667 ui_text_clip_give_next_off(but, but->editstr, but->editstr + editstr_len);
1668 }
1669 else {
1670 /* shift string to the left */
1671 if (width < 20 && but->ofs > 0) {
1673 }
1676 }
1677
1678 but->strwidth = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, len - but->ofs);
1679
1680 if (but->strwidth < 10) {
1681 break;
1682 }
1683 }
1684 }
1685}
1686
1692static void ui_text_clip_right_label(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1693{
1694 const int border = UI_TEXT_CLIP_MARGIN + 1;
1695 const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
1696
1697 int drawstr_len = but->drawstr.size();
1698 char new_drawstr[UI_MAX_DRAW_STR];
1699 STRNCPY(new_drawstr, but->drawstr.c_str());
1700
1701 const char *cpend = new_drawstr + drawstr_len;
1702
1703 /* need to set this first */
1704 UI_fontstyle_set(fstyle);
1705
1706 but->strwidth = BLF_width(fstyle->uifont_id, new_drawstr, drawstr_len);
1707
1708 /* The string already fits, so do nothing. */
1709 if (but->strwidth <= okwidth) {
1710 return;
1711 }
1712
1713 const char sep[] = BLI_STR_UTF8_HORIZONTAL_ELLIPSIS;
1714 const int sep_len = sizeof(sep) - 1;
1715 const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
1716
1717 /* Assume the string will have an ellipsis for initial tests. */
1718 but->strwidth += sep_strwidth;
1719
1720 but->ofs = 0;
1721
1722 /* First shorten number-buttons eg,
1723 * Translucency: 0.000
1724 * becomes
1725 * Trans: 0.000
1726 */
1727
1728 /* find the space after ':' separator */
1729 char *cpoin = strrchr(new_drawstr, ':');
1730
1731 if (cpoin && (cpoin < cpend - 2)) {
1732 char *cp2 = cpoin;
1733
1734 /* chop off the leading text, starting from the right */
1735 while (but->strwidth > okwidth && cp2 > new_drawstr) {
1736 const char *prev_utf8 = BLI_str_find_prev_char_utf8(cp2, new_drawstr);
1737 const int bytes = cp2 - prev_utf8;
1738
1739 /* shift the text after and including cp2 back by 1 char,
1740 * +1 to include null terminator */
1741 memmove(cp2 - bytes, cp2, drawstr_len + 1);
1742 cp2 -= bytes;
1743
1744 drawstr_len -= bytes;
1745
1746 but->strwidth = BLF_width(fstyle->uifont_id,
1747 new_drawstr + but->ofs,
1748 sizeof(new_drawstr) - but->ofs) +
1749 sep_strwidth;
1750 if (but->strwidth < sep_strwidth) {
1751 break;
1752 }
1753 }
1754
1755 /* after the leading text is gone, chop off the : and following space, with ofs */
1756 while ((but->strwidth > okwidth) && (but->ofs < 2)) {
1757 ui_text_clip_give_next_off(but, new_drawstr, new_drawstr + drawstr_len);
1758 but->strwidth = BLF_width(
1759 fstyle->uifont_id, new_drawstr + but->ofs, sizeof(new_drawstr) - but->ofs);
1760 if (but->strwidth < 10) {
1761 break;
1762 }
1763 }
1764 }
1765
1766 /* Now just remove trailing chars */
1767 /* once the label's gone, chop off the least significant digits */
1768 if (but->strwidth > okwidth) {
1769 float strwidth;
1770 drawstr_len = BLF_width_to_strlen(fstyle->uifont_id,
1771 new_drawstr + but->ofs,
1772 drawstr_len - but->ofs,
1773 okwidth,
1774 &strwidth) +
1775 but->ofs;
1776 but->strwidth = strwidth;
1777 new_drawstr[drawstr_len] = 0;
1778 }
1779
1780 cpoin = strrchr(new_drawstr, ':');
1781 if (cpoin && (cpoin - new_drawstr > 0) && (drawstr_len < (sizeof(new_drawstr) - sep_len))) {
1782 /* We shortened the string and still have a colon, so insert ellipsis. */
1783 memmove(cpoin + sep_len, cpoin, cpend - cpoin);
1784 memcpy(cpoin, sep, sep_len);
1785 but->strwidth = BLF_width(
1786 fstyle->uifont_id, new_drawstr + but->ofs, sizeof(new_drawstr) - but->ofs);
1787 }
1788
1789 but->drawstr = new_drawstr;
1790}
1791
1792#ifdef WITH_INPUT_IME
1793static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
1794 const uiWidgetColors *wcol,
1795 const uiBut *but,
1796 const rcti *rect,
1797 const wmIMEData *ime_data,
1798 const char *drawstr)
1799{
1800 int ofs_x, width;
1801 int rect_x = BLI_rcti_size_x(rect);
1802 int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end;
1803 float fcol[4];
1804
1805 if (drawstr[0] != 0) {
1806 if (but->pos >= but->ofs) {
1807 ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
1808 }
1809 else {
1810 ofs_x = 0;
1811 }
1812
1813 width = BLF_width(
1814 fstyle->uifont_id, drawstr + but->ofs, ime_data->composite_len + but->pos - but->ofs);
1815
1816 rgba_uchar_to_float(fcol, wcol->text);
1817 UI_draw_text_underline(rect->xmin + ofs_x,
1818 rect->ymin + 6 * U.pixelsize,
1819 min_ii(width, rect_x - 2) - ofs_x,
1820 1,
1821 fcol);
1822
1823 /* draw the thick line */
1824 if (sel_start != -1 && sel_end != -1) {
1825 sel_end -= sel_start;
1826 sel_start += but->pos;
1827
1828 if (sel_start >= but->ofs) {
1829 ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_start - but->ofs);
1830 }
1831 else {
1832 ofs_x = 0;
1833 }
1834
1835 width = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_end + sel_start - but->ofs);
1836
1837 UI_draw_text_underline(rect->xmin + ofs_x,
1838 rect->ymin + 6 * U.pixelsize,
1839 min_ii(width, rect_x - 2) - ofs_x,
1840 2,
1841 fcol);
1842 }
1843 }
1844}
1845#endif /* WITH_INPUT_IME */
1846
1847static void widget_draw_text(const uiFontStyle *fstyle,
1848 const uiWidgetColors *wcol,
1849 uiBut *but,
1850 rcti *rect)
1851{
1852 int drawstr_left_len = UI_MAX_DRAW_STR;
1853 const char *drawstr = but->drawstr.c_str();
1854 const char *drawstr_right = nullptr;
1855 bool use_right_only = false;
1856 const char *indeterminate_str = UI_VALUE_INDETERMINATE_CHAR;
1857
1858#ifdef WITH_INPUT_IME
1859 const wmIMEData *ime_data;
1860#endif
1861
1862 UI_fontstyle_set(fstyle);
1863
1864 eFontStyle_Align align;
1865 if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT)) {
1866 align = UI_STYLE_TEXT_LEFT;
1867 }
1868 else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
1869 align = UI_STYLE_TEXT_RIGHT;
1870 }
1871 else {
1872 align = UI_STYLE_TEXT_CENTER;
1873 }
1874
1875 /* Special case: when we're entering text for multiple buttons,
1876 * don't draw the text for any of the multi-editing buttons */
1877 if (UNLIKELY(but->flag & UI_BUT_DRAG_MULTI)) {
1878 uiBut *but_edit = ui_but_drag_multi_edit_get(but);
1879 if (but_edit) {
1880 drawstr = but_edit->editstr;
1881 align = UI_STYLE_TEXT_LEFT;
1882 }
1883 }
1884 else {
1885 if (but->editstr) {
1886 /* max length isn't used in this case,
1887 * we rely on string being nullptr terminated. */
1888 drawstr_left_len = INT_MAX;
1889
1890#ifdef WITH_INPUT_IME
1891 /* FIXME: IME is modifying `const char *drawstr`! */
1892 ime_data = ui_but_ime_data_get(but);
1893
1894 if (ime_data && ime_data->composite_len) {
1895 /* insert composite string into cursor pos */
1896 char tmp_drawstr[UI_MAX_DRAW_STR];
1897 STRNCPY(tmp_drawstr, drawstr);
1898 BLI_snprintf(tmp_drawstr,
1899 sizeof(tmp_drawstr),
1900 "%.*s%s%s",
1901 but->pos,
1902 but->editstr,
1903 ime_data->str_composite,
1904 but->editstr + but->pos);
1905 but->drawstr = tmp_drawstr;
1906 drawstr = but->drawstr.c_str();
1907 }
1908 else
1909#endif
1910 {
1911 drawstr = but->editstr;
1912 }
1913 }
1914 }
1915
1916 /* If not editing and indeterminate, show dash. */
1917 if (but->drawflag & UI_BUT_INDETERMINATE && !but->editstr &&
1918 ELEM(but->type,
1924 {
1925 drawstr = indeterminate_str;
1926 drawstr_left_len = strlen(drawstr);
1927 align = UI_STYLE_TEXT_CENTER;
1928 }
1929
1930 /* text button selection, cursor, composite underline */
1931 if (but->editstr && but->pos != -1) {
1932 int but_pos_ofs;
1933
1934#ifdef WITH_INPUT_IME
1935 bool ime_reposition_window = false;
1936 int ime_win_x, ime_win_y;
1937#endif
1938
1939 /* text button selection */
1940 if ((but->selend - but->selsta) != 0 && drawstr[0] != 0) {
1941 /* We are drawing on top of widget bases. Flush cache. */
1948 const auto boxes = BLF_str_selection_boxes(
1949 fstyle->uifont_id,
1950 drawstr + but->ofs,
1951 strlen(drawstr + but->ofs),
1952 (but->selsta >= but->ofs) ? but->selsta - but->ofs : 0,
1953 but->selend - std::max(but->ofs, but->selsta));
1954 for (auto bounds : boxes) {
1955 immRecti(pos,
1956 rect->xmin + bounds.min,
1957 rect->ymin + U.pixelsize,
1958 std::min(rect->xmin + bounds.max, rect->xmax - 2),
1959 rect->ymax - U.pixelsize);
1960 }
1963
1964#ifdef WITH_INPUT_IME
1965 /* IME candidate window uses selection position. */
1966 if (!ime_reposition_window && boxes.size() > 0) {
1967 ime_reposition_window = true;
1968 ime_win_x = rect->xmin + boxes[0].min;
1969 ime_win_y = rect->ymin + U.pixelsize;
1970 }
1971#endif
1972 }
1973
1974 /* Text cursor position. */
1975 but_pos_ofs = but->pos;
1976
1977#ifdef WITH_INPUT_IME
1978 /* If is IME compositing, move the cursor. */
1979 if (ime_data && ime_data->composite_len && ime_data->cursor_pos != -1) {
1980 but_pos_ofs += ime_data->cursor_pos;
1981 }
1982#endif
1983
1984 /* Draw text cursor (caret). */
1985 if (but->pos >= but->ofs) {
1986
1987 int t = BLF_str_offset_to_cursor(fstyle->uifont_id,
1988 drawstr + but->ofs,
1990 but_pos_ofs - but->ofs,
1991 max_ii(1, int(U.pixelsize * 2)));
1992
1993 /* We are drawing on top of widget bases. Flush cache. */
1997
2001
2003
2004 /* draw cursor */
2005 immRecti(pos,
2006 rect->xmin + t,
2007 rect->ymin + U.pixelsize,
2008 rect->xmin + t + int(2.0f * U.pixelsize),
2009 rect->ymax - U.pixelsize);
2010
2012
2013#ifdef WITH_INPUT_IME
2014 /* IME candidate window uses cursor position. */
2015 if (!ime_reposition_window) {
2016 ime_reposition_window = true;
2017 ime_win_x = rect->xmin + t + 5;
2018 ime_win_y = rect->ymin + 3;
2019 }
2020#endif
2021 }
2022
2023#ifdef WITH_INPUT_IME
2024 /* IME cursor following. */
2025 if (ime_reposition_window) {
2026 ui_but_ime_reposition(but, ime_win_x, ime_win_y, false);
2027 }
2028 if (ime_data && ime_data->composite_len) {
2029 /* Composite underline. */
2030 widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr);
2031 }
2032#endif
2033 }
2034
2035#if 0
2036 ui_rasterpos_safe(x, y, but->aspect);
2037 transopts = ui_translate_buttons();
2038#endif
2039
2040 bool use_drawstr_right_as_hint = false;
2041
2042 /* cut string in 2 parts - only for menu entries */
2043 if (but->flag & UI_BUT_HAS_SEP_CHAR && (but->editstr == nullptr)) {
2044 drawstr_right = strrchr(drawstr, UI_SEP_CHAR);
2045 if (drawstr_right) {
2046 use_drawstr_right_as_hint = true;
2047 drawstr_left_len = (drawstr_right - drawstr);
2048 drawstr_right++;
2049 }
2050 }
2051
2052#ifdef USE_NUMBUTS_LR_ALIGN
2053 if (!drawstr_right && (but->drawflag & UI_BUT_TEXT_LEFT) &&
2055 /* if we're editing or multi-drag (fake editing), then use left alignment */
2056 (but->editstr == nullptr) && (drawstr == but->drawstr))
2057 {
2058 drawstr_right = strrchr(drawstr + but->ofs, ':');
2059 if (drawstr_right) {
2060 drawstr_right++;
2061 drawstr_left_len = (drawstr_right - drawstr - 1);
2062
2063 while (*drawstr_right == ' ') {
2064 drawstr_right++;
2065 }
2066 }
2067 else {
2068 /* no prefix, even so use only cpoin */
2069 drawstr_right = drawstr + but->ofs;
2070 use_right_only = true;
2071 }
2072 }
2073#endif
2074
2075 if (!use_right_only) {
2076 /* for underline drawing */
2077 int font_xofs, font_yofs;
2078
2079 int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) :
2080 (drawstr_left_len - but->ofs);
2081
2082 if (drawlen > 0) {
2084 params.align = align;
2085 UI_fontstyle_draw_ex(fstyle,
2086 rect,
2087 drawstr + but->ofs,
2088 drawlen,
2089 wcol->text,
2090 &params,
2091 &font_xofs,
2092 &font_yofs,
2093 nullptr);
2094
2095 if (but->menu_key != '\0') {
2096 const char *drawstr_ofs = drawstr + but->ofs;
2097 int ul_index = -1;
2098
2099 {
2100 /* Find upper case, fallback to lower case. */
2101 const char *drawstr_end = drawstr_ofs + drawlen;
2102 const char keys[] = {char(but->menu_key - 32), but->menu_key};
2103 for (int i = 0; i < ARRAY_SIZE(keys); i++) {
2104 const char *drawstr_menu = strchr(drawstr_ofs, keys[i]);
2105 if (drawstr_menu != nullptr && drawstr_menu < drawstr_end) {
2106 ul_index = int(drawstr_menu - drawstr_ofs);
2107 break;
2108 }
2109 }
2110 }
2111
2112 if (ul_index != -1) {
2113 rcti bounds;
2114 if (BLF_str_offset_to_glyph_bounds(fstyle->uifont_id, drawstr_ofs, ul_index, &bounds) &&
2116 {
2117 int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2));
2118 int pos_x = rect->xmin + font_xofs + bounds.xmin +
2119 (bounds.xmax - bounds.xmin - ul_width) / 2;
2120 int pos_y = rect->ymin + font_yofs + bounds.ymin - U.pixelsize;
2121 /* Use text output because direct drawing doesn't always work. See #89246. */
2122 BLF_position(fstyle->uifont_id, float(pos_x), pos_y, 0.0f);
2123 BLF_color4ubv(fstyle->uifont_id, wcol->text);
2124 BLF_draw(fstyle->uifont_id, "_", 2);
2125 }
2126 }
2127 }
2128 }
2129 }
2130
2131 /* Show placeholder text if the input is empty and not being edited. */
2132 if (!drawstr[0] && !but->editstr && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
2133 const char *placeholder = ui_but_placeholder_get(but);
2134 if (placeholder && placeholder[0]) {
2136 params.align = align;
2137 uiFontStyle style = *fstyle;
2138 style.shadow = 0;
2139 uchar col[4];
2140 copy_v4_v4_uchar(col, wcol->text);
2141 col[3] *= 0.33f;
2143 &style, rect, placeholder, strlen(placeholder), col, &params, nullptr, nullptr, nullptr);
2144 }
2145 }
2146
2147 /* part text right aligned */
2148 if (drawstr_right) {
2149 uchar col[4];
2150 copy_v4_v4_uchar(col, wcol->text);
2151 if (use_drawstr_right_as_hint) {
2152 col[3] *= 0.5f;
2153 }
2154
2155 rect->xmax -= UI_TEXT_CLIP_MARGIN;
2158 UI_fontstyle_draw(fstyle, rect, drawstr_right, UI_MAX_DRAW_STR, col, &params);
2159 }
2160}
2161
2163 uiBut *but,
2164 rcti *rect,
2165 float alpha)
2166{
2167 const float icon_size = ICON_SIZE_FROM_BUTRECT(rect);
2168
2169 /* Offset of icons from the right edge. Keep in sync
2170 * with 'ui_but_extra_operator_icon_mouse_over_get'. */
2172 /* Eyeballed. */
2173 rect->xmax -= 0.2 * icon_size;
2174 }
2175
2176 /* Inverse order, from right to left. */
2178 rcti temp = *rect;
2179 float alpha_this = alpha;
2180
2181 temp.xmin = temp.xmax - icon_size;
2182
2183 if (op_icon->disabled) {
2184 alpha_this *= 0.4f;
2185 }
2186 else if (!op_icon->highlighted) {
2187 alpha_this *= 0.75f;
2188 }
2189
2190 /* Draw the icon at the center, and restore the flags after. */
2191 const int old_drawflags = but->drawflag;
2193 widget_draw_icon(but, op_icon->icon, alpha_this, &temp, wcol->text);
2194 but->drawflag = old_drawflags;
2195
2196 rect->xmax -= icon_size;
2197 }
2198}
2199
2201 const rcti *rect,
2202 uiBut *but,
2203 float alpha)
2204{
2205 /* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */
2206 if (but->custom_data) {
2207 const float scale = 0.9f / but->block->aspect;
2208
2209 float col[4];
2211 col[3] *= alpha;
2212
2216
2218 static_cast<bNodeSocket *>(but->custom_data), rect, col, scale);
2219 }
2220 else {
2221 widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text);
2222 }
2223}
2224
2225/* draws text and icons for buttons */
2226static void widget_draw_text_icon(const uiFontStyle *fstyle,
2227 const uiWidgetColors *wcol,
2228 uiBut *but,
2229 rcti *rect)
2230{
2231 const bool show_menu_icon = ui_but_draw_menu_icon(but);
2232 const float alpha = float(wcol->text[3]) / 255.0f;
2233 char password_str[UI_MAX_DRAW_STR];
2234 bool no_text_padding = but->drawflag & UI_BUT_NO_TEXT_PADDING;
2235
2236 ui_but_text_password_hide(password_str, but, false);
2237
2238 /* check for button text label */
2239 if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) {
2240 rcti temp = *rect;
2241 const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */
2242
2243 if (but->drawflag & UI_BUT_ICON_LEFT) {
2244 temp.xmax = rect->xmin + size;
2245 rect->xmin = temp.xmax;
2246 /* Further padding looks off. */
2247 no_text_padding = true;
2248 }
2249 else {
2250 temp.xmin = rect->xmax - size;
2251 rect->xmax = temp.xmin;
2252 }
2253
2254 widget_draw_node_link_socket(wcol, &temp, but, alpha);
2255 }
2256
2257 /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
2258 * and offset the text label to accommodate it */
2259
2260 /* Big previews with optional text label below */
2261 if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
2262 const BIFIconID icon = ui_but_icon(but);
2263 int icon_size = BLI_rcti_size_y(rect);
2264 int text_size = 0;
2265
2266 /* This is a bit brittle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */
2267 if (icon_size > BLI_rcti_size_x(rect)) {
2268 /* button is not square, it has extra height for label */
2269 text_size = UI_UNIT_Y;
2270 icon_size -= text_size;
2271 }
2272
2273 /* draw icon in rect above the space reserved for the label */
2274 rect->ymin += text_size;
2276 widget_draw_preview(icon, alpha, rect);
2278
2279 /* offset rect to draw label in */
2280 rect->ymin -= text_size;
2281 rect->ymax -= icon_size;
2282
2283 /* vertically centering text */
2284 rect->ymin += UI_UNIT_Y / 2;
2285 }
2286 /* Icons on the left with optional text label on the right */
2287 else if (but->flag & UI_HAS_ICON || show_menu_icon) {
2288 const bool is_tool = ((but->icon != ICON_NONE) & UI_but_is_tool(but));
2289
2290 /* XXX add way to draw icons at a different size!
2291 * Use small icons for popup. */
2292#ifdef USE_UI_TOOLBAR_HACK
2293 const float aspect_orig = but->block->aspect;
2294 if (is_tool && (but->block->flag & UI_BLOCK_POPOVER)) {
2295 but->block->aspect *= 2.0f;
2296 }
2297#endif
2298
2299 const BIFIconID icon = ui_but_icon(but);
2300 const int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT;
2301 const float icon_size = icon_size_init / (but->block->aspect * UI_INV_SCALE_FAC);
2302 const float icon_padding = 2 * UI_SCALE_FAC;
2303
2304#ifdef USE_UI_TOOLBAR_HACK
2305 if (is_tool) {
2306 /* pass (even if its a menu toolbar) */
2307 but->drawflag |= UI_BUT_TEXT_LEFT;
2308 but->drawflag |= UI_BUT_ICON_LEFT;
2309 }
2310#endif
2311
2312 /* menu item - add some more padding so menus don't feel cramped. it must
2313 * be part of the button so that this area is still clickable */
2314 if (is_tool) {
2315 /* pass (even if its a menu toolbar) */
2316 }
2317 else if (ui_block_is_pie_menu(but->block)) {
2318 if (but->emboss == UI_EMBOSS_PIE_MENU) {
2319 rect->xmin += 0.3f * U.widget_unit;
2320 }
2321 }
2322 /* Menu items, but only if they are not icon-only (rare). */
2323 else if (ui_block_is_menu(but->block) && but->drawstr[0]) {
2324 rect->xmin += 0.2f * U.widget_unit;
2325 }
2326
2327 /* By default icon is the color of text, but can optionally override with but->col. */
2328 widget_draw_icon(but, icon, alpha, rect, (but->col[3] != 0) ? but->col : wcol->text);
2329
2330 if (show_menu_icon) {
2332 widget_draw_submenu_tria(but, rect, wcol);
2333 }
2334
2335#ifdef USE_UI_TOOLBAR_HACK
2336 but->block->aspect = aspect_orig;
2337#endif
2338
2339 rect->xmin += round_fl_to_int(icon_size + icon_padding);
2340 }
2341
2342 if (!no_text_padding) {
2343 const int text_padding = round_fl_to_int((UI_TEXT_MARGIN_X * U.widget_unit) /
2344 but->block->aspect);
2345 if (but->editstr) {
2346 rect->xmin += text_padding;
2347 }
2348 else if (but->flag & UI_BUT_DRAG_MULTI) {
2349 const bool text_is_edited = ui_but_drag_multi_edit_get(but) != nullptr;
2350 if (text_is_edited || (but->drawflag & UI_BUT_TEXT_LEFT)) {
2351 rect->xmin += text_padding;
2352 }
2353 }
2354 else if (but->drawflag & UI_BUT_TEXT_LEFT) {
2355 rect->xmin += text_padding;
2356 }
2357 else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
2358 rect->xmax -= text_padding;
2359 }
2360 }
2361 else {
2362 /* In case a separate text label and some other button are placed under each other,
2363 * and the outline of the button does not contrast with the background.
2364 * Add an offset (thickness of the outline) so that the text does not stick out visually. */
2365 if (but->drawflag & UI_BUT_TEXT_LEFT) {
2366 rect->xmin += U.pixelsize;
2367 }
2368 else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
2369 rect->xmax -= U.pixelsize;
2370 }
2371 }
2372
2373 /* Menu contains sub-menu items with triangle icon on their right. Shortcut
2374 * strings should be drawn with some padding to the right then. */
2376 {
2378 }
2379
2380 /* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
2381 widget_draw_extra_icons(wcol, but, rect, alpha);
2382
2383 /* clip but->drawstr to fit in available space */
2384 if (but->editstr && but->pos >= 0) {
2385 ui_text_clip_cursor(fstyle, but, rect);
2386 }
2387 else if (but->drawstr[0] == '\0') {
2388 /* bypass text clipping on icon buttons */
2389 but->ofs = 0;
2390 but->strwidth = 0;
2391 }
2392 else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
2393 ui_text_clip_right_label(fstyle, but, rect);
2394 }
2395 else if (but->flag & UI_BUT_HAS_SEP_CHAR) {
2396 /* Clip middle, but protect in all case right part containing the shortcut, if any. */
2398 }
2399 else {
2400 ui_text_clip_middle(fstyle, but, rect);
2401 }
2402
2403 /* Always draw text for text-button cursor. */
2404 widget_draw_text(fstyle, wcol, but, rect);
2405
2406 ui_but_text_password_hide(password_str, but, true);
2407
2408 /* if a widget uses font shadow it has to be deactivated now */
2410}
2411
2412#undef UI_TEXT_CLIP_MARGIN
2413
2416/* -------------------------------------------------------------------- */
2422/* put all widget colors on half alpha, use local storage */
2424{
2425 static uiWidgetColors wcol_theme_s;
2426
2427 wcol_theme_s = *wt->wcol_theme;
2428
2429 const float factor = widget_alpha_factor(state);
2430
2431 wcol_theme_s.outline[3] *= factor;
2432 wcol_theme_s.inner[3] *= factor;
2433 wcol_theme_s.inner_sel[3] *= factor;
2434 wcol_theme_s.item[3] *= factor;
2435 wcol_theme_s.text[3] *= factor;
2436 wcol_theme_s.text_sel[3] *= factor;
2437
2438 wt->wcol_theme = &wcol_theme_s;
2439}
2440
2442{
2443 const bool dark = (rgb_to_grayscale_byte(wcol->text) > rgb_to_grayscale_byte(wcol->inner));
2444 color_mul_hsl_v3(wcol->inner, 1.0f, 1.15f, dark ? 1.2f : 1.1f);
2445 color_mul_hsl_v3(wcol->outline, 1.0f, 1.15f, 1.15f);
2446 color_mul_hsl_v3(wcol->text, 1.0f, 1.15f, dark ? 1.25f : 0.8f);
2447}
2448
2450 const uiWidgetStateInfo *state,
2451 const eUIEmbossType emboss)
2452{
2453 /* Explicitly require #UI_EMBOSS_NONE_OR_STATUS for color blending with no emboss. */
2454 if (emboss == UI_EMBOSS_NONE) {
2455 return nullptr;
2456 }
2457
2458 if (state->but_drawflag & UI_BUT_ANIMATED_CHANGED) {
2459 return wcol_state->inner_changed_sel;
2460 }
2461 if (state->but_flag & UI_BUT_ANIMATED_KEY) {
2462 return wcol_state->inner_key_sel;
2463 }
2464 if (state->but_flag & UI_BUT_ANIMATED) {
2465 return wcol_state->inner_anim_sel;
2466 }
2467 if (state->but_flag & UI_BUT_DRIVEN) {
2468 return wcol_state->inner_driven_sel;
2469 }
2470 if (state->but_flag & UI_BUT_OVERRIDDEN) {
2471 return wcol_state->inner_overridden_sel;
2472 }
2473 return nullptr;
2474}
2475
2476/* copy colors from theme, and set changes in it based on state */
2478{
2479 uiWidgetStateColors *wcol_state = wt->wcol_state;
2480
2481 if (state->but_flag & UI_BUT_LIST_ITEM) {
2482 /* Override default widget's colors. */
2483 bTheme *btheme = UI_GetTheme();
2484 wt->wcol_theme = &btheme->tui.wcol_list_item;
2485
2488 }
2489 }
2490
2491 wt->wcol = *(wt->wcol_theme);
2492
2493 const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
2494
2495 if (state->but_flag & UI_SELECT) {
2497 if (color_blend != nullptr) {
2498 color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
2499 }
2500
2502
2503 std::swap(wt->wcol.shadetop, wt->wcol.shadedown);
2504 }
2505 else {
2506 if (state->but_flag & UI_BUT_ACTIVE_DEFAULT) {
2509 }
2510 if (color_blend != nullptr) {
2511 color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
2512 }
2513
2514 /* Add "hover" highlight. Ideally this could apply in all cases,
2515 * even if UI_SELECT. But currently this causes some flickering
2516 * as buttons can be created and updated without respect to mouse
2517 * position and so can draw without UI_HOVER set. See D6503. */
2518 if (state->but_flag & UI_HOVER) {
2520 }
2521 }
2522
2523 if (state->but_flag & UI_BUT_REDALERT) {
2524 const uchar red[4] = {255, 0, 0};
2525 if (wt->draw && emboss != UI_EMBOSS_NONE) {
2526 color_blend_v3_v3(wt->wcol.inner, red, 0.4f);
2527 }
2528 else {
2529 color_blend_v3_v3(wt->wcol.text, red, 0.4f);
2530 }
2531 }
2532
2533 if (state->but_flag & UI_BUT_DRAG_MULTI) {
2534 /* the button isn't SELECT but we're editing this so draw with sel color */
2536 std::swap(wt->wcol.shadetop, wt->wcol.shadedown);
2537 color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
2538 }
2539
2540 if (state->but_flag & UI_BUT_NODE_ACTIVE) {
2541 const uchar blue[4] = {86, 128, 194};
2542 color_blend_v3_v3(wt->wcol.inner, blue, 0.3f);
2543 }
2544}
2545
2548/* -------------------------------------------------------------------- */
2557static float widget_radius_from_zoom(const float zoom, const uiWidgetColors *wcol)
2558{
2559 return wcol->roundness * U.widget_unit * zoom;
2560}
2561
2562static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wcol)
2563{
2564 return wcol->roundness * BLI_rcti_size_y(rect);
2565}
2566
2569/* -------------------------------------------------------------------- */
2576static bool draw_emboss(const uiBut *but)
2577{
2578 if (but->drawflag & UI_BUT_ALIGN_DOWN) {
2579 return false;
2580 }
2581
2582 if (but->type == UI_BTYPE_TAB &&
2583 (BLI_rctf_size_y(&but->block->rect) > BLI_rctf_size_x(&but->block->rect)) &&
2584 !(but->next == nullptr || but->next->type == UI_BTYPE_SEPR))
2585 {
2586 /* Vertical tabs, emboss at end and before separators. */
2587 return false;
2588 }
2589
2590 return true;
2591}
2592
2595/* -------------------------------------------------------------------- */
2599/* sliders use special hack which sets 'item' as inner when drawing filling */
2601 const uiWidgetStateInfo *state,
2602 eUIEmbossType emboss)
2603{
2604 uiWidgetStateColors *wcol_state = wt->wcol_state;
2605
2606 /* call this for option button */
2607 widget_state(wt, state, emboss);
2608
2609 const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
2610 if (color_blend != nullptr) {
2611 /* Set the slider 'item' so that it reflects state settings too.
2612 * De-saturate so the color of the slider doesn't conflict with the blend color,
2613 * which can make the color hard to see when the slider is set to full (see #66102). */
2614 wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = rgb_to_grayscale_byte(wt->wcol.item);
2615 color_blend_v3_v3(wt->wcol.item, color_blend, wcol_state->blend);
2617 }
2618
2619 if (state->but_flag & UI_SELECT) {
2620 std::swap(wt->wcol.shadetop, wt->wcol.shadedown);
2621 }
2622}
2623
2624/* labels use theme colors for text */
2626 const uiWidgetStateInfo *state,
2627 eUIEmbossType emboss)
2628{
2629 const bTheme *btheme = UI_GetTheme();
2630
2631 const uiWidgetColors *old_wcol = wt->wcol_theme;
2632 uiWidgetColors wcol_menu_option = *wt->wcol_theme;
2633
2634 /* Override the checkbox theme colors to use the menu-back text colors. */
2635 copy_v3_v3_uchar(wcol_menu_option.text, btheme->tui.wcol_menu_back.text);
2636 copy_v3_v3_uchar(wcol_menu_option.text_sel, btheme->tui.wcol_menu_back.text_sel);
2637 wt->wcol_theme = &wcol_menu_option;
2638
2639 widget_state(wt, state, emboss);
2640
2641 wt->wcol_theme = old_wcol;
2642}
2643
2645 const uiWidgetStateInfo * /*state*/,
2646 eUIEmbossType /*emboss*/)
2647{
2648 wt->wcol = *(wt->wcol_theme);
2649}
2650
2651/* special case, button that calls pulldown */
2653 const uiWidgetStateInfo * /*state*/,
2654 eUIEmbossType /*emboss*/)
2655{
2656 wt->wcol = *(wt->wcol_theme);
2657}
2658
2659/* special case, pie menu items */
2661 const uiWidgetStateInfo *state,
2662 eUIEmbossType /*emboss*/)
2663{
2664 wt->wcol = *(wt->wcol_theme);
2665
2666 if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_HOVER)) {
2667 color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
2668 /* draw the backdrop at low alpha, helps navigating with keys
2669 * when disabled items are active */
2671 wt->wcol.inner[3] = 64;
2672 }
2673 else {
2674 /* regular active */
2675 if (state->but_flag & (UI_SELECT | UI_HOVER)) {
2677 }
2678 else if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
2679 /* regular disabled */
2680 color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
2681 }
2682
2683 if (state->but_flag & UI_SELECT) {
2685 }
2686 else if (state->but_flag & UI_HOVER) {
2688 }
2689 }
2690}
2691
2692/* special case, menu items */
2694 const uiWidgetStateInfo *state,
2695 eUIEmbossType /*emboss*/)
2696{
2697 wt->wcol = *(wt->wcol_theme);
2698
2699 if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_HOVER)) {
2700 /* Hovering over disabled item. */
2701 wt->wcol.text[3] = 128;
2702 color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.5f);
2703 wt->wcol.inner[3] = 64;
2704 }
2705 else if (state->but_flag & UI_BUT_DISABLED) {
2706 /* Regular disabled. */
2707 wt->wcol.text[3] = 128;
2708 }
2709 else if (state->but_flag & UI_BUT_INACTIVE) {
2710 /* Inactive. */
2711 if (state->but_flag & UI_HOVER) {
2712 color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.2f);
2714 wt->wcol.inner[3] = 255;
2715 }
2716 color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
2717 }
2718 else if (state->but_flag & (UI_BUT_ACTIVE_DEFAULT | UI_SELECT_DRAW)) {
2719 /* Currently-selected item. */
2722 }
2723 else if ((state->but_flag & (UI_SELECT | UI_BUT_ICON_PREVIEW)) ==
2725 {
2726 /* Currently-selected list or menu item that is large icon preview. */
2729 }
2730 else if (state->but_flag & UI_HOVER) {
2731 /* Regular hover. */
2732 color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.2f);
2734 wt->wcol.inner[3] = 255;
2735 wt->wcol.text[3] = 255;
2736 }
2737}
2738
2741/* -------------------------------------------------------------------- */
2745/* outside of rect, rad to left/bottom/right */
2746static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
2747{
2748 const float outline = U.pixelsize;
2749
2750 rctf shadow_rect;
2751 BLI_rctf_rcti_copy(&shadow_rect, rect);
2752 BLI_rctf_pad(&shadow_rect, -outline, -outline);
2753
2754 UI_draw_roundbox_corner_set(roundboxalign);
2755
2756 const float shadow_alpha = UI_GetTheme()->tui.menu_shadow_fac;
2757 const float shadow_width = UI_ThemeMenuShadowWidth();
2758
2759 ui_draw_dropshadow(&shadow_rect, radin, shadow_width, 1.0f, shadow_alpha);
2760}
2761
2763 const rcti *rect,
2764 const int block_flag,
2765 const int direction,
2766 const float zoom)
2767{
2768 uiWidgetBase wtb;
2769 int roundboxalign = UI_CNR_ALL;
2770
2771 widget_init(&wtb);
2772
2773 /* menu is 2nd level or deeper */
2774 if (block_flag & UI_BLOCK_POPUP) {
2775 // rect->ymin -= 4.0;
2776 // rect->ymax += 4.0;
2777 }
2778 else if (direction & (UI_DIR_DOWN | UI_DIR_UP)) {
2779 if (direction & UI_DIR_DOWN) {
2780 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
2781 }
2782 else {
2783 roundboxalign = (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
2784 }
2785 /* Corner rounding based on secondary direction. */
2786 if (direction & UI_DIR_LEFT) {
2787 roundboxalign |= (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
2788 }
2789 if (direction & UI_DIR_RIGHT) {
2790 roundboxalign |= (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
2791 }
2792 }
2793
2795 const float radius = widget_radius_from_zoom(zoom, wcol);
2796 widget_softshadow(rect, roundboxalign, radius);
2797
2798 round_box_edges(&wtb, roundboxalign, rect, radius);
2799 wtb.draw_emboss = false;
2800 widgetbase_draw(&wtb, wcol);
2801
2803}
2804
2805static void ui_hsv_cursor(const float x,
2806 const float y,
2807 const float zoom,
2808 const float rgb[3],
2809 const float hsv[3],
2810 const bool is_active)
2811{
2812 /* Draw the circle larger while the mouse button is pressed down. */
2813 const float radius = zoom * (((is_active ? 20.0f : 12.0f) * UI_SCALE_FAC) + U.pixelsize);
2814
2820 immUniformColor3fv(rgb);
2821 immUniform1f("outlineWidth", U.pixelsize);
2822
2823 /* Alpha of outline colors just strong enough to give good contrast. */
2824 const float fg = std::min(1.0f - hsv[2] + 0.2f, 0.8f);
2825 const float bg = hsv[2] / 2.0f;
2826
2827 immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, bg);
2828 immUniform1f("size", radius);
2830 immVertex2f(pos, x, y);
2831 immEnd();
2832
2833 immUniform4f("outlineColor", 1.0f, 1.0f, 1.0f, fg);
2834 immUniform1f("size", radius - 1.0f);
2836 immVertex2f(pos, x, y);
2837 immEnd();
2838
2842}
2843
2845 const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist)
2846{
2847 /* duplication of code... well, simple is better now */
2848 const float centx = BLI_rcti_cent_x_fl(rect);
2849 const float centy = BLI_rcti_cent_y_fl(rect);
2850 const float radius = float(min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect))) / 2.0f;
2851 const float m_delta[2] = {mx - centx, my - centy};
2852 const float dist_sq = len_squared_v2(m_delta);
2853
2854 *r_val_dist = (dist_sq < (radius * radius)) ? sqrtf(dist_sq) / radius : 1.0f;
2855 *r_val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * float(M_PI)) + 0.5f;
2856}
2857
2859 const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *r_xpos, float *r_ypos)
2860{
2861 /* duplication of code... well, simple is better now */
2862 const float centx = BLI_rcti_cent_x_fl(rect);
2863 const float centy = BLI_rcti_cent_y_fl(rect);
2864 const float radius = float(min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect))) / 2.0f;
2865
2866 const float ang = 2.0f * float(M_PI) * hsv[0] + float(M_PI_2);
2867
2868 float radius_t;
2869 if (cpicker->use_color_cubic && (U.color_picker_type == USER_CP_CIRCLE_HSV)) {
2870 radius_t = (1.0f - pow3f(1.0f - hsv[1]));
2871 }
2872 else {
2873 radius_t = hsv[1];
2874 }
2875
2876 const float rad = clamp_f(radius_t, 0.0f, 1.0f) * radius;
2877 *r_xpos = centx + cosf(-ang) * rad;
2878 *r_ypos = centy + sinf(-ang) * rad;
2879}
2880
2881static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
2882{
2883 /* TODO(merwin): reimplement as shader for pixel-perfect colors */
2884
2885 const int tot = 64;
2886 const float radstep = 2.0f * float(M_PI) / float(tot);
2887 const float centx = BLI_rcti_cent_x_fl(rect);
2888 const float centy = BLI_rcti_cent_y_fl(rect);
2889 const float radius = float(min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect))) / 2.0f;
2890
2891 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
2892 float rgb[3], hsv[3], rgb_center[3];
2893 const bool is_color_gamma = ui_but_is_color_gamma(but);
2894
2895 /* Initialize for compatibility. */
2896 copy_v3_v3(hsv, cpicker->hsv_perceptual);
2897
2898 /* Compute current hue. */
2899 ui_but_v3_get(but, rgb);
2902
2903 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
2904
2905 /* exception: if 'lock' is set
2906 * lock the value of the color wheel to 1.
2907 * Useful for color correction tools where you're only interested in hue. */
2908 if (cpicker->use_color_lock) {
2909 if (U.color_picker_type == USER_CP_CIRCLE_HSV) {
2910 hsv[2] = 1.0f;
2911 }
2912 else {
2913 hsv[2] = 0.5f;
2914 }
2915 }
2916
2917 const float hsv_center[3] = {0.0f, 0.0f, hsv[2]};
2918 ui_color_picker_hsv_to_rgb(hsv_center, rgb_center);
2919 ui_perceptual_to_scene_linear_space(but, rgb_center);
2920
2921 if (!is_color_gamma) {
2922 ui_block_cm_to_display_space_v3(but->block, rgb_center);
2923 }
2924
2927 const uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
2928
2930
2931 immBegin(GPU_PRIM_TRI_FAN, tot + 2);
2932 immAttr3fv(color, rgb_center);
2933 immVertex2f(pos, centx, centy);
2934
2935 float ang = 0.0f;
2936 for (int a = 0; a <= tot; a++, ang += radstep) {
2937 const float si = sinf(ang);
2938 const float co = cosf(ang);
2939 float hsv_ang[3];
2940 float rgb_ang[3];
2941
2943 rect, centx + co * radius, centy + si * radius, hsv_ang, hsv_ang + 1);
2944 hsv_ang[2] = hsv[2];
2945
2946 ui_color_picker_hsv_to_rgb(hsv_ang, rgb_ang);
2948
2949 if (!is_color_gamma) {
2951 }
2952
2953 immAttr3fv(color, rgb_ang);
2954 immVertex2f(pos, centx + co * radius, centy + si * radius);
2955 }
2956 immEnd();
2958
2959 /* fully rounded outline */
2962
2964
2966 GPU_line_smooth(true);
2967
2969 imm_draw_circle_wire_2d(pos, centx, centy, radius, tot);
2970
2972
2974 GPU_line_smooth(false);
2975
2976 /* cursor */
2977 copy_v3_v3(hsv, cpicker->hsv_perceptual);
2978 ui_but_v3_get(but, rgb);
2981
2982 float xpos, ypos;
2983 ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos);
2984 const float zoom = 1.0f / but->block->aspect;
2985 ui_hsv_cursor(xpos, ypos, zoom, rgb, hsv, but->flag & UI_SELECT);
2986}
2987
2990/* -------------------------------------------------------------------- */
2994void ui_draw_gradient(const rcti *rect,
2995 const float hsv[3],
2996 const eButGradientType type,
2997 const float alpha)
2998{
2999 /* allows for 4 steps (red->yellow) */
3000 const int steps = 48;
3001 const float color_step = 1.0f / steps;
3002 int a;
3003 const float h = hsv[0], s = hsv[1], v = hsv[2];
3004 float dx, dy, sx1, sx2, sy;
3005 float col0[4][3]; /* left half, rect bottom to top */
3006 float col1[4][3]; /* right half, rect bottom to top */
3007
3008 /* draw series of gouraud rects */
3009
3010 switch (type) {
3011 case UI_GRAD_SV:
3012 hsv_to_rgb(h, 0.0, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
3013 hsv_to_rgb(h, 0.0, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
3014 hsv_to_rgb(h, 0.0, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
3015 hsv_to_rgb(h, 0.0, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
3016 break;
3017 case UI_GRAD_HV:
3018 hsv_to_rgb(0.0, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
3019 hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
3020 hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
3021 hsv_to_rgb(0.0, s, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
3022 break;
3023 case UI_GRAD_HS:
3024 hsv_to_rgb(0.0, 0.0, v, &col1[0][0], &col1[0][1], &col1[0][2]);
3025 hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
3026 hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
3027 hsv_to_rgb(0.0, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
3028 break;
3029 case UI_GRAD_H:
3030 hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
3031 copy_v3_v3(col1[1], col1[0]);
3032 copy_v3_v3(col1[2], col1[0]);
3033 copy_v3_v3(col1[3], col1[0]);
3034 break;
3035 case UI_GRAD_S:
3036 hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
3037 copy_v3_v3(col1[0], col1[1]);
3038 copy_v3_v3(col1[2], col1[1]);
3039 copy_v3_v3(col1[3], col1[1]);
3040 break;
3041 case UI_GRAD_V:
3042 hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
3043 copy_v3_v3(col1[0], col1[2]);
3044 copy_v3_v3(col1[1], col1[2]);
3045 copy_v3_v3(col1[3], col1[2]);
3046 break;
3047 default:
3048 BLI_assert_msg(0, "invalid 'type' argument");
3049 hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
3050 copy_v3_v3(col1[0], col1[2]);
3051 copy_v3_v3(col1[1], col1[2]);
3052 copy_v3_v3(col1[3], col1[2]);
3053 break;
3054 }
3055
3056 /* old below */
3061
3062 immBegin(GPU_PRIM_TRIS, steps * 3 * 6);
3063
3064 /* 0.999 = prevent float inaccuracy for steps */
3065 for (dx = 0.0f; dx < 0.999f; dx += color_step) {
3066 const float dx_next = dx + color_step;
3067
3068 /* previous color */
3069 copy_v3_v3(col0[0], col1[0]);
3070 copy_v3_v3(col0[1], col1[1]);
3071 copy_v3_v3(col0[2], col1[2]);
3072 copy_v3_v3(col0[3], col1[3]);
3073
3074 /* new color */
3075 switch (type) {
3076 case UI_GRAD_SV:
3077 hsv_to_rgb(h, dx, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
3078 hsv_to_rgb(h, dx, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
3079 hsv_to_rgb(h, dx, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
3080 hsv_to_rgb(h, dx, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
3081 break;
3082 case UI_GRAD_HV:
3083 hsv_to_rgb(dx_next, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
3084 hsv_to_rgb(dx_next, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
3085 hsv_to_rgb(dx_next, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
3086 hsv_to_rgb(dx_next, s, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
3087 break;
3088 case UI_GRAD_HS:
3089 hsv_to_rgb(dx_next, 0.0, v, &col1[0][0], &col1[0][1], &col1[0][2]);
3090 hsv_to_rgb(dx_next, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
3091 hsv_to_rgb(dx_next, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
3092 hsv_to_rgb(dx_next, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
3093 break;
3094 case UI_GRAD_H:
3095 /* annoying but without this the color shifts - could be solved some other way
3096 * - campbell */
3097 hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
3098 copy_v3_v3(col1[1], col1[0]);
3099 copy_v3_v3(col1[2], col1[0]);
3100 copy_v3_v3(col1[3], col1[0]);
3101 break;
3102 case UI_GRAD_S:
3103 hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
3104 copy_v3_v3(col1[0], col1[1]);
3105 copy_v3_v3(col1[2], col1[1]);
3106 copy_v3_v3(col1[3], col1[1]);
3107 break;
3108 case UI_GRAD_V:
3109 hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
3110 copy_v3_v3(col1[0], col1[2]);
3111 copy_v3_v3(col1[1], col1[2]);
3112 copy_v3_v3(col1[3], col1[2]);
3113 break;
3114 default:
3115 break;
3116 }
3117
3118 /* rect */
3119 sx1 = rect->xmin + dx * BLI_rcti_size_x(rect);
3120 sx2 = rect->xmin + dx_next * BLI_rcti_size_x(rect);
3121 sy = rect->ymin;
3122 dy = float(BLI_rcti_size_y(rect)) / 3.0f;
3123
3124 for (a = 0; a < 3; a++, sy += dy) {
3125 immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
3126 immVertex2f(pos, sx1, sy);
3127
3128 immAttr4f(col, col1[a][0], col1[a][1], col1[a][2], alpha);
3129 immVertex2f(pos, sx2, sy);
3130
3131 immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
3132 immVertex2f(pos, sx2, sy + dy);
3133
3134 immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
3135 immVertex2f(pos, sx1, sy);
3136
3137 immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
3138 immVertex2f(pos, sx2, sy + dy);
3139
3140 immAttr4f(col, col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
3141 immVertex2f(pos, sx1, sy + dy);
3142 }
3143 }
3144 immEnd();
3145
3147}
3148
3150 const uiButHSVCube *hsv_but, const rcti *rect, const float *hsv, float *r_xp, float *r_yp)
3151{
3152 float x = 0.0f, y = 0.0f;
3153
3154 switch (hsv_but->gradient_type) {
3155 case UI_GRAD_SV:
3156 x = hsv[1];
3157 y = hsv[2];
3158 break;
3159 case UI_GRAD_HV:
3160 x = hsv[0];
3161 y = hsv[2];
3162 break;
3163 case UI_GRAD_HS:
3164 x = hsv[0];
3165 y = hsv[1];
3166 break;
3167 case UI_GRAD_H:
3168 x = hsv[0];
3169 y = 0.5;
3170 break;
3171 case UI_GRAD_S:
3172 x = hsv[1];
3173 y = 0.5;
3174 break;
3175 case UI_GRAD_V:
3176 x = hsv[2];
3177 y = 0.5;
3178 break;
3179 case UI_GRAD_L_ALT:
3180 x = 0.5f;
3181 /* exception only for value strip - use the range set in but->min/max */
3182 y = hsv[2];
3183 break;
3184 case UI_GRAD_V_ALT:
3185 x = 0.5f;
3186 /* exception only for value strip - use the range set in but->min/max */
3187 y = (hsv[2] - hsv_but->softmin) / (hsv_but->softmax - hsv_but->softmin);
3188 break;
3189 case UI_GRAD_NONE:
3191 }
3192
3193 /* cursor */
3194 *r_xp = rect->xmin + x * BLI_rcti_size_x(rect);
3195 *r_yp = rect->ymin + y * BLI_rcti_size_y(rect);
3196}
3197
3198static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
3199{
3200 const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
3201 float rgb[3];
3202 float x = 0.0f, y = 0.0f;
3203 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
3204 float *hsv = cpicker->hsv_perceptual;
3205 float hsv_n[3];
3206
3207 /* Is this the larger color canvas or narrow color slider? */
3208 bool is_canvas = ELEM(hsv_but->gradient_type, UI_GRAD_SV, UI_GRAD_HV, UI_GRAD_HS);
3209
3210 /* Initialize for compatibility. */
3211 copy_v3_v3(hsv_n, hsv);
3212
3213 ui_but_v3_get(but, rgb);
3215 rgb_to_hsv_compat_v(rgb, hsv_n);
3216
3217 ui_draw_gradient(rect, hsv_n, hsv_but->gradient_type, 1.0f);
3218
3219 ui_hsvcube_pos_from_vals(hsv_but, rect, hsv_n, &x, &y);
3220
3221 const float zoom = 1.0f / but->block->aspect;
3222
3223 /* outline */
3227 immUniformColor3ub(0, 0, 0);
3228 imm_draw_box_wire_2d(pos, (rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
3230
3231 if (is_canvas) {
3232 /* Round cursor in the large square area. */
3233 float margin = (4.0f * UI_SCALE_FAC);
3234 CLAMP(x, rect->xmin + margin, rect->xmax - margin);
3235 CLAMP(y, rect->ymin + margin, rect->ymax - margin);
3236 ui_hsv_cursor(x, y, zoom, rgb, hsv, but->flag & UI_SELECT);
3237 }
3238 else {
3239 /* Square indicator in the narrow area. */
3240 rctf rectf;
3241 BLI_rctf_rcti_copy(&rectf, rect);
3242 const float margin = (2.0f * UI_SCALE_FAC);
3243 CLAMP(x, rect->xmin + margin, rect->xmax - margin);
3244 CLAMP(y, rect->ymin + margin, rect->ymax - margin);
3245 rectf.ymax += 1;
3246 rectf.xmin = x - (4.0f * UI_SCALE_FAC) - U.pixelsize;
3247 rectf.xmax = x + (4.0f * UI_SCALE_FAC) + U.pixelsize;
3248
3249 if (but->flag & UI_SELECT) {
3250 /* Make the indicator larger while the mouse button is pressed. */
3251 rectf.xmin -= U.pixelsize;
3252 rectf.xmax += U.pixelsize;
3253 rectf.ymin -= U.pixelsize;
3254 rectf.ymax += U.pixelsize;
3255 }
3256
3257 const float col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3258 UI_draw_roundbox_4fv(&rectf, false, 0, col);
3259
3260 rectf.xmin += 1.0f;
3261 rectf.xmax -= 1.0f;
3262 const float inner[4] = {1.0f, 1.0f, 1.0f, 1.0f};
3263 const float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3264 UI_draw_roundbox_4fv_ex(&rectf, col2, nullptr, 0.0f, inner, U.pixelsize, 0.0f);
3265 }
3266}
3267
3268/* vertical 'value' slider, using new widget code */
3269static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
3270{
3271 const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
3272 float rgb[3], hsv[3], v;
3273
3274 ui_but_v3_get(but, rgb);
3276
3277 if (hsv_but->gradient_type == UI_GRAD_L_ALT) {
3278 rgb_to_hsl_v(rgb, hsv);
3279 }
3280 else {
3281 rgb_to_hsv_v(rgb, hsv);
3282 }
3283 v = hsv[2];
3284
3285 /* map v from property range to [0,1] */
3286 if (hsv_but->gradient_type == UI_GRAD_V_ALT) {
3287 const float min = but->softmin, max = but->softmax;
3288 v = (v - min) / (max - min);
3289 }
3290
3291 rctf rectf;
3292 BLI_rctf_rcti_copy(&rectf, rect);
3293
3294 const float inner1[4] = {1.0f, 1.0f, 1.0f, 1.0f};
3295 const float inner2[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3296 const float outline[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3297 UI_draw_roundbox_4fv_ex(&rectf, inner1, inner2, U.pixelsize, outline, 1.0f, 0.0f);
3298
3299 /* cursor */
3300 float y = rect->ymin + v * BLI_rcti_size_y(rect);
3301 CLAMP(y, float(rect->ymin) + (2.0f * UI_SCALE_FAC), float(rect->ymax) - (2.0f * UI_SCALE_FAC));
3302 rectf.ymin = y - (4.0f * UI_SCALE_FAC) - U.pixelsize;
3303 rectf.ymax = y + (4.0f * UI_SCALE_FAC) + U.pixelsize;
3304 float col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3305
3306 if (but->flag & UI_SELECT) {
3307 /* Enlarge the indicator while the mouse button is pressed down. */
3308 rectf.xmin -= U.pixelsize;
3309 rectf.xmax += U.pixelsize;
3310 rectf.ymin -= U.pixelsize;
3311 rectf.ymax += U.pixelsize;
3312 }
3313
3314 UI_draw_roundbox_4fv(&rectf, false, 0.0f, col);
3315
3316 rectf.ymin += 1.0f;
3317 rectf.ymax -= 1.0f;
3318 const float col2[4] = {v, v, v, 1.0f};
3319 UI_draw_roundbox_4fv_ex(&rectf, col2, nullptr, 0.0f, inner1, U.pixelsize, 0.0f);
3320}
3321
3323static void ui_draw_separator(const uiWidgetColors *wcol, uiBut *but, const rcti *rect)
3324{
3325 const uiButSeparatorLine *but_line = static_cast<uiButSeparatorLine *>(but);
3326 const bool vertical = but_line->is_vertical;
3327 const int mid = vertical ? BLI_rcti_cent_x(rect) : BLI_rcti_cent_y(rect);
3328 const uchar col[4] = {
3329 wcol->text[0],
3330 wcol->text[1],
3331 wcol->text[2],
3332 30,
3333 };
3334
3338
3341 GPU_line_width(1.0f);
3342
3344
3345 if (vertical) {
3346 immVertex2f(pos, mid, rect->ymin);
3347 immVertex2f(pos, mid, rect->ymax);
3348 }
3349 else {
3350 immVertex2f(pos, rect->xmin, mid);
3351 immVertex2f(pos, rect->xmax, mid);
3352 }
3353
3354 immEnd();
3355
3357
3359}
3360
3363/* -------------------------------------------------------------------- */
3367#define NUM_BUT_PADDING_FACTOR 0.425f
3368
3369static void widget_numbut_draw(const uiBut *but,
3370 uiWidgetColors *wcol,
3371 rcti *rect,
3372 const float zoom,
3373 const uiWidgetStateInfo *state,
3374 int roundboxalign,
3375 bool emboss)
3376{
3377 const float rad = widget_radius_from_zoom(zoom, wcol);
3378 const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
3379
3380 if (state->but_flag & UI_SELECT) {
3381 std::swap(wcol->shadetop, wcol->shadedown);
3382 }
3383
3384 uiWidgetBase wtb;
3385 widget_init(&wtb);
3386
3387 if (!emboss) {
3388 round_box_edges(&wtb, roundboxalign, rect, rad);
3389 }
3390 else {
3391 wtb.draw_inner = false;
3392 wtb.draw_outline = false;
3393 }
3394
3395 /* decoration */
3396 if ((state->but_flag & UI_HOVER) && !state->is_text_input) {
3397 uiWidgetColors wcol_zone;
3398 uiWidgetBase wtb_zone;
3399 rcti rect_zone;
3400 int roundboxalign_zone;
3401
3402 /* left arrow zone */
3403 widget_init(&wtb_zone);
3404 wtb_zone.draw_outline = false;
3405 wtb_zone.draw_emboss = false;
3406
3407 wcol_zone = *wcol;
3408 copy_v3_v3_uchar(wcol_zone.item, wcol->text);
3409 if (state->but_drawflag & UI_BUT_HOVER_LEFT) {
3410 widget_active_color(&wcol_zone);
3411 }
3412
3413 rect_zone = *rect;
3414 rect_zone.xmax = rect->xmin + handle_width + U.pixelsize;
3415 roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
3416 round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
3417
3418 shape_preset_init_number_arrows(&wtb_zone.tria1, &rect_zone, 0.6f, 'l');
3419 widgetbase_draw(&wtb_zone, &wcol_zone);
3420
3421 /* right arrow zone */
3422 widget_init(&wtb_zone);
3423 wtb_zone.draw_outline = false;
3424 wtb_zone.draw_emboss = false;
3425 wtb_zone.tria1.type = ROUNDBOX_TRIA_ARROWS;
3426
3427 wcol_zone = *wcol;
3428 copy_v3_v3_uchar(wcol_zone.item, wcol->text);
3429 if (state->but_drawflag & UI_BUT_HOVER_RIGHT) {
3430 widget_active_color(&wcol_zone);
3431 }
3432
3433 rect_zone = *rect;
3434 rect_zone.xmin = rect->xmax - handle_width - U.pixelsize;
3435 roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
3436 round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
3437
3438 shape_preset_init_number_arrows(&wtb_zone.tria2, &rect_zone, 0.6f, 'r');
3439 widgetbase_draw(&wtb_zone, &wcol_zone);
3440
3441 /* middle highlight zone */
3442 widget_init(&wtb_zone);
3443 wtb_zone.draw_outline = false;
3444 wtb_zone.draw_emboss = false;
3445
3446 wcol_zone = *wcol;
3447 copy_v3_v3_uchar(wcol_zone.item, wcol->text);
3448 if (!(state->but_drawflag & (UI_BUT_HOVER_LEFT | UI_BUT_HOVER_RIGHT))) {
3449 widget_active_color(&wcol_zone);
3450 }
3451
3452 rect_zone = *rect;
3453 rect_zone.xmin = rect->xmin + handle_width - U.pixelsize;
3454 rect_zone.xmax = rect->xmax - handle_width + U.pixelsize;
3455 round_box_edges(&wtb_zone, 0, &rect_zone, 0);
3456 widgetbase_draw(&wtb_zone, &wcol_zone);
3457
3458 /* outline */
3459 wtb.draw_inner = false;
3460 wtb.draw_emboss = draw_emboss(but);
3461 widgetbase_draw(&wtb, wcol);
3462 }
3463 else {
3464 /* inner and outline */
3465 wtb.draw_emboss = draw_emboss(but);
3466 widgetbase_draw(&wtb, wcol);
3467 }
3468
3469 if (!state->is_text_input) {
3470 const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
3471
3472 rect->xmin += text_padding;
3473 rect->xmax -= text_padding;
3474 }
3475}
3476
3477static void widget_numbut(uiBut *but,
3478 uiWidgetColors *wcol,
3479 rcti *rect,
3480 const uiWidgetStateInfo *state,
3481 int roundboxalign,
3482 const float zoom)
3483{
3484 widget_numbut_draw(but, wcol, rect, zoom, state, roundboxalign, false);
3485}
3486
3488 rcti *rect,
3489 const uiWidgetStateInfo * /*state*/,
3490 int roundboxalign,
3491 const float zoom)
3492{
3493 uiWidgetBase wtb;
3494 widget_init(&wtb);
3495
3496 const float rad = widget_radius_from_zoom(zoom, wcol);
3497 round_box_edges(&wtb, roundboxalign, rect, rad);
3498
3499 /* decoration */
3501 /* copy size and center to 2nd tria */
3502 wtb.tria2 = wtb.tria1;
3503
3504 widgetbase_draw(&wtb, wcol);
3505
3506 /* text space, arrows are about 0.6 height of button */
3507 rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
3508}
3509
3513static void widget_menubut_embossn(const uiBut * /*but*/,
3514 uiWidgetColors *wcol,
3515 rcti *rect,
3516 const uiWidgetStateInfo * /*state*/,
3517 int /*roundboxalign*/)
3518{
3519 uiWidgetBase wtb;
3520 widget_init(&wtb);
3521 wtb.draw_inner = false;
3522 wtb.draw_outline = false;
3523
3524 /* decoration */
3526 /* copy size and center to 2nd tria */
3527 wtb.tria2 = wtb.tria1;
3528
3529 widgetbase_draw(&wtb, wcol);
3530}
3531
3535static void widget_numbut_embossn(const uiBut *but,
3536 uiWidgetColors *wcol,
3537 rcti *rect,
3538 const uiWidgetStateInfo *state,
3539 int roundboxalign,
3540 const float zoom)
3541{
3542 widget_numbut_draw(but, wcol, rect, zoom, state, roundboxalign, true);
3543}
3544
3545void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
3546{
3547 uiWidgetBase wtb;
3548
3549 widget_init(&wtb);
3550
3551 /* determine horizontal/vertical */
3552 const bool horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
3553
3554 const float rad = (horizontal) ? wcol->roundness * BLI_rcti_size_y(rect) :
3555 wcol->roundness * BLI_rcti_size_x(rect);
3556
3557 wtb.uniform_params.shade_dir = (horizontal) ? 1.0f : 0.0;
3558
3559 /* draw back part, colors swapped and shading inverted */
3560 if (horizontal) {
3561 std::swap(wcol->shadetop, wcol->shadedown);
3562 }
3563
3564 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
3565 widgetbase_draw(&wtb, wcol);
3566
3567 /* slider */
3568 if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
3569 /* pass */
3570 }
3571 else {
3572 std::swap(wcol->shadetop, wcol->shadedown);
3573
3574 copy_v4_v4_uchar(wcol->inner, wcol->item);
3575
3576 if (wcol->shadetop > wcol->shadedown) {
3577 wcol->shadetop += 20; /* XXX violates themes... */
3578 }
3579 else {
3580 wcol->shadedown += 20;
3581 }
3582
3583 if (state & UI_SCROLL_PRESSED) {
3584 wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
3585 wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
3586 wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
3587 }
3588
3589 /* draw */
3590 wtb.draw_emboss = false; /* only emboss once */
3591
3592 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
3593
3594 if (state & UI_SCROLL_ARROWS) {
3595 if (wcol->item[0] > 48) {
3596 wcol->item[0] -= 48;
3597 }
3598 if (wcol->item[1] > 48) {
3599 wcol->item[1] -= 48;
3600 }
3601 if (wcol->item[2] > 48) {
3602 wcol->item[2] -= 48;
3603 }
3604 wcol->item[3] = 255;
3605
3606 if (horizontal) {
3607 rcti slider_inset = *slider;
3608 slider_inset.xmin += 0.05 * U.widget_unit;
3609 slider_inset.xmax -= 0.05 * U.widget_unit;
3610 shape_preset_init_scroll_circle(&wtb.tria1, &slider_inset, 0.6f, 'l');
3611 shape_preset_init_scroll_circle(&wtb.tria2, &slider_inset, 0.6f, 'r');
3612 }
3613 else {
3614 shape_preset_init_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
3615 shape_preset_init_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
3616 }
3617 }
3618 widgetbase_draw(&wtb, wcol);
3619 }
3620}
3621
3622static void widget_scroll(uiBut *but,
3623 uiWidgetColors *wcol,
3624 rcti *rect,
3625 const uiWidgetStateInfo *state,
3626 int /*roundboxalign*/,
3627 const float /*zoom*/)
3628{
3629 const uiButScrollBar *but_scroll = reinterpret_cast<const uiButScrollBar *>(but);
3630 const float height = but_scroll->visual_height;
3631
3632 /* calculate slider part */
3633 const float value = float(ui_but_value_get(but));
3634
3635 const float size = max_ff((but->softmax + height - but->softmin), 2.0f);
3636
3637 /* position */
3638 rcti rect1 = *rect;
3639
3640 /* determine horizontal/vertical */
3641 const bool horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
3642
3643 if (horizontal) {
3644 const float fac = BLI_rcti_size_x(rect) / size;
3645 rect1.xmin = rect1.xmin + ceilf(fac * (value - but->softmin));
3646 rect1.xmax = rect1.xmin + ceilf(fac * (height - but->softmin));
3647
3648 /* Ensure minimum size. */
3649 const float min = BLI_rcti_size_y(rect);
3650
3651 if (BLI_rcti_size_x(&rect1) < min) {
3652 rect1.xmax = rect1.xmin + min;
3653
3654 if (rect1.xmax > rect->xmax) {
3655 rect1.xmax = rect->xmax;
3656 rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
3657 }
3658 }
3659 }
3660 else {
3661 const float fac = BLI_rcti_size_y(rect) / size;
3662 rect1.ymax = rect1.ymax - ceilf(fac * (value - but->softmin));
3663 rect1.ymin = rect1.ymax - ceilf(fac * (height - but->softmin));
3664
3665 /* Ensure minimum size. */
3666 const float min = BLI_rcti_size_x(rect);
3667
3668 if (BLI_rcti_size_y(&rect1) < min) {
3669 rect1.ymax = rect1.ymin + min;
3670
3671 if (rect1.ymax > rect->ymax) {
3672 rect1.ymax = rect->ymax;
3673 rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
3674 }
3675 }
3676 }
3677
3678 UI_draw_widget_scroll(wcol, rect, &rect1, (state->but_flag & UI_SELECT) ? UI_SCROLL_PRESSED : 0);
3679}
3680
3681static void widget_progress_type_bar(uiButProgress *but_progress,
3682 uiWidgetColors *wcol,
3683 rcti *rect,
3684 int roundboxalign,
3685 const float zoom)
3686{
3687 rcti rect_prog = *rect, rect_bar = *rect;
3688
3689 uiWidgetBase wtb, wtb_bar;
3690 widget_init(&wtb);
3691 widget_init(&wtb_bar);
3692
3693 /* round corners */
3694 const float factor = but_progress->progress_factor;
3695 const float ofs = widget_radius_from_zoom(zoom, wcol);
3696 float w = factor * BLI_rcti_size_x(&rect_prog);
3697
3698 /* Ensure minimum size. */
3699 w = std::max(w, ofs);
3700
3701 rect_bar.xmax = rect_bar.xmin + w;
3702
3703 round_box_edges(&wtb, roundboxalign, &rect_prog, ofs);
3704 round_box_edges(&wtb_bar, roundboxalign, &rect_bar, ofs);
3705
3706 wtb.draw_outline = true;
3707 widgetbase_draw(&wtb, wcol);
3708
3709 /* "slider" bar color */
3710 copy_v3_v3_uchar(wcol->inner, wcol->item);
3711 widgetbase_draw(&wtb_bar, wcol);
3712}
3713
3718 uiWidgetColors *wcol,
3719 rcti *rect)
3720{
3721 const float ring_width = 0.6; /* 0.0 would be a pie. */
3722 const float outer_rad = (rect->ymax - rect->ymin) / 2.0f;
3723 const float inner_rad = outer_rad * ring_width;
3724 const float x = rect->xmin + outer_rad;
3725 const float y = rect->ymin + outer_rad;
3726 const float start = 0.0f;
3727 const float end = but_progress->progress_factor * 360.0f;
3733
3734 for (int i = 0; i < UI_PIXEL_AA_JITTER; i++) {
3736 x + ui_pixel_jitter[i][0],
3737 y + ui_pixel_jitter[i][1],
3738 inner_rad,
3739 outer_rad,
3740 48,
3741 start,
3742 end);
3743 }
3745
3746 if (but_progress->drawstr[0]) {
3747 rect->xmin += UI_UNIT_X;
3748 }
3749}
3750
3752 uiWidgetColors *wcol,
3753 rcti *rect,
3754 const uiWidgetStateInfo * /*state*/,
3755 int roundboxalign,
3756 const float zoom)
3757{
3758 uiButProgress *but_progress = static_cast<uiButProgress *>(but);
3759 switch (but_progress->progress_type) {
3761 widget_progress_type_bar(but_progress, wcol, rect, roundboxalign, zoom);
3762 break;
3763 }
3765 widget_progress_type_ring(but_progress, wcol, rect);
3766 break;
3767 }
3768 }
3769}
3770
3771static void widget_nodesocket(uiBut *but,
3772 uiWidgetColors *wcol,
3773 rcti *rect,
3774 const uiWidgetStateInfo * /*state*/,
3775 int /*roundboxalign*/,
3776 const float /*zoom*/)
3777{
3778 const int radi = 0.25f * BLI_rcti_size_y(rect);
3779
3780 uiWidgetBase wtb;
3781 widget_init(&wtb);
3782
3783 uchar old_inner[3], old_outline[3];
3784 copy_v3_v3_uchar(old_inner, wcol->inner);
3785 copy_v3_v3_uchar(old_outline, wcol->outline);
3786
3787 wcol->inner[0] = but->col[0];
3788 wcol->inner[1] = but->col[1];
3789 wcol->inner[2] = but->col[2];
3790 wcol->outline[0] = 0;
3791 wcol->outline[1] = 0;
3792 wcol->outline[2] = 0;
3793 wcol->outline[3] = 150;
3794
3795 const int cent_x = BLI_rcti_cent_x(rect);
3796 const int cent_y = BLI_rcti_cent_y(rect);
3797 rect->xmin = cent_x - radi;
3798 rect->xmax = cent_x + radi;
3799 rect->ymin = cent_y - radi;
3800 rect->ymax = cent_y + radi;
3801
3802 wtb.draw_outline = true;
3803 round_box_edges(&wtb, UI_CNR_ALL, rect, float(radi));
3804 widgetbase_draw(&wtb, wcol);
3805
3806 copy_v3_v3_uchar(wcol->inner, old_inner);
3807 copy_v3_v3_uchar(wcol->outline, old_outline);
3808}
3809
3810static void widget_numslider(uiBut *but,
3811 uiWidgetColors *wcol,
3812 rcti *rect,
3813 const uiWidgetStateInfo *state,
3814 int roundboxalign,
3815 const float zoom)
3816{
3817 uiWidgetBase wtb, wtb1;
3818 widget_init(&wtb);
3819 widget_init(&wtb1);
3820
3821 /* Backdrop first. */
3822 const float rad = widget_radius_from_zoom(zoom, wcol);
3823 round_box_edges(&wtb, roundboxalign, rect, rad);
3824
3825 wtb.draw_outline = false;
3826 widgetbase_draw(&wtb, wcol);
3827
3828 /* Draw slider part only when not in text editing. */
3829 if (!state->is_text_input && !(but->drawflag & UI_BUT_INDETERMINATE)) {
3830 int roundboxalign_slider = roundboxalign;
3831
3832 uchar outline[3];
3833 copy_v3_v3_uchar(outline, wcol->outline);
3834 copy_v3_v3_uchar(wcol->outline, wcol->item);
3835 copy_v3_v3_uchar(wcol->inner, wcol->item);
3836
3837 if (!(state->but_flag & UI_SELECT)) {
3838 std::swap(wcol->shadetop, wcol->shadedown);
3839 }
3840
3841 rcti rect1 = *rect;
3842 float factor, factor_ui;
3843 float factor_discard = 1.0f; /* No discard. */
3844 const float value = float(ui_but_value_get(but));
3845 const float softmin = but->softmin;
3846 const float softmax = but->softmax;
3847 const float softrange = softmax - softmin;
3848 const PropertyScaleType scale_type = ui_but_scale_type(but);
3849
3850 switch (scale_type) {
3851 case PROP_SCALE_LINEAR: {
3852 if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) {
3853 factor = value / softmax;
3854 }
3855 else {
3856 factor = (value - softmin) / softrange;
3857 }
3858 break;
3859 }
3860 case PROP_SCALE_LOG: {
3861 const float logmin = fmaxf(softmin, 0.5e-8f);
3862 const float base = softmax / logmin;
3863 factor = logf(value / logmin) / logf(base);
3864 break;
3865 }
3866 case PROP_SCALE_CUBIC: {
3867 const float cubicmin = cube_f(softmin);
3868 const float cubicmax = cube_f(softmax);
3869 const float cubicrange = cubicmax - cubicmin;
3870 const float f = (value - softmin) * cubicrange / softrange + cubicmin;
3871 factor = (cbrtf(f) - softmin) / softrange;
3872 break;
3873 }
3874 }
3875
3876 const float width = float(BLI_rcti_size_x(rect));
3877 factor_ui = factor * width;
3878 /* The rectangle width needs to be at least twice the corner radius for the round corners
3879 * to be drawn properly. */
3880 const float min_width = 2.0f * rad;
3881
3882 if (factor_ui > width - rad) {
3883 /* Left part + middle part + right part. */
3884 factor_discard = factor;
3885 }
3886 else if (factor_ui > min_width) {
3887 /* Left part + middle part. */
3888 roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
3889 rect1.xmax = rect1.xmin + factor_ui;
3890 }
3891 else {
3892 /* Left part */
3893 roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
3894 rect1.xmax = rect1.xmin + min_width;
3895 factor_discard = factor_ui / min_width;
3896 }
3897
3898 round_box_edges(&wtb1, roundboxalign_slider, &rect1, rad);
3899 wtb1.draw_outline = false;
3900 widgetbase_set_uniform_discard_factor(&wtb1, factor_discard);
3901 widgetbase_draw(&wtb1, wcol);
3902
3903 copy_v3_v3_uchar(wcol->outline, outline);
3904
3905 if (!(state->but_flag & UI_SELECT)) {
3906 std::swap(wcol->shadetop, wcol->shadedown);
3907 }
3908 }
3909
3910 /* Outline. */
3911 wtb.draw_outline = true;
3912 wtb.draw_inner = false;
3913 widgetbase_draw(&wtb, wcol);
3914
3915 /* Add space at either side of the button so text aligns with number-buttons
3916 * (which have arrow icons). */
3917 if (!state->is_text_input) {
3918 const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
3919 rect->xmax -= text_padding;
3920 rect->xmin += text_padding;
3921 }
3922}
3923
3924/* I think 3 is sufficient border to indicate keyed status */
3925#define SWATCH_KEYED_BORDER 3
3926
3927static void widget_swatch(uiBut *but,
3928 uiWidgetColors *wcol,
3929 rcti *rect,
3930 const uiWidgetStateInfo *state,
3931 int roundboxalign,
3932 const float zoom)
3933{
3935 uiButColor *color_but = (uiButColor *)but;
3936 float col[4];
3937
3938 col[3] = 1.0f;
3939
3940 if (but->rnaprop) {
3941 BLI_assert(but->rnaindex == -1);
3942
3943 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
3944 col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
3945 }
3946 }
3947
3948 uiWidgetBase wtb;
3949 widget_init(&wtb);
3950
3951 const float rad = widget_radius_from_zoom(zoom, wcol);
3952 round_box_edges(&wtb, roundboxalign, rect, rad);
3953
3954 ui_but_v3_get(but, col);
3955
3956 if (but->drawflag & UI_BUT_INDETERMINATE) {
3957 col[0] = col[1] = col[2] = col[3] = 0.5f;
3958 }
3959
3962 (state->but_drawflag & UI_BUT_ANIMATED_CHANGED))
3963 {
3964 /* draw based on state - color for keyed etc */
3965 widgetbase_draw(&wtb, wcol);
3966
3967 /* inset to draw swatch color */
3968 rect->xmin += SWATCH_KEYED_BORDER;
3969 rect->xmax -= SWATCH_KEYED_BORDER;
3970 rect->ymin += SWATCH_KEYED_BORDER;
3971 rect->ymax -= SWATCH_KEYED_BORDER;
3972
3973 round_box_edges(&wtb, roundboxalign, rect, rad);
3974 }
3975
3976 if (!ui_but_is_color_gamma(but)) {
3978 }
3979
3981 const bool show_alpha_checkers = (wcol->inner[3] < 255);
3982
3983 wcol->shaded = 0;
3984
3985 /* Now we reduce alpha of the inner color (i.e. the color shown)
3986 * so that this setting can look grayed out, while retaining
3987 * the checkerboard (for transparent values). This is needed
3988 * here as the effects of ui_widget_color_disabled() are overwritten. */
3989 wcol->inner[3] *= widget_alpha_factor(state);
3990
3991 widgetbase_draw_ex(&wtb, wcol, show_alpha_checkers);
3992 if (color_but->is_pallete_color &&
3993 ((Palette *)but->rnapoin.owner_id)->active_color == color_but->palette_color_index)
3994 {
3995 const float width = rect->xmax - rect->xmin;
3996 const float height = rect->ymax - rect->ymin;
3997 /* find color luminance and change it slightly */
3998 float bw = rgb_to_grayscale(col);
3999
4000 bw += (bw < 0.5f) ? 0.5f : -0.5f;
4001
4002 /* We are drawing on top of widget bases. Flush cache. */
4006
4010
4011 immUniformColor3f(bw, bw, bw);
4013 immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
4014 immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
4015 immVertex2f(pos, rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
4016 immEnd();
4017
4019 }
4020}
4021
4022static void widget_unitvec(uiBut *but,
4023 uiWidgetColors *wcol,
4024 rcti *rect,
4025 const uiWidgetStateInfo * /*state*/,
4026 int /*roundboxalign*/,
4027 const float zoom)
4028{
4029 const float rad = widget_radius_from_zoom(zoom, wcol);
4030 ui_draw_but_UNITVEC(but, wcol, rect, rad);
4031}
4032
4034 uiWidgetColors *wcol,
4035 rcti *rect,
4036 const uiWidgetStateInfo *state,
4037 int roundboxalign,
4038 const float zoom)
4039{
4042 but->emboss != UI_EMBOSS_NONE)
4043 {
4044 uiWidgetBase wtb;
4045 widget_init(&wtb);
4046 wtb.draw_outline = false;
4047
4048 const float rad = widget_radius_from_zoom(zoom, wcol);
4049 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4050 widgetbase_draw(&wtb, wcol);
4051 }
4052 else if (but->type == UI_BTYPE_NUM) {
4053 /* Draw number buttons still with left/right
4054 * triangles when field is not embossed */
4055 widget_numbut_embossn(but, wcol, rect, state, roundboxalign, zoom);
4056 }
4057 else if (but->type == UI_BTYPE_MENU) {
4058 /* Draw menu buttons still with down arrow. */
4059 widget_menubut_embossn(but, wcol, rect, state, roundboxalign);
4060 }
4061}
4062
4064 rcti *rect,
4065 const uiWidgetStateInfo *state,
4066 int roundboxalign,
4067 const float zoom)
4068{
4069 if (state->but_flag & UI_SELECT) {
4070 std::swap(wcol->shadetop, wcol->shadedown);
4071 }
4072
4073 uiWidgetBase wtb;
4074 widget_init(&wtb);
4075
4076 const float rad = widget_radius_from_zoom(zoom, wcol);
4077 round_box_edges(&wtb, roundboxalign, rect, rad);
4078
4079 widgetbase_draw(&wtb, wcol);
4080}
4081
4083 rcti *rect,
4084 const uiWidgetStateInfo * /*state*/,
4085 int roundboxalign,
4086 const float zoom)
4087{
4088 uiWidgetBase wtb;
4089 widget_init(&wtb);
4090
4091 const float rad = widget_radius_from_zoom(zoom, wcol);
4092 round_box_edges(&wtb, roundboxalign, rect, rad);
4093
4094 /* decoration */
4095 widgetbase_draw(&wtb, wcol);
4096}
4097
4099 rcti *rect,
4100 const uiWidgetStateInfo *state,
4101 int roundboxalign,
4102 const float zoom)
4103{
4104 float back[4];
4106
4107 if ((state->but_flag & UI_HOVER) || (back[3] < 1.0f)) {
4108 uiWidgetBase wtb;
4109 const float rad = widget_radius_from_zoom(zoom, wcol);
4110
4111 if (state->but_flag & UI_HOVER) {
4112 copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
4113 copy_v3_v3_uchar(wcol->text, wcol->text_sel);
4114 copy_v3_v3_uchar(wcol->outline, wcol->inner);
4115 }
4116 else {
4117 wcol->inner[3] *= 1.0f - back[3];
4118 wcol->outline[3] = 0.0f;
4119 }
4120
4121 widget_init(&wtb);
4122
4123 /* half rounded */
4124 round_box_edges(&wtb, roundboxalign, rect, rad);
4125
4126 widgetbase_draw(&wtb, wcol);
4127 }
4128}
4129
4131 rcti *rect,
4132 const uiWidgetStateInfo * /*state*/,
4133 int /*roundboxalign*/,
4134 const float zoom)
4135{
4136 uiWidgetBase wtb;
4137 widget_init(&wtb);
4138
4139 /* Padding on the sides. */
4140 const float padding = zoom * 0.125f * U.widget_unit;
4141 rect->xmin += padding;
4142 rect->xmax -= padding;
4143
4144 /* No outline. */
4145 wtb.draw_outline = false;
4146
4147 const float rad = widget_radius_from_zoom(zoom, wcol);
4148
4149 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4150
4151 widgetbase_draw(&wtb, wcol);
4152}
4153
4155 rcti *rect,
4156 const uiWidgetStateInfo * /*state*/,
4157 int /*roundboxalign*/,
4158 const float zoom)
4159{
4160 /* This function is used for menu items placed close to each other horizontally, e.g. the matcap
4161 * preview popup or the row of collection color icons in the Outliner context menu. Don't use
4162 * padding on the sides like the normal menu item. */
4163
4164 uiWidgetBase wtb;
4165 widget_init(&wtb);
4166
4167 /* No outline. */
4168 wtb.draw_outline = false;
4169 const float rad = widget_radius_from_zoom(zoom, wcol);
4170 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4171
4172 widgetbase_draw(&wtb, wcol);
4173}
4174
4176 uiWidgetColors *wcol,
4177 rcti *rect,
4178 const uiWidgetStateInfo * /*state*/,
4179 int /*roundboxalign*/,
4180 const float zoom)
4181{
4182 const float fac = but->block->pie_data.alphafac;
4183
4184 uiWidgetBase wtb;
4185 widget_init(&wtb);
4186
4187 wtb.draw_emboss = false;
4188
4189 const float rad = widget_radius_from_zoom(zoom, wcol);
4190 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4191
4192 wcol->inner[3] *= fac;
4193 wcol->inner_sel[3] *= fac;
4194 wcol->item[3] *= fac;
4195 wcol->text[3] *= fac;
4196 wcol->text_sel[3] *= fac;
4197 wcol->outline[3] *= fac;
4198
4199 widgetbase_draw(&wtb, wcol);
4200}
4201
4203 uiWidgetColors *wcol,
4204 rcti *rect,
4205 const uiWidgetStateInfo *state,
4206 int /*roundboxalign*/,
4207 const float zoom)
4208{
4209 rcti draw_rect = *rect;
4210
4211 if (but->type == UI_BTYPE_VIEW_ITEM) {
4212 uiButViewItem *item_but = static_cast<uiButViewItem *>(but);
4213 if (item_but->draw_width > 0) {
4214 BLI_rcti_resize_x(&draw_rect, zoom * item_but->draw_width);
4215 }
4216 if (item_but->draw_height > 0) {
4217 BLI_rcti_resize_y(&draw_rect, zoom * item_but->draw_height);
4218 }
4219 }
4220
4221 uiWidgetBase wtb;
4222 widget_init(&wtb);
4223
4224 /* no outline */
4225 wtb.draw_outline = false;
4226 const float rad = widget_radius_from_zoom(zoom, wcol);
4227 round_box_edges(&wtb, UI_CNR_ALL, &draw_rect, rad);
4228
4229 if (state->but_flag & UI_HOVER && !(state->but_flag & UI_SELECT)) {
4230 copy_v3_v3_uchar(wcol->inner, wcol->text);
4231 wcol->inner[3] = 20;
4232 }
4233
4234 widgetbase_draw(&wtb, wcol);
4235}
4236
4238 uiWidgetColors *wcol,
4239 rcti *rect,
4240 const uiWidgetStateInfo *state,
4241 int roundboxalign,
4242 const float zoom)
4243{
4245 widget_list_itembut(but, wcol, rect, state, roundboxalign, zoom);
4246 }
4247
4248 /* When the button is not tagged as having a preview icon, do regular icon drawing with the
4249 * standard icon size. */
4250 const bool draw_as_icon = !(but->flag & UI_BUT_ICON_PREVIEW);
4251
4253 rect,
4254 but->drawstr,
4255 but->icon,
4256 wcol->text,
4258 draw_as_icon);
4259}
4260
4262 rcti *rect,
4263 const uiWidgetStateInfo *state,
4264 int /*roundboxalign*/,
4265 const float /*zoom*/)
4266{
4267 /* For a right aligned layout (signified by #UI_BUT_TEXT_RIGHT), draw the text on the left of the
4268 * checkbox. */
4269 const bool text_before_widget = (state->but_drawflag & UI_BUT_TEXT_RIGHT);
4270 rcti recttemp = *rect;
4271
4272 uiWidgetBase wtb;
4273 widget_init(&wtb);
4274
4275 /* square */
4276 if (text_before_widget) {
4277 recttemp.xmin = recttemp.xmax - BLI_rcti_size_y(&recttemp);
4278 }
4279 else {
4280 recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
4281 }
4282
4283 /* smaller */
4284 const int delta = (BLI_rcti_size_y(&recttemp) - 2 * U.pixelsize) / 6;
4286 &recttemp, BLI_rcti_size_x(&recttemp) - delta * 2, BLI_rcti_size_y(&recttemp) - delta * 2);
4287 /* Keep one edge in place. */
4288 BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
4289
4290 if (state->but_drawflag & UI_BUT_INDETERMINATE) {
4291 /* The same muted background color regardless of state. */
4292 color_blend_v4_v4v4(wcol->inner, wcol->inner, wcol->inner_sel, 0.75f);
4293 }
4294
4295 const float rad = widget_radius_from_rcti(&recttemp, wcol);
4296 round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
4297
4298 /* decoration */
4299 if (state->but_drawflag & UI_BUT_INDETERMINATE) {
4301 }
4302 else if (state->but_flag & UI_SELECT) {
4304 }
4305
4306 widgetbase_draw(&wtb, wcol);
4307
4308 /* Text space - factor is really just eyeballed. */
4309 const float offset = delta * 0.9;
4310 if (text_before_widget) {
4311 rect->xmax = recttemp.xmin - offset;
4312 }
4313 else {
4314 rect->xmin = recttemp.xmax + offset;
4315 }
4316}
4317
4318/* labels use Editor theme colors for text */
4320 const uiWidgetStateInfo *state,
4321 eUIEmbossType emboss)
4322{
4323 if (state->but_flag & UI_BUT_LIST_ITEM) {
4324 /* Override default label theme's colors. */
4325 bTheme *btheme = UI_GetTheme();
4326 wt->wcol_theme = &btheme->tui.wcol_list_item;
4327 /* call this for option button */
4328 widget_state(wt, state, emboss);
4329 }
4330 else {
4331 /* call this for option button */
4332 widget_state(wt, state, emboss);
4333 if (state->but_flag & UI_SELECT) {
4335 }
4336 else {
4338 }
4339 }
4340
4341 if (state->but_flag & UI_BUT_REDALERT) {
4342 const uchar red[4] = {255, 0, 0};
4343 color_blend_v3_v3(wt->wcol.text, red, 0.4f);
4344 }
4345}
4346
4348 rcti *rect,
4349 const uiWidgetStateInfo * /*state*/,
4350 int roundboxalign,
4351 const float zoom)
4352{
4353 uiWidgetBase wtb;
4354 widget_init(&wtb);
4355
4356 const float rad = widget_radius_from_zoom(zoom, wcol);
4357 round_box_edges(&wtb, roundboxalign, rect, rad);
4358
4359 widgetbase_draw(&wtb, wcol);
4360}
4361
4362static void widget_box(uiBut *but,
4363 uiWidgetColors *wcol,
4364 rcti *rect,
4365 const uiWidgetStateInfo * /*state*/,
4366 int roundboxalign,
4367 const float zoom)
4368{
4369 uiWidgetBase wtb;
4370 widget_init(&wtb);
4371
4372 uchar old_col[3];
4373 copy_v3_v3_uchar(old_col, wcol->inner);
4374
4375 /* abuse but->hsv - if it's non-zero, use this color as the box's background */
4376 if (but != nullptr && but->col[3]) {
4377 wcol->inner[0] = but->col[0];
4378 wcol->inner[1] = but->col[1];
4379 wcol->inner[2] = but->col[2];
4380 wcol->inner[3] = but->col[3];
4381 }
4382
4383 const float rad = widget_radius_from_zoom(zoom, wcol);
4384 round_box_edges(&wtb, roundboxalign, rect, rad);
4385 wtb.draw_emboss = draw_emboss(but);
4386 widgetbase_draw(&wtb, wcol);
4387
4388 copy_v3_v3_uchar(wcol->inner, old_col);
4389}
4390
4391static void widget_but(uiWidgetColors *wcol,
4392 rcti *rect,
4393 const uiWidgetStateInfo * /*state*/,
4394 int roundboxalign,
4395 const float zoom)
4396{
4397 uiWidgetBase wtb;
4398 widget_init(&wtb);
4399
4400 const float rad = widget_radius_from_zoom(zoom, wcol);
4401 round_box_edges(&wtb, roundboxalign, rect, rad);
4402
4403 widgetbase_draw(&wtb, wcol);
4404}
4405
4406#if 0
4407static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int /*state*/ int roundboxalign)
4408{
4409 uiWidgetBase wtb;
4410 const float rad = wcol->roundness * U.widget_unit;
4411
4412 widget_init(&wtb);
4413
4414 /* half rounded */
4415 round_box_edges(&wtb, roundboxalign, rect, rad);
4416
4417 widgetbase_draw(&wtb, wcol);
4418}
4419#endif
4420
4422 uiWidgetColors *wcol,
4423 rcti *rect,
4424 const uiWidgetStateInfo *state,
4425 int roundboxalign,
4426 const float zoom)
4427{
4428 uiWidgetBase wtb;
4429 widget_init(&wtb);
4430
4431 if (state->has_hold_action) {
4432 /* Show that keeping pressed performs another action (typically a menu). */
4433 shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
4434 }
4435
4436 const float rad = widget_radius_from_zoom(zoom, wcol);
4437
4438 /* half rounded */
4439 round_box_edges(&wtb, roundboxalign, rect, rad);
4440 wtb.draw_emboss = draw_emboss(but);
4441 widgetbase_draw(&wtb, wcol);
4442}
4443
4444static void widget_tab(uiBut *but,
4445 uiWidgetColors *wcol,
4446 rcti *rect,
4447 const uiWidgetStateInfo *state,
4448 int roundboxalign,
4449 const float zoom)
4450{
4451 const float rad = widget_radius_from_zoom(zoom, wcol);
4452 const bool is_active = (state->but_flag & UI_SELECT);
4453
4454 /* Draw shaded outline - Disabled for now,
4455 * seems incorrect and also looks nicer without it IMHO ;). */
4456 // #define USE_TAB_SHADED_HIGHLIGHT
4457
4458 uchar theme_col_tab_highlight[3];
4459
4460#ifdef USE_TAB_SHADED_HIGHLIGHT
4461 /* create outline highlight colors */
4462 if (is_active) {
4463 interp_v3_v3v3_uchar(theme_col_tab_highlight, wcol->inner_sel, wcol->outline, 0.2f);
4464 }
4465 else {
4466 interp_v3_v3v3_uchar(theme_col_tab_highlight, wcol->inner, wcol->outline, 0.12f);
4467 }
4468#endif
4469
4470 uiWidgetBase wtb;
4471 widget_init(&wtb);
4472
4473 /* half rounded */
4474 round_box_edges(&wtb, roundboxalign, rect, rad);
4475
4476 /* draw inner */
4477#ifdef USE_TAB_SHADED_HIGHLIGHT
4478 wtb.draw_outline = 0;
4479#endif
4480 wtb.draw_emboss = draw_emboss(but);
4481 widgetbase_draw(&wtb, wcol);
4482
4483 /* We are drawing on top of widget bases. Flush cache. */
4487
4488#ifdef USE_TAB_SHADED_HIGHLIGHT
4489 /* draw outline (3d look) */
4490 ui_draw_but_TAB_outline(rect, rad, theme_col_tab_highlight, wcol->inner);
4491#endif
4492
4493#ifndef USE_TAB_SHADED_HIGHLIGHT
4494 UNUSED_VARS(is_active, theme_col_tab_highlight);
4495#endif
4496}
4497
4498static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
4499{
4500 bTheme *btheme = UI_GetTheme();
4501 uiWidgetColors *wcol = &btheme->tui.wcol_radio;
4502 const float rad = wcol->roundness * U.widget_unit;
4503
4504 /* state copy! */
4505 wt->wcol = *(wt->wcol_theme);
4506
4507 uiWidgetBase wtb;
4508 widget_init(&wtb);
4509
4510 if (but->block->drawextra) {
4511 /* NOTE: drawextra can change rect +1 or -1, to match round errors of existing previews. */
4512 but->block->drawextra(C, rect);
4513
4517
4518 /* make mask to draw over image */
4519 uchar col[4];
4522
4523 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
4524 widgetbase_outline(&wtb, pos);
4525
4527 }
4528
4529 /* outline */
4530 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4531 wtb.draw_outline = true;
4532 wtb.draw_inner = false;
4533 widgetbase_draw(&wtb, &wt->wcol);
4534}
4535
4537{
4538 bTheme *btheme = UI_GetTheme();
4539
4540 /* defaults */
4541 static uiWidgetType wt;
4542 wt.wcol_theme = &btheme->tui.wcol_regular;
4543 wt.wcol_state = &btheme->tui.wcol_state;
4544 wt.state = widget_state;
4545 wt.draw = widget_but;
4546 wt.custom = nullptr;
4548
4549 switch (type) {
4550 case UI_WTYPE_REGULAR:
4551 break;
4552
4553 case UI_WTYPE_LABEL:
4554 wt.draw = nullptr;
4556 break;
4557
4558 case UI_WTYPE_TOGGLE:
4559 wt.wcol_theme = &btheme->tui.wcol_toggle;
4560 break;
4561
4562 case UI_WTYPE_CHECKBOX:
4563 wt.wcol_theme = &btheme->tui.wcol_option;
4565 break;
4566
4567 case UI_WTYPE_RADIO:
4568 wt.wcol_theme = &btheme->tui.wcol_radio;
4569 wt.draw = widget_radiobut;
4570 break;
4571
4572 case UI_WTYPE_NUMBER:
4573 wt.wcol_theme = &btheme->tui.wcol_num;
4574 wt.custom = widget_numbut;
4575 break;
4576
4577 case UI_WTYPE_SLIDER:
4578 wt.wcol_theme = &btheme->tui.wcol_numslider;
4581 break;
4582
4583 case UI_WTYPE_EXEC:
4584 wt.wcol_theme = &btheme->tui.wcol_tool;
4586 break;
4587
4589 wt.wcol_theme = &btheme->tui.wcol_toolbar_item;
4591 break;
4592
4593 case UI_WTYPE_TAB:
4594 wt.wcol_theme = &btheme->tui.wcol_tab;
4595 wt.custom = widget_tab;
4596 break;
4597
4598 case UI_WTYPE_TOOLTIP:
4599 wt.wcol_theme = &btheme->tui.wcol_tooltip;
4601 break;
4602
4603 /* strings */
4604 case UI_WTYPE_NAME:
4605 wt.wcol_theme = &btheme->tui.wcol_text;
4606 wt.draw = widget_textbut;
4607 break;
4608
4609 case UI_WTYPE_NAME_LINK:
4610 break;
4611
4613 break;
4614
4615 case UI_WTYPE_FILENAME:
4616 break;
4617
4618 /* start menus */
4620 wt.wcol_theme = &btheme->tui.wcol_menu;
4621 wt.draw = widget_menubut;
4622 break;
4623
4626 wt.wcol_theme = &btheme->tui.wcol_menu;
4628 break;
4629
4631 wt.wcol_theme = &btheme->tui.wcol_menu;
4632 wt.draw = widget_menubut;
4633 break;
4634
4635 case UI_WTYPE_PULLDOWN:
4636 wt.wcol_theme = &btheme->tui.wcol_pulldown;
4639 break;
4640
4641 /* in menus */
4642 case UI_WTYPE_MENU_ITEM:
4643 wt.wcol_theme = &btheme->tui.wcol_menu_item;
4646 break;
4647
4649 wt.wcol_theme = &btheme->tui.wcol_menu_item;
4652 break;
4653
4654 case UI_WTYPE_MENU_BACK:
4655 wt.wcol_theme = &btheme->tui.wcol_menu_back;
4657 break;
4658
4659 /* specials */
4660 case UI_WTYPE_ICON:
4662 break;
4663
4665 /* behave like regular labels (this is simply a label with an icon) */
4668 break;
4669
4671 wt.draw = nullptr;
4672 /* Drawn via the `custom` callback. */
4673 wt.text = nullptr;
4674 /* Drawing indicates state well enough. No need to change colors further. */
4677 wt.wcol_theme = &btheme->tui.wcol_list_item;
4678 break;
4679
4680 case UI_WTYPE_SWATCH:
4681 wt.custom = widget_swatch;
4682 break;
4683
4684 case UI_WTYPE_BOX:
4685 wt.custom = widget_box;
4686 wt.wcol_theme = &btheme->tui.wcol_box;
4687 break;
4688
4690 break;
4691
4692 case UI_WTYPE_UNITVEC:
4694 break;
4695
4696 case UI_WTYPE_SCROLL:
4697 wt.wcol_theme = &btheme->tui.wcol_scroll;
4699 wt.custom = widget_scroll;
4700 break;
4701
4702 case UI_WTYPE_LISTITEM:
4703 case UI_WTYPE_VIEW_ITEM:
4704 wt.wcol_theme = &btheme->tui.wcol_list_item;
4706 break;
4707
4708 case UI_WTYPE_PROGRESS:
4709 wt.wcol_theme = &btheme->tui.wcol_progress;
4711 break;
4712
4715 break;
4716
4718 wt.wcol_theme = &btheme->tui.wcol_pie_menu;
4721 break;
4722 }
4723
4724 return &wt;
4725}
4726
4727static int widget_roundbox_set(uiBut *but, rcti *rect)
4728{
4729 int roundbox = UI_CNR_ALL;
4730
4731 /* alignment */
4732 if ((but->drawflag & UI_BUT_ALIGN) && but->type != UI_BTYPE_PULLDOWN) {
4733
4734 /* ui_popup_block_position has this correction too, keep in sync */
4736 rect->ymax += U.pixelsize;
4737 }
4739 rect->xmin -= U.pixelsize;
4740 }
4741
4742 switch (but->drawflag & UI_BUT_ALIGN) {
4743 case UI_BUT_ALIGN_TOP:
4745 break;
4746 case UI_BUT_ALIGN_DOWN:
4747 roundbox = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
4748 break;
4749 case UI_BUT_ALIGN_LEFT:
4751 break;
4752 case UI_BUT_ALIGN_RIGHT:
4754 break;
4756 roundbox = UI_CNR_TOP_LEFT;
4757 break;
4759 roundbox = UI_CNR_TOP_RIGHT;
4760 break;
4762 roundbox = UI_CNR_BOTTOM_LEFT;
4763 break;
4765 roundbox = UI_CNR_BOTTOM_RIGHT;
4766 break;
4767 default:
4768 roundbox = 0;
4769 break;
4770 }
4771 }
4772
4773 /* align with open menu */
4774 if (but->active && (but->type != UI_BTYPE_POPOVER) && !ui_but_menu_draw_as_popover(but)) {
4775 const int direction = ui_but_menu_direction(but);
4776
4777 /* Pull-down menus that open above or below a button can have more than one direction. */
4778 if (direction & UI_DIR_UP) {
4779 roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
4780 }
4781 else if (direction & UI_DIR_DOWN) {
4782 roundbox &= ~(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
4783 }
4784 else if (direction == UI_DIR_LEFT) {
4785 roundbox &= ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
4786 }
4787 else if (direction == UI_DIR_RIGHT) {
4788 roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
4789 }
4790 }
4791
4792 return roundbox;
4793}
4794
4797/* -------------------------------------------------------------------- */
4801void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
4802{
4803 bTheme *btheme = UI_GetTheme();
4804 const ThemeUI *tui = &btheme->tui;
4805 const uiFontStyle *fstyle = &style->widget;
4806 uiWidgetType *wt = nullptr;
4807
4808 /* handle menus separately */
4809 if (but->emboss == UI_EMBOSS_PULLDOWN) {
4810 switch (but->type) {
4811 case UI_BTYPE_LABEL:
4812 widget_draw_text_icon(&style->widget, &tui->wcol_menu_back, but, rect);
4813 break;
4814 case UI_BTYPE_SEPR:
4815 break;
4816 case UI_BTYPE_SEPR_LINE:
4817 /* Add horizontal padding between the line and menu sides. */
4818 BLI_rcti_pad(rect, int(-7.0f * UI_SCALE_FAC), 0);
4819 ui_draw_separator(&tui->wcol_menu_item, but, rect);
4820 break;
4821 default: {
4822 const bool use_unpadded = (but->flag & UI_BUT_ICON_PREVIEW) ||
4823 ((but->flag & UI_HAS_ICON) && !but->drawstr[0]);
4825 break;
4826 }
4827 }
4828 }
4830 /* Use the same widget types for both no emboss types. Later on,
4831 * #UI_EMBOSS_NONE_OR_STATUS will blend state colors if they apply. */
4832 switch (but->type) {
4833 case UI_BTYPE_LABEL:
4834 case UI_BTYPE_TEXT:
4836 if (!(but->flag & UI_HAS_ICON)) {
4838 }
4839 break;
4842 break;
4843 default:
4845 break;
4846 }
4847 }
4848 else if (but->emboss == UI_EMBOSS_PIE_MENU) {
4850 }
4851 else {
4852 BLI_assert(but->emboss == UI_EMBOSS);
4853
4854 switch (but->type) {
4855 case UI_BTYPE_LABEL:
4857 if (but->drawflag & UI_BUT_BOX_ITEM) {
4858 wt->wcol_theme = &tui->wcol_box;
4859 wt->state = widget_state;
4860 }
4861 else if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) {
4862 wt->wcol_theme = &tui->wcol_menu_back;
4863 wt->state = widget_state;
4864 }
4865 if (!(but->flag & UI_HAS_ICON)) {
4867 }
4868 break;
4869
4870 case UI_BTYPE_SEPR:
4872 break;
4873 case UI_BTYPE_SEPR_LINE:
4874 ui_draw_separator(&tui->wcol_menu_item, but, rect);
4875 break;
4876
4877 case UI_BTYPE_BUT:
4878 case UI_BTYPE_DECORATOR:
4879#ifdef USE_UI_TOOLBAR_HACK
4880 if ((but->icon != ICON_NONE) && UI_but_is_tool(but)) {
4882 }
4883 else {
4885 }
4886#else
4888#endif
4889 break;
4890
4891 case UI_BTYPE_NUM:
4893 break;
4894
4897 break;
4898
4899 case UI_BTYPE_ROW:
4901 break;
4902
4903 case UI_BTYPE_LISTROW:
4905 break;
4906
4907 case UI_BTYPE_TEXT:
4909 break;
4910
4913 break;
4914
4915 case UI_BTYPE_TAB:
4917 break;
4918
4920 case UI_BTYPE_TOGGLE:
4921 case UI_BTYPE_TOGGLE_N:
4923 break;
4924
4925 case UI_BTYPE_CHECKBOX:
4927 if (!(but->flag & UI_HAS_ICON)) {
4929
4930 if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) {
4931 but->drawflag |= UI_BUT_TEXT_LEFT;
4932 }
4933 /* #widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
4934 * text drawing were to add its own padding, DPI and zoom factor would be applied twice
4935 * in the final padding, so it's difficult to control it. */
4937 }
4938 else {
4940 }
4941
4942 /* option buttons have strings outside, on menus use different colors */
4945 }
4946 break;
4947
4948 case UI_BTYPE_MENU:
4949 case UI_BTYPE_BLOCK:
4950 case UI_BTYPE_POPOVER:
4951 if (but->flag & UI_BUT_NODE_LINK) {
4952 /* new node-link button, not active yet XXX */
4954 }
4955 else {
4956 /* with menu arrows */
4957
4958 /* We could use a flag for this, but for now just check size,
4959 * add up/down arrows if there is room. */
4960 if ((but->str.empty() && but->icon &&
4961 (BLI_rcti_size_x(rect) < BLI_rcti_size_y(rect) + 2)) ||
4962 /* disable for brushes also */
4963 (but->flag & UI_BUT_ICON_PREVIEW))
4964 {
4965 /* no arrows */
4967 }
4968 else {
4970 }
4971 }
4972 break;
4973
4974 case UI_BTYPE_PULLDOWN:
4976 break;
4977
4978 case UI_BTYPE_BUT_MENU:
4980 break;
4981
4982 case UI_BTYPE_COLOR:
4984 break;
4985
4986 case UI_BTYPE_ROUNDBOX:
4987 case UI_BTYPE_LISTBOX:
4989 break;
4990
4993 break;
4994
4995 case UI_BTYPE_EXTRA:
4997 break;
4998
4999 case UI_BTYPE_HSVCUBE: {
5000 const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
5001
5003 /* vertical V slider, uses new widget draw now */
5004 ui_draw_but_HSV_v(but, rect);
5005 }
5006 else { /* other HSV pickers... */
5007 ui_draw_but_HSVCUBE(but, rect);
5008 }
5009 break;
5010 }
5011
5012 case UI_BTYPE_HSVCIRCLE:
5013 ui_draw_but_HSVCIRCLE(but, &tui->wcol_regular, rect);
5014 break;
5015
5016 case UI_BTYPE_COLORBAND: {
5017 /* Horizontal padding to make room for handles at edges. */
5018 const int padding = BLI_rcti_size_y(rect) / 6;
5019 rect->xmin += padding;
5020 rect->xmax -= padding;
5021 ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect);
5022 break;
5023 }
5024
5025 case UI_BTYPE_UNITVEC:
5027 break;
5028
5029 case UI_BTYPE_IMAGE:
5030 ui_draw_but_IMAGE(region, but, &tui->wcol_regular, rect);
5031 break;
5032
5033 case UI_BTYPE_HISTOGRAM:
5034 ui_draw_but_HISTOGRAM(region, but, &tui->wcol_regular, rect);
5035 break;
5036
5037 case UI_BTYPE_WAVEFORM:
5038 ui_draw_but_WAVEFORM(region, but, &tui->wcol_regular, rect);
5039 break;
5040
5042 ui_draw_but_VECTORSCOPE(region, but, &tui->wcol_regular, rect);
5043 break;
5044
5045 case UI_BTYPE_CURVE:
5046 ui_draw_but_CURVE(region, but, &tui->wcol_regular, rect);
5047 break;
5048
5050 ui_draw_but_CURVEPROFILE(region, but, &tui->wcol_regular, rect);
5051 break;
5052
5053 case UI_BTYPE_PROGRESS:
5055 break;
5056
5057 case UI_BTYPE_VIEW_ITEM:
5059 break;
5060
5061 case UI_BTYPE_SCROLL:
5063 break;
5064
5065 case UI_BTYPE_GRIP:
5067 break;
5068
5070 ui_draw_but_TRACKPREVIEW(region, but, &tui->wcol_regular, rect);
5071 break;
5072
5075 break;
5076
5077 default:
5079 break;
5080 }
5081 }
5082
5083 if (wt == nullptr) {
5084 return;
5085 }
5086
5087 // rcti disablerect = *rect; /* rect gets clipped smaller for text */
5088
5089 const int roundboxalign = widget_roundbox_set(but, rect);
5090
5092 state.but_flag = but->flag;
5093 state.but_drawflag = but->drawflag;
5094
5095 /* Override selected flag for drawing. */
5096 if (but->flag & UI_SELECT_DRAW) {
5097 state.but_flag |= UI_SELECT;
5098 }
5099
5100 if ((but->editstr) ||
5102 {
5103 state.is_text_input = true;
5104 }
5105
5106 if (but->hold_func) {
5107 state.has_hold_action = true;
5108 }
5109
5110 bool use_alpha_blend = false;
5111 if (but->emboss != UI_EMBOSS_PULLDOWN) {
5113 use_alpha_blend = true;
5115 }
5116 }
5117
5118#ifdef USE_UI_POPOVER_ONCE
5119 if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
5120 if ((but->flag & UI_HOVER) && ui_but_is_popover_once_compat(but)) {
5121 state.but_flag |= UI_BUT_ACTIVE_DEFAULT;
5122 }
5123 }
5124#endif
5126 state.but_flag &= ~UI_BUT_OVERRIDDEN;
5127 }
5128
5129 if (state.but_drawflag & UI_BUT_INDETERMINATE) {
5130 state.but_flag &= ~UI_SELECT;
5131 }
5132
5133 const float zoom = 1.0f / but->block->aspect;
5134 wt->state(wt, &state, but->emboss);
5135 if (wt->custom) {
5136 wt->custom(but, &wt->wcol, rect, &state, roundboxalign, zoom);
5137 }
5138 else if (wt->draw) {
5139 wt->draw(&wt->wcol, rect, &state, roundboxalign, zoom);
5140 }
5141
5142 if (wt->text) {
5143 if (use_alpha_blend) {
5145 }
5146
5147 if (but->type == UI_BTYPE_LABEL && !(but->flag & UI_HAS_ICON) && but->col[3] != 0) {
5148 /* Optionally use button color for text color if label without icon.
5149 * For example, ensuring that the Splash version text is always white. */
5150 copy_v4_v4_uchar(wt->wcol.text, but->col);
5151 }
5152
5153 wt->text(fstyle, &wt->wcol, but, rect);
5154 if (use_alpha_blend) {
5156 }
5157 }
5158}
5159
5160static void ui_draw_clip_tri(uiBlock *block, const rcti *rect, uiWidgetType *wt)
5161{
5162 if (block) {
5163 float draw_color[4];
5164 const uchar *color = wt->wcol.text;
5165
5166 draw_color[0] = float(color[0]) / 255.0f;
5167 draw_color[1] = float(color[1]) / 255.0f;
5168 draw_color[2] = float(color[2]) / 255.0f;
5169 draw_color[3] = 1.0f;
5170
5171 if (block->flag & UI_BLOCK_CLIPTOP) {
5172 /* XXX no scaling for UI here yet */
5173 UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 6 * UI_SCALE_FAC, 't', draw_color);
5174 }
5175 if (block->flag & UI_BLOCK_CLIPBOTTOM) {
5176 /* XXX no scaling for UI here yet */
5177 UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10 * UI_SCALE_FAC, 'v', draw_color);
5178 }
5179 }
5180}
5181
5182void ui_draw_menu_back(uiStyle * /*style*/, uiBlock *block, const rcti *rect)
5183{
5185
5187 if (block) {
5188 const float zoom = 1.0f / block->aspect;
5189 wt->draw_block(&wt->wcol, rect, block->flag, block->direction, zoom);
5190 }
5191 else {
5192 wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
5193 }
5194
5195 ui_draw_clip_tri(block, rect, wt);
5196}
5197
5203 const rcti *rect,
5204 int direction,
5205 const float unit_size,
5206 const float mval_origin[2])
5207{
5208 /* Alas, this isn't nice. */
5209 const float unit_half = unit_size / 2;
5210 const float cent_x = mval_origin ? std::clamp(mval_origin[0],
5211 rect->xmin + unit_size,
5212 rect->xmax - unit_size) :
5213 BLI_rcti_cent_x(rect);
5214
5216
5217 /* Extracted from 'widget_menu_back', keep separate to avoid menu changes breaking popovers */
5218 {
5219 uiWidgetBase wtb;
5220 widget_init(&wtb);
5221
5222 const int roundboxalign = UI_CNR_ALL;
5223 widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
5224
5225 round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
5226 wtb.draw_emboss = false;
5227 widgetbase_draw(&wtb, wcol);
5228 }
5229
5230 /* Draw popover arrow (top/bottom) */
5231 if (ELEM(direction, UI_DIR_UP, UI_DIR_DOWN)) {
5235
5236 const bool is_down = (direction == UI_DIR_DOWN);
5237 const int sign = is_down ? 1 : -1;
5238 float y = is_down ? rect->ymax : rect->ymin;
5239
5243 immVertex2f(pos, cent_x - unit_half, y);
5244 immVertex2f(pos, cent_x + unit_half, y);
5245 immVertex2f(pos, cent_x, y + sign * unit_half);
5246 immEnd();
5247
5248 y = y - sign * round(U.pixelsize * 1.41);
5249
5252 immUniformColor4ub(0, 0, 0, 0);
5253 immVertex2f(pos, cent_x - unit_half, y);
5254 immVertex2f(pos, cent_x + unit_half, y);
5255 immVertex2f(pos, cent_x, y + sign * unit_half);
5256 immEnd();
5257
5261 immVertex2f(pos, cent_x - unit_half, y);
5262 immVertex2f(pos, cent_x + unit_half, y);
5263 immVertex2f(pos, cent_x, y + sign * unit_half);
5264 immEnd();
5265
5267 }
5268
5270}
5271
5272void ui_draw_popover_back(ARegion *region, uiStyle * /*style*/, uiBlock *block, const rcti *rect)
5273{
5275
5276 float mval_origin[2] = {float(block->bounds_offset[0]), float(block->bounds_offset[1])};
5277 ui_window_to_block_fl(region, block, &mval_origin[0], &mval_origin[1]);
5279 wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin);
5280
5281 ui_draw_clip_tri(block, rect, wt);
5282}
5283
5284static void draw_disk_shaded(float start,
5285 float angle,
5286 float radius_int,
5287 float radius_ext,
5288 int subd,
5289 const uchar col1[4],
5290 const uchar col2[4],
5291 bool shaded)
5292{
5293 const float radius_ext_scale = (0.5f / radius_ext); /* 1 / (2 * radius_ext) */
5294
5295 uint col;
5298 if (shaded) {
5301 }
5302 else {
5304 immUniformColor4ubv(col1);
5305 }
5306
5307 immBegin(GPU_PRIM_TRI_STRIP, subd * 2);
5308 for (int i = 0; i < subd; i++) {
5309 const float a = start + ((i) / float(subd - 1)) * angle;
5310 const float s = sinf(a);
5311 const float c = cosf(a);
5312 const float y1 = s * radius_int;
5313 const float y2 = s * radius_ext;
5314
5315 if (shaded) {
5316 uchar r_col[4];
5317 const float fac = (y1 + radius_ext) * radius_ext_scale;
5318 color_blend_v4_v4v4(r_col, col1, col2, fac);
5319 immAttr4ubv(col, r_col);
5320 }
5321 immVertex2f(pos, c * radius_int, s * radius_int);
5322
5323 if (shaded) {
5324 uchar r_col[4];
5325 const float fac = (y2 + radius_ext) * radius_ext_scale;
5326 color_blend_v4_v4v4(r_col, col1, col2, fac);
5327 immAttr4ubv(col, r_col);
5328 }
5329 immVertex2f(pos, c * radius_ext, s * radius_ext);
5330 }
5331 immEnd();
5332
5334}
5335
5337{
5338 bTheme *btheme = UI_GetTheme();
5339 const float cx = block->pie_data.pie_center_spawned[0];
5340 const float cy = block->pie_data.pie_center_spawned[1];
5341
5342 const float *pie_dir = block->pie_data.pie_dir;
5343
5344 const float pie_radius_internal = UI_SCALE_FAC * U.pie_menu_threshold;
5345 const float pie_radius_external = UI_SCALE_FAC * (U.pie_menu_threshold + 7.0f);
5346
5347 const int subd = 40;
5348
5349 const float angle = atan2f(pie_dir[1], pie_dir[0]);
5350 /* Use a smaller range if there are both axis aligned & diagonal buttons. */
5351 const bool has_aligned = (block->pie_data.pie_dir_mask & UI_RADIAL_MASK_ALL_AXIS_ALIGNED) != 0;
5352 const bool has_diagonal = (block->pie_data.pie_dir_mask & UI_RADIAL_MASK_ALL_DIAGONAL) != 0;
5353 const float range = (has_aligned && has_diagonal) ? M_PI_4 : M_PI_2;
5354
5357
5359 if (btheme->tui.wcol_pie_menu.shaded) {
5360 uchar col1[4], col2[4];
5362 btheme->tui.wcol_pie_menu.shadetop,
5363 btheme->tui.wcol_pie_menu.shadedown,
5364 col1,
5365 col2);
5367 0.0f, float(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true);
5368 }
5369 else {
5370 draw_disk_shaded(0.0f,
5371 float(M_PI * 2.0),
5372 pie_radius_internal,
5373 pie_radius_external,
5374 subd,
5375 btheme->tui.wcol_pie_menu.inner,
5376 nullptr,
5377 false);
5378 }
5379
5380 if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) {
5381 if (btheme->tui.wcol_pie_menu.shaded) {
5382 uchar col1[4], col2[4];
5384 btheme->tui.wcol_pie_menu.shadetop,
5385 btheme->tui.wcol_pie_menu.shadedown,
5386 col1,
5387 col2);
5388 draw_disk_shaded(angle - range / 2.0f,
5389 range,
5390 pie_radius_internal,
5391 pie_radius_external,
5392 subd,
5393 col1,
5394 col2,
5395 true);
5396 }
5397 else {
5398 draw_disk_shaded(angle - range / 2.0f,
5399 range,
5400 pie_radius_internal,
5401 pie_radius_external,
5402 subd,
5403 btheme->tui.wcol_pie_menu.inner_sel,
5404 nullptr,
5405 false);
5406 }
5407 }
5408
5413
5414 imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_internal, subd);
5415 imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_external, subd);
5416
5418
5419 if (U.pie_menu_confirm > 0 &&
5421 {
5422 const float pie_confirm_radius = UI_SCALE_FAC * (pie_radius_internal + U.pie_menu_confirm);
5423 const float pie_confirm_external = UI_SCALE_FAC *
5424 (pie_radius_internal + U.pie_menu_confirm + 7.0f);
5425
5426 const uchar col[4] = {UNPACK3(btheme->tui.wcol_pie_menu.text_sel), 64};
5427 draw_disk_shaded(angle - range / 2.0f,
5428 range,
5429 pie_confirm_radius,
5430 pie_confirm_external,
5431 subd,
5432 col,
5433 nullptr,
5434 false);
5435 }
5436
5439}
5440
5446
5451 bool use_shadow,
5452 const rcti *rect,
5453 const float color[4])
5454{
5455 uiWidgetType *wt = widget_type(type);
5456
5457 if (use_shadow) {
5458 widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit);
5459 }
5460
5462 if (color) {
5463 rgba_float_to_uchar(wt->wcol.inner, color);
5464 }
5465
5466 if (wt->draw_block) {
5467 wt->draw_block(&wt->wcol, rect, 0, UI_CNR_ALL, 1.0f);
5468 }
5469 else if (wt->draw) {
5470 rcti rect_copy = *rect;
5471 wt->draw(&wt->wcol, &rect_copy, &STATE_INFO_NULL, UI_CNR_ALL, 1.0f);
5472 }
5473 else {
5475 }
5476}
5477void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
5478{
5479 ui_draw_widget_back_color(UI_WTYPE_MENU_BACK, use_shadow, rect, color);
5480}
5481
5482void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow)
5483{
5484 ui_draw_widget_back_color(UI_WTYPE_MENU_BACK, use_shadow, rect, nullptr);
5485}
5486
5487void ui_draw_tooltip_background(const uiStyle * /*style*/, uiBlock * /*block*/, const rcti *rect)
5488{
5491 /* wt->draw_block ends up using same function to draw the tooltip as menu_back */
5492 wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
5493}
5494
5496 rcti *rect,
5497 const char *name,
5498 int iconid,
5499 int but_flag,
5500 uiMenuItemSeparatorType separator_type,
5501 int *r_xmax)
5502{
5504 const rcti _rect = *rect;
5505 const int row_height = BLI_rcti_size_y(rect);
5506 int max_hint_width = INT_MAX;
5507 int padding = 0.25f * row_height;
5508 char *cpoin = nullptr;
5509
5511 state.but_flag = but_flag;
5512
5513 wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
5514 wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
5515
5516 UI_fontstyle_set(fstyle);
5517
5518 /* text location offset */
5519 rect->xmin += padding;
5520 if (iconid) {
5521 rect->xmin += row_height; /* Use square area for icon. */
5522 }
5523
5524 /* cut string in 2 parts? */
5525 if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
5526 cpoin = const_cast<char *>(strrchr(name, UI_SEP_CHAR));
5527 if (cpoin) {
5528 *cpoin = 0;
5529
5530 /* need to set this first */
5531 UI_fontstyle_set(fstyle);
5532
5533 if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) {
5534 /* Shrink rect to exclude the shortcut string. */
5535 rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_ICON_SIZE;
5536 }
5537 else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) {
5538 /* Determine max-width for the hint string to leave the name string un-clipped (if there's
5539 * enough space to display it). */
5540
5541 const int available_width = BLI_rcti_size_x(rect) - padding;
5542 const int name_width = BLF_width(fstyle->uifont_id, name, INT_MAX);
5543 const int hint_width = BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + padding;
5544
5545 if ((name_width + hint_width) > available_width) {
5546 /* Clipping width for hint string. */
5547 max_hint_width = available_width * 0.40f;
5548 /* Clipping xmax for clipping of item name. */
5549 rect->xmax = (hint_width < max_hint_width) ?
5550 (rect->xmax - hint_width) :
5551 (rect->xmin + (available_width - max_hint_width));
5552 }
5553 }
5554 else {
5555 BLI_assert_msg(0, "Unknown menu item separator type");
5556 }
5557 }
5558 }
5559
5560 {
5561 char drawstr[UI_MAX_DRAW_STR];
5562 const float okwidth = float(BLI_rcti_size_x(rect));
5563 const size_t max_len = sizeof(drawstr);
5564 const float minwidth = float(UI_ICON_SIZE);
5565
5566 STRNCPY(drawstr, name);
5567 if (drawstr[0]) {
5568 UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
5569 }
5570
5571 int xofs = 0, yofs = 0;
5572 ResultBLF info;
5574 params.align = UI_STYLE_TEXT_LEFT;
5576 fstyle, rect, drawstr, sizeof(drawstr), wt->wcol.text, &params, &xofs, &yofs, &info);
5577 if (r_xmax != nullptr) {
5578 *r_xmax = xofs + info.width;
5579 }
5580 }
5581
5582 /* restore rect, was messed with */
5583 *rect = _rect;
5584
5585 if (iconid) {
5586 float height, aspect;
5587 const int xs = rect->xmin + 0.2f * UI_UNIT_X;
5588 const int ys = rect->ymin + 0.1f * BLI_rcti_size_y(rect);
5589
5590 height = ICON_SIZE_FROM_BUTRECT(rect);
5591 aspect = ICON_DEFAULT_HEIGHT / height;
5592
5594 /* XXX scale weak get from fstyle? */
5596 xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT);
5598 }
5599
5600 /* part text right aligned */
5601 if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
5602 if (cpoin) {
5603 /* State info for the hint drawing. */
5604 uiWidgetStateInfo hint_state = state;
5605 /* Set inactive state for grayed out text. */
5606 hint_state.but_flag |= UI_BUT_INACTIVE;
5607
5608 wt->state(wt, &hint_state, UI_EMBOSS_UNDEFINED);
5609
5610 char hint_drawstr[UI_MAX_DRAW_STR];
5611 {
5612 const size_t max_len = sizeof(hint_drawstr);
5613 const float minwidth = float(UI_ICON_SIZE);
5614
5615 STRNCPY(hint_drawstr, cpoin + 1);
5616 if (hint_drawstr[0] && (max_hint_width < INT_MAX)) {
5617 UI_text_clip_middle_ex(fstyle, hint_drawstr, max_hint_width, minwidth, max_len, '\0');
5618 }
5619 }
5620
5621 rect->xmax = _rect.xmax - 5;
5624 UI_fontstyle_draw(fstyle, rect, hint_drawstr, sizeof(hint_drawstr), wt->wcol.text, &params);
5625 *cpoin = UI_SEP_CHAR;
5626 }
5627 }
5628}
5629
5631 rcti *rect,
5632 const blender::StringRef name,
5633 int iconid,
5634 const uchar text_col[4],
5635 eFontStyle_Align text_align,
5636 bool draw_as_icon)
5637{
5638 rcti trect = *rect;
5639 const float text_size = UI_UNIT_Y;
5640 const bool has_text = !name.is_empty();
5641
5642 float alpha = 1.0f;
5643
5644 {
5645 /* Special handling: Previews often want to show a loading icon while the preview is being
5646 * loaded. Draw this with reduced opacity. */
5647 const bool is_loading_icon = iconid == ICON_TEMP;
5648 if (is_loading_icon) {
5649 alpha *= 0.5f;
5650 draw_as_icon = true;
5651 }
5652 }
5653
5654 if (has_text) {
5655 /* draw icon in rect above the space reserved for the label */
5656 rect->ymin += text_size;
5657 }
5659 if (draw_as_icon) {
5660 widget_draw_icon_centered(iconid, 1.0f, alpha, rect, text_col);
5661 }
5662 else {
5663 widget_draw_preview(iconid, alpha, rect);
5664 }
5666
5667 if (!has_text) {
5668 return;
5669 }
5670
5671 /* text rect */
5672 trect.ymax = trect.ymin + text_size;
5673 trect.ymin += PREVIEW_PAD;
5674 trect.xmin += PREVIEW_PAD;
5675 trect.xmax -= PREVIEW_PAD;
5676
5677 {
5678 char drawstr[UI_MAX_DRAW_STR];
5679 const float okwidth = float(BLI_rcti_size_x(&trect));
5680 const size_t max_len = sizeof(drawstr);
5681 const float minwidth = float(UI_ICON_SIZE);
5682
5683 memcpy(drawstr, name.data(), name.size());
5684 drawstr[name.size()] = '\0';
5685 UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
5686
5688 params.align = text_align;
5689 UI_fontstyle_draw(fstyle, &trect, drawstr, sizeof(drawstr), text_col, &params);
5690 }
5691}
5692
5694 rcti *rect,
5695 const char *name,
5696 int iconid,
5697 int but_flag,
5698 eFontStyle_Align text_align)
5699{
5701
5703 state.but_flag = but_flag;
5704
5705 /* drawing button background */
5706 wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
5707 wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
5708
5709 ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
5710}
5711
size_t BLF_width_to_strlen(int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:717
blender::Vector< blender::Bounds< int > > BLF_str_selection_boxes(int fontid, const char *str, size_t str_len, size_t sel_start, size_t sel_length)
Definition blf.cc:707
bool int BLF_str_offset_to_cursor(int fontid, const char *str, size_t str_len, size_t str_offset, int cursor_width)
Definition blf.cc:694
bool BLF_str_offset_to_glyph_bounds(int fontid, const char *str, size_t str_offset, rcti *r_glyph_bounds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2
void BLF_disable(int fontid, int option)
Definition blf.cc:321
void BLF_draw(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:568
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:791
@ BLF_SHADOW
Definition BLF_api.hh:363
void BLF_color4ubv(int fontid, const unsigned char rgba[4])
Definition blf.cc:435
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:371
size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:739
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define ATTR_NONNULL(...)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE float cube_f(float a)
#define M_PI_2
MINLINE float pow3f(float x)
#define M_PI
#define M_PI_4
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
#define rgba_float_args_set_ch(col, r, g, b, a)
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3])
MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3])
MINLINE float rgb_to_grayscale(const float rgb[3])
void hsl_to_rgb_v(const float hsl[3], float r_rgb[3])
Definition math_color.cc:62
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b)
Definition math_color.cc:21
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3_uchar(unsigned char target[3], const unsigned char a[3], const unsigned char b[3], float t)
MINLINE void add_v3_uchar_clamped(uchar r[3], int i)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE float BLI_rcti_cent_x_fl(const struct rcti *rct)
Definition BLI_rect.h:164
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y)
Definition rct.c:623
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.c:560
void BLI_rcti_resize_y(struct rcti *rect, int y)
Definition rct.c:609
void BLI_rctf_scale(rctf *rect, float scale)
Definition rct.c:671
void BLI_rcti_resize(struct rcti *rect, int x, int y)
Definition rct.c:615
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.c:408
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y)
Definition rct.c:631
BLI_INLINE float BLI_rcti_cent_y_fl(const struct rcti *rct)
Definition BLI_rect.h:168
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:176
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
void BLI_rcti_resize_x(struct rcti *rect, int x)
Definition rct.c:603
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
bool BLI_rcti_is_empty(const struct rcti *rect)
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:172
#define STRNCPY(dst, src)
Definition BLI_string.h:593
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
const char const char * BLI_str_find_next_char_utf8(const char *p, const char *str_end) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
const char * BLI_str_find_prev_char_utf8(const char *p, const char *str_start) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1
#define BLI_STR_UTF8_HORIZONTAL_ELLIPSIS
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
void rect_copy(int dst[2][2], int src[2][2])
Definition Basic.c:33
@ USER_CP_CIRCLE_HSV
#define UI_SCALE_FAC
#define UI_INV_SCALE_FAC
#define UI_ICON_SIZE
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
void GPU_batch_draw_instance_range(blender::gpu::Batch *batch, int instance_first, int instance_count)
#define GPU_batch_uniform_4fv_array(batch, name, len, val)
Definition GPU_batch.hh:310
#define GPU_batch_uniform_3fv(batch, name, val)
Definition GPU_batch.hh:306
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, eGPUBuiltinShader shader_id)
void GPU_batch_draw(blender::gpu::Batch *batch)
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:51
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
void gpu_batch_presets_register(blender::gpu::Batch *preset_batch)
void immUniformColor4ubv(const unsigned char rgba[4])
void immUniform4f(const char *name, float x, float y, float z, float w)
void immEnd()
void immUnbindProgram()
void immAttr4ubv(uint attr_id, const unsigned char data[4])
void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b)
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColor(int color_id)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immVertex2fv(uint attr_id, const float data[2])
void immUniformColor3ubv(const unsigned char rgb[3])
void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a)
void immUniform1f(const char *name, float x)
void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
GPUVertFormat * immVertexFormat()
void immAttr4f(uint attr_id, float x, float y, float z, float w)
void immUniformColor4fv(const float rgba[4])
void immUniformColor3f(float r, float g, float b)
void immAttr3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fv(const float rgb[3])
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
void immRecti(uint pos, int x1, int y1, int x2, int y2)
void imm_draw_disk_partial_fill_2d(uint pos, float x, float y, float rad_inner, float rad_outer, int nsegments, float start, float sweep)
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3)
void GPU_matrix_push()
void GPU_matrix_pop()
void GPU_matrix_translate_2f(float x, float y)
GPUPrimType
@ GPU_PRIM_TRI_FAN
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRI_STRIP
@ GPU_PRIM_TRIS
@ GPU_SHADER_3D_SMOOTH_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_2D_WIDGET_BASE_INST
@ GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA
@ GPU_SHADER_2D_WIDGET_BASE
void GPU_program_point_size(bool enable)
Definition gpu_state.cc:175
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:161
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
void GPU_vertbuf_attr_get_raw_data(blender::gpu::VertBuf *, uint a_idx, GPUVertBufRaw *access)
GPU_INLINE void * GPU_vertbuf_raw_step(GPUVertBufRaw *a)
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
@ GPU_FETCH_INT_TO_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_U32
@ GPU_COMP_U8
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its red
PropertyScaleType
Definition RNA_types.hh:106
@ PROP_SCALE_LOG
Definition RNA_types.hh:113
@ PROP_SCALE_LINEAR
Definition RNA_types.hh:108
@ PROP_SCALE_CUBIC
Definition RNA_types.hh:118
@ PROP_PERCENTAGE
Definition RNA_types.hh:153
#define UI_ALPHA_CHECKER_LIGHT
#define UI_UNIT_Y
void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float col[4])
void ui_draw_dropshadow(const rctf *rct, float radius, float width, float aspect, float alpha)
eUIEmbossType
@ UI_EMBOSS_UNDEFINED
@ UI_EMBOSS_NONE
@ UI_EMBOSS_PIE_MENU
@ UI_EMBOSS
@ UI_EMBOSS_PULLDOWN
@ UI_EMBOSS_NONE_OR_STATUS
@ UI_BLOCK_CLIPBOTTOM
@ UI_BLOCK_POPOVER_ONCE
@ UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE
@ UI_BLOCK_POPUP
@ UI_BLOCK_CLIPTOP
@ UI_BLOCK_POPOVER
@ UI_SCROLL_PRESSED
@ UI_SCROLL_ARROWS
#define UI_SEP_CHAR
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4])
void UI_draw_roundbox_4fv_ex(const rctf *rect, const float inner1[4], const float inner2[4], float shade_dir, const float outline[4], float outline_width, float rad)
#define UI_ALPHA_CHECKER_DARK
@ UI_BUT_PROGRESS_TYPE_BAR
@ UI_BUT_PROGRESS_TYPE_RING
void UI_draw_roundbox_corner_set(int type)
void UI_fontstyle_draw_ex(const uiFontStyle *fs, const rcti *rect, const char *str, size_t str_len, const uchar col[4], const uiFontStyleDraw_Params *fs_params, int *r_xofs, int *r_yofs, ResultBLF *r_info)
eFontStyle_Align
@ UI_STYLE_TEXT_LEFT
@ UI_STYLE_TEXT_CENTER
@ UI_STYLE_TEXT_RIGHT
const uiStyle * UI_style_get()
void UI_fontstyle_set(const uiFontStyle *fs)
#define UI_MAX_DRAW_STR
#define UI_VALUE_INDETERMINATE_CHAR
@ UI_DIR_DOWN
@ UI_DIR_RIGHT
@ UI_DIR_LEFT
@ UI_DIR_UP
void UI_but_drawflag_disable(uiBut *but, int flag)
@ UI_BLOCK_THEME_STYLE_POPUP
eButGradientType
@ UI_GRAD_L_ALT
@ UI_GRAD_SV
@ UI_GRAD_V_ALT
@ UI_GRAD_S
@ UI_GRAD_HV
@ UI_GRAD_HS
@ UI_GRAD_V
@ UI_GRAD_H
@ UI_GRAD_NONE
void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str, size_t str_len, const uchar col[4], const uiFontStyleDraw_Params *fs_params)
@ UI_CNR_BOTTOM_LEFT
@ UI_CNR_BOTTOM_RIGHT
@ UI_CNR_ALL
@ UI_CNR_TOP_LEFT
@ UI_CNR_TOP_RIGHT
#define UI_UNIT_X
@ UI_BTYPE_BUT
@ UI_BTYPE_TOGGLE
@ UI_BTYPE_PROGRESS
@ UI_BTYPE_EXTRA
@ UI_BTYPE_TAB
@ UI_BTYPE_LISTBOX
@ UI_BTYPE_VECTORSCOPE
@ UI_BTYPE_SEPR_SPACER
@ UI_BTYPE_NODE_SOCKET
@ UI_BTYPE_ROUNDBOX
@ UI_BTYPE_COLORBAND
@ UI_BTYPE_BUT_MENU
@ UI_BTYPE_TOGGLE_N
@ UI_BTYPE_HISTOGRAM
@ UI_BTYPE_WAVEFORM
@ UI_BTYPE_BLOCK
@ UI_BTYPE_NUM_SLIDER
@ UI_BTYPE_HSVCIRCLE
@ UI_BTYPE_LISTROW
@ UI_BTYPE_TEXT
@ UI_BTYPE_BUT_TOGGLE
@ UI_BTYPE_VIEW_ITEM
@ UI_BTYPE_HSVCUBE
@ UI_BTYPE_PREVIEW_TILE
@ UI_BTYPE_LABEL
@ UI_BTYPE_CURVE
@ UI_BTYPE_DECORATOR
@ UI_BTYPE_ROW
@ UI_BTYPE_SEARCH_MENU
@ UI_BTYPE_UNITVEC
@ UI_BTYPE_SEPR_LINE
@ UI_BTYPE_POPOVER
@ UI_BTYPE_CHECKBOX_N
@ UI_BTYPE_SEPR
@ UI_BTYPE_NUM
@ UI_BTYPE_PULLDOWN
@ UI_BTYPE_CURVEPROFILE
@ UI_BTYPE_TRACK_PREVIEW
@ UI_BTYPE_COLOR
@ UI_BTYPE_CHECKBOX
@ UI_BTYPE_GRIP
@ UI_BTYPE_MENU
@ UI_BTYPE_IMAGE
@ UI_BTYPE_SCROLL
bool UI_but_is_tool(const uiBut *but)
@ UI_BUT_TEXT_RIGHT
@ UI_BUT_ICON_LEFT
@ UI_BUT_INDETERMINATE
@ UI_BUT_ICON_INVERT
@ UI_BUT_ALIGN_DOWN
@ UI_BUT_ALIGN_TOP
@ UI_BUT_ALIGN
@ UI_BUT_NO_TEXT_PADDING
@ UI_BUT_HOVER_RIGHT
@ UI_BUT_ALIGN_STITCH_TOP
@ UI_BUT_HOVER_LEFT
@ UI_BUT_ANIMATED_CHANGED
@ UI_BUT_TEXT_LEFT
@ UI_BUT_BOX_ITEM
@ UI_BUT_ALIGN_STITCH_LEFT
@ UI_BUT_ALIGN_RIGHT
@ UI_BUT_ALIGN_LEFT
@ UI_BUT_LIST_ITEM
@ UI_BUT_REDALERT
@ UI_BUT_ACTIVE_DEFAULT
@ UI_BUT_ANIMATED
@ UI_BUT_DISABLED
@ UI_BUT_INACTIVE
@ UI_BUT_OVERRIDDEN
@ UI_BUT_HAS_SEP_CHAR
@ UI_BUT_NODE_LINK
@ UI_BUT_ICON_PREVIEW
@ UI_BUT_NODE_ACTIVE
@ UI_BUT_DRIVEN
@ UI_BUT_DRAG_MULTI
@ UI_BUT_ICON_SUBMENU
@ UI_BUT_ANIMATED_KEY
#define ICON_DEFAULT_HEIGHT
#define ICON_DEFAULT_HEIGHT_TOOLBAR
bool UI_icon_get_theme_color(int icon_id, unsigned char color[4])
#define UI_NO_ICON_OVERLAY_TEXT
void UI_icon_draw_ex(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const uchar mono_color[4], bool mono_border, const IconTextOverlay *text_overlay, const bool inverted=false)
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size)
#define ICON_DEFAULT_WIDTH
@ TH_BACK
@ TH_WIDGET_EMBOSS
@ TH_WIDGET_TEXT_CURSOR
@ TH_TEXT
@ TH_TEXT_HI
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
void UI_GetThemeColor4fv(int colorid, float col[4])
bTheme * UI_GetTheme()
int BIFIconID
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
int UI_ThemeMenuShadowWidth()
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
btVector3 m_delta
Definition half.h:42
#define logf(x)
#define sinf(x)
#define cosf(x)
#define atan2f(x, y)
#define fmaxf(x, y)
#define ceilf(x)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
static float verts[][3]
struct @620::@622 batch
uint col
uint padding(uint offset, uint alignment)
uiBut * ui_but_drag_multi_edit_get(uiBut *but)
PropertyScaleType ui_but_scale_type(const uiBut *but)
const char * ui_but_placeholder_get(uiBut *but)
double ui_but_value_get(uiBut *but)
void ui_window_to_block_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
Definition interface.cc:184
void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3])
bool ui_but_menu_draw_as_popover(const uiBut *but)
void ui_but_v3_get(uiBut *but, float vec[3])
bool ui_but_drag_is_draggable(const uiBut *but)
void ui_draw_but_HISTOGRAM(ARegion *, uiBut *but, const uiWidgetColors *, const rcti *recti)
void ui_draw_but_TRACKPREVIEW(ARegion *, uiBut *but, const uiWidgetColors *, const rcti *recti)
void ui_draw_but_IMAGE(ARegion *, uiBut *but, const uiWidgetColors *, const rcti *rect)
void ui_draw_but_WAVEFORM(ARegion *, uiBut *but, const uiWidgetColors *, const rcti *recti)
void ui_draw_but_VECTORSCOPE(ARegion *, uiBut *but, const uiWidgetColors *, const rcti *recti)
void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rect, const float radius)
void ui_draw_but_CURVEPROFILE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
void ui_draw_but_TAB_outline(const rcti *rect, float rad, uchar highlight[3], uchar highlight_fade[3])
void ui_draw_but_COLORBAND(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
int ui_but_menu_direction(uiBut *but)
void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *but, const bool restore)
void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3])
void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3])
#define UI_MENU_SUBMENU_PADDING
bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
#define UI_RADIAL_MASK_ALL_DIAGONAL
#define UI_RADIAL_MASK_ALL_AXIS_ALIGNED
@ UI_PIE_INVALID_DIR
@ UI_PIE_CLICK_STYLE
void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3])
#define UI_TEXT_MARGIN_X
bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3])
@ UI_BLOCK_CONTAINS_SUBMENU_BUT
@ UI_SELECT_DRAW
@ UI_HOVER
@ UI_HAS_ICON
@ UI_SELECT
@ UI_SEARCH_FILTER_NO_MATCH
int ui_but_icon(const uiBut *but)
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT
bool ui_but_is_color_gamma(uiBut *but)
#define UI_PIXEL_AA_JITTER
uiMenuItemSeparatorType
@ UI_MENU_ITEM_SEPARATOR_NONE
@ UI_MENU_ITEM_SEPARATOR_HINT
@ UI_MENU_ITEM_SEPARATOR_SHORTCUT
@ ROUNDBOX_TRIA_CHECK
@ ROUNDBOX_TRIA_DASH
@ ROUNDBOX_TRIA_SCROLL
@ ROUNDBOX_TRIA_MENU
@ ROUNDBOX_TRIA_ARROWS
@ ROUNDBOX_TRIA_NONE
@ ROUNDBOX_TRIA_HOLD_ACTION_ARROW
const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2]
static void color_blend_v3_v3(uchar cp[3], const uchar cpstate[3], const float fac)
static void widget_numbut_draw(const uiBut *but, uiWidgetColors *wcol, rcti *rect, const float zoom, const uiWidgetStateInfo *state, int roundboxalign, bool emboss)
static void ui_draw_clip_tri(uiBlock *block, const rcti *rect, uiWidgetType *wt)
static void widget_state_option_menu(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType emboss)
static void shape_preset_trias_from_rect_dash(uiWidgetTrias *tria, const rcti *rect)
static void widget_roundbut_exec(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void widget_draw_vertex_buffer(uint pos, uint col, GPUPrimType mode, const float quads_pos[WIDGET_SIZE_MAX][2], const uchar quads_col[WIDGET_SIZE_MAX][4], uint totvert)
void ui_draw_tooltip_background(const uiStyle *, uiBlock *, const rcti *rect)
static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int, const float zoom)
static void widget_numbut(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static const float g_shape_preset_hold_action_vert[6][2]
static const uint g_shape_preset_scroll_circle_face[14][3]
GPUVertFormat format
static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
static const float g_shape_preset_number_arrow_vert[3][2]
static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
static int ui_but_draw_menu_icon(const uiBut *but)
static void widgetbase_set_uniform_discard_factor(uiWidgetBase *wtb, const float discard_factor)
static void shape_preset_init_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void ui_widget_color_disabled(uiWidgetType *wt, const uiWidgetStateInfo *state)
static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
static void widget_unitvec(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int, const float zoom)
static void draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
#define INNER
static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int roundboxalign, const float zoom)
const uiWidgetColors * ui_tooltip_get_theme()
static const float cornervec[WIDGET_CURVE_RESOLU][2]
static void widget_state_pulldown(uiWidgetType *wt, const uiWidgetStateInfo *, eUIEmbossType)
static void ui_text_clip_right_ex(const uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth, const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
static void widget_nodesocket(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int, const float)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static void widget_state_nothing(uiWidgetType *wt, const uiWidgetStateInfo *, eUIEmbossType)
static void widget_progress_type_ring(uiButProgress *but_progress, uiWidgetColors *wcol, rcti *rect)
static const uint g_shape_preset_checkmark_face[4][3]
static void widgetbase_set_uniform_alpha_discard(uiWidgetBase *wtb, const bool alpha_check, const float discard_factor)
static void widget_state_menu_item(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType)
static void ui_text_clip_right_label(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
void ui_hsvcircle_pos_from_vals(const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *r_xpos, float *r_ypos)
static const GPUVertFormat & vflag_format()
static void widget_draw_extra_icons(const uiWidgetColors *wcol, uiBut *but, rcti *rect, float alpha)
static void widgetbase_outline(uiWidgetBase *wtb, uint pos)
#define UI_TEXT_CLIP_MARGIN
static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX *2+2][2])
static void color_mul_hsl_v3(uchar ch[3], float h_factor, float s_factor, float l_factor)
#define PREVIEW_PAD
static void widget_state_pie_menu_item(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType)
void ui_draw_gradient(const rcti *rect, const float hsv[3], const eButGradientType type, const float alpha)
static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
#define NUM_BUT_PADDING_FACTOR
void UI_widgetbase_draw_cache_end()
void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow)
static void draw_disk_shaded(float start, float angle, float radius_int, float radius_ext, int subd, const uchar col1[4], const uchar col2[4], bool shaded)
static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int roundboxalign, const float zoom)
static void widget_draw_text_icon(const uiFontStyle *fstyle, const uiWidgetColors *wcol, uiBut *but, rcti *rect)
static void widget_numbut_embossn(const uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
uint vflag_id
#define MAX_WIDGET_BASE_BATCH
void ui_draw_preview_item(const uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int but_flag, eFontStyle_Align text_align)
void ui_draw_popover_back(ARegion *region, uiStyle *, uiBlock *block, const rcti *rect)
static void ui_text_clip_give_next_off(uiBut *but, const char *str, const char *str_end)
void ui_hsvcube_pos_from_vals(const uiButHSVCube *hsv_but, const rcti *rect, const float *hsv, float *r_xp, float *r_yp)
static void widget_draw_icon_centered(const BIFIconID icon, const float aspect, const float alpha, const rcti *rect, const uchar mono_color[4])
static void widget_tab(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void round_box__edges(uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad, float radi)
static void widget_menubut_embossn(const uiBut *, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int)
static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wcol)
static void widget_state(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType emboss)
#define SC
static void widget_progress_indicator(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int roundboxalign, const float zoom)
uiWidgetTypeEnum
@ UI_WTYPE_SLIDER
@ UI_WTYPE_RGB_PICKER
@ UI_WTYPE_POINTER_LINK
@ UI_WTYPE_BOX
@ UI_WTYPE_MENU_ICON_RADIO
@ UI_WTYPE_SWATCH
@ UI_WTYPE_ICON_LABEL
@ UI_WTYPE_VIEW_ITEM
@ UI_WTYPE_FILENAME
@ UI_WTYPE_LABEL
@ UI_WTYPE_TOGGLE
@ UI_WTYPE_LISTITEM
@ UI_WTYPE_MENU_ITEM_PIE
@ UI_WTYPE_ICON
@ UI_WTYPE_NAME
@ UI_WTYPE_EXEC
@ UI_WTYPE_PULLDOWN
@ UI_WTYPE_NUMBER
@ UI_WTYPE_MENU_ITEM
@ UI_WTYPE_NAME_LINK
@ UI_WTYPE_TOOLTIP
@ UI_WTYPE_UNITVEC
@ UI_WTYPE_TOOLBAR_ITEM
@ UI_WTYPE_PROGRESS
@ UI_WTYPE_PREVIEW_TILE
@ UI_WTYPE_CHECKBOX
@ UI_WTYPE_RADIO
@ UI_WTYPE_MENU_BACK
@ UI_WTYPE_MENU_ITEM_UNPADDED
@ UI_WTYPE_TAB
@ UI_WTYPE_REGULAR
@ UI_WTYPE_MENU_POINTER_LINK
@ UI_WTYPE_SCROLL
@ UI_WTYPE_MENU_RADIO
@ UI_WTYPE_MENU_NODE_LINK
@ UI_WTYPE_NODESOCKET
static void widget_textbut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void color_blend_v4_v4v4(uchar r_col[4], const uchar col1[4], const uchar col2[4], const float fac)
static void shape_preset_init_number_arrows(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void widget_state_label(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType emboss)
#define OY
void ui_draw_menu_back(uiStyle *, uiBlock *block, const rcti *rect)
void ui_draw_menu_item(const uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int but_flag, uiMenuItemSeparatorType separator_type, int *r_xmax)
static void shape_preset_init_hold_action(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
static void widget_draw_node_link_socket(const uiWidgetColors *wcol, const rcti *rect, uiBut *but, float alpha)
static const uint g_shape_preset_hold_action_face[2][3]
void ui_draw_preview_item_stateless(const uiFontStyle *fstyle, rcti *rect, const blender::StringRef name, int iconid, const uchar text_col[4], eFontStyle_Align text_align, bool draw_as_icon)
static void shape_preset_trias_from_rect_menu(uiWidgetTrias *tria, const rcti *rect)
bool enabled
static float widget_radius_from_zoom(const float zoom, const uiWidgetColors *wcol)
static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
static void set_roundbox_vertex_data(GPUVertBufRaw *vflag_step, uint32_t d)
static void ui_text_clip_middle_protect_right(const uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char rsep)
static void draw_widgetbase_batch(uiWidgetBase *wtb)
static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int, const float)
static void widget_draw_submenu_tria(const uiBut *but, const rcti *rect, const uiWidgetColors *wcol)
static const float g_shape_preset_menu_arrow_vert[6][2]
#define jit
static const float g_shape_preset_checkmark_vert[6][2]
static void shape_preset_trias_from_rect_checkmark(uiWidgetTrias *tria, const rcti *rect)
static void widget_preview_tile(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void widget_progress_type_bar(uiButProgress *but_progress, uiWidgetColors *wcol, rcti *rect, int roundboxalign, const float zoom)
#define WIDGET_SIZE_MAX
static const uint g_shape_preset_number_arrow_face[1][3]
static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
static void shape_preset_init_trias_ex(uiWidgetTrias *tria, const rcti *rect, float triasize, char where, const float verts[][2], const int verts_tot, const uint tris[][3], const int tris_tot)
static void ui_draw_widget_back_color(uiWidgetTypeEnum type, bool use_shadow, const rcti *rect, const float color[4])
static struct @398 g_widget_base_batch
static void widgetbase_set_uniform_alpha_check(uiWidgetBase *wtb, const bool alpha_check)
#define ICON_SIZE_FROM_BUTRECT(rect)
static float widget_alpha_factor(const uiWidgetStateInfo *state)
blender::gpu::Batch * roundbox_shadow
void ui_hsvcircle_vals_from_pos(const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist)
static void ui_text_clip_cursor(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
static const uiWidgetStateInfo STATE_INFO_NULL
static void widgetbase_set_uniform_colors_ubv(uiWidgetBase *wtb, const uchar *col1, const uchar *col2, const uchar *outline, const uchar *emboss, const uchar *tria, const bool alpha_check)
static void widget_init(uiWidgetBase *wtb)
blender::gpu::Batch * roundbox_widget
static uiWidgetType * widget_type(uiWidgetTypeEnum type)
float UI_text_clip_middle_ex(const uiFontStyle *fstyle, char *str, float okwidth, const float minwidth, const size_t max_len, const char rpart_sep)
static void widget_menu_back(uiWidgetColors *wcol, const rcti *rect, const int block_flag, const int direction, const float zoom)
static void widget_list_itembut(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int, const float zoom)
static bool draw_emboss(const uiBut *but)
static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad)
static int widget_roundbox_set(uiBut *but, rcti *rect)
#define WIDGET_CURVE_RESOLU
static void ui_draw_popover_back_impl(const uiWidgetColors *wcol, const rcti *rect, int direction, const float unit_size, const float mval_origin[2])
static void widget_menu_itembut_unpadded(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int, const float zoom)
blender::gpu::Batch * ui_batch_roundbox_shadow_get()
int count
static struct @397 g_ui_batch_cache
static void widgetbase_draw_ex(uiWidgetBase *wtb, const uiWidgetColors *wcol, bool show_alpha_checkers)
#define MAX_WIDGET_PARAMETERS
#define NO_AA
static void ui_hsv_cursor(const float x, const float y, const float zoom, const float rgb[3], const float hsv[3], const bool is_active)
#define WIDGET_AA_JITTER
blender::gpu::Batch * ui_batch_roundbox_widget_get()
static void widget_draw_text(const uiFontStyle *fstyle, const uiWidgetColors *wcol, uiBut *but, rcti *rect)
static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const uchar mono_color[4])
static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int roundboxalign, const float zoom)
static void ui_draw_separator(const uiWidgetColors *wcol, uiBut *but, const rcti *rect)
static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
static void draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
static void shadecolors4(const uchar *color, short shadetop, short shadedown, uchar r_coltop[4], uchar r_coldown[4])
static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int contrast)
void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
static const float g_shape_preset_scroll_circle_vert[16][2]
void UI_widgetbase_draw_cache_flush()
static void widget_menu_pie_itembut(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int, const float zoom)
static void widget_active_color(uiWidgetColors *wcol)
void UI_widgetbase_draw_cache_begin()
static void widget_state_numslider(uiWidgetType *wt, const uiWidgetStateInfo *state, eUIEmbossType emboss)
static void widget_menubut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int roundboxalign, const float zoom)
static void widget_but(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int roundboxalign, const float zoom)
static const uchar * widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state, const uiWidgetStateInfo *state, const eUIEmbossType emboss)
static uint32_t set_roundbox_vertex(GPUVertBufRaw *vflag_step, int corner_id, int corner_v, int jit_v, bool inner, bool emboss, int color)
static const uint g_shape_preset_menu_arrow_face[2][3]
#define SWATCH_KEYED_BORDER
static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int, const float)
void ui_draw_pie_center(uiBlock *block)
static void ui_text_clip_middle(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
format
#define unit_float_to_uchar_clamp(val)
ccl_device_inline float2 fabs(const float2 a)
static ulong state[N]
void node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
static const int steps
#define min(a, b)
Definition sort.c:32
unsigned int uint32_t
Definition stdint.h:80
float hsv_perceptual[3]
float pie_center_spawned[2]
ID * owner_id
Definition RNA_types.hh:40
int width
Definition BLF_api.hh:410
float menu_shadow_fac
uiWidgetColors wcol_pulldown
uiWidgetColors wcol_numslider
uiWidgetColors wcol_list_item
uiWidgetColors wcol_menu
uiWidgetColors wcol_progress
uiWidgetColors wcol_menu_back
uiWidgetColors wcol_num
float icon_border_intensity
uiWidgetColors wcol_menu_item
uiWidgetColors wcol_toggle
uiWidgetColors wcol_regular
uiWidgetColors wcol_tooltip
uiWidgetColors wcol_option
uiWidgetColors wcol_text
uiWidgetColors wcol_tab
uiWidgetStateColors wcol_state
uiWidgetColors wcol_radio
uiWidgetColors wcol_scroll
uiWidgetColors wcol_pie_menu
uiWidgetColors wcol_toolbar_item
uiWidgetColors wcol_tool
float icon_saturation
uiWidgetColors wcol_box
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
PieMenuData pie_data
int bounds_offset[2]
std::function< void(const bContext *, rcti *)> drawextra
short content_hints
eButGradientType gradient_type
eButProgressType progress_type
ListBase extra_op_icons
void * custom_data
IconTextOverlay icon_overlay_text
PropertyRNA * rnaprop
char * editstr
eButType type
uiHandleButtonData * active
uiBlock * block
eUIEmbossType emboss
std::string drawstr
uiBut * next
std::string str
uiButHandleHoldFunc hold_func
BIFIconID icon
PointerRNA rnapoin
uchar col[4]
uiFontStyle widget
uiWidgetTrias tria2
float inner_v[WIDGET_SIZE_MAX][2]
float outer_v[WIDGET_SIZE_MAX][2]
uiWidgetTrias tria1
float inner_uv[WIDGET_SIZE_MAX][2]
uiWidgetBaseParameters uniform_params
unsigned char inner_sel[4]
unsigned char inner[4]
unsigned char outline[4]
unsigned char text[4]
unsigned char item[4]
unsigned char text_sel[4]
unsigned char shaded
unsigned char inner_key_sel[4]
unsigned char inner_changed_sel[4]
unsigned char inner_anim_sel[4]
unsigned char inner_driven_sel[4]
unsigned char inner_overridden_sel[4]
const uint(* index)[3]
void(* state)(uiWidgetType *, const uiWidgetStateInfo *state, eUIEmbossType emboss) ATTR_NONNULL()
uiWidgetColors wcol
void(* custom)(uiBut *, uiWidgetColors *, rcti *, const uiWidgetStateInfo *, int roundboxalign, const float zoom) ATTR_NONNULL()
const uiWidgetColors * wcol_theme
void(* text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *)
uiWidgetStateColors * wcol_state
void(* draw_block)(uiWidgetColors *, const rcti *, int block_flag, int roundboxalign, const float zoom)
void(* draw)(uiWidgetColors *, rcti *, const uiWidgetStateInfo *, int roundboxalign, const float zoom) ATTR_NONNULL()