Blender V5.0
interface_context_menu.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_screen_types.h"
16
17#include "BLI_fileops.h"
18#include "BLI_path_utils.hh"
19#include "BLI_string_utf8.h"
20#include "BLI_utildefines.h"
21
22#include "BLT_translation.hh"
23
24#include "BKE_context.hh"
25#include "BKE_idprop.hh"
26#include "BKE_screen.hh"
27
28#include "ED_asset.hh"
29#include "ED_buttons.hh"
30#include "ED_keyframing.hh"
31#include "ED_screen.hh"
32
33#include "UI_abstract_view.hh"
35
36#include "interface_intern.hh"
37
38#include "RNA_access.hh"
39#include "RNA_path.hh"
40#include "RNA_prototypes.hh"
41
42#ifdef WITH_PYTHON
43# include "BPY_extern.hh"
44# include "BPY_extern_run.hh"
45#endif
46
47#include "WM_api.hh"
48#include "WM_types.hh"
49
50/* This hack is needed because we don't have a good way to
51 * re-reference keymap items once added: #42944 */
52#define USE_KEYMAP_ADD_HACK
53
54/* -------------------------------------------------------------------- */
57
59{
60 using namespace blender;
61 /* Compute data path from context to property. */
62
63 /* If this returns null, we won't be able to bind shortcuts to these RNA properties.
64 * Support can be added at #wm_context_member_from_ptr. */
65 std::optional<std::string> final_data_path = WM_context_path_resolve_property_full(
66 C, &but->rnapoin, but->rnaprop, but->rnaindex);
67 if (!final_data_path.has_value()) {
68 return nullptr;
69 }
70
71 /* Create ID property of data path, to pass to the operator. */
72 IDProperty *prop = bke::idprop::create_group(__func__).release();
73 IDP_AddToGroup(prop, bke::idprop::create("data_path", final_data_path.value()).release());
74 return prop;
75}
76
77static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **r_prop)
78{
79 using namespace blender;
80 if (but->optype) {
81 /* Operator */
82 *r_prop = (but->opptr && but->opptr->data) ?
83 IDP_CopyProperty(static_cast<IDProperty *>(but->opptr->data)) :
84 nullptr;
85 return but->optype->idname;
86 }
87
88 if (but->rnaprop) {
89 const PropertyType rnaprop_type = RNA_property_type(but->rnaprop);
90
91 if (rnaprop_type == PROP_BOOLEAN) {
92 /* Boolean */
93 *r_prop = shortcut_property_from_rna(C, but);
94 if (*r_prop == nullptr) {
95 return nullptr;
96 }
97 return "WM_OT_context_toggle";
98 }
99 if (rnaprop_type == PROP_ENUM) {
100 /* Enum */
101 *r_prop = shortcut_property_from_rna(C, but);
102 if (*r_prop == nullptr) {
103 return nullptr;
104 }
105 return "WM_OT_context_menu_enum";
106 }
107 }
108
109 if (MenuType *mt = UI_but_menutype_get(but)) {
110 IDProperty *prop = bke::idprop::create_group(__func__).release();
111 IDP_AddToGroup(prop, bke::idprop::create("name", mt->idname).release());
112 *r_prop = prop;
113 return "WM_OT_call_menu";
114 }
115
116 if (std::optional asset_shelf_idname = UI_but_asset_shelf_type_idname_get(but)) {
117 IDProperty *prop = blender::bke::idprop::create_group(__func__).release();
118 IDP_AddToGroup(prop, bke::idprop::create("name", *asset_shelf_idname).release());
119 *r_prop = prop;
120 return "WM_OT_call_asset_shelf_popover";
121 }
122
123 if (PanelType *pt = UI_but_paneltype_get(but)) {
124 IDProperty *prop = blender::bke::idprop::create_group(__func__).release();
125 IDP_AddToGroup(prop, bke::idprop::create("name", pt->idname).release());
126 *r_prop = prop;
127 return "WM_OT_call_panel";
128 }
129
130 *r_prop = nullptr;
131 return nullptr;
132}
133
135{
136 if (prop) {
137 IDP_FreeProperty(prop);
138 }
139}
140
141static void but_shortcut_name_func(bContext *C, void *arg1, int /*event*/)
142{
143 uiBut *but = (uiBut *)arg1;
144
145 IDProperty *prop;
146 const char *idname = shortcut_get_operator_property(C, but, &prop);
147 if (idname == nullptr) {
148 return;
149 }
150
151 /* complex code to change name of button */
152 if (std::optional<std::string> shortcut_str = WM_key_event_operator_string(
153 C, idname, but->opcontext, prop, true))
154 {
155 ui_but_add_shortcut(but, shortcut_str->c_str(), true);
156 }
157 else {
158 /* simply strip the shortcut */
159 ui_but_add_shortcut(but, nullptr, true);
160 }
161
163}
164
165static uiBlock *menu_change_shortcut(bContext *C, ARegion *region, void *arg)
166{
168 uiBut *but = (uiBut *)arg;
169 const uiStyle *style = UI_style_get_dpi();
170 IDProperty *prop;
171 const char *idname = shortcut_get_operator_property(C, but, &prop);
172
173 wmKeyMap *km;
175 idname,
176 but->opcontext,
177 prop,
180 &km);
181 U.runtime.is_dirty = true;
182
183 BLI_assert(kmi != nullptr);
184
185 PointerRNA ptr = RNA_pointer_create_discrete(&wm->id, &RNA_KeyMapItem, kmi);
186
187 uiBlock *block = UI_block_begin(C, region, "_popup", blender::ui::EmbossType::Emboss);
191
192 uiLayout &layout = blender::ui::block_layout(block,
195 0,
196 0,
197 U.widget_unit * 10,
198 U.widget_unit * 2,
199 0,
200 style);
201
202 layout.label(CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), ICON_HAND);
203 layout.prop(&ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
204
205 const int bounds_offset[2] = {int(-100 * UI_SCALE_FAC), int(36 * UI_SCALE_FAC)};
206 UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, bounds_offset);
207
209
210 return block;
211}
212
213#ifdef USE_KEYMAP_ADD_HACK
214static int g_kmi_id_hack;
215#endif
216
217static uiBlock *menu_add_shortcut(bContext *C, ARegion *region, void *arg)
218{
220 uiBut *but = (uiBut *)arg;
221 const uiStyle *style = UI_style_get_dpi();
222 IDProperty *prop;
223 const char *idname = shortcut_get_operator_property(C, but, &prop);
224
225 /* XXX this guess_opname can potentially return a different keymap
226 * than being found on adding later... */
227 wmKeyMap *km = WM_keymap_guess_opname(C, idname);
229 params.type = EVT_AKEY;
230 params.value = KM_PRESS;
231 params.modifier = 0;
232 params.direction = KM_ANY;
233 wmKeyMapItem *kmi = WM_keymap_add_item(km, idname, &params);
234 const int kmi_id = kmi->id;
235
236 /* This takes ownership of prop, or prop can be nullptr for reset. */
238
239 /* update and get pointers again */
241 U.runtime.is_dirty = true;
242
243 km = WM_keymap_guess_opname(C, idname);
244 kmi = WM_keymap_item_find_id(km, kmi_id);
245
246 PointerRNA ptr = RNA_pointer_create_discrete(&wm->id, &RNA_KeyMapItem, kmi);
247
248 uiBlock *block = UI_block_begin(C, region, "_popup", blender::ui::EmbossType::Emboss);
251
252 uiLayout &layout = blender::ui::block_layout(block,
255 0,
256 0,
257 U.widget_unit * 10,
258 U.widget_unit * 2,
259 0,
260 style);
261
262 layout.label(CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), ICON_HAND);
263 layout.prop(&ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
264
265 const int bounds_offset[2] = {int(-100 * UI_SCALE_FAC), int(36 * UI_SCALE_FAC)};
266 UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, bounds_offset);
267
268#ifdef USE_KEYMAP_ADD_HACK
269 g_kmi_id_hack = kmi_id;
270#endif
271
272 return block;
273}
274
275static void menu_add_shortcut_cancel(bContext *C, void *arg1)
276{
277 uiBut *but = (uiBut *)arg1;
278
279 IDProperty *prop;
280 const char *idname = shortcut_get_operator_property(C, but, &prop);
281
282#ifdef USE_KEYMAP_ADD_HACK
283 wmKeyMap *km = WM_keymap_guess_opname(C, idname);
284 const int kmi_id = g_kmi_id_hack;
285 UNUSED_VARS(but);
286#else
287 int kmi_id = WM_key_event_operator_id(C, idname, but->opcontext, prop, true, &km);
288#endif
289
291
292 wmKeyMapItem *kmi = WM_keymap_item_find_id(km, kmi_id);
293 WM_keymap_remove_item(km, kmi);
294}
295
297{
298 IDProperty *prop;
299 const char *idname = shortcut_get_operator_property(C, but, &prop);
300
301 wmKeyMap *km;
303 idname,
304 but->opcontext,
305 prop,
308 &km);
309 BLI_assert(kmi != nullptr);
310
311 WM_keymap_remove_item(km, kmi);
312 U.runtime.is_dirty = true;
313
315 but_shortcut_name_func(C, but, 0);
316}
317
319{
320 bool result = false;
321 if (but->optype) {
322 result = true;
323 }
324 else if (but->rnaprop) {
326 std::optional<std::string> data_path = WM_context_path_resolve_full(C, &but->rnapoin);
327 if (data_path.has_value()) {
328 result = true;
329 }
330 }
331 }
332 else if (UI_but_menutype_get(but)) {
333 result = true;
334 }
335 else if (UI_but_operatortype_get_from_enum_menu(but, nullptr)) {
336 result = true;
337 }
338
339 return result;
340}
341
343{
344 if (but->optype) {
345 IDProperty *prop = (but->opptr) ? static_cast<IDProperty *>(but->opptr->data) : nullptr;
347 &um->items, but->optype, prop, "", but->opcontext);
348 }
349 if (but->rnaprop) {
350 std::optional<std::string> member_id_data_path = WM_context_path_resolve_full(C,
351 &but->rnapoin);
352 /* NOTE(@ideasman42): It's highly unlikely this ever occurs since the path must be resolved
353 * for this to be added in the first place, there might be some cases where manually
354 * constructed RNA paths don't resolve and in this case a crash should be avoided. */
355 if (UNLIKELY(!member_id_data_path.has_value())) {
356 /* Assert because this should never happen for typical usage. */
358 return nullptr;
359 }
360 /* Ignore the actual array index [pass -1] since the index is handled separately. */
361 const std::string prop_id = RNA_property_is_idprop(but->rnaprop) ?
362 RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
365 &um->items, member_id_data_path->c_str(), prop_id.c_str(), but->rnaindex);
366 return umi;
367 }
368
369 wmOperatorType *ot = nullptr;
370 PropertyRNA *prop_enum = nullptr;
371 if ((ot = UI_but_operatortype_get_from_enum_menu(but, &prop_enum))) {
373 &um->items, ot, nullptr, RNA_property_identifier(prop_enum), but->opcontext);
374 }
375
376 MenuType *mt = UI_but_menutype_get(but);
377 if (mt != nullptr) {
379 }
380 return nullptr;
381}
382
384{
386
387 std::string drawstr = ui_but_drawstr_without_sep_char(but);
388
389 /* Used for USER_MENU_TYPE_MENU. */
390 MenuType *mt = nullptr;
391 /* Used for USER_MENU_TYPE_OPERATOR (property enum used). */
392 wmOperatorType *ot = nullptr;
393 PropertyRNA *prop = nullptr;
394 if (but->optype) {
395 if (drawstr[0] == '\0') {
396 /* Hard code overrides for generic operators. */
397 if (UI_but_is_tool(but)) {
398 char idname[64];
399 RNA_string_get(but->opptr, "name", idname);
400#ifdef WITH_PYTHON
401 {
402 const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
403 char expr[256];
404 SNPRINTF_UTF8(expr,
405 "bl_ui.space_toolsystem_common.item_from_id("
406 "bpy.context, "
407 "bpy.context.space_data.type, "
408 "'%s').label",
409 idname);
410 char *expr_result = nullptr;
411 if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) {
412 drawstr = expr_result;
413 MEM_freeN(expr_result);
414 }
415 else {
416 BLI_assert(0);
417 drawstr = idname;
418 }
419 }
420#else
421 drawstr = idname;
422#endif
423 }
424 else if (but->tip_quick_func) {
425 /* The "quick tooltip" often contains a short string that can be used as a fallback. */
426 drawstr = but->tip_quick_func(but);
427 }
428 }
430 &um->items,
431 drawstr.c_str(),
432 but->optype,
433 but->opptr ? static_cast<const IDProperty *>(but->opptr->data) : nullptr,
434 "",
435 but->opcontext);
436 }
437 else if (but->rnaprop) {
438 /* NOTE: 'member_id' may be a path. */
439 std::optional<std::string> member_id_data_path = WM_context_path_resolve_full(C,
440 &but->rnapoin);
441 if (!member_id_data_path.has_value()) {
442 /* See #ui_but_user_menu_find code-comment. */
444 }
445 else {
446 /* Ignore the actual array index [pass -1] since the index is handled separately. */
447 const std::string prop_id = RNA_property_is_idprop(but->rnaprop) ?
448 RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
450 /* NOTE: ignore 'drawstr', use property idname always. */
452 &um->items, "", member_id_data_path->c_str(), prop_id.c_str(), but->rnaindex);
453 }
454 }
455 else if ((mt = UI_but_menutype_get(but))) {
456 ED_screen_user_menu_item_add_menu(&um->items, drawstr.c_str(), mt);
457 }
458 else if ((ot = UI_but_operatortype_get_from_enum_menu(but, &prop))) {
460 WM_operatortype_name(ot, nullptr).c_str(),
461 ot,
462 nullptr,
464 but->opcontext);
465 }
466}
467
469{
470 const PropertySubType subtype = RNA_property_subtype(prop);
471 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
472 char filepath[FILE_MAX];
473 char dir[FILE_MAXDIR];
474 char file[FILE_MAXFILE];
475 PointerRNA props_ptr;
476
478 UNUSED_VARS_NDEBUG(subtype);
479
480 RNA_property_string_get(ptr, prop, filepath);
481
482 if (!BLI_exists(filepath)) {
483 return false;
484 }
485
486 if (BLI_is_file(filepath)) {
487 BLI_assert(subtype == PROP_FILEPATH);
488 props_ptr = layout->op(ot,
489 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open File Externally"),
490 ICON_NONE,
493 RNA_string_set(&props_ptr, "filepath", filepath);
494 }
495 else {
496 /* This is a directory, so ensure it ends in a slash. */
497 BLI_path_slash_ensure(filepath, ARRAY_SIZE(filepath));
498 }
499
500 BLI_path_split_dir_file(filepath, dir, sizeof(dir), file, sizeof(file));
501
502 props_ptr = layout->op(ot,
503 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Location Externally"),
504 ICON_NONE,
507 RNA_string_set(&props_ptr, "filepath", dir);
508
509 return true;
510}
511
513{
514 if (!but->context) {
515 return;
516 }
517 layout->context_copy(but->context);
518 CTX_store_set(C, layout->context_store());
519}
520
522{
523 using namespace blender::ed;
524 /* ui_but_is_interactive() may let some buttons through that should not get a context menu - it
525 * doesn't make sense for them. */
527 return false;
528 }
529
530 uiPopupMenu *pup;
531 uiLayout *layout;
532 const bContextStore *previous_ctx = CTX_store_get(C);
533 {
534 pup = UI_popup_menu_begin(C, UI_but_context_menu_title_from_button(*but).c_str(), ICON_NONE);
535 layout = UI_popup_menu_layout(pup);
536
537 set_layout_context_from_button(C, layout, but);
539 }
540
541 const bool is_disabled = but->flag & UI_BUT_DISABLED;
542
543 if (is_disabled) {
544 /* Suppress editing commands. */
545 }
546 else if (but->type == ButType::Tab) {
547 uiButTab *tab = (uiButTab *)but;
548 if (tab->menu) {
549 UI_menutype_draw(C, tab->menu, layout);
550 layout->separator();
551 }
552 }
553 else if (but->rnapoin.data && but->rnaprop) {
554 PointerRNA *ptr = &but->rnapoin;
555 PropertyRNA *prop = but->rnaprop;
556 const PropertyType type = RNA_property_type(prop);
557 const PropertySubType subtype = RNA_property_subtype(prop);
558 bool is_anim = RNA_property_anim_editable(ptr, prop);
559 const bool is_idprop = RNA_property_is_idprop(prop);
560
561 /* second slower test,
562 * saved people finding keyframe items in menus when its not possible */
563 if (is_anim) {
564 is_anim = RNA_property_path_from_ID_check(&but->rnapoin, but->rnaprop);
565 }
566
567 /* determine if we can key a single component of an array */
568 const bool is_array = RNA_property_array_length(&but->rnapoin, but->rnaprop) != 0;
569 const bool is_array_component = (is_array && but->rnaindex != -1);
570 const bool is_whole_array = (is_array && but->rnaindex == -1);
571
572 const uint override_status = RNA_property_override_library_status(
573 CTX_data_main(C), ptr, prop, -1);
574 const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0;
575
576 /* Set the (button_pointer, button_prop)
577 * and pointer data for Python access to the hovered UI element. */
578 layout->context_set_from_but(but);
579
580 /* Keyframes */
581 if (but->flag & UI_BUT_ANIMATED_KEY) {
582 /* Replace/delete keyframes. */
583 if (is_array_component) {
584 PointerRNA op_ptr = layout->op(
585 "ANIM_OT_keyframe_insert_button",
586 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframes"),
587 ICON_KEY_HLT);
588 RNA_boolean_set(&op_ptr, "all", true);
589 op_ptr = layout->op(
590 "ANIM_OT_keyframe_insert_button",
591 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Single Keyframe"),
592 ICON_NONE);
593 RNA_boolean_set(&op_ptr, "all", false);
594 op_ptr = layout->op("ANIM_OT_keyframe_delete_button",
595 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframes"),
596 ICON_NONE);
597 RNA_boolean_set(&op_ptr, "all", true);
598 op_ptr = layout->op("ANIM_OT_keyframe_delete_button",
599 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Keyframe"),
600 ICON_NONE);
601 RNA_boolean_set(&op_ptr, "all", false);
602 }
603 else {
604 PointerRNA op_ptr = layout->op(
605 "ANIM_OT_keyframe_insert_button",
606 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframe"),
607 ICON_KEY_HLT);
608 RNA_boolean_set(&op_ptr, "all", true);
609 op_ptr = layout->op("ANIM_OT_keyframe_delete_button",
611 ICON_NONE);
612 RNA_boolean_set(&op_ptr, "all", true);
613 }
614
615 /* keyframe settings */
616 layout->separator();
617 }
618 else if (but->flag & UI_BUT_DRIVEN) {
619 /* pass */
620 }
621 else if (is_anim) {
622 if (is_array_component) {
623 PointerRNA op_ptr = layout->op(
624 "ANIM_OT_keyframe_insert_button",
625 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframes"),
626 ICON_KEY_HLT);
627 RNA_boolean_set(&op_ptr, "all", true);
628 op_ptr = layout->op("ANIM_OT_keyframe_insert_button",
629 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Single Keyframe"),
630 ICON_NONE);
631 RNA_boolean_set(&op_ptr, "all", false);
632 }
633 else {
634 PointerRNA op_ptr = layout->op(
635 "ANIM_OT_keyframe_insert_button",
637 ICON_KEY_HLT);
638 RNA_boolean_set(&op_ptr, "all", true);
639 }
640 }
641
642 if ((but->flag & UI_BUT_ANIMATED) && (but->rnapoin.type != &RNA_NlaStrip)) {
643 if (is_array_component) {
644 PointerRNA op_ptr = layout->op(
645 "ANIM_OT_keyframe_clear_button",
647 ICON_KEY_DEHLT);
648 RNA_boolean_set(&op_ptr, "all", true);
649 op_ptr = layout->op("ANIM_OT_keyframe_clear_button",
650 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Single Keyframes"),
651 ICON_NONE);
652 RNA_boolean_set(&op_ptr, "all", false);
653 }
654 else {
655 PointerRNA op_ptr = layout->op(
656 "ANIM_OT_keyframe_clear_button",
658 ICON_KEY_DEHLT);
659 RNA_boolean_set(&op_ptr, "all", true);
660 }
661 }
662
663 if (but->flag & UI_BUT_ANIMATED) {
664 layout->separator();
665 if (is_array_component) {
666 PointerRNA op_ptr;
668 ot = WM_operatortype_find("ANIM_OT_view_curve_in_graph_editor", false);
669 op_ptr = layout->op(
670 ot,
671 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "View All in Graph Editor"),
672 ICON_GRAPH,
675 RNA_boolean_set(&op_ptr, "all", true);
676
677 op_ptr = layout->op(
678 ot,
679 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "View Single in Graph Editor"),
680 ICON_NONE,
683 RNA_boolean_set(&op_ptr, "all", false);
684 }
685 else {
686 PointerRNA op_ptr;
688 ot = WM_operatortype_find("ANIM_OT_view_curve_in_graph_editor", false);
689
690 op_ptr = layout->op(ot,
691 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "View in Graph Editor"),
692 ICON_NONE,
695 RNA_boolean_set(&op_ptr, "all", false);
696 }
697 }
698
699 /* Drivers */
700 if (but->flag & UI_BUT_DRIVEN) {
701 layout->separator();
702
703 if (is_array_component) {
704 PointerRNA op_ptr = layout->op(
705 "ANIM_OT_driver_button_remove",
707 ICON_X);
708 RNA_boolean_set(&op_ptr, "all", true);
709 op_ptr = layout->op("ANIM_OT_driver_button_remove",
710 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Driver"),
711 ICON_NONE);
712 RNA_boolean_set(&op_ptr, "all", false);
713 }
714 else {
715 PointerRNA op_ptr = layout->op(
716 "ANIM_OT_driver_button_remove",
718 ICON_X);
719 RNA_boolean_set(&op_ptr, "all", true);
720 }
721
722 if (is_whole_array) {
723 PointerRNA op_ptr = layout->op(
724 "UI_OT_copy_driver_to_selected_button",
725 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Drivers to Selected"),
726 ICON_NONE);
727 RNA_boolean_set(&op_ptr, "all", true);
728 }
729 else {
730 layout->op("ANIM_OT_copy_driver_button",
732 ICON_NONE);
733 if (ANIM_driver_can_paste()) {
734 layout->op("ANIM_OT_paste_driver_button",
736 ICON_NONE);
737 }
738 PointerRNA op_ptr = layout->op(
739 "UI_OT_copy_driver_to_selected_button",
740 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver to Selected"),
741 ICON_NONE);
742 RNA_boolean_set(&op_ptr, "all", false);
743 if (is_array_component) {
744 PointerRNA op_ptr = layout->op(
745 "UI_OT_copy_driver_to_selected_button",
746 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All Drivers to Selected"),
747 ICON_NONE);
748 RNA_boolean_set(&op_ptr, "all", true);
749 }
750
751 layout->op("ANIM_OT_driver_button_edit",
753 ICON_DRIVER);
754 }
755
756 layout->op("SCREEN_OT_drivers_editor_show",
757 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Drivers Editor"),
758 ICON_NONE);
759 }
760 else if (but->flag & (UI_BUT_ANIMATED_KEY | UI_BUT_ANIMATED)) {
761 /* pass */
762 }
763 else if (is_anim) {
764 layout->separator();
765
766 layout->op("ANIM_OT_driver_button_add",
768 ICON_DRIVER);
769
770 if (!is_whole_array) {
771 if (ANIM_driver_can_paste()) {
772 layout->op("ANIM_OT_paste_driver_button",
774 ICON_NONE);
775 }
776 }
777
778 layout->op("SCREEN_OT_drivers_editor_show",
779 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Drivers Editor"),
780 ICON_NONE);
781 }
782
783 /* Keying Sets */
784 /* TODO: check on modifiability of Keying Set when doing this. */
785 if (is_anim) {
786 layout->separator();
787
788 if (is_array_component) {
789 PointerRNA op_ptr = layout->op(
790 "ANIM_OT_keyingset_button_add",
791 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add All to Keying Set"),
792 ICON_KEYINGSET);
793 RNA_boolean_set(&op_ptr, "all", true);
794 op_ptr = layout->op(
795 "ANIM_OT_keyingset_button_add",
796 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single to Keying Set"),
797 ICON_NONE);
798 RNA_boolean_set(&op_ptr, "all", false);
799 layout->op("ANIM_OT_keyingset_button_remove",
800 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
801 ICON_NONE);
802 }
803 else {
804 PointerRNA op_ptr = layout->op(
805 "ANIM_OT_keyingset_button_add",
806 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Keying Set"),
807 ICON_KEYINGSET);
808 RNA_boolean_set(&op_ptr, "all", true);
809 layout->op("ANIM_OT_keyingset_button_remove",
810 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
811 ICON_NONE);
812 }
813 }
814
815 if (is_overridable) {
817 PointerRNA op_ptr;
818 /* Override Operators */
819 layout->separator();
820
821 if (but->flag & UI_BUT_OVERRIDDEN) {
822 if (is_array_component) {
823 PointerRNA op_ptr = layout->op(
824 "UI_OT_override_remove_button",
825 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Overrides"),
826 ICON_X);
827 RNA_boolean_set(&op_ptr, "all", true);
828 op_ptr = layout->op(
829 "UI_OT_override_remove_button",
830 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Single Override"),
831 ICON_X);
832 RNA_boolean_set(&op_ptr, "all", false);
833 }
834 else {
835 PointerRNA op_ptr = layout->op(
836 "UI_OT_override_remove_button",
838 ICON_X);
839 RNA_boolean_set(&op_ptr, "all", true);
840 }
841 }
842 else {
843 ot = WM_operatortype_find("UI_OT_override_add_button", false);
844 if (is_array_component) {
845 op_ptr = layout->op(ot,
847 ICON_NONE,
850 RNA_boolean_set(&op_ptr, "all", true);
851 op_ptr = layout->op(ot,
852 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single Override"),
853 ICON_NONE,
856 RNA_boolean_set(&op_ptr, "all", false);
857 }
858 else {
859 op_ptr = layout->op(ot,
861 ICON_NONE,
864 RNA_boolean_set(&op_ptr, "all", false);
865 }
866 }
867 }
868
869 layout->separator();
870
871 /* Property Operators */
872
873 /* Copy Property Value
874 * Paste Property Value */
875
876 if (is_array_component) {
877 PointerRNA op_ptr = layout->op(
878 "UI_OT_reset_default_button",
879 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset All to Default Values"),
880 ICON_LOOP_BACK);
881 RNA_boolean_set(&op_ptr, "all", true);
882 op_ptr = layout->op(
883 "UI_OT_reset_default_button",
884 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Single to Default Value"),
885 ICON_NONE);
886 RNA_boolean_set(&op_ptr, "all", false);
887 }
888 else {
889 PointerRNA op_ptr = layout->op(
890 "UI_OT_reset_default_button",
891 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset to Default Value"),
892 ICON_LOOP_BACK);
893 RNA_boolean_set(&op_ptr, "all", true);
894 }
895
896 if (is_idprop && !is_array && ELEM(type, PROP_INT, PROP_FLOAT)) {
897 layout->op("UI_OT_assign_default_button",
898 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Value as Default"),
899 ICON_NONE);
900
901 layout->separator();
902 }
903
904 if (is_array_component) {
905 PointerRNA op_ptr = layout->op(
906 "UI_OT_copy_to_selected_button",
907 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All to Selected"),
908 ICON_NONE);
909 RNA_boolean_set(&op_ptr, "all", true);
910 op_ptr = layout->op("UI_OT_copy_to_selected_button",
911 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single to Selected"),
912 ICON_NONE);
913 RNA_boolean_set(&op_ptr, "all", false);
914 }
915 else {
916 PointerRNA op_ptr = layout->op(
917 "UI_OT_copy_to_selected_button",
918 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
919 ICON_NONE);
920 RNA_boolean_set(&op_ptr, "all", true);
921 }
922
923 layout->op("UI_OT_copy_data_path_button",
925 ICON_NONE);
926 PointerRNA op_ptr = layout->op(
927 "UI_OT_copy_data_path_button",
928 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Full Data Path"),
929 ICON_NONE);
930 RNA_boolean_set(&op_ptr, "full_path", true);
931
932 if (ptr->owner_id && !is_whole_array &&
934 {
935 layout->op("UI_OT_copy_as_driver_button",
936 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy as New Driver"),
937 ICON_NONE);
938 }
939
940 layout->separator();
941
942 if (type == PROP_STRING && ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
943 if (ui_but_menu_add_path_operators(layout, ptr, prop)) {
944 layout->separator();
945 }
946 }
947 }
948 else if (but->optype && but->opptr && RNA_struct_property_is_set(but->opptr, "filepath")) {
949 /* Operator with "filepath" string property of PROP_FILEPATH subtype. */
950 PropertyRNA *prop = RNA_struct_find_property(but->opptr, "filepath");
951 const PropertySubType subtype = RNA_property_subtype(prop);
952
953 if (prop && RNA_property_type(prop) == PROP_STRING &&
955 {
956 char filepath[FILE_MAX] = {0};
957 RNA_property_string_get(but->opptr, prop, filepath);
958 if (filepath[0] && BLI_exists(filepath)) {
959 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
960 PointerRNA props_ptr;
961 char dir[FILE_MAXDIR];
962 BLI_path_split_dir_part(filepath, dir, sizeof(dir));
963 props_ptr = layout->op(ot,
964 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open File Location"),
965 ICON_NONE,
968 RNA_string_set(&props_ptr, "filepath", dir);
969 layout->separator();
970 }
971 }
972 }
973
974 {
976 uiButViewItem *view_item_but = (but->type == ButType::ViewItem) ?
977 static_cast<uiButViewItem *>(but) :
978 static_cast<uiButViewItem *>(
979 ui_view_item_find_mouse_over(region, event->xy));
980 if (view_item_but) {
981 BLI_assert(view_item_but->type == ButType::ViewItem);
982
983 const bContextStore *prev_ctx = CTX_store_get(C);
984 /* Sub-layout for context override. */
985 uiLayout *sub = &layout->column(false);
986 set_layout_context_from_button(C, sub, view_item_but);
987 view_item_but->view_item->build_context_menu(*C, *sub);
988
989 /* Reset context. */
990 CTX_store_set(C, prev_ctx);
991
992 layout->separator();
993 }
994 }
995
996 /* Expose id specific operators in context menu when button has no operator associated. Otherwise
997 * they would appear in nested context menus, see: #126006. */
998 if ((but->optype == nullptr) && (but->apply_func == nullptr) &&
999 (but->menu_create_func == nullptr))
1000 {
1001 /* If the button represents an id, it can set the "id" context pointer. */
1003 const ID *id = static_cast<const ID *>(CTX_data_pointer_get_type(C, "id", &RNA_ID).data);
1004
1005 /* Gray out items depending on if data-block is an asset. Preferably this could be done via
1006 * operator poll, but that doesn't work since the operator also works with "selected_ids",
1007 * which isn't cheap to check. */
1008 uiLayout *sub = &layout->column(true);
1009 sub->enabled_set(!id->asset_data);
1010 sub->op("ASSET_OT_mark_single",
1012 ICON_ASSET_MANAGER);
1013 sub = &layout->column(true);
1014 sub->enabled_set(id->asset_data);
1015 sub->op("ASSET_OT_clear_single",
1017 ICON_NONE);
1018 layout->separator();
1019 }
1020
1021 MenuType *mt_idtemplate_liboverride = WM_menutype_find("UI_MT_idtemplate_liboverride", true);
1022 if (mt_idtemplate_liboverride && mt_idtemplate_liboverride->poll(C, mt_idtemplate_liboverride))
1023 {
1024 layout->menu(mt_idtemplate_liboverride, IFACE_("Library Override"), ICON_NONE);
1025 layout->separator();
1026 }
1027 }
1028
1029 /* Pointer properties and string properties with
1030 * prop_search support jumping to target object/bone. */
1031 if (but->rnapoin.data && but->rnaprop) {
1032 const PropertyType prop_type = RNA_property_type(but->rnaprop);
1033 if (((prop_type == PROP_POINTER) ||
1034 (prop_type == PROP_STRING && but->type == ButType::SearchMenu &&
1035 ((uiButSearch *)but)->items_update_fn == ui_rna_collection_search_update_fn)) &&
1037 {
1038 layout->op("UI_OT_jump_to_target_button",
1040 ICON_NONE);
1041 layout->separator();
1042 }
1043 }
1044
1045 /* Favorites Menu */
1047 uiBlock *block = layout->block();
1048 const int w = layout->width();
1049 bool item_found = false;
1050
1051 uint um_array_len;
1052 bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len);
1053 for (int um_index = 0; um_index < um_array_len; um_index++) {
1054 bUserMenu *um = um_array[um_index];
1055 if (um == nullptr) {
1056 continue;
1057 }
1058 bUserMenuItem *umi = ui_but_user_menu_find(C, but, um);
1059 if (umi != nullptr) {
1060 uiBut *but2 = uiDefIconTextBut(
1061 block,
1063 0,
1064 ICON_MENU_PANEL,
1065 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Quick Favorites"),
1066 0,
1067 0,
1068 w,
1069 UI_UNIT_Y,
1070 nullptr,
1071 "");
1072 item_found = true;
1073 UI_but_func_set(but2, [um, umi](bContext &) {
1074 U.runtime.is_dirty = true;
1076 });
1077 }
1078 }
1079 if (um_array) {
1080 MEM_freeN(um_array);
1081 }
1082
1083 if (!item_found) {
1084 uiBut *but2 = uiDefIconTextBut(
1085 block,
1087 0,
1088 ICON_MENU_PANEL,
1089 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Quick Favorites"),
1090 0,
1091 0,
1092 w,
1093 UI_UNIT_Y,
1094 nullptr,
1095 TIP_("Add to a user defined context menu (stored in the user preferences)"));
1096 UI_but_func_set(but2, [but](bContext &C) {
1098 U.runtime.is_dirty = true;
1099 ui_but_user_menu_add(&C, but, um);
1100 });
1101 }
1102
1103 layout->separator();
1104 }
1105
1106 /* Shortcut menu */
1107 IDProperty *prop;
1108 const char *idname = shortcut_get_operator_property(C, but, &prop);
1109 if (idname != nullptr) {
1110 uiBlock *block = layout->block();
1111 const int w = layout->width();
1112
1113 /* We want to know if this op has a shortcut, be it hotkey or not. */
1114 wmKeyMap *km;
1116 C, idname, but->opcontext, prop, EVT_TYPE_MASK_ALL, 0, &km);
1117
1118 /* We do have a shortcut, but only keyboard ones are editable that way... */
1119 if (kmi) {
1120 if (ISKEYBOARD(kmi->type) || ISNDOF_BUTTON(kmi->type)) {
1121#if 0 /* would rather use a block but, but gets weirdly positioned... */
1122 uiDefBlockBut(block,
1124 but,
1125 "Change Shortcut",
1126 0,
1127 0,
1128 layout->width(),
1129 UI_UNIT_Y,
1130 "");
1131#endif
1132
1133 uiBut *but2 = uiDefIconTextBut(
1134 block,
1136 0,
1137 ICON_HAND,
1138 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"),
1139 0,
1140 0,
1141 w,
1142 UI_UNIT_Y,
1143 nullptr,
1144 "");
1145 UI_but_func_set(but2, [but](bContext &C) {
1147 });
1148 }
1149 else {
1150 uiBut *but2 = uiDefIconTextBut(block,
1152 0,
1153 ICON_HAND,
1154 IFACE_("Non-Keyboard Shortcut"),
1155 0,
1156 0,
1157 w,
1158 UI_UNIT_Y,
1159 nullptr,
1160 TIP_("Only keyboard shortcuts can be edited that way, "
1161 "please use User Preferences otherwise"));
1163 }
1164
1165 uiBut *but2 = uiDefIconTextBut(
1166 block,
1168 0,
1169 ICON_BLANK1,
1170 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"),
1171 0,
1172 0,
1173 w,
1174 UI_UNIT_Y,
1175 nullptr,
1176 "");
1177 UI_but_func_set(but2, [but](bContext &C) { remove_shortcut_func(&C, but); });
1178 }
1179 /* only show 'assign' if there's a suitable key map for it to go in */
1180 else if (WM_keymap_guess_opname(C, idname)) {
1181 uiBut *but2 = uiDefIconTextBut(
1182 block,
1184 0,
1185 ICON_HAND,
1186 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"),
1187 0,
1188 0,
1189 w,
1190 UI_UNIT_Y,
1191 nullptr,
1192 "");
1193 UI_but_func_set(but2, [but](bContext &C) {
1195 });
1196 }
1197
1199
1200 /* Set the operator pointer for python access */
1201 layout->context_set_from_but(but);
1202
1203 layout->separator();
1204 }
1205
1206 { /* Docs */
1207 if (std::optional<std::string> manual_id = UI_but_online_manual_id(but)) {
1208 PointerRNA ptr_props;
1209 layout->op("WM_OT_doc_view_manual_ui_context",
1211 ICON_URL);
1212
1213 if (U.flag & USER_DEVELOPER_UI) {
1214 ptr_props = layout->op(
1215 "WM_OT_doc_view",
1216 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
1217 ICON_NONE,
1219 UI_ITEM_NONE);
1220 RNA_string_set(&ptr_props, "doc_id", manual_id.value().c_str());
1221 }
1222 }
1223 }
1224
1225 if (but->optype && U.flag & USER_DEVELOPER_UI) {
1226 layout->op("UI_OT_copy_python_command_button", std::nullopt, ICON_NONE);
1227 }
1228
1229 /* perhaps we should move this into (G.debug & G_DEBUG) - campbell */
1230 if (U.flag & USER_DEVELOPER_UI) {
1231 if (ui_block_is_menu(but->block) == false) {
1232 layout->op("UI_OT_editsource",
1233 std::nullopt,
1234 ICON_NONE,
1236 UI_ITEM_NONE);
1237 }
1238 }
1239
1240 /* Show header tools for header buttons. */
1241 if (ui_block_is_popup_any(but->block) == false) {
1242 const ARegion *region = CTX_wm_region(C);
1243
1244 if (!region) {
1245 /* skip */
1246 }
1248 layout->menu_fn(IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, nullptr);
1249 }
1250 else if (region->regiontype == RGN_TYPE_NAV_BAR) {
1251 layout->menu_fn(IFACE_("Navigation Bar"), ICON_NONE, ED_buttons_navbar_menu, nullptr);
1252 const ScrArea *area = CTX_wm_area(C);
1253 if (area && area->spacetype == SPACE_PROPERTIES) {
1254 layout->menu_fn(IFACE_("Visible Tabs"), ICON_NONE, ED_buttons_visible_tabs_menu, nullptr);
1255 }
1256 }
1257 else if (region->regiontype == RGN_TYPE_FOOTER) {
1258 layout->menu_fn(IFACE_("Footer"), ICON_NONE, ED_screens_footer_tools_menu_create, nullptr);
1259 }
1260 }
1261
1262 /* UI List item context menu. Scripts can add items to it, by default there's nothing shown. */
1264 const bool is_inside_listbox = ui_list_find_mouse_over(region, event) != nullptr;
1265 const bool is_inside_listrow = is_inside_listbox ?
1266 ui_list_row_find_mouse_over(region, event->xy) != nullptr :
1267 false;
1268 if (is_inside_listrow) {
1269 MenuType *mt = WM_menutype_find("UI_MT_list_item_context_menu", true);
1270 if (mt) {
1271 UI_menutype_draw(C, mt, &layout->column(false));
1272 }
1273 }
1274
1275 MenuType *mt = WM_menutype_find("UI_MT_button_context_menu", true);
1276 if (mt) {
1277 UI_menutype_draw(C, mt, &layout->column(false));
1278 }
1279
1280 if (but->context) {
1281 CTX_store_set(C, previous_ctx);
1282 }
1283
1284 return UI_popup_menu_end_or_cancel(C, pup);
1285}
1286
1288
1289/* -------------------------------------------------------------------- */
1292
1294{
1295 bScreen *screen = CTX_wm_screen(C);
1296 const bool has_panel_category = UI_panel_category_is_visible(region);
1297 const bool any_item_visible = has_panel_category;
1298
1299 if (!any_item_visible) {
1300 return;
1301 }
1302 if (panel->type->parent != nullptr) {
1303 return;
1304 }
1305 if (!UI_panel_can_be_pinned(panel)) {
1306 return;
1307 }
1308
1309 PointerRNA ptr = RNA_pointer_create_discrete(&screen->id, &RNA_Panel, panel);
1310
1311 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE);
1312 uiLayout *layout = UI_popup_menu_layout(pup);
1313
1314 if (has_panel_category) {
1315 char tmpstr[80];
1316 SNPRINTF_UTF8(tmpstr, "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift Left Mouse"));
1317 layout->prop(&ptr, "use_pin", UI_ITEM_NONE, tmpstr, ICON_NONE);
1318
1319 /* evil, force shortcut flag */
1320 {
1321 uiBlock *block = layout->block();
1322 uiBut *but = block->buttons.last().get();
1323 but->flag |= UI_BUT_HAS_SEP_CHAR;
1324 }
1325 }
1326 UI_popup_menu_end(C, pup);
1327}
1328
bScreen * CTX_wm_screen(const bContext *C)
ARegion * CTX_wm_region_popup(const bContext *C)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
ScrArea * CTX_wm_area(const bContext *C)
Main * CTX_data_main(const bContext *C)
const bContextStore * CTX_store_get(const bContext *C)
void CTX_store_set(bContext *C, const bContextStore *store)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1251
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:717
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:863
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:360
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:448
#define FILE_MAXFILE
#define FILE_MAX
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
#define FILE_MAXDIR
#define SNPRINTF_UTF8(dst, format,...)
unsigned int uint
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
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
@ RGN_TYPE_TOOL_HEADER
@ RGN_TYPE_NAV_BAR
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
@ SPACE_PROPERTIES
#define UI_SCALE_FAC
@ USER_DEVELOPER_UI
void ED_buttons_navbar_menu(bContext *C, uiLayout *layout, void *)
void ED_buttons_visible_tabs_menu(bContext *C, uiLayout *layout, void *)
void ED_screen_user_menu_item_add_operator(ListBase *lb, const char *ui_name, const wmOperatorType *ot, const IDProperty *prop, const char *op_prop_enum, blender::wm::OpCallContext opcontext)
bUserMenu * ED_screen_user_menu_ensure(bContext *C)
bUserMenuItem_Op * ED_screen_user_menu_item_find_operator(ListBase *lb, const wmOperatorType *ot, IDProperty *prop, const char *op_prop_enum, blender::wm::OpCallContext opcontext)
void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *arg)
bUserMenu ** ED_screen_user_menus_find(const bContext *C, uint *r_len)
bUserMenuItem_Prop * ED_screen_user_menu_item_find_prop(ListBase *lb, const char *context_data_path, const char *prop_id, int prop_index)
void ED_screen_user_menu_item_add_prop(ListBase *lb, const char *ui_name, const char *context_data_path, const char *prop_id, int prop_index)
void ED_screen_user_menu_item_add_menu(ListBase *lb, const char *ui_name, const MenuType *mt)
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *arg)
void ED_screen_user_menu_item_remove(ListBase *lb, bUserMenuItem *umi)
bUserMenuItem_Menu * ED_screen_user_menu_item_find_menu(ListBase *lb, const MenuType *mt)
static bool is_disabled
Read Guarded memory(de)allocation.
@ RNA_OVERRIDE_STATUS_OVERRIDABLE
PropertyType
Definition RNA_types.hh:161
@ PROP_FLOAT
Definition RNA_types.hh:164
@ PROP_BOOLEAN
Definition RNA_types.hh:162
@ PROP_ENUM
Definition RNA_types.hh:166
@ PROP_INT
Definition RNA_types.hh:163
@ PROP_STRING
Definition RNA_types.hh:165
@ PROP_POINTER
Definition RNA_types.hh:167
PropertySubType
Definition RNA_types.hh:232
@ PROP_DIRPATH
Definition RNA_types.hh:237
@ PROP_FILEPATH
Definition RNA_types.hh:236
#define C
Definition RandGen.cpp:29
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
uiBut * uiDefIconTextBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, std::optional< blender::StringRef > tip)
#define UI_UNIT_Y
#define UI_SEP_CHAR_S
@ UI_BLOCK_MOVEMOUSE_QUIT
bool UI_panel_can_be_pinned(const Panel *panel)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
@ UI_BUT_ANIMATED
@ UI_BUT_DISABLED
@ UI_BUT_OVERRIDDEN
@ UI_BUT_HAS_SEP_CHAR
@ UI_BUT_DRIVEN
@ UI_BUT_ANIMATED_KEY
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
Definition interface.cc:653
void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
MenuType * UI_but_menutype_get(const uiBut *but)
const uiStyle * UI_style_get_dpi()
bool UI_panel_category_is_visible(const ARegion *region)
void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, wmOperator *op)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
std::string UI_but_context_menu_title_from_button(uiBut &but)
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiBut * uiDefBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, blender::StringRef str, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
std::optional< std::string > UI_but_online_manual_id(const uiBut *but) ATTR_WARN_UNUSED_RESULT
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
PanelType * UI_but_paneltype_get(const uiBut *but)
bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
void UI_block_direction_set(uiBlock *block, char direction)
void UI_block_flag_enable(uiBlock *block, int flag)
bool UI_but_is_tool(const uiBut *but)
void UI_but_flag_enable(uiBut *but, int flag)
@ UI_DIR_CENTER_Y
std::optional< blender::StringRefNull > UI_but_asset_shelf_type_idname_get(const uiBut *but)
wmOperatorType * UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
@ UI_ITEM_R_IMMEDIATE
@ UI_ITEM_R_FULL_EVENT
#define UI_ITEM_NONE
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
@ KM_ANY
Definition WM_types.hh:309
@ KM_PRESS
Definition WM_types.hh:311
#define U
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
const T & last(const int64_t n=0) const
virtual void build_context_menu(bContext &C, uiLayout &column) const
bool ANIM_driver_can_paste()
Definition drivers.cc:555
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip)
static bool ui_but_is_user_menu_compatible(bContext *C, uiBut *but)
static void set_layout_context_from_button(bContext *C, uiLayout *layout, uiBut *but)
static IDProperty * shortcut_property_from_rna(bContext *C, uiBut *but)
static void but_shortcut_name_func(bContext *C, void *arg1, int)
static bool ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop)
static uiBlock * menu_change_shortcut(bContext *C, ARegion *region, void *arg)
void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
static uiBlock * menu_add_shortcut(bContext *C, ARegion *region, void *arg)
static const char * shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **r_prop)
static bUserMenuItem * ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *um)
bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *event)
static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
static void shortcut_free_operator_property(IDProperty *prop)
static void remove_shortcut_func(bContext *C, uiBut *but)
static void menu_add_shortcut_cancel(bContext *C, void *arg1)
static int g_kmi_id_hack
uiBut * ui_view_item_find_mouse_over(const ARegion *region, const int xy[2]) ATTR_NONNULL(1
bool ui_jump_to_target_button_poll(bContext *C)
bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
uiBut * ui_list_find_mouse_over(const ARegion *region, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
blender::StringRef ui_but_drawstr_without_sep_char(const uiBut *but) ATTR_NONNULL()
uiBut * ui_list_row_find_mouse_over(const ARegion *region, const int xy[2]) ATTR_NONNULL(1
void ui_rna_collection_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRef prop_name, int32_t value, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_INT, set its name and value.
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRef prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
bool can_mark_single_from_context(const bContext *C)
uiLayout & block_layout(uiBlock *block, LayoutDirection direction, LayoutType type, int x, int y, int size, int em, int padding, const uiStyle *style)
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
PropertyType RNA_property_type(PropertyRNA *prop)
bool RNA_property_anim_editable(const PointerRNA *ptr, PropertyRNA *prop_orig)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_is_idprop(const PropertyRNA *prop)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
const char * RNA_property_identifier(const PropertyRNA *prop)
eRNAOverrideStatus RNA_property_override_library_status(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const int index)
std::string RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index)
Definition rna_path.cc:1352
Definition DNA_ID.h:414
struct AssetMetaData * asset_data
Definition DNA_ID.h:423
bool(* poll)(const bContext *C, MenuType *mt)
PanelType * parent
struct PanelType * type
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
blender::Vector< std::unique_ptr< uiBut > > buttons
MenuType * menu
blender::ui::AbstractViewItem * view_item
std::function< void(bContext &)> apply_func
PropertyRNA * rnaprop
wmOperatorType * optype
std::function< std::string(const uiBut *)> tip_quick_func
ButType type
uiBlock * block
PointerRNA * opptr
uiMenuCreateFunc menu_create_func
blender::wm::OpCallContext opcontext
const bContextStore * context
PointerRNA rnapoin
uiBlock * block() const
bContextStore * context_store() const
void operator_context_set(blender::wm::OpCallContext opcontext)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
void enabled_set(bool enabled)
void menu_fn(blender::StringRefNull name, int icon, uiMenuCreateFunc func, void *arg)
int width() const
void context_copy(const bContextStore *context)
void context_set_from_but(const uiBut *but)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void menu(MenuType *mt, std::optional< blender::StringRef > name, int icon)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
int xy[2]
Definition WM_types.hh:761
const char * idname
Definition WM_types.hh:1035
#define EVT_TYPE_MASK_HOTKEY_INCLUDE
#define ISNDOF_BUTTON(event_type)
@ EVT_AKEY
#define ISKEYBOARD(event_type)
#define EVT_TYPE_MASK_HOTKEY_EXCLUDE
#define EVT_TYPE_MASK_ALL
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
std::optional< std::string > WM_key_event_operator_string(const bContext *C, const char *opname, blender::wm::OpCallContext opcontext, IDProperty *properties, const bool is_strict)
void WM_keyconfig_update(wmWindowManager *wm)
wmKeyMapItem * WM_keymap_item_find_id(wmKeyMap *keymap, int id)
void WM_keymap_item_properties_reset(wmKeyMapItem *kmi, IDProperty *properties)
Definition wm_keymap.cc:206
wmKeyMapItem * WM_keymap_add_item(wmKeyMap *keymap, const char *idname, const KeyMapItem_Params *params)
Definition wm_keymap.cc:548
void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
Definition wm_keymap.cc:580
wmKeyMapItem * WM_key_event_operator(const bContext *C, const char *opname, blender::wm::OpCallContext opcontext, IDProperty *properties, const short include_mask, const short exclude_mask, wmKeyMap **r_keymap)
wmKeyMap * WM_keymap_guess_opname(const bContext *C, const char *opname)
MenuType * WM_menutype_find(const StringRef idname, bool quiet)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
std::optional< std::string > WM_context_path_resolve_property_full(const bContext *C, const PointerRNA *ptr, PropertyRNA *prop, int index)
std::optional< std::string > WM_context_path_resolve_full(bContext *C, const PointerRNA *ptr)