Blender V4.3
interface_region_tooltip.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11/* TODO(@ideasman42):
12 * We may want to have a higher level API that initializes a timer,
13 * checks for mouse motion and clears the tool-tip afterwards.
14 * We never want multiple tool-tips at once
15 * so this could be handled on the window / window-manager level.
16 *
17 * For now it's not a priority, so leave as-is.
18 */
19
20#include <algorithm>
21#include <cstdarg>
22#include <cstdlib>
23#include <cstring>
24#include <memory>
25
26#include <fmt/format.h>
27
28#include "MEM_guardedalloc.h"
29
30#include "DNA_userdef_types.h"
31
32#include "BLI_fileops.h"
33#include "BLI_listbase.h"
34#include "BLI_math_color.h"
35#include "BLI_math_vector.h"
36#include "BLI_path_utils.hh"
37#include "BLI_rect.h"
38#include "BLI_string.h"
39#include "BLI_utildefines.h"
40
41#include "BKE_context.hh"
42#include "BKE_idtype.hh"
43#include "BKE_image.hh"
44#include "BKE_paint.hh"
45#include "BKE_screen.hh"
46
47#include "BIF_glutil.hh"
48
49#include "DNA_vfont_types.h"
50
51#include "GPU_immediate.hh"
52#include "GPU_immediate_util.hh"
53#include "GPU_state.hh"
54
55#include "IMB_imbuf.hh"
56#include "IMB_imbuf_types.hh"
57#include "IMB_thumbs.hh"
58
59#include "WM_api.hh"
60#include "WM_types.hh"
61
62#include "RNA_access.hh"
63#include "RNA_path.hh"
64#include "RNA_prototypes.hh"
65
66#include "UI_interface.hh"
67
68#include "BLF_api.hh"
69#include "BLT_translation.hh"
70
71#ifdef WITH_PYTHON
72# include "BPY_extern_run.hh"
73#endif
74
75#include "ED_screen.hh"
76
77#include "interface_intern.hh"
79
80#define UI_TIP_SPACER 0.3f
81#define UI_TIP_PADDING int(1.3f * UI_UNIT_Y)
82#define UI_TIP_MAXWIDTH 600
83#define UI_TIP_MAXIMAGEWIDTH 500
84#define UI_TIP_MAXIMAGEHEIGHT 300
85#define UI_TIP_STR_MAX 1024
86
91
93 std::string text;
94 std::string text_suffix;
95 struct {
102 std::optional<uiTooltipImage> image;
103};
104
112
113BLI_STATIC_ASSERT(int(UI_TIP_LC_MAX) == int(UI_TIP_LC_ALERT) + 1, "invalid lc-max");
114
116 std::string text,
117 std::string suffix,
118 const uiTooltipStyle style,
119 const uiTooltipColorID color_id,
120 const bool is_pad)
121{
122 if (is_pad) {
123 /* Add a spacer field before this one. */
125 }
126
127 uiTooltipField field{};
128 field.format.style = style;
129 field.format.color_id = color_id;
130 field.text = std::move(text);
131 field.text_suffix = std::move(suffix);
132 data.fields.append(std::move(field));
133}
134
136{
137 uiTooltipField field{};
139 field.image = image_data;
140 field.image->ibuf = IMB_dupImBuf(image_data.ibuf);
141 data.fields.append(std::move(field));
142}
143
144/* -------------------------------------------------------------------- */
148static void rgb_tint(float col[3], float h, float h_strength, float v, float v_strength)
149{
150 float col_hsv_from[3];
151 float col_hsv_to[3];
152
153 rgb_to_hsv_v(col, col_hsv_from);
154
155 col_hsv_to[0] = h;
156 col_hsv_to[1] = h_strength;
157 col_hsv_to[2] = (col_hsv_from[2] * (1.0f - v_strength)) + (v * v_strength);
158
159 hsv_to_rgb_v(col_hsv_to, col);
160}
161
162static void ui_tooltip_region_draw_cb(const bContext * /*C*/, ARegion *region)
163{
164 const float pad_px = UI_TIP_PADDING;
165 uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata);
166 const uiWidgetColors *theme = ui_tooltip_get_theme();
167 rcti bbox = data->bbox;
168 float tip_colors[UI_TIP_LC_MAX][3];
169 uchar drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */
170
171 /* The color from the theme. */
172 float *main_color = tip_colors[UI_TIP_LC_MAIN];
173 float *value_color = tip_colors[UI_TIP_LC_VALUE];
174 float *active_color = tip_colors[UI_TIP_LC_ACTIVE];
175 float *normal_color = tip_colors[UI_TIP_LC_NORMAL];
176 float *python_color = tip_colors[UI_TIP_LC_PYTHON];
177 float *alert_color = tip_colors[UI_TIP_LC_ALERT];
178
179 float background_color[3];
180
182
183 /* Draw background. */
184 ui_draw_tooltip_background(UI_style_get(), nullptr, &bbox);
185
186 /* set background_color */
187 rgb_uchar_to_float(background_color, theme->inner);
188
189 /* Calculate `normal_color`. */
190 rgb_uchar_to_float(main_color, theme->text);
191 copy_v3_v3(active_color, main_color);
192 copy_v3_v3(normal_color, main_color);
193 copy_v3_v3(python_color, main_color);
194 copy_v3_v3(alert_color, main_color);
195 copy_v3_v3(value_color, main_color);
196
197 /* Find the brightness difference between background and text colors. */
198
199 const float tone_bg = rgb_to_grayscale(background_color);
200 // tone_fg = rgb_to_grayscale(main_color);
201
202 /* Mix the colors. */
203 rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* Light gray. */
204 rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* Light blue. */
205 rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* Gray. */
206 rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* Dark gray. */
207 rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* Red. */
208
209 /* Draw text. */
210 BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width);
211 BLF_wordwrap(blf_mono_font, data->wrap_width);
212
213 bbox.xmin += 0.5f * pad_px; /* add padding to the text */
214 bbox.ymax -= 0.25f * pad_px;
215
216 for (int i = 0; i < data->fields.size(); i++) {
217 const uiTooltipField *field = &data->fields[i];
218
219 bbox.ymin = bbox.ymax - (data->lineh * field->geom.lines);
220 if (field->format.style == UI_TIP_STYLE_HEADER) {
221 uiFontStyleDraw_Params fs_params{};
222 fs_params.align = UI_STYLE_TEXT_LEFT;
223 fs_params.word_wrap = true;
224
225 /* Draw header and active data (is done here to be able to change color). */
226 rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]);
227 UI_fontstyle_set(&data->fstyle);
229 &data->fstyle, &bbox, field->text.c_str(), field->text.size(), drawcol, &fs_params);
230
231 /* Offset to the end of the last line. */
232 if (!field->text_suffix.empty()) {
233 const float xofs = field->geom.x_pos;
234 const float yofs = data->lineh * (field->geom.lines - 1);
235 bbox.xmin += xofs;
236 bbox.ymax -= yofs;
237
238 rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
239 UI_fontstyle_draw(&data->fstyle,
240 &bbox,
241 field->text_suffix.c_str(),
242 field->text_suffix.size(),
243 drawcol,
244 &fs_params);
245
246 /* Undo offset. */
247 bbox.xmin -= xofs;
248 bbox.ymax += yofs;
249 }
250 }
251 else if (field->format.style == UI_TIP_STYLE_MONO) {
252 uiFontStyleDraw_Params fs_params{};
253 fs_params.align = UI_STYLE_TEXT_LEFT;
254 fs_params.word_wrap = true;
255 uiFontStyle fstyle_mono = data->fstyle;
256 fstyle_mono.uifont_id = blf_mono_font;
257
258 UI_fontstyle_set(&fstyle_mono);
259 /* XXX: needed because we don't have mono in 'U.uifonts'. */
260 BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * UI_SCALE_FAC);
261 rgb_float_to_uchar(drawcol, tip_colors[int(field->format.color_id)]);
263 &fstyle_mono, &bbox, field->text.c_str(), field->text.size(), drawcol, &fs_params);
264 }
265 else if (field->format.style == UI_TIP_STYLE_IMAGE && field->image.has_value()) {
266
267 bbox.ymax -= field->image->height;
268
269 if (field->image->background == uiTooltipImageBackground::Checkerboard_Themed) {
270 imm_draw_box_checker_2d(float(bbox.xmin),
271 float(bbox.ymax),
272 float(bbox.xmin + field->image->width),
273 float(bbox.ymax + field->image->height));
274 }
275 else if (field->image->background == uiTooltipImageBackground::Checkerboard_Fixed) {
276 const float checker_dark = UI_ALPHA_CHECKER_DARK / 255.0f;
277 const float checker_light = UI_ALPHA_CHECKER_LIGHT / 255.0f;
278 const float color1[4] = {checker_dark, checker_dark, checker_dark, 1.0f};
279 const float color2[4] = {checker_light, checker_light, checker_light, 1.0f};
280 imm_draw_box_checker_2d_ex(float(bbox.xmin + U.pixelsize),
281 float(bbox.ymax + U.pixelsize),
282 float(bbox.xmin + field->image->width),
283 float(bbox.ymax + field->image->height),
284 color1,
285 color2,
286 8);
287 }
288
289 GPU_blend((field->image->premultiplied) ? GPU_BLEND_ALPHA_PREMULT : GPU_BLEND_ALPHA);
290
293 bbox.xmin,
294 bbox.ymax,
295 field->image->ibuf->x,
296 field->image->ibuf->y,
297 GPU_RGBA8,
298 true,
299 field->image->ibuf->byte_buffer.data,
300 1.0f,
301 1.0f,
302 float(field->image->width) / float(field->image->ibuf->x),
303 float(field->image->height) / float(field->image->ibuf->y),
304 (field->image->text_color) ? main_color : nullptr);
305
306 if (field->image->border) {
311 float border_color[4] = {1.0f, 1.0f, 1.0f, 0.15f};
312 float bgcolor[4];
314 if (rgb_to_grayscale(bgcolor) > 0.5f) {
315 border_color[0] = 0.0f;
316 border_color[1] = 0.0f;
317 border_color[2] = 0.0f;
318 }
319 immUniformColor4fv(border_color);
321 float(bbox.xmin),
322 float(bbox.ymax),
323 float(bbox.xmin + field->image->width),
324 float(bbox.ymax + field->image->height));
327 }
328 }
329 else if (field->format.style == UI_TIP_STYLE_SPACER) {
330 bbox.ymax -= data->lineh * UI_TIP_SPACER;
331 }
332 else {
333 BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL);
334 uiFontStyleDraw_Params fs_params{};
335 fs_params.align = UI_STYLE_TEXT_LEFT;
336 fs_params.word_wrap = true;
337
338 /* Draw remaining data. */
339 rgb_float_to_uchar(drawcol, tip_colors[int(field->format.color_id)]);
340 UI_fontstyle_set(&data->fstyle);
342 &data->fstyle, &bbox, field->text.c_str(), field->text.size(), drawcol, &fs_params);
343 }
344
345 bbox.ymax -= data->lineh * field->geom.lines;
346 }
347
348 BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP);
350}
351
353{
354 /* Put ownership back into a unique pointer. */
355 std::unique_ptr<uiTooltipData> data{static_cast<uiTooltipData *>(region->regiondata)};
356 for (uiTooltipField &field : data->fields) {
357 if (field.image && field.image->ibuf) {
358 IMB_freeImBuf(field.image->ibuf);
359 }
360 }
361 region->regiondata = nullptr;
362}
363
366/* -------------------------------------------------------------------- */
372 PointerRNA *opptr)
373{
374 std::string str = WM_operator_pystring_ex(C, nullptr, false, false, ot, opptr);
375
376 /* Avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary. */
377 return WM_operator_pystring_abbreviate(std::move(str), 32);
378}
379
382/* -------------------------------------------------------------------- */
386#ifdef WITH_PYTHON
387
388static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData &data, wmKeyMap *keymap)
389{
390 const int fields_len_init = data.fields.size();
391
392 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
393 wmOperatorType *ot = WM_operatortype_find(kmi->idname, true);
394 if (!ot) {
395 continue;
396 }
397 /* Tip. */
399 ot->description ? ot->description : ot->name,
400 {},
403 true);
404
405 /* Shortcut. */
406 const std::string kmi_str = WM_keymap_item_to_string(kmi, false).value_or("None");
408 fmt::format(TIP_("Shortcut: {}"), kmi_str),
409 {},
412
413 /* Python. */
414 if (U.flag & USER_TOOLTIPS_PYTHON) {
415 std::string str = ui_tooltip_text_python_from_op(C, ot, kmi->ptr);
417 data, fmt::format(TIP_("Python: {}"), str), {}, UI_TIP_STYLE_MONO, UI_TIP_LC_PYTHON);
418 }
419 }
420
421 return (fields_len_init != data.fields.size());
422}
423
424#endif /* WITH_PYTHON */
425
427{
428 if (tip.is_empty()) {
429 return false;
430 }
431
432 /* Already ends with punctuation. */
433 if (ELEM(tip.back(), '.', '!', '?')) {
434 return false;
435 }
436
437 /* Contains a bullet Unicode character. */
438 if (tip.find("\xe2\x80\xa2") != blender::StringRef::not_found) {
439 return false;
440 }
441
442 return true;
443}
444
448static std::unique_ptr<uiTooltipData> ui_tooltip_data_from_tool(bContext *C,
449 uiBut *but,
450 bool is_label)
451{
452 if (but->optype == nullptr) {
453 return nullptr;
454 }
455 /* While this should always be set for buttons as they are shown in the UI,
456 * the operator search popup can create a button that has no properties, see: #112541. */
457 if (but->opptr == nullptr) {
458 return nullptr;
459 }
460
461 if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_id")) {
462 return nullptr;
463 }
464
465 /* Needed to get the space-data's type (below). */
466 if (CTX_wm_space_data(C) == nullptr) {
467 return nullptr;
468 }
469
470 char tool_id[MAX_NAME];
471 RNA_string_get(but->opptr, "name", tool_id);
472 BLI_assert(tool_id[0] != '\0');
473
474 /* When false, we're in a different space type to the tool being set.
475 * Needed for setting the fallback tool from the properties space.
476 *
477 * If we drop the hard coded 3D-view in properties hack, we can remove this check. */
478 bool has_valid_context = true;
479 const char *has_valid_context_error = IFACE_("Unsupported context");
480 {
481 ScrArea *area = CTX_wm_area(C);
482 if (area == nullptr) {
483 has_valid_context = false;
484 }
485 else {
486 PropertyRNA *prop = RNA_struct_find_property(but->opptr, "space_type");
487 if (RNA_property_is_set(but->opptr, prop)) {
488 const int space_type_prop = RNA_property_enum_get(but->opptr, prop);
489 if (space_type_prop != area->spacetype) {
490 has_valid_context = false;
491 }
492 }
493 }
494 }
495
496 /* We have a tool, now extract the info. */
497 std::unique_ptr<uiTooltipData> data = std::make_unique<uiTooltipData>();
498
499#ifdef WITH_PYTHON
500 /* It turns out to be most simple to do this via Python since C
501 * doesn't have access to information about non-active tools. */
502
503 /* Title (when icon-only). */
504 if (but->drawstr.empty()) {
505 const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
506 char expr[256];
507 SNPRINTF(expr,
508 "bl_ui.space_toolsystem_common.item_from_id("
509 "bpy.context, "
510 "bpy.context.space_data.type, "
511 "'%s').label",
512 tool_id);
513 char *expr_result = nullptr;
514 bool is_error = false;
515
516 if (has_valid_context == false) {
517 expr_result = BLI_strdup(has_valid_context_error);
518 }
519 else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) {
520 if (STREQ(expr_result, "")) {
521 MEM_freeN(expr_result);
522 expr_result = nullptr;
523 }
524 }
525 else {
526 /* NOTE: this is an exceptional case, we could even remove it
527 * however there have been reports of tooltips failing, so keep it for now. */
528 expr_result = BLI_strdup(IFACE_("Internal error!"));
529 is_error = true;
530 }
531
532 if (expr_result != nullptr) {
533 /* NOTE: This is a very weak hack to get a valid translation most of the time...
534 * Proper way to do would be to get i18n context from the item, somehow. */
535 const char *label_str = CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, expr_result);
536 if (label_str == expr_result) {
537 label_str = IFACE_(expr_result);
538 }
539
540 if (label_str != expr_result) {
541 MEM_freeN(expr_result);
542 expr_result = BLI_strdup(label_str);
543 }
544
546 expr_result,
547 {},
549 (is_error) ? UI_TIP_LC_ALERT : UI_TIP_LC_MAIN,
550 true);
551 MEM_freeN(expr_result);
552 }
553 }
554
555 /* Tip. */
556 if (is_label == false) {
557 const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
558 char expr[256];
559 SNPRINTF(expr,
560 "bl_ui.space_toolsystem_common.description_from_id("
561 "bpy.context, "
562 "bpy.context.space_data.type, "
563 "'%s')",
564 tool_id);
565
566 char *expr_result = nullptr;
567 bool is_error = false;
568
569 if (has_valid_context == false) {
570 expr_result = BLI_strdup(has_valid_context_error);
571 }
572 else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) {
573 if (STREQ(expr_result, "")) {
574 MEM_freeN(expr_result);
575 expr_result = nullptr;
576 }
577 }
578 else {
579 /* NOTE: this is an exceptional case, we could even remove it
580 * however there have been reports of tooltips failing, so keep it for now. */
581 expr_result = BLI_strdup(TIP_("Internal error!"));
582 is_error = true;
583 }
584
585 if (expr_result != nullptr) {
586 const bool add_period = ui_tooltip_period_needed(expr_result);
588 fmt::format("{}{}", expr_result, add_period ? "." : ""),
589 {},
591 (is_error) ? UI_TIP_LC_ALERT : UI_TIP_LC_MAIN,
592 true);
593 MEM_freeN(expr_result);
594 }
595 }
596
597 /* Shortcut. */
598 const bool show_shortcut = is_label == false &&
600
601 if (show_shortcut) {
602 /* There are different kinds of shortcuts:
603 *
604 * - Direct access to the tool (as if the toolbar button is pressed).
605 * - The key is assigned to the operator itself
606 * (bypassing the tool, executing the operator).
607 *
608 * Either way case it's useful to show the shortcut.
609 */
610 std::string shortcut = UI_but_string_get_operator_keymap(*C, *but);
611
612 if (shortcut.empty()) {
613 /* Check for direct access to the tool. */
614 if (std::optional<std::string> shortcut_toolbar = WM_key_event_operator_string(
615 C, "WM_OT_toolbar", WM_OP_INVOKE_REGION_WIN, nullptr, true))
616 {
617 /* Generate keymap in order to inspect it.
618 * NOTE: we could make a utility to avoid the keymap generation part of this. */
619 const char *expr_imports[] = {
620 "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", nullptr};
621 const char *expr =
622 ("getattr("
623 "bl_keymap_utils.keymap_from_toolbar.generate("
624 "bpy.context, "
625 "bpy.context.space_data.type), "
626 "'as_pointer', lambda: 0)()");
627
628 intptr_t expr_result = 0;
629
630 if (has_valid_context == false) {
631 shortcut = has_valid_context_error;
632 }
633 else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) {
634 if (expr_result != 0) {
635 wmKeyMap *keymap = (wmKeyMap *)expr_result;
636 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
637 if (STREQ(kmi->idname, but->optype->idname)) {
638 char tool_id_test[MAX_NAME];
639 RNA_string_get(kmi->ptr, "name", tool_id_test);
640 if (STREQ(tool_id, tool_id_test)) {
641 std::string kmi_str = WM_keymap_item_to_string(kmi, false).value_or("");
642 shortcut = fmt::format("{}, {}", *shortcut_toolbar, kmi_str);
643 break;
644 }
645 }
646 }
647 }
648 }
649 else {
650 BLI_assert(0);
651 }
652 }
653 }
654
655 if (!shortcut.empty()) {
657 fmt::format(TIP_("Shortcut: {}"), shortcut),
658 {},
661 true);
662 }
663 }
664
665 if (show_shortcut) {
666 /* Shortcut for Cycling
667 *
668 * As a second option, we may have a shortcut to cycle this tool group.
669 *
670 * Since some keymaps may use this for the primary means of binding keys,
671 * it's useful to show these too.
672 * Without this there is no way to know how to use a key to set the tool.
673 *
674 * This is a little involved since the shortcut may be bound to another tool in this group,
675 * instead of the current tool on display. */
676
677 char *expr_result = nullptr;
678 size_t expr_result_len;
679
680 {
681 const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
682 char expr[256];
683 SNPRINTF(expr,
684 "'\\x00'.join("
685 "item.idname for item in bl_ui.space_toolsystem_common.item_group_from_id("
686 "bpy.context, "
687 "bpy.context.space_data.type, '%s', coerce=True) "
688 "if item is not None)",
689 tool_id);
690
691 if (has_valid_context == false) {
692 /* pass */
693 }
695 C, expr_imports, expr, nullptr, &expr_result, &expr_result_len))
696 {
697 /* pass. */
698 }
699 }
700
701 if (expr_result != nullptr) {
702 PointerRNA op_props;
704 RNA_boolean_set(&op_props, "cycle", true);
705
706 std::optional<std::string> shortcut;
707
708 const char *item_end = expr_result + expr_result_len;
709 const char *item_step = expr_result;
710
711 while (item_step < item_end) {
712 RNA_string_set(&op_props, "name", item_step);
713 shortcut = WM_key_event_operator_string(C,
714 but->optype->idname,
716 static_cast<IDProperty *>(op_props.data),
717 true);
718 if (shortcut) {
719 break;
720 }
721 item_step += strlen(item_step) + 1;
722 }
723
725 MEM_freeN(expr_result);
726
727 if (shortcut) {
729 fmt::format(TIP_("Shortcut Cycle: {}"), *shortcut),
730 {},
733 true);
734 }
735 }
736 }
737
738 /* Python */
739 if ((is_label == false) && (U.flag & USER_TOOLTIPS_PYTHON)) {
740 std::string str = ui_tooltip_text_python_from_op(C, but->optype, but->opptr);
742 fmt::format(TIP_("Python: {}"), str),
743 {},
746 true);
747 }
748
749 /* Keymap */
750
751 /* This is too handy not to expose somehow, let's be sneaky for now. */
752 if ((is_label == false) && CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
753 const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
754 char expr[256];
755 SNPRINTF(expr,
756 "getattr("
757 "bl_ui.space_toolsystem_common.keymap_from_id("
758 "bpy.context, "
759 "bpy.context.space_data.type, "
760 "'%s'), "
761 "'as_pointer', lambda: 0)()",
762 tool_id);
763
764 intptr_t expr_result = 0;
765
766 if (has_valid_context == false) {
767 /* pass */
768 }
769 else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) {
770 if (expr_result != 0) {
772 *data, TIP_("Tool Keymap:"), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL, true);
773 wmKeyMap *keymap = (wmKeyMap *)expr_result;
774 ui_tooltip_data_append_from_keymap(C, *data, keymap);
775 }
776 }
777 else {
778 BLI_assert(0);
779 }
780 }
781#else
782 UNUSED_VARS(is_label, has_valid_context, has_valid_context_error);
783#endif /* WITH_PYTHON */
784
785 return data->fields.is_empty() ? nullptr : std::move(data);
786}
787
788static std::unique_ptr<uiTooltipData> ui_tooltip_data_from_button_or_extra_icon(
789 bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, const bool is_label)
790{
791 char buf[512];
792
793 wmOperatorType *optype = extra_icon ? UI_but_extra_operator_icon_optype_get(extra_icon) :
794 but->optype;
795 PropertyRNA *rnaprop = extra_icon ? nullptr : but->rnaprop;
796
797 std::unique_ptr<uiTooltipData> data = std::make_unique<uiTooltipData>();
798
799 /* Menus already show shortcuts, don't show them in the tool-tips. */
800 const bool is_menu = ui_block_is_menu(but->block) && !ui_block_is_pie_menu(but->block);
801
802 std::string but_label;
803 std::string but_tip;
804 std::string but_tip_label;
805 std::string op_keymap;
806 std::string prop_keymap;
807 std::string rna_struct;
808 std::string rna_prop;
809 std::string enum_label;
810 std::string enum_tip;
811
812 if (extra_icon) {
813 if (is_label) {
814 but_label = UI_but_extra_icon_string_get_label(*extra_icon);
815 }
816 else {
817 but_label = UI_but_extra_icon_string_get_label(*extra_icon);
818 but_tip = UI_but_extra_icon_string_get_tooltip(*C, *extra_icon);
819 if (!is_menu) {
820 op_keymap = UI_but_extra_icon_string_get_operator_keymap(*C, *extra_icon);
821 }
822 }
823 }
824 else {
825 const std::optional<EnumPropertyItem> enum_item = UI_but_rna_enum_item_get(*C, *but);
826 if (is_label) {
827 but_tip_label = UI_but_string_get_tooltip_label(*but);
828 but_label = UI_but_string_get_label(*but);
829 enum_label = enum_item ? enum_item->name : "";
830 }
831 else {
832 but_label = UI_but_string_get_label(*but);
833 but_tip_label = UI_but_string_get_tooltip_label(*but);
834 but_tip = UI_but_string_get_tooltip(*C, *but);
835 enum_label = enum_item ? enum_item->name : "";
836 const char *description_c = enum_item ? enum_item->description : nullptr;
837 enum_tip = description_c ? description_c : "";
838 if (!is_menu) {
839 op_keymap = UI_but_string_get_operator_keymap(*C, *but);
840 prop_keymap = UI_but_string_get_property_keymap(*C, *but);
841 }
844 }
845 }
846
847 /* Label: If there is a custom tooltip label, use that to override the label to display.
848 * Otherwise fallback to the regular label. */
849 if (!but_tip_label.empty()) {
851 }
852 /* Regular (non-custom) label. Only show when the button doesn't already show the label. Check
853 * prefix instead of comparing because the button may include the shortcut. Buttons with dynamic
854 * tool-tips also don't get their default label here since they can already provide more accurate
855 * and specific tool-tip content. */
856 else if (!but_label.empty() && !blender::StringRef(but->drawstr).startswith(but_label) &&
857 !but->tip_func)
858 {
860 }
861
862 /* Tip */
863 if (!but_tip.empty()) {
864 if (!enum_label.empty()) {
866 *data, fmt::format("{}: ", but_tip), enum_label, UI_TIP_STYLE_HEADER, UI_TIP_LC_NORMAL);
867 }
868 else {
869 const bool add_period = ui_tooltip_period_needed(but_tip);
871 fmt::format("{}{}", but_tip, add_period ? "." : ""),
872 {},
875 }
876
877 /* special case enum rna buttons */
878 if ((but->type & UI_BTYPE_ROW) && rnaprop && RNA_property_flag(rnaprop) & PROP_ENUM_FLAG) {
880 TIP_("(Shift-Click/Drag to select multiple)"),
881 {},
884 }
885 }
886 /* When there is only an enum label (no button label or tip), draw that as header. */
887 else if (!enum_label.empty() && but_label.empty()) {
889 *data, std::move(enum_label), {}, UI_TIP_STYLE_HEADER, UI_TIP_LC_NORMAL);
890 }
891
892 /* Don't include further details if this is just a quick label tooltip. */
893 if (is_label) {
894 return data->fields.is_empty() ? nullptr : std::move(data);
895 }
896
897 /* Enum field label & tip. */
898 if (!enum_tip.empty()) {
900 *data, std::move(enum_tip), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_VALUE);
901 }
902
903 /* Operator shortcut. */
904 if (!op_keymap.empty()) {
906 fmt::format(TIP_("Shortcut: {}"), op_keymap),
907 {},
910 true);
911 }
912
913 /* Property context-toggle shortcut. */
914 if (!prop_keymap.empty()) {
916 fmt::format(TIP_("Shortcut: {}"), prop_keymap),
917 {},
920 true);
921 }
922
924 /* Better not show the value of a password. */
925 if ((rnaprop && (RNA_property_subtype(rnaprop) == PROP_PASSWORD)) == 0) {
926 /* Full string. */
927 ui_but_string_get(but, buf, sizeof(buf));
928 if (buf[0]) {
930 fmt::format(TIP_("Value: {}"), buf),
931 {},
934 true);
935 }
936 }
937 }
938
939 if (rnaprop) {
940 const int unit_type = UI_but_unit_type_get(but);
941
942 if (unit_type == PROP_UNIT_ROTATION) {
943 if (RNA_property_type(rnaprop) == PROP_FLOAT) {
944 float value = RNA_property_array_check(rnaprop) ?
945 RNA_property_float_get_index(&but->rnapoin, rnaprop, but->rnaindex) :
946 RNA_property_float_get(&but->rnapoin, rnaprop);
948 fmt::format(TIP_("Radians: {}"), value),
949 {},
952 }
953 }
954
955 if (but->flag & UI_BUT_DRIVEN) {
956 if (ui_but_anim_expression_get(but, buf, sizeof(buf))) {
958 fmt::format(TIP_("Expression: {}"), buf),
959 {},
962 }
963 }
964
965 if (but->rnapoin.owner_id) {
966 const ID *id = but->rnapoin.owner_id;
967 if (ID_IS_LINKED(id)) {
969 fmt::format(TIP_("Library: {}"), id->lib->filepath),
970 {},
973 }
974 }
975 }
976 else if (optype) {
977 PointerRNA *opptr = extra_icon ? UI_but_extra_operator_icon_opptr_get(extra_icon) :
978 /* Allocated when needed, the button owns it. */
980
981 /* So the context is passed to field functions (some Python field functions use it). */
983
984 std::string str = ui_tooltip_text_python_from_op(C, optype, opptr);
985
986 /* Operator info. */
987 if (U.flag & USER_TOOLTIPS_PYTHON) {
989 fmt::format(TIP_("Python: {}"), str),
990 {},
993 true);
994 }
995 }
996
997 /* Button is disabled, we may be able to tell user why. */
998 if ((but->flag & UI_BUT_DISABLED) || extra_icon) {
999 const char *disabled_msg_orig = nullptr;
1000 const char *disabled_msg = nullptr;
1001 bool disabled_msg_free = false;
1002
1003 /* If operator poll check failed, it can give pretty precise info why. */
1004 if (optype) {
1005 const wmOperatorCallContext opcontext = extra_icon ? extra_icon->optype_params->opcontext :
1006 but->opcontext;
1007 wmOperatorCallParams call_params{};
1008 call_params.optype = optype;
1009 call_params.opcontext = opcontext;
1011 ui_but_context_poll_operator_ex(C, but, &call_params);
1012 disabled_msg_orig = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free);
1013 disabled_msg = TIP_(disabled_msg_orig);
1014 }
1015 /* Alternatively, buttons can store some reasoning too. */
1016 else if (!extra_icon && but->disabled_info) {
1017 disabled_msg = TIP_(but->disabled_info);
1018 }
1019
1020 if (disabled_msg && disabled_msg[0]) {
1022 fmt::format(TIP_("Disabled: {}"), disabled_msg),
1023 {},
1026 }
1027 if (disabled_msg_free) {
1028 MEM_freeN((void *)disabled_msg_orig);
1029 }
1030 }
1031
1032 if ((U.flag & USER_TOOLTIPS_PYTHON) && !optype && !rna_struct.empty()) {
1033 {
1035 rna_prop.empty() ?
1036 fmt::format(TIP_("Python: {}"), rna_struct) :
1037 fmt::format(TIP_("Python: {}.{}"), rna_struct, rna_prop),
1038 {},
1041 (data->fields.size() > 0));
1042 }
1043
1044 if (but->rnapoin.owner_id) {
1045 std::optional<std::string> str = rnaprop ? RNA_path_full_property_py_ex(
1046 &but->rnapoin, rnaprop, but->rnaindex, true) :
1049 }
1050 }
1051
1052 if (but->type == UI_BTYPE_COLOR) {
1053
1054 float color[4];
1055 ui_but_v3_get(but, color);
1056 color[3] = 1.0f;
1057
1058 if (but->rnaprop) {
1059 BLI_assert(but->rnaindex == -1);
1060 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
1061 color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
1062 }
1063 }
1064
1065 if (!ui_but_is_color_gamma(but)) {
1067 }
1068
1069 uchar rgb_hex_uchar[4];
1070 rgba_float_to_uchar(rgb_hex_uchar, color);
1071 const std::string hex_st = fmt::format("Hex: #{:02X}{:02X}{:02X}{:02X}",
1072 int(rgb_hex_uchar[0]),
1073 int(rgb_hex_uchar[1]),
1074 int(rgb_hex_uchar[2]),
1075 int(rgb_hex_uchar[3]));
1076
1077 const std::string rgba_st = fmt::format("{}: {:.3f} {:.3f} {:.3f} {:.3f}",
1078 TIP_("RGBA"),
1079 color[0],
1080 color[1],
1081 color[2],
1082 color[3]);
1083 float hsva[4];
1084 rgb_to_hsv_v(color, hsva);
1085 hsva[3] = color[3];
1086 const std::string hsva_st = fmt::format(
1087 "{}: {:.3f} {:.3f} {:.3f} {:.3f}", TIP_("HSVA"), hsva[0], hsva[1], hsva[2], hsva[3]);
1088
1089 const uiFontStyle *fs = &UI_style_get()->tooltip;
1091 float w = BLF_width(blf_mono_font, hsva_st.c_str(), hsva_st.size());
1092
1093 uiTooltipImage image_data;
1094 image_data.width = int(w);
1095 image_data.height = int(w / 4.0f);
1096 image_data.ibuf = IMB_allocImBuf(image_data.width, image_data.height, 32, IB_rect);
1097 image_data.border = true;
1098 image_data.premultiplied = false;
1099
1101 if (color[3] == 1.0f) {
1102 /* No transparency so draw the entire area solid without checkerboard. */
1105 image_data.ibuf, color, 1, 1, image_data.width, image_data.height, display);
1106 }
1107 else {
1109 /* Draw one half with transparency. */
1110 IMB_rectfill_area(image_data.ibuf,
1111 color,
1112 image_data.width / 2,
1113 1,
1114 image_data.width,
1115 image_data.height,
1116 display);
1117 /* Draw the other half with a solid color. */
1118 color[3] = 1.0f;
1120 image_data.ibuf, color, 1, 1, image_data.width / 2, image_data.height, display);
1121 }
1122
1125 UI_tooltip_image_field_add(*data, image_data);
1131
1132 /* Tooltip now owns a copy of the ImBuf, so we can delete ours.*/
1133 IMB_freeImBuf(image_data.ibuf);
1134 }
1135
1136 return data->fields.is_empty() ? nullptr : std::move(data);
1137}
1138
1139static std::unique_ptr<uiTooltipData> ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
1140{
1141 std::unique_ptr<uiTooltipData> data = std::make_unique<uiTooltipData>();
1142
1143 /* TODO(@ideasman42): a way for gizmos to have their own descriptions (low priority). */
1144
1145 /* Operator Actions */
1146 {
1147 const bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part;
1148 struct GizmoOpActions {
1149 int part;
1150 const char *prefix;
1151 };
1152 GizmoOpActions gzop_actions[] = {
1153 {
1154 gz->highlight_part,
1155 use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : nullptr,
1156 },
1157 {
1158 use_drag ? gz->drag_part : -1,
1159 use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : nullptr,
1160 },
1161 };
1162
1163 for (int i = 0; i < ARRAY_SIZE(gzop_actions); i++) {
1164 wmGizmoOpElem *gzop = (gzop_actions[i].part != -1) ?
1165 WM_gizmo_operator_get(gz, gzop_actions[i].part) :
1166 nullptr;
1167 if (gzop != nullptr) {
1168 /* Description */
1169 std::string info = WM_operatortype_description_or_name(C, gzop->type, &gzop->ptr);
1170
1171 if (!info.empty()) {
1173 *data,
1174 gzop_actions[i].prefix ? fmt::format("{}: {}", gzop_actions[i].prefix, info) : info,
1175 {},
1178 false);
1179 }
1180
1181 /* Shortcut */
1182 {
1183 IDProperty *prop = static_cast<IDProperty *>(gzop->ptr.data);
1184 if (std::optional<std::string> shortcut_str = WM_key_event_operator_string(
1185 C, gzop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true))
1186 {
1188 fmt::format(TIP_("Shortcut: {}"), *shortcut_str),
1189 {},
1192 true);
1193 }
1194 }
1195 }
1196 }
1197 }
1198
1199 /* Property Actions */
1200 if (gz->type->target_property_defs_len) {
1202 for (int i = 0; i < gz->type->target_property_defs_len; i++) {
1203 /* TODO(@ideasman42): function callback descriptions. */
1204 wmGizmoProperty *gz_prop = &gz_prop_array[i];
1205 if (gz_prop->prop != nullptr) {
1206 const char *info = RNA_property_ui_description(gz_prop->prop);
1207 if (info && info[0]) {
1209 }
1210 }
1211 }
1212 }
1213
1214 return data->fields.is_empty() ? nullptr : std::move(data);
1215}
1216
1217static std::unique_ptr<uiTooltipData> ui_tooltip_data_from_custom_func(bContext *C, uiBut *but)
1218{
1219 /* Create tooltip data. */
1220 std::unique_ptr<uiTooltipData> data = std::make_unique<uiTooltipData>();
1221
1222 /* Create fields from custom callback. */
1223 but->tip_custom_func(*C, *data, but->tip_arg);
1224
1225 return data->fields.is_empty() ? nullptr : std::move(data);
1226}
1227
1229 std::unique_ptr<uiTooltipData> data_uptr,
1230 const float init_position[2],
1231 const rcti *init_rect_overlap)
1232{
1233 const float pad_px = UI_TIP_PADDING;
1234 wmWindow *win = CTX_wm_window(C);
1235 const blender::int2 win_size = WM_window_native_pixel_size(win);
1236 const uiStyle *style = UI_style_get();
1237 rcti rect_i;
1238 int font_flag = 0;
1239
1240 /* Create area region. */
1242
1243 static ARegionType type;
1244 memset(&type, 0, sizeof(ARegionType));
1245 type.draw = ui_tooltip_region_draw_cb;
1246 type.free = ui_tooltip_region_free_cb;
1247 type.regionid = RGN_TYPE_TEMPORARY;
1248 region->type = &type;
1249 /* Move ownership to region data. The region type free callback puts it back into a unique
1250 * pointer for save freeing. */
1251 region->regiondata = data_uptr.release();
1252
1253 uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata);
1254
1255 /* Set font, get bounding-box. */
1256 data->fstyle = style->tooltip; /* copy struct */
1257
1258 UI_fontstyle_set(&data->fstyle);
1259
1260 data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize, win_size[0] - (UI_TIP_PADDING * 2));
1261
1262 font_flag |= BLF_WORD_WRAP;
1263 BLF_enable(data->fstyle.uifont_id, font_flag);
1264 BLF_enable(blf_mono_font, font_flag);
1265 BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width);
1266 BLF_wordwrap(blf_mono_font, data->wrap_width);
1267
1268 /* These defines tweaked depending on font. */
1269#define TIP_BORDER_X (16.0f)
1270#define TIP_BORDER_Y (6.0f)
1271
1272 int h = BLF_height_max(data->fstyle.uifont_id);
1273
1274 int i, fonth, fontw;
1275 for (i = 0, fontw = 0, fonth = 0; i < data->fields.size(); i++) {
1276 uiTooltipField *field = &data->fields[i];
1277 ResultBLF info = {0};
1278 int w = 0;
1279 int x_pos = 0;
1280 int font_id;
1281
1282 if (field->format.style == UI_TIP_STYLE_MONO) {
1283 BLF_size(blf_mono_font, data->fstyle.points * UI_SCALE_FAC);
1284 font_id = blf_mono_font;
1285 }
1286 else {
1287 font_id = data->fstyle.uifont_id;
1288 }
1289
1290 if (!field->text.empty()) {
1291 w = BLF_width(font_id, field->text.c_str(), field->text.size(), &info);
1292 }
1293
1294 /* check for suffix (enum label) */
1295 if (!field->text_suffix.empty()) {
1296 x_pos = info.width;
1297 w = max_ii(
1298 w, x_pos + BLF_width(font_id, field->text_suffix.c_str(), field->text_suffix.size()));
1299 }
1300
1301 fonth += h * info.lines;
1302
1303 if (field->format.style == UI_TIP_STYLE_SPACER) {
1304 fonth += h * UI_TIP_SPACER;
1305 }
1306
1307 if (field->format.style == UI_TIP_STYLE_IMAGE && field->image) {
1308 fonth += field->image->height;
1309 w = max_ii(w, field->image->width);
1310 }
1311
1312 fontw = max_ii(fontw, w);
1313
1314 field->geom.lines = info.lines;
1315 field->geom.x_pos = x_pos;
1316 }
1317
1318 BLF_disable(data->fstyle.uifont_id, font_flag);
1319 BLF_disable(blf_mono_font, font_flag);
1320
1321 data->toth = fonth;
1322 data->lineh = h;
1323
1324 /* Compute position. */
1325 {
1326 rctf rect_fl;
1327 rect_fl.xmin = init_position[0] - TIP_BORDER_X;
1328 rect_fl.xmax = rect_fl.xmin + fontw + pad_px;
1329 rect_fl.ymax = init_position[1] - TIP_BORDER_Y;
1330 rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y;
1331 BLI_rcti_rctf_copy(&rect_i, &rect_fl);
1332 }
1333
1334#undef TIP_BORDER_X
1335#undef TIP_BORDER_Y
1336
1337 // #define USE_ALIGN_Y_CENTER
1338
1339 /* Clamp to window bounds. */
1340 {
1341 /* Ensure at least 5 px above screen bounds.
1342 * #UI_UNIT_Y is just a guess to be above the menu item. */
1343 if (init_rect_overlap != nullptr) {
1344 const int pad = max_ff(1.0f, U.pixelsize) * 5;
1345 rcti init_rect;
1346 init_rect.xmin = init_rect_overlap->xmin - pad;
1347 init_rect.xmax = init_rect_overlap->xmax + pad;
1348 init_rect.ymin = init_rect_overlap->ymin - pad;
1349 init_rect.ymax = init_rect_overlap->ymax + pad;
1350 rcti rect_clamp;
1351 rect_clamp.xmin = 0;
1352 rect_clamp.xmax = win_size[0];
1353 rect_clamp.ymin = 0;
1354 rect_clamp.ymax = win_size[1];
1355 /* try right. */
1356 const int size_x = BLI_rcti_size_x(&rect_i);
1357 const int size_y = BLI_rcti_size_y(&rect_i);
1358 const int cent_overlap_x = BLI_rcti_cent_x(&init_rect);
1359#ifdef USE_ALIGN_Y_CENTER
1360 const int cent_overlap_y = BLI_rcti_cent_y(&init_rect);
1361#endif
1362 struct {
1363 rcti xpos;
1364 rcti xneg;
1365 rcti ypos;
1366 rcti yneg;
1367 } rect;
1368
1369 { /* xpos */
1370 rcti r = rect_i;
1371 r.xmin = init_rect.xmax;
1372 r.xmax = r.xmin + size_x;
1373#ifdef USE_ALIGN_Y_CENTER
1374 r.ymin = cent_overlap_y - (size_y / 2);
1375 r.ymax = r.ymin + size_y;
1376#else
1377 r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i);
1378 r.ymax = init_rect.ymax;
1379 r.ymin -= UI_POPUP_MARGIN;
1380 r.ymax -= UI_POPUP_MARGIN;
1381#endif
1382 rect.xpos = r;
1383 }
1384 { /* xneg */
1385 rcti r = rect_i;
1386 r.xmin = init_rect.xmin - size_x;
1387 r.xmax = r.xmin + size_x;
1388#ifdef USE_ALIGN_Y_CENTER
1389 r.ymin = cent_overlap_y - (size_y / 2);
1390 r.ymax = r.ymin + size_y;
1391#else
1392 r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i);
1393 r.ymax = init_rect.ymax;
1394 r.ymin -= UI_POPUP_MARGIN;
1395 r.ymax -= UI_POPUP_MARGIN;
1396#endif
1397 rect.xneg = r;
1398 }
1399 { /* ypos */
1400 rcti r = rect_i;
1401 r.xmin = cent_overlap_x - (size_x / 2);
1402 r.xmax = r.xmin + size_x;
1403 r.ymin = init_rect.ymax;
1404 r.ymax = r.ymin + size_y;
1405 rect.ypos = r;
1406 }
1407 { /* yneg */
1408 rcti r = rect_i;
1409 r.xmin = cent_overlap_x - (size_x / 2);
1410 r.xmax = r.xmin + size_x;
1411 r.ymin = init_rect.ymin - size_y;
1412 r.ymax = r.ymin + size_y;
1413 rect.yneg = r;
1414 }
1415
1416 bool found = false;
1417 for (int j = 0; j < 4; j++) {
1418 const rcti *r = (&rect.xpos) + j;
1419 if (BLI_rcti_inside_rcti(&rect_clamp, r)) {
1420 rect_i = *r;
1421 found = true;
1422 break;
1423 }
1424 }
1425 if (!found) {
1426 /* Fallback, we could pick the best fallback, for now just use xpos. */
1427 int offset_dummy[2];
1428 rect_i = rect.xpos;
1429 BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy);
1430 }
1431 }
1432 else {
1433 const int pad = max_ff(1.0f, U.pixelsize) * 5;
1434 rcti rect_clamp;
1435 rect_clamp.xmin = pad;
1436 rect_clamp.xmax = win_size[0] - pad;
1437 rect_clamp.ymin = pad + (UI_UNIT_Y * 2);
1438 rect_clamp.ymax = win_size[1] - pad;
1439 int offset_dummy[2];
1440 BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy);
1441 }
1442 }
1443
1444#undef USE_ALIGN_Y_CENTER
1445
1446 /* add padding */
1447 BLI_rcti_resize(&rect_i, BLI_rcti_size_x(&rect_i) + pad_px, BLI_rcti_size_y(&rect_i) + pad_px);
1448
1449 /* widget rect, in region coords */
1450 {
1451 /* Compensate for margin offset, visually this corrects the position. */
1452 const int margin = UI_POPUP_MARGIN;
1453 if (init_rect_overlap != nullptr) {
1454 BLI_rcti_translate(&rect_i, margin, margin / 2);
1455 }
1456
1457 data->bbox.xmin = margin;
1458 data->bbox.xmax = BLI_rcti_size_x(&rect_i) - margin;
1459 data->bbox.ymin = margin;
1460 data->bbox.ymax = BLI_rcti_size_y(&rect_i);
1461
1462 /* region bigger for shadow */
1463 region->winrct.xmin = rect_i.xmin - margin;
1464 region->winrct.xmax = rect_i.xmax + margin;
1465 region->winrct.ymin = rect_i.ymin - margin;
1466 region->winrct.ymax = rect_i.ymax + margin;
1467 }
1468
1469 /* Adds sub-window. */
1471
1472 /* notify change and redraw */
1473 ED_region_tag_redraw(region);
1474
1475 return region;
1476}
1477
1480/* -------------------------------------------------------------------- */
1485 bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label)
1486{
1487 wmWindow *win = CTX_wm_window(C);
1488 float init_position[2];
1489
1490 if (but->drawflag & UI_BUT_NO_TOOLTIP) {
1491 return nullptr;
1492 }
1493 std::unique_ptr<uiTooltipData> data = nullptr;
1494
1495 if (but->tip_custom_func) {
1496 data = ui_tooltip_data_from_custom_func(C, but);
1497 }
1498
1499 if (data == nullptr) {
1500 data = ui_tooltip_data_from_tool(C, but, is_label);
1501 }
1502
1503 if (data == nullptr) {
1504 data = ui_tooltip_data_from_button_or_extra_icon(C, but, extra_icon, is_label);
1505 }
1506
1507 if (data == nullptr) {
1508 data = ui_tooltip_data_from_button_or_extra_icon(C, but, nullptr, is_label);
1509 }
1510
1511 if (data == nullptr) {
1512 return nullptr;
1513 }
1514
1515 const bool is_no_overlap = UI_but_has_tooltip_label(but) || UI_but_is_tool(but);
1516 rcti init_rect;
1517 if (is_no_overlap) {
1518 rctf overlap_rect_fl;
1519 init_position[0] = BLI_rctf_cent_x(&but->rect);
1520 init_position[1] = BLI_rctf_cent_y(&but->rect);
1521 if (butregion) {
1522 ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
1523 ui_block_to_window_rctf(butregion, but->block, &overlap_rect_fl, &but->rect);
1524 }
1525 else {
1526 overlap_rect_fl = but->rect;
1527 }
1528 BLI_rcti_rctf_copy_round(&init_rect, &overlap_rect_fl);
1529 }
1530 else if (but->type == UI_BTYPE_LABEL && BLI_rctf_size_y(&but->rect) > UI_UNIT_Y) {
1531 init_position[0] = win->eventstate->xy[0];
1532 init_position[1] = win->eventstate->xy[1] - (UI_POPUP_MARGIN / 2);
1533 }
1534 else {
1535 init_position[0] = BLI_rctf_cent_x(&but->rect);
1536 init_position[1] = but->rect.ymin;
1537 if (butregion) {
1538 ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
1539 init_position[0] = win->eventstate->xy[0];
1540 }
1541 init_position[1] -= (UI_POPUP_MARGIN / 2);
1542 }
1543
1545 C, std::move(data), init_position, is_no_overlap ? &init_rect : nullptr);
1546
1547 return region;
1548}
1549
1550ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
1551{
1552 return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, nullptr, is_label);
1553}
1554
1556{
1557 wmWindow *win = CTX_wm_window(C);
1558 float init_position[2] = {float(win->eventstate->xy[0]), float(win->eventstate->xy[1])};
1559
1560 std::unique_ptr<uiTooltipData> data = ui_tooltip_data_from_gizmo(C, gz);
1561 if (data == nullptr) {
1562 return nullptr;
1563 }
1564
1565 /* TODO(@harley): Julian preferred that the gizmo callback return the 3D bounding box
1566 * which we then project to 2D here. Would make a nice improvement. */
1567 if (gz->type->screen_bounds_get) {
1568 rcti bounds;
1569 if (gz->type->screen_bounds_get(C, gz, &bounds)) {
1570 init_position[0] = bounds.xmin;
1571 init_position[1] = bounds.ymin;
1572 }
1573 }
1574
1575 return ui_tooltip_create_with_data(C, std::move(data), init_position, nullptr);
1576}
1577
1579{
1580 if (ima.filepath[0]) {
1581 char root[FILE_MAX];
1584 }
1585
1586 std::string image_type;
1587 switch (ima.source) {
1588 case IMA_SRC_FILE:
1589 image_type = TIP_("Single Image");
1590 break;
1591 case IMA_SRC_SEQUENCE:
1592 image_type = TIP_("Image Sequence");
1593 break;
1594 case IMA_SRC_MOVIE:
1595 image_type = TIP_("Movie");
1596 break;
1597 case IMA_SRC_GENERATED:
1598 image_type = TIP_("Generated");
1599 break;
1600 case IMA_SRC_VIEWER:
1601 image_type = TIP_("Viewer");
1602 break;
1603 case IMA_SRC_TILED:
1604 image_type = TIP_("UDIM Tiles");
1605 break;
1606 }
1608
1609 short w;
1610 short h;
1611 ImBuf *ibuf = BKE_image_preview(&ima, 200.0f * UI_SCALE_FAC, &w, &h);
1612
1613 if (ibuf) {
1615 data, fmt::format("{} \u00D7 {}", w, h), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
1616 }
1617
1618 if (BKE_image_has_anim(&ima)) {
1619 ImBufAnim *anim = static_cast<ImBufAnim *>(ima.anims.first);
1620 if (anim) {
1621 int duration = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
1623 data, fmt::format("Frames: {}", duration), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
1624 }
1625 }
1626
1629
1631 data, fmt::format(TIP_("Users: {}"), ima.id.us), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
1632
1633 if (ibuf) {
1634 uiTooltipImage image_data;
1635 image_data.width = int(ibuf->x);
1636 image_data.height = int(ibuf->y);
1637 image_data.ibuf = ibuf;
1638 image_data.border = true;
1640 image_data.premultiplied = true;
1643 UI_tooltip_image_field_add(data, image_data);
1644 IMB_freeImBuf(ibuf);
1645 }
1646}
1647
1649{
1650 if (clip.filepath[0]) {
1651 char root[FILE_MAX];
1652 BLI_path_split_dir_part(clip.filepath, root, FILE_MAX);
1654 }
1655
1656 std::string image_type;
1657 switch (clip.source) {
1658 case IMA_SRC_SEQUENCE:
1659 image_type = TIP_("Image Sequence");
1660 break;
1661 case IMA_SRC_MOVIE:
1662 image_type = TIP_("Movie");
1663 break;
1664 }
1666
1667 if (clip.anim) {
1668 ImBufAnim *anim = clip.anim;
1669
1671 fmt::format("{} \u00D7 {}",
1674 {},
1677
1679 data,
1680 fmt::format("Frames: {}", IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN)),
1681 {},
1684
1685 ImBuf *ibuf = IMB_anim_previewframe(anim);
1686
1687 if (ibuf) {
1688 /* Resize. */
1689 float scale = float(200.0f * UI_SCALE_FAC) / float(std::max(ibuf->x, ibuf->y));
1690 IMB_scale(ibuf, scale * ibuf->x, scale * ibuf->y, IMBScaleFilter::Box, false);
1691 IMB_rect_from_float(ibuf);
1692
1693 uiTooltipImage image_data;
1694 image_data.width = int(ibuf->x);
1695 image_data.height = int(ibuf->y);
1696 image_data.ibuf = ibuf;
1697 image_data.border = true;
1699 image_data.premultiplied = true;
1702 UI_tooltip_image_field_add(data, image_data);
1703 IMB_freeImBuf(ibuf);
1704 }
1705 }
1706}
1707
1708static void ui_tooltip_from_vfont(const VFont &font, uiTooltipData &data)
1709{
1710 if (!font.filepath[0]) {
1711 /* Let's not bother with packed files _for now_.*/
1712 return;
1713 }
1714
1715 if (!BLI_exists(font.filepath)) {
1717 data, TIP_("File not found"), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_ALERT);
1718 return;
1719 }
1720
1721 float color[4];
1722 const uiWidgetColors *theme = ui_tooltip_get_theme();
1723 rgba_uchar_to_float(color, theme->text);
1724 ImBuf *ibuf = IMB_font_preview(font.filepath, 200 * UI_SCALE_FAC, color);
1725 if (ibuf) {
1726 uiTooltipImage image_data;
1727 image_data.width = ibuf->x;
1728 image_data.height = ibuf->y;
1729 image_data.ibuf = ibuf;
1730 image_data.border = false;
1732 image_data.premultiplied = false;
1733 image_data.text_color = true;
1734 UI_tooltip_image_field_add(data, image_data);
1735 IMB_freeImBuf(ibuf);
1736 }
1737}
1738
1739static std::unique_ptr<uiTooltipData> ui_tooltip_data_from_search_item_tooltip_data(ID *id)
1740{
1741 std::unique_ptr<uiTooltipData> data = std::make_unique<uiTooltipData>();
1742 const ID_Type type_id = GS(id->name);
1743
1745
1746 if (type_id == ID_IM) {
1747 ui_tooltip_from_image(*reinterpret_cast<Image *>(id), *data);
1748 }
1749 else if (type_id == ID_MC) {
1750 ui_tooltip_from_clip(*reinterpret_cast<MovieClip *>(id), *data);
1751 }
1752 else if (type_id == ID_VF) {
1753 ui_tooltip_from_vfont(*reinterpret_cast<VFont *>(id), *data);
1754 }
1755 else {
1757 fmt::format(TIP_("Choose {} data-block to be assigned to this user"),
1758 BKE_idtype_idcode_to_name(GS(id->name))),
1759 {},
1762 }
1763
1765 if (ID_IS_LINKED(id)) {
1767 *data,
1768 fmt::format(TIP_("Source library: {}\n{}"), id->lib->id.name + 2, id->lib->filepath),
1769 {},
1772 }
1773
1774 return data->fields.is_empty() ? nullptr : std::move(data);
1775}
1776
1778 const ARegion *searchbox_region,
1779 const rcti *item_rect,
1780 ID *id)
1781{
1782 std::unique_ptr<uiTooltipData> data = ui_tooltip_data_from_search_item_tooltip_data(id);
1783 if (data == nullptr) {
1784 return nullptr;
1785 }
1786
1787 const wmWindow *win = CTX_wm_window(C);
1788 float init_position[2];
1789 init_position[0] = win->eventstate->xy[0];
1790 init_position[1] = item_rect->ymin + searchbox_region->winrct.ymin - (UI_POPUP_MARGIN / 2);
1791
1792 return ui_tooltip_create_with_data(C, std::move(data), init_position, nullptr);
1793}
1794
1795void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region)
1796{
1797 ui_region_temp_remove(C, screen, region);
1798}
1799
void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, float x, float y, int img_w, int img_h, eGPUTextureFormat gpu_format, bool use_filter, const void *rect, float scaleX, float scaleY, float xzoom, float yzoom, const float color[4])
Definition glutil.cc:55
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
Definition glutil.cc:40
bScreen * CTX_wm_screen(const bContext *C)
void CTX_wm_operator_poll_msg_clear(bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
SpaceLink * CTX_wm_space_data(const bContext *C)
const char * CTX_wm_operator_poll_msg_get(bContext *C, bool *r_free)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:168
bool BKE_image_has_anim(Image *image)
ImBuf * BKE_image_preview(Image *ima, short max_size, short *r_width, short *r_height)
void BLF_size(int fontid, float size)
Definition blf.cc:426
void BLF_disable(int fontid, int option)
Definition blf.cc:321
int blf_mono_font
Definition blf.cc:51
void BLF_enable(int fontid, int option)
Definition blf.cc:312
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:791
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:828
@ BLF_WORD_WRAP
Definition BLF_api.hh:367
void BLF_wordwrap(int fontid, int wrap_width)
Definition blf.cc:893
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:87
#define BLI_assert(a)
Definition BLI_assert.h:50
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
MINLINE float rgb_to_grayscale(const float rgb[3])
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define FILE_MAX
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:184
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:180
void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src)
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.c:560
void BLI_rcti_resize(struct rcti *rect, int x, int y)
Definition rct.c:615
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:176
void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src)
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b)
Definition rct.c:198
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2])
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:172
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned char uchar
unsigned int uint
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define ELEM(...)
#define STREQ(a, b)
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
#define CTX_TIP_(context, msgid)
bool bool BPY_run_string_as_intptr(bContext *C, const char *imports[], const char *expr, BPy_RunErrInfo *err_info, intptr_t *r_value) ATTR_NONNULL(1
bool bool bool BPY_run_string_as_string_and_len(bContext *C, const char *imports[], const char *expr, BPy_RunErrInfo *err_info, char **r_value, size_t *r_value_len) ATTR_NONNULL(1
bool bool bool bool BPY_run_string_as_string(bContext *C, const char *imports[], const char *expr, BPy_RunErrInfo *err_info, char **r_value) ATTR_NONNULL(1
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
ID_Type
@ ID_MC
@ ID_IM
@ ID_VF
#define MAX_NAME
Definition DNA_defs.h:50
@ IMA_SRC_FILE
@ IMA_SRC_MOVIE
@ IMA_SRC_GENERATED
@ IMA_SRC_VIEWER
@ IMA_SRC_TILED
@ IMA_SRC_SEQUENCE
@ RGN_TYPE_TEMPORARY
@ USER_TOOLTIPS_PYTHON
#define UI_SCALE_FAC
void ED_region_floating_init(ARegion *region)
Definition area.cc:2206
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void immUnbindProgram()
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
void imm_draw_box_checker_2d_ex(float x1, float y1, float x2, float y2, const float color_primary[4], const float color_secondary[4], int checker_size)
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_IMAGE_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
@ GPU_BLEND_ALPHA_PREMULT
Definition GPU_state.hh:88
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
int IMB_anim_get_image_height(ImBufAnim *anim)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
void IMB_rectfill_area(ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, ColorManagedDisplay *display)
Definition rectop.cc:1241
int IMB_anim_get_image_width(ImBufAnim *anim)
ImBuf * IMB_anim_previewframe(ImBufAnim *anim)
int IMB_anim_get_duration(ImBufAnim *anim, IMB_Timecode_Type tc)
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:779
@ IMB_TC_RECORD_RUN
Contains defines and structs used throughout the imbuf module.
@ IB_rect
ImBuf * IMB_font_preview(const char *filepath, unsigned int width, const float color[4])
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_UNIT_ROTATION
Definition RNA_types.hh:81
@ PROP_ENUM_FLAG
Definition RNA_types.hh:293
@ PROP_PASSWORD
Definition RNA_types.hh:146
#define UI_ALPHA_CHECKER_LIGHT
#define UI_UNIT_Y
std::string UI_but_string_get_property_keymap(bContext &C, uiBut &but)
@ UI_BLOCK_SHOW_SHORTCUT_ALWAYS
int UI_but_unit_type_get(const uiBut *but)
#define UI_ALPHA_CHECKER_DARK
std::optional< EnumPropertyItem > UI_but_rna_enum_item_get(bContext &C, uiBut &but)
PointerRNA * UI_but_extra_operator_icon_opptr_get(const uiButExtraOpIcon *extra_icon)
std::string UI_but_string_get_operator_keymap(bContext &C, uiBut &but)
std::string UI_but_string_get_label(uiBut &but)
@ UI_STYLE_TEXT_LEFT
const uiStyle * UI_style_get()
void UI_fontstyle_set(const uiFontStyle *fs)
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
uiTooltipStyle
@ UI_TIP_STYLE_IMAGE
@ UI_TIP_STYLE_MONO
@ UI_TIP_STYLE_NORMAL
@ UI_TIP_STYLE_SPACER
@ UI_TIP_STYLE_HEADER
std::string UI_but_string_get_rna_property_identifier(const uiBut &but)
std::string UI_but_extra_icon_string_get_tooltip(bContext &C, const uiButExtraOpIcon &extra_icon)
wmOperatorType * UI_but_extra_operator_icon_optype_get(const uiButExtraOpIcon *extra_icon)
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)
std::string UI_but_extra_icon_string_get_label(const uiButExtraOpIcon &extra_icon)
uiTooltipColorID
@ UI_TIP_LC_ALERT
@ UI_TIP_LC_PYTHON
@ UI_TIP_LC_MAIN
@ UI_TIP_LC_VALUE
@ UI_TIP_LC_NORMAL
@ UI_TIP_LC_ACTIVE
@ UI_TIP_LC_MAX
std::string UI_but_string_get_tooltip_label(const uiBut &but)
std::string UI_but_string_get_tooltip(bContext &C, uiBut &but)
std::string UI_but_string_get_rna_struct_identifier(const uiBut &but)
@ UI_BTYPE_TEXT
@ UI_BTYPE_LABEL
@ UI_BTYPE_ROW
@ UI_BTYPE_SEARCH_MENU
@ UI_BTYPE_COLOR
std::string UI_but_extra_icon_string_get_operator_keymap(const bContext &C, const uiButExtraOpIcon &extra_icon)
bool UI_but_is_tool(const uiBut *but)
bool UI_but_has_tooltip_label(const uiBut *but)
@ UI_BUT_NO_TOOLTIP
@ UI_BUT_DISABLED
@ UI_BUT_DRIVEN
@ TH_BACK
void UI_GetThemeColor4fv(int colorid, float col[4])
wmOperatorCallContext
Definition WM_types.hh:216
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ KM_SHIFT
Definition WM_types.hh:255
int pad[32 - sizeof(int)]
ATTR_WARN_UNUSED_RESULT const BMVert * v
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static constexpr int64_t not_found
constexpr int64_t find(char c, int64_t pos=0) const
constexpr bool is_empty() const
constexpr bool startswith(StringRef prefix) const
constexpr const char & back() const
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
RAYTRACE_GROUP_SIZE additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "eevee_utility_texture", "eevee_hiz_data", "draw_view") .specialization_constant(Type RAYTRACE_GROUP_SIZE in_sh_0_tx in_sh_2_tx screen_normal_tx GPU_RGBA8
#define str(s)
uint col
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void IMB_freeImBuf(ImBuf *)
bool ui_but_context_poll_operator_ex(bContext *C, const uiBut *but, const wmOperatorCallParams *optype_params)
void ui_but_string_get(uiBut *but, char *str, const size_t str_maxncpy)
void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3])
void ui_block_to_window_rctf(const ARegion *region, const uiBlock *block, rctf *rct_dst, const rctf *rct_src)
Definition interface.cc:163
void ui_but_v3_get(uiBut *but, float vec[3])
ColorManagedDisplay * ui_block_cm_display_get(uiBlock *block)
void ui_block_to_window_fl(const ARegion *region, const uiBlock *block, float *x, float *y)
Definition interface.cc:135
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t str_maxncpy)
void ui_draw_tooltip_background(const uiStyle *style, uiBlock *block, const rcti *rect)
bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
const uiWidgetColors * ui_tooltip_get_theme()
#define UI_POPUP_MARGIN
bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
bool ui_but_is_color_gamma(uiBut *but)
#define UI_TIP_PADDING
ARegion * UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
#define TIP_BORDER_Y
#define UI_TIP_MAXWIDTH
static void rgb_tint(float col[3], float h, float h_strength, float v, float v_strength)
static std::string ui_tooltip_text_python_from_op(bContext *C, wmOperatorType *ot, PointerRNA *opptr)
ARegion * UI_tooltip_create_from_button_or_extra_icon(bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label)
static std::unique_ptr< uiTooltipData > ui_tooltip_data_from_custom_func(bContext *C, uiBut *but)
void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region)
void UI_tooltip_image_field_add(uiTooltipData &data, const uiTooltipImage &image_data)
static std::unique_ptr< uiTooltipData > ui_tooltip_data_from_search_item_tooltip_data(ID *id)
static std::unique_ptr< uiTooltipData > ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
static void ui_tooltip_from_image(Image &ima, uiTooltipData &data)
static void ui_tooltip_from_clip(MovieClip &clip, uiTooltipData &data)
#define UI_TIP_SPACER
static bool ui_tooltip_period_needed(blender::StringRef tip)
#define TIP_BORDER_X
static void ui_tooltip_region_draw_cb(const bContext *, ARegion *region)
static ARegion * ui_tooltip_create_with_data(bContext *C, std::unique_ptr< uiTooltipData > data_uptr, const float init_position[2], const rcti *init_rect_overlap)
static void ui_tooltip_from_vfont(const VFont &font, uiTooltipData &data)
static std::unique_ptr< uiTooltipData > ui_tooltip_data_from_button_or_extra_icon(bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, const bool is_label)
static std::unique_ptr< uiTooltipData > ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is_label)
ARegion * UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
ARegion * UI_tooltip_create_from_search_item_generic(bContext *C, const ARegion *searchbox_region, const rcti *item_rect, ID *id)
static void ui_tooltip_region_free_cb(ARegion *region)
void UI_tooltip_text_field_add(uiTooltipData &data, std::string text, std::string suffix, const uiTooltipStyle style, const uiTooltipColorID color_id, const bool is_pad)
ARegion * ui_region_temp_add(bScreen *screen)
void ui_region_temp_remove(bContext *C, bScreen *screen, ARegion *region)
#define GS(x)
Definition iris.cc:202
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static ulong state[N]
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_ui_description(const PropertyRNA *prop)
bool RNA_property_array_check(PropertyRNA *prop)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
PropertyType RNA_property_type(PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_property_flag(PropertyRNA *prop)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
std::optional< std::string > RNA_path_full_property_py_ex(const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
Definition rna_path.cc:1276
std::optional< std::string > RNA_path_full_struct_py(const PointerRNA *ptr)
Definition rna_path.cc:1260
_W64 int intptr_t
Definition stdint.h:118
Definition DNA_ID.h:413
int us
Definition DNA_ID.h:435
ListBase anims
ColorManagedColorspaceSettings colorspace_settings
char filepath[1024]
short source
void * first
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
int lines
Definition BLF_api.hh:406
int width
Definition BLF_api.hh:410
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
wmOperatorCallParams * optype_params
wmOperatorCallContext opcontext
PropertyRNA * rnaprop
wmOperatorType * optype
eButType type
const char * disabled_info
void * tip_arg
uiBlock * block
PointerRNA * opptr
uiButToolTipFunc tip_func
std::string drawstr
PointerRNA rnapoin
uiButToolTipCustomFunc tip_custom_func
uiFontStyle tooltip
blender::Vector< uiTooltipField > fields
struct uiTooltipField::@399 geom
std::optional< uiTooltipImage > image
uiTooltipImageBackground background
unsigned char inner[4]
unsigned char text[4]
int xy[2]
Definition WM_types.hh:726
wmOperatorType * type
PropertyRNA * prop
wmGizmoFnScreenBoundsGet screen_bounds_get
int target_property_defs_len
const wmGizmoType * type
wmOperatorType * optype
Definition WM_types.hh:1118
wmOperatorCallContext opcontext
Definition WM_types.hh:1120
const char * idname
Definition WM_types.hh:992
const char * description
Definition WM_types.hh:996
struct wmEvent * eventstate
wmOperatorType * ot
Definition wm_files.cc:4125
wmGizmoOpElem * WM_gizmo_operator_get(wmGizmo *gz, int part_index)
Definition wm_gizmo.cc:195
wmGizmoProperty * WM_gizmo_target_property_array(wmGizmo *gz)
std::optional< std::string > WM_key_event_operator_string(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict)
std::optional< std::string > WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact)
std::string WM_operatortype_description_or_name(bContext *C, wmOperatorType *ot, PointerRNA *properties)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
std::string WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args, wmOperatorType *ot, PointerRNA *opptr)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
std::string WM_operator_pystring_abbreviate(std::string str, int str_len_max)
void wmOrtho2_region_pixelspace(const ARegion *region)
blender::int2 WM_window_native_pixel_size(const wmWindow *win)