Blender V5.0
interface_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10
11#include <fmt/format.h>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_armature_types.h"
16#include "DNA_key_types.h"
17#include "DNA_material_types.h"
18#include "DNA_modifier_types.h" /* for handling geometry nodes properties */
19#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
20#include "DNA_screen_types.h"
21
22#include "ANIM_keyframing.hh"
23
24#include "BLI_listbase.h"
25#include "BLI_math_color.h"
26#include "BLI_rect.h"
27#include "BLI_string.h"
28#include "BLI_string_utf8.h"
29
30#include "BLF_api.hh"
31#include "BLT_lang.hh"
32#include "BLT_translation.hh"
33
34#include "BKE_anim_data.hh"
35#include "BKE_context.hh"
36#include "BKE_fcurve.hh"
37#include "BKE_idtype.hh"
38#include "BKE_layer.hh"
39#include "BKE_lib_id.hh"
40#include "BKE_lib_override.hh"
41#include "BKE_lib_remap.hh"
42#include "BKE_library.hh"
43#include "BKE_material.hh"
44#include "BKE_node.hh"
45#include "BKE_report.hh"
46#include "BKE_screen.hh"
47
49
50#include "DEG_depsgraph.hh"
52
53#include "RNA_access.hh"
54#include "RNA_define.hh"
55#include "RNA_path.hh"
56#include "RNA_prototypes.hh"
57
58#include "UI_abstract_view.hh"
59#include "UI_interface.hh"
61
62#include "interface_intern.hh"
63
64#include "WM_api.hh"
65#include "WM_types.hh"
66
67#include "ED_object.hh"
68#include "ED_outliner.hh"
69#include "ED_paint.hh"
70#include "ED_undo.hh"
71
72/* for Copy As Driver */
73#include "ED_keyframing.hh"
74
75/* Only for #UI_OT_editsource. */
76#include "BLI_ghash.h"
77#include "ED_screen.hh"
78
79using namespace blender::ui;
80
81/* -------------------------------------------------------------------- */
95
97{
98 ED_region_do_layout(C, region);
100 ED_region_do_draw(C, region);
102 region->runtime->do_draw = 0;
103}
104
106
107/* -------------------------------------------------------------------- */
110
112{
114 PropertyRNA *prop;
115 int index;
116
117 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
118
119 if (ptr.owner_id && ptr.data && prop) {
120 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
121 UNUSED_VARS(path);
122 return true;
123 }
124 }
125
126 return false;
127}
128
130{
131 Main *bmain = CTX_data_main(C);
133 PropertyRNA *prop;
134 int index;
135 ID *id;
136
137 const bool full_path = RNA_boolean_get(op->ptr, "full_path");
138
139 /* try to create driver using property retrieved from UI */
140 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
141
142 std::optional<std::string> path;
143 if (ptr.owner_id != nullptr) {
144 if (full_path) {
145 if (prop) {
146 path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
147 }
148 else {
150 }
151 }
152 else {
153 const int index_dim = (index != -1 && RNA_property_array_check(prop)) ? 1 : 0;
154 path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, index_dim, index, &id);
155
156 if (!path) {
157 path = RNA_path_from_ID_to_property_index(&ptr, prop, index_dim, index);
158 }
159 }
160
161 if (path) {
162 WM_clipboard_text_set(path->c_str(), false);
163 return OPERATOR_FINISHED;
164 }
165 }
166
167 return OPERATOR_CANCELLED;
168}
169
171{
172 PropertyRNA *prop;
173
174 /* identifiers */
175 ot->name = "Copy Data Path";
176 ot->idname = "UI_OT_copy_data_path_button";
177 ot->description = "Copy the RNA data path for this property to the clipboard";
178
179 /* callbacks */
182
183 /* flags */
184 ot->flag = OPTYPE_REGISTER;
185
186 /* properties */
187 prop = RNA_def_boolean(ot->srna, "full_path", false, "full_path", "Copy full data path");
189}
190
192
193/* -------------------------------------------------------------------- */
196
198{
200 PropertyRNA *prop;
201 int index;
202
203 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
204
205 if (ptr.owner_id && ptr.data && prop &&
207 (index >= 0 || !RNA_property_array_check(prop)))
208 {
209 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
210 UNUSED_VARS(path);
211 return true;
212 }
213 }
214
215 return false;
216}
217
219{
220 Main *bmain = CTX_data_main(C);
222 PropertyRNA *prop;
223 int index;
224
225 /* try to create driver using property retrieved from UI */
226 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
227
228 if (ptr.owner_id && ptr.data && prop) {
229 ID *id;
230 const int dim = RNA_property_array_dimension(&ptr, prop, nullptr);
231 if (const std::optional<std::string> path = RNA_path_from_real_ID_to_property_index(
232 bmain, &ptr, prop, dim, index, &id))
233 {
234 ANIM_copy_as_driver(id, path->c_str(), RNA_property_identifier(prop));
235 return OPERATOR_FINISHED;
236 }
237
238 BKE_reportf(op->reports, RPT_ERROR, "Could not compute a valid data path");
239 return OPERATOR_CANCELLED;
240 }
241
242 return OPERATOR_CANCELLED;
243}
244
246{
247 /* identifiers */
248 ot->name = "Copy as New Driver";
249 ot->idname = "UI_OT_copy_as_driver_button";
250 ot->description =
251 "Create a new driver with this property as input, and copy it to the "
252 "internal clipboard. Use Paste Driver to add it to the target property, "
253 "or Paste Driver Variables to extend an existing driver";
254
255 /* callbacks */
258
259 /* flags */
260 ot->flag = OPTYPE_REGISTER;
261}
262
264
265/* -------------------------------------------------------------------- */
268
270{
272
273 if (but && (but->optype != nullptr)) {
274 return true;
275 }
276
277 return false;
278}
279
281{
283
284 if (but && (but->optype != nullptr)) {
285 /* allocated when needed, the button owns it */
287
288 std::string str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
289
290 WM_clipboard_text_set(str.c_str(), false);
291
292 return OPERATOR_FINISHED;
293 }
294
295 return OPERATOR_CANCELLED;
296}
297
299{
300 /* identifiers */
301 ot->name = "Copy Python Command";
302 ot->idname = "UI_OT_copy_python_command_button";
303 ot->description = "Copy the Python command matching this button";
304
305 /* callbacks */
308
309 /* flags */
310 ot->flag = OPTYPE_REGISTER;
311}
312
314
315/* -------------------------------------------------------------------- */
318
321 PropertyRNA *prop)
322{
323 /* Assign before executing logic in the unlikely event the ID is freed. */
324 const bool is_undo = ptr->owner_id && ID_CHECK_UNDO(ptr->owner_id);
325
326 /* perform updates required for this property */
327 RNA_property_update(C, ptr, prop);
328
329 /* as if we pressed the button */
331
332 /* Since we don't want to undo _all_ edits to settings, eg window
333 * edits on the screen or on operator settings.
334 * it might be better to move undo's inline - campbell */
335 if (is_undo) {
336 /* do nothing, go ahead with undo */
337 return OPERATOR_FINISHED;
338 }
339 return OPERATOR_CANCELLED;
340}
341
344 PropertyRNA *prop)
345{
346 /* Perform updates required for this property. */
347 RNA_property_update(C, ptr, prop);
348
349 /* As if we pressed the button. */
351
352 return OPERATOR_FINISHED;
353}
354
356{
358 PropertyRNA *prop;
359 int index;
360
361 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
362
363 return (ptr.data && prop && RNA_property_editable(&ptr, prop));
364}
365
367{
369 PropertyRNA *prop;
370 int index;
371 const bool all = RNA_boolean_get(op->ptr, "all");
372
373 /* try to reset the nominated setting to its default value */
374 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
375
376 /* if there is a valid property that is editable... */
377 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
378 const int array_index = (all) ? -1 : index;
379 if (RNA_property_reset(&ptr, prop, array_index)) {
380
381 /* Apply auto keyframe when property is successfully reset. */
382 Scene *scene = CTX_data_scene(C);
384 C, scene, &ptr, prop, array_index, scene->r.cfra, true);
385
387 }
388 }
389
390 return OPERATOR_CANCELLED;
391}
392
394{
395 /* identifiers */
396 ot->name = "Reset to Default Value";
397 ot->idname = "UI_OT_reset_default_button";
398 ot->description = "Reset this property's value to its default value";
399
400 /* callbacks */
403
404 /* flags */
405 /* Don't set #OPTYPE_UNDO because #operator_button_property_finish_with_undo
406 * is responsible for the undo push. */
407 ot->flag = OPTYPE_REGISTER;
408
409 /* properties */
411 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
412}
413
415
416/* -------------------------------------------------------------------- */
419
421{
423 PropertyRNA *prop;
424 int index;
425
426 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
427
428 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
429 const PropertyType type = RNA_property_type(prop);
430
431 return RNA_property_is_idprop(prop) && !RNA_property_array_check(prop) &&
432 ELEM(type, PROP_INT, PROP_FLOAT);
433 }
434
435 return false;
436}
437
439{
441 PropertyRNA *prop;
442 int index;
443
444 /* try to reset the nominated setting to its default value */
445 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
446
447 /* if there is a valid property that is editable... */
448 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
449 if (RNA_property_assign_default(&ptr, prop)) {
450 return operator_button_property_finish(C, &ptr, prop);
451 }
452 }
453
454 return OPERATOR_CANCELLED;
455}
456
458{
459 /* identifiers */
460 ot->name = "Assign Value as Default";
461 ot->idname = "UI_OT_assign_default_button";
462 ot->description = "Set this property's current value as the new default";
463
464 /* callbacks */
467
468 /* flags */
469 ot->flag = OPTYPE_UNDO;
470}
471
473
474/* -------------------------------------------------------------------- */
477
479{
481 PropertyRNA *prop;
482 int index;
483
484 /* try to unset the nominated property */
485 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
486
487 /* if there is a valid property that is editable... */
488 if (ptr.data && prop && RNA_property_editable(&ptr, prop) &&
489 /* RNA_property_is_idprop(prop) && */
490 RNA_property_is_set(&ptr, prop))
491 {
492 RNA_property_unset(&ptr, prop);
493 return operator_button_property_finish(C, &ptr, prop);
494 }
495
496 return OPERATOR_CANCELLED;
497}
498
500{
501 /* identifiers */
502 ot->name = "Unset Property";
503 ot->idname = "UI_OT_unset_property_button";
504 ot->description = "Clear the property and use default or generated value in operators";
505
506 /* callbacks */
509
510 /* flags */
511 ot->flag = OPTYPE_UNDO;
512}
513
515
516/* -------------------------------------------------------------------- */
519
521{
523 PropertyRNA *prop;
524 int index;
525
526 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
527
528 const uint override_status = RNA_property_override_library_status(
529 CTX_data_main(C), &ptr, prop, index);
530
531 return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE));
532}
533
535{
537 PropertyRNA *prop;
538 int index;
539 bool created;
540 const bool all = RNA_boolean_get(op->ptr, "all");
541
542 const short operation = LIBOVERRIDE_OP_REPLACE;
543
544 /* try to reset the nominated setting to its default value */
545 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
546
547 BLI_assert(ptr.owner_id != nullptr);
548
549 if (all) {
550 index = -1;
551 }
552
554 CTX_data_main(C), &ptr, prop, operation, index, true, nullptr, &created);
555
556 if (opop == nullptr) {
557 /* Sometimes e.g. RNA cannot generate a path to the given property. */
558 BKE_reportf(op->reports, RPT_WARNING, "Failed to create the override operation");
559 return OPERATOR_CANCELLED;
560 }
561
562 if (!created) {
563 opop->operation = operation;
564 }
565
566 /* Outliner e.g. has to be aware of this change. */
568
569 return operator_button_property_finish(C, &ptr, prop);
570}
571
573{
574 /* identifiers */
575 ot->name = "Add Override";
576 ot->idname = "UI_OT_override_add_button";
577 ot->description = "Create an override operation";
578
579 /* callbacks */
582
583 /* flags */
584 ot->flag = OPTYPE_UNDO;
585
586 /* properties */
587 RNA_def_boolean(ot->srna, "all", true, "All", "Add overrides for all elements of the array");
588}
589
591{
593 PropertyRNA *prop;
594 int index;
595
596 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
597
598 const uint override_status = RNA_property_override_library_status(
599 CTX_data_main(C), &ptr, prop, index);
600
601 return (ptr.data && ptr.owner_id && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN));
602}
603
605{
606 Main *bmain = CTX_data_main(C);
607 PointerRNA ptr, src;
608 PropertyRNA *prop;
609 int index;
610 const bool all = RNA_boolean_get(op->ptr, "all");
611
612 /* try to reset the nominated setting to its default value */
613 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
614
615 ID *id = ptr.owner_id;
617 BLI_assert(oprop != nullptr);
618 BLI_assert(id != nullptr && id->override_library != nullptr);
619
620 /* The source (i.e. linked data) is required to restore values of deleted overrides. */
621 PropertyRNA *src_prop;
623 if (!RNA_path_resolve_property(&id_refptr, oprop->rna_path, &src, &src_prop)) {
624 BLI_assert_msg(0, "Failed to create matching source (linked data) RNA pointer");
625 }
626
627 if (!all && index != -1) {
628 bool is_strict_find;
629 /* Remove override operation for given item,
630 * add singular operations for the other items as needed. */
632 oprop, nullptr, nullptr, {}, {}, index, index, false, &is_strict_find);
633 BLI_assert(opop != nullptr);
634 if (!is_strict_find) {
635 /* No specific override operation, we have to get generic one,
636 * and create item-specific override operations for all but given index,
637 * before removing generic one. */
638 for (int idx = RNA_property_array_length(&ptr, prop); idx--;) {
639 if (idx != index) {
641 oprop, opop->operation, nullptr, nullptr, {}, {}, idx, idx, true, nullptr, nullptr);
642 }
643 }
644 }
646 RNA_property_copy(bmain, &ptr, &src, prop, index);
647 if (BLI_listbase_is_empty(&oprop->operations)) {
649 }
650 }
651 else {
652 /* Just remove whole generic override operation of this property. */
654 RNA_property_copy(bmain, &ptr, &src, prop, -1);
655 }
656
657 /* Outliner e.g. has to be aware of this change. */
659
660 return operator_button_property_finish(C, &ptr, prop);
661}
662
664{
665 /* identifiers */
666 ot->name = "Remove Override";
667 ot->idname = "UI_OT_override_remove_button";
668 ot->description = "Remove an override operation";
669
670 /* callbacks */
673
674 /* flags */
675 ot->flag = OPTYPE_UNDO;
676
677 /* properties */
679 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
680}
681
683 bContext *C, ID **r_owner_id, ID **r_id, PointerRNA *r_owner_ptr, PropertyRNA **r_prop)
684{
685 PointerRNA owner_ptr;
686 PropertyRNA *prop;
688
689 if (owner_ptr.data == nullptr || prop == nullptr) {
690 *r_owner_id = *r_id = nullptr;
691 if (r_owner_ptr != nullptr) {
692 *r_owner_ptr = PointerRNA_NULL;
693 }
694 if (r_prop != nullptr) {
695 *r_prop = nullptr;
696 }
697 return;
698 }
699
700 *r_owner_id = owner_ptr.owner_id;
701 PointerRNA idptr = RNA_property_pointer_get(&owner_ptr, prop);
702 *r_id = static_cast<ID *>(idptr.data);
703 if (r_owner_ptr != nullptr) {
704 *r_owner_ptr = owner_ptr;
705 }
706 if (r_prop != nullptr) {
707 *r_prop = prop;
708 }
709}
710
711static bool override_idtemplate_poll(bContext *C, const bool is_create_op)
712{
713 ID *owner_id, *id;
714 override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
715
716 if (owner_id == nullptr || id == nullptr) {
717 return false;
718 }
719
720 if (ID_IS_PACKED(id)) {
721 return false;
722 }
723
724 if (is_create_op) {
725 if (!ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
726 return false;
727 }
728 return true;
729 }
730
731 /* Reset/Clear operations. */
733 return false;
734 }
735 return true;
736}
737
739{
740 return override_idtemplate_poll(C, true);
741}
742
744{
745 ID *owner_id, *id;
746 PointerRNA owner_ptr;
747 PropertyRNA *prop;
748 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
749 if (ELEM(nullptr, owner_id, id)) {
750 return OPERATOR_CANCELLED;
751 }
752
754 C, CTX_data_main(C), owner_id, id, nullptr);
755
756 if (id_override == nullptr) {
757 return OPERATOR_CANCELLED;
758 }
759
760 /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
761 * to ensure remapping of the owner property from the linked data to the newly created
762 * liboverride (note that in theory this remapping has already been done by code above), but
763 * only in case owner ID was already local ID (override or pure local data).
764 *
765 * Otherwise, owner ID will also have been overridden, and remapped already to use it's
766 * override of the data too. */
767 if (!ID_IS_LINKED(owner_id)) {
768 PointerRNA idptr = RNA_id_pointer_create(id_override);
769 RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
770 }
771 RNA_property_update(C, &owner_ptr, prop);
772
773 /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
774 * used ID, relying on the property update code only is not always enough. */
779
780 return OPERATOR_FINISHED;
781}
782
784{
785 /* identifiers */
786 ot->name = "Make Library Override";
787 ot->idname = "UI_OT_override_idtemplate_make";
788 ot->description =
789 "Create a local override of the selected linked data-block, and its hierarchy of "
790 "dependencies";
791
792 /* callbacks */
795
796 /* flags */
797 ot->flag = OPTYPE_UNDO;
798}
799
801{
802 return override_idtemplate_poll(C, false);
803}
804
806{
807 ID *owner_id, *id;
808 PointerRNA owner_ptr;
809 PropertyRNA *prop;
810 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
811 if (ELEM(nullptr, owner_id, id)) {
812 return OPERATOR_CANCELLED;
813 }
814
816 return OPERATOR_CANCELLED;
817 }
818
820
821 /* `idptr` is re-assigned to owner property to ensure proper updates etc. */
823 RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
824 RNA_property_update(C, &owner_ptr, prop);
825
826 /* No need for 'security' extra tagging here, since this process will never affect the owner ID.
827 */
828
829 return OPERATOR_FINISHED;
830}
831
833{
834 /* identifiers */
835 ot->name = "Reset Library Override";
836 ot->idname = "UI_OT_override_idtemplate_reset";
837 ot->description = "Reset the selected local override to its linked reference values";
838
839 /* callbacks */
842
843 /* flags */
844 ot->flag = OPTYPE_UNDO;
845}
846
848{
849 return override_idtemplate_poll(C, false);
850}
851
853{
854 ID *owner_id, *id;
855 PointerRNA owner_ptr;
856 PropertyRNA *prop;
857 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
858 if (ELEM(nullptr, owner_id, id)) {
859 return OPERATOR_CANCELLED;
860 }
861
862 if (ID_IS_LINKED(id)) {
863 return OPERATOR_CANCELLED;
864 }
865
866 Main *bmain = CTX_data_main(C);
867 ViewLayer *view_layer = CTX_data_view_layer(C);
868 Scene *scene = CTX_data_scene(C);
869 ID *id_new = id;
870
872 id_new = id->override_library->reference;
873 bool do_remap_active = false;
874 BKE_view_layer_synced_ensure(scene, view_layer);
875 if (BKE_view_layer_active_object_get(view_layer) == (Object *)id) {
876 BLI_assert(GS(id->name) == ID_OB);
877 BLI_assert(GS(id_new->name) == ID_OB);
878 do_remap_active = true;
879 }
881 if (do_remap_active) {
882 Object *ref_object = (Object *)id_new;
883 Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
884 if (basact != nullptr) {
885 view_layer->basact = basact;
886 }
888 }
889 BKE_id_delete(bmain, id);
890 }
891 else {
892 BKE_lib_override_library_id_reset(bmain, id, true);
893 }
894
895 /* Here the affected ID may remain the same, or be replaced by its linked reference. In either
896 * case, the owner ID remains unchanged, and remapping is already handled by internal code, so
897 * calling `RNA_property_update` on it is enough to ensure proper notifiers are sent. */
898 RNA_property_update(C, &owner_ptr, prop);
899
900 /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
901 * used ID, relying on the property update code only is not always enough. */
906
907 return OPERATOR_FINISHED;
908}
909
911{
912 /* identifiers */
913 ot->name = "Clear Library Override";
914 ot->idname = "UI_OT_override_idtemplate_clear";
915 ot->description =
916 "Delete the selected local override and relink its usages to the linked data-block if "
917 "possible, else reset it and mark it as non editable";
918
919 /* callbacks */
922
923 /* flags */
924 ot->flag = OPTYPE_UNDO;
925}
926
927static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType * /*mt*/)
928{
929 bContext *C = (bContext *)C_const;
930 ID *owner_id, *id;
931 override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
932
933 if (owner_id == nullptr || id == nullptr) {
934 return false;
935 }
936
937 if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY_REAL(id))) {
938 return false;
939 }
940 return true;
941}
942
943static void override_idtemplate_menu_draw(const bContext * /*C*/, Menu *menu)
944{
945 uiLayout *layout = menu->layout;
946 layout->op("UI_OT_override_idtemplate_make", IFACE_("Make"), ICON_NONE);
947 layout->op("UI_OT_override_idtemplate_reset", IFACE_("Reset"), ICON_NONE);
948 layout->op("UI_OT_override_idtemplate_clear", IFACE_("Clear"), ICON_NONE);
949}
950
952{
953 MenuType *mt;
954
955 mt = MEM_callocN<MenuType>(__func__);
956 STRNCPY_UTF8(mt->idname, "UI_MT_idtemplate_liboverride");
957 STRNCPY_UTF8(mt->label, N_("Library Override"));
960 WM_menutype_add(mt);
961}
962
964
965/* -------------------------------------------------------------------- */
968
969#define NOT_RNA_NULL(assignment) ((assignment).data != nullptr)
970
978{
979 bPoseChannel *pchan = static_cast<bPoseChannel *>(pchan_ptr.data);
980
981 BLI_assert(GS(pchan_ptr.owner_id->name) == ID_OB);
982 Object *object = reinterpret_cast<Object *>(pchan_ptr.owner_id);
983
984 BLI_assert(GS(static_cast<ID *>(object->data)->name) == ID_AR);
985 bArmature *armature = static_cast<bArmature *>(object->data);
986
987 return RNA_pointer_create_discrete(&armature->id, &RNA_Bone, pchan->bone);
988}
989
991{
992 blender::Vector<PointerRNA> lb = CTX_data_collection_get(C, "selected_pose_bones");
993
994 for (PointerRNA &ptr : lb) {
996 }
997
998 *r_lb = std::move(lb);
999}
1000
1003 FModifier *source)
1004{
1005 blender::Vector<PointerRNA> fcurve_links;
1006 fcurve_links = CTX_data_collection_get(C, "selected_editable_fcurves");
1007 if (fcurve_links.is_empty()) {
1008 return;
1009 }
1010 r_lb->clear();
1011 for (const PointerRNA &ptr : fcurve_links) {
1012 const FCurve *fcu = static_cast<const FCurve *>(ptr.data);
1014 if (STREQ(mod->name, source->name) && mod->type == source->type) {
1015 r_lb->append(RNA_pointer_create_discrete(ptr.owner_id, &RNA_FModifier, mod));
1016 /* Since names are unique it is safe to break here. */
1017 break;
1018 }
1019 }
1020 }
1021}
1022
1024{
1025 /* This function chooses to return the selected keyblocks of the owning Key ID.
1026 * The other option would be to return identically named keyblocks from selected objects. I
1027 * (christoph) think that the first case is more useful which is why the function works as it
1028 * does. */
1029 Key *containing_key = reinterpret_cast<Key *>(owner_id_key);
1030 LISTBASE_FOREACH (KeyBlock *, key_block, &containing_key->block) {
1031 /* This does not use the function `shape_key_is_selected` since that would include the active
1032 * shapekey which is not required for this function to work. */
1033 if (key_block->flag & KEYBLOCK_SEL) {
1034 r_lb->append(RNA_pointer_create_discrete(owner_id_key, &RNA_ShapeKey, key_block));
1035 }
1036 }
1037}
1038
1040 PointerRNA *ptr,
1041 PropertyRNA *prop,
1043 bool *r_use_path_from_id,
1044 std::optional<std::string> *r_path)
1045{
1046 *r_use_path_from_id = false;
1047 *r_path = std::nullopt;
1048 /* special case for bone constraints */
1049 const bool is_rna = !RNA_property_is_idprop(prop);
1050 /* Remove links from the collection list which don't contain 'prop'. */
1051 bool ensure_list_items_contain_prop = false;
1052
1053 /* PropertyGroup objects don't have a reference to the struct that actually owns
1054 * them, so it is normally necessary to do a brute force search to find it. This
1055 * handles the search for non-ID owners by using the 'active' reference as a hint
1056 * to preserve efficiency. Only properties defined through RNA are handled, as
1057 * custom properties cannot be assumed to be valid for all instances.
1058 *
1059 * Properties owned by the ID are handled by the 'if (ptr->owner_id)' case below.
1060 */
1061 if (is_rna && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) {
1062 PointerRNA owner_ptr;
1063 std::optional<std::string> idpath;
1064
1065 /* First, check the active PoseBone and PoseBone->Bone. */
1066 if (NOT_RNA_NULL(owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone)))
1067 {
1068 idpath = RNA_path_from_struct_to_idproperty(&owner_ptr,
1069 static_cast<const IDProperty *>(ptr->data));
1070 if (idpath) {
1071 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1072 }
1073 else {
1074 PointerRNA bone_ptr = rnapointer_pchan_to_bone(owner_ptr);
1075 idpath = RNA_path_from_struct_to_idproperty(&bone_ptr,
1076 static_cast<const IDProperty *>(ptr->data));
1077 if (idpath) {
1079 }
1080 }
1081 }
1082
1083 if (!idpath) {
1084 /* Check the active EditBone if in edit mode. */
1085 if (NOT_RNA_NULL(
1086 owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)))
1087 {
1088 idpath = RNA_path_from_struct_to_idproperty(&owner_ptr,
1089 static_cast<const IDProperty *>(ptr->data));
1090 if (idpath) {
1091 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
1092 }
1093 }
1094
1095 /* Add other simple cases here (Node, NodeSocket, Sequence, ViewLayer etc). */
1096 }
1097
1098 if (idpath) {
1099 *r_path = fmt::format("{}.{}", *idpath, RNA_property_identifier(prop));
1100 return true;
1101 }
1102 }
1103
1104 if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
1105 /* Special case when we do this for #edit_bone.lock.
1106 * (if the edit_bone is locked, it is not included in "selected_editable_bones"). */
1107 const char *prop_id = RNA_property_identifier(prop);
1108 if (STREQ(prop_id, "lock")) {
1109 *r_lb = CTX_data_collection_get(C, "selected_bones");
1110 }
1111 else {
1112 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
1113 }
1114 }
1115 else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
1116 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1117 }
1118 else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
1119 /* "selected_bones" or "selected_editable_bones" will only yield anything in Armature Edit
1120 * mode. In other modes, it'll be empty, and the only way to get the selected bones is via
1121 * "selected_pose_bones". */
1123 }
1124 else if (RNA_struct_is_a(ptr->type, &RNA_BoneColor)) {
1125 /* Get the things that own the bone color (bones, pose bones, or edit bones). */
1126 /* First this will be bones, then gets remapped to colors. */
1127 blender::Vector<PointerRNA> list_of_things = {};
1128 switch (GS(ptr->owner_id->name)) {
1129 case ID_OB:
1130 list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
1131 break;
1132 case ID_AR: {
1133 /* Armature-owned bones can be accessed from both edit mode and pose mode.
1134 * - Edit mode: visit selected edit bones.
1135 * - Pose mode: visit the armature bones of selected pose bones.
1136 */
1137 const bArmature *arm = reinterpret_cast<bArmature *>(ptr->owner_id);
1138 if (arm->edbo) {
1139 list_of_things = CTX_data_collection_get(C, "selected_editable_bones");
1140 }
1141 else {
1142 list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
1143 CTX_data_collection_remap_property(list_of_things, "bone");
1144 }
1145 break;
1146 }
1147 default:
1148 printf("BoneColor is unexpectedly owned by %s '%s'\n",
1149 BKE_idtype_idcode_to_name(GS(ptr->owner_id->name)),
1150 ptr->owner_id->name + 2);
1151 BLI_assert_msg(false,
1152 "expected BoneColor to be owned by the Armature "
1153 "(bone & edit bone) or the Object (pose bone)");
1154 return false;
1155 }
1156
1157 /* Remap from some bone to its color, to ensure the items of r_lb are of
1158 * type ptr->type. Since all three structs `bPoseChan`, `Bone`, and
1159 * `EditBone` have the same name for their embedded `BoneColor` struct, this
1160 * code is suitable for all of them. */
1161 CTX_data_collection_remap_property(list_of_things, "color");
1162
1163 *r_lb = list_of_things;
1164 }
1165 else if (RNA_struct_is_a(ptr->type, &RNA_Strip)) {
1166 /* Special case when we do this for 'Strip.lock'.
1167 * (if the strip is locked, it won't be in "selected_editable_strips"). */
1168 const char *prop_id = RNA_property_identifier(prop);
1169 if (STREQ(prop_id, "lock")) {
1170 *r_lb = CTX_data_collection_get(C, "selected_strips");
1171 }
1172 else {
1173 *r_lb = CTX_data_collection_get(C, "selected_editable_strips");
1174 }
1175
1176 if (is_rna) {
1177 /* Account for properties only being available for some sequence types. */
1178 ensure_list_items_contain_prop = true;
1179 }
1180 }
1181 else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
1182 *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
1183 }
1184 else if (RNA_struct_is_a(ptr->type, &RNA_FModifier)) {
1185 FModifier *mod = static_cast<FModifier *>(ptr->data);
1187 }
1188 else if (RNA_struct_is_a(ptr->type, &RNA_Keyframe)) {
1189 *r_lb = CTX_data_collection_get(C, "selected_editable_keyframes");
1190 }
1191 else if (RNA_struct_is_a(ptr->type, &RNA_Action)) {
1192 *r_lb = CTX_data_collection_get(C, "selected_editable_actions");
1193 }
1194 else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
1195 *r_lb = CTX_data_collection_get(C, "selected_nla_strips");
1196 }
1197 else if (RNA_struct_is_a(ptr->type, &RNA_MovieTrackingTrack)) {
1198 *r_lb = CTX_data_collection_get(C, "selected_movieclip_tracks");
1199 }
1200 else if (RNA_struct_is_a(ptr->type, &RNA_ShapeKey)) {
1201 ui_context_selected_key_blocks(ptr->owner_id, r_lb);
1202 }
1203 else if (const std::optional<std::string> path_from_bone =
1204 RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone);
1205 RNA_struct_is_a(ptr->type, &RNA_Constraint) && path_from_bone)
1206 {
1207 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1208 *r_path = path_from_bone;
1209 }
1210 else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
1212 std::optional<std::string> path;
1213 bNode *node = nullptr;
1214
1215 /* Get the node we're editing */
1216 if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
1217 bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
1218 bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data);
1219 node = &blender::bke::node_find_node(*ntree, *sock);
1220 path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node);
1221 if (path) {
1222 /* we're good! */
1223 }
1224 else {
1225 node = nullptr;
1226 }
1227 }
1228 else {
1229 node = static_cast<bNode *>(ptr->data);
1230 }
1231
1232 /* Now filter out non-matching nodes (by idname). */
1233 if (node) {
1234 const blender::StringRef node_idname = node->idname;
1235 lb = CTX_data_collection_get(C, "selected_nodes");
1236 lb.remove_if([&](const PointerRNA &link) {
1237 bNode *node_data = static_cast<bNode *>(link.data);
1238 if (node_data->idname != node_idname) {
1239 return true;
1240 }
1241 return false;
1242 });
1243 }
1244
1245 *r_lb = lb;
1246 *r_path = path;
1247 }
1248 else if (RNA_struct_is_a(ptr->type, &RNA_AssetMetaData)) {
1249 /* Remap from #AssetRepresentation to #AssetMetaData. */
1250 blender::Vector<PointerRNA> list_of_things = CTX_data_collection_get(C, "selected_assets");
1251 CTX_data_collection_remap_property(list_of_things, "metadata");
1252 *r_lb = list_of_things;
1253 }
1254 else if (CTX_wm_space_outliner(C)) {
1255 const ID *id = ptr->owner_id;
1256 if (!(id && (GS(id->name) == ID_OB))) {
1257 return false;
1258 }
1259
1260 ListBase selected_objects = {nullptr};
1261 ED_outliner_selected_objects_get(C, &selected_objects);
1262 LISTBASE_FOREACH (LinkData *, link, &selected_objects) {
1263 Object *ob = static_cast<Object *>(link->data);
1264 r_lb->append(RNA_id_pointer_create(&ob->id));
1265 }
1266 }
1267 else if (ptr->owner_id) {
1268 ID *id = ptr->owner_id;
1269
1270 if (GS(id->name) == ID_OB) {
1271 *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
1272 *r_use_path_from_id = true;
1273 *r_path = RNA_path_from_ID_to_property(ptr, prop);
1274 }
1275 else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
1276 /* check we're using the active object */
1277 const short id_code = GS(id->name);
1278 blender::Vector<PointerRNA> lb = CTX_data_collection_get(C, "selected_editable_objects");
1279 const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
1280
1281 /* de-duplicate obdata */
1282 if (!lb.is_empty()) {
1283 for (const PointerRNA &ob_ptr : lb) {
1284 Object *ob = (Object *)ob_ptr.owner_id;
1285 if (ID *id_data = static_cast<ID *>(ob->data)) {
1286 id_data->tag |= ID_TAG_DOIT;
1287 }
1288 }
1289
1291 for (const PointerRNA &link : lb) {
1292 Object *ob = (Object *)link.owner_id;
1293 ID *id_data = static_cast<ID *>(ob->data);
1294 if ((id_data == nullptr) || (id_data->tag & ID_TAG_DOIT) == 0 ||
1295 !ID_IS_EDITABLE(id_data) || (GS(id_data->name) != id_code))
1296 {
1297 continue;
1298 }
1299 /* Avoid prepending 'data' to the path. */
1300 new_lb.append(RNA_id_pointer_create(id_data));
1301
1302 if (id_data) {
1303 id_data->tag &= ~ID_TAG_DOIT;
1304 }
1305 }
1306
1307 lb = std::move(new_lb);
1308 }
1309
1310 *r_lb = lb;
1311 *r_path = path;
1312 }
1313 else if (GS(id->name) == ID_SCE) {
1314 /* Sequencer's ID is scene :/ */
1315 /* Try to recursively find an RNA_Strip ancestor,
1316 * to handle situations like #41062... */
1317 *r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Strip);
1318 if (r_path->has_value()) {
1319 /* Special case when we do this for 'Strip.lock'.
1320 * (if the strip is locked, it won't be in "selected_editable_strips"). */
1321 const char *prop_id = RNA_property_identifier(prop);
1322 if (is_rna && STREQ(prop_id, "lock")) {
1323 *r_lb = CTX_data_collection_get(C, "selected_strips");
1324 }
1325 else {
1326 *r_lb = CTX_data_collection_get(C, "selected_editable_strips");
1327 }
1328
1329 if (is_rna) {
1330 /* Account for properties only being available for some sequence types. */
1331 ensure_list_items_contain_prop = true;
1332 }
1333 }
1334 }
1335 return r_path->has_value();
1336 }
1337 else {
1338 return false;
1339 }
1340
1341 if (RNA_property_is_idprop(prop)) {
1342 if (!r_path->has_value()) {
1343 *r_path = RNA_path_from_ptr_to_property_index(ptr, prop, 0, -1);
1344 BLI_assert(*r_path);
1345 }
1346 /* Always resolve custom-properties because they can always exist per-item. */
1347 ensure_list_items_contain_prop = true;
1348 }
1349
1350 if (ensure_list_items_contain_prop) {
1351 if (is_rna) {
1352 const char *prop_id = RNA_property_identifier(prop);
1353 r_lb->remove_if([&](const PointerRNA &link) {
1354 if ((ptr->type != link.type) &&
1355 (RNA_struct_type_find_property(link.type, prop_id) != prop))
1356 {
1357 return true;
1358 }
1359 return false;
1360 });
1361 }
1362 else {
1363 const bool prop_is_array = RNA_property_array_check(prop);
1364 const int prop_array_len = prop_is_array ? RNA_property_array_length(ptr, prop) : -1;
1365 const PropertyType prop_type = RNA_property_type(prop);
1366 r_lb->remove_if([&](PointerRNA &link) {
1367 PointerRNA lptr;
1368 PropertyRNA *lprop = nullptr;
1370 &link, r_path->has_value() ? r_path->value().c_str() : nullptr, &lptr, &lprop);
1371
1372 if (lprop == nullptr) {
1373 return true;
1374 }
1375 if (!RNA_property_is_idprop(lprop)) {
1376 return true;
1377 }
1378 if (prop_type != RNA_property_type(lprop)) {
1379 return true;
1380 }
1381 if (prop_is_array != RNA_property_array_check(lprop)) {
1382 return true;
1383 }
1384 if (prop_is_array && (prop_array_len != RNA_property_array_length(&link, lprop))) {
1385 return true;
1386 }
1387 return false;
1388 });
1389 }
1390 }
1391
1392 return true;
1393}
1394
1396 PointerRNA *ptr_link,
1397 PropertyRNA *prop,
1398 const char *path,
1399 bool use_path_from_id,
1400 PointerRNA *r_ptr,
1401 PropertyRNA **r_prop)
1402{
1403 PropertyRNA *lprop;
1404 PointerRNA lptr;
1405
1406 if (ptr_link->data == ptr->data) {
1407 return false;
1408 }
1409
1410 if (use_path_from_id) {
1411 /* Path relative to ID. */
1412 lprop = nullptr;
1413 PointerRNA idptr = RNA_id_pointer_create(ptr_link->owner_id);
1414 RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
1415 }
1416 else if (path) {
1417 /* Path relative to elements from list. */
1418 lprop = nullptr;
1419 RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
1420 }
1421 else {
1423 lptr = *ptr_link;
1424 lprop = prop;
1425 }
1426
1427 if (lptr.data == ptr->data) {
1428 /* The source & destination are the same, so there is nothing to copy. */
1429 return false;
1430 }
1431
1432 /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
1433 * check but we are now more permissive when it comes to ID properties, see below. */
1434 if (lprop == nullptr) {
1435 return false;
1436 }
1437
1438 if (RNA_property_type(lprop) != RNA_property_type(prop)) {
1439 return false;
1440 }
1441
1442 /* Check property pointers matching.
1443 * For ID properties, these pointers match:
1444 * - If the property is API defined on an existing class (and they are equally named).
1445 * - Never for ID properties on specific ID (even if they are equally named).
1446 * - Never for NodesModifierSettings properties (even if they are equally named).
1447 *
1448 * Be permissive on ID properties in the following cases:
1449 * - #NodesModifierSettings properties
1450 * - (special check: only if the node-group matches, since the 'Input_n' properties are name
1451 * based and similar on potentially very different node-groups).
1452 * - ID properties on specific ID
1453 * - (no special check, copying seems OK [even if type does not match -- does not do anything
1454 * then])
1455 */
1456 bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
1457 if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
1458 RNA_struct_is_a(ptr->type, &RNA_NodesModifier))
1459 {
1460 ignore_prop_eq = false;
1461
1462 NodesModifierData *nmd_link = (NodesModifierData *)lptr.data;
1463 NodesModifierData *nmd_src = (NodesModifierData *)ptr->data;
1464 if (nmd_link->node_group == nmd_src->node_group) {
1465 ignore_prop_eq = true;
1466 }
1467 }
1468
1469 if ((lprop != prop) && !ignore_prop_eq) {
1470 return false;
1471 }
1472
1473 if (!RNA_property_editable(&lptr, lprop)) {
1474 return false;
1475 }
1476
1477 if (r_ptr) {
1478 *r_ptr = lptr;
1479 }
1480 if (r_prop) {
1481 *r_prop = lprop;
1482 }
1483
1484 return true;
1485}
1486
1494static bool copy_to_selected_button(bContext *C, bool all, bool poll)
1495{
1496 Main *bmain = CTX_data_main(C);
1497 PointerRNA ptr, lptr;
1498 PropertyRNA *prop, *lprop;
1499 int index;
1500
1501 /* try to reset the nominated setting to its default value */
1502 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1503
1504 /* if there is a valid property that is editable... */
1505 if (ptr.data == nullptr || prop == nullptr) {
1506 return false;
1507 }
1508
1509 bool success = false;
1510 std::optional<std::string> path;
1511 bool use_path_from_id;
1513
1514 if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) {
1515 for (PointerRNA &link : lb) {
1516 if (link.data == ptr.data) {
1517 continue;
1518 }
1519
1521 &link,
1522 prop,
1523 path.has_value() ? path->c_str() : nullptr,
1524 use_path_from_id,
1525 &lptr,
1526 &lprop))
1527 {
1528 continue;
1529 }
1530
1531 if (poll) {
1532 success = true;
1533 break;
1534 }
1535 if (RNA_property_copy(bmain, &lptr, &ptr, prop, (all) ? -1 : index)) {
1536 RNA_property_update(C, &lptr, prop);
1537 success = true;
1538 }
1539 }
1540 }
1541
1542 return success;
1543}
1544
1546{
1547 return copy_to_selected_button(C, false, true);
1548}
1549
1551{
1552 bool success;
1553
1554 const bool all = RNA_boolean_get(op->ptr, "all");
1555
1556 success = copy_to_selected_button(C, all, false);
1557
1558 return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1559}
1560
1562{
1563 /* identifiers */
1564 ot->name = "Copy to Selected";
1565 ot->idname = "UI_OT_copy_to_selected_button";
1566 ot->description =
1567 "Copy the property's value from the active item to the same property of all selected items "
1568 "if the same property exists";
1569
1570 /* callbacks */
1573
1574 /* flags */
1575 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1576
1577 /* properties */
1578 RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
1579}
1580
1582
1583/* -------------------------------------------------------------------- */
1586
1587/* Name-spaced for unit testing. Conceptually these functions should be static
1588 * and not be used outside this source file. But they need to be externally
1589 * accessible to add unit tests for them. */
1591
1593 PointerRNA *ptr, PropertyRNA *prop, const bool get_all, const int index, bool *r_is_array_prop)
1594{
1595 BLI_assert(ptr && prop);
1596
1597 const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
1598 if (!path.has_value()) {
1599 return {};
1600 }
1601
1602 AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
1603 if (!adt) {
1604 return {};
1605 }
1606
1607 blender::Vector<FCurve *> drivers = {};
1608 const bool is_array_prop = RNA_property_array_check(prop);
1609 if (!is_array_prop) {
1610 /* NOTE: by convention Blender assigns 0 as the index for drivers of
1611 * non-array properties, which is why we search for it here. Values > 0 are
1612 * not recognized by Blender's driver system in that case. Values < 0 are
1613 * recognized for driver evaluation, but `BKE_fcurve_find()` unconditionally
1614 * returns nullptr in that case so it wouldn't matter here anyway. */
1615 drivers.append(BKE_fcurve_find(&adt->drivers, path->c_str(), 0));
1616 }
1617 else {
1618 /* For array properties, we always allocate space for all elements of an
1619 * array property, and the unused ones just remain null. */
1620 drivers.resize(RNA_property_array_length(ptr, prop), nullptr);
1621 for (int i = 0; i < drivers.size(); i++) {
1622 if (get_all || i == index) {
1623 drivers[i] = BKE_fcurve_find(&adt->drivers, path->c_str(), i);
1624 }
1625 }
1626 }
1627
1628 /* If we didn't get any drivers to copy, instead of returning a vector of all
1629 * nullptr, return an empty vector for clarity. That way the caller gets
1630 * either a useful result or an empty one. */
1631 bool fetched_at_least_one = false;
1632 for (const FCurve *driver : drivers) {
1633 fetched_at_least_one |= driver != nullptr;
1634 }
1635 if (!fetched_at_least_one) {
1636 return {};
1637 }
1638
1639 if (r_is_array_prop) {
1640 *r_is_array_prop = is_array_prop;
1641 }
1642
1643 return drivers;
1644}
1645
1647 const bool is_array_prop,
1648 PointerRNA *dst_ptr,
1649 PropertyRNA *dst_prop)
1650{
1651 BLI_assert(src_drivers.size() > 0);
1652 BLI_assert(is_array_prop || src_drivers.size() == 1);
1653
1654 /* Get the RNA path and relevant animdata for the property we're copying to. */
1655 const std::optional<std::string> dst_path = RNA_path_from_ID_to_property(dst_ptr, dst_prop);
1656 if (!dst_path.has_value()) {
1657 return 0;
1658 }
1659 AnimData *dst_adt = BKE_animdata_ensure_id(dst_ptr->owner_id);
1660 if (!dst_adt) {
1661 return 0;
1662 }
1663
1664 /* Do the copying. */
1665 int paste_count = 0;
1666 for (int i = 0; i < src_drivers.size(); i++) {
1667 if (!src_drivers[i]) {
1668 continue;
1669 }
1670 const int dst_index = is_array_prop ? i : -1;
1671
1672 /* If it's already animated by something other than a driver, skip. This is
1673 * because Blender's UI assumes that properties are either animated *or*
1674 * driven, and things can get confusing for users otherwise. Additionally,
1675 * no other parts of Blender's UI allow users to (at least easily) add
1676 * drivers on already-animated properties, so this keeps things consistent
1677 * across driver-related operators. */
1678 bool driven;
1679 {
1680 const FCurve *fcu = BKE_fcurve_find_by_rna(
1681 dst_ptr, dst_prop, dst_index, nullptr, nullptr, &driven, nullptr);
1682 if (fcu && !driven) {
1683 continue;
1684 }
1685 }
1686
1687 /* If there's an existing matching driver, remove it first.
1688 *
1689 * TODO: in the context of `copy_driver_to_selected_button()` this has
1690 * quadratic complexity when the drivers are within the same ID, due to this
1691 * being inside of a loop and doing a linear scan of the drivers to find one
1692 * that matches. We should be able to make this more efficient with a
1693 * little cleverness. */
1694 if (driven) {
1695 FCurve *old_driver = BKE_fcurve_find(&dst_adt->drivers, dst_path->c_str(), dst_index);
1696 if (old_driver) {
1697 BLI_remlink(&dst_adt->drivers, old_driver);
1698 BKE_fcurve_free(old_driver);
1699 }
1700 }
1701
1702 /* Create the new driver. */
1703 FCurve *new_driver = BKE_fcurve_copy(src_drivers[i]);
1704 BKE_fcurve_rnapath_set(*new_driver, dst_path.value());
1705 BLI_addtail(&dst_adt->drivers, new_driver);
1706
1707 paste_count++;
1708 }
1709
1710 return paste_count;
1711}
1712
1713} // namespace blender::interface::internal
1714
1736static bool copy_driver_to_selected_button(bContext *C, bool copy_entire_array, const bool poll)
1737{
1738 using namespace blender::interface::internal;
1739
1740 PropertyRNA *prop;
1742 int index;
1743
1744 /* Get the property of the clicked button. */
1745 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1746 if (!ptr.data || !ptr.owner_id || !prop) {
1747 return false;
1748 }
1749 copy_entire_array |= index == -1; /* -1 implies `copy_entire_array` for array properties. */
1750
1751 /* Get the property's driver(s). */
1752 bool is_array_prop = false;
1754 &ptr, prop, copy_entire_array, index, &is_array_prop);
1755 if (src_drivers.is_empty()) {
1756 return false;
1757 }
1758
1759 /* Build the list of properties to copy the driver(s) to, along with relevant
1760 * side data. */
1761 std::optional<std::string> path;
1762 bool use_path_from_id;
1763 blender::Vector<PointerRNA> target_properties;
1765 C, &ptr, prop, &target_properties, &use_path_from_id, &path))
1766 {
1767 return false;
1768 }
1769
1770 /* Copy the driver(s) to the list of target properties. */
1771 int total_copy_count = 0;
1772 for (PointerRNA &target_prop : target_properties) {
1773 if (target_prop.data == ptr.data) {
1774 continue;
1775 }
1776
1777 /* Get the target property and ensure that it's appropriate for adding
1778 * drivers. */
1779 PropertyRNA *dst_prop;
1780 PointerRNA dst_ptr;
1782 &target_prop,
1783 prop,
1784 path.has_value() ? path->c_str() : nullptr,
1785 use_path_from_id,
1786 &dst_ptr,
1787 &dst_prop))
1788 {
1789 continue;
1790 }
1791 if (!RNA_property_driver_editable(&dst_ptr, dst_prop)) {
1792 continue;
1793 }
1794
1795 /* If we're just polling, then we early-out on the first property we would
1796 * be able to copy to. */
1797 if (poll) {
1798 return true;
1799 }
1800
1801 const int paste_count = paste_property_drivers(
1802 src_drivers.as_span(), is_array_prop, &dst_ptr, dst_prop);
1803 if (paste_count == 0) {
1804 continue;
1805 }
1806
1807 RNA_property_update(C, &dst_ptr, dst_prop);
1808 total_copy_count += paste_count;
1809 }
1810
1811 return total_copy_count > 0;
1812}
1813
1815{
1816 return copy_driver_to_selected_button(C, false, true);
1817}
1818
1820{
1821 const bool all = RNA_boolean_get(op->ptr, "all");
1822
1823 if (!copy_driver_to_selected_button(C, all, false)) {
1824 return OPERATOR_CANCELLED;
1825 }
1826
1829 return OPERATOR_FINISHED;
1830}
1831
1833{
1834 /* Identifiers. */
1835 ot->name = "Copy Driver to Selected";
1836 ot->idname = "UI_OT_copy_driver_to_selected_button";
1837 ot->description =
1838 "Copy the property's driver from the active item to the same property "
1839 "of all selected items, if the same property exists";
1840
1841 /* Callbacks. */
1844
1845 /* Flags. */
1846 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1847
1848 /* Properties. */
1850 ot->srna, "all", false, "All", "Copy to selected the drivers of all elements of the array");
1851}
1852
1854
1855/* -------------------------------------------------------------------- */
1858
1860static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
1861{
1862 if (RNA_pointer_is_null(&ptr)) {
1863 return false;
1864 }
1865
1866 /* Verify pointer type. */
1867 char bone_name[MAXBONENAME];
1868 const StructRNA *target_type = nullptr;
1869
1870 if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) {
1871 RNA_string_get(&ptr, "name", bone_name);
1872 if (bone_name[0] != '\0') {
1873 target_type = &RNA_Bone;
1874 }
1875 }
1876 else if (RNA_struct_is_a(ptr.type, &RNA_Object)) {
1877 target_type = &RNA_Object;
1878 }
1879
1880 if (target_type == nullptr) {
1881 return false;
1882 }
1883
1884 /* Find the containing Object. */
1885 const Scene *scene = CTX_data_scene(C);
1886 ViewLayer *view_layer = CTX_data_view_layer(C);
1887 Base *base = nullptr;
1888 const short id_type = GS(ptr.owner_id->name);
1889 if (id_type == ID_OB) {
1890 BKE_view_layer_synced_ensure(scene, view_layer);
1891 base = BKE_view_layer_base_find(view_layer, (Object *)ptr.owner_id);
1892 }
1893 else if (OB_DATA_SUPPORT_ID(id_type)) {
1894 base = blender::ed::object::find_first_by_data_id(scene, view_layer, ptr.owner_id);
1895 }
1896
1897 bool ok = false;
1898 if ((base == nullptr) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) {
1899 /* pass */
1900 }
1901 else if (poll) {
1902 ok = true;
1903 }
1904 else {
1905 /* Make optional. */
1906 const bool reveal_hidden = true;
1907 /* Select and activate the target. */
1908 if (target_type == &RNA_Bone) {
1909 ok = blender::ed::object::jump_to_bone(C, base->object, bone_name, reveal_hidden);
1910 }
1911 else if (target_type == &RNA_Object) {
1912 ok = blender::ed::object::jump_to_object(C, base->object, reveal_hidden);
1913 }
1914 else {
1915 BLI_assert(0);
1916 }
1917 }
1918 return ok;
1919}
1920
1928static bool jump_to_target_button(bContext *C, bool poll)
1929{
1930 PointerRNA ptr, target_ptr;
1931 PropertyRNA *prop;
1932 int index;
1933
1934 const uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1935
1936 /* If there is a valid property... */
1937 if (ptr.data && prop) {
1938 const PropertyType type = RNA_property_type(prop);
1939
1940 /* For pointer properties, use their value directly. */
1941 if (type == PROP_POINTER) {
1942 target_ptr = RNA_property_pointer_get(&ptr, prop);
1943
1944 return jump_to_target_ptr(C, target_ptr, poll);
1945 }
1946 /* For string properties with prop_search, look up the search collection item. */
1947 if (type == PROP_STRING) {
1948 const uiButSearch *search_but = (but->type == ButType::SearchMenu) ? (uiButSearch *)but :
1949 nullptr;
1950
1951 if (search_but && search_but->items_update_fn == ui_rna_collection_search_update_fn) {
1952 uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(search_but->arg);
1953
1954 char str_buf[MAXBONENAME];
1955 char *str_ptr = RNA_property_string_get_alloc(
1956 &ptr, prop, str_buf, sizeof(str_buf), nullptr);
1957
1958 bool found = false;
1959 /* Jump to target only works with search properties currently, not search callbacks yet.
1960 * See ui_but_add_search. */
1961 if (coll_search->search_prop != nullptr) {
1963 &coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
1964 }
1965
1966 if (str_ptr != str_buf) {
1967 MEM_freeN(str_ptr);
1968 }
1969
1970 if (found) {
1971 return jump_to_target_ptr(C, target_ptr, poll);
1972 }
1973 }
1974 }
1975 }
1976
1977 return false;
1978}
1979
1981{
1982 return jump_to_target_button(C, true);
1983}
1984
1986{
1987 const bool success = jump_to_target_button(C, false);
1988
1989 return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1990}
1991
1993{
1994 /* identifiers */
1995 ot->name = "Jump to Target";
1996 ot->idname = "UI_OT_jump_to_target_button";
1997 ot->description = "Switch to the target object or bone";
1998
1999 /* callbacks */
2002
2003 /* flags */
2004 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2005}
2006
2008
2009/* -------------------------------------------------------------------- */
2012
2013#ifdef WITH_PYTHON
2014
2015/* ------------------------------------------------------------------------- */
2016/* EditSource Utility functions and operator,
2017 * NOTE: this includes utility functions and button matching checks. */
2018
2019struct uiEditSourceStore {
2020 uiBut but_orig;
2021 GHash *hash;
2022};
2023
2024struct uiEditSourceButStore {
2025 char py_dbg_fn[FILE_MAX];
2026 int py_dbg_line_number;
2027};
2028
2029/* should only ever be set while the edit source operator is running */
2030static uiEditSourceStore *ui_editsource_info = nullptr;
2031
2033{
2034 return (ui_editsource_info != nullptr);
2035}
2036
2037static void ui_editsource_active_but_set(uiBut *but)
2038{
2039 BLI_assert(ui_editsource_info == nullptr);
2040
2041 ui_editsource_info = MEM_new<uiEditSourceStore>(__func__);
2042 ui_editsource_info->but_orig = *but;
2043
2044 ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
2045}
2046
2047static void ui_editsource_active_but_clear()
2048{
2049 BLI_ghash_free(ui_editsource_info->hash, nullptr, MEM_freeN);
2050 MEM_delete(ui_editsource_info);
2051 ui_editsource_info = nullptr;
2052}
2053
2054static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
2055{
2056# if 0
2057 printf("matching buttons: '%s' == '%s'\n", but_a->drawstr, but_b->drawstr);
2058# endif
2059
2060 /* this just needs to be a 'good-enough' comparison so we can know beyond
2061 * reasonable doubt that these buttons are the same between redraws.
2062 * if this fails it only means edit-source fails - campbell */
2063 if (BLI_rctf_compare(&but_a->rect, &but_b->rect, FLT_EPSILON) && (but_a->type == but_b->type) &&
2064 (but_a->rnaprop == but_b->rnaprop) && (but_a->optype == but_b->optype) &&
2065 (but_a->unit_type == but_b->unit_type) && but_a->drawstr == but_b->drawstr)
2066 {
2067 return true;
2068 }
2069 return false;
2070}
2071
2072extern void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno);
2073
2075{
2076
2077 uiEditSourceButStore *but_store = MEM_callocN<uiEditSourceButStore>(__func__);
2078
2079 const char *fn;
2080 int line_number = -1;
2081
2082# if 0
2083 printf("comparing buttons: '%s' == '%s'\n", but->drawstr, ui_editsource_info->but_orig.drawstr);
2084# endif
2085
2086 PyC_FileAndNum_Safe(&fn, &line_number);
2087
2088 if (line_number != -1) {
2089 STRNCPY(but_store->py_dbg_fn, fn);
2090 but_store->py_dbg_line_number = line_number;
2091 }
2092 else {
2093 but_store->py_dbg_fn[0] = '\0';
2094 but_store->py_dbg_line_number = -1;
2095 }
2096
2097 BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
2098}
2099
2100void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
2101{
2102 uiEditSourceButStore *but_store = static_cast<uiEditSourceButStore *>(
2103 BLI_ghash_lookup(ui_editsource_info->hash, old_but));
2104 if (but_store) {
2105 BLI_ghash_remove(ui_editsource_info->hash, old_but, nullptr, nullptr);
2106 BLI_ghash_insert(ui_editsource_info->hash, new_but, but_store);
2107 }
2108}
2109
2110static wmOperatorStatus editsource_text_edit(bContext *C,
2111 wmOperator * /*op*/,
2112 const char filepath[FILE_MAX],
2113 const int line)
2114{
2115 wmOperatorType *ot = WM_operatortype_find("TEXT_OT_jump_to_file_at_point", true);
2116 PointerRNA op_props;
2117
2119 RNA_string_set(&op_props, "filepath", filepath);
2120 RNA_int_set(&op_props, "line", line - 1);
2121 RNA_int_set(&op_props, "column", 0);
2122
2124 C, ot, blender::wm::OpCallContext::ExecDefault, &op_props, nullptr);
2125 WM_operator_properties_free(&op_props);
2126 return result;
2127}
2128
2129static wmOperatorStatus editsource_exec(bContext *C, wmOperator *op)
2130{
2132
2133 if (but) {
2134 GHashIterator ghi;
2135 uiEditSourceButStore *but_store = nullptr;
2136
2137 ARegion *region = CTX_wm_region(C);
2139
2140 /* needed else the active button does not get tested */
2142
2143 // printf("%s: begin\n", __func__);
2144
2145 /* take care not to return before calling ui_editsource_active_but_clear */
2146 ui_editsource_active_but_set(but);
2147
2148 /* redraw and get active button python info */
2150
2151 /* It's possible the key button referenced in `ui_editsource_info` has been freed.
2152 * This typically happens with popovers but could happen in other situations, see: #140439. */
2153 blender::Set<const uiBut *> valid_buttons_in_region;
2154 LISTBASE_FOREACH (uiBlock *, block_base, &region->runtime->uiblocks) {
2155 uiBlock *block_pair[2] = {block_base, block_base->oldblock};
2156 for (uiBlock *block : blender::Span(block_pair, block_pair[1] ? 2 : 1)) {
2157 for (int i = 0; i < block->buttons.size(); i++) {
2158 const uiBut *but = block->buttons[i].get();
2159 valid_buttons_in_region.add(but);
2160 }
2161 }
2162 }
2163
2164 for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
2165 BLI_ghashIterator_done(&ghi) == false;
2167 {
2168 uiBut *but_key = static_cast<uiBut *>(BLI_ghashIterator_getKey(&ghi));
2169 if (but_key == nullptr) {
2170 continue;
2171 }
2172
2173 if (!valid_buttons_in_region.contains(but_key)) {
2174 continue;
2175 }
2176
2177 if (ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) {
2178 but_store = static_cast<uiEditSourceButStore *>(BLI_ghashIterator_getValue(&ghi));
2179 break;
2180 }
2181 }
2182
2183 if (but_store) {
2184 if (but_store->py_dbg_line_number != -1) {
2185 ret = editsource_text_edit(C, op, but_store->py_dbg_fn, but_store->py_dbg_line_number);
2186 }
2187 else {
2188 BKE_report(
2189 op->reports, RPT_ERROR, "Active button is not from a script, cannot edit source");
2191 }
2192 }
2193 else {
2194 BKE_report(op->reports, RPT_ERROR, "Active button match cannot be found");
2196 }
2197
2198 ui_editsource_active_but_clear();
2199
2200 // printf("%s: end\n", __func__);
2201
2202 return ret;
2203 }
2204
2205 BKE_report(op->reports, RPT_ERROR, "Active button not found");
2206 return OPERATOR_CANCELLED;
2207}
2208
2209static void UI_OT_editsource(wmOperatorType *ot)
2210{
2211 /* identifiers */
2212 ot->name = "Edit Source";
2213 ot->idname = "UI_OT_editsource";
2214 ot->description = "Edit UI source code of the active button";
2215
2216 /* callbacks */
2217 ot->exec = editsource_exec;
2218}
2219
2221
2222#endif /* WITH_PYTHON */
2223
2224/* -------------------------------------------------------------------- */
2227
2229{
2230 BLT_lang_init();
2232 BLT_lang_set(nullptr);
2234 return OPERATOR_FINISHED;
2235}
2236
2238{
2239 /* identifiers */
2240 ot->name = "Reload Translation";
2241 ot->idname = "UI_OT_reloadtranslation";
2242 ot->description = "Force a full reload of UI translation";
2243
2244 /* callbacks */
2245 ot->exec = reloadtranslation_exec;
2246}
2247
2249
2250/* -------------------------------------------------------------------- */
2253
2255{
2256 bScreen *screen = CTX_wm_screen(C);
2257 const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
2258 ARegion *region_prev = CTX_wm_region(C);
2259 ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : nullptr;
2260
2261 if (region == nullptr) {
2262 region = region_prev;
2263 }
2264
2265 if (region == nullptr) {
2266 return OPERATOR_PASS_THROUGH;
2267 }
2268
2269 CTX_wm_region_set(C, region);
2271 CTX_wm_region_set(C, region_prev);
2272
2273 if (but == nullptr) {
2274 return OPERATOR_PASS_THROUGH;
2275 }
2276 if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) {
2277 return OPERATOR_PASS_THROUGH;
2278 }
2279
2280 /* Weak, this is a workaround for 'UI_but_is_tool', which checks the operator type,
2281 * having this avoids a minor drawing glitch. */
2282 void *but_optype = but->optype;
2283
2284 UI_but_execute(C, region, but);
2285
2286 but->optype = static_cast<wmOperatorType *>(but_optype);
2287
2289
2290 return OPERATOR_FINISHED;
2291}
2292
2294{
2295 ot->name = "Press Button";
2296 ot->idname = "UI_OT_button_execute";
2297 ot->description = "Presses active button";
2298
2299 ot->invoke = ui_button_press_invoke;
2300 ot->flag = OPTYPE_INTERNAL;
2301
2302 RNA_def_boolean(ot->srna, "skip_depressed", false, "Skip Depressed", "");
2303}
2304
2306
2307/* -------------------------------------------------------------------- */
2310
2312{
2314
2315 if (but) {
2317 }
2318
2319 return OPERATOR_FINISHED;
2320}
2321
2323{
2324 ot->name = "Clear Button String";
2325 ot->idname = "UI_OT_button_string_clear";
2326 ot->description = "Unsets the text of the active button";
2327
2330 ot->flag = OPTYPE_INTERNAL;
2331}
2332
2334
2335/* -------------------------------------------------------------------- */
2338
2339bool UI_drop_color_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
2340{
2341 /* should only return true for regions that include buttons, for now
2342 * return true always */
2343 if (drag->type == WM_DRAG_COLOR) {
2345 ARegion *region = CTX_wm_region(C);
2346
2348 return true;
2349 }
2350
2351 if (sima && (sima->mode == SI_MODE_PAINT) && sima->image &&
2352 (region && region->regiontype == RGN_TYPE_WINDOW))
2353 {
2354 return true;
2355 }
2356 }
2357
2358 return false;
2359}
2360
2361void UI_drop_color_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
2362{
2363 uiDragColorHandle *drag_info = static_cast<uiDragColorHandle *>(drag->poin);
2364
2365 RNA_float_set_array(drop->ptr, "color", drag_info->color);
2366 RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
2367 RNA_boolean_set(drop->ptr, "has_alpha", drag_info->has_alpha);
2368}
2369
2371{
2372 ARegion *region = CTX_wm_region(C);
2373 uiBut *but = nullptr;
2374
2375 float color[4];
2376 RNA_float_get_array(op->ptr, "color", color);
2377
2378 const bool gamma = RNA_boolean_get(op->ptr, "gamma");
2379 const bool has_alpha = RNA_boolean_get(op->ptr, "has_alpha");
2380
2381 /* find button under mouse, check if it has RNA color property and
2382 * if it does copy the data */
2383 but = ui_region_find_active_but(region);
2384
2385 if (but && but->type == ButType::Color && but->rnaprop) {
2386 if (!has_alpha) {
2387 color[3] = 1.0f;
2388 }
2389
2391 if (!gamma) {
2393 }
2395 RNA_property_update(C, &but->rnapoin, but->rnaprop);
2396 }
2397 else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
2398 if (gamma) {
2400 }
2402 RNA_property_update(C, &but->rnapoin, but->rnaprop);
2403 }
2404
2405 if (UI_but_flag_is_set(but, UI_BUT_UNDO)) {
2407 }
2408 }
2409 else {
2410 if (gamma) {
2412 }
2413
2414 ED_imapaint_bucket_fill(C, color, op, event->mval);
2415 }
2416
2417 ED_region_tag_redraw(region);
2418
2419 return OPERATOR_FINISHED;
2420}
2421
2423{
2424 ot->name = "Drop Color";
2425 ot->idname = "UI_OT_drop_color";
2426 ot->description = "Drop colors to buttons";
2427
2428 ot->invoke = drop_color_invoke;
2430
2431 ot->flag = OPTYPE_INTERNAL;
2432
2434 ot->srna, "color", 4, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
2436 ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected");
2438 ot->srna, "has_alpha", false, "Has Alpha", "The source color contains an Alpha component");
2439}
2440
2442
2443/* -------------------------------------------------------------------- */
2446
2448{
2450 return false;
2451 }
2452
2454 if (!but) {
2455 return false;
2456 }
2457
2458 if (but->flag & UI_BUT_DISABLED) {
2459 return false;
2460 }
2461
2462 return true;
2463}
2464
2466{
2468 std::string str = RNA_string_get(op->ptr, "string");
2469
2470 ui_but_set_string_interactive(C, but, str.c_str());
2471
2472 return OPERATOR_FINISHED;
2473}
2474
2476{
2477 ot->name = "Drop Name";
2478 ot->idname = "UI_OT_drop_name";
2479 ot->description = "Drop name to button";
2480
2481 ot->poll = drop_name_poll;
2482 ot->invoke = drop_name_invoke;
2483 ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
2484
2486 ot->srna, "string", nullptr, 0, "String", "The string value to drop into the button");
2487}
2488
2490
2491/* -------------------------------------------------------------------- */
2494
2496{
2497 const ARegion *region = CTX_wm_region(C);
2498 if (!region) {
2499 return false;
2500 }
2501 const wmWindow *win = CTX_wm_window(C);
2502 const uiList *list = UI_list_find_mouse_over(region, win->eventstate);
2503
2504 return list != nullptr;
2505}
2506
2512{
2513 if (list->filter_flag & UILST_FLT_SHOW) {
2514 /* Nothing to be done. */
2515 return false;
2516 }
2517
2518 list->filter_flag |= UILST_FLT_SHOW;
2519 return true;
2520}
2521
2523 wmOperator * /*op*/,
2524 const wmEvent *event)
2525{
2526 ARegion *region = CTX_wm_region(C);
2527 uiList *list = UI_list_find_mouse_over(region, event);
2528 /* Poll should check. */
2529 BLI_assert(list != nullptr);
2530
2533 }
2534
2535 if (!UI_textbutton_activate_rna(C, region, list, "filter_name")) {
2536 return OPERATOR_CANCELLED;
2537 }
2538
2539 return OPERATOR_FINISHED;
2540}
2541
2543{
2544 ot->name = "List Filter";
2545 ot->idname = "UI_OT_list_start_filter";
2546 ot->description = "Start entering filter text for the list in focus";
2547
2549 ot->poll = ui_list_focused_poll;
2550}
2551
2553
2554/* -------------------------------------------------------------------- */
2557
2559{
2560 const wmWindow *win = CTX_wm_window(C);
2561 if (!(win && win->eventstate)) {
2562 return nullptr;
2563 }
2564
2565 const ARegion *region = CTX_wm_region(C);
2566 if (!region) {
2567 return nullptr;
2568 }
2569 return UI_region_view_find_at(region, win->eventstate->xy, 0);
2570}
2571
2573{
2575 return view != nullptr;
2576}
2577
2579 wmOperator * /*op*/,
2580 const wmEvent *event)
2581{
2582 const ARegion *region = CTX_wm_region(C);
2583 const blender::ui::AbstractView *hovered_view = UI_region_view_find_at(region, event->xy, 0);
2584
2585 if (!hovered_view->begin_filtering(*C)) {
2587 }
2588
2589 return OPERATOR_FINISHED;
2590}
2591
2593{
2594 ot->name = "View Filter";
2595 ot->idname = "UI_OT_view_start_filter";
2596 ot->description = "Start entering filter text for the data-set in focus";
2597
2599 ot->poll = ui_view_focused_poll;
2600
2601 ot->flag = OPTYPE_INTERNAL;
2602}
2603
2605
2606/* -------------------------------------------------------------------- */
2609
2611{
2612 const wmWindow *win = CTX_wm_window(C);
2613 if (!(win && win->eventstate)) {
2614 return false;
2615 }
2616 const ARegion *region = CTX_wm_region(C);
2617 if (region == nullptr) {
2618 return false;
2619 }
2620 return region_views_find_drop_target_at(region, win->eventstate->xy) != nullptr;
2621}
2622
2624{
2625 if (event->custom != EVT_DATA_DRAGDROP) {
2627 }
2628
2629 ARegion *region = CTX_wm_region(C);
2630 std::unique_ptr<DropTargetInterface> drop_target = region_views_find_drop_target_at(region,
2631 event->xy);
2632
2634 *C, *region, *event, *drop_target, *static_cast<const ListBase *>(event->customdata)))
2635 {
2637 }
2638
2639 ED_region_tag_redraw(region);
2640 return OPERATOR_FINISHED;
2641}
2642
2644{
2645 ot->name = "View Drop";
2646 ot->idname = "UI_OT_view_drop";
2647 ot->description = "Drag and drop onto a data-set or item within the data-set";
2648
2649 ot->invoke = ui_view_drop_invoke;
2650 ot->poll = ui_view_drop_poll;
2651
2652 ot->flag = OPTYPE_INTERNAL;
2653}
2654
2656
2657/* -------------------------------------------------------------------- */
2660
2662{
2664 if (!view) {
2665 return false;
2666 }
2667
2668 return view->supports_scrolling();
2669}
2670
2672 wmOperator * /*op*/,
2673 const wmEvent *event)
2674{
2675 ARegion *region = CTX_wm_region(C);
2676 int type = event->type;
2677 bool invert_direction = false;
2678
2679 if (type == MOUSEPAN) {
2680 int dummy_val;
2681 ui_pan_to_scroll(event, &type, &dummy_val);
2682
2683 /* 'ui_pan_to_scroll' gives the absolute direction. */
2684 if (event->flag & WM_EVENT_SCROLL_INVERT) {
2685 invert_direction = true;
2686 }
2687 }
2688
2690 std::optional<ViewScrollDirection> direction =
2691 [type, invert_direction]() -> std::optional<ViewScrollDirection> {
2692 switch (type) {
2693 case WHEELUPMOUSE:
2694 return invert_direction ? ViewScrollDirection::DOWN : ViewScrollDirection::UP;
2695 case WHEELDOWNMOUSE:
2696 return invert_direction ? ViewScrollDirection::UP : ViewScrollDirection::DOWN;
2697 default:
2698 return std::nullopt;
2699 }
2700 }();
2701 if (!direction) {
2702 return OPERATOR_CANCELLED;
2703 }
2704
2705 BLI_assert(view->supports_scrolling());
2706 if (view->is_fully_visible()) {
2707 /* The view does not need scrolling currently, so pass the event through. This allows scrolling
2708 * e.g. the entire region even when hovering a tree-view that supports scrolling generally. */
2709 return OPERATOR_PASS_THROUGH;
2710 }
2711 view->scroll(*direction);
2712
2713 ED_region_tag_redraw(region);
2714 return OPERATOR_FINISHED;
2715}
2716
2718{
2719 ot->name = "View Scroll";
2720 ot->idname = "UI_OT_view_scroll";
2721
2722 ot->invoke = ui_view_scroll_invoke;
2723 ot->poll = ui_view_scroll_poll;
2724
2725 ot->flag = OPTYPE_INTERNAL;
2726}
2727
2729
2730/* -------------------------------------------------------------------- */
2738
2740{
2741 const ARegion *region = CTX_wm_region(C);
2742 if (region == nullptr) {
2743 return false;
2744 }
2746 return active_item != nullptr && UI_view_item_can_rename(*active_item);
2747}
2748
2750{
2751 ARegion *region = CTX_wm_region(C);
2753
2754 UI_view_item_begin_rename(*active_item);
2755 ED_region_tag_redraw(region);
2756
2757 return OPERATOR_FINISHED;
2758}
2759
2761{
2762 ot->name = "Rename View Item";
2763 ot->idname = "UI_OT_view_item_rename";
2764 ot->description = "Rename the active item in the data-set view";
2765
2768 /* Could get a custom tooltip via the `get_description()` callback and another overridable
2769 * function of the view. */
2770
2771 ot->flag = OPTYPE_INTERNAL;
2772}
2773
2775 AbstractViewItem *clicked_item,
2776 const AbstractView &view,
2777 const bool extend,
2778 const bool range_select,
2779 bool wait_to_deselect_others)
2780{
2781 const bool already_selected = clicked_item && clicked_item->is_selected();
2782
2783 if (extend || range_select) {
2784 wait_to_deselect_others = false;
2785 }
2786
2787 if (clicked_item && already_selected && wait_to_deselect_others) {
2789 }
2790
2791 if (!extend) {
2792 view.foreach_view_item([](AbstractViewItem &item) { item.set_selected(false); });
2793 }
2794
2795 if (clicked_item == nullptr) {
2796 /* Only clear selection (if needed). */
2797 return OPERATOR_FINISHED;
2798 }
2799
2800 if (range_select) {
2801 bool is_inside_range = false;
2802 view.foreach_view_item([&](AbstractViewItem &item) {
2803 if (item.is_active() ^ (&item == clicked_item)) {
2804 is_inside_range = !is_inside_range;
2805 /* Select end items from the range. */
2806 item.set_selected(true);
2807 }
2808 if (is_inside_range) {
2809 /* Select items within the range. */
2810 item.set_selected(true);
2811 }
2812 });
2813 return OPERATOR_FINISHED;
2814 }
2815
2816 clicked_item->activate(C);
2817
2818 return OPERATOR_FINISHED;
2819}
2820
2821static std::pair<AbstractView *, AbstractViewItem *> select_operator_view_and_item_find_xy(
2822 const ARegion &region, const wmOperator &op)
2823{
2824 /* Mouse coordinates in window space. */
2825 int window_xy[2];
2826 {
2827 /* Mouse coordinates in region space. */
2828 int region_xy[2];
2829 region_xy[0] = RNA_int_get(op.ptr, "mouse_x");
2830 region_xy[1] = RNA_int_get(op.ptr, "mouse_y");
2831 ui_region_to_window(&region, region_xy[0], region_xy[1], &window_xy[0], &window_xy[1]);
2832 }
2833
2834 AbstractView *view = UI_region_view_find_at(&region, window_xy, 0);
2835 AbstractViewItem *item = UI_region_views_find_item_at(region, window_xy);
2836 BLI_assert(!item || &item->get_view() == view);
2837
2838 return std::make_pair(view, item);
2839}
2840
2842{
2843 ARegion &region = *CTX_wm_region(C);
2844 auto [view, clicked_item] = select_operator_view_and_item_find_xy(region, *op);
2845
2846 if (!view) {
2847 return OPERATOR_CANCELLED;
2848 }
2849
2850 const bool is_multiselect = view->is_multiselect_supported();
2851 const bool extend = RNA_boolean_get(op->ptr, "extend") && is_multiselect;
2852 const bool range_select = RNA_boolean_get(op->ptr, "range_select") && is_multiselect;
2853 const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
2854
2856 *C, clicked_item, *view, extend, range_select, wait_to_deselect_others);
2857
2858 ED_region_tag_redraw(&region);
2859
2860 return status;
2861}
2862
2864 wmOperator *op,
2865 const wmEvent *event)
2866{
2867 const ARegion &region = *CTX_wm_region(C);
2868 const AbstractViewItem *clicked_item = UI_region_views_find_item_at(region, event->xy);
2869
2870 /* Wait with selecting to see if there's a click or drag event, if requested by the view item. */
2871 if (clicked_item && clicked_item->is_select_on_click()) {
2872 RNA_boolean_set(op->ptr, "use_select_on_click", true);
2873 }
2874
2875 return WM_generic_select_invoke(C, op, event);
2876}
2877
2879{
2880 ot->name = "Select View Item";
2881 ot->idname = "UI_OT_view_item_select";
2882 ot->description = "Activate selected view item";
2883
2886 ot->modal = WM_generic_select_modal;
2887 ot->poll = ui_view_focused_poll;
2888
2889 ot->flag = OPTYPE_INTERNAL;
2890
2892 PropertyRNA *prop = RNA_def_boolean(ot->srna, "extend", false, "extend", "Extend Selection");
2894 prop = RNA_def_boolean(ot->srna,
2895 "range_select",
2896 false,
2897 "Range Select",
2898 "Select all between clicked and active items");
2900}
2901
2903 wmOperator * /*op*/,
2904 const wmEvent * /*event*/)
2905{
2907
2908 view->foreach_view_item([&](AbstractViewItem &item) {
2909 if (item.is_active() || item.is_selected()) {
2910 item.delete_item(C);
2911 }
2912 });
2913
2914 return OPERATOR_FINISHED;
2915}
2916
2918{
2919 ot->name = "Delete";
2920 ot->idname = "UI_OT_view_item_delete";
2921 ot->description = "Delete selected list item";
2922
2924 ot->poll = ui_view_focused_poll;
2925
2926 ot->flag = OPTYPE_INTERNAL;
2927}
2928
2929
2930/* -------------------------------------------------------------------- */
2934
2936{
2937 PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
2938 const Object *ob = static_cast<const Object *>(ptr.data);
2939 if (ob == nullptr) {
2940 return false;
2941 }
2942
2943 PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
2944 if (RNA_pointer_is_null(&mat_slot)) {
2945 return false;
2946 }
2947
2948 return true;
2949}
2950
2952{
2953 Main *bmain = CTX_data_main(C);
2954
2956 bmain, op->ptr, ID_MA);
2957 if (ma == nullptr) {
2958 return OPERATOR_CANCELLED;
2959 }
2960
2961 PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
2962 Object *ob = static_cast<Object *>(ptr.data);
2963 BLI_assert(ob);
2964
2965 PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
2966 BLI_assert(mat_slot.data);
2967 const int target_slot = RNA_int_get(&mat_slot, "slot_index") + 1;
2968
2969 /* only drop grease pencil material on grease pencil objects */
2970 if ((ma->gp_style != nullptr) && (ob->type != OB_GREASE_PENCIL)) {
2971 return OPERATOR_CANCELLED;
2972 }
2973
2974 BKE_object_material_assign(bmain, ob, ma, target_slot, BKE_MAT_ASSIGN_USERPREF);
2975
2980
2981 return OPERATOR_FINISHED;
2982}
2983
2985{
2986 ot->name = "Drop Material in Material slots";
2987 ot->description = "Drag material to Material slots in Properties";
2988 ot->idname = "UI_OT_drop_material";
2989
2990 ot->poll = ui_drop_material_poll;
2991 ot->exec = ui_drop_material_exec;
2993
2995}
2996
2998
2999/* -------------------------------------------------------------------- */
3002
3004{
3005 using namespace blender::ui;
3018#ifdef WITH_PYTHON
3019 WM_operatortype_append(UI_OT_editsource);
3020#endif
3024
3026
3033
3040
3041 /* external */
3050}
3051
3053{
3054 WM_keymap_ensure(keyconf, "User Interface", SPACE_EMPTY, RGN_TYPE_WINDOW);
3055
3056 eyedropper_modal_keymap(keyconf);
3058}
3059
Functions to insert, delete or modify keyframes.
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:97
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:83
blender::Vector< PointerRNA > CTX_data_collection_get(const bContext *C, const char *member)
PointerRNA CTX_data_pointer_get_type_silent(const bContext *C, const char *member, StructRNA *type)
SpaceImage * CTX_wm_space_image(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
SpaceOutliner * CTX_wm_space_outliner(const bContext *C)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
void CTX_data_collection_remap_property(blender::MutableSpan< PointerRNA > collection_pointers, const char *propname)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
FCurve * BKE_fcurve_copy(const FCurve *fcu)
FCurve * BKE_fcurve_find(ListBase *list, const char rna_path[], int array_index)
FCurve * BKE_fcurve_find_by_rna(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **r_adt, bAction **r_action, bool *r_driven, bool *r_special)
void BKE_fcurve_rnapath_set(FCurve &fcu, blender::StringRef rna_path)
void BKE_fcurve_free(FCurve *fcu)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:164
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
void BKE_lib_override_library_property_operation_delete(IDOverrideLibraryProperty *liboverride_property, IDOverrideLibraryPropertyOperation *liboverride_property_operation)
IDOverrideLibraryPropertyOperation * BKE_lib_override_library_property_operation_get(IDOverrideLibraryProperty *liboverride_property, short operation, const char *subitem_refname, const char *subitem_locname, const std::optional< ID * > &subitem_refid, const std::optional< ID * > &subitem_locid, int subitem_refindex, int subitem_locindex, bool strict, bool *r_strict, bool *r_created)
IDOverrideLibraryPropertyOperation * BKE_lib_override_library_property_operation_find(IDOverrideLibraryProperty *liboverride_property, const char *subitem_refname, const char *subitem_locname, const std::optional< const ID * > &subitem_refid, const std::optional< const ID * > &subitem_locid, int subitem_refindex, int subitem_locindex, bool strict, bool *r_strict)
void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root, bool do_reset_system_override)
bool BKE_lib_override_library_is_hierarchy_leaf(Main *bmain, ID *id)
void BKE_lib_override_library_property_delete(IDOverrideLibrary *liboverride, IDOverrideLibraryProperty *liboverride_property)
void void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, int remap_flags) ATTR_NONNULL(1
@ ID_REMAP_SKIP_INDIRECT_USAGE
General operations, lookup, etc. for materials.
@ BKE_MAT_ASSIGN_USERPREF
void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
ARegion * BKE_screen_find_region_xy(const bScreen *screen, int regiontype, const int xy[2]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void BLF_cache_clear()
Definition blf.cc:98
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
struct GHash GHash
Definition BLI_ghash.h:39
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:295
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition BLI_ghash.cc:911
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
Definition BLI_ghash.cc:895
BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:307
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
#define FILE_MAX
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, float limit)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define STRNCPY_UTF8(dst, src)
unsigned int uint
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define ELEM(...)
#define STREQ(a, b)
void BLT_lang_set(const char *)
Definition blt_lang.cc:250
void BLT_lang_init()
Definition blt_lang.cc:192
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
#define ID_IS_PACKED(_id)
Definition DNA_ID.h:700
@ ID_TAG_DOIT
Definition DNA_ID.h:1036
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
@ ID_RECALC_SELECT
Definition DNA_ID.h:1101
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1104
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:723
#define ID_CHECK_UNDO(id)
Definition DNA_ID.h:683
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ LIBOVERRIDE_OP_REPLACE
Definition DNA_ID.h:230
@ ID_AR
@ ID_SCE
@ ID_MA
@ ID_OB
#define MAXBONENAME
@ KEYBLOCK_SEL
Object is a sort of wrapper for general info.
#define OB_DATA_SUPPORT_ID(_id_type)
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ UILST_FLT_SHOW
@ RGN_TYPE_WINDOW
#define RGN_TYPE_ANY
@ SPACE_EMPTY
@ SI_MODE_PAINT
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
void ED_imapaint_bucket_fill(bContext *C, const float color[3], wmOperator *op, const int mouse[2])
bool ED_operator_regionactive(bContext *C)
void ED_region_do_layout(bContext *C, ARegion *region)
Definition area.cc:456
void ED_region_do_draw(bContext *C, ARegion *region)
Definition area.cc:479
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:98
static AppView * view
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
Read Guarded memory(de)allocation.
@ RNA_OVERRIDE_STATUS_OVERRIDABLE
@ RNA_OVERRIDE_STATUS_OVERRIDDEN
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
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_COLOR
Definition RNA_types.hh:260
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:272
#define C
Definition RandGen.cpp:29
bool UI_view_item_can_rename(const blender::ui::AbstractViewItem &item)
bool UI_textbutton_activate_rna(const bContext *C, ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
uiList * UI_list_find_mouse_over(const ARegion *region, const wmEvent *event)
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
blender::ui::AbstractView * UI_region_view_find_at(const ARegion *region, const int xy[2], int pad)
bool UI_editsource_enable_check()
void UI_reinit_font()
uiBut * UI_context_active_but_get(const bContext *C)
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
void UI_but_execute(const bContext *C, ARegion *region, uiBut *but)
void UI_view_item_begin_rename(blender::ui::AbstractViewItem &item)
void UI_editsource_active_but_test(uiBut *but)
blender::ui::AbstractViewItem * UI_region_views_find_active_item(const ARegion *region)
uiBut * UI_context_active_but_prop_get(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
uiBut * UI_but_active_drop_name_button(const bContext *C)
uiBut * UI_context_active_but_get_respect_popup(const bContext *C)
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
void UI_context_active_but_prop_handle(bContext *C, bool handle_undo)
bool UI_but_active_drop_color(bContext *C)
void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen)
bool UI_but_flag_is_set(uiBut *but, int flag)
blender::ui::AbstractViewItem * UI_region_views_find_item_at(const ARegion &region, const int xy[2])
#define NC_WINDOW
Definition WM_types.hh:375
@ WM_EVENT_SCROLL_INVERT
Definition WM_types.hh:677
#define NC_WM
Definition WM_types.hh:374
#define NC_ANIMATION
Definition WM_types.hh:388
@ WM_DRAG_COLOR
Definition WM_types.hh:1218
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:419
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_KEYFRAME_PROP
Definition WM_types.hh:495
#define NC_MATERIAL
Definition WM_types.hh:380
#define ND_OB_SHADING
Definition WM_types.hh:457
#define ND_SPACE_VIEW3D
Definition WM_types.hh:528
#define NC_OBJECT
Definition WM_types.hh:379
#define ND_SHADING_LINKS
Definition WM_types.hh:479
#define NC_SPACE
Definition WM_types.hh:392
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:252
int64_t size() const
int64_t remove_if(Predicate &&predicate)
void append(const T &value)
bool is_empty() const
void resize(const int64_t new_size)
Span< T > as_span() const
virtual void delete_item(bContext *C)
virtual void set_selected(const bool select)
virtual bool begin_filtering(const bContext &C) const
void ANIM_copy_as_driver(ID *target_id, const char *target_path, const char *var_name)
Definition drivers.cc:767
void UI_OT_eyedropper_color(wmOperatorType *ot)
void UI_OT_eyedropper_id(wmOperatorType *ot)
void UI_OT_eyedropper_depth(wmOperatorType *ot)
void UI_OT_eyedropper_driver(wmOperatorType *ot)
void UI_OT_eyedropper_grease_pencil_color(wmOperatorType *ot)
#define str(s)
#define GS(x)
#define printf(...)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
bool all(VecOp< bool, D >) RET
void ui_region_to_window(const ARegion *region, int *x, int *y)
Definition interface.cc:261
static bool ui_drop_material_poll(bContext *C, wmDrag *drag, const wmEvent *)
static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
wmKeyMap * eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
wmKeyMap * eyedropper_modal_keymap(wmKeyConfig *keyconf)
void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
ID * ui_template_id_liboverride_hierarchy_make(bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
bool ui_jump_to_target_button_poll(bContext *C)
uiBut * ui_region_find_active_but(ARegion *region) ATTR_WARN_UNUSED_RESULT
@ UI_SELECT_DRAW
@ UI_SELECT
void ui_rna_collection_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first)
static wmOperatorStatus ui_drop_material_exec(bContext *C, wmOperator *op)
static wmOperatorStatus drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus copy_to_selected_button_exec(bContext *C, wmOperator *op)
static bool ui_list_unhide_filter_options(uiList *list)
static wmOperatorStatus ui_view_item_select_exec(bContext *C, wmOperator *op)
static void UI_OT_override_idtemplate_reset(wmOperatorType *ot)
static void override_idtemplate_ids_get(bContext *C, ID **r_owner_id, ID **r_id, PointerRNA *r_owner_ptr, PropertyRNA **r_prop)
static void UI_OT_unset_property_button(wmOperatorType *ot)
static wmOperatorStatus reloadtranslation_exec(bContext *, wmOperator *)
static bool ui_view_focused_poll(bContext *C)
static wmOperatorStatus ui_view_item_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus override_remove_button_exec(bContext *C, wmOperator *op)
static wmOperatorStatus ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool ui_list_focused_poll(bContext *C)
static void UI_OT_button_execute(wmOperatorType *ot)
static bool override_remove_button_poll(bContext *C)
static bool ui_view_drop_poll(bContext *C)
static void ui_region_redraw_immediately(bContext *C, ARegion *region)
static wmOperatorStatus jump_to_target_button_exec(bContext *C, wmOperator *)
static PointerRNA rnapointer_pchan_to_bone(const PointerRNA &pchan_ptr)
static wmOperatorStatus operator_button_property_finish(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
static wmOperatorStatus copy_as_driver_button_exec(bContext *C, wmOperator *op)
static bool reset_default_button_poll(bContext *C)
static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType *)
static bool copy_driver_to_selected_button_poll(bContext *C)
static void UI_OT_copy_data_path_button(wmOperatorType *ot)
static void UI_OT_reloadtranslation(wmOperatorType *ot)
static std::pair< AbstractView *, AbstractViewItem * > select_operator_view_and_item_find_xy(const ARegion &region, const wmOperator &op)
bool ui_jump_to_target_button_poll(bContext *C)
static wmOperatorStatus operator_button_property_finish_with_undo(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
static wmOperatorStatus ui_view_item_rename_exec(bContext *C, wmOperator *)
static bool copy_data_path_button_poll(bContext *C)
static void UI_OT_copy_python_command_button(wmOperatorType *ot)
static void UI_OT_assign_default_button(wmOperatorType *ot)
static bool ui_view_scroll_poll(bContext *C)
static wmOperatorStatus override_idtemplate_make_exec(bContext *C, wmOperator *)
static void UI_OT_override_idtemplate_clear(wmOperatorType *ot)
static wmOperatorStatus override_idtemplate_clear_exec(bContext *C, wmOperator *)
void ED_operatortypes_ui()
bool UI_drop_color_poll(bContext *C, wmDrag *drag, const wmEvent *)
static void UI_OT_list_start_filter(wmOperatorType *ot)
static bool copy_driver_to_selected_button(bContext *C, bool copy_entire_array, const bool poll)
static bool copy_to_selected_button_poll(bContext *C)
static wmOperatorStatus reset_default_button_exec(bContext *C, wmOperator *op)
static wmOperatorStatus button_string_clear_exec(bContext *C, wmOperator *)
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
void UI_drop_color_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static AbstractView * get_view_focused(bContext *C)
static void UI_OT_view_start_filter(wmOperatorType *ot)
static void UI_OT_jump_to_target_button(wmOperatorType *ot)
static void UI_OT_drop_name(wmOperatorType *ot)
static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
static wmOperatorStatus ui_view_drop_invoke(bContext *C, wmOperator *, const wmEvent *event)
static wmOperatorStatus ui_view_item_delete_invoke(bContext *C, wmOperator *, const wmEvent *)
static void UI_OT_copy_driver_to_selected_button(wmOperatorType *ot)
static wmOperatorStatus override_add_button_exec(bContext *C, wmOperator *op)
static void UI_OT_override_add_button(wmOperatorType *ot)
static void override_idtemplate_menu_draw(const bContext *, Menu *menu)
static void UI_OT_drop_material(wmOperatorType *ot)
static void UI_OT_view_scroll(wmOperatorType *ot)
static bool override_idtemplate_reset_poll(bContext *C)
static wmOperatorStatus override_idtemplate_reset_exec(bContext *C, wmOperator *)
static bool jump_to_target_button(bContext *C, bool poll)
static void UI_OT_override_remove_button(wmOperatorType *ot)
static bool override_add_button_poll(bContext *C)
static void UI_OT_button_string_clear(wmOperatorType *ot)
static bool drop_name_poll(bContext *C)
bool UI_context_copy_to_selected_list(bContext *C, PointerRNA *ptr, PropertyRNA *prop, blender::Vector< PointerRNA > *r_lb, bool *r_use_path_from_id, std::optional< std::string > *r_path)
#define NOT_RNA_NULL(assignment)
static bool copy_python_command_button_poll(bContext *C)
static wmOperatorStatus copy_driver_to_selected_button_exec(bContext *C, wmOperator *op)
static wmOperatorStatus copy_python_command_button_exec(bContext *C, wmOperator *)
static void UI_OT_reset_default_button(wmOperatorType *ot)
static void UI_OT_view_item_select(wmOperatorType *ot)
static wmOperatorStatus unset_property_button_exec(bContext *C, wmOperator *)
void ED_keymap_ui(wmKeyConfig *keyconf)
User Interface Keymap.
static void UI_OT_override_idtemplate_make(wmOperatorType *ot)
static wmOperatorStatus ui_list_start_filter_invoke(bContext *C, wmOperator *, const wmEvent *event)
static bool assign_default_button_poll(bContext *C)
static void UI_OT_view_item_delete(wmOperatorType *ot)
static void UI_OT_view_drop(wmOperatorType *ot)
static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
static bool override_idtemplate_clear_poll(bContext *C)
static wmOperatorStatus ui_view_start_filter_invoke(bContext *C, wmOperator *, const wmEvent *event)
static void ui_context_fcurve_modifiers_via_fcurve(bContext *C, blender::Vector< PointerRNA > *r_lb, FModifier *source)
static wmOperatorStatus ui_view_scroll_invoke(bContext *C, wmOperator *, const wmEvent *event)
static bool ui_drop_material_poll(bContext *C)
static wmOperatorStatus assign_default_button_exec(bContext *C, wmOperator *)
static bool copy_as_driver_button_poll(bContext *C)
static wmOperatorStatus view_item_click_select(bContext &C, AbstractViewItem *clicked_item, const AbstractView &view, const bool extend, const bool range_select, bool wait_to_deselect_others)
static wmOperatorStatus drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void override_idtemplate_menu()
static void UI_OT_drop_color(wmOperatorType *ot)
bool UI_context_copy_to_selected_check(PointerRNA *ptr, PointerRNA *ptr_link, PropertyRNA *prop, const char *path, bool use_path_from_id, PointerRNA *r_ptr, PropertyRNA **r_prop)
static bool ui_view_item_rename_poll(bContext *C)
static void UI_OT_view_item_rename(wmOperatorType *ot)
static bool override_idtemplate_make_poll(bContext *C)
static wmOperatorStatus copy_data_path_button_exec(bContext *C, wmOperator *op)
static bool override_idtemplate_poll(bContext *C, const bool is_create_op)
static void ui_context_selected_key_blocks(ID *owner_id_key, blender::Vector< PointerRNA > *r_lb)
static void ui_context_selected_bones_via_pose(bContext *C, blender::Vector< PointerRNA > *r_lb)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
bNode & node_find_node(bNodeTree &ntree, bNodeSocket &socket)
Definition node.cc:3281
bool jump_to_object(bContext *C, Object *ob, bool reveal_hidden)
Base * find_first_by_data_id(const Scene *scene, ViewLayer *view_layer, ID *id)
bool jump_to_bone(bContext *C, Object *ob, const char *bone_name, bool reveal_hidden)
blender::Vector< FCurve * > get_property_drivers(PointerRNA *ptr, PropertyRNA *prop, bool get_all, int index, bool *r_is_array_prop)
int paste_property_drivers(blender::Span< FCurve * > src_drivers, bool is_array_prop, PointerRNA *dst_ptr, PropertyRNA *dst_prop)
void UI_OT_eyedropper_colorramp(wmOperatorType *ot)
void UI_OT_eyedropper_colorramp_point(wmOperatorType *ot)
bool drop_target_apply_drop(bContext &C, const ARegion &region, const wmEvent &event, const DropTargetInterface &drop_target, const ListBase &drags)
void UI_OT_eyedropper_bone(wmOperatorType *ot)
std::unique_ptr< DropTargetInterface > region_views_find_drop_target_at(const ARegion *region, const int xy[2])
#define hash
Definition noise_c.cc:154
void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno)
const int status
return ret
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
bool RNA_property_array_check(PropertyRNA *prop)
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
PropertyType RNA_property_type(PropertyRNA *prop)
const PointerRNA PointerRNA_NULL
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_ui_name(const PropertyRNA *prop, const PointerRNA *ptr)
void RNA_property_float_set_array_at_most(PointerRNA *ptr, PropertyRNA *prop, const float *values, int values_num)
int RNA_int_get(PointerRNA *ptr, const char *name)
int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
std::string RNA_string_get(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_is_idprop(const PropertyRNA *prop)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
bool RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr)
bool RNA_property_driver_editable(const PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
IDOverrideLibraryPropertyOperation * RNA_property_override_property_operation_get(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index, const bool strict, bool *r_strict, bool *r_created)
IDOverrideLibraryProperty * RNA_property_override_property_find(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, ID **r_owner_id)
eRNAOverrideStatus RNA_property_override_library_status(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const int index)
bool RNA_property_copy(Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float_color(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
StructRNA RNA_PropertyGroup
std::optional< std::string > RNA_path_from_struct_to_idproperty(PointerRNA *ptr, const IDProperty *needle)
Definition rna_path.cc:920
std::optional< std::string > RNA_path_from_real_ID_to_property_index(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, ID **r_real_id)
Definition rna_path.cc:1178
std::optional< std::string > RNA_path_full_property_py_ex(const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
Definition rna_path.cc:1283
std::optional< std::string > RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, PropertyRNA *prop, const StructRNA *type)
Definition rna_path.cc:1196
std::optional< std::string > RNA_path_full_struct_py(const PointerRNA *ptr)
Definition rna_path.cc:1267
std::optional< std::string > RNA_path_from_ID_to_property_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
Definition rna_path.cc:1156
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1173
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:560
std::string RNA_path_from_ptr_to_property_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
Definition rna_path.cc:1148
#define FLT_MAX
Definition stdcycles.h:14
ARegionRuntimeHandle * runtime
ListBase drivers
struct Object * object
ListBase modifiers
char name[64]
struct ID * reference
Definition DNA_ID.h:334
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
char name[258]
Definition DNA_ID.h:432
IDOverrideLibrary * override_library
Definition DNA_ID.h:494
ListBase block
struct MaterialGPencilStyle * gp_style
char label[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, MenuType *mt)
char idname[BKE_ST_MAXNAME]
void(* draw)(const bContext *C, Menu *menu)
uiLayout * layout
ustring name
Definition graph/node.h:177
struct bNodeTree * node_group
ID * owner_id
Definition RNA_types.hh:51
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
struct RenderData r
struct Image * image
struct Base * basact
ListBase * edbo
char idname[64]
struct Bone * bone
uiButSearchUpdateFn items_update_fn
PropertyRNA * rnaprop
wmOperatorType * optype
ButType type
uchar unit_type
std::string drawstr
PointerRNA rnapoin
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
eWM_DragDataType type
Definition WM_types.hh:1331
void * poin
Definition WM_types.hh:1332
PointerRNA * ptr
Definition WM_types.hh:1420
short custom
Definition WM_types.hh:793
int xy[2]
Definition WM_types.hh:761
int mval[2]
Definition WM_types.hh:763
eWM_EventFlag flag
Definition WM_types.hh:788
void * customdata
Definition WM_types.hh:807
struct ReportList * reports
struct PointerRNA * ptr
struct wmEvent * eventstate
i
Definition text_draw.cc:230
#define N_(msgid)
void WM_draw_region_viewport_unbind(ARegion *region)
Definition wm_draw.cc:1731
void WM_draw_region_viewport_bind(ARegion *region)
Definition wm_draw.cc:1726
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_event_add_mousemove(wmWindow *win)
@ EVT_DATA_DRAGDROP
@ MOUSEPAN
@ WHEELUPMOUSE
@ WHEELDOWNMOUSE
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:895
bool WM_menutype_add(MenuType *mt)
void WM_operator_properties_generic_select(wmOperatorType *ot)
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
wmOperatorStatus WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
std::string WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args, wmOperatorType *ot, PointerRNA *opptr)
wmOperatorStatus WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_clipboard_text_set(const char *buf, bool selection)