Blender V5.0
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
8
9#include <algorithm>
10#include <climits>
11#include <cstdlib>
12#include <cstring>
13#include <list>
14
15#include "DNA_brush_types.h"
16#include "DNA_node_types.h"
17#include "DNA_screen_types.h"
18#include "DNA_space_types.h"
19#include "DNA_userdef_types.h"
20
21#include "BLI_color.hh"
22#include "BLI_listbase.h"
23#include "BLI_math_color.h"
24#include "BLI_math_vector.h"
25#include "BLI_rect.h"
26#include "BLI_string.h"
27#include "BLI_string_utf8.h"
28#include "BLI_utildefines.h"
29
30#include "BKE_context.hh"
31
32#include "RNA_access.hh"
33
34#include "BLF_api.hh"
35
36#include "ED_node.hh"
37
38#include "UI_interface_icons.hh"
39#include "UI_view2d.hh"
40
41#include "interface_intern.hh"
42
43#include "GPU_batch.hh"
44#include "GPU_batch_presets.hh"
45#include "GPU_immediate.hh"
46#include "GPU_immediate_util.hh"
47#include "GPU_matrix.hh"
48#include "GPU_state.hh"
49
50#include "UI_abstract_view.hh"
51
53
54#ifdef WITH_INPUT_IME
55# include "WM_types.hh"
56#endif
57
58/* -------------------------------------------------------------------- */
61
62/* icons are 80% of height of button (16 pixels inside 20 height) */
63#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
64
65/* visual types for drawing */
66/* for time being separated from functional types */
118
135
137
139
140/* -------------------------------------------------------------------- */
143
144static void color_blend_v3_v3(uchar cp[3], const uchar cpstate[3], const float fac)
145{
146 if (fac != 0.0f) {
147 cp[0] = int((1.0f - fac) * cp[0] + fac * cpstate[0]);
148 cp[1] = int((1.0f - fac) * cp[1] + fac * cpstate[1]);
149 cp[2] = int((1.0f - fac) * cp[2] + fac * cpstate[2]);
150 }
151}
152
153static void color_blend_v4_v4v4(uchar r_col[4],
154 const uchar col1[4],
155 const uchar col2[4],
156 const float fac)
157{
158 const int faci = unit_float_to_uchar_clamp(fac);
159 const int facm = 255 - faci;
160
161 r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
162 r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
163 r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
164 r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
165}
166
167static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int contrast)
168{
169 BLI_assert(contrast > 0);
170 const int item_value = srgb_to_grayscale_byte(cp);
171 const int inner_value = srgb_to_grayscale_byte(cp_other);
172 const int delta = item_value - inner_value;
173 if (delta >= 0) {
174 if (contrast > delta) {
175 add_v3_uchar_clamped(cp, contrast - delta);
176 }
177 }
178 else {
179 if (contrast > -delta) {
180 add_v3_uchar_clamped(cp, -contrast - delta);
181 }
182 }
183}
184
185static void color_mul_hsl_v3(uchar ch[3], float h_factor, float s_factor, float l_factor)
186{
187 float rgb[3], hsl[3];
188 rgb_uchar_to_float(rgb, ch);
189 rgb_to_hsl_v(rgb, hsl);
190 hsl[0] *= h_factor;
191 hsl[1] *= s_factor;
192 hsl[2] *= l_factor;
193 hsl_to_rgb_v(hsl, rgb);
194 rgb_float_to_uchar(ch, rgb);
195}
196
198
199/* -------------------------------------------------------------------- */
202
215
216/* fill this struct with polygon info to draw AA'ed */
217/* it has outline, back, and two optional tria meshes */
218
221 int type;
222 float size, center[2];
223
224 float vec[16][2];
225 const uint (*index)[3];
226};
227
228/* max as used by round_box__edges */
229/* Make sure to change widget_base_vert.glsl accordingly. */
230#define WIDGET_CURVE_RESOLU 9
231#define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4)
232
234 /* TODO: remove these completely. */
239
241
244
245 /* Widget shader parameters, must match the shader layout. */
247};
248
254
255 /* pointer to theme color definition */
258
259 /* converted colors for state */
261
263 ATTR_NONNULL();
265 rcti *,
266 const uiWidgetStateInfo *,
267 int roundboxalign,
268 const float zoom) ATTR_NONNULL();
269 void (*custom)(uiBut *,
271 rcti *,
272 const uiWidgetStateInfo *,
273 int roundboxalign,
274 const float zoom) ATTR_NONNULL();
275 void (*draw_block)(
276 uiWidgetColors *, const rcti *, int block_flag, int roundboxalign, const float zoom);
277 void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
278};
279
281
282/* -------------------------------------------------------------------- */
285
286static const float cornervec[WIDGET_CURVE_RESOLU][2] = {
287 {0.0, 0.0},
288 {0.195, 0.02},
289 {0.383, 0.067},
290 {0.55, 0.169},
291 {0.707, 0.293},
292 {0.831, 0.45},
293 {0.924, 0.617},
294 {0.98, 0.805},
295 {1.0, 1.0},
296};
297
299 {0.468813, -0.481430},
300 {-0.155755, -0.352820},
301 {0.219306, -0.238501},
302 {-0.393286, -0.110949},
303 {-0.024699, 0.013908},
304 {0.343805, 0.147431},
305 {-0.272855, 0.269918},
306 {0.095909, 0.388710},
307};
308#define WIDGET_AA_JITTER UI_PIXEL_AA_JITTER
309#define jit ui_pixel_jitter
310
311static const float g_shape_preset_number_arrow_vert[3][2] = {
312 {-0.352077, 0.532607},
313 {-0.352077, -0.549313},
314 {0.330000, -0.008353},
315};
317 {0, 1, 2},
318};
319
320static const float g_shape_preset_scroll_circle_vert[16][2] = {
321 {0.382684, 0.923879},
322 {0.000001, 1.000000},
323 {-0.382683, 0.923880},
324 {-0.707107, 0.707107},
325 {-0.923879, 0.382684},
326 {-1.000000, 0.000000},
327 {-0.923880, -0.382684},
328 {-0.707107, -0.707107},
329 {-0.382683, -0.923880},
330 {0.000000, -1.000000},
331 {0.382684, -0.923880},
332 {0.707107, -0.707107},
333 {0.923880, -0.382684},
334 {1.000000, -0.000000},
335 {0.923880, 0.382683},
336 {0.707107, 0.707107},
337};
339 {0, 1, 2},
340 {2, 0, 3},
341 {3, 0, 15},
342 {3, 15, 4},
343 {4, 15, 14},
344 {4, 14, 5},
345 {5, 14, 13},
346 {5, 13, 6},
347 {6, 13, 12},
348 {6, 12, 7},
349 {7, 12, 11},
350 {7, 11, 8},
351 {8, 11, 10},
352 {8, 10, 9},
353};
354
355static const float g_shape_preset_menu_arrow_vert[6][2] = {
356 {-0.33, 0.16},
357 {0.33, 0.16},
358 {0, 0.82},
359 {0, -0.82},
360 {-0.33, -0.16},
361 {0.33, -0.16},
362};
363static const uint g_shape_preset_menu_arrow_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
364
365static const float g_shape_preset_checkmark_vert[6][2] = {
366 {-0.578579, 0.253369},
367 {-0.392773, 0.412794},
368 {-0.004241, -0.328551},
369 {-0.003001, 0.034320},
370 {1.055313, 0.864744},
371 {0.866408, 1.026895},
372};
373
375 {3, 2, 4},
376 {3, 4, 5},
377 {1, 0, 3},
378 {0, 2, 3},
379};
380
381#define OY (-0.2 / 2)
382#define SC (0.35 * 2)
383static const float g_shape_preset_hold_action_vert[6][2] = {
384 {-0.5 + SC, 1.0 + OY},
385 {0.5, 1.0 + OY},
386 {0.5, 0.0 + OY + SC},
387};
388static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
389#undef OY
390#undef SC
391
393
394/* -------------------------------------------------------------------- */
402
403static struct {
404 blender::gpu::Batch *roundbox_widget;
405 blender::gpu::Batch *roundbox_shadow;
406
407 /* TODO: remove. */
410} g_ui_batch_cache = {nullptr};
411
413{
414 if (g_ui_batch_cache.format.attr_len == 0) {
417 format, "vflag", blender::gpu::VertAttrType::UINT_32);
418 }
419 return g_ui_batch_cache.format;
420}
421
422#define INNER 0
423#define OUTLINE 1
424#define EMBOSS 2
425#define NO_AA 0
426
427static void set_roundbox_vertex_data(GPUVertBufRaw *vflag_step, uint32_t d)
428{
429 uint32_t *data = static_cast<uint32_t *>(GPU_vertbuf_raw_step(vflag_step));
430 *data = d;
431}
432
433static uint32_t set_roundbox_vertex(GPUVertBufRaw *vflag_step,
434 int corner_id,
435 int corner_v,
436 int jit_v,
437 bool inner,
438 bool emboss,
439 int color)
440{
441 uint32_t *data = static_cast<uint32_t *>(GPU_vertbuf_raw_step(vflag_step));
442 *data = corner_id;
443 *data |= corner_v << 2;
444 *data |= jit_v << 6;
445 *data |= color << 12;
446 *data |= (inner) ? (1 << 10) : 0; /* is inner vert */
447 *data |= (emboss) ? (1 << 11) : 0; /* is emboss vert */
448 return *data;
449}
450
451blender::gpu::Batch *ui_batch_roundbox_widget_get()
452{
453 if (g_ui_batch_cache.roundbox_widget == nullptr) {
455
456 GPU_vertbuf_data_alloc(*vbo, 12);
457
459 GPU_indexbuf_init(&ibuf, GPU_PRIM_TRIS, 6, 12);
460 /* Widget */
461 GPU_indexbuf_add_tri_verts(&ibuf, 0, 1, 2);
462 GPU_indexbuf_add_tri_verts(&ibuf, 2, 1, 3);
463 /* Trias */
464 GPU_indexbuf_add_tri_verts(&ibuf, 4, 5, 6);
465 GPU_indexbuf_add_tri_verts(&ibuf, 6, 5, 7);
466
467 GPU_indexbuf_add_tri_verts(&ibuf, 8, 9, 10);
468 GPU_indexbuf_add_tri_verts(&ibuf, 10, 9, 11);
469
470 g_ui_batch_cache.roundbox_widget = GPU_batch_create_ex(
473 }
474 return g_ui_batch_cache.roundbox_widget;
475}
476
477blender::gpu::Batch *ui_batch_roundbox_shadow_get()
478{
479 if (g_ui_batch_cache.roundbox_shadow == nullptr) {
480 uint32_t last_data;
481 GPUVertBufRaw vflag_step;
483 const int vcount = (WIDGET_SIZE_MAX + 1) * 2 + 2 + WIDGET_SIZE_MAX;
484 GPU_vertbuf_data_alloc(*vbo, vcount);
485 GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
486
487 for (int c = 0; c < 4; c++) {
488 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
489 set_roundbox_vertex(&vflag_step, c, a, NO_AA, true, false, INNER);
490 set_roundbox_vertex(&vflag_step, c, a, NO_AA, false, false, INNER);
491 }
492 }
493 /* close loop */
494 last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
495 last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, false, false, INNER);
496 /* restart */
497 set_roundbox_vertex_data(&vflag_step, last_data);
498 set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
499 /* filled */
500 for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
501 for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU - 1; a2 >= 0; a1++, a2--) {
502 set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER);
503 set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER);
504 }
505 }
506 g_ui_batch_cache.roundbox_shadow = GPU_batch_create_ex(
509 }
510 return g_ui_batch_cache.roundbox_shadow;
511}
512
513#undef INNER
514#undef OUTLINE
515#undef EMBOSS
516#undef NO_AA
517
519
520/* -------------------------------------------------------------------- */
523
524static void draw_anti_tria(
525 float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
526{
527 const float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
528
529 float draw_color[4];
530 copy_v4_v4(draw_color, color);
531 /* NOTE: This won't give back the original color. */
532 draw_color[3] *= 1.0f / WIDGET_AA_JITTER;
533
535
537 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
539
540 immUniformColor4fv(draw_color);
542
543 /* for each AA step */
544 for (int j = 0; j < WIDGET_AA_JITTER; j++) {
545 immVertex2f(pos, tri_arr[0][0] + jit[j][0], tri_arr[0][1] + jit[j][1]);
546 immVertex2f(pos, tri_arr[1][0] + jit[j][0], tri_arr[1][1] + jit[j][1]);
547 immVertex2f(pos, tri_arr[2][0] + jit[j][0], tri_arr[2][1] + jit[j][1]);
548 }
549
550 immEnd();
551
553
555}
556
557void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
558{
559 const float f3 = 0.05 * U.widget_unit;
560 const float f5 = 0.15 * U.widget_unit;
561 const float f7 = 0.25 * U.widget_unit;
562
563 if (dir == 'h') {
564 draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
565 }
566 else if (dir == 't') {
567 draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
568 }
569 else { /* 'v' = vertical, down. */
570 draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
571 }
572}
573
574/* triangle 'icon' inside rect */
575static void draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
576{
577 if (dir == 'h') {
578 const float half = 0.5f * BLI_rctf_size_y(rect);
580 rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color);
581 }
582 else {
583 const float half = 0.5f * BLI_rctf_size_x(rect);
585 rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
586 }
587}
588
589static void widget_init(uiWidgetBase *wtb)
590{
591 wtb->totvert = wtb->halfwayvert = 0;
592 wtb->tria1.tot = 0;
593 wtb->tria2.tot = 0;
595 wtb->tria1.size = 0;
596 wtb->tria2.size = 0;
597
598 wtb->draw_inner = true;
599 wtb->draw_outline = true;
600 wtb->draw_emboss = true;
601
602 wtb->uniform_params.shade_dir = 1.0f;
603 wtb->uniform_params.alpha_discard = 1.0f;
604}
605
607
608/* -------------------------------------------------------------------- */
611
612/* this call has 1 extra arg to allow mask outline */
614 uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad, float radi)
615{
616 float vec[WIDGET_CURVE_RESOLU][2], veci[WIDGET_CURVE_RESOLU][2];
617 const float minx = rect->xmin, miny = rect->ymin, maxx = rect->xmax, maxy = rect->ymax;
618 const float minxi = minx + U.pixelsize; /* Bounding-box inner. */
619 const float maxxi = maxx - U.pixelsize;
620 const float minyi = miny + U.pixelsize;
621 const float maxyi = maxy - U.pixelsize;
622 /* for uv, can divide by zero */
623 const float facxi = (maxxi != minxi) ? 1.0f / (maxxi - minxi) : 0.0f;
624 const float facyi = (maxyi != minyi) ? 1.0f / (maxyi - minyi) : 0.0f;
625 int tot = 0;
626 const int hnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT)) ==
628 (roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) ==
630 1 :
631 2;
632 const int vnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)) ==
634 (roundboxalign & (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) ==
636 1 :
637 2;
638
639 const int minsize = min_ii(BLI_rcti_size_x(rect) * hnum, BLI_rcti_size_y(rect) * vnum);
640
641 if (2.0f * rad > minsize) {
642 rad = 0.5f * minsize;
643 }
644
645 if (2.0f * (radi + 1.0f) > minsize) {
646 radi = 0.5f * minsize - U.pixelsize;
647 }
648
649 wt->uniform_params.rad = rad;
650 wt->uniform_params.radi = radi;
651 wt->uniform_params.facxi = facxi;
652 wt->uniform_params.facyi = facyi;
653 wt->uniform_params.round_corners[0] = (roundboxalign & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f;
654 wt->uniform_params.round_corners[1] = (roundboxalign & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f;
655 wt->uniform_params.round_corners[2] = (roundboxalign & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f;
656 wt->uniform_params.round_corners[3] = (roundboxalign & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f;
658 BLI_rctf_init(&wt->uniform_params.recti, minxi, maxxi, minyi, maxyi);
659
660 /* Multiply by radius. */
661 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
662 veci[a][0] = radi * cornervec[a][0];
663 veci[a][1] = radi * cornervec[a][1];
664 vec[a][0] = rad * cornervec[a][0];
665 vec[a][1] = rad * cornervec[a][1];
666 }
667
668 /* corner left-bottom */
669 if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
670 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
671 wt->inner_v[tot][0] = minxi + veci[a][1];
672 wt->inner_v[tot][1] = minyi + radi - veci[a][0];
673
674 wt->outer_v[tot][0] = minx + vec[a][1];
675 wt->outer_v[tot][1] = miny + rad - vec[a][0];
676
677 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
678 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
679 }
680 }
681 else {
682 wt->inner_v[tot][0] = minxi;
683 wt->inner_v[tot][1] = minyi;
684
685 wt->outer_v[tot][0] = minx;
686 wt->outer_v[tot][1] = miny;
687
688 wt->inner_uv[tot][0] = 0.0f;
689 wt->inner_uv[tot][1] = 0.0f;
690
691 tot++;
692 }
693
694 /* corner right-bottom */
695 if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
696 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
697 wt->inner_v[tot][0] = maxxi - radi + veci[a][0];
698 wt->inner_v[tot][1] = minyi + veci[a][1];
699
700 wt->outer_v[tot][0] = maxx - rad + vec[a][0];
701 wt->outer_v[tot][1] = miny + vec[a][1];
702
703 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
704 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
705 }
706 }
707 else {
708 wt->inner_v[tot][0] = maxxi;
709 wt->inner_v[tot][1] = minyi;
710
711 wt->outer_v[tot][0] = maxx;
712 wt->outer_v[tot][1] = miny;
713
714 wt->inner_uv[tot][0] = 1.0f;
715 wt->inner_uv[tot][1] = 0.0f;
716
717 tot++;
718 }
719
720 wt->halfwayvert = tot;
721
722 /* corner right-top */
723 if (roundboxalign & UI_CNR_TOP_RIGHT) {
724 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
725 wt->inner_v[tot][0] = maxxi - veci[a][1];
726 wt->inner_v[tot][1] = maxyi - radi + veci[a][0];
727
728 wt->outer_v[tot][0] = maxx - vec[a][1];
729 wt->outer_v[tot][1] = maxy - rad + vec[a][0];
730
731 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
732 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
733 }
734 }
735 else {
736 wt->inner_v[tot][0] = maxxi;
737 wt->inner_v[tot][1] = maxyi;
738
739 wt->outer_v[tot][0] = maxx;
740 wt->outer_v[tot][1] = maxy;
741
742 wt->inner_uv[tot][0] = 1.0f;
743 wt->inner_uv[tot][1] = 1.0f;
744
745 tot++;
746 }
747
748 /* corner left-top */
749 if (roundboxalign & UI_CNR_TOP_LEFT) {
750 for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
751 wt->inner_v[tot][0] = minxi + radi - veci[a][0];
752 wt->inner_v[tot][1] = maxyi - veci[a][1];
753
754 wt->outer_v[tot][0] = minx + rad - vec[a][0];
755 wt->outer_v[tot][1] = maxy - vec[a][1];
756
757 wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
758 wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
759 }
760 }
761 else {
762 wt->inner_v[tot][0] = minxi;
763 wt->inner_v[tot][1] = maxyi;
764
765 wt->outer_v[tot][0] = minx;
766 wt->outer_v[tot][1] = maxy;
767
768 wt->inner_uv[tot][0] = 0.0f;
769 wt->inner_uv[tot][1] = 1.0f;
770
771 tot++;
772 }
773
775
776 wt->totvert = tot;
777}
778
779static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad)
780{
781 round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
782}
783
785
786/* -------------------------------------------------------------------- */
789
790/* based on button rect, return scaled array of triangles */
792 const rcti *rect,
793 float triasize,
794 char where,
795 /* input data */
796 const float verts[][2],
797 const int verts_tot,
798 const uint tris[][3],
799 const int tris_tot)
800{
801 float sizex, sizey;
802 int i1 = 0, i2 = 1;
803
804 const float minsize = ELEM(where, 'r', 'l') ? BLI_rcti_size_y(rect) : BLI_rcti_size_x(rect);
805
806 /* center position and size */
807 float centx = float(rect->xmin) + 0.4f * minsize;
808 float centy = float(rect->ymin) + 0.5f * minsize;
809 tria->size = sizex = sizey = -0.5f * triasize * minsize;
810
811 if (where == 'r') {
812 centx = float(rect->xmax) - 0.4f * minsize;
813 sizex = -sizex;
814 }
815 else if (where == 't') {
816 centx = float(rect->xmin) + 0.5f * minsize;
817 centy = float(rect->ymax) - 0.5f * minsize;
818 sizey = -sizey;
819 i2 = 0;
820 i1 = 1;
821 }
822 else if (where == 'b') {
823 centx = float(rect->xmin) + 0.5f * minsize;
824 sizex = -sizex;
825 i2 = 0;
826 i1 = 1;
827 }
828
829 for (int a = 0; a < verts_tot; a++) {
830 tria->vec[a][0] = sizex * verts[a][i1] + centx;
831 tria->vec[a][1] = sizey * verts[a][i2] + centy;
832 }
833
834 tria->center[0] = centx;
835 tria->center[1] = centy;
836
837 tria->tot = tris_tot;
838 tria->index = tris;
839}
840
842 const rcti *rect,
843 float triasize,
844 char where)
845{
848 rect,
849 triasize,
850 where,
855}
856
858 const rcti *rect,
859 float triasize,
860 char where)
861{
863 /* With the current changes to use batches for widget drawing, the code
864 * below is doing almost nothing effectively. 'where' doesn't work either,
865 * shader is currently hardcoded to work for the button triangle pointing
866 * at the lower right. The same limitation applies to other trias as well.
867 * XXX Should be addressed. */
869 rect,
870 triasize,
871 where,
876}
877
879 const rcti *rect,
880 float triasize,
881 char where)
882{
885 rect,
886 triasize,
887 where,
892}
893
895 uint col,
896 GPUPrimType mode,
897 const float quads_pos[WIDGET_SIZE_MAX][2],
898 const uchar quads_col[WIDGET_SIZE_MAX][4],
899 uint totvert)
900{
901 immBegin(mode, totvert);
902 for (int i = 0; i < totvert; i++) {
903 if (quads_col) {
904 immAttr4ubv(col, quads_col[i]);
905 }
906 immVertex2fv(pos, quads_pos[i]);
907 }
908 immEnd();
909}
910
912{
913 const float width = BLI_rcti_size_x(rect);
914 const float height = BLI_rcti_size_y(rect);
915 if ((width / height) < 0.5f) {
916 /* Too narrow to fit. */
917 return;
918 }
919 float centx, centy, size;
920
921 tria->type = ROUNDBOX_TRIA_MENU;
922
923 /* Center position and size. */
924 tria->center[0] = centx = rect->xmin + 0.52f * BLI_rcti_size_y(rect);
925 tria->center[1] = centy = rect->ymin + 0.52f * BLI_rcti_size_y(rect);
926 tria->size = size = 0.4f * height;
927
928 if (width > height * 1.1f) {
929 /* For wider buttons align tighter to the right. */
930 tria->center[0] = centx = rect->xmax - 0.32f * height;
931 }
932
933 for (int a = 0; a < 6; a++) {
934 tria->vec[a][0] = size * g_shape_preset_menu_arrow_vert[a][0] + centx;
935 tria->vec[a][1] = size * g_shape_preset_menu_arrow_vert[a][1] + centy;
936 }
937
938 tria->tot = 2;
940}
941
943{
944 float centx, centy, size;
945
947
948 /* Center position and size. */
949 tria->center[0] = centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
950 tria->center[1] = centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
951 tria->size = size = 0.5f * BLI_rcti_size_y(rect);
952
953 for (int a = 0; a < 6; a++) {
954 tria->vec[a][0] = size * g_shape_preset_checkmark_vert[a][0] + centx;
955 tria->vec[a][1] = size * g_shape_preset_checkmark_vert[a][1] + centy;
956 }
957
958 tria->tot = 4;
960}
961
963{
964 tria->type = ROUNDBOX_TRIA_DASH;
965
966 /* Center position and size. */
967 tria->center[0] = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
968 tria->center[1] = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
969 tria->size = 0.5f * BLI_rcti_size_y(rect);
970}
971
973
974/* -------------------------------------------------------------------- */
977
978/* prepares shade colors */
979static void shadecolors4(
980 const uchar *color, short shadetop, short shadedown, uchar r_coltop[4], uchar r_coldown[4])
981{
982 r_coltop[0] = std::clamp(color[0] + shadetop, 0, 255);
983 r_coltop[1] = std::clamp(color[1] + shadetop, 0, 255);
984 r_coltop[2] = std::clamp(color[2] + shadetop, 0, 255);
985 r_coltop[3] = color[3];
986
987 r_coldown[0] = std::clamp(color[0] + shadedown, 0, 255);
988 r_coldown[1] = std::clamp(color[1] + shadedown, 0, 255);
989 r_coldown[2] = std::clamp(color[2] + shadedown, 0, 255);
990 r_coldown[3] = color[3];
991}
992
994 const int totvert,
995 float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
996{
997 int a;
998 for (a = 0; a < totvert; a++) {
999 copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[a]);
1000 copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[a]);
1001 }
1002 copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[0]);
1003 copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]);
1004}
1005
1007{
1008 float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
1009 widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
1010
1012 pos, 0, GPU_PRIM_TRI_STRIP, triangle_strip, nullptr, wtb->totvert * 2 + 2);
1013}
1014
1016 const bool alpha_check,
1017 const float discard_factor)
1018{
1019 if (alpha_check) {
1020 wtb->uniform_params.alpha_discard = -discard_factor;
1021 }
1022 else {
1023 wtb->uniform_params.alpha_discard = discard_factor;
1024 }
1025}
1026
1027static void widgetbase_set_uniform_alpha_check(uiWidgetBase *wtb, const bool alpha_check)
1028{
1029 const float discard_factor = fabs(wtb->uniform_params.alpha_discard);
1030 widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
1031}
1032
1033static void widgetbase_set_uniform_discard_factor(uiWidgetBase *wtb, const float discard_factor)
1034{
1035 const bool alpha_check = wtb->uniform_params.alpha_discard < 0.0f;
1036 widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
1037}
1038
1040 const uchar *col1,
1041 const uchar *col2,
1042 const uchar *outline,
1043 const uchar *emboss,
1044 const uchar *tria)
1045{
1046 rgba_float_args_set_ch(wtb->uniform_params.color_inner1, col1[0], col1[1], col1[2], col1[3]);
1047 rgba_float_args_set_ch(wtb->uniform_params.color_inner2, col2[0], col2[1], col2[2], col2[3]);
1049 wtb->uniform_params.color_outline, outline[0], outline[1], outline[2], outline[3]);
1051 wtb->uniform_params.color_emboss, emboss[0], emboss[1], emboss[2], emboss[3]);
1052 rgba_float_args_set_ch(wtb->uniform_params.color_tria, tria[0], tria[1], tria[2], tria[3]);
1053}
1054
1056
1057/* -------------------------------------------------------------------- */
1060
1061/* keep in sync with shader */
1062#define MAX_WIDGET_BASE_BATCH 6
1063#define MAX_WIDGET_PARAMETERS 12
1064
1065static struct {
1070
1072{
1073 const float checker_params[3] = {
1074 UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
1075
1076 if (g_widget_base_batch.count == 0) {
1077 return;
1078 }
1079
1080 blender::gpu::Batch *batch = ui_batch_roundbox_widget_get();
1081 if (g_widget_base_batch.count == 1) {
1082 /* draw single */
1085 "parameters",
1087 (const float (*)[4])g_widget_base_batch.params);
1088 GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
1090 }
1091 else {
1094 "parameters",
1096 (float (*)[4])g_widget_base_batch.params);
1097 GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
1099 }
1100 g_widget_base_batch.count = 0;
1101}
1102
1104{
1105 BLI_assert(g_widget_base_batch.enabled == false);
1106 g_widget_base_batch.enabled = true;
1107}
1108
1110{
1111 BLI_assert(g_widget_base_batch.enabled == true);
1112 g_widget_base_batch.enabled = false;
1113
1115
1117
1119}
1120
1122{
1123 wtb->uniform_params.tria_type = wtb->tria1.type;
1124 wtb->uniform_params.tria1_size = wtb->tria1.size;
1125 wtb->uniform_params.tria2_size = wtb->tria2.size;
1128
1129 if (g_widget_base_batch.enabled) {
1131 g_widget_base_batch.count++;
1132
1135 }
1136 }
1137 else {
1138 const float checker_params[3] = {
1139 UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
1140 /* draw single */
1141 blender::gpu::Batch *batch = ui_batch_roundbox_widget_get();
1144 batch, "parameters", MAX_WIDGET_PARAMETERS, (float (*)[4]) & wtb->uniform_params);
1145 GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
1147 }
1148}
1149
1150static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
1151{
1152 uchar inner_col1[4] = {0};
1153 uchar inner_col2[4] = {0};
1154 uchar emboss_col[4] = {0};
1155 uchar outline_col[4] = {0};
1156 uchar tria_col[4] = {0};
1157
1158 /* backdrop non AA */
1159 if (wtb->draw_inner) {
1160 if (wcol->shaded == 0) {
1161 /* simple fill */
1162 inner_col1[0] = inner_col2[0] = wcol->inner[0];
1163 inner_col1[1] = inner_col2[1] = wcol->inner[1];
1164 inner_col1[2] = inner_col2[2] = wcol->inner[2];
1165 inner_col1[3] = inner_col2[3] = wcol->inner[3];
1166 }
1167 else {
1168 /* gradient fill */
1169 shadecolors4(wcol->inner, wcol->shadetop, wcol->shadedown, inner_col1, inner_col2);
1170 }
1171 }
1172
1173 if (wtb->draw_outline) {
1174 outline_col[0] = wcol->outline[0];
1175 outline_col[1] = wcol->outline[1];
1176 outline_col[2] = wcol->outline[2];
1177 outline_col[3] = wcol->outline[3];
1178
1179 /* Emboss shadow if enabled, and inner and outline colors are not fully transparent. */
1180 if ((wtb->draw_emboss) && (wcol->inner[3] != 0.0f || wcol->outline[3] != 0.0f)) {
1182 }
1183 }
1184
1185 if (wtb->tria1.type != ROUNDBOX_TRIA_NONE) {
1186 tria_col[0] = wcol->item[0];
1187 tria_col[1] = wcol->item[1];
1188 tria_col[2] = wcol->item[2];
1189 tria_col[3] = wcol->item[3];
1190 }
1191
1192 /* Draw everything in one draw-call. */
1193 if (inner_col1[3] || inner_col2[3] || outline_col[3] || emboss_col[3] || tria_col[3]) {
1195 wtb, inner_col1, inner_col2, outline_col, emboss_col, tria_col);
1196
1200 }
1201}
1202
1203/* widgetbase_draw variation for drawing colors, with full float color for wide gamut. */
1205 const uiWidgetColors *wcol,
1206 float color[4],
1207 bool show_alpha_checkers)
1208{
1209 const uchar unused_col[4] = {0};
1210 uchar emboss_col[4] = {0};
1211 uchar outline_col[4] = {0};
1212
1213 if (wtb->draw_outline) {
1214 outline_col[0] = wcol->outline[0];
1215 outline_col[1] = wcol->outline[1];
1216 outline_col[2] = wcol->outline[2];
1217 outline_col[3] = wcol->outline[3];
1218
1219 /* Emboss shadow if enabled, and inner and outline colors are not fully transparent. */
1220 if ((wtb->draw_emboss) && (wcol->inner[3] != 0.0f || wcol->outline[3] != 0.0f)) {
1222 }
1223 }
1224
1225 /* Draw everything in one draw-call. */
1226 widgetbase_set_uniform_alpha_check(wtb, show_alpha_checkers);
1228 wtb, unused_col, unused_col, outline_col, emboss_col, unused_col);
1231
1235}
1236
1238
1239/* -------------------------------------------------------------------- */
1242
1243#define UI_TEXT_CLIP_MARGIN (0.25f * U.widget_unit / but->block->aspect)
1244
1245#define PREVIEW_PAD (0.15f * UI_UNIT_X)
1246
1248{
1249 if (state->but_flag & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
1250 if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
1251 return 0.25f;
1252 }
1253 return 0.5f;
1254 }
1255
1256 if (state->but_flag & UI_SEARCH_FILTER_NO_MATCH) {
1257 return 0.5f;
1258 }
1259
1260 return 1.0f;
1261}
1262
1264 const float aspect,
1265 const float alpha,
1266 const rcti *rect,
1267 const uchar mono_color[4])
1268{
1269 if (icon == ICON_NONE) {
1270 return;
1271 }
1272
1273 const float size = ICON_DEFAULT_HEIGHT / (aspect * UI_INV_SCALE_FAC);
1274
1275 if (size > 0) {
1276 const int x = BLI_rcti_cent_x(rect) - size / 2;
1277 const int y = BLI_rcti_cent_y(rect) - size / 2;
1278
1279 const bTheme *btheme = UI_GetTheme();
1280 const float desaturate = 1.0 - btheme->tui.icon_saturation;
1281 uchar color[4] = {mono_color[0], mono_color[1], mono_color[2], mono_color[3]};
1282 const bool has_theme = UI_icon_get_theme_color(int(icon), color);
1283 const bool outline = btheme->tui.icon_border_intensity > 0.0f && has_theme;
1284
1286 x, y, icon, aspect * UI_INV_SCALE_FAC, alpha, desaturate, color, outline, nullptr);
1287 }
1288}
1289
1296 float alpha,
1297 float aspect,
1298 const bool add_padding,
1299 const rcti *rect,
1300 const uchar mono_color[4])
1301{
1302 if (icon == ICON_NONE) {
1303 return;
1304 }
1305
1306 if (icon < BIFICONID_LAST_STATIC) {
1307 widget_draw_icon_centered(icon, aspect, alpha, rect, mono_color);
1308 return;
1309 }
1310
1311 const int w = BLI_rcti_size_x(rect);
1312 const int h = BLI_rcti_size_y(rect);
1313 const int size = std::min(w, h) - (add_padding ? (PREVIEW_PAD * 2) : 0);
1314
1315 if (size > 0) {
1316 const int x = rect->xmin + w / 2 - size / 2;
1317 const int y = rect->ymin + h / 2 - size / 2;
1318
1319 UI_icon_draw_preview(x, y, icon, 1.0f, alpha, size);
1320 }
1321}
1322
1323static int ui_but_draw_menu_icon(const uiBut *but)
1324{
1326}
1327
1328/* icons have been standardized... and this call draws in untransformed coordinates */
1329
1331 const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const uchar mono_color[4])
1332{
1333 if (but->flag & UI_BUT_ICON_PREVIEW) {
1336 alpha,
1337 but->block->aspect,
1339 rect,
1340 mono_color);
1342 return;
1343 }
1344
1345 /* this icon doesn't need draw... */
1346 if (icon == ICON_BLANK1 && (but->flag & UI_BUT_ICON_SUBMENU) == 0) {
1347 return;
1348 }
1349
1350 const float aspect = but->block->aspect * UI_INV_SCALE_FAC;
1351 const float height = ICON_DEFAULT_HEIGHT / aspect;
1352
1353 /* calculate blend color */
1355 if (but->flag & UI_SELECT) {
1356 /* pass */
1357 }
1358 else if (but->flag & UI_HOVER) {
1359 /* pass */
1360 }
1361 else {
1362 alpha = 0.75f;
1363 }
1364 }
1365 else if (but->type == ButType::Label) {
1366 /* extra feature allows more alpha blending */
1367 const uiButLabel *but_label = reinterpret_cast<const uiButLabel *>(but);
1368 alpha *= but_label->alpha_factor;
1369 }
1370 else if (ELEM(but->type, ButType::But, ButType::Decorator)) {
1372 state.but_flag = but->flag;
1373 state.but_drawflag = but->drawflag;
1374 alpha *= widget_alpha_factor(&state);
1375 }
1376
1377 /* Dim the icon as its space is reduced to zero. */
1378 if (height > (rect->xmax - rect->xmin)) {
1379 alpha *= std::max(float(rect->xmax - rect->xmin) / height, 0.0f);
1380 }
1381
1383
1384 if (icon && icon != ICON_BLANK1) {
1385 const float ofs = 1.0f / aspect;
1386 float xs, ys;
1387
1388 if (but->drawflag & UI_BUT_ICON_LEFT) {
1389 /* special case - icon_only pie buttons */
1391 but->str.empty())
1392 {
1393 xs = rect->xmin + 2.0f * ofs;
1394 }
1395 else if (but->emboss == blender::ui::EmbossType::None || but->type == ButType::Label) {
1396 xs = rect->xmin + 2.0f * ofs;
1397 }
1398 else {
1399 xs = rect->xmin + 4.0f * ofs;
1400 }
1401 }
1402 else {
1403 xs = (rect->xmin + rect->xmax - height) / 2.0f;
1404 }
1405 ys = (rect->ymin + rect->ymax - height) / 2.0f;
1406
1407 /* force positions to integers, for zoom levels near 1. draws icons crisp. */
1408 if (aspect > 0.95f && aspect < 1.05f) {
1409 xs = roundf(xs);
1410 ys = roundf(ys);
1411 }
1412
1413 /* Get theme color. */
1414 uchar color[4] = {mono_color[0], mono_color[1], mono_color[2], mono_color[3]};
1415 const bTheme *btheme = UI_GetTheme();
1416 /* Only use theme colors if the button doesn't override the color. */
1417 const bool has_theme = !but->col[3] && UI_icon_get_theme_color(int(icon), color);
1418 const bool outline = btheme->tui.icon_border_intensity > 0.0f && has_theme;
1419
1420 /* to indicate draggable */
1421 if (ui_but_drag_is_draggable(but) && (but->flag & UI_HOVER)) {
1422 UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, outline, &but->icon_overlay_text);
1423 }
1424 else if (but->flag & (UI_HOVER | UI_SELECT | UI_SELECT_DRAW)) {
1425 UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, outline, &but->icon_overlay_text);
1426 }
1427 else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) {
1428 if (has_theme) {
1429 alpha *= 0.8f;
1430 }
1431 UI_icon_draw_ex(xs,
1432 ys,
1433 icon,
1434 aspect,
1435 alpha,
1436 0.0f,
1437 color,
1438 outline,
1439 &but->icon_overlay_text,
1441 }
1442 else {
1443 const float desaturate = 1.0 - btheme->tui.icon_saturation;
1445 xs, ys, icon, aspect, alpha, desaturate, color, outline, &but->icon_overlay_text);
1446 }
1447 }
1448
1450}
1451
1452static void widget_draw_submenu_tria(const uiBut *but,
1453 const rcti *rect,
1454 const uiWidgetColors *wcol)
1455{
1456 const float aspect = but->block->aspect * UI_INV_SCALE_FAC;
1457 const int tria_height = int(ICON_DEFAULT_HEIGHT / aspect);
1458 const int tria_width = int(ICON_DEFAULT_WIDTH / aspect) - 2 * U.pixelsize;
1459 const int xs = rect->xmax - tria_width;
1460 const int ys = (rect->ymin + rect->ymax - tria_height) / 2.0f;
1461
1462 float col[4];
1464 col[3] *= 0.8f;
1465
1466 rctf tria_rect;
1467 BLI_rctf_init(&tria_rect, xs, xs + tria_width, ys, ys + tria_height);
1468 BLI_rctf_scale(&tria_rect, 0.4f);
1469
1473 draw_anti_tria_rect(&tria_rect, 'h', col);
1474}
1475
1476static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
1477{
1478 const char *prev_utf8 = BLI_str_find_prev_char_utf8(str + but->ofs, str);
1479 const int bytes = str + but->ofs - prev_utf8;
1480
1481 but->ofs -= bytes;
1482}
1483
1484static void ui_text_clip_give_next_off(uiBut *but, const char *str, const char *str_end)
1485{
1486 const char *next_utf8 = BLI_str_find_next_char_utf8(str + but->ofs, str_end);
1487 const int bytes = next_utf8 - (str + but->ofs);
1488
1489 but->ofs += bytes;
1490}
1491
1497static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
1498 char *str,
1499 const size_t max_len,
1500 const float okwidth,
1501 const char *sep,
1502 const int sep_len,
1503 const float sep_strwidth,
1504 size_t *r_final_len)
1505{
1506 BLI_assert(str[0]);
1507
1508 /* How many BYTES (not characters) of this UTF8 string can fit, along with appended ellipsis. */
1509 int l_end = BLF_width_to_strlen(
1510 fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, nullptr);
1511
1512 if (l_end > 0) {
1513 /* At least one character, so clip and add the ellipsis. */
1514 memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
1515 if (r_final_len) {
1516 *r_final_len = size_t(l_end) + sep_len;
1517 }
1518 }
1519 else {
1520 /* Otherwise fit as much as we can without adding an ellipsis. */
1521 l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, nullptr);
1522 str[l_end] = '\0';
1523 if (r_final_len) {
1524 *r_final_len = size_t(l_end);
1525 }
1526 }
1527}
1528
1530 char *str,
1531 float okwidth,
1532 const float minwidth,
1533 const size_t max_len,
1534 const char rpart_sep,
1535 const bool clip_right_if_tight)
1536{
1537 BLI_assert(str[0]);
1538
1539 /* need to set this first */
1540 UI_fontstyle_set(fstyle);
1541
1542 float strwidth = BLF_width(fstyle->uifont_id, str, max_len);
1543
1544 if ((okwidth > 0.0f) && (strwidth > okwidth)) {
1545 const char sep[] = BLI_STR_UTF8_HORIZONTAL_ELLIPSIS;
1546 const int sep_len = sizeof(sep) - 1;
1547 const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
1548
1549 char *rpart = nullptr, rpart_buf[UI_MAX_DRAW_STR];
1550 float rpart_width = 0.0f;
1551 size_t rpart_len = 0;
1552 size_t final_lpart_len;
1553
1554 if (rpart_sep) {
1555 rpart = strrchr(str, rpart_sep);
1556
1557 if (rpart) {
1558 rpart_len = strlen(rpart);
1559 rpart_width = BLF_width(fstyle->uifont_id, rpart, rpart_len);
1560 okwidth -= rpart_width;
1561 strwidth -= rpart_width;
1562
1563 if (okwidth < 0.0f) {
1564 /* Not enough place for actual label, just display protected right part.
1565 * Here just for safety, should never happen in real life! */
1566 memmove(str, rpart, rpart_len + 1);
1567 rpart = nullptr;
1568 okwidth += rpart_width;
1569 strwidth = rpart_width;
1570 }
1571 }
1572 }
1573
1574 const float parts_strwidth = (okwidth - sep_strwidth) / 2.0f;
1575
1576 if (rpart) {
1577 STRNCPY(rpart_buf, rpart);
1578 *rpart = '\0';
1579 rpart = rpart_buf;
1580 }
1581
1582 const size_t l_end = BLF_width_to_strlen(
1583 fstyle->uifont_id, str, max_len, parts_strwidth, nullptr);
1584 if (clip_right_if_tight &&
1585 (l_end < 10 || min_ff(parts_strwidth, strwidth - okwidth) < minwidth))
1586 {
1587 /* If we really have no place, or we would clip a very small piece of string in the middle,
1588 * only show start of string.
1589 */
1591 fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
1592 }
1593 else {
1594 size_t r_offset, r_len;
1595
1596 r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, nullptr);
1597 r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */
1598
1599 if (l_end + sep_len + r_len + rpart_len > max_len) {
1600 /* Corner case, the str already takes all available mem,
1601 * and the ellipsis chars would actually add more chars.
1602 * Better to just trim one or two letters to the right in this case...
1603 * NOTE: with a single-char ellipsis, this should never happen! But better be safe
1604 * here...
1605 */
1607 fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
1608 }
1609 else {
1610 memmove(str + l_end + sep_len, str + r_offset, r_len);
1611 memcpy(str + l_end, sep, sep_len);
1612 /* -1 to remove trailing '\0'! */
1613 final_lpart_len = size_t(l_end + sep_len + r_len - 1);
1614
1615/* Seems like this was only needed because of an error in #BLF_width_to_rstrlen(), not because of
1616 * integer imprecision. See PR #135239. */
1617#if 0
1618 while (BLF_width(fstyle->uifont_id, str, max_len) > okwidth) {
1619 /* This will happen because a lot of string width processing is done in integer pixels,
1620 * which can introduce a rather high error in the end (about 2 pixels or so).
1621 * Only one char removal shall ever be needed in real-life situation... */
1622 r_len--;
1623 final_lpart_len--;
1624 char *c = str + l_end + sep_len;
1625 memmove(c, c + 1, r_len);
1626 }
1627#endif
1628 }
1629 }
1630
1631 if (rpart) {
1632 /* Add back preserved right part to our shorten str. */
1633 memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */
1634 okwidth += rpart_width;
1635 }
1636
1637 strwidth = BLF_width(fstyle->uifont_id, str, max_len);
1638 }
1639
1640 /* The following assert is meant to catch code changes that break this function's result, but
1641 * some wriggle room is fine and needed. Just a couple pixels for large sizes and with some
1642 * settings like "Full" hinting which can move features both left and right a pixel. We could
1643 * probably reduce this to one pixel if we consolidate text output with length measuring. But
1644 * our text string lengths include the last character's right-side bearing anyway, so a string
1645 * can be longer by that amount and still fit visibly in the required space. */
1646 BLI_assert((strwidth <= (okwidth + 2)) || (okwidth <= 0.0f) ||
1647 /* TODO: proper handling of non UTF8 strings. */
1648 (BLI_str_utf8_invalid_byte(str, max_len) != -1));
1649 UNUSED_VARS_NDEBUG(okwidth);
1650
1651 return strwidth;
1652}
1653
1657static void ui_text_clip_middle(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1658{
1659 /* No margin for labels! */
1660 const int border = ELEM(but->type, ButType::Label, ButType::Menu, ButType::Popover) ?
1661 0 :
1662 int(UI_TEXT_CLIP_MARGIN + 0.5f);
1663 const float okwidth = float(max_ii(BLI_rcti_size_x(rect) - border, 0));
1664 const float minwidth = UI_ICON_SIZE / but->block->aspect * 2.0f;
1665
1666 but->ofs = 0;
1667 char new_drawstr[UI_MAX_DRAW_STR];
1668 STRNCPY(new_drawstr, but->drawstr.c_str());
1669 const size_t max_len = sizeof(new_drawstr);
1670 but->strwidth = UI_text_clip_middle_ex(fstyle, new_drawstr, okwidth, minwidth, max_len, '\0');
1671 but->drawstr = new_drawstr;
1672}
1673
1681 uiBut *but,
1682 const rcti *rect,
1683 const char rsep)
1684{
1685 /* No margin for labels! */
1686 const int border = ELEM(but->type, ButType::Label, ButType::Menu, ButType::Popover) ?
1687 0 :
1688 int(UI_TEXT_CLIP_MARGIN + 0.5f);
1689 const float okwidth = float(max_ii(BLI_rcti_size_x(rect) - border, 0));
1690 const float minwidth = UI_ICON_SIZE / but->block->aspect * 2.0f;
1691
1692 but->ofs = 0;
1693 char new_drawstr[UI_MAX_DRAW_STR];
1694 STRNCPY(new_drawstr, but->drawstr.c_str());
1695 const size_t max_len = sizeof(new_drawstr);
1696 but->strwidth = UI_text_clip_middle_ex(fstyle, new_drawstr, okwidth, minwidth, max_len, rsep);
1697 but->drawstr = new_drawstr;
1698}
1699
1701 const uiFontStyle *fstyle,
1702 const char *str,
1703 char *clipped_str_buf,
1704 const size_t clipped_str_buf_maxncpy,
1705 const float max_line_width,
1706 const int max_lines)
1707{
1708 using namespace blender;
1709 BLI_assert(max_lines > 0);
1710
1711 const Vector<StringRef> lines = BLF_string_wrap(
1712 fstyle->uifont_id,
1713 str,
1714 max_line_width,
1716
1717 if (lines.size() <= max_lines) {
1718 return lines;
1719 }
1720
1721 Vector<StringRef> clipped_lines;
1722 clipped_lines.reserve(max_lines);
1723
1724 if (max_lines == 1) {
1725 BLI_strncpy(clipped_str_buf, str, clipped_str_buf_maxncpy);
1726
1728 fstyle, clipped_str_buf, max_line_width, UI_ICON_SIZE, clipped_str_buf_maxncpy, '\0');
1729 clipped_lines.append(clipped_str_buf);
1730 return clipped_lines;
1731 }
1732 if (max_lines == 2) {
1733 clipped_lines.append(lines[0]);
1734 BLI_strncpy(clipped_str_buf, str + lines[0].size(), clipped_str_buf_maxncpy);
1736 clipped_str_buf,
1737 max_line_width,
1739 clipped_str_buf_maxncpy,
1740 '\0',
1741 false);
1742 clipped_lines.append(clipped_str_buf);
1743 return clipped_lines;
1744 }
1745
1746 /* The line in the middle that will get the "..." (rounded upwards, so will use the first line of
1747 * the second half if the number of lines is even) */
1748 const int middle_index = max_lines / 2;
1749
1750 /* Take the lines until the middle line with the "..." as is. */
1751 for (int i = 0; i < middle_index; i++) {
1752 clipped_lines.append(lines[i]);
1753 }
1754
1755 /* Clip the middle of the middle line. */
1756 {
1757 BLI_strncpy(clipped_str_buf, lines[middle_index].data(), clipped_str_buf_maxncpy);
1759 clipped_str_buf,
1760 max_line_width,
1762 clipped_str_buf_maxncpy,
1763 '\0',
1764 false);
1765 clipped_lines.append(clipped_str_buf);
1766 }
1767
1768 /* All remaining lines should be completely filled, including the last one. So fill lines
1769 * backwards, and append them to #clipped_lines in the correct order afterwards. */
1770 if ((middle_index + 1) < max_lines) {
1771 const char *remaining = lines[middle_index + 1].data();
1772 size_t remaining_len = strlen(remaining);
1773 std::list<StringRef> last_lines;
1774 for (int i = 0; i < max_lines - (middle_index + 1) && remaining_len; i++) {
1775 size_t offset = BLF_width_to_rstrlen(
1776 fstyle->uifont_id, remaining, remaining_len, max_line_width, nullptr);
1777 size_t line_len = remaining_len - offset;
1778 last_lines.emplace_front(remaining + offset, int64_t(line_len));
1779 remaining_len = offset;
1780 }
1781
1782 for (StringRef line : last_lines) {
1783 clipped_lines.append(line);
1784 }
1785 }
1786
1787 return clipped_lines;
1788}
1789
1793static void ui_text_clip_cursor(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1794{
1795 const int border = int(UI_TEXT_CLIP_MARGIN + 0.5f);
1796 const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
1797
1798 BLI_assert(but->editstr && but->pos >= 0);
1799
1800 /* need to set this first */
1801 UI_fontstyle_set(fstyle);
1802
1803 /* define ofs dynamically */
1804 but->ofs = std::min(but->ofs, but->pos);
1805
1806 if (BLF_width(fstyle->uifont_id, but->editstr, INT_MAX) <= okwidth) {
1807 but->ofs = 0;
1808 }
1809
1810 but->strwidth = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, INT_MAX);
1811
1812 if (but->strwidth > okwidth) {
1813 const int editstr_len = strlen(but->editstr);
1814 int len = editstr_len;
1815
1816 while (but->strwidth > okwidth) {
1817 float width;
1818
1819 /* string position of cursor */
1820 width = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, (but->pos - but->ofs));
1821
1822 /* if cursor is at 20 pixels of right side button we clip left */
1823 if (width > okwidth - 20) {
1824 ui_text_clip_give_next_off(but, but->editstr, but->editstr + editstr_len);
1825 }
1826 else {
1827 /* shift string to the left */
1828 if (width < 20 && but->ofs > 0) {
1830 }
1833 }
1834
1835 but->strwidth = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, len - but->ofs);
1836
1837 if (but->strwidth < 10) {
1838 break;
1839 }
1840 }
1841 }
1842}
1843
1849static void ui_text_clip_right_label(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1850{
1851 const int border = UI_TEXT_CLIP_MARGIN + 1;
1852 const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
1853
1854 int drawstr_len = but->drawstr.size();
1855 char new_drawstr[UI_MAX_DRAW_STR];
1856 STRNCPY(new_drawstr, but->drawstr.c_str());
1857
1858 const char *cpend = new_drawstr + drawstr_len;
1859
1860 /* need to set this first */
1861 UI_fontstyle_set(fstyle);
1862
1863 but->strwidth = BLF_width(fstyle->uifont_id, new_drawstr, drawstr_len);
1864
1865 /* The string already fits, so do nothing. */
1866 if (but->strwidth <= okwidth) {
1867 return;
1868 }
1869
1870 const char sep[] = BLI_STR_UTF8_HORIZONTAL_ELLIPSIS;
1871 const int sep_len = sizeof(sep) - 1;
1872 const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
1873
1874 /* Assume the string will have an ellipsis for initial tests. */
1875 but->strwidth += sep_strwidth;
1876
1877 but->ofs = 0;
1878
1879 /* First shorten number-buttons eg,
1880 * Translucency: 0.000
1881 * becomes
1882 * Trans: 0.000
1883 */
1884
1885 /* find the space after ':' separator */
1886 char *cpoin = strrchr(new_drawstr, ':');
1887
1888 if (cpoin && (cpoin < cpend - 2)) {
1889 char *cp2 = cpoin;
1890
1891 /* chop off the leading text, starting from the right */
1892 while (but->strwidth > okwidth && cp2 > new_drawstr) {
1893 const char *prev_utf8 = BLI_str_find_prev_char_utf8(cp2, new_drawstr);
1894 const int bytes = cp2 - prev_utf8;
1895
1896 /* shift the text after and including cp2 back by 1 char,
1897 * +1 to include null terminator */
1898 memmove(cp2 - bytes, cp2, drawstr_len + 1);
1899 cp2 -= bytes;
1900
1901 drawstr_len -= bytes;
1902
1903 but->strwidth = BLF_width(fstyle->uifont_id,
1904 new_drawstr + but->ofs,
1905 sizeof(new_drawstr) - but->ofs) +
1906 sep_strwidth;
1907 if (but->strwidth < sep_strwidth) {
1908 break;
1909 }
1910 }
1911
1912 /* after the leading text is gone, chop off the : and following space, with ofs */
1913 while ((but->strwidth > okwidth) && (but->ofs < 2)) {
1914 ui_text_clip_give_next_off(but, new_drawstr, new_drawstr + drawstr_len);
1915 but->strwidth = BLF_width(
1916 fstyle->uifont_id, new_drawstr + but->ofs, sizeof(new_drawstr) - but->ofs);
1917 if (but->strwidth < 10) {
1918 break;
1919 }
1920 }
1921 }
1922
1923 /* Now just remove trailing chars */
1924 /* once the label's gone, chop off the least significant digits */
1925 if (but->strwidth > okwidth) {
1926 float strwidth;
1927 drawstr_len = BLF_width_to_strlen(fstyle->uifont_id,
1928 new_drawstr + but->ofs,
1929 drawstr_len - but->ofs,
1930 okwidth,
1931 &strwidth) +
1932 but->ofs;
1933 but->strwidth = strwidth;
1934 new_drawstr[drawstr_len] = 0;
1935 }
1936
1937 cpoin = strrchr(new_drawstr, ':');
1938 if (cpoin && (cpoin - new_drawstr > 0) && (drawstr_len < (sizeof(new_drawstr) - sep_len))) {
1939 /* We shortened the string and still have a colon, so insert ellipsis. */
1940 memmove(cpoin + sep_len, cpoin, cpend - cpoin);
1941 memcpy(cpoin, sep, sep_len);
1942 but->strwidth = BLF_width(
1943 fstyle->uifont_id, new_drawstr + but->ofs, sizeof(new_drawstr) - but->ofs);
1944 }
1945
1946 but->drawstr = new_drawstr;
1947}
1948
1949#ifdef WITH_INPUT_IME
1950static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
1951 const uiWidgetColors *wcol,
1952 const uiBut *but,
1953 const rcti *rect,
1954 const wmIMEData *ime_data,
1955 const char *drawstr)
1956{
1957 int ofs_x, width;
1958 int rect_x = BLI_rcti_size_x(rect);
1959 int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end;
1960 float fcol[4];
1961
1962 if (drawstr[0] != 0) {
1963 if (but->pos >= but->ofs) {
1964 ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
1965 }
1966 else {
1967 ofs_x = 0;
1968 }
1969
1970 width = BLF_width(
1971 fstyle->uifont_id, drawstr + but->ofs, ime_data->composite.size() + but->pos - but->ofs);
1972
1973 rgba_uchar_to_float(fcol, wcol->text);
1974 UI_draw_text_underline(rect->xmin + ofs_x,
1975 rect->ymin + 6 * U.pixelsize,
1976 min_ii(width, rect_x - 2) - ofs_x,
1977 1,
1978 fcol);
1979
1980 /* draw the thick line */
1981 if (sel_start != -1 && sel_end != -1) {
1982 sel_end -= sel_start;
1983 sel_start += but->pos;
1984
1985 if (sel_start >= but->ofs) {
1986 ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_start - but->ofs);
1987 }
1988 else {
1989 ofs_x = 0;
1990 }
1991
1992 width = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_end + sel_start - but->ofs);
1993
1994 UI_draw_text_underline(rect->xmin + ofs_x,
1995 rect->ymin + 6 * U.pixelsize,
1996 min_ii(width, rect_x - 2) - ofs_x,
1997 2,
1998 fcol);
1999 }
2000 }
2001}
2002#endif /* WITH_INPUT_IME */
2003
2004static void widget_draw_text(const uiFontStyle *fstyle,
2005 const uiWidgetColors *wcol,
2006 uiBut *but,
2007 rcti *rect)
2008{
2009 int drawstr_left_len = UI_MAX_DRAW_STR;
2010 const char *drawstr = but->drawstr.c_str();
2011 const char *drawstr_right = nullptr;
2012 bool use_right_only = false;
2013 const char *indeterminate_str = UI_VALUE_INDETERMINATE_CHAR;
2014
2015#ifdef WITH_INPUT_IME
2016 const wmIMEData *ime_data;
2017#endif
2018
2019 UI_fontstyle_set(fstyle);
2020
2021 eFontStyle_Align align;
2022 if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT)) {
2023 align = UI_STYLE_TEXT_LEFT;
2024 }
2025 else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
2026 align = UI_STYLE_TEXT_RIGHT;
2027 }
2028 else {
2029 align = UI_STYLE_TEXT_CENTER;
2030 }
2031
2032 /* Special case: when we're entering text for multiple buttons,
2033 * don't draw the text for any of the multi-editing buttons */
2034 if (UNLIKELY(but->flag & UI_BUT_DRAG_MULTI)) {
2035 uiBut *but_edit = ui_but_drag_multi_edit_get(but);
2036 if (but_edit) {
2037 drawstr = but_edit->editstr;
2038 align = UI_STYLE_TEXT_LEFT;
2039 }
2040 }
2041 else {
2042 if (but->editstr) {
2043 /* The maximum length isn't used in this case,
2044 * we rely on string being null terminated. */
2045 drawstr_left_len = INT_MAX;
2046
2047#ifdef WITH_INPUT_IME
2048 /* FIXME: IME is modifying `const char *drawstr`! */
2049 ime_data = ui_but_ime_data_get(but);
2050
2051 if (ime_data && ime_data->composite.size()) {
2052 /* insert composite string into cursor pos */
2053 char tmp_drawstr[UI_MAX_DRAW_STR];
2054 STRNCPY(tmp_drawstr, drawstr);
2055 BLI_snprintf(tmp_drawstr,
2056 sizeof(tmp_drawstr),
2057 "%.*s%s%s",
2058 but->pos,
2059 but->editstr,
2060 ime_data->composite.c_str(),
2061 but->editstr + but->pos);
2062 but->drawstr = tmp_drawstr;
2063 drawstr = but->drawstr.c_str();
2064 }
2065 else
2066#endif
2067 {
2068 drawstr = but->editstr;
2069 }
2070 }
2071 }
2072
2073 /* If not editing and indeterminate, show dash. */
2074 if (but->drawflag & UI_BUT_INDETERMINATE && !but->editstr &&
2075 ELEM(but->type,
2081 {
2082 drawstr = indeterminate_str;
2083 drawstr_left_len = strlen(drawstr);
2084 align = UI_STYLE_TEXT_CENTER;
2085 }
2086
2087 /* text button selection, cursor, composite underline */
2088 if (but->editstr && but->pos != -1) {
2089 int but_pos_ofs;
2090
2091#ifdef WITH_INPUT_IME
2092 bool ime_reposition_window = false;
2093 int ime_win_x, ime_win_y;
2094#endif
2095
2096 /* text button selection */
2097 if ((but->selend - but->selsta) != 0 && drawstr[0] != 0) {
2098 /* We are drawing on top of widget bases. Flush cache. */
2102 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
2105 const auto boxes = BLF_str_selection_boxes(
2106 fstyle->uifont_id,
2107 drawstr + but->ofs,
2108 strlen(drawstr + but->ofs),
2109 (but->selsta >= but->ofs) ? but->selsta - but->ofs : 0,
2110 but->selend - std::max(but->ofs, but->selsta));
2111 for (auto bounds : boxes) {
2112 immRectf(pos,
2113 rect->xmin + bounds.min,
2114 rect->ymin + U.pixelsize,
2115 std::min(rect->xmin + bounds.max, rect->xmax - 2),
2116 rect->ymax - U.pixelsize);
2117 }
2120
2121#ifdef WITH_INPUT_IME
2122 /* IME candidate window uses selection position. */
2123 if (!ime_reposition_window && boxes.size() > 0) {
2124 ime_reposition_window = true;
2125 ime_win_x = rect->xmin + boxes[0].min;
2126 ime_win_y = rect->ymin + U.pixelsize;
2127 }
2128#endif
2129 }
2130
2131 /* Text cursor position. */
2132 but_pos_ofs = but->pos;
2133
2134#ifdef WITH_INPUT_IME
2135 /* If is IME compositing, move the cursor. */
2136 if (ime_data && ime_data->composite.size() && ime_data->cursor_pos != -1) {
2137 but_pos_ofs += ime_data->cursor_pos;
2138 }
2139#endif
2140
2141 /* Draw text cursor (caret). */
2142 if (but->pos >= but->ofs) {
2143
2144 int t = BLF_str_offset_to_cursor(fstyle->uifont_id,
2145 drawstr + but->ofs,
2147 but_pos_ofs - but->ofs,
2148 max_ii(1, int(U.pixelsize * 2)));
2149
2150 /* We are drawing on top of widget bases. Flush cache. */
2154
2156 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
2158
2160
2161 /* draw cursor */
2162 immRectf(pos,
2163 rect->xmin + t,
2164 rect->ymin + U.pixelsize,
2165 rect->xmin + t + int(2.0f * U.pixelsize),
2166 rect->ymax - U.pixelsize);
2167
2169
2170#ifdef WITH_INPUT_IME
2171 /* IME candidate window uses cursor position. */
2172 if (!ime_reposition_window) {
2173 ime_reposition_window = true;
2174 ime_win_x = rect->xmin + t + 5;
2175 ime_win_y = rect->ymin + 3;
2176 }
2177#endif
2178 }
2179
2180#ifdef WITH_INPUT_IME
2181 /* IME cursor following. */
2182 if (ime_reposition_window) {
2183 ui_but_ime_reposition(but, ime_win_x, ime_win_y, false);
2184 }
2185 if (ime_data && ime_data->composite.size()) {
2186 /* Composite underline. */
2187 widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr);
2188 }
2189#endif
2190 }
2191
2192#if 0
2193 ui_rasterpos_safe(x, y, but->aspect);
2194 transopts = ui_translate_buttons();
2195#endif
2196
2197 bool use_drawstr_right_as_hint = false;
2198
2199 /* cut string in 2 parts - only for menu entries */
2200 if (but->flag & UI_BUT_HAS_SEP_CHAR && (but->editstr == nullptr)) {
2201 drawstr_right = strrchr(drawstr, UI_SEP_CHAR);
2202 if (drawstr_right) {
2203 use_drawstr_right_as_hint = true;
2204 drawstr_left_len = (drawstr_right - drawstr);
2205 drawstr_right++;
2206 }
2207 }
2208
2209#ifdef USE_NUMBUTS_LR_ALIGN
2210 if (!drawstr_right && (but->drawflag & UI_BUT_TEXT_LEFT) &&
2212 /* if we're editing or multi-drag (fake editing), then use left alignment */
2213 (but->editstr == nullptr) && (drawstr == but->drawstr))
2214 {
2215 drawstr_right = strrchr(drawstr + but->ofs, ':');
2216 if (drawstr_right) {
2217 drawstr_right++;
2218 drawstr_left_len = (drawstr_right - drawstr - 1);
2219
2220 while (*drawstr_right == ' ') {
2221 drawstr_right++;
2222 }
2223 }
2224 else {
2225 /* no prefix, even so use only cpoin */
2226 drawstr_right = drawstr + but->ofs;
2227 use_right_only = true;
2228 }
2229 }
2230#endif
2231
2232 if (!use_right_only) {
2233 /* for underline drawing */
2234 int font_xofs, font_yofs;
2235
2236 int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) :
2237 (drawstr_left_len - but->ofs);
2238
2239 if (drawlen > 0) {
2241 params.align = align;
2242 UI_fontstyle_draw_ex(fstyle,
2243 rect,
2244 drawstr + but->ofs,
2245 drawlen,
2246 wcol->text,
2247 &params,
2248 &font_xofs,
2249 &font_yofs,
2250 nullptr);
2251
2252 if (but->menu_key != '\0') {
2253 const char *drawstr_ofs = drawstr + but->ofs;
2254 int ul_index = -1;
2255
2256 {
2257 /* Find upper case, fall back to lower case. */
2258 const char *drawstr_end = drawstr_ofs + drawlen;
2259 const char keys[] = {char(but->menu_key - 32), but->menu_key};
2260 for (int i = 0; i < ARRAY_SIZE(keys); i++) {
2261 const char *drawstr_menu = strchr(drawstr_ofs, keys[i]);
2262 if (drawstr_menu != nullptr && drawstr_menu < drawstr_end) {
2263 ul_index = int(drawstr_menu - drawstr_ofs);
2264 break;
2265 }
2266 }
2267 }
2268
2269 if (ul_index != -1) {
2270 rcti bounds;
2271 if (BLF_str_offset_to_glyph_bounds(fstyle->uifont_id, drawstr_ofs, ul_index, &bounds) &&
2273 {
2274 int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2));
2275 int pos_x = rect->xmin + font_xofs + bounds.xmin +
2276 (bounds.xmax - bounds.xmin - ul_width) / 2;
2277 int pos_y = rect->ymin + font_yofs + bounds.ymin - U.pixelsize;
2278 /* Use text output because direct drawing doesn't always work. See #89246. */
2279 BLF_position(fstyle->uifont_id, float(pos_x), pos_y, 0.0f);
2280 BLF_color4ubv(fstyle->uifont_id, wcol->text);
2281 BLF_draw(fstyle->uifont_id, "_", 2);
2282 }
2283 }
2284 }
2285 }
2286 }
2287
2288 /* Show placeholder text if the input is empty and not being edited. */
2289 if (!drawstr[0] && !but->editstr && ELEM(but->type, ButType::Text, ButType::SearchMenu)) {
2290 const char *placeholder = ui_but_placeholder_get(but);
2291 if (placeholder && placeholder[0]) {
2293 params.align = align;
2294 uiFontStyle style = *fstyle;
2295 style.shadow = 0;
2296 uchar col[4];
2297 copy_v4_v4_uchar(col, wcol->text);
2298 col[3] *= 0.33f;
2300 &style, rect, placeholder, strlen(placeholder), col, &params, nullptr, nullptr, nullptr);
2301 }
2302 }
2303
2304 /* part text right aligned */
2305 if (drawstr_right) {
2306 uchar col[4];
2307 copy_v4_v4_uchar(col, wcol->text);
2308 if (use_drawstr_right_as_hint) {
2309 col[3] *= 0.5f;
2310 }
2311
2312 rect->xmax -= UI_TEXT_CLIP_MARGIN;
2315 UI_fontstyle_draw(fstyle, rect, drawstr_right, UI_MAX_DRAW_STR, col, &params);
2316 }
2317}
2318
2320 uiBut *but,
2321 rcti *rect,
2322 float alpha)
2323{
2324 const float icon_size = ICON_SIZE_FROM_BUTRECT(rect);
2325
2326 /* Offset of icons from the right edge. Keep in sync
2327 * with 'ui_but_extra_operator_icon_mouse_over_get'. */
2329 /* Eyeballed. */
2330 rect->xmax -= 0.2 * icon_size;
2331 }
2332
2333 /* Inverse order, from right to left. */
2335 rcti temp = *rect;
2336 float alpha_this = alpha;
2337
2338 temp.xmin = temp.xmax - icon_size;
2339
2340 if (op_icon->disabled) {
2341 alpha_this *= 0.4f;
2342 }
2343 else if (!op_icon->highlighted) {
2344 alpha_this *= 0.75f;
2345 }
2346
2347 /* Draw the icon at the center, and restore the flags after. */
2348 const int old_drawflags = but->drawflag;
2350 widget_draw_icon(but, op_icon->icon, alpha_this, &temp, wcol->text);
2351 but->drawflag = old_drawflags;
2352
2353 rect->xmax -= icon_size;
2354 }
2355}
2356
2358 const rcti *rect,
2359 uiBut *but,
2360 float alpha)
2361{
2362 /* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */
2363 if (but->custom_data) {
2364 const float scale = 0.9f / but->block->aspect;
2365
2366 float col[4];
2368 col[3] *= alpha;
2369
2373
2375 static_cast<bNodeSocket *>(but->custom_data), rect, col, scale);
2376 }
2377 else {
2378 widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text);
2379 }
2380}
2381
2382/* draws text and icons for buttons */
2383static void widget_draw_text_icon(const uiFontStyle *fstyle,
2384 const uiWidgetColors *wcol,
2385 uiBut *but,
2386 rcti *rect)
2387{
2388 const bool show_menu_icon = ui_but_draw_menu_icon(but);
2389 const float alpha = float(wcol->text[3]) / 255.0f;
2390 char password_str[UI_MAX_DRAW_STR];
2391 bool no_text_padding = but->drawflag & UI_BUT_NO_TEXT_PADDING;
2392
2393 ui_but_text_password_hide(password_str, but, false);
2394
2395 /* check for button text label */
2396 if (ELEM(but->type, ButType::Menu, ButType::Popover) && (but->flag & UI_BUT_NODE_LINK)) {
2397 rcti temp = *rect;
2398 const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */
2399
2400 if (but->drawflag & UI_BUT_ICON_LEFT) {
2401 temp.xmax = rect->xmin + size;
2402 rect->xmin = temp.xmax;
2403 /* Further padding looks off. */
2404 no_text_padding = true;
2405 }
2406 else {
2407 temp.xmin = rect->xmax - size;
2408 rect->xmax = temp.xmin;
2409 }
2410
2411 widget_draw_node_link_socket(wcol, &temp, but, alpha);
2412 }
2413
2414 const uchar *icon_color = (but->col[3] != 0) ? but->col : wcol->text;
2415
2416 /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
2417 * and offset the text label to accommodate it */
2418
2419 /* Big previews with optional text label below */
2420 if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
2421 const BIFIconID icon = ui_but_icon(but);
2422 int icon_size = BLI_rcti_size_y(rect);
2423 int text_size = 0;
2424
2425 /* This is a bit brittle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */
2426 if (icon_size > BLI_rcti_size_x(rect)) {
2427 /* button is not square, it has extra height for label */
2428 text_size = UI_UNIT_Y;
2429 icon_size -= text_size;
2430 }
2431
2432 /* draw icon in rect above the space reserved for the label */
2433 rect->ymin += text_size;
2436 alpha,
2437 but->block->aspect,
2439 rect,
2440 icon_color);
2442
2443 /* offset rect to draw label in */
2444 rect->ymin -= text_size;
2445 rect->ymax -= icon_size;
2446
2447 /* vertically centering text */
2448 rect->ymin += UI_UNIT_Y / 2;
2449 }
2450 /* Icons on the left with optional text label on the right */
2451 else if (but->flag & UI_HAS_ICON || show_menu_icon) {
2452 const bool is_tool = ((but->icon != ICON_NONE) & UI_but_is_tool(but));
2453
2454 /* XXX add way to draw icons at a different size!
2455 * Use small icons for popup. */
2456#ifdef USE_UI_TOOLBAR_HACK
2457 const float aspect_orig = but->block->aspect;
2458 if (is_tool && (but->block->flag & UI_BLOCK_POPOVER)) {
2459 but->block->aspect *= 2.0f;
2460 }
2461#endif
2462
2463 const BIFIconID icon = ui_but_icon(but);
2464 const int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT;
2465 const float icon_size = icon_size_init / (but->block->aspect * UI_INV_SCALE_FAC);
2466 const float icon_padding = 2 * UI_SCALE_FAC;
2467
2468#ifdef USE_UI_TOOLBAR_HACK
2469 if (is_tool) {
2470 /* pass (even if its a menu toolbar) */
2471 but->drawflag |= UI_BUT_TEXT_LEFT;
2472 but->drawflag |= UI_BUT_ICON_LEFT;
2473 }
2474#endif
2475
2476 /* menu item - add some more padding so menus don't feel cramped. it must
2477 * be part of the button so that this area is still clickable */
2478 if (is_tool) {
2479 /* pass (even if its a menu toolbar) */
2480 }
2481 else if (ui_block_is_pie_menu(but->block)) {
2483 rect->xmin += 0.3f * U.widget_unit;
2484 }
2485 }
2486 /* Menu items, but only if they are not icon-only (rare). */
2487 else if (ui_block_is_menu(but->block) && but->drawstr[0]) {
2488 rect->xmin += 0.2f * U.widget_unit;
2489 }
2490
2491 /* By default icon is the color of text, but can optionally override with but->col. */
2492 widget_draw_icon(but, icon, alpha, rect, icon_color);
2493
2494 if (show_menu_icon) {
2496 widget_draw_submenu_tria(but, rect, wcol);
2497 }
2498
2499#ifdef USE_UI_TOOLBAR_HACK
2500 but->block->aspect = aspect_orig;
2501#endif
2502
2503 rect->xmin += round_fl_to_int(icon_size + icon_padding);
2504 }
2505
2506 if (!no_text_padding) {
2507 const int text_padding = round_fl_to_int((UI_TEXT_MARGIN_X * U.widget_unit) /
2508 but->block->aspect);
2509 if (but->editstr) {
2510 rect->xmin += text_padding;
2511 }
2512 else if (but->flag & UI_BUT_DRAG_MULTI) {
2513 const bool text_is_edited = ui_but_drag_multi_edit_get(but) != nullptr;
2514 if (text_is_edited || (but->drawflag & UI_BUT_TEXT_LEFT)) {
2515 rect->xmin += text_padding;
2516 }
2517 }
2518 else if (but->drawflag & UI_BUT_TEXT_LEFT) {
2519 rect->xmin += text_padding;
2520 }
2521 else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
2522 rect->xmax -= text_padding;
2523 }
2524 }
2525 else {
2526 /* In case a separate text label and some other button are placed under each other,
2527 * and the outline of the button does not contrast with the background.
2528 * Add an offset (thickness of the outline) so that the text does not stick out visually. */
2529 if (but->drawflag & UI_BUT_TEXT_LEFT) {
2530 rect->xmin += U.pixelsize;
2531 }
2532 else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
2533 rect->xmax -= U.pixelsize;
2534 }
2535 }
2536
2537 /* Menu contains sub-menu items with triangle icon on their right. Shortcut
2538 * strings should be drawn with some padding to the right then. */
2540 {
2542 }
2543
2544 /* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
2545 widget_draw_extra_icons(wcol, but, rect, alpha);
2546
2547 /* clip but->drawstr to fit in available space */
2548 if (but->editstr && but->pos >= 0) {
2549 ui_text_clip_cursor(fstyle, but, rect);
2550 }
2551 else if (but->drawstr[0] == '\0') {
2552 /* bypass text clipping on icon buttons */
2553 but->ofs = 0;
2554 but->strwidth = 0;
2555 }
2556 else if (ELEM(but->type, ButType::Num, ButType::NumSlider)) {
2557 ui_text_clip_right_label(fstyle, but, rect);
2558 }
2559 else if (but->flag & UI_BUT_HAS_SEP_CHAR) {
2560 /* Clip middle, but protect in all case right part containing the shortcut, if any. */
2562 }
2563 else {
2564 ui_text_clip_middle(fstyle, but, rect);
2565 }
2566
2567 /* Always draw text for text-button cursor. */
2568 widget_draw_text(fstyle, wcol, but, rect);
2569
2570 ui_but_text_password_hide(password_str, but, true);
2571
2572 /* if a widget uses font shadow it has to be deactivated now */
2574}
2575
2576#undef UI_TEXT_CLIP_MARGIN
2577
2579
2580/* -------------------------------------------------------------------- */
2585
2586/* put all widget colors on half alpha, use local storage */
2588{
2589 static uiWidgetColors wcol_theme_s;
2590
2591 wcol_theme_s = *wt->wcol_theme;
2592
2593 const float factor = widget_alpha_factor(state);
2594
2595 wcol_theme_s.outline[3] *= factor;
2596 wcol_theme_s.outline_sel[3] *= factor;
2597 wcol_theme_s.inner[3] *= factor;
2598 wcol_theme_s.inner_sel[3] *= factor;
2599 wcol_theme_s.item[3] *= factor;
2600 wcol_theme_s.text[3] *= factor;
2601 wcol_theme_s.text_sel[3] *= factor;
2602
2603 wt->wcol_theme = &wcol_theme_s;
2604}
2605
2607{
2608 const bool dark = (srgb_to_grayscale_byte(wcol->text) > srgb_to_grayscale_byte(wcol->inner));
2609 color_mul_hsl_v3(wcol->inner, 1.0f, 1.15f, dark ? 1.2f : 1.1f);
2610 color_blend_v4_v4v4(wcol->outline, wcol->outline, wcol->outline_sel, 0.5f);
2611 color_mul_hsl_v3(wcol->outline_sel, 1.0f, 1.15f, 1.15f);
2612 color_mul_hsl_v3(wcol->text, 1.0f, 1.15f, dark ? 1.25f : 0.8f);
2613}
2614
2616 const uiWidgetStateInfo *state,
2617 const blender::ui::EmbossType emboss)
2618{
2619 /* Explicitly require #blender::ui::EmbossType::NoneOrStatus for color blending with no emboss.
2620 */
2621 if (emboss == blender::ui::EmbossType::None) {
2622 return nullptr;
2623 }
2624
2625 if (state->but_drawflag & UI_BUT_ANIMATED_CHANGED) {
2626 return wcol_state->inner_changed_sel;
2627 }
2628 if (state->but_flag & UI_BUT_ANIMATED_KEY) {
2629 return wcol_state->inner_key_sel;
2630 }
2631 if (state->but_flag & UI_BUT_ANIMATED) {
2632 return wcol_state->inner_anim_sel;
2633 }
2634 if (state->but_flag & UI_BUT_DRIVEN) {
2635 return wcol_state->inner_driven_sel;
2636 }
2637 if (state->but_flag & UI_BUT_OVERRIDDEN) {
2638 return wcol_state->inner_overridden_sel;
2639 }
2640 return nullptr;
2641}
2642
2643/* copy colors from theme, and set changes in it based on state */
2645 const uiWidgetStateInfo *state,
2647{
2648 uiWidgetStateColors *wcol_state = wt->wcol_state;
2649
2650 if (state->but_flag & UI_BUT_LIST_ITEM) {
2651 /* Override default widget's colors. */
2652 bTheme *btheme = UI_GetTheme();
2653 wt->wcol_theme = &btheme->tui.wcol_list_item;
2654
2657 }
2658 }
2659
2660 wt->wcol = *(wt->wcol_theme);
2661
2662 const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
2663
2664 if (state->but_flag & UI_SELECT) {
2667 if (color_blend != nullptr) {
2668 color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
2669 }
2670
2672
2673 std::swap(wt->wcol.shadetop, wt->wcol.shadedown);
2674 }
2675 else {
2676 if (state->but_flag & UI_BUT_ACTIVE_DEFAULT) {
2680 }
2681 if (color_blend != nullptr) {
2682 color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
2683 }
2684
2685 /* Add "hover" highlight. Ideally this could apply in all cases,
2686 * even if UI_SELECT. But currently this causes some flickering
2687 * as buttons can be created and updated without respect to mouse
2688 * position and so can draw without UI_HOVER set. See D6503. */
2689 if (state->but_flag & UI_HOVER) {
2691 }
2692 }
2693
2694 if (state->but_flag & UI_BUT_REDALERT) {
2695 if (wt->draw && emboss != blender::ui::EmbossType::None) {
2697 }
2698 else {
2699 uchar red[4];
2701 color_mul_hsl_v3(red, 1.0f, 1.5f, 1.5f);
2702 color_blend_v3_v3(wt->wcol.text, red, 0.5f);
2703 }
2704 }
2705
2706 if (state->but_flag & UI_BUT_DRAG_MULTI) {
2707 /* the button isn't SELECT but we're editing this so draw with sel color */
2710 std::swap(wt->wcol.shadetop, wt->wcol.shadedown);
2711 color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
2712 }
2713
2714 if (state->but_flag & UI_BUT_NODE_ACTIVE) {
2715 const uchar blue[4] = {86, 128, 194};
2716 color_blend_v3_v3(wt->wcol.inner, blue, 0.3f);
2717 }
2718}
2719
2721
2722/* -------------------------------------------------------------------- */
2730
2731static float widget_radius_from_zoom(const float zoom, const uiWidgetColors *wcol)
2732{
2733 return wcol->roundness * U.widget_unit * zoom;
2734}
2735
2736static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wcol)
2737{
2738 return wcol->roundness * BLI_rcti_size_y(rect);
2739}
2740
2742
2743/* -------------------------------------------------------------------- */
2749
2750static bool draw_emboss(const uiBut *but)
2751{
2752 if (but->drawflag & UI_BUT_ALIGN_DOWN) {
2753 return false;
2754 }
2755 uiBut *but_next = but->block->next_but(but);
2756 if (but->type == ButType::Tab &&
2757 (BLI_rctf_size_y(&but->block->rect) > BLI_rctf_size_x(&but->block->rect)) &&
2758 !(but_next == nullptr || but_next->type == ButType::Sepr))
2759 {
2760 /* Vertical tabs, emboss at end and before separators. */
2761 return false;
2762 }
2763
2764 return true;
2765}
2766
2768
2769/* -------------------------------------------------------------------- */
2772
2773/* sliders use special hack which sets 'item' as inner when drawing filling */
2775 const uiWidgetStateInfo *state,
2777{
2778 uiWidgetStateColors *wcol_state = wt->wcol_state;
2779
2780 /* call this for option button */
2781 widget_state(wt, state, emboss);
2782
2783 const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, emboss);
2784 if (color_blend != nullptr) {
2785 /* Set the slider 'item' so that it reflects state settings too.
2786 * De-saturate so the color of the slider doesn't conflict with the blend color,
2787 * which can make the color hard to see when the slider is set to full (see #66102). */
2788 wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = srgb_to_grayscale_byte(wt->wcol.item);
2789 color_blend_v3_v3(wt->wcol.item, color_blend, wcol_state->blend);
2791 }
2792
2793 if (state->but_flag & UI_SELECT) {
2794 std::swap(wt->wcol.shadetop, wt->wcol.shadedown);
2795 }
2796}
2797
2798/* labels use theme colors for text */
2800 const uiWidgetStateInfo *state,
2802{
2803 const bTheme *btheme = UI_GetTheme();
2804
2805 const uiWidgetColors *old_wcol = wt->wcol_theme;
2806 uiWidgetColors wcol_menu_option = *wt->wcol_theme;
2807
2808 /* Override the checkbox theme colors to use the menu-back text colors. */
2809 copy_v3_v3_uchar(wcol_menu_option.text, btheme->tui.wcol_menu_back.text);
2810 copy_v3_v3_uchar(wcol_menu_option.text_sel, btheme->tui.wcol_menu_back.text_sel);
2811 wt->wcol_theme = &wcol_menu_option;
2812
2813 widget_state(wt, state, emboss);
2814
2815 wt->wcol_theme = old_wcol;
2816}
2817
2819 const uiWidgetStateInfo * /*state*/,
2820 blender::ui::EmbossType /*emboss*/)
2821{
2822 wt->wcol = *(wt->wcol_theme);
2823}
2824
2825/* special case, button that calls pulldown */
2827 const uiWidgetStateInfo * /*state*/,
2828 blender::ui::EmbossType /*emboss*/)
2829{
2830 wt->wcol = *(wt->wcol_theme);
2831}
2832
2833/* special case, pie menu items */
2835 const uiWidgetStateInfo *state,
2836 blender::ui::EmbossType /*emboss*/)
2837{
2838 wt->wcol = *(wt->wcol_theme);
2839
2840 if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_HOVER)) {
2841 color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
2843 /* draw the backdrop at low alpha, helps navigating with keys
2844 * when disabled items are active */
2846 wt->wcol.inner[3] = 64;
2847 }
2848 else {
2849 /* regular active */
2850 if (state->but_flag & (UI_SELECT | UI_HOVER)) {
2853 }
2854 else if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
2855 /* regular disabled */
2856 color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
2857 }
2858
2859 if (state->but_flag & UI_SELECT) {
2862 }
2863 else if (state->but_flag & UI_HOVER) {
2866 }
2867 }
2868}
2869
2870/* special case, menu items */
2872 const uiWidgetStateInfo *state,
2873 blender::ui::EmbossType /*emboss*/)
2874{
2875 wt->wcol = *(wt->wcol_theme);
2876
2877 if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_HOVER)) {
2878 /* Hovering over disabled item. */
2879 wt->wcol.text[3] = 128;
2880 color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.5f);
2881 wt->wcol.inner[3] = 64;
2882 }
2883 else if (state->but_flag & UI_BUT_DISABLED) {
2884 /* Regular disabled. */
2885 wt->wcol.text[3] = 128;
2886 }
2887 else if (state->but_flag & UI_BUT_INACTIVE) {
2888 /* Inactive. */
2889 if (state->but_flag & UI_HOVER) {
2890 color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.2f);
2892 wt->wcol.inner[3] = 255;
2893 }
2894 color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
2895 }
2896 else if (state->but_flag & (UI_BUT_ACTIVE_DEFAULT | UI_SELECT_DRAW)) {
2897 /* Currently-selected item. */
2901 }
2902 else if ((state->but_flag & (UI_SELECT | UI_BUT_ICON_PREVIEW)) ==
2904 {
2905 /* Currently-selected list or menu item that is large icon preview. */
2909 }
2910 else if (state->but_flag & UI_HOVER) {
2911 /* Regular hover. */
2912 color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.2f);
2915 wt->wcol.inner[3] = 255;
2916 wt->wcol.text[3] = 255;
2917 }
2918 /* Subtle background for larger preview buttons, so text and icons feel connected (esp. for while
2919 * previews are loading still and a loading icon is displayed). */
2920 else if (state->but_flag & UI_BUT_ICON_PREVIEW) {
2922 wt->wcol.inner[3] = 11;
2923 }
2924}
2925
2927
2928/* -------------------------------------------------------------------- */
2931
2932/* outside of rect, rad to left/bottom/right */
2933static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
2934{
2935 const float outline = U.pixelsize;
2936
2937 rctf shadow_rect;
2938 BLI_rctf_rcti_copy(&shadow_rect, rect);
2939 BLI_rctf_pad(&shadow_rect, -outline, -outline);
2940
2941 UI_draw_roundbox_corner_set(roundboxalign);
2942
2943 const float shadow_alpha = UI_GetTheme()->tui.menu_shadow_fac;
2944 const float shadow_width = UI_ThemeMenuShadowWidth();
2945
2946 ui_draw_dropshadow(&shadow_rect, radin, shadow_width, 1.0f, shadow_alpha);
2947}
2948
2950 const rcti *rect,
2951 const int block_flag,
2952 const int direction,
2953 const float zoom)
2954{
2955 uiWidgetBase wtb;
2956 int roundboxalign = UI_CNR_ALL;
2957
2958 widget_init(&wtb);
2959
2960 /* menu is 2nd level or deeper */
2961 if (block_flag & UI_BLOCK_POPUP) {
2962 // rect->ymin -= 4.0;
2963 // rect->ymax += 4.0;
2964 }
2965 else if (direction & (UI_DIR_DOWN | UI_DIR_UP)) {
2966 if (direction & UI_DIR_DOWN) {
2967 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
2968 }
2969 else {
2970 roundboxalign = (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
2971 }
2972 /* Corner rounding based on secondary direction. */
2973 if (direction & UI_DIR_LEFT) {
2974 roundboxalign |= (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
2975 }
2976 if (direction & UI_DIR_RIGHT) {
2977 roundboxalign |= (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
2978 }
2979 }
2980
2982 const float radius = widget_radius_from_zoom(zoom, wcol);
2983 widget_softshadow(rect, roundboxalign, radius);
2984
2985 round_box_edges(&wtb, roundboxalign, rect, radius);
2986 wtb.draw_emboss = false;
2987 widgetbase_draw(&wtb, wcol);
2988
2990}
2991
2992static void ui_hsv_cursor(const float x,
2993 const float y,
2994 const float zoom,
2995 const float rgb[3],
2996 const float hsv[3],
2997 const bool is_active)
2998{
2999 /* Draw the circle larger while the mouse button is pressed down. */
3000 const float radius = zoom * (((is_active ? 20.0f : 12.0f) * UI_SCALE_FAC) + U.pixelsize);
3001
3004 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3007 immUniformColor3fv(rgb);
3008 immUniform1f("outlineWidth", U.pixelsize);
3009
3010 /* Alpha of outline colors just strong enough to give good contrast. */
3011 const float fg = std::min(1.0f - hsv[2] + 0.2f, 0.8f);
3012 const float bg = hsv[2] / 2.0f;
3013
3014 immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, bg);
3015 immUniform1f("size", radius);
3017 immVertex2f(pos, x, y);
3018 immEnd();
3019
3020 immUniform4f("outlineColor", 1.0f, 1.0f, 1.0f, fg);
3021 immUniform1f("size", radius - 1.0f);
3023 immVertex2f(pos, x, y);
3024 immEnd();
3025
3029}
3030
3032 const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist)
3033{
3034 /* duplication of code... well, simple is better now */
3035 const float centx = BLI_rcti_cent_x_fl(rect);
3036 const float centy = BLI_rcti_cent_y_fl(rect);
3037 const float radius = float(min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect))) / 2.0f;
3038 const float m_delta[2] = {mx - centx, my - centy};
3039 const float dist_sq = len_squared_v2(m_delta);
3040
3041 *r_val_dist = (dist_sq < (radius * radius)) ? sqrtf(dist_sq) / radius : 1.0f;
3042 *r_val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * float(M_PI)) + 0.5f;
3043}
3044
3046 const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *r_xpos, float *r_ypos)
3047{
3048 /* duplication of code... well, simple is better now */
3049 const float centx = BLI_rcti_cent_x_fl(rect);
3050 const float centy = BLI_rcti_cent_y_fl(rect);
3051 const float radius = float(min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect))) / 2.0f;
3052
3053 const float ang = 2.0f * float(M_PI) * hsv[0] + float(M_PI_2);
3054
3055 float radius_t;
3056 if (cpicker->use_color_cubic && (U.color_picker_type == USER_CP_CIRCLE_HSV)) {
3057 radius_t = (1.0f - pow3f(1.0f - hsv[1]));
3058 }
3059 else {
3060 radius_t = hsv[1];
3061 }
3062
3063 const float rad = clamp_f(radius_t, 0.0f, 1.0f) * radius;
3064 *r_xpos = centx + cosf(-ang) * rad;
3065 *r_ypos = centy + sinf(-ang) * rad;
3066}
3067
3068static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
3069{
3070 /* TODO(merwin): reimplement as shader for pixel-perfect colors */
3071
3072 const int tot = 64;
3073 const float radstep = 2.0f * float(M_PI) / float(tot);
3074 const float centx = BLI_rcti_cent_x_fl(rect);
3075 const float centy = BLI_rcti_cent_y_fl(rect);
3076 const float radius = float(min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect))) / 2.0f;
3077
3078 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
3079 float rgb[3], hsv[3], rgb_center[3], rgb_perceptual[3];
3080 const bool is_color_gamma = ui_but_is_color_gamma(but);
3081
3082 /* Initialize for compatibility. */
3083 copy_v3_v3(hsv, cpicker->hsv_perceptual);
3084
3085 /* Compute current hue. */
3086 ui_but_v3_get(but, rgb);
3087 copy_v3_v3(rgb_perceptual, rgb);
3088 ui_scene_linear_to_perceptual_space(but, rgb_perceptual);
3089 ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, hsv);
3090
3091 if (!is_color_gamma) {
3093 }
3094
3095 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
3096
3097 /* exception: if 'lock' is set
3098 * lock the value of the color wheel to 1.
3099 * Useful for color correction tools where you're only interested in hue. */
3100 if (cpicker->use_color_lock) {
3101 if (U.color_picker_type == USER_CP_CIRCLE_HSV) {
3102 hsv[2] = 1.0f;
3103 }
3104 else {
3105 hsv[2] = 0.5f;
3106 }
3107 }
3108
3109 const float hsv_center[3] = {0.0f, 0.0f, hsv[2]};
3110 ui_color_picker_hsv_to_rgb(hsv_center, rgb_center);
3111 ui_perceptual_to_scene_linear_space(but, rgb_center);
3112
3113 if (!is_color_gamma) {
3114 ui_block_cm_to_display_space_v3(but->block, rgb_center);
3115 }
3116
3118 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3120 format, "color", blender::gpu::VertAttrType::SFLOAT_32_32_32);
3121
3123
3124 immBegin(GPU_PRIM_TRI_FAN, tot + 2);
3125 immAttr3fv(color, rgb_center);
3126 immVertex2f(pos, centx, centy);
3127
3128 float ang = 0.0f;
3129 for (int a = 0; a <= tot; a++, ang += radstep) {
3130 const float si = sinf(ang);
3131 const float co = cosf(ang);
3132 float hsv_ang[3];
3133 float rgb_ang[3];
3134
3136 rect, centx + co * radius, centy + si * radius, hsv_ang, hsv_ang + 1);
3137 hsv_ang[2] = hsv[2];
3138
3139 ui_color_picker_hsv_to_rgb(hsv_ang, rgb_ang);
3141
3142 if (!is_color_gamma) {
3144 }
3145
3146 immAttr3fv(color, rgb_ang);
3147 immVertex2f(pos, centx + co * radius, centy + si * radius);
3148 }
3149 immEnd();
3151
3152 /* fully rounded outline */
3154 pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3155
3157
3159 GPU_line_smooth(true);
3160
3162 imm_draw_circle_wire_2d(pos, centx, centy, radius, tot);
3163
3165
3167 GPU_line_smooth(false);
3168
3169 /* cursor */
3170 copy_v3_v3(hsv, cpicker->hsv_perceptual);
3171 ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, hsv);
3172
3173 float xpos, ypos;
3174 ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos);
3175 const float zoom = 1.0f / but->block->aspect;
3176 ui_hsv_cursor(xpos, ypos, zoom, rgb, hsv, but->flag & UI_SELECT);
3177}
3178
3180
3181/* -------------------------------------------------------------------- */
3184
3186 const ColorManagedDisplay *display, float h, float s, float v, float rgb[3])
3187{
3188 hsv_to_rgb(h, s, v, rgb, rgb + 1, rgb + 2);
3189
3190 if (display) {
3193 }
3194}
3195
3196void ui_draw_gradient(const rcti *rect,
3197 const float hsv[3],
3198 const eButGradientType type,
3199 const float alpha,
3200 const ColorManagedDisplay *display)
3201{
3202 /* allows for 4 steps (red->yellow) */
3203 const int steps = 48;
3204 const float color_step = 1.0f / steps;
3205 int a;
3206 const float h = hsv[0], s = hsv[1], v = hsv[2];
3207 float dx, dy, sx1, sx2, sy;
3208 float col0[4][3]; /* left half, rect bottom to top */
3209 float col1[4][3]; /* right half, rect bottom to top */
3210
3211 /* draw series of gouraud rects */
3212
3213 switch (type) {
3214 case UI_GRAD_SV:
3215 ui_draw_gradient_hsv_to_rgb(display, h, 0.0, 0.0, col1[0]);
3216 ui_draw_gradient_hsv_to_rgb(display, h, 0.0, 0.333, col1[1]);
3217 ui_draw_gradient_hsv_to_rgb(display, h, 0.0, 0.666, col1[2]);
3218 ui_draw_gradient_hsv_to_rgb(display, h, 0.0, 1.0, col1[3]);
3219 break;
3220 case UI_GRAD_HV:
3221 ui_draw_gradient_hsv_to_rgb(display, 0.0, s, 0.0, col1[0]);
3222 ui_draw_gradient_hsv_to_rgb(display, 0.0, s, 0.333, col1[1]);
3223 ui_draw_gradient_hsv_to_rgb(display, 0.0, s, 0.666, col1[2]);
3224 ui_draw_gradient_hsv_to_rgb(display, 0.0, s, 1.0, col1[3]);
3225 break;
3226 case UI_GRAD_HS:
3227 ui_draw_gradient_hsv_to_rgb(display, 0.0, 0.0, v, col1[0]);
3228 ui_draw_gradient_hsv_to_rgb(display, 0.0, 0.333, v, col1[1]);
3229 ui_draw_gradient_hsv_to_rgb(display, 0.0, 0.666, v, col1[2]);
3230 ui_draw_gradient_hsv_to_rgb(display, 0.0, 1.0, v, col1[3]);
3231 break;
3232 case UI_GRAD_H:
3233 ui_draw_gradient_hsv_to_rgb(display, 0.0, 1.0, 1.0, col1[0]);
3234 copy_v3_v3(col1[1], col1[0]);
3235 copy_v3_v3(col1[2], col1[0]);
3236 copy_v3_v3(col1[3], col1[0]);
3237 break;
3238 case UI_GRAD_S:
3239 ui_draw_gradient_hsv_to_rgb(display, 1.0, 0.0, 1.0, col1[1]);
3240 copy_v3_v3(col1[0], col1[1]);
3241 copy_v3_v3(col1[2], col1[1]);
3242 copy_v3_v3(col1[3], col1[1]);
3243 break;
3244 case UI_GRAD_V:
3245 ui_draw_gradient_hsv_to_rgb(display, 1.0, 1.0, 0.0, col1[2]);
3246 copy_v3_v3(col1[0], col1[2]);
3247 copy_v3_v3(col1[1], col1[2]);
3248 copy_v3_v3(col1[3], col1[2]);
3249 break;
3250 default:
3251 BLI_assert_msg(0, "invalid 'type' argument");
3252 ui_draw_gradient_hsv_to_rgb(display, 1.0, 1.0, 1.0, col1[2]);
3253 copy_v3_v3(col1[0], col1[2]);
3254 copy_v3_v3(col1[1], col1[2]);
3255 copy_v3_v3(col1[3], col1[2]);
3256 break;
3257 }
3258
3259 /* old below */
3262 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3264 format, "color", blender::gpu::VertAttrType::SFLOAT_32_32_32_32);
3266
3267 immBegin(GPU_PRIM_TRIS, steps * 3 * 6);
3268
3269 /* 0.999 = prevent float inaccuracy for steps */
3270 for (dx = 0.0f; dx < 0.999f; dx += color_step) {
3271 const float dx_next = dx + color_step;
3272
3273 /* previous color */
3274 copy_v3_v3(col0[0], col1[0]);
3275 copy_v3_v3(col0[1], col1[1]);
3276 copy_v3_v3(col0[2], col1[2]);
3277 copy_v3_v3(col0[3], col1[3]);
3278
3279 /* new color */
3280 switch (type) {
3281 case UI_GRAD_SV:
3282 ui_draw_gradient_hsv_to_rgb(display, h, dx, 0.0, col1[0]);
3283 ui_draw_gradient_hsv_to_rgb(display, h, dx, 0.333, col1[1]);
3284 ui_draw_gradient_hsv_to_rgb(display, h, dx, 0.666, col1[2]);
3285 ui_draw_gradient_hsv_to_rgb(display, h, dx, 1.0, col1[3]);
3286 break;
3287 case UI_GRAD_HV:
3288 ui_draw_gradient_hsv_to_rgb(display, dx_next, s, 0.0, col1[0]);
3289 ui_draw_gradient_hsv_to_rgb(display, dx_next, s, 0.333, col1[1]);
3290 ui_draw_gradient_hsv_to_rgb(display, dx_next, s, 0.666, col1[2]);
3291 ui_draw_gradient_hsv_to_rgb(display, dx_next, s, 1.0, col1[3]);
3292 break;
3293 case UI_GRAD_HS:
3294 ui_draw_gradient_hsv_to_rgb(display, dx_next, 0.0, v, col1[0]);
3295 ui_draw_gradient_hsv_to_rgb(display, dx_next, 0.333, v, col1[1]);
3296 ui_draw_gradient_hsv_to_rgb(display, dx_next, 0.666, v, col1[2]);
3297 ui_draw_gradient_hsv_to_rgb(display, dx_next, 1.0, v, col1[3]);
3298 break;
3299 case UI_GRAD_H:
3300 /* annoying but without this the color shifts - could be solved some other way
3301 * - campbell */
3302 ui_draw_gradient_hsv_to_rgb(display, dx_next, 1.0, 1.0, col1[0]);
3303 copy_v3_v3(col1[1], col1[0]);
3304 copy_v3_v3(col1[2], col1[0]);
3305 copy_v3_v3(col1[3], col1[0]);
3306 break;
3307 case UI_GRAD_S:
3308 ui_draw_gradient_hsv_to_rgb(display, h, dx, 1.0, col1[1]);
3309 copy_v3_v3(col1[0], col1[1]);
3310 copy_v3_v3(col1[2], col1[1]);
3311 copy_v3_v3(col1[3], col1[1]);
3312 break;
3313 case UI_GRAD_V:
3314 ui_draw_gradient_hsv_to_rgb(display, h, 1.0, dx, col1[2]);
3315 copy_v3_v3(col1[0], col1[2]);
3316 copy_v3_v3(col1[1], col1[2]);
3317 copy_v3_v3(col1[3], col1[2]);
3318 break;
3319 default:
3320 break;
3321 }
3322
3323 /* rect */
3324 sx1 = rect->xmin + dx * BLI_rcti_size_x(rect);
3325 sx2 = rect->xmin + dx_next * BLI_rcti_size_x(rect);
3326 sy = rect->ymin;
3327 dy = float(BLI_rcti_size_y(rect)) / 3.0f;
3328
3329 for (a = 0; a < 3; a++, sy += dy) {
3330 immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
3331 immVertex2f(pos, sx1, sy);
3332
3333 immAttr4f(col, col1[a][0], col1[a][1], col1[a][2], alpha);
3334 immVertex2f(pos, sx2, sy);
3335
3336 immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
3337 immVertex2f(pos, sx2, sy + dy);
3338
3339 immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
3340 immVertex2f(pos, sx1, sy);
3341
3342 immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
3343 immVertex2f(pos, sx2, sy + dy);
3344
3345 immAttr4f(col, col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
3346 immVertex2f(pos, sx1, sy + dy);
3347 }
3348 }
3349 immEnd();
3350
3352}
3353
3355 const uiButHSVCube *hsv_but, const rcti *rect, const float *hsv, float *r_xp, float *r_yp)
3356{
3357 float x = 0.0f, y = 0.0f;
3358
3359 switch (hsv_but->gradient_type) {
3360 case UI_GRAD_SV:
3361 x = hsv[1];
3362 y = hsv[2];
3363 break;
3364 case UI_GRAD_HV:
3365 x = hsv[0];
3366 y = hsv[2];
3367 break;
3368 case UI_GRAD_HS:
3369 x = hsv[0];
3370 y = hsv[1];
3371 break;
3372 case UI_GRAD_H:
3373 x = hsv[0];
3374 y = 0.5;
3375 break;
3376 case UI_GRAD_S:
3377 x = hsv[1];
3378 y = 0.5;
3379 break;
3380 case UI_GRAD_V:
3381 x = hsv[2];
3382 y = 0.5;
3383 break;
3384 case UI_GRAD_L_ALT:
3385 x = 0.5f;
3386 /* exception only for value strip - use the range set in but->min/max */
3387 y = hsv[2];
3388 break;
3389 case UI_GRAD_V_ALT:
3390 x = 0.5f;
3391 /* exception only for value strip - use the range set in but->min/max */
3392 y = (hsv[2] - hsv_but->softmin) / (hsv_but->softmax - hsv_but->softmin);
3393 break;
3394 case UI_GRAD_NONE:
3396 }
3397
3398 /* cursor */
3399 *r_xp = rect->xmin + x * BLI_rcti_size_x(rect);
3400 *r_yp = rect->ymin + y * BLI_rcti_size_y(rect);
3401}
3402
3403static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
3404{
3405 const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
3406 float rgb[3], rgb_perceptual[3];
3407 float x = 0.0f, y = 0.0f;
3408 const ColorManagedDisplay *display = ui_block_cm_display_get(but->block);
3409 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
3410 float *hsv = cpicker->hsv_perceptual;
3411 float hsv_n[3];
3412
3413 /* Is this the larger color canvas or narrow color slider? */
3414 bool is_canvas = ELEM(hsv_but->gradient_type, UI_GRAD_SV, UI_GRAD_HV, UI_GRAD_HS);
3415
3416 /* Initialize for compatibility. */
3417 copy_v3_v3(hsv_n, hsv);
3418
3419 ui_but_v3_get(but, rgb);
3420 copy_v3_v3(rgb_perceptual, rgb);
3421 ui_scene_linear_to_perceptual_space(but, rgb_perceptual);
3422 rgb_to_hsv_compat_v(rgb_perceptual, hsv_n);
3423
3424 if (!ui_but_is_color_gamma(but)) {
3426 }
3427
3428 ui_draw_gradient(rect, hsv_n, hsv_but->gradient_type, 1.0f, display);
3429
3430 ui_hsvcube_pos_from_vals(hsv_but, rect, hsv_n, &x, &y);
3431
3432 const float zoom = 1.0f / but->block->aspect;
3433
3434 /* outline */
3436 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3438 immUniformColor3ub(0, 0, 0);
3439 imm_draw_box_wire_2d(pos, (rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
3441
3442 if (is_canvas) {
3443 /* Round cursor in the large square area. */
3444 float margin = (4.0f * UI_SCALE_FAC);
3445 CLAMP(x, rect->xmin + margin, rect->xmax - margin);
3446 CLAMP(y, rect->ymin + margin, rect->ymax - margin);
3447 ui_hsv_cursor(x, y, zoom, rgb, hsv, but->flag & UI_SELECT);
3448 }
3449 else {
3450 /* Square indicator in the narrow area. */
3451 rctf rectf;
3452 BLI_rctf_rcti_copy(&rectf, rect);
3453 const float margin = (2.0f * UI_SCALE_FAC);
3454 CLAMP(x, rect->xmin + margin, rect->xmax - margin);
3455 CLAMP(y, rect->ymin + margin, rect->ymax - margin);
3456 rectf.ymax += 1;
3457 const float cursor_width = std::max(BLI_rctf_size_y(&rectf) * 0.35f, 1.0f);
3458 rectf.xmin = x - cursor_width;
3459 rectf.xmax = x + cursor_width;
3460
3461 if (but->flag & UI_SELECT) {
3462 /* Make the indicator larger while the mouse button is pressed. */
3463 rectf.xmin -= U.pixelsize;
3464 rectf.xmax += U.pixelsize;
3465 rectf.ymin -= U.pixelsize;
3466 rectf.ymax += U.pixelsize;
3467 }
3468
3469 const float col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3470 UI_draw_roundbox_4fv(&rectf, false, 0, col);
3471
3472 rectf.xmin += 1.0f;
3473 rectf.xmax -= 1.0f;
3474 const float inner[4] = {1.0f, 1.0f, 1.0f, 1.0f};
3475 const float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3476 UI_draw_roundbox_4fv_ex(&rectf, col2, nullptr, 0.0f, inner, U.pixelsize, 0.0f);
3477 }
3478}
3479
3480/* vertical 'value' slider, using new widget code */
3481static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
3482{
3483 const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
3484 float rgb[3], hsv[3], v;
3485
3486 ui_but_v3_get(but, rgb);
3488
3489 if (hsv_but->gradient_type == UI_GRAD_L_ALT) {
3490 rgb_to_hsl_v(rgb, hsv);
3491 }
3492 else {
3493 rgb_to_hsv_v(rgb, hsv);
3494 }
3495 v = hsv[2];
3496
3497 /* map v from property range to [0,1] */
3498 if (hsv_but->gradient_type == UI_GRAD_V_ALT) {
3499 const float min = but->softmin, max = but->softmax;
3500 v = (v - min) / (max - min);
3501 }
3502
3503 rctf rectf;
3504 BLI_rctf_rcti_copy(&rectf, rect);
3505
3506 const float inner1[4] = {1.0f, 1.0f, 1.0f, 1.0f};
3507 const float inner2[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3508 const float outline[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3509
3510 const float outline_width = (BLI_rctf_size_x(&rectf) < 4.0f) ? 0.0f : 1.0f;
3511 UI_draw_roundbox_4fv_ex(&rectf, inner1, inner2, U.pixelsize, outline, outline_width, 0.0f);
3512
3513 /* cursor */
3514 float y = rect->ymin + v * BLI_rcti_size_y(rect);
3515 CLAMP(y, float(rect->ymin) + (2.0f * UI_SCALE_FAC), float(rect->ymax) - (2.0f * UI_SCALE_FAC));
3516 const float cursor_height = std::max(BLI_rctf_size_x(&rectf) * 0.35f, 1.0f);
3517 rectf.ymin = y - cursor_height;
3518 rectf.ymax = y + cursor_height;
3519 float col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3520
3521 if (but->flag & UI_SELECT) {
3522 /* Enlarge the indicator while the mouse button is pressed down. */
3523 rectf.xmin -= U.pixelsize;
3524 rectf.xmax += U.pixelsize;
3525 rectf.ymin -= U.pixelsize;
3526 rectf.ymax += U.pixelsize;
3527 }
3528
3529 UI_draw_roundbox_4fv(&rectf, false, 0.0f, col);
3530
3531 rectf.ymin += 1.0f;
3532 rectf.ymax -= 1.0f;
3533 const float col2[4] = {v, v, v, 1.0f};
3534 UI_draw_roundbox_4fv_ex(&rectf, col2, nullptr, 0.0f, inner1, U.pixelsize, 0.0f);
3535}
3536
3538static void ui_draw_separator(const uiWidgetColors *wcol, uiBut *but, const rcti *rect)
3539{
3540 const uiButSeparatorLine *but_line = static_cast<uiButSeparatorLine *>(but);
3541 const bool vertical = but_line->is_vertical;
3542 const int mid = vertical ? BLI_rcti_cent_x(rect) : BLI_rcti_cent_y(rect);
3543 const uchar col[4] = {
3544 wcol->text[0],
3545 wcol->text[1],
3546 wcol->text[2],
3547 30,
3548 };
3549
3551 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3553
3556 GPU_line_width(1.0f);
3557
3559
3560 if (vertical) {
3561 immVertex2f(pos, mid, rect->ymin);
3562 immVertex2f(pos, mid, rect->ymax);
3563 }
3564 else {
3565 immVertex2f(pos, rect->xmin, mid);
3566 immVertex2f(pos, rect->xmax, mid);
3567 }
3568
3569 immEnd();
3570
3572
3574}
3575
3577
3578/* -------------------------------------------------------------------- */
3581
3582#define NUM_BUT_PADDING_FACTOR 0.425f
3583
3584static void widget_numbut_draw(const uiBut *but,
3585 uiWidgetColors *wcol,
3586 rcti *rect,
3587 const float zoom,
3588 const uiWidgetStateInfo *state,
3589 int roundboxalign,
3590 bool emboss)
3591{
3592 const float rad = widget_radius_from_zoom(zoom, wcol);
3593 const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
3594
3595 if (state->but_flag & UI_SELECT) {
3596 std::swap(wcol->shadetop, wcol->shadedown);
3597 }
3598
3599 uiWidgetBase wtb;
3600 widget_init(&wtb);
3601
3602 if (!emboss) {
3603 round_box_edges(&wtb, roundboxalign, rect, rad);
3604 }
3605 else {
3606 wtb.draw_inner = false;
3607 wtb.draw_outline = false;
3608 }
3609
3610 /* decoration */
3611 if (((state->but_flag & UI_HOVER) || (U.uiflag2 & USER_ALWAYS_SHOW_NUMBER_ARROWS)) &&
3612 !state->is_text_input)
3613 {
3614 uiWidgetColors wcol_zone;
3615 uiWidgetBase wtb_zone;
3616 rcti rect_zone;
3617 int roundboxalign_zone;
3618
3619 /* left arrow zone */
3620 widget_init(&wtb_zone);
3621 wtb_zone.draw_outline = false;
3622 wtb_zone.draw_emboss = false;
3623
3624 wcol_zone = *wcol;
3625 copy_v3_v3_uchar(wcol_zone.item, wcol->text);
3626 if (!(state->but_flag & UI_HOVER)) {
3627 wcol_zone.item[3] = 180;
3628 }
3629 if (state->but_drawflag & UI_BUT_HOVER_LEFT) {
3630 widget_active_color(&wcol_zone);
3631 }
3632
3633 rect_zone = *rect;
3634 rect_zone.xmax = rect->xmin + handle_width + U.pixelsize;
3635 roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
3636 round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
3637
3638 shape_preset_init_number_arrows(&wtb_zone.tria1, &rect_zone, 0.6f, 'l');
3639 widgetbase_draw(&wtb_zone, &wcol_zone);
3640
3641 /* right arrow zone */
3642 widget_init(&wtb_zone);
3643 wtb_zone.draw_outline = false;
3644 wtb_zone.draw_emboss = false;
3645 wtb_zone.tria1.type = ROUNDBOX_TRIA_ARROWS;
3646
3647 wcol_zone = *wcol;
3648 copy_v3_v3_uchar(wcol_zone.item, wcol->text);
3649 if (!(state->but_flag & UI_HOVER)) {
3650 wcol_zone.item[3] = 180;
3651 }
3652 if (state->but_drawflag & UI_BUT_HOVER_RIGHT) {
3653 widget_active_color(&wcol_zone);
3654 }
3655
3656 rect_zone = *rect;
3657 rect_zone.xmin = rect->xmax - handle_width - U.pixelsize;
3658 roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
3659 round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
3660
3661 shape_preset_init_number_arrows(&wtb_zone.tria2, &rect_zone, 0.6f, 'r');
3662 widgetbase_draw(&wtb_zone, &wcol_zone);
3663
3664 /* middle highlight zone */
3665 widget_init(&wtb_zone);
3666 wtb_zone.draw_outline = false;
3667 wtb_zone.draw_emboss = false;
3668
3669 wcol_zone = *wcol;
3670 copy_v3_v3_uchar(wcol_zone.item, wcol->text);
3671 if ((state->but_flag & UI_HOVER) &&
3672 !(state->but_drawflag & (UI_BUT_HOVER_LEFT | UI_BUT_HOVER_RIGHT)))
3673 {
3674 widget_active_color(&wcol_zone);
3675 }
3676
3677 rect_zone = *rect;
3678 rect_zone.xmin = rect->xmin + handle_width - U.pixelsize;
3679 rect_zone.xmax = rect->xmax - handle_width + U.pixelsize;
3680 round_box_edges(&wtb_zone, 0, &rect_zone, 0);
3681 widgetbase_draw(&wtb_zone, &wcol_zone);
3682
3683 /* outline */
3684 wtb.draw_inner = false;
3685 wtb.draw_emboss = draw_emboss(but);
3686 widgetbase_draw(&wtb, wcol);
3687 }
3688 else {
3689 /* inner and outline */
3690 wtb.draw_emboss = draw_emboss(but);
3691 widgetbase_draw(&wtb, wcol);
3692 }
3693
3694 if (!state->is_text_input) {
3695 const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
3696
3697 rect->xmin += text_padding;
3698 rect->xmax -= text_padding;
3699 }
3700}
3701
3702static void widget_numbut(uiBut *but,
3703 uiWidgetColors *wcol,
3704 rcti *rect,
3705 const uiWidgetStateInfo *state,
3706 int roundboxalign,
3707 const float zoom)
3708{
3709 widget_numbut_draw(but, wcol, rect, zoom, state, roundboxalign, false);
3710}
3711
3713 rcti *rect,
3714 const uiWidgetStateInfo *state,
3715 int roundboxalign,
3716 const float zoom)
3717{
3718 uiWidgetBase wtb;
3719 widget_init(&wtb);
3720
3721 const float rad = widget_radius_from_zoom(zoom, wcol);
3722 round_box_edges(&wtb, roundboxalign, rect, rad);
3723
3724 /* decoration */
3726 /* copy size and center to 2nd tria */
3727 wtb.tria2 = wtb.tria1;
3728
3730 wtb.draw_inner = false;
3731 wtb.draw_outline = false;
3732 wtb.draw_emboss = false;
3733 }
3734
3735 widgetbase_draw(&wtb, wcol);
3736
3737 /* text space, arrows are about 0.6 height of button */
3738 rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
3739}
3740
3744static void widget_menubut_embossn(const uiBut * /*but*/,
3745 uiWidgetColors *wcol,
3746 rcti *rect,
3747 const uiWidgetStateInfo * /*state*/,
3748 int /*roundboxalign*/)
3749{
3750 uiWidgetBase wtb;
3751 widget_init(&wtb);
3752 wtb.draw_inner = false;
3753 wtb.draw_outline = false;
3754
3755 /* decoration */
3757 /* copy size and center to 2nd tria */
3758 wtb.tria2 = wtb.tria1;
3759
3760 widgetbase_draw(&wtb, wcol);
3761}
3762
3766static void widget_numbut_embossn(const uiBut *but,
3767 uiWidgetColors *wcol,
3768 rcti *rect,
3769 const uiWidgetStateInfo *state,
3770 int roundboxalign,
3771 const float zoom)
3772{
3773 widget_numbut_draw(but, wcol, rect, zoom, state, roundboxalign, true);
3774}
3775
3776void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
3777{
3778 uiWidgetBase wtb;
3779
3780 widget_init(&wtb);
3781
3782 /* determine horizontal/vertical */
3783 const bool horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
3784
3785 const float rad = (horizontal) ? wcol->roundness * BLI_rcti_size_y(rect) :
3786 wcol->roundness * BLI_rcti_size_x(rect);
3787
3788 wtb.uniform_params.shade_dir = (horizontal) ? 1.0f : 0.0;
3789
3790 /* draw back part, colors swapped and shading inverted */
3791 if (horizontal) {
3792 std::swap(wcol->shadetop, wcol->shadedown);
3793 }
3794
3795 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
3796 widgetbase_draw(&wtb, wcol);
3797
3798 /* slider */
3799 if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
3800 /* pass */
3801 }
3802 else {
3803 std::swap(wcol->shadetop, wcol->shadedown);
3804
3805 copy_v4_v4_uchar(wcol->inner, wcol->item);
3806
3807 if (wcol->shadetop > wcol->shadedown) {
3808 wcol->shadetop += 20; /* XXX violates themes... */
3809 }
3810 else {
3811 wcol->shadedown += 20;
3812 }
3813
3814 if (state & UI_SCROLL_PRESSED) {
3815 wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
3816 wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
3817 wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
3818 }
3819
3820 /* draw */
3821 wtb.draw_emboss = false; /* only emboss once */
3822
3823 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
3824
3825 if (state & UI_SCROLL_ARROWS) {
3826 const uchar lightness = srgb_to_grayscale_byte(wcol->item);
3827 if (lightness > 70) {
3828 wcol->item[0] = 0;
3829 wcol->item[1] = 0;
3830 wcol->item[2] = 0;
3831 wcol->item[3] = 128;
3832 }
3833 else {
3834 wcol->item[0] = 255;
3835 wcol->item[1] = 255;
3836 wcol->item[2] = 255;
3837 wcol->item[3] = 128;
3838 }
3839
3840 if (horizontal) {
3841 rcti slider_inset = *slider;
3842 slider_inset.xmin += 0.05 * U.widget_unit;
3843 slider_inset.xmax -= 0.05 * U.widget_unit;
3844 shape_preset_init_scroll_circle(&wtb.tria1, &slider_inset, 0.6f, 'l');
3845 shape_preset_init_scroll_circle(&wtb.tria2, &slider_inset, 0.6f, 'r');
3846 }
3847 else {
3848 shape_preset_init_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
3849 shape_preset_init_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
3850 }
3851 }
3852 widgetbase_draw(&wtb, wcol);
3853 }
3854}
3855
3856static void widget_scroll(uiBut *but,
3857 uiWidgetColors *wcol,
3858 rcti *rect,
3859 const uiWidgetStateInfo *state,
3860 int /*roundboxalign*/,
3861 const float /*zoom*/)
3862{
3863 const uiButScrollBar *but_scroll = reinterpret_cast<const uiButScrollBar *>(but);
3864 const float height = but_scroll->visual_height;
3865
3866 /* calculate slider part */
3867 const float value = float(ui_but_value_get(but));
3868
3869 const float size = max_ff((but->softmax + height - but->softmin), 2.0f);
3870
3871 /* position */
3872 rcti rect1 = *rect;
3873
3874 /* determine horizontal/vertical */
3875 const bool horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
3876
3877 if (horizontal) {
3878 const float fac = BLI_rcti_size_x(rect) / size;
3879 rect1.xmin = rect1.xmin + ceilf(fac * (value - but->softmin));
3880 rect1.xmax = rect1.xmin + ceilf(fac * (height - but->softmin));
3881
3882 /* Ensure minimum size. */
3883 const float min = BLI_rcti_size_y(rect);
3884
3885 if (BLI_rcti_size_x(&rect1) < min) {
3886 rect1.xmax = rect1.xmin + min;
3887
3888 if (rect1.xmax > rect->xmax) {
3889 rect1.xmax = rect->xmax;
3890 rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
3891 }
3892 }
3893 }
3894 else {
3895 const float fac = BLI_rcti_size_y(rect) / size;
3896 rect1.ymax = rect1.ymax - ceilf(fac * (value - but->softmin));
3897 rect1.ymin = rect1.ymax - ceilf(fac * (height - but->softmin));
3898
3899 /* Ensure minimum size. */
3900 const float min = BLI_rcti_size_x(rect);
3901
3902 if (BLI_rcti_size_y(&rect1) < min) {
3903 rect1.ymax = rect1.ymin + min;
3904
3905 if (rect1.ymax > rect->ymax) {
3906 rect1.ymax = rect->ymax;
3907 rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
3908 }
3909 }
3910 }
3911
3912 UI_draw_widget_scroll(wcol, rect, &rect1, (state->but_flag & UI_SELECT) ? UI_SCROLL_PRESSED : 0);
3913}
3914
3915static void widget_progress_type_bar(uiButProgress *but_progress,
3916 uiWidgetColors *wcol,
3917 rcti *rect,
3918 int roundboxalign,
3919 const float zoom)
3920{
3921 rcti rect_prog = *rect, rect_bar = *rect;
3922
3923 uiWidgetBase wtb, wtb_bar;
3924 widget_init(&wtb);
3925 widget_init(&wtb_bar);
3926
3927 /* round corners */
3928 const float factor = but_progress->progress_factor;
3929 const float ofs = widget_radius_from_zoom(zoom, wcol);
3930 float w = factor * BLI_rcti_size_x(&rect_prog);
3931
3932 /* Ensure minimum size. */
3933 w = std::max(w, ofs);
3934
3935 rect_bar.xmax = rect_bar.xmin + w;
3936
3937 round_box_edges(&wtb, roundboxalign, &rect_prog, ofs);
3938 round_box_edges(&wtb_bar, roundboxalign, &rect_bar, ofs);
3939
3940 wtb.draw_outline = true;
3941 widgetbase_draw(&wtb, wcol);
3942
3943 /* "slider" bar color */
3944 copy_v3_v3_uchar(wcol->inner, wcol->item);
3945 widgetbase_draw(&wtb_bar, wcol);
3946}
3947
3952 uiWidgetColors *wcol,
3953 rcti *rect)
3954{
3955 const float ring_width = 0.6; /* 0.0 would be a pie. */
3956 const float outer_rad = (rect->ymax - rect->ymin) / 2.0f;
3957 const float inner_rad = outer_rad * ring_width;
3958 const float x = rect->xmin + outer_rad;
3959 const float y = rect->ymin + outer_rad;
3960 const float start = 0.0f;
3961 const float end = but_progress->progress_factor * 360.0f;
3964 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3968
3969 for (int i = 0; i < UI_PIXEL_AA_JITTER; i++) {
3971 x + ui_pixel_jitter[i][0],
3972 y + ui_pixel_jitter[i][1],
3973 inner_rad,
3974 outer_rad,
3975 48,
3976 start,
3977 end);
3978 }
3980
3981 if (but_progress->drawstr[0]) {
3982 rect->xmin += UI_UNIT_X;
3983 }
3984}
3985
3987 uiWidgetColors *wcol,
3988 rcti *rect,
3989 const uiWidgetStateInfo * /*state*/,
3990 int roundboxalign,
3991 const float zoom)
3992{
3993 uiButProgress *but_progress = static_cast<uiButProgress *>(but);
3994 switch (but_progress->progress_type) {
3996 widget_progress_type_bar(but_progress, wcol, rect, roundboxalign, zoom);
3997 break;
3998 }
4000 widget_progress_type_ring(but_progress, wcol, rect);
4001 break;
4002 }
4003 }
4004}
4005
4006static void widget_nodesocket(uiBut *but,
4007 uiWidgetColors * /*wcol*/,
4008 rcti *rect,
4009 const uiWidgetStateInfo * /*state*/,
4010 int /*roundboxalign*/,
4011 const float zoom)
4012{
4013 blender::ColorTheme4f socket_color;
4014 rgba_uchar_to_float(socket_color, but->col);
4015
4016 blender::ColorTheme4f outline_color;
4018 outline_color.a = 1.0f;
4019
4020 const int cent_x = BLI_rcti_cent_x(rect);
4021 const int cent_y = BLI_rcti_cent_y(rect);
4022 const int socket_radius = 0.25f * BLI_rcti_size_y(rect);
4023
4024 rctf socket_rect;
4025 socket_rect.xmin = cent_x - socket_radius;
4026 socket_rect.xmax = cent_x + socket_radius;
4027 socket_rect.ymin = cent_y - socket_radius;
4028 socket_rect.ymax = cent_y + socket_radius;
4029
4033
4035 socket_color,
4036 outline_color,
4037 U.pixelsize,
4039 1.0f / zoom);
4040}
4041
4042static void widget_numslider(uiBut *but,
4043 uiWidgetColors *wcol,
4044 rcti *rect,
4045 const uiWidgetStateInfo *state,
4046 int roundboxalign,
4047 const float zoom)
4048{
4049 uiWidgetBase wtb, wtb1;
4050 widget_init(&wtb);
4051 widget_init(&wtb1);
4052
4053 /* Backdrop first. */
4054 const float rad = widget_radius_from_zoom(zoom, wcol);
4055 round_box_edges(&wtb, roundboxalign, rect, rad);
4056
4057 wtb.draw_outline = false;
4058 widgetbase_draw(&wtb, wcol);
4059
4060 /* Draw slider part only when not in text editing. */
4061 if (!state->is_text_input && !(but->drawflag & UI_BUT_INDETERMINATE)) {
4062 int roundboxalign_slider = roundboxalign;
4063
4064 uchar outline[3];
4065 copy_v3_v3_uchar(outline, wcol->outline);
4066 copy_v3_v3_uchar(wcol->outline, wcol->item);
4067 copy_v3_v3_uchar(wcol->inner, wcol->item);
4068
4069 if (!(state->but_flag & UI_SELECT)) {
4070 std::swap(wcol->shadetop, wcol->shadedown);
4071 }
4072
4073 rcti rect1 = *rect;
4074 float factor, factor_ui;
4075 float factor_discard = 1.0f; /* No discard. */
4076 const float value = float(ui_but_value_get(but));
4077 const float softmin = but->softmin;
4078 const float softmax = but->softmax;
4079 const float softrange = softmax - softmin;
4080 const PropertyScaleType scale_type = ui_but_scale_type(but);
4081
4082 switch (scale_type) {
4083 case PROP_SCALE_LINEAR: {
4084 if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) {
4085 factor = value / softmax;
4086 }
4087 else {
4088 factor = (value - softmin) / softrange;
4089 }
4090 break;
4091 }
4092 case PROP_SCALE_LOG: {
4093 const float logmin = fmaxf(softmin, 0.5e-8f);
4094 const float base = softmax / logmin;
4095 factor = logf(value / logmin) / logf(base);
4096 break;
4097 }
4098 case PROP_SCALE_CUBIC: {
4099 const float cubicmin = cube_f(softmin);
4100 const float cubicmax = cube_f(softmax);
4101 const float cubicrange = cubicmax - cubicmin;
4102 const float f = (value - softmin) * cubicrange / softrange + cubicmin;
4103 factor = (cbrtf(f) - softmin) / softrange;
4104 break;
4105 }
4106 }
4107
4108 const float width = float(BLI_rcti_size_x(rect));
4109 factor_ui = factor * width;
4110 /* The rectangle width needs to be at least twice the corner radius for the round corners
4111 * to be drawn properly. */
4112 const float min_width = 2.0f * rad;
4113
4114 if (factor_ui > width - rad) {
4115 /* Left part + middle part + right part. */
4116 factor_discard = factor;
4117 }
4118 else if (factor_ui > min_width) {
4119 /* Left part + middle part. */
4120 roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
4121 rect1.xmax = rect1.xmin + factor_ui;
4122 }
4123 else {
4124 /* Left part */
4125 roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
4126 rect1.xmax = rect1.xmin + min_width;
4127 factor_discard = factor_ui / min_width;
4128 }
4129
4130 round_box_edges(&wtb1, roundboxalign_slider, &rect1, rad);
4131 wtb1.draw_outline = false;
4132 widgetbase_set_uniform_discard_factor(&wtb1, factor_discard);
4133 widgetbase_draw(&wtb1, wcol);
4134
4135 copy_v3_v3_uchar(wcol->outline, outline);
4136
4137 if (!(state->but_flag & UI_SELECT)) {
4138 std::swap(wcol->shadetop, wcol->shadedown);
4139 }
4140 }
4141
4142 /* Outline. */
4143 wtb.draw_outline = true;
4144 wtb.draw_inner = false;
4145 widgetbase_draw(&wtb, wcol);
4146
4147 /* Add space at either side of the button so text aligns with number-buttons
4148 * (which have arrow icons). */
4149 if (!state->is_text_input) {
4150 const float text_padding = NUM_BUT_PADDING_FACTOR * BLI_rcti_size_y(rect);
4151 rect->xmax -= text_padding;
4152 rect->xmin += text_padding;
4153 }
4154}
4155
4156/* I think 3 is sufficient border to indicate keyed status */
4157#define SWATCH_KEYED_BORDER 3
4158
4159static void widget_swatch(uiBut *but,
4160 uiWidgetColors *wcol,
4161 rcti *rect,
4162 const uiWidgetStateInfo *state,
4163 int roundboxalign,
4164 const float zoom)
4165{
4167 uiButColor *color_but = (uiButColor *)but;
4168 float col[4];
4169
4170 col[3] = 1.0f;
4171
4172 if (but->rnaprop) {
4173 BLI_assert(but->rnaindex == -1);
4174
4175 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) >= 4) {
4176 col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
4177 }
4178 }
4179
4180 uiWidgetBase wtb;
4181 widget_init(&wtb);
4182
4183 const float rad = widget_radius_from_zoom(zoom, wcol);
4184 round_box_edges(&wtb, roundboxalign, rect, rad);
4185
4186 ui_but_v3_get(but, col);
4187
4188 if (but->drawflag & UI_BUT_INDETERMINATE) {
4189 col[0] = col[1] = col[2] = col[3] = 0.5f;
4190 }
4191
4194 (state->but_drawflag & UI_BUT_ANIMATED_CHANGED))
4195 {
4196 /* draw based on state - color for keyed etc */
4197 widgetbase_draw(&wtb, wcol);
4198
4199 /* inset to draw swatch color */
4200 rect->xmin += SWATCH_KEYED_BORDER;
4201 rect->xmax -= SWATCH_KEYED_BORDER;
4202 rect->ymin += SWATCH_KEYED_BORDER;
4203 rect->ymax -= SWATCH_KEYED_BORDER;
4204
4205 round_box_edges(&wtb, roundboxalign, rect, rad);
4206 }
4207
4208 if (!ui_but_is_color_gamma(but)) {
4210 }
4211
4212 const bool show_alpha_checkers = col[3] < 1.0f;
4213
4214 /* Now we reduce alpha of the inner color (i.e. the color shown)
4215 * so that this setting can look grayed out, while retaining
4216 * the checkerboard (for transparent values). This is needed
4217 * here as the effects of ui_widget_color_disabled() are overwritten. */
4219
4220 widgetbase_draw_color(&wtb, wcol, col, show_alpha_checkers);
4221 if (color_but->is_pallete_color &&
4222 ((Palette *)but->rnapoin.owner_id)->active_color == color_but->palette_color_index)
4223 {
4224 const float width = rect->xmax - rect->xmin;
4225 const float height = rect->ymax - rect->ymin;
4226 /* find color luminance and change it slightly */
4227 float bw = srgb_to_grayscale(col);
4228
4229 bw += (bw < 0.5f) ? 0.5f : -0.5f;
4230
4231 /* We are drawing on top of widget bases. Flush cache. */
4235
4237 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
4239
4240 immUniformColor3f(bw, bw, bw);
4242 immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
4243 immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
4244 immVertex2f(pos, rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
4245 immEnd();
4246
4248 }
4249}
4250
4251static void widget_unitvec(uiBut *but,
4252 uiWidgetColors *wcol,
4253 rcti *rect,
4254 const uiWidgetStateInfo * /*state*/,
4255 int /*roundboxalign*/,
4256 const float zoom)
4257{
4258 const float rad = widget_radius_from_zoom(zoom, wcol);
4259 ui_draw_but_UNITVEC(but, wcol, rect, rad);
4260}
4261
4263 uiWidgetColors *wcol,
4264 rcti *rect,
4265 const uiWidgetStateInfo *state,
4266 int roundboxalign,
4267 const float zoom)
4268{
4272 {
4273 uiWidgetBase wtb;
4274 widget_init(&wtb);
4275 wtb.draw_outline = false;
4276
4277 const float rad = widget_radius_from_zoom(zoom, wcol);
4278 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4279 widgetbase_draw(&wtb, wcol);
4280 }
4281 else if (but->type == ButType::Num) {
4282 /* Draw number buttons still with left/right
4283 * triangles when field is not embossed */
4284 widget_numbut_embossn(but, wcol, rect, state, roundboxalign, zoom);
4285 }
4286 else if (but->type == ButType::Menu) {
4287 /* Draw menu buttons still with down arrow. */
4288 widget_menubut_embossn(but, wcol, rect, state, roundboxalign);
4289 }
4290}
4291
4293 rcti *rect,
4294 const uiWidgetStateInfo *state,
4295 int roundboxalign,
4296 const float zoom)
4297{
4298 if (state->but_flag & UI_SELECT) {
4299 std::swap(wcol->shadetop, wcol->shadedown);
4300 }
4301
4302 uiWidgetBase wtb;
4303 widget_init(&wtb);
4304
4305 const float rad = widget_radius_from_zoom(zoom, wcol);
4306 round_box_edges(&wtb, roundboxalign, rect, rad);
4307
4308 widgetbase_draw(&wtb, wcol);
4309}
4310
4312 rcti *rect,
4313 const uiWidgetStateInfo * /*state*/,
4314 int roundboxalign,
4315 const float zoom)
4316{
4317 uiWidgetBase wtb;
4318 widget_init(&wtb);
4319
4320 const float rad = widget_radius_from_zoom(zoom, wcol);
4321 round_box_edges(&wtb, roundboxalign, rect, rad);
4322
4323 /* decoration */
4324 widgetbase_draw(&wtb, wcol);
4325}
4326
4328 rcti *rect,
4329 const uiWidgetStateInfo *state,
4330 int roundboxalign,
4331 const float zoom)
4332{
4333 float back[4];
4335
4336 if ((state->but_flag & UI_HOVER) || (back[3] < 1.0f)) {
4337 uiWidgetBase wtb;
4338 const float rad = widget_radius_from_zoom(zoom, wcol);
4339
4340 if (state->but_flag & UI_HOVER) {
4341 copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
4342 copy_v3_v3_uchar(wcol->text, wcol->text_sel);
4343 }
4344 else {
4345 wcol->inner[3] *= 1.0f - back[3];
4346 wcol->outline[3] = 0.0f;
4347 }
4348
4349 widget_init(&wtb);
4350
4351 /* half rounded */
4352 round_box_edges(&wtb, roundboxalign, rect, rad);
4353
4354 widgetbase_draw(&wtb, wcol);
4355 }
4356}
4357
4359 rcti *rect,
4360 const uiWidgetStateInfo * /*state*/,
4361 int /*roundboxalign*/,
4362 const float zoom)
4363{
4364 uiWidgetBase wtb;
4365 widget_init(&wtb);
4366
4367 /* Padding on the sides. */
4368 const float padding = zoom * 0.125f * U.widget_unit;
4369 rect->xmin += padding;
4370 rect->xmax -= padding;
4371
4372 const float rad = widget_radius_from_zoom(zoom, wcol);
4373
4374 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4375
4376 widgetbase_draw(&wtb, wcol);
4377}
4378
4380 rcti *rect,
4381 const uiWidgetStateInfo * /*state*/,
4382 int /*roundboxalign*/,
4383 const float zoom)
4384{
4385 /* This function is used for menu items placed close to each other horizontally, e.g. the matcap
4386 * preview popup or the row of collection color icons in the Outliner context menu. Don't use
4387 * padding on the sides like the normal menu item. */
4388
4389 uiWidgetBase wtb;
4390 widget_init(&wtb);
4391
4392 /* No outline. */
4393 wtb.draw_outline = false;
4394 const float rad = widget_radius_from_zoom(zoom, wcol);
4395 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4396
4397 widgetbase_draw(&wtb, wcol);
4398}
4399
4401 uiWidgetColors *wcol,
4402 rcti *rect,
4403 const uiWidgetStateInfo * /*state*/,
4404 int /*roundboxalign*/,
4405 const float zoom)
4406{
4407 const float fac = but->block->pie_data.alphafac;
4408
4409 uiWidgetBase wtb;
4410 widget_init(&wtb);
4411
4412 wtb.draw_emboss = false;
4413
4414 const float rad = widget_radius_from_zoom(zoom, wcol);
4415 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4416
4417 wcol->inner[3] *= fac;
4418 wcol->inner_sel[3] *= fac;
4419 wcol->item[3] *= fac;
4420 wcol->text[3] *= fac;
4421 wcol->text_sel[3] *= fac;
4422 wcol->outline[3] *= fac;
4423
4424 widgetbase_draw(&wtb, wcol);
4425}
4426
4428 uiWidgetColors *wcol,
4429 rcti *rect,
4430 const uiWidgetStateInfo *state,
4431 int /*roundboxalign*/,
4432 const float zoom)
4433{
4434 rcti draw_rect = *rect;
4435 bool is_selected = state->but_flag & UI_SELECT;
4436
4437 if (but->type == ButType::ViewItem) {
4438 uiButViewItem *item_but = static_cast<uiButViewItem *>(but);
4439 blender::ui::AbstractViewItem &view_item = *item_but->view_item;
4440
4441 if (!view_item.is_active() && view_item.is_selected()) {
4442 copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
4443 color_blend_v3_v3(wcol->inner, wcol->outline, 0.5);
4444 is_selected = true;
4445 }
4446 if (item_but->draw_width > 0) {
4447 BLI_rcti_resize_x(&draw_rect, zoom * item_but->draw_width);
4448 }
4449 if (item_but->draw_height > 0) {
4450 BLI_rcti_resize_y(&draw_rect, zoom * item_but->draw_height);
4451 }
4452 }
4453
4454 uiWidgetBase wtb;
4455 widget_init(&wtb);
4456
4457 const float rad = widget_radius_from_zoom(zoom, wcol);
4458 round_box_edges(&wtb, UI_CNR_ALL, &draw_rect, rad);
4459
4460 if (state->but_flag & UI_HOVER) {
4461 color_blend_v3_v3(wcol->inner, wcol->text, 0.2);
4462 wcol->inner[3] = is_selected ? 255 : 20;
4463 }
4464
4465 widgetbase_draw(&wtb, wcol);
4466}
4467
4469 uiWidgetColors *wcol,
4470 rcti *rect,
4471 const uiWidgetStateInfo *state,
4472 int roundboxalign,
4473 const float zoom)
4474{
4476 widget_list_itembut(but, wcol, rect, state, roundboxalign, zoom);
4477 }
4478
4479 const BIFIconID icon = ui_but_icon(but);
4481 rect,
4482 but->drawstr,
4483 icon,
4484 wcol->text,
4487}
4488
4490 rcti *rect,
4491 const uiWidgetStateInfo *state,
4492 int /*roundboxalign*/,
4493 const float /*zoom*/)
4494{
4495 /* For a right aligned layout (signified by #UI_BUT_TEXT_RIGHT), draw the text on the left of the
4496 * checkbox. */
4497 const bool text_before_widget = (state->but_drawflag & UI_BUT_TEXT_RIGHT);
4498 rcti recttemp = *rect;
4499
4500 uiWidgetBase wtb;
4501 widget_init(&wtb);
4502
4503 /* square */
4504 if (text_before_widget) {
4505 recttemp.xmin = recttemp.xmax - BLI_rcti_size_y(&recttemp);
4506 }
4507 else {
4508 recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
4509 }
4510
4511 /* smaller */
4512 const int delta = (BLI_rcti_size_y(&recttemp) - 2 * U.pixelsize) / 6;
4514 &recttemp, BLI_rcti_size_x(&recttemp) - delta * 2, BLI_rcti_size_y(&recttemp) - delta * 2);
4515 /* Keep one edge in place. */
4516 BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
4517
4518 if (state->but_drawflag & UI_BUT_INDETERMINATE) {
4519 /* The same muted background color regardless of state. */
4520 color_blend_v4_v4v4(wcol->inner, wcol->inner, wcol->inner_sel, 0.75f);
4521 }
4522
4523 const float rad = widget_radius_from_rcti(&recttemp, wcol);
4524 round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
4525
4526 /* decoration */
4527 if (state->but_drawflag & UI_BUT_INDETERMINATE) {
4529 }
4530 else if (state->but_flag & UI_SELECT) {
4532 }
4533
4534 widgetbase_draw(&wtb, wcol);
4535
4536 /* Text space - factor is really just eyeballed. */
4537 const float offset = delta * 0.9;
4538 if (text_before_widget) {
4539 rect->xmax = recttemp.xmin - offset;
4540 }
4541 else {
4542 rect->xmin = recttemp.xmax + offset;
4543 }
4544}
4545
4546/* labels use Editor theme colors for text */
4548 const uiWidgetStateInfo *state,
4550{
4551 if (state->but_flag & UI_BUT_LIST_ITEM) {
4552 /* Override default label theme's colors. */
4553 bTheme *btheme = UI_GetTheme();
4554 wt->wcol_theme = &btheme->tui.wcol_list_item;
4555 /* call this for option button */
4556 widget_state(wt, state, emboss);
4557 }
4558 else {
4559 /* call this for option button */
4560 widget_state(wt, state, emboss);
4561 if (state->but_flag & UI_SELECT) {
4563 }
4564 else {
4566 }
4567 }
4568
4569 if (state->but_flag & UI_BUT_REDALERT) {
4570 uchar red[4];
4572 color_mul_hsl_v3(red, 1.0f, 1.5f, 1.5f);
4573 color_blend_v3_v3(wt->wcol.text, red, 0.5f);
4574 }
4575}
4576
4578 rcti *rect,
4579 const uiWidgetStateInfo * /*state*/,
4580 int roundboxalign,
4581 const float zoom)
4582{
4583 uiWidgetBase wtb;
4584 widget_init(&wtb);
4585
4586 const float rad = widget_radius_from_zoom(zoom, wcol);
4587 round_box_edges(&wtb, roundboxalign, rect, rad);
4588
4589 widgetbase_draw(&wtb, wcol);
4590}
4591
4592static void widget_box(uiBut *but,
4593 uiWidgetColors *wcol,
4594 rcti *rect,
4595 const uiWidgetStateInfo * /*state*/,
4596 int roundboxalign,
4597 const float zoom)
4598{
4599 uiWidgetBase wtb;
4600 widget_init(&wtb);
4601
4602 uchar old_col[3];
4603 copy_v3_v3_uchar(old_col, wcol->inner);
4604
4605 /* abuse but->hsv - if it's non-zero, use this color as the box's background */
4606 if (but != nullptr && but->col[3]) {
4607 wcol->inner[0] = but->col[0];
4608 wcol->inner[1] = but->col[1];
4609 wcol->inner[2] = but->col[2];
4610 wcol->inner[3] = but->col[3];
4611 }
4612
4613 const float rad = widget_radius_from_zoom(zoom, wcol);
4614 round_box_edges(&wtb, roundboxalign, rect, rad);
4615 wtb.draw_emboss = draw_emboss(but);
4616 widgetbase_draw(&wtb, wcol);
4617
4618 copy_v3_v3_uchar(wcol->inner, old_col);
4619
4620 /* Flush the cache so that we don't draw over contents. #125035 */
4624}
4625
4626static void widget_but(uiWidgetColors *wcol,
4627 rcti *rect,
4628 const uiWidgetStateInfo * /*state*/,
4629 int roundboxalign,
4630 const float zoom)
4631{
4632 uiWidgetBase wtb;
4633 widget_init(&wtb);
4634
4635 const float rad = widget_radius_from_zoom(zoom, wcol);
4636 round_box_edges(&wtb, roundboxalign, rect, rad);
4637
4638 widgetbase_draw(&wtb, wcol);
4639}
4640
4641#if 0
4642static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int /*state*/ int roundboxalign)
4643{
4644 uiWidgetBase wtb;
4645 const float rad = wcol->roundness * U.widget_unit;
4646
4647 widget_init(&wtb);
4648
4649 /* half rounded */
4650 round_box_edges(&wtb, roundboxalign, rect, rad);
4651
4652 widgetbase_draw(&wtb, wcol);
4653}
4654#endif
4655
4657 uiWidgetColors *wcol,
4658 rcti *rect,
4659 const uiWidgetStateInfo *state,
4660 int roundboxalign,
4661 const float zoom)
4662{
4663 uiWidgetBase wtb;
4664 widget_init(&wtb);
4665
4666 if (state->has_hold_action) {
4667 /* Show that keeping pressed performs another action (typically a menu). */
4668 shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
4669 }
4670
4671 const float rad = widget_radius_from_zoom(zoom, wcol);
4672
4673 /* half rounded */
4674 round_box_edges(&wtb, roundboxalign, rect, rad);
4675 wtb.draw_emboss = draw_emboss(but);
4676 widgetbase_draw(&wtb, wcol);
4677}
4678
4679static void widget_tab(uiBut *but,
4680 uiWidgetColors *wcol,
4681 rcti *rect,
4682 const uiWidgetStateInfo *state,
4683 int roundboxalign,
4684 const float zoom)
4685{
4686 const float rad = widget_radius_from_zoom(zoom, wcol);
4687 const bool is_active = (state->but_flag & UI_SELECT);
4688
4689 /* Draw shaded outline - Disabled for now,
4690 * seems incorrect and also looks nicer without it IMHO ;). */
4691 // #define USE_TAB_SHADED_HIGHLIGHT
4692
4693 uchar theme_col_tab_highlight[3];
4694
4695#ifdef USE_TAB_SHADED_HIGHLIGHT
4696 /* create outline highlight colors */
4697 if (is_active) {
4698 interp_v3_v3v3_uchar(theme_col_tab_highlight, wcol->inner_sel, wcol->outline, 0.2f);
4699 }
4700 else {
4701 interp_v3_v3v3_uchar(theme_col_tab_highlight, wcol->inner, wcol->outline, 0.12f);
4702 }
4703#endif
4704
4705 uiWidgetBase wtb;
4706 widget_init(&wtb);
4707
4708 /* half rounded */
4709 round_box_edges(&wtb, roundboxalign, rect, rad);
4710
4711 /* draw inner */
4712#ifdef USE_TAB_SHADED_HIGHLIGHT
4713 wtb.draw_outline = 0;
4714#endif
4715 wtb.draw_emboss = draw_emboss(but);
4716 widgetbase_draw(&wtb, wcol);
4717
4718 /* We are drawing on top of widget bases. Flush cache. */
4722
4723#ifdef USE_TAB_SHADED_HIGHLIGHT
4724 /* draw outline (3d look) */
4725 ui_draw_but_TAB_outline(rect, rad, theme_col_tab_highlight, wcol->inner);
4726#endif
4727
4728#ifndef USE_TAB_SHADED_HIGHLIGHT
4729 UNUSED_VARS(is_active, theme_col_tab_highlight);
4730#endif
4731}
4732
4733static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
4734{
4735 bTheme *btheme = UI_GetTheme();
4736 uiWidgetColors *wcol = &btheme->tui.wcol_radio;
4737 const float rad = wcol->roundness * U.widget_unit;
4738
4739 /* state copy! */
4740 wt->wcol = *(wt->wcol_theme);
4741
4742 uiWidgetBase wtb;
4743 widget_init(&wtb);
4744
4745 if (but->block->drawextra) {
4746 /* NOTE: drawextra can change rect +1 or -1, to match round errors of existing previews. */
4747 but->block->drawextra(C, rect);
4748
4750 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
4752
4753 /* make mask to draw over image */
4754 uchar col[4];
4757
4758 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
4759 widgetbase_outline(&wtb, pos);
4760
4762 }
4763
4764 /* outline */
4765 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
4766 wtb.draw_outline = true;
4767 wtb.draw_inner = false;
4768 widgetbase_draw(&wtb, &wt->wcol);
4769}
4770
4772{
4773 bTheme *btheme = UI_GetTheme();
4774
4775 /* defaults */
4776 static uiWidgetType wt;
4777 wt.wcol_theme = &btheme->tui.wcol_regular;
4778 wt.wcol_state = &btheme->tui.wcol_state;
4779 wt.state = widget_state;
4780 wt.draw = widget_but;
4781 wt.custom = nullptr;
4783
4784 switch (type) {
4785 case UI_WTYPE_REGULAR:
4786 break;
4787
4788 case UI_WTYPE_LABEL:
4789 wt.draw = nullptr;
4791 break;
4792
4793 case UI_WTYPE_TOGGLE:
4794 wt.wcol_theme = &btheme->tui.wcol_toggle;
4795 break;
4796
4797 case UI_WTYPE_CHECKBOX:
4798 wt.wcol_theme = &btheme->tui.wcol_option;
4800 break;
4801
4802 case UI_WTYPE_RADIO:
4803 wt.wcol_theme = &btheme->tui.wcol_radio;
4804 wt.draw = widget_radiobut;
4805 break;
4806
4807 case UI_WTYPE_NUMBER:
4808 wt.wcol_theme = &btheme->tui.wcol_num;
4809 wt.custom = widget_numbut;
4810 break;
4811
4812 case UI_WTYPE_SLIDER:
4813 wt.wcol_theme = &btheme->tui.wcol_numslider;
4816 break;
4817
4818 case UI_WTYPE_EXEC:
4819 wt.wcol_theme = &btheme->tui.wcol_tool;
4821 break;
4822
4824 wt.wcol_theme = &btheme->tui.wcol_toolbar_item;
4826 break;
4827
4828 case UI_WTYPE_TAB:
4829 wt.wcol_theme = &btheme->tui.wcol_tab;
4830 wt.custom = widget_tab;
4831 break;
4832
4833 case UI_WTYPE_TOOLTIP:
4834 wt.wcol_theme = &btheme->tui.wcol_tooltip;
4836 break;
4837
4838 /* strings */
4839 case UI_WTYPE_NAME:
4840 wt.wcol_theme = &btheme->tui.wcol_text;
4841 wt.draw = widget_textbut;
4842 break;
4843
4844 case UI_WTYPE_NAME_LINK:
4845 break;
4846
4848 break;
4849
4850 case UI_WTYPE_FILENAME:
4851 break;
4852
4853 /* start menus */
4855 wt.wcol_theme = &btheme->tui.wcol_menu;
4856 wt.draw = widget_menubut;
4857 break;
4858
4861 wt.wcol_theme = &btheme->tui.wcol_menu;
4863 break;
4864
4866 wt.wcol_theme = &btheme->tui.wcol_menu;
4867 wt.draw = widget_menubut;
4868 break;
4869
4870 case UI_WTYPE_PULLDOWN:
4871 wt.wcol_theme = &btheme->tui.wcol_pulldown;
4874 break;
4875
4876 /* in menus */
4877 case UI_WTYPE_MENU_ITEM:
4878 wt.wcol_theme = &btheme->tui.wcol_menu_item;
4881 break;
4882
4884 wt.wcol_theme = &btheme->tui.wcol_menu_item;
4887 break;
4888
4889 case UI_WTYPE_MENU_BACK:
4890 wt.wcol_theme = &btheme->tui.wcol_menu_back;
4892 break;
4893
4894 /* specials */
4895 case UI_WTYPE_ICON:
4897 break;
4898
4900 /* behave like regular labels (this is simply a label with an icon) */
4903 break;
4904
4906 wt.draw = nullptr;
4907 /* Drawn via the `custom` callback. */
4908 wt.text = nullptr;
4909 /* Drawing indicates state well enough. No need to change colors further. */
4912 wt.wcol_theme = &btheme->tui.wcol_list_item;
4913 break;
4914
4915 case UI_WTYPE_SWATCH:
4916 wt.custom = widget_swatch;
4917 break;
4918
4919 case UI_WTYPE_BOX:
4920 wt.custom = widget_box;
4921 wt.wcol_theme = &btheme->tui.wcol_box;
4922 break;
4923
4925 break;
4926
4927 case UI_WTYPE_UNITVEC:
4929 break;
4930
4931 case UI_WTYPE_SCROLL:
4932 wt.wcol_theme = &btheme->tui.wcol_scroll;
4934 wt.custom = widget_scroll;
4935 break;
4936
4937 case UI_WTYPE_LISTITEM:
4938 case UI_WTYPE_VIEW_ITEM:
4939 wt.wcol_theme = &btheme->tui.wcol_list_item;
4941 break;
4942
4943 case UI_WTYPE_PROGRESS:
4944 wt.wcol_theme = &btheme->tui.wcol_progress;
4946 break;
4947
4950 break;
4951
4953 wt.wcol_theme = &btheme->tui.wcol_pie_menu;
4956 break;
4957 }
4958
4959 return &wt;
4960}
4961
4962static int widget_roundbox_set(uiBut *but, rcti *rect)
4963{
4964 int roundbox = UI_CNR_ALL;
4965
4966 /* alignment */
4967 if ((but->drawflag & UI_BUT_ALIGN) && but->type != ButType::Pulldown) {
4968
4969 /* ui_popup_block_position has this correction too, keep in sync */
4971 rect->ymax += U.pixelsize;
4972 }
4974 rect->xmin -= U.pixelsize;
4975 }
4976
4977 switch (but->drawflag & UI_BUT_ALIGN) {
4978 case UI_BUT_ALIGN_TOP:
4980 break;
4981 case UI_BUT_ALIGN_DOWN:
4982 roundbox = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
4983 break;
4984 case UI_BUT_ALIGN_LEFT:
4986 break;
4987 case UI_BUT_ALIGN_RIGHT:
4989 break;
4991 roundbox = UI_CNR_TOP_LEFT;
4992 break;
4994 roundbox = UI_CNR_TOP_RIGHT;
4995 break;
4997 roundbox = UI_CNR_BOTTOM_LEFT;
4998 break;
5000 roundbox = UI_CNR_BOTTOM_RIGHT;
5001 break;
5002 default:
5003 roundbox = 0;
5004 break;
5005 }
5006 }
5007
5008 /* align with open menu */
5009 if (but->active && (but->type != ButType::Popover) && !ui_but_menu_draw_as_popover(but)) {
5010 const int direction = ui_but_menu_direction(but);
5011
5012 /* Pull-down menus that open above or below a button can have more than one direction. */
5013 if (direction & UI_DIR_UP) {
5014 roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
5015 }
5016 else if (direction & UI_DIR_DOWN) {
5017 roundbox &= ~(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
5018 }
5019 else if (direction == UI_DIR_LEFT) {
5020 roundbox &= ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
5021 }
5022 else if (direction == UI_DIR_RIGHT) {
5023 roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
5024 }
5025 }
5026
5027 return roundbox;
5028}
5029
5031{
5032 /* We could use a flag for this, but for now just check size,
5033 * add up/down arrows if there is room. */
5034 if ((but->str.empty() && but->icon && (BLI_rcti_size_x(rect) < BLI_rcti_size_y(rect) + 2)) ||
5035 /* disable for brushes also */
5036 (but->flag & UI_BUT_ICON_PREVIEW))
5037 {
5038 /* No arrows. */
5040 }
5041
5042 /* With menu arrows. */
5044}
5045
5047
5048/* -------------------------------------------------------------------- */
5051
5052void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
5053{
5054 bTheme *btheme = UI_GetTheme();
5055 const ThemeUI *tui = &btheme->tui;
5056 const uiFontStyle *fstyle = &style->widget;
5057 uiWidgetType *wt = nullptr;
5058
5059 /* handle menus separately */
5061 switch (but->type) {
5062 case ButType::Label:
5063 widget_draw_text_icon(&style->widget, &tui->wcol_menu_back, but, rect);
5064 break;
5065 case ButType::Sepr:
5066 break;
5067 case ButType::SeprLine:
5068 /* Add horizontal padding between the line and menu sides. */
5069 BLI_rcti_pad(rect, int(-7.0f * UI_SCALE_FAC), 0);
5070 ui_draw_separator(&tui->wcol_menu_item, but, rect);
5071 break;
5072 default: {
5073 const bool use_unpadded = (but->flag & UI_BUT_ICON_PREVIEW) ||
5074 ((but->flag & UI_HAS_ICON) && !but->drawstr[0]);
5076 break;
5077 }
5078 }
5079 }
5081 {
5082 /* Use the same widget types for both no emboss types. Later on,
5083 * #blender::ui::EmbossType::NoneOrStatus will blend state colors if they apply. */
5084 switch (but->type) {
5085 case ButType::Label:
5086 case ButType::Text:
5088 if (!(but->flag & UI_HAS_ICON)) {
5090 }
5091 break;
5094 break;
5095 case ButType::Popover:
5096 if (but->icon == 0) {
5097 wt = popover_widget_type(but, rect);
5098 }
5099 else { /* Currently used for presets. */
5101 }
5102 break;
5105 break;
5106 default:
5108 break;
5109 }
5110 }
5111 else if (but->emboss == blender::ui::EmbossType::PieMenu) {
5113 }
5114 else {
5116
5117 switch (but->type) {
5118 case ButType::Label:
5120 if (but->drawflag & UI_BUT_BOX_ITEM) {
5121 wt->wcol_theme = &tui->wcol_box;
5122 wt->state = widget_state;
5123 }
5124 else if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) {
5125 wt->wcol_theme = &tui->wcol_menu_back;
5126 wt->state = widget_state;
5127 }
5128 if (!(but->flag & UI_HAS_ICON)) {
5130 }
5131 break;
5132
5133 case ButType::Sepr:
5135 break;
5136 case ButType::SeprLine:
5137 ui_draw_separator(&tui->wcol_menu_item, but, rect);
5138 break;
5139
5140 case ButType::But:
5141 case ButType::Decorator:
5142#ifdef USE_UI_TOOLBAR_HACK
5143 if ((but->icon != ICON_NONE) && UI_but_is_tool(but)) {
5145 }
5146 else {
5148 }
5149#else
5151#endif
5152 break;
5153
5154 case ButType::Num:
5156 break;
5157
5158 case ButType::NumSlider:
5160 break;
5161
5162 case ButType::Row:
5164 break;
5165
5166 case ButType::ListRow:
5168 break;
5169
5170 case ButType::Text:
5172 break;
5173
5176 break;
5177
5178 case ButType::Tab:
5180 break;
5181
5182 case ButType::ButToggle:
5183 case ButType::Toggle:
5184 case ButType::ToggleN:
5186 break;
5187
5188 case ButType::Checkbox:
5189 case ButType::CheckboxN:
5190 if (!(but->flag & UI_HAS_ICON)) {
5192
5193 if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) {
5194 but->drawflag |= UI_BUT_TEXT_LEFT;
5195 }
5196 /* #widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
5197 * text drawing were to add its own padding, DPI and zoom factor would be applied twice
5198 * in the final padding, so it's difficult to control it. */
5200 }
5201 else {
5203 }
5204
5205 /* option buttons have strings outside, on menus use different colors */
5208 }
5209 break;
5210
5211 case ButType::Menu:
5212 case ButType::Block:
5213 case ButType::Popover:
5214 if (but->flag & UI_BUT_NODE_LINK) {
5215 /* new node-link button, not active yet XXX */
5217 }
5218 else {
5219 /* Popover button. */
5220 wt = popover_widget_type(but, rect);
5221 }
5222 break;
5223
5224 case ButType::Pulldown:
5226 break;
5227
5228 case ButType::ButMenu:
5230 break;
5231
5232 case ButType::Color:
5234 break;
5235
5236 case ButType::Roundbox:
5237 case ButType::ListBox:
5239 break;
5240
5243 break;
5244
5245 case ButType::Extra:
5247 break;
5248
5249 case ButType::HsvCube: {
5250 const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
5251
5253 /* vertical V slider, uses new widget draw now */
5254 ui_draw_but_HSV_v(but, rect);
5255 }
5256 else { /* other HSV pickers... */
5257 ui_draw_but_HSVCUBE(but, rect);
5258 }
5259 break;
5260 }
5261
5262 case ButType::HsvCircle:
5263 ui_draw_but_HSVCIRCLE(but, &tui->wcol_regular, rect);
5264 break;
5265
5266 case ButType::ColorBand: {
5267 /* Horizontal padding to make room for handles at edges. */
5268 const int padding = BLI_rcti_size_y(rect) / 6;
5269 rect->xmin += padding;
5270 rect->xmax -= padding;
5271 ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect);
5272 break;
5273 }
5274
5275 case ButType::Unitvec:
5277 break;
5278
5279 case ButType::Image:
5280 ui_draw_but_IMAGE(region, but, &tui->wcol_regular, rect);
5281 break;
5282
5283 case ButType::Histogram:
5284 ui_draw_but_HISTOGRAM(region, but, &tui->wcol_regular, rect);
5285 break;
5286
5287 case ButType::Waveform:
5288 ui_draw_but_WAVEFORM(region, but, &tui->wcol_regular, rect);
5289 break;
5290
5292 ui_draw_but_VECTORSCOPE(region, but, &tui->wcol_regular, rect);
5293 break;
5294
5295 case ButType::Curve:
5296 ui_draw_but_CURVE(region, but, &tui->wcol_curve, rect);
5297 break;
5298
5300 ui_draw_but_CURVEPROFILE(region, but, &tui->wcol_curve, rect);
5301 break;
5302
5303 case ButType::Progress:
5305 break;
5306
5307 case ButType::ViewItem:
5309 break;
5310
5311 case ButType::Scroll:
5313 break;
5314
5315 case ButType::Grip:
5317 break;
5318
5320 ui_draw_but_TRACKPREVIEW(region, but, &tui->wcol_regular, rect);
5321 break;
5322
5325 break;
5326
5327 default:
5329 break;
5330 }
5331 }
5332
5333 if (wt == nullptr) {
5334 return;
5335 }
5336
5337 // rcti disablerect = *rect; /* rect gets clipped smaller for text */
5338
5339 const int roundboxalign = widget_roundbox_set(but, rect);
5340
5342 state.but_flag = but->flag;
5343 state.but_drawflag = but->drawflag;
5344 state.emboss = but->emboss;
5345
5346 /* Override selected flag for drawing. */
5347 if (but->flag & UI_SELECT_DRAW) {
5348 state.but_flag |= UI_SELECT;
5349 }
5350
5351 if ((but->editstr) ||
5353 {
5354 state.is_text_input = true;
5355 }
5356
5357 if (but->hold_func) {
5358 state.has_hold_action = true;
5359 }
5360
5361 bool use_alpha_blend = false;
5364 use_alpha_blend = true;
5366 }
5367 }
5368
5369#ifdef USE_UI_POPOVER_ONCE
5370 if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
5371 if ((but->flag & UI_HOVER) && ui_but_is_popover_once_compat(but)) {
5372 state.but_flag |= UI_BUT_ACTIVE_DEFAULT;
5373 }
5374 }
5375#endif
5377 state.but_flag &= ~UI_BUT_OVERRIDDEN;
5378 }
5379
5380 if (state.but_drawflag & UI_BUT_INDETERMINATE) {
5381 state.but_flag &= ~UI_SELECT;
5382 }
5383
5384 const float zoom = 1.0f / but->block->aspect;
5385 wt->state(wt, &state, but->emboss);
5386 if (wt->custom) {
5387 wt->custom(but, &wt->wcol, rect, &state, roundboxalign, zoom);
5388 }
5389 else if (wt->draw) {
5390 wt->draw(&wt->wcol, rect, &state, roundboxalign, zoom);
5391 }
5392
5393 if (wt->text) {
5394 if (use_alpha_blend) {
5396 }
5397
5398 if (but->type == ButType::Label && !(but->flag & UI_HAS_ICON) && but->col[3] != 0) {
5399 /* Optionally use button color for text color if label without icon.
5400 * For example, ensuring that the Splash version text is always white. */
5401 copy_v4_v4_uchar(wt->wcol.text, but->col);
5402 }
5403
5404 wt->text(fstyle, &wt->wcol, but, rect);
5405 if (use_alpha_blend) {
5407 }
5408 }
5409}
5410
5411static void ui_draw_clip_tri(uiBlock *block, const rcti *rect, uiWidgetType *wt)
5412{
5413 if (block) {
5414 float draw_color[4];
5415 const uchar *color = wt->wcol.text;
5416
5417 draw_color[0] = float(color[0]) / 255.0f;
5418 draw_color[1] = float(color[1]) / 255.0f;
5419 draw_color[2] = float(color[2]) / 255.0f;
5420 draw_color[3] = 1.0f;
5421
5422 if (block->flag & UI_BLOCK_CLIPTOP) {
5423 /* XXX no scaling for UI here yet */
5424 UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 6 * UI_SCALE_FAC, 't', draw_color);
5425 }
5426 if (block->flag & UI_BLOCK_CLIPBOTTOM) {
5427 /* XXX no scaling for UI here yet */
5428 UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10 * UI_SCALE_FAC, 'v', draw_color);
5429 }
5430 }
5431}
5432
5433static void ui_draw_dialog_alert(uiBlock *block, const rcti *rect)
5434{
5435 if (block->alert_level != uiBlockAlertLevel::Error) {
5436 return;
5437 }
5438
5439 float color[4];
5440 switch (block->alert_level) {
5443 break;
5446 break;
5449 break;
5450 default:
5452 }
5453
5454 bTheme *btheme = UI_GetTheme();
5455 const float bg_radius = btheme->tui.wcol_menu_back.roundness * U.widget_unit;
5456 const float line_width = 3.0f * UI_SCALE_FAC;
5457 const float radius = (bg_radius > (line_width * 2.0f)) ? 0.0f : bg_radius;
5458 const float padding = (bg_radius > (line_width * 2.0f)) ? bg_radius : 0.0f;
5459 rctf line_rect;
5460 BLI_rctf_rcti_copy(&line_rect, rect);
5461 line_rect.ymin = line_rect.ymax - line_width;
5462 BLI_rctf_pad(&line_rect, -padding, 0.0f);
5464 UI_draw_roundbox_4fv(&line_rect, true, radius, color);
5465}
5466
5467void ui_draw_menu_back(uiStyle * /*style*/, uiBlock *block, const rcti *rect)
5468{
5470
5472 if (block) {
5473 const float zoom = 1.0f / block->aspect;
5474 wt->draw_block(&wt->wcol,
5475 rect,
5476 block->flag,
5477 block->alert_level == uiBlockAlertLevel::None ? block->direction :
5478 char(UI_DIR_DOWN),
5479 zoom);
5480 if (block->alert_level != uiBlockAlertLevel::None) {
5481 ui_draw_dialog_alert(block, rect);
5482 }
5483 }
5484 else {
5485 wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
5486 }
5487
5488 ui_draw_clip_tri(block, rect, wt);
5489}
5490
5496 const rcti *rect,
5497 int direction,
5498 const float unit_size,
5499 const float mval_origin[2])
5500{
5501 /* Alas, this isn't nice. */
5502 const float unit_half = unit_size / 2;
5503 const float cent_x = mval_origin ? std::clamp(mval_origin[0],
5504 rect->xmin + unit_size,
5505 rect->xmax - unit_size) :
5506 BLI_rcti_cent_x(rect);
5507
5509
5510 /* Extracted from 'widget_menu_back', keep separate to avoid menu changes breaking popovers */
5511 {
5512 uiWidgetBase wtb;
5513 widget_init(&wtb);
5514
5515 const int roundboxalign = UI_CNR_ALL;
5516 widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
5517
5518 round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
5519 wtb.draw_emboss = false;
5520 widgetbase_draw(&wtb, wcol);
5521 }
5522
5523 /* Draw popover arrow (top/bottom) */
5524 if (ELEM(direction, UI_DIR_UP, UI_DIR_DOWN)) {
5526 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
5528
5529 const bool is_down = (direction == UI_DIR_DOWN);
5530 const int sign = is_down ? 1 : -1;
5531 float y = is_down ? rect->ymax : rect->ymin;
5532
5536 immVertex2f(pos, cent_x - unit_half, y);
5537 immVertex2f(pos, cent_x + unit_half, y);
5538 immVertex2f(pos, cent_x, y + sign * unit_half);
5539 immEnd();
5540
5541 y = y - sign * round(U.pixelsize * 1.41);
5542
5545 immUniformColor4ub(0, 0, 0, 0);
5546 immVertex2f(pos, cent_x - unit_half, y);
5547 immVertex2f(pos, cent_x + unit_half, y);
5548 immVertex2f(pos, cent_x, y + sign * unit_half);
5549 immEnd();
5550
5554 immVertex2f(pos, cent_x - unit_half, y);
5555 immVertex2f(pos, cent_x + unit_half, y);
5556 immVertex2f(pos, cent_x, y + sign * unit_half);
5557 immEnd();
5558
5560 }
5561
5563}
5564
5565void ui_draw_popover_back(ARegion *region, uiStyle * /*style*/, uiBlock *block, const rcti *rect)
5566{
5568
5569 float mval_origin[2] = {float(block->bounds_offset[0]), float(block->bounds_offset[1])};
5570 ui_window_to_block_fl(region, block, &mval_origin[0], &mval_origin[1]);
5572 wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin);
5573
5574 ui_draw_clip_tri(block, rect, wt);
5575}
5576
5577static void draw_disk_shaded(float start,
5578 float angle,
5579 float radius_int,
5580 float radius_ext,
5581 int subd,
5582 const uchar col1[4],
5583 const uchar col2[4],
5584 bool shaded)
5585{
5586 const float radius_ext_scale = (0.5f / radius_ext); /* 1 / (2 * radius_ext) */
5587
5588 uint col;
5591 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
5592 if (shaded) {
5593 col = GPU_vertformat_attr_add(format, "color", blender::gpu::VertAttrType::SFLOAT_32_32_32_32);
5595 }
5596 else {
5598 immUniformColor4ubv(col1);
5599 }
5600
5601 immBegin(GPU_PRIM_TRI_STRIP, subd * 2);
5602 for (int i = 0; i < subd; i++) {
5603 const float a = start + ((i) / float(subd - 1)) * angle;
5604 const float s = sinf(a);
5605 const float c = cosf(a);
5606 const float y1 = s * radius_int;
5607 const float y2 = s * radius_ext;
5608
5609 if (shaded) {
5610 uchar r_col[4];
5611 const float fac = (y1 + radius_ext) * radius_ext_scale;
5612 color_blend_v4_v4v4(r_col, col1, col2, fac);
5613 float f_col[4];
5614 rgba_uchar_to_float(f_col, r_col);
5615 immAttr4fv(col, f_col);
5616 }
5617 immVertex2f(pos, c * radius_int, s * radius_int);
5618
5619 if (shaded) {
5620 uchar r_col[4];
5621 const float fac = (y2 + radius_ext) * radius_ext_scale;
5622 color_blend_v4_v4v4(r_col, col1, col2, fac);
5623 float f_col[4];
5624 rgba_uchar_to_float(f_col, r_col);
5625 immAttr4fv(col, f_col);
5626 }
5627 immVertex2f(pos, c * radius_ext, s * radius_ext);
5628 }
5629 immEnd();
5630
5632}
5633
5635{
5636 bTheme *btheme = UI_GetTheme();
5637 const float cx = block->pie_data.pie_center_spawned[0];
5638 const float cy = block->pie_data.pie_center_spawned[1];
5639
5640 const float *pie_dir = block->pie_data.pie_dir;
5641
5642 const float pie_radius_internal = UI_SCALE_FAC * U.pie_menu_threshold;
5643 const float pie_radius_external = UI_SCALE_FAC * (U.pie_menu_threshold + 7.0f);
5644
5645 const int subd = 40;
5646
5647 const float angle = atan2f(pie_dir[1], pie_dir[0]);
5648 /* Use a smaller range if there are both axis aligned & diagonal buttons. */
5649 const bool has_aligned = (block->pie_data.pie_dir_mask & UI_RADIAL_MASK_ALL_AXIS_ALIGNED) != 0;
5650 const bool has_diagonal = (block->pie_data.pie_dir_mask & UI_RADIAL_MASK_ALL_DIAGONAL) != 0;
5651 const float range = (has_aligned && has_diagonal) ? M_PI_4 : M_PI_2;
5652
5655
5657 if (btheme->tui.wcol_pie_menu.shaded) {
5658 uchar col1[4], col2[4];
5660 btheme->tui.wcol_pie_menu.shadetop,
5661 btheme->tui.wcol_pie_menu.shadedown,
5662 col1,
5663 col2);
5665 0.0f, float(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true);
5666 }
5667 else {
5668 draw_disk_shaded(0.0f,
5669 float(M_PI * 2.0),
5670 pie_radius_internal,
5671 pie_radius_external,
5672 subd,
5673 btheme->tui.wcol_pie_menu.inner,
5674 nullptr,
5675 false);
5676 }
5677
5678 if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) {
5679 if (btheme->tui.wcol_pie_menu.shaded) {
5680 uchar col1[4], col2[4];
5682 btheme->tui.wcol_pie_menu.shadetop,
5683 btheme->tui.wcol_pie_menu.shadedown,
5684 col1,
5685 col2);
5686 draw_disk_shaded(angle - range / 2.0f,
5687 range,
5688 pie_radius_internal,
5689 pie_radius_external,
5690 subd,
5691 col1,
5692 col2,
5693 true);
5694 }
5695 else {
5696 draw_disk_shaded(angle - range / 2.0f,
5697 range,
5698 pie_radius_internal,
5699 pie_radius_external,
5700 subd,
5701 btheme->tui.wcol_pie_menu.inner_sel,
5702 nullptr,
5703 false);
5704 }
5705 }
5706
5709 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
5712
5713 imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_internal, subd);
5714 imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_external, subd);
5715
5717
5718 if (U.pie_menu_confirm > 0 &&
5720 {
5721 const float pie_confirm_radius = UI_SCALE_FAC * (pie_radius_internal + U.pie_menu_confirm);
5722 const float pie_confirm_external = UI_SCALE_FAC *
5723 (pie_radius_internal + U.pie_menu_confirm + 7.0f);
5724
5725 const uchar col[4] = {UNPACK3(btheme->tui.wcol_pie_menu.text_sel), 64};
5726 draw_disk_shaded(angle - range / 2.0f,
5727 range,
5728 pie_confirm_radius,
5729 pie_confirm_external,
5730 subd,
5731 col,
5732 nullptr,
5733 false);
5734 }
5735
5738}
5739
5745
5750 bool use_shadow,
5751 const rcti *rect,
5752 const float color[4])
5753{
5754 uiWidgetType *wt = widget_type(type);
5755
5756 if (use_shadow) {
5757 widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit);
5758 }
5759
5761 if (color) {
5763 }
5764
5765 if (wt->draw_block) {
5766 wt->draw_block(&wt->wcol, rect, 0, UI_CNR_ALL, 1.0f);
5767 }
5768 else if (wt->draw) {
5769 rcti rect_copy = *rect;
5770 wt->draw(&wt->wcol, &rect_copy, &STATE_INFO_NULL, UI_CNR_ALL, 1.0f);
5771 }
5772 else {
5774 }
5775}
5776void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
5777{
5779}
5780
5781void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow)
5782{
5783 ui_draw_widget_back_color(UI_WTYPE_MENU_BACK, use_shadow, rect, nullptr);
5784}
5785
5786void ui_draw_tooltip_background(const uiStyle * /*style*/, uiBlock * /*block*/, const rcti *rect)
5787{
5790 /* wt->draw_block ends up using same function to draw the tooltip as menu_back */
5791 wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
5792}
5793
5795 rcti *rect,
5796 rcti *back_rect,
5797 const float zoom,
5798 const bool use_unpadded,
5799 const char *name,
5800 int iconid,
5801 int but_flag,
5802 uiMenuItemSeparatorType separator_type,
5803 int *r_xmax)
5804{
5806 const rcti _rect = *rect;
5807 const int row_height = BLI_rcti_size_y(rect);
5808 int max_hint_width = INT_MAX;
5809 int padding = 0.25f * row_height;
5810 char *cpoin = nullptr;
5811
5813 state.but_flag = but_flag;
5814
5816
5817 if (back_rect) {
5818 wt->draw(&wt->wcol, back_rect, &STATE_INFO_NULL, 0, zoom);
5819 }
5820
5821 UI_fontstyle_set(fstyle);
5822
5823 /* text location offset */
5824 rect->xmin += padding;
5825 if (iconid) {
5826 rect->xmin += row_height; /* Use square area for icon. */
5827 }
5828
5829 /* cut string in 2 parts? */
5830 if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
5831 cpoin = const_cast<char *>(strrchr(name, UI_SEP_CHAR));
5832 if (cpoin) {
5833 *cpoin = 0;
5834
5835 /* need to set this first */
5836 UI_fontstyle_set(fstyle);
5837
5838 if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) {
5839 /* Shrink rect to exclude the shortcut string. */
5840 rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_ICON_SIZE;
5841 }
5842 else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) {
5843 /* Determine max-width for the hint string to leave the name string un-clipped (if there's
5844 * enough space to display it). */
5845
5846 const int available_width = BLI_rcti_size_x(rect) - padding;
5847 const int name_width = BLF_width(fstyle->uifont_id, name, INT_MAX);
5848 const int hint_width = BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + padding;
5849
5850 if ((name_width + hint_width) > available_width) {
5851 /* Clipping width for hint string. */
5852 max_hint_width = available_width * 0.40f;
5853 /* Clipping xmax for clipping of item name. */
5854 rect->xmax = (hint_width < max_hint_width) ?
5855 (rect->xmax - hint_width) :
5856 (rect->xmin + (available_width - max_hint_width));
5857 }
5858 }
5859 else {
5860 BLI_assert_msg(0, "Unknown menu item separator type");
5861 }
5862 }
5863 }
5864
5865 {
5866 char drawstr[UI_MAX_DRAW_STR];
5867 const float okwidth = float(BLI_rcti_size_x(rect));
5868 const size_t max_len = sizeof(drawstr);
5869 const float minwidth = UI_ICON_SIZE;
5870
5871 STRNCPY_UTF8(drawstr, name);
5872 if (drawstr[0]) {
5873 UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
5874 }
5875
5876 int xofs = 0, yofs = 0;
5877 ResultBLF info;
5879 params.align = UI_STYLE_TEXT_LEFT;
5881 fstyle, rect, drawstr, sizeof(drawstr), wt->wcol.text, &params, &xofs, &yofs, &info);
5882 if (r_xmax != nullptr) {
5883 *r_xmax = xofs + info.width;
5884 }
5885 }
5886
5887 /* restore rect, was messed with */
5888 *rect = _rect;
5889
5890 if (iconid) {
5891 const int xs = rect->xmin + 0.2f * UI_UNIT_X * zoom;
5892 const int ys = rect->ymin + 0.5f * (BLI_rcti_size_y(rect) - UI_ICON_SIZE * zoom);
5893
5894 const float aspect = U.inv_scale_factor / zoom;
5895
5898 xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT);
5900 }
5901
5902 /* part text right aligned */
5903 if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
5904 if (cpoin) {
5905 /* State info for the hint drawing. */
5906 uiWidgetStateInfo hint_state = state;
5907 /* Set inactive state for grayed out text. */
5908 hint_state.but_flag |= UI_BUT_INACTIVE;
5909
5910 wt->state(wt, &hint_state, blender::ui::EmbossType::Undefined);
5911
5912 char hint_drawstr[UI_MAX_DRAW_STR];
5913 {
5914 const size_t max_len = sizeof(hint_drawstr);
5915 const float minwidth = UI_ICON_SIZE;
5916
5917 STRNCPY_UTF8(hint_drawstr, cpoin + 1);
5918 if (hint_drawstr[0] && (max_hint_width < INT_MAX)) {
5919 UI_text_clip_middle_ex(fstyle, hint_drawstr, max_hint_width, minwidth, max_len, '\0');
5920 }
5921 }
5922
5923 rect->xmax = _rect.xmax - padding;
5926 UI_fontstyle_draw(fstyle, rect, hint_drawstr, sizeof(hint_drawstr), wt->wcol.text, &params);
5927 *cpoin = UI_SEP_CHAR;
5928 }
5929 }
5930}
5931
5933 rcti *rect,
5935 int iconid,
5936 const uchar text_col[4],
5937 eFontStyle_Align text_align,
5938 const bool add_padding)
5939{
5940 rcti trect = *rect;
5941 const float text_size = UI_UNIT_Y;
5942 const bool has_text = !name.is_empty();
5943
5944 float alpha = 1.0f;
5945
5946 if (has_text) {
5947 /* draw icon in rect above the space reserved for the label */
5948 rect->ymin += text_size;
5949 }
5951 widget_draw_preview_icon(iconid, alpha, 1.0f, add_padding, rect, text_col);
5953
5954 if (!has_text) {
5955 return;
5956 }
5957
5958 /* text rect */
5959 trect.ymax = trect.ymin + text_size;
5960 if (add_padding) {
5961 trect.ymin += PREVIEW_PAD;
5962 trect.xmin += PREVIEW_PAD;
5963 trect.xmax -= PREVIEW_PAD;
5964 }
5965
5966 {
5967 char drawstr[UI_MAX_DRAW_STR];
5968 const float okwidth = float(BLI_rcti_size_x(&trect));
5969 const size_t max_len = sizeof(drawstr);
5970 const float minwidth = UI_ICON_SIZE;
5971
5972 memcpy(drawstr, name.data(), name.size());
5973 drawstr[name.size()] = '\0';
5974 UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
5975
5977 params.align = text_align;
5978 UI_fontstyle_draw(fstyle, &trect, drawstr, sizeof(drawstr), text_col, &params);
5979 }
5980}
5981
5983 rcti *rect,
5984 const float zoom,
5985 const char *name,
5986 int iconid,
5987 int but_flag,
5988 eFontStyle_Align text_align)
5989{
5991
5993 state.but_flag = but_flag;
5994
5995 /* drawing button background */
5997 wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, zoom);
5998
5999 ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align, true);
6000}
6001
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:728
blender::Vector< blender::StringRef > BLF_string_wrap(int fontid, blender::StringRef str, const int max_pixel_width, BLFWrapMode mode=BLFWrapMode::Minimal)
Definition blf.cc:1061
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:718
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:705
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_draw(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:585
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:802
void BLF_disable(int fontid, FontFlags flag)
Definition blf.cc:329
void BLF_color4ubv(int fontid, const unsigned char rgba[4])
Definition blf.cc:452
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:388
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:750
BLFWrapMode
Definition BLF_enums.hh:20
@ BLF_SHADOW
Definition BLF_enums.hh:35
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define ATTR_NONNULL(...)
BLI_INLINE bool BLI_listbase_is_empty(const 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)
MINLINE float pow3f(float x)
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 void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[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
MINLINE void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
MINLINE void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
MINLINE void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
MINLINE unsigned char srgb_to_grayscale_byte(const unsigned char rgb[3])
void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
MINLINE float srgb_to_grayscale(const float rgb[3])
#define M_PI_2
#define M_PI
#define M_PI_4
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:198
BLI_INLINE float BLI_rcti_cent_x_fl(const struct rcti *rct)
Definition BLI_rect.h:169
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y)
Definition rct.cc:629
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.cc:566
void BLI_rcti_resize_y(struct rcti *rect, int y)
Definition rct.cc:615
void BLI_rctf_scale(rctf *rect, float scale)
Definition rct.cc:677
void BLI_rcti_resize(struct rcti *rect, int x, int y)
Definition rct.cc:621
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.cc:404
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y)
Definition rct.cc:637
BLI_INLINE float BLI_rcti_cent_y_fl(const struct rcti *rct)
Definition BLI_rect.h:173
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:181
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
void BLI_rcti_resize_x(struct rcti *rect, int x)
Definition rct.cc:609
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
bool BLI_rcti_is_empty(const struct rcti *rect)
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:177
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
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
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t str_len) 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 STRNCPY_UTF8(dst, src)
#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
@ SOCK_DISPLAY_SHAPE_CIRCLE
@ SPACE_NODE
#define UI_SCALE_FAC
#define UI_INV_SCALE_FAC
#define UI_ICON_SIZE
@ USER_CP_CIRCLE_HSV
@ USER_ALWAYS_SHOW_NUMBER_ARROWS
int BIFIconID
Definition ED_asset.hh:28
void GPU_batch_draw_instance_range(blender::gpu::Batch *batch, int instance_first, int instance_count)
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, GPUBuiltinShader shader_id)
#define GPU_batch_uniform_4fv_array(batch, name, len, val)
Definition GPU_batch.hh:282
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, GPUBatchFlag owns_flag)
Definition gpu_batch.cc:51
#define GPU_batch_uniform_3fv(batch, name, val)
Definition GPU_batch.hh:278
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:46
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
void GPU_batch_draw(blender::gpu::Batch *batch)
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 immAttr4fv(uint attr_id, const float data[4])
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
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 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 immRectf(uint pos, float x1, float y1, float x2, float 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:180
void GPU_line_width(float width)
Definition gpu_state.cc:166
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_vertbuf_attr_get_raw_data(blender::gpu::VertBuf *, uint a_idx, GPUVertBufRaw *access)
GPU_INLINE void * GPU_vertbuf_raw_step(GPUVertBufRaw *a)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3], const float color_picking[3])
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], const ColorManagedDisplay *display, const ColorManagedDisplaySpace display_space=DISPLAY_SPACE_DRAW)
PropertyScaleType
Definition RNA_types.hh:203
@ PROP_SCALE_LOG
Definition RNA_types.hh:210
@ PROP_SCALE_LINEAR
Definition RNA_types.hh:205
@ PROP_SCALE_CUBIC
Definition RNA_types.hh:215
@ PROP_PERCENTAGE
Definition RNA_types.hh:250
#define C
Definition RandGen.cpp:29
#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)
@ UI_BLOCK_CLIPBOTTOM
@ UI_BLOCK_POPOVER_ONCE
@ UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE
@ UI_BLOCK_POPUP
@ UI_BLOCK_CLIPTOP
@ UI_BLOCK_POPOVER
#define UI_SEP_CHAR
@ UI_SCROLL_PRESSED
@ UI_SCROLL_ARROWS
@ 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
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
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_VALUE_INDETERMINATE_CHAR
void UI_but_drawflag_disable(uiBut *but, int flag)
@ UI_CNR_BOTTOM_LEFT
@ UI_CNR_BOTTOM_RIGHT
@ UI_CNR_ALL
@ UI_CNR_TOP_LEFT
@ UI_CNR_TOP_RIGHT
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_BLOCK_THEME_STYLE_POPUP
#define UI_UNIT_X
@ 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_NO_PREVIEW_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
bool UI_but_is_tool(const uiBut *but)
@ UI_DIR_DOWN
@ UI_DIR_RIGHT
@ UI_DIR_LEFT
@ UI_DIR_UP
#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
#define UI_MAX_DRAW_STR
blender::ocio::Display ColorManagedDisplay
@ TH_WARNING
@ TH_BACK
@ TH_WIRE
@ TH_WIDGET_EMBOSS
@ TH_REDALERT
@ TH_INFO
@ TH_SUCCESS
@ TH_ERROR
@ TH_WIDGET_TEXT_CURSOR
@ TH_TEXT
@ TH_TEXT_HI
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4])
void UI_GetThemeColor4fv(int colorid, float col[4])
@ BIFICONID_LAST_STATIC
bTheme * UI_GetTheme()
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
int UI_ThemeMenuShadowWidth()
#define U
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
btVector3 m_delta
int64_t size() const
void append(const T &value)
T * data()
void reserve(const int64_t min_capacity)
ChannelStorageType a
Definition half.h:41
nullptr float
#define logf(x)
#define roundf(x)
#define str(s)
static float verts[][3]
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
uint pos
uint col
#define round
constexpr T sign(T) RET
uint padding(uint offset, uint alignment)
const ColorManagedDisplay * ui_block_cm_display_get(uiBlock *block)
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:191
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_IMAGE(ARegion *, uiBut *but, const uiWidgetColors *, const rcti *rect)
void ui_draw_but_WAVEFORM(ARegion *region, 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_HISTOGRAM(ARegion *region, uiBut *but, const uiWidgetColors *, const rcti *recti)
void ui_draw_but_TRACKPREVIEW(ARegion *region, uiBut *but, const uiWidgetColors *, const rcti *recti)
void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rect, const float radius)
void ui_draw_but_VECTORSCOPE(ARegion *region, uiBut *but, const uiWidgetColors *, const rcti *recti)
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)
const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2]
@ UI_PIE_INVALID_DIR
@ UI_PIE_CLICK_STYLE
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
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
@ ROUNDBOX_TRIA_CHECK
@ ROUNDBOX_TRIA_DASH
@ ROUNDBOX_TRIA_SCROLL
@ ROUNDBOX_TRIA_MENU
@ ROUNDBOX_TRIA_ARROWS
@ ROUNDBOX_TRIA_NONE
@ ROUNDBOX_TRIA_HOLD_ACTION_ARROW
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
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, const bool clip_right_if_tight)
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 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 void ui_draw_gradient_hsv_to_rgb(const ColorManagedDisplay *display, float h, float s, float v, float rgb[3])
static const uint g_shape_preset_scroll_circle_face[14][3]
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 widget_state_option_menu(uiWidgetType *wt, const uiWidgetStateInfo *state, blender::ui::EmbossType emboss)
void ui_draw_gradient(const rcti *rect, const float hsv[3], const eButGradientType type, const float alpha, const ColorManagedDisplay *display)
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_menubut(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, int roundboxalign, const float zoom)
static void widgetbase_draw_color(uiWidgetBase *wtb, const uiWidgetColors *wcol, float color[4], bool show_alpha_checkers)
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 ui_draw_dialog_alert(uiBlock *block, const rcti *rect)
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)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static void widget_progress_type_ring(uiButProgress *but_progress, uiWidgetColors *wcol, rcti *rect)
static struct @317251010272112334075076254011225224116111317373 g_widget_base_batch
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 struct @211023143140134257042036125133347160362320150344 g_ui_batch_cache
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
void ui_draw_preview_item(const uiFontStyle *fstyle, rcti *rect, const float zoom, const char *name, int iconid, int but_flag, eFontStyle_Align text_align)
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_state_label(uiWidgetType *wt, const uiWidgetStateInfo *state, blender::ui::EmbossType emboss)
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_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_state_pulldown(uiWidgetType *wt, const uiWidgetStateInfo *, blender::ui::EmbossType)
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)
#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_nodesocket(uiBut *but, uiWidgetColors *, rcti *rect, const uiWidgetStateInfo *, int, const float zoom)
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_menu_item(uiWidgetType *wt, const uiWidgetStateInfo *state, blender::ui::EmbossType)
#define OY
void ui_draw_menu_back(uiStyle *, uiBlock *block, const rcti *rect)
static void shape_preset_init_hold_action(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
static void widget_state(uiWidgetType *wt, const uiWidgetStateInfo *state, blender::ui::EmbossType emboss)
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]
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_menu_item(const uiFontStyle *fstyle, rcti *rect, rcti *back_rect, const float zoom, const bool use_unpadded, const char *name, int iconid, int but_flag, uiMenuItemSeparatorType separator_type, int *r_xmax)
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_state_numslider(uiWidgetType *wt, const uiWidgetStateInfo *state, blender::ui::EmbossType emboss)
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 uiWidgetType * popover_widget_type(uiBut *but, rcti *rect)
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 widget_state_nothing(uiWidgetType *wt, const uiWidgetStateInfo *, blender::ui::EmbossType)
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 void widgetbase_set_uniform_alpha_check(uiWidgetBase *wtb, const bool alpha_check)
static const uchar * widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state, const uiWidgetStateInfo *state, const blender::ui::EmbossType emboss)
#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
blender::Vector< blender::StringRef > UI_text_clip_multiline_middle(const uiFontStyle *fstyle, const char *str, char *clipped_str_buf, const size_t clipped_str_buf_maxncpy, const float max_line_width, const int max_lines)
static void widget_init(uiWidgetBase *wtb)
blender::gpu::Batch * roundbox_widget
static uiWidgetType * widget_type(uiWidgetTypeEnum type)
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_set_uniform_colors_ubv(uiWidgetBase *wtb, const uchar *col1, const uchar *col2, const uchar *outline, const uchar *emboss, const uchar *tria)
static void widget_draw_preview_icon(BIFIconID icon, float alpha, float aspect, const bool add_padding, const rcti *rect, const uchar mono_color[4])
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 widget_state_pie_menu_item(uiWidgetType *wt, const uiWidgetStateInfo *state, blender::ui::EmbossType)
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
#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])
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, const bool add_padding)
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_but(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *, int roundboxalign, const float zoom)
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
MINLINE unsigned char unit_float_to_uchar_clamp(float 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)
void node_draw_nodesocket(const rctf *rect, const float color_inner[4], const float color_outline[4], float outline_thickness, int shape, float aspect)
Definition drawnode.cc:1805
ColorTheme4< float > ColorTheme4f
const char * name
#define sqrtf
#define fmaxf
#define sinf
#define cosf
#define ceilf
#define atan2f
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)
#define min(a, b)
Definition sort.cc:36
float hsv_perceptual[3]
float pie_center_spawned[2]
ID * owner_id
Definition RNA_types.hh:51
int width
Definition BLF_api.hh:457
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_curve
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
ThemeUI tui
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
uiBlockAlertLevel alert_level
short content_hints
uiBut * next_but(const uiBut *but) const
Definition interface.cc:286
eButGradientType gradient_type
blender::ui::ButProgressType progress_type
blender::ui::AbstractViewItem * view_item
ListBase extra_op_icons
void * custom_data
IconTextOverlay icon_overlay_text
blender::ui::EmbossType emboss
PropertyRNA * rnaprop
char * editstr
uiHandleButtonData * active
ButType type
uiBlock * block
std::string drawstr
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 outline_sel[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]
blender::ui::EmbossType emboss
const uint(* index)[3]
uiWidgetColors wcol
void(* custom)(uiBut *, uiWidgetColors *, rcti *, const uiWidgetStateInfo *, int roundboxalign, const float zoom) ATTR_NONNULL()
const uiWidgetColors * wcol_theme
void(* state)(uiWidgetType *, const uiWidgetStateInfo *state, blender::ui::EmbossType emboss) ATTR_NONNULL()
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()
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len