Blender V4.3
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
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_scene_types.h"
16#include "DNA_screen_types.h"
17
18#include "BLI_fileops.h"
19#include "BLI_path_utils.hh"
20#include "BLI_string.h"
21#include "BLI_utildefines.h"
22
23#include "BLT_translation.hh"
24
25#include "BKE_addon.h"
26#include "BKE_context.hh"
27#include "BKE_idprop.hh"
28#include "BKE_screen.hh"
29
30#include "ED_asset.hh"
31#include "ED_keyframing.hh"
32#include "ED_screen.hh"
33
34#include "UI_abstract_view.hh"
35#include "UI_interface.hh"
36
37#include "interface_intern.hh"
38
39#include "RNA_access.hh"
40#include "RNA_path.hh"
41#include "RNA_prototypes.hh"
42
43#ifdef WITH_PYTHON
44# include "BPY_extern.hh"
45# include "BPY_extern_run.hh"
46#endif
47
48#include "WM_api.hh"
49#include "WM_types.hh"
50
51/* This hack is needed because we don't have a good way to
52 * re-reference keymap items once added: #42944 */
53#define USE_KEYMAP_ADD_HACK
54
55/* -------------------------------------------------------------------- */
60{
61 using namespace blender;
62 /* Compute data path from context to property. */
63
64 /* If this returns null, we won't be able to bind shortcuts to these RNA properties.
65 * Support can be added at #wm_context_member_from_ptr. */
66 std::optional<std::string> final_data_path = WM_context_path_resolve_property_full(
67 C, &but->rnapoin, but->rnaprop, but->rnaindex);
68 if (!final_data_path.has_value()) {
69 return nullptr;
70 }
71
72 /* Create ID property of data path, to pass to the operator. */
73 IDProperty *prop = bke::idprop::create_group(__func__).release();
74 IDP_AddToGroup(prop, bke::idprop::create("data_path", final_data_path.value()).release());
75 return prop;
76}
77
78static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **r_prop)
79{
80 using namespace blender;
81 if (but->optype) {
82 /* Operator */
83 *r_prop = (but->opptr && but->opptr->data) ?
84 IDP_CopyProperty(static_cast<IDProperty *>(but->opptr->data)) :
85 nullptr;
86 return but->optype->idname;
87 }
88
89 if (but->rnaprop) {
90 const PropertyType rnaprop_type = RNA_property_type(but->rnaprop);
91
92 if (rnaprop_type == PROP_BOOLEAN) {
93 /* Boolean */
94 *r_prop = shortcut_property_from_rna(C, but);
95 if (*r_prop == nullptr) {
96 return nullptr;
97 }
98 return "WM_OT_context_toggle";
99 }
100 if (rnaprop_type == PROP_ENUM) {
101 /* Enum */
102 *r_prop = shortcut_property_from_rna(C, but);
103 if (*r_prop == nullptr) {
104 return nullptr;
105 }
106 return "WM_OT_context_menu_enum";
107 }
108 }
109
110 if (MenuType *mt = UI_but_menutype_get(but)) {
111 IDProperty *prop = bke::idprop::create_group(__func__).release();
112 IDP_AddToGroup(prop, bke::idprop::create("name", mt->idname).release());
113 *r_prop = prop;
114 return "WM_OT_call_menu";
115 }
116
117 if (std::optional asset_shelf_idname = UI_but_asset_shelf_type_idname_get(but)) {
118 IDProperty *prop = blender::bke::idprop::create_group(__func__).release();
119 IDP_AddToGroup(prop, bke::idprop::create("name", *asset_shelf_idname).release());
120 *r_prop = prop;
121 return "WM_OT_call_asset_shelf_popover";
122 }
123
124 if (PanelType *pt = UI_but_paneltype_get(but)) {
125 IDProperty *prop = blender::bke::idprop::create_group(__func__).release();
126 IDP_AddToGroup(prop, bke::idprop::create("name", pt->idname).release());
127 *r_prop = prop;
128 return "WM_OT_call_panel";
129 }
130
131 *r_prop = nullptr;
132 return nullptr;
133}
134
136{
137 if (prop) {
138 IDP_FreeProperty(prop);
139 }
140}
141
142static void but_shortcut_name_func(bContext *C, void *arg1, int /*event*/)
143{
144 uiBut *but = (uiBut *)arg1;
145
146 IDProperty *prop;
147 const char *idname = shortcut_get_operator_property(C, but, &prop);
148 if (idname == nullptr) {
149 return;
150 }
151
152 /* complex code to change name of button */
153 if (std::optional<std::string> shortcut_str = WM_key_event_operator_string(
154 C, idname, but->opcontext, prop, true))
155 {
156 ui_but_add_shortcut(but, shortcut_str->c_str(), true);
157 }
158 else {
159 /* simply strip the shortcut */
160 ui_but_add_shortcut(but, nullptr, true);
161 }
162
164}
165
166static uiBlock *menu_change_shortcut(bContext *C, ARegion *region, void *arg)
167{
169 uiBut *but = (uiBut *)arg;
170 const uiStyle *style = UI_style_get_dpi();
171 IDProperty *prop;
172 const char *idname = shortcut_get_operator_property(C, but, &prop);
173
174 wmKeyMap *km;
176 idname,
177 but->opcontext,
178 prop,
181 &km);
182 U.runtime.is_dirty = true;
183
184 BLI_assert(kmi != nullptr);
185
186 PointerRNA ptr = RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi);
187
188 uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
192
193 uiLayout *layout = UI_block_layout(block,
196 0,
197 0,
198 U.widget_unit * 10,
199 U.widget_unit * 2,
200 0,
201 style);
202
203 uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), ICON_HAND);
204 uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
205
206 const int bounds_offset[2] = {int(-100 * UI_SCALE_FAC), int(36 * UI_SCALE_FAC)};
207 UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, bounds_offset);
208
210
211 return block;
212}
213
214#ifdef USE_KEYMAP_ADD_HACK
215static int g_kmi_id_hack;
216#endif
217
218static uiBlock *menu_add_shortcut(bContext *C, ARegion *region, void *arg)
219{
221 uiBut *but = (uiBut *)arg;
222 const uiStyle *style = UI_style_get_dpi();
223 IDProperty *prop;
224 const char *idname = shortcut_get_operator_property(C, but, &prop);
225
226 /* XXX this guess_opname can potentially return a different keymap
227 * than being found on adding later... */
228 wmKeyMap *km = WM_keymap_guess_opname(C, idname);
230 params.type = EVT_AKEY;
231 params.value = KM_PRESS;
232 params.modifier = 0;
233 params.direction = KM_ANY;
234 wmKeyMapItem *kmi = WM_keymap_add_item(km, idname, &params);
235 const int kmi_id = kmi->id;
236
237 /* This takes ownership of prop, or prop can be nullptr for reset. */
239
240 /* update and get pointers again */
242 U.runtime.is_dirty = true;
243
244 km = WM_keymap_guess_opname(C, idname);
245 kmi = WM_keymap_item_find_id(km, kmi_id);
246
247 PointerRNA ptr = RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi);
248
249 uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
252
253 uiLayout *layout = UI_block_layout(block,
256 0,
257 0,
258 U.widget_unit * 10,
259 U.widget_unit * 2,
260 0,
261 style);
262
263 uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), ICON_HAND);
264 uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
265
266 const int bounds_offset[2] = {int(-100 * UI_SCALE_FAC), int(36 * UI_SCALE_FAC)};
267 UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, bounds_offset);
268
269#ifdef USE_KEYMAP_ADD_HACK
270 g_kmi_id_hack = kmi_id;
271#endif
272
273 return block;
274}
275
276static void menu_add_shortcut_cancel(bContext *C, void *arg1)
277{
278 uiBut *but = (uiBut *)arg1;
279
280 IDProperty *prop;
281 const char *idname = shortcut_get_operator_property(C, but, &prop);
282
283#ifdef USE_KEYMAP_ADD_HACK
284 wmKeyMap *km = WM_keymap_guess_opname(C, idname);
285 const int kmi_id = g_kmi_id_hack;
286 UNUSED_VARS(but);
287#else
288 int kmi_id = WM_key_event_operator_id(C, idname, but->opcontext, prop, true, &km);
289#endif
290
292
293 wmKeyMapItem *kmi = WM_keymap_item_find_id(km, kmi_id);
294 WM_keymap_remove_item(km, kmi);
295}
296
298{
299 IDProperty *prop;
300 const char *idname = shortcut_get_operator_property(C, but, &prop);
301
302 wmKeyMap *km;
304 idname,
305 but->opcontext,
306 prop,
309 &km);
310 BLI_assert(kmi != nullptr);
311
312 WM_keymap_remove_item(km, kmi);
313 U.runtime.is_dirty = true;
314
316 but_shortcut_name_func(C, but, 0);
317}
318
320{
321 bool result = false;
322 if (but->optype) {
323 result = true;
324 }
325 else if (but->rnaprop) {
327 std::optional<std::string> data_path = WM_context_path_resolve_full(C, &but->rnapoin);
328 if (data_path.has_value()) {
329 result = true;
330 }
331 }
332 }
333 else if (UI_but_menutype_get(but)) {
334 result = true;
335 }
336 else if (UI_but_operatortype_get_from_enum_menu(but, nullptr)) {
337 result = true;
338 }
339
340 return result;
341}
342
344{
345 if (but->optype) {
346 IDProperty *prop = (but->opptr) ? static_cast<IDProperty *>(but->opptr->data) : nullptr;
348 &um->items, but->optype, prop, "", but->opcontext);
349 }
350 if (but->rnaprop) {
351 std::optional<std::string> member_id_data_path = WM_context_path_resolve_full(C,
352 &but->rnapoin);
353 /* NOTE(@ideasman42): It's highly unlikely a this ever occurs since the path must be resolved
354 * for this to be added in the first place, there might be some cases where manually
355 * constructed RNA paths don't resolve and in this case a crash should be avoided. */
356 if (UNLIKELY(!member_id_data_path.has_value())) {
357 /* Assert because this should never happen for typical usage. */
359 return nullptr;
360 }
361 /* Ignore the actual array index [pass -1] since the index is handled separately. */
362 const std::string prop_id = RNA_property_is_idprop(but->rnaprop) ?
363 RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
366 &um->items, member_id_data_path->c_str(), prop_id.c_str(), but->rnaindex);
367 return umi;
368 }
369
370 wmOperatorType *ot = nullptr;
371 PropertyRNA *prop_enum = nullptr;
372 if ((ot = UI_but_operatortype_get_from_enum_menu(but, &prop_enum))) {
374 &um->items, ot, nullptr, RNA_property_identifier(prop_enum), but->opcontext);
375 }
376
377 MenuType *mt = UI_but_menutype_get(but);
378 if (mt != nullptr) {
380 }
381 return nullptr;
382}
383
385{
387
388 std::string drawstr = ui_but_drawstr_without_sep_char(but);
389
390 /* Used for USER_MENU_TYPE_MENU. */
391 MenuType *mt = nullptr;
392 /* Used for USER_MENU_TYPE_OPERATOR (property enum used). */
393 wmOperatorType *ot = nullptr;
394 PropertyRNA *prop = nullptr;
395 if (but->optype) {
396 if (drawstr[0] == '\0') {
397 /* Hard code overrides for generic operators. */
398 if (UI_but_is_tool(but)) {
399 char idname[64];
400 RNA_string_get(but->opptr, "name", idname);
401#ifdef WITH_PYTHON
402 {
403 const char *expr_imports[] = {"bpy", "bl_ui", nullptr};
404 char expr[256];
405 SNPRINTF(expr,
406 "bl_ui.space_toolsystem_common.item_from_id("
407 "bpy.context, "
408 "bpy.context.space_data.type, "
409 "'%s').label",
410 idname);
411 char *expr_result = nullptr;
412 if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) {
413 drawstr = expr_result;
414 MEM_freeN(expr_result);
415 }
416 else {
417 BLI_assert(0);
418 drawstr = idname;
419 }
420 }
421#else
422 STRNCPY(drawstr, idname);
423#endif
424 }
425 else if (but->tip_label_func) {
426 /* The "quick tooltip" often contains a short string that can be used as a fallback. */
427 drawstr = but->tip_label_func(but);
428 }
429 }
431 &um->items,
432 drawstr.c_str(),
433 but->optype,
434 but->opptr ? static_cast<const IDProperty *>(but->opptr->data) : nullptr,
435 "",
436 but->opcontext);
437 }
438 else if (but->rnaprop) {
439 /* NOTE: 'member_id' may be a path. */
440 std::optional<std::string> member_id_data_path = WM_context_path_resolve_full(C,
441 &but->rnapoin);
442 if (!member_id_data_path.has_value()) {
443 /* See #ui_but_user_menu_find code-comment. */
445 }
446 else {
447 /* Ignore the actual array index [pass -1] since the index is handled separately. */
448 const std::string prop_id = RNA_property_is_idprop(but->rnaprop) ?
449 RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
451 /* NOTE: ignore 'drawstr', use property idname always. */
453 &um->items, "", member_id_data_path->c_str(), prop_id.c_str(), but->rnaindex);
454 }
455 }
456 else if ((mt = UI_but_menutype_get(but))) {
457 ED_screen_user_menu_item_add_menu(&um->items, drawstr.c_str(), mt);
458 }
459 else if ((ot = UI_but_operatortype_get_from_enum_menu(but, &prop))) {
461 WM_operatortype_name(ot, nullptr).c_str(),
462 ot,
463 nullptr,
465 but->opcontext);
466 }
467}
468
470{
471 const PropertySubType subtype = RNA_property_subtype(prop);
472 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
473 char filepath[FILE_MAX];
474 char dir[FILE_MAXDIR];
475 char file[FILE_MAXFILE];
476 PointerRNA props_ptr;
477
479 UNUSED_VARS_NDEBUG(subtype);
480
481 RNA_property_string_get(ptr, prop, filepath);
482
483 if (!BLI_exists(filepath)) {
484 return false;
485 }
486
487 if (BLI_is_file(filepath)) {
488 BLI_assert(subtype == PROP_FILEPATH);
489 uiItemFullO_ptr(layout,
490 ot,
491 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open File Externally"),
492 ICON_NONE,
493 nullptr,
496 &props_ptr);
497 RNA_string_set(&props_ptr, "filepath", filepath);
498 }
499 else {
500 /* This is a directory, so ensure it ends in a slash. */
501 BLI_path_slash_ensure(filepath, ARRAY_SIZE(filepath));
502 }
503
504 BLI_path_split_dir_file(filepath, dir, sizeof(dir), file, sizeof(file));
505
506 uiItemFullO_ptr(layout,
507 ot,
508 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Location Externally"),
509 ICON_NONE,
510 nullptr,
513 &props_ptr);
514 RNA_string_set(&props_ptr, "filepath", dir);
515
516 return true;
517}
518
520{
521 if (!but->context) {
522 return;
523 }
524 uiLayoutContextCopy(layout, but->context);
526}
527
529{
530 using namespace blender::ed;
531 /* ui_but_is_interactive() may let some buttons through that should not get a context menu - it
532 * doesn't make sense for them. */
534 return false;
535 }
536
537 uiPopupMenu *pup;
538 uiLayout *layout;
539 const bContextStore *previous_ctx = CTX_store_get(C);
540 {
541 pup = UI_popup_menu_begin(C, UI_but_context_menu_title_from_button(*but).c_str(), ICON_NONE);
542 layout = UI_popup_menu_layout(pup);
543
544 set_layout_context_from_button(C, layout, but);
546 }
547
548 const bool is_disabled = but->flag & UI_BUT_DISABLED;
549
550 if (is_disabled) {
551 /* Suppress editing commands. */
552 }
553 else if (but->type == UI_BTYPE_TAB) {
554 uiButTab *tab = (uiButTab *)but;
555 if (tab->menu) {
556 UI_menutype_draw(C, tab->menu, layout);
557 uiItemS(layout);
558 }
559 }
560 else if (but->rnapoin.data && but->rnaprop) {
561 PointerRNA *ptr = &but->rnapoin;
562 PropertyRNA *prop = but->rnaprop;
563 const PropertyType type = RNA_property_type(prop);
564 const PropertySubType subtype = RNA_property_subtype(prop);
565 bool is_anim = RNA_property_anim_editable(ptr, prop);
566 const bool is_idprop = RNA_property_is_idprop(prop);
567
568 /* second slower test,
569 * saved people finding keyframe items in menus when its not possible */
570 if (is_anim) {
571 is_anim = RNA_property_path_from_ID_check(&but->rnapoin, but->rnaprop);
572 }
573
574 /* determine if we can key a single component of an array */
575 const bool is_array = RNA_property_array_length(&but->rnapoin, but->rnaprop) != 0;
576 const bool is_array_component = (is_array && but->rnaindex != -1);
577 const bool is_whole_array = (is_array && but->rnaindex == -1);
578
579 const uint override_status = RNA_property_override_library_status(
580 CTX_data_main(C), ptr, prop, -1);
581 const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0;
582
583 /* Set the (button_pointer, button_prop)
584 * and pointer data for Python access to the hovered UI element. */
585 uiLayoutSetContextFromBut(layout, but);
586
587 /* Keyframes */
588 if (but->flag & UI_BUT_ANIMATED_KEY) {
589 /* Replace/delete keyframes. */
590 if (is_array_component) {
591 uiItemBooleanO(layout,
592 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframes"),
593 ICON_KEY_HLT,
594 "ANIM_OT_keyframe_insert_button",
595 "all",
596 1);
597 uiItemBooleanO(layout,
598 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Single Keyframe"),
599 ICON_NONE,
600 "ANIM_OT_keyframe_insert_button",
601 "all",
602 0);
603 uiItemBooleanO(layout,
604 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframes"),
605 ICON_NONE,
606 "ANIM_OT_keyframe_delete_button",
607 "all",
608 1);
609 uiItemBooleanO(layout,
610 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Keyframe"),
611 ICON_NONE,
612 "ANIM_OT_keyframe_delete_button",
613 "all",
614 0);
615 }
616 else {
617 uiItemBooleanO(layout,
618 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframe"),
619 ICON_KEY_HLT,
620 "ANIM_OT_keyframe_insert_button",
621 "all",
622 1);
623 uiItemBooleanO(layout,
625 ICON_NONE,
626 "ANIM_OT_keyframe_delete_button",
627 "all",
628 1);
629 }
630
631 /* keyframe settings */
632 uiItemS(layout);
633 }
634 else if (but->flag & UI_BUT_DRIVEN) {
635 /* pass */
636 }
637 else if (is_anim) {
638 if (is_array_component) {
639 uiItemBooleanO(layout,
640 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframes"),
641 ICON_KEY_HLT,
642 "ANIM_OT_keyframe_insert_button",
643 "all",
644 1);
645 uiItemBooleanO(layout,
646 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Single Keyframe"),
647 ICON_NONE,
648 "ANIM_OT_keyframe_insert_button",
649 "all",
650 0);
651 }
652 else {
653 uiItemBooleanO(layout,
655 ICON_KEY_HLT,
656 "ANIM_OT_keyframe_insert_button",
657 "all",
658 1);
659 }
660 }
661
662 if ((but->flag & UI_BUT_ANIMATED) && (but->rnapoin.type != &RNA_NlaStrip)) {
663 if (is_array_component) {
664 uiItemBooleanO(layout,
666 ICON_KEY_DEHLT,
667 "ANIM_OT_keyframe_clear_button",
668 "all",
669 1);
670 uiItemBooleanO(layout,
671 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Single Keyframes"),
672 ICON_NONE,
673 "ANIM_OT_keyframe_clear_button",
674 "all",
675 0);
676 }
677 else {
678 uiItemBooleanO(layout,
680 ICON_KEY_DEHLT,
681 "ANIM_OT_keyframe_clear_button",
682 "all",
683 1);
684 }
685 }
686
687 if (but->flag & UI_BUT_ANIMATED) {
688 uiItemS(layout);
689 if (is_array_component) {
690 PointerRNA op_ptr;
692 ot = WM_operatortype_find("ANIM_OT_view_curve_in_graph_editor", false);
693 uiItemFullO_ptr(layout,
694 ot,
695 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "View All in Graph Editor"),
696 ICON_GRAPH,
697 nullptr,
700 &op_ptr);
701 RNA_boolean_set(&op_ptr, "all", true);
702
704 layout,
705 ot,
706 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "View Single in Graph Editor"),
707 ICON_NONE,
708 nullptr,
711 &op_ptr);
712 RNA_boolean_set(&op_ptr, "all", false);
713 }
714 else {
715 PointerRNA op_ptr;
717 ot = WM_operatortype_find("ANIM_OT_view_curve_in_graph_editor", false);
718
719 uiItemFullO_ptr(layout,
720 ot,
721 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "View in Graph Editor"),
722 ICON_NONE,
723 nullptr,
726 &op_ptr);
727 RNA_boolean_set(&op_ptr, "all", false);
728 }
729 }
730
731 /* Drivers */
732 if (but->flag & UI_BUT_DRIVEN) {
733 uiItemS(layout);
734
735 if (is_array_component) {
736 uiItemBooleanO(layout,
738 ICON_X,
739 "ANIM_OT_driver_button_remove",
740 "all",
741 1);
742 uiItemBooleanO(layout,
743 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Driver"),
744 ICON_NONE,
745 "ANIM_OT_driver_button_remove",
746 "all",
747 0);
748 }
749 else {
750 uiItemBooleanO(layout,
752 ICON_X,
753 "ANIM_OT_driver_button_remove",
754 "all",
755 1);
756 }
757
758 if (is_whole_array) {
759 uiItemBooleanO(layout,
760 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Drivers to Selected"),
761 ICON_NONE,
762 "UI_OT_copy_driver_to_selected_button",
763 "all",
764 true);
765 }
766 else {
767 uiItemO(layout,
769 ICON_NONE,
770 "ANIM_OT_copy_driver_button");
771 if (ANIM_driver_can_paste()) {
772 uiItemO(layout,
774 ICON_NONE,
775 "ANIM_OT_paste_driver_button");
776 }
777 uiItemBooleanO(layout,
778 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver to Selected"),
779 ICON_NONE,
780 "UI_OT_copy_driver_to_selected_button",
781 "all",
782 false);
783 if (is_array_component) {
785 layout,
786 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All Drivers to Selected"),
787 ICON_NONE,
788 "UI_OT_copy_driver_to_selected_button",
789 "all",
790 true);
791 }
792
793 uiItemO(layout,
795 ICON_DRIVER,
796 "ANIM_OT_driver_button_edit");
797 }
798
799 uiItemO(layout,
800 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Drivers Editor"),
801 ICON_NONE,
802 "SCREEN_OT_drivers_editor_show");
803 }
804 else if (but->flag & (UI_BUT_ANIMATED_KEY | UI_BUT_ANIMATED)) {
805 /* pass */
806 }
807 else if (is_anim) {
808 uiItemS(layout);
809
810 uiItemO(layout,
812 ICON_DRIVER,
813 "ANIM_OT_driver_button_add");
814
815 if (!is_whole_array) {
816 if (ANIM_driver_can_paste()) {
817 uiItemO(layout,
819 ICON_NONE,
820 "ANIM_OT_paste_driver_button");
821 }
822 }
823
824 uiItemO(layout,
825 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Drivers Editor"),
826 ICON_NONE,
827 "SCREEN_OT_drivers_editor_show");
828 }
829
830 /* Keying Sets */
831 /* TODO: check on modifiability of Keying Set when doing this. */
832 if (is_anim) {
833 uiItemS(layout);
834
835 if (is_array_component) {
836 uiItemBooleanO(layout,
837 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add All to Keying Set"),
838 ICON_KEYINGSET,
839 "ANIM_OT_keyingset_button_add",
840 "all",
841 1);
842 uiItemBooleanO(layout,
843 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single to Keying Set"),
844 ICON_NONE,
845 "ANIM_OT_keyingset_button_add",
846 "all",
847 0);
848 uiItemO(layout,
849 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
850 ICON_NONE,
851 "ANIM_OT_keyingset_button_remove");
852 }
853 else {
854 uiItemBooleanO(layout,
855 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Keying Set"),
856 ICON_KEYINGSET,
857 "ANIM_OT_keyingset_button_add",
858 "all",
859 1);
860 uiItemO(layout,
861 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
862 ICON_NONE,
863 "ANIM_OT_keyingset_button_remove");
864 }
865 }
866
867 if (is_overridable) {
869 PointerRNA op_ptr;
870 /* Override Operators */
871 uiItemS(layout);
872
873 if (but->flag & UI_BUT_OVERRIDDEN) {
874 if (is_array_component) {
875#if 0 /* Disabled for now. */
876 ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
878 layout, ot, "Overrides Type", ICON_NONE, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
879 RNA_boolean_set(&op_ptr, "all", true);
880 uiItemFullO_ptr(layout,
881 ot,
882 "Single Override Type",
883 ICON_NONE,
884 nullptr,
886 0,
887 &op_ptr);
888 RNA_boolean_set(&op_ptr, "all", false);
889#endif
890 uiItemBooleanO(layout,
891 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Overrides"),
892 ICON_X,
893 "UI_OT_override_remove_button",
894 "all",
895 true);
896 uiItemBooleanO(layout,
897 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Single Override"),
898 ICON_X,
899 "UI_OT_override_remove_button",
900 "all",
901 false);
902 }
903 else {
904#if 0 /* Disabled for now. */
905 uiItemFullO(layout,
906 "UI_OT_override_type_set_button",
907 "Override Type",
908 ICON_NONE,
909 nullptr,
911 0,
912 &op_ptr);
913 RNA_boolean_set(&op_ptr, "all", false);
914#endif
915 uiItemBooleanO(layout,
917 ICON_X,
918 "UI_OT_override_remove_button",
919 "all",
920 true);
921 }
922 }
923 else {
924 if (is_array_component) {
925 ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
926 uiItemFullO_ptr(layout,
927 ot,
928 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Define Overrides"),
929 ICON_NONE,
930 nullptr,
933 &op_ptr);
934 RNA_boolean_set(&op_ptr, "all", true);
935 uiItemFullO_ptr(layout,
936 ot,
937 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Define Single Override"),
938 ICON_NONE,
939 nullptr,
942 &op_ptr);
943 RNA_boolean_set(&op_ptr, "all", false);
944 }
945 else {
946 uiItemFullO(layout,
947 "UI_OT_override_type_set_button",
949 ICON_NONE,
950 nullptr,
953 &op_ptr);
954 RNA_boolean_set(&op_ptr, "all", false);
955 }
956 }
957 }
958
959 uiItemS(layout);
960
961 /* Property Operators */
962
963 /* Copy Property Value
964 * Paste Property Value */
965
966 if (is_array_component) {
967 uiItemBooleanO(layout,
968 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset All to Default Values"),
969 ICON_LOOP_BACK,
970 "UI_OT_reset_default_button",
971 "all",
972 1);
973 uiItemBooleanO(layout,
974 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Single to Default Value"),
975 ICON_NONE,
976 "UI_OT_reset_default_button",
977 "all",
978 0);
979 }
980 else {
981 uiItemBooleanO(layout,
982 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset to Default Value"),
983 ICON_LOOP_BACK,
984 "UI_OT_reset_default_button",
985 "all",
986 1);
987 }
988
989 if (is_idprop && !is_array && ELEM(type, PROP_INT, PROP_FLOAT)) {
990 uiItemO(layout,
991 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Value as Default"),
992 ICON_NONE,
993 "UI_OT_assign_default_button");
994
995 uiItemS(layout);
996 }
997
998 if (is_array_component) {
999 uiItemBooleanO(layout,
1000 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All to Selected"),
1001 ICON_NONE,
1002 "UI_OT_copy_to_selected_button",
1003 "all",
1004 true);
1005 uiItemBooleanO(layout,
1006 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single to Selected"),
1007 ICON_NONE,
1008 "UI_OT_copy_to_selected_button",
1009 "all",
1010 false);
1011 }
1012 else {
1013 uiItemBooleanO(layout,
1014 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
1015 ICON_NONE,
1016 "UI_OT_copy_to_selected_button",
1017 "all",
1018 true);
1019 }
1020
1021 uiItemO(layout,
1023 ICON_NONE,
1024 "UI_OT_copy_data_path_button");
1025 uiItemBooleanO(layout,
1026 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Full Data Path"),
1027 ICON_NONE,
1028 "UI_OT_copy_data_path_button",
1029 "full_path",
1030 true);
1031
1032 if (ptr->owner_id && !is_whole_array &&
1034 {
1035 uiItemO(layout,
1036 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy as New Driver"),
1037 ICON_NONE,
1038 "UI_OT_copy_as_driver_button");
1039 }
1040
1041 uiItemS(layout);
1042
1043 if (type == PROP_STRING && ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
1044 if (ui_but_menu_add_path_operators(layout, ptr, prop)) {
1045 uiItemS(layout);
1046 }
1047 }
1048 }
1049 else if (but->optype && but->opptr && RNA_struct_property_is_set(but->opptr, "filepath")) {
1050 /* Operator with "filepath" string property of PROP_FILEPATH subtype. */
1051 PropertyRNA *prop = RNA_struct_find_property(but->opptr, "filepath");
1052 const PropertySubType subtype = RNA_property_subtype(prop);
1053
1054 if (prop && RNA_property_type(prop) == PROP_STRING &&
1056 {
1057 char filepath[FILE_MAX] = {0};
1058 RNA_property_string_get(but->opptr, prop, filepath);
1059 if (filepath[0] && BLI_exists(filepath)) {
1060 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
1061 PointerRNA props_ptr;
1062 char dir[FILE_MAXDIR];
1063 BLI_path_split_dir_part(filepath, dir, sizeof(dir));
1064 uiItemFullO_ptr(layout,
1065 ot,
1066 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open File Location"),
1067 ICON_NONE,
1068 nullptr,
1071 &props_ptr);
1072 RNA_string_set(&props_ptr, "filepath", dir);
1073 uiItemS(layout);
1074 }
1075 }
1076 }
1077
1078 {
1079 const ARegion *region = CTX_wm_region_popup(C) ? CTX_wm_region_popup(C) : CTX_wm_region(C);
1080 uiButViewItem *view_item_but = (but->type == UI_BTYPE_VIEW_ITEM) ?
1081 static_cast<uiButViewItem *>(but) :
1082 static_cast<uiButViewItem *>(
1083 ui_view_item_find_mouse_over(region, event->xy));
1084 if (view_item_but) {
1085 BLI_assert(view_item_but->type == UI_BTYPE_VIEW_ITEM);
1086
1087 const bContextStore *prev_ctx = CTX_store_get(C);
1088 /* Sub-layout for context override. */
1089 uiLayout *sub = uiLayoutColumn(layout, false);
1090 set_layout_context_from_button(C, sub, view_item_but);
1091 view_item_but->view_item->build_context_menu(*C, *sub);
1092
1093 /* Reset context. */
1094 CTX_store_set(C, prev_ctx);
1095
1096 uiItemS(layout);
1097 }
1098 }
1099
1100 /* Expose id specific operators in context menu when button has no operator associated. Otherwise
1101 * they would appear in nested context menus, see: #126006. */
1102 if ((but->optype == nullptr) && (but->apply_func == nullptr) &&
1103 (but->menu_create_func == nullptr))
1104 {
1105 /* If the button represents an id, it can set the "id" context pointer. */
1106 if (asset::can_mark_single_from_context(C)) {
1107 const ID *id = static_cast<const ID *>(CTX_data_pointer_get_type(C, "id", &RNA_ID).data);
1108
1109 /* Gray out items depending on if data-block is an asset. Preferably this could be done via
1110 * operator poll, but that doesn't work since the operator also works with "selected_ids",
1111 * which isn't cheap to check. */
1112 uiLayout *sub = uiLayoutColumn(layout, true);
1113 uiLayoutSetEnabled(sub, !id->asset_data);
1114 uiItemO(sub,
1116 ICON_ASSET_MANAGER,
1117 "ASSET_OT_mark_single");
1118 sub = uiLayoutColumn(layout, true);
1119 uiLayoutSetEnabled(sub, id->asset_data);
1120 uiItemO(sub,
1122 ICON_NONE,
1123 "ASSET_OT_clear_single");
1124 uiItemS(layout);
1125 }
1126
1127 MenuType *mt_idtemplate_liboverride = WM_menutype_find("UI_MT_idtemplate_liboverride", true);
1128 if (mt_idtemplate_liboverride && mt_idtemplate_liboverride->poll(C, mt_idtemplate_liboverride))
1129 {
1130 uiItemM_ptr(layout, mt_idtemplate_liboverride, IFACE_("Library Override"), ICON_NONE);
1131 uiItemS(layout);
1132 }
1133 }
1134
1135 /* Pointer properties and string properties with
1136 * prop_search support jumping to target object/bone. */
1137 if (but->rnapoin.data && but->rnaprop) {
1138 const PropertyType prop_type = RNA_property_type(but->rnaprop);
1139 if (((prop_type == PROP_POINTER) ||
1140 (prop_type == PROP_STRING && but->type == UI_BTYPE_SEARCH_MENU &&
1141 ((uiButSearch *)but)->items_update_fn == ui_rna_collection_search_update_fn)) &&
1143 {
1144 uiItemO(layout,
1146 ICON_NONE,
1147 "UI_OT_jump_to_target_button");
1148 uiItemS(layout);
1149 }
1150 }
1151
1152 /* Favorites Menu */
1153 if (ui_but_is_user_menu_compatible(C, but)) {
1154 uiBlock *block = uiLayoutGetBlock(layout);
1155 const int w = uiLayoutGetWidth(layout);
1156 bool item_found = false;
1157
1158 uint um_array_len;
1159 bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len);
1160 for (int um_index = 0; um_index < um_array_len; um_index++) {
1161 bUserMenu *um = um_array[um_index];
1162 if (um == nullptr) {
1163 continue;
1164 }
1165 bUserMenuItem *umi = ui_but_user_menu_find(C, but, um);
1166 if (umi != nullptr) {
1167 uiBut *but2 = uiDefIconTextBut(
1168 block,
1170 0,
1171 ICON_MENU_PANEL,
1172 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Quick Favorites"),
1173 0,
1174 0,
1175 w,
1176 UI_UNIT_Y,
1177 nullptr,
1178 0,
1179 0,
1180 "");
1181 item_found = true;
1182 UI_but_func_set(but2, [um, umi](bContext &) {
1183 U.runtime.is_dirty = true;
1185 });
1186 }
1187 }
1188 if (um_array) {
1189 MEM_freeN(um_array);
1190 }
1191
1192 if (!item_found) {
1193 uiBut *but2 = uiDefIconTextBut(
1194 block,
1196 0,
1197 ICON_MENU_PANEL,
1198 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Quick Favorites"),
1199 0,
1200 0,
1201 w,
1202 UI_UNIT_Y,
1203 nullptr,
1204 0,
1205 0,
1206 TIP_("Add to a user defined context menu (stored in the user preferences)"));
1207 UI_but_func_set(but2, [but](bContext &C) {
1209 U.runtime.is_dirty = true;
1210 ui_but_user_menu_add(&C, but, um);
1211 });
1212 }
1213
1214 uiItemS(layout);
1215 }
1216
1217 /* Shortcut menu */
1218 IDProperty *prop;
1219 const char *idname = shortcut_get_operator_property(C, but, &prop);
1220 if (idname != nullptr) {
1221 uiBlock *block = uiLayoutGetBlock(layout);
1222 const int w = uiLayoutGetWidth(layout);
1223
1224 /* We want to know if this op has a shortcut, be it hotkey or not. */
1225 wmKeyMap *km;
1227 C, idname, but->opcontext, prop, EVT_TYPE_MASK_ALL, 0, &km);
1228
1229 /* We do have a shortcut, but only keyboard ones are editable that way... */
1230 if (kmi) {
1231 if (ISKEYBOARD(kmi->type) || ISNDOF_BUTTON(kmi->type)) {
1232#if 0 /* would rather use a block but, but gets weirdly positioned... */
1233 uiDefBlockBut(block,
1235 but,
1236 "Change Shortcut",
1237 0,
1238 0,
1239 uiLayoutGetWidth(layout),
1240 UI_UNIT_Y,
1241 "");
1242#endif
1243
1244 uiBut *but2 = uiDefIconTextBut(
1245 block,
1247 0,
1248 ICON_HAND,
1249 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"),
1250 0,
1251 0,
1252 w,
1253 UI_UNIT_Y,
1254 nullptr,
1255 0,
1256 0,
1257 "");
1258 UI_but_func_set(but2, [but](bContext &C) {
1260 });
1261 }
1262 else {
1263 uiBut *but2 = uiDefIconTextBut(block,
1265 0,
1266 ICON_HAND,
1267 IFACE_("Non-Keyboard Shortcut"),
1268 0,
1269 0,
1270 w,
1271 UI_UNIT_Y,
1272 nullptr,
1273 0,
1274 0,
1275 TIP_("Only keyboard shortcuts can be edited that way, "
1276 "please use User Preferences otherwise"));
1278 }
1279
1280 uiBut *but2 = uiDefIconTextBut(
1281 block,
1283 0,
1284 ICON_BLANK1,
1285 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"),
1286 0,
1287 0,
1288 w,
1289 UI_UNIT_Y,
1290 nullptr,
1291 0,
1292 0,
1293 "");
1294 UI_but_func_set(but2, [but](bContext &C) { remove_shortcut_func(&C, but); });
1295 }
1296 /* only show 'assign' if there's a suitable key map for it to go in */
1297 else if (WM_keymap_guess_opname(C, idname)) {
1298 uiBut *but2 = uiDefIconTextBut(
1299 block,
1301 0,
1302 ICON_HAND,
1303 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"),
1304 0,
1305 0,
1306 w,
1307 UI_UNIT_Y,
1308 nullptr,
1309 0,
1310 0,
1311 "");
1312 UI_but_func_set(but2, [but](bContext &C) {
1314 });
1315 }
1316
1318
1319 /* Set the operator pointer for python access */
1320 uiLayoutSetContextFromBut(layout, but);
1321
1322 uiItemS(layout);
1323 }
1324
1325 { /* Docs */
1326 if (std::optional<std::string> manual_id = UI_but_online_manual_id(but)) {
1327 PointerRNA ptr_props;
1328 uiItemO(layout,
1330 ICON_URL,
1331 "WM_OT_doc_view_manual_ui_context");
1332
1333 if (U.flag & USER_DEVELOPER_UI) {
1334 uiItemFullO(layout,
1335 "WM_OT_doc_view",
1336 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
1337 ICON_NONE,
1338 nullptr,
1341 &ptr_props);
1342 RNA_string_set(&ptr_props, "doc_id", manual_id.value().c_str());
1343 }
1344 }
1345 }
1346
1347 if (but->optype && U.flag & USER_DEVELOPER_UI) {
1348 uiItemO(layout, nullptr, ICON_NONE, "UI_OT_copy_python_command_button");
1349 }
1350
1351 /* perhaps we should move this into (G.debug & G_DEBUG) - campbell */
1352 if (U.flag & USER_DEVELOPER_UI) {
1353 if (ui_block_is_menu(but->block) == false) {
1354 uiItemFullO(layout,
1355 "UI_OT_editsource",
1356 nullptr,
1357 ICON_NONE,
1358 nullptr,
1361 nullptr);
1362 }
1363 }
1364
1365 /* Show header tools for header buttons. */
1366 if (ui_block_is_popup_any(but->block) == false) {
1367 const ARegion *region = CTX_wm_region(C);
1368
1369 if (!region) {
1370 /* skip */
1371 }
1372 else if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
1374 layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, nullptr);
1375 }
1376 else if (region->regiontype == RGN_TYPE_NAV_BAR) {
1377 uiItemMenuF(layout,
1378 IFACE_("Navigation Bar"),
1379 ICON_NONE,
1381 nullptr);
1382 }
1383 else if (region->regiontype == RGN_TYPE_FOOTER) {
1385 layout, IFACE_("Footer"), ICON_NONE, ED_screens_footer_tools_menu_create, nullptr);
1386 }
1387 }
1388
1389 /* UI List item context menu. Scripts can add items to it, by default there's nothing shown. */
1390 const ARegion *region = CTX_wm_region_popup(C) ? CTX_wm_region_popup(C) : CTX_wm_region(C);
1391 const bool is_inside_listbox = ui_list_find_mouse_over(region, event) != nullptr;
1392 const bool is_inside_listrow = is_inside_listbox ?
1393 ui_list_row_find_mouse_over(region, event->xy) != nullptr :
1394 false;
1395 if (is_inside_listrow) {
1396 MenuType *mt = WM_menutype_find("UI_MT_list_item_context_menu", true);
1397 if (mt) {
1398 UI_menutype_draw(C, mt, uiLayoutColumn(layout, false));
1399 }
1400 }
1401
1402 MenuType *mt = WM_menutype_find("UI_MT_button_context_menu", true);
1403 if (mt) {
1404 UI_menutype_draw(C, mt, uiLayoutColumn(layout, false));
1405 }
1406
1407 if (but->context) {
1408 CTX_store_set(C, previous_ctx);
1409 }
1410
1411 return UI_popup_menu_end_or_cancel(C, pup);
1412}
1413
1416/* -------------------------------------------------------------------- */
1421{
1422 bScreen *screen = CTX_wm_screen(C);
1423 const bool has_panel_category = UI_panel_category_is_visible(region);
1424 const bool any_item_visible = has_panel_category;
1425
1426 if (!any_item_visible) {
1427 return;
1428 }
1429 if (panel->type->parent != nullptr) {
1430 return;
1431 }
1432 if (!UI_panel_can_be_pinned(panel)) {
1433 return;
1434 }
1435
1436 PointerRNA ptr = RNA_pointer_create(&screen->id, &RNA_Panel, panel);
1437
1438 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE);
1439 uiLayout *layout = UI_popup_menu_layout(pup);
1440
1441 if (has_panel_category) {
1442 char tmpstr[80];
1443 SNPRINTF(tmpstr, "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift Left Mouse"));
1444 uiItemR(layout, &ptr, "use_pin", UI_ITEM_NONE, tmpstr, ICON_NONE);
1445
1446 /* evil, force shortcut flag */
1447 {
1448 uiBlock *block = uiLayoutGetBlock(layout);
1449 uiBut *but = static_cast<uiBut *>(block->buttons.last);
1450 but->flag |= UI_BUT_HAS_SEP_CHAR;
1451 }
1452 }
1453 UI_popup_menu_end(C, pup);
1454}
1455
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)
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:1227
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:722
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:861
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#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
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:438
#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 STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
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
@ USER_DEVELOPER_UI
#define UI_SCALE_FAC
bUserMenu * ED_screen_user_menu_ensure(bContext *C)
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_Op * ED_screen_user_menu_item_find_operator(ListBase *lb, const wmOperatorType *ot, IDProperty *prop, const char *op_prop_enum, wmOperatorCallContext opcontext)
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_operator(ListBase *lb, const char *ui_name, const wmOperatorType *ot, const IDProperty *prop, const char *op_prop_enum, wmOperatorCallContext opcontext)
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)
ScrArea void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *arg)
void ED_screens_region_flip_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:64
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_INT
Definition RNA_types.hh:66
@ PROP_STRING
Definition RNA_types.hh:68
@ PROP_POINTER
Definition RNA_types.hh:70
PropertySubType
Definition RNA_types.hh:135
@ PROP_DIRPATH
Definition RNA_types.hh:140
@ PROP_FILEPATH
Definition RNA_types.hh:139
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
#define UI_UNIT_Y
#define UI_SEP_CHAR_S
@ UI_EMBOSS
bool UI_panel_can_be_pinned(const Panel *panel)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
@ UI_BLOCK_MOVEMOUSE_QUIT
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
Definition interface.cc:590
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
MenuType * UI_but_menutype_get(const uiBut *but)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const uiStyle *style)
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)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
void uiItemS(uiLayout *layout)
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
#define UI_ITEM_NONE
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, const char *tip)
void uiItemM_ptr(uiLayout *layout, MenuType *mt, const char *name, int icon)
std::optional< std::string > UI_but_online_manual_id(const uiBut *but) ATTR_WARN_UNUSED_RESULT
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
@ UI_DIR_CENTER_Y
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
@ UI_LAYOUT_VERTICAL
PanelType * UI_but_paneltype_get(const uiBut *but)
bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
@ UI_LAYOUT_PANEL
int uiLayoutGetWidth(uiLayout *layout)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void UI_block_direction_set(uiBlock *block, char direction)
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_BUT
@ UI_BTYPE_TAB
@ UI_BTYPE_VIEW_ITEM
@ UI_BTYPE_LABEL
@ UI_BTYPE_SEARCH_MENU
@ UI_BTYPE_IMAGE
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
bContextStore * uiLayoutGetContextStore(uiLayout *layout)
bool UI_but_is_tool(const uiBut *but)
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context)
void UI_but_flag_enable(uiBut *but, int flag)
std::optional< blender::StringRefNull > UI_but_asset_shelf_type_idname_get(const uiBut *but)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
wmOperatorType * UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
@ UI_ITEM_R_IMMEDIATE
@ UI_ITEM_R_FULL_EVENT
@ UI_BUT_ANIMATED
@ UI_BUT_DISABLED
@ UI_BUT_OVERRIDDEN
@ UI_BUT_HAS_SEP_CHAR
@ UI_BUT_DRIVEN
@ UI_BUT_ANIMATED_KEY
@ KM_ANY
Definition WM_types.hh:282
@ KM_PRESS
Definition WM_types.hh:284
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
virtual void build_context_menu(bContext &C, uiLayout &column) const
bool ANIM_driver_can_paste()
Definition drivers.cc:573
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
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:105
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRefNull prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
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)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
bool RNA_property_anim_editable(const PointerRNA *ptr, PropertyRNA *prop_orig)
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(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:1345
Definition DNA_ID.h:413
void * last
bool(* poll)(const bContext *C, MenuType *mt)
PanelType * parent
struct PanelType * type
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
ListBase buttons
MenuType * menu
blender::ui::AbstractViewItem * view_item
wmOperatorCallContext opcontext
std::function< void(bContext &)> apply_func
PropertyRNA * rnaprop
wmOperatorType * optype
eButType type
uiBlock * block
PointerRNA * opptr
uiMenuCreateFunc menu_create_func
const bContextStore * context
std::function< std::string(const uiBut *)> tip_label_func
PointerRNA rnapoin
int xy[2]
Definition WM_types.hh:726
const char * idname
Definition WM_types.hh:992
#define EVT_TYPE_MASK_HOTKEY_INCLUDE
#define ISNDOF_BUTTON(event_type)
#define ISKEYBOARD(event_type)
#define EVT_TYPE_MASK_HOTKEY_EXCLUDE
@ EVT_AKEY
#define EVT_TYPE_MASK_ALL
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
wmKeyMapItem * WM_key_event_operator(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const short include_mask, const short exclude_mask, wmKeyMap **r_keymap)
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:204
std::optional< std::string > WM_key_event_operator_string(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict)
wmKeyMapItem * WM_keymap_add_item(wmKeyMap *keymap, const char *idname, const KeyMapItem_Params *params)
Definition wm_keymap.cc:546
void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
Definition wm_keymap.cc:579
wmKeyMap * WM_keymap_guess_opname(const bContext *C, const char *opname)
MenuType * WM_menutype_find(const char *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)