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