Blender V4.3
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
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_material_types.h"
17#include "DNA_modifier_types.h" /* for handling geometry nodes properties */
18#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
19#include "DNA_screen_types.h"
20
21#include "BLI_blenlib.h"
22#include "BLI_math_color.h"
23
24#include "BLF_api.hh"
25#include "BLT_lang.hh"
26#include "BLT_translation.hh"
27
28#include "BKE_anim_data.hh"
29#include "BKE_context.hh"
30#include "BKE_fcurve.hh"
31#include "BKE_idtype.hh"
32#include "BKE_layer.hh"
33#include "BKE_lib_id.hh"
34#include "BKE_lib_override.hh"
35#include "BKE_lib_remap.hh"
36#include "BKE_material.h"
37#include "BKE_node.hh"
38#include "BKE_report.hh"
39#include "BKE_screen.hh"
40
42
43#include "DEG_depsgraph.hh"
45
46#include "RNA_access.hh"
47#include "RNA_define.hh"
48#include "RNA_path.hh"
49#include "RNA_prototypes.hh"
50
51#include "UI_abstract_view.hh"
52#include "UI_interface.hh"
53
54#include "interface_intern.hh"
55
56#include "WM_api.hh"
57#include "WM_types.hh"
58
59#include "ED_object.hh"
60#include "ED_paint.hh"
61#include "ED_undo.hh"
62
63/* for Copy As Driver */
64#include "ED_keyframing.hh"
65
66/* only for UI_OT_editsource */
67#include "BLI_ghash.h"
68#include "ED_screen.hh"
69
70using namespace blender::ui;
71
72/* -------------------------------------------------------------------- */
88{
89 ED_region_do_layout(C, region);
91 ED_region_do_draw(C, region);
93 region->do_draw = 0;
94}
95
98/* -------------------------------------------------------------------- */
103{
105 PropertyRNA *prop;
106 int index;
107
108 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
109
110 if (ptr.owner_id && ptr.data && prop) {
111 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
112 UNUSED_VARS(path);
113 return true;
114 }
115 }
116
117 return false;
118}
119
121{
122 Main *bmain = CTX_data_main(C);
124 PropertyRNA *prop;
125 int index;
126 ID *id;
127
128 const bool full_path = RNA_boolean_get(op->ptr, "full_path");
129
130 /* try to create driver using property retrieved from UI */
131 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
132
133 std::optional<std::string> path;
134 if (ptr.owner_id != nullptr) {
135 if (full_path) {
136 if (prop) {
137 path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
138 }
139 else {
141 }
142 }
143 else {
144 const int index_dim = (index != -1 && RNA_property_array_check(prop)) ? 1 : 0;
145 path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, index_dim, index, &id);
146
147 if (!path) {
148 path = RNA_path_from_ID_to_property_index(&ptr, prop, index_dim, index);
149 }
150 }
151
152 if (path) {
153 WM_clipboard_text_set(path->c_str(), false);
154 return OPERATOR_FINISHED;
155 }
156 }
157
158 return OPERATOR_CANCELLED;
159}
160
162{
163 PropertyRNA *prop;
164
165 /* identifiers */
166 ot->name = "Copy Data Path";
167 ot->idname = "UI_OT_copy_data_path_button";
168 ot->description = "Copy the RNA data path for this property to the clipboard";
169
170 /* callbacks */
173
174 /* flags */
176
177 /* properties */
178 prop = RNA_def_boolean(ot->srna, "full_path", false, "full_path", "Copy full data path");
180}
181
184/* -------------------------------------------------------------------- */
189{
191 PropertyRNA *prop;
192 int index;
193
194 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
195
196 if (ptr.owner_id && ptr.data && prop &&
198 (index >= 0 || !RNA_property_array_check(prop)))
199 {
200 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
201 UNUSED_VARS(path);
202 return true;
203 }
204 }
205
206 return false;
207}
208
210{
211 Main *bmain = CTX_data_main(C);
213 PropertyRNA *prop;
214 int index;
215
216 /* try to create driver using property retrieved from UI */
217 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
218
219 if (ptr.owner_id && ptr.data && prop) {
220 ID *id;
221 const int dim = RNA_property_array_dimension(&ptr, prop, nullptr);
222 if (const std::optional<std::string> path = RNA_path_from_real_ID_to_property_index(
223 bmain, &ptr, prop, dim, index, &id))
224 {
225 ANIM_copy_as_driver(id, path->c_str(), RNA_property_identifier(prop));
226 return OPERATOR_FINISHED;
227 }
228
229 BKE_reportf(op->reports, RPT_ERROR, "Could not compute a valid data path");
230 return OPERATOR_CANCELLED;
231 }
232
233 return OPERATOR_CANCELLED;
234}
235
237{
238 /* identifiers */
239 ot->name = "Copy as New Driver";
240 ot->idname = "UI_OT_copy_as_driver_button";
241 ot->description =
242 "Create a new driver with this property as input, and copy it to the "
243 "internal clipboard. Use Paste Driver to add it to the target property, "
244 "or Paste Driver Variables to extend an existing driver";
245
246 /* callbacks */
249
250 /* flags */
252}
253
256/* -------------------------------------------------------------------- */
261{
263
264 if (but && (but->optype != nullptr)) {
265 return true;
266 }
267
268 return false;
269}
270
272{
274
275 if (but && (but->optype != nullptr)) {
276 /* allocated when needed, the button owns it */
278
279 std::string str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
280
281 WM_clipboard_text_set(str.c_str(), false);
282
283 return OPERATOR_FINISHED;
284 }
285
286 return OPERATOR_CANCELLED;
287}
288
290{
291 /* identifiers */
292 ot->name = "Copy Python Command";
293 ot->idname = "UI_OT_copy_python_command_button";
294 ot->description = "Copy the Python command matching this button";
295
296 /* callbacks */
299
300 /* flags */
302}
303
306/* -------------------------------------------------------------------- */
311{
312 ID *id = ptr->owner_id;
313
314 /* perform updates required for this property */
315 RNA_property_update(C, ptr, prop);
316
317 /* as if we pressed the button */
319
320 /* Since we don't want to undo _all_ edits to settings, eg window
321 * edits on the screen or on operator settings.
322 * it might be better to move undo's inline - campbell */
323 if (id && ID_CHECK_UNDO(id)) {
324 /* do nothing, go ahead with undo */
325 return OPERATOR_FINISHED;
326 }
327 return OPERATOR_CANCELLED;
328}
329
332 PropertyRNA *prop)
333{
334 /* Perform updates required for this property. */
335 RNA_property_update(C, ptr, prop);
336
337 /* As if we pressed the button. */
339
340 return OPERATOR_FINISHED;
341}
342
344{
346 PropertyRNA *prop;
347 int index;
348
349 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
350
351 return (ptr.data && prop && RNA_property_editable(&ptr, prop));
352}
353
355{
357 PropertyRNA *prop;
358 int index;
359 const bool all = RNA_boolean_get(op->ptr, "all");
360
361 /* try to reset the nominated setting to its default value */
362 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
363
364 /* if there is a valid property that is editable... */
365 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
366 if (RNA_property_reset(&ptr, prop, (all) ? -1 : index)) {
368 }
369 }
370
371 return OPERATOR_CANCELLED;
372}
373
375{
376 /* identifiers */
377 ot->name = "Reset to Default Value";
378 ot->idname = "UI_OT_reset_default_button";
379 ot->description = "Reset this property's value to its default value";
380
381 /* callbacks */
384
385 /* flags */
386 /* Don't set #OPTYPE_UNDO because #operator_button_property_finish_with_undo
387 * is responsible for the undo push. */
388 ot->flag = 0;
389
390 /* properties */
392 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
393}
394
397/* -------------------------------------------------------------------- */
402{
404 PropertyRNA *prop;
405 int index;
406
407 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
408
409 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
410 const PropertyType type = RNA_property_type(prop);
411
412 return RNA_property_is_idprop(prop) && !RNA_property_array_check(prop) &&
413 ELEM(type, PROP_INT, PROP_FLOAT);
414 }
415
416 return false;
417}
418
420{
422 PropertyRNA *prop;
423 int index;
424
425 /* try to reset the nominated setting to its default value */
426 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
427
428 /* if there is a valid property that is editable... */
429 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
430 if (RNA_property_assign_default(&ptr, prop)) {
431 return operator_button_property_finish(C, &ptr, prop);
432 }
433 }
434
435 return OPERATOR_CANCELLED;
436}
437
439{
440 /* identifiers */
441 ot->name = "Assign Value as Default";
442 ot->idname = "UI_OT_assign_default_button";
443 ot->description = "Set this property's current value as the new default";
444
445 /* callbacks */
448
449 /* flags */
451}
452
455/* -------------------------------------------------------------------- */
460{
462 PropertyRNA *prop;
463 int index;
464
465 /* try to unset the nominated property */
466 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
467
468 /* if there is a valid property that is editable... */
469 if (ptr.data && prop && RNA_property_editable(&ptr, prop) &&
470 /* RNA_property_is_idprop(prop) && */
471 RNA_property_is_set(&ptr, prop))
472 {
473 RNA_property_unset(&ptr, prop);
474 return operator_button_property_finish(C, &ptr, prop);
475 }
476
477 return OPERATOR_CANCELLED;
478}
479
481{
482 /* identifiers */
483 ot->name = "Unset Property";
484 ot->idname = "UI_OT_unset_property_button";
485 ot->description = "Clear the property and use default or generated value in operators";
486
487 /* callbacks */
490
491 /* flags */
493}
494
497/* -------------------------------------------------------------------- */
501/* Note that we use different values for UI/UX than 'real' override operations, user does not care
502 * whether it's added or removed for the differential operation e.g. */
503enum {
506 UIOverride_Type_Difference = 2, /* Add/subtract */
507 UIOverride_Type_Factor = 3, /* Multiply */
508 /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */
509};
510
513 "NOOP",
514 0,
515 "NoOp",
516 "'No-Operation', place holder preventing automatic override to ever affect the property"},
518 "REPLACE",
519 0,
520 "Replace",
521 "Completely replace value from linked data by local one"},
523 "DIFFERENCE",
524 0,
525 "Difference",
526 "Store difference to linked data value"},
528 "FACTOR",
529 0,
530 "Factor",
531 "Store factor to linked data value (useful e.g. for scale)"},
532 {0, nullptr, 0, nullptr, nullptr},
533};
534
536{
538 PropertyRNA *prop;
539 int index;
540
541 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
542
543 const uint override_status = RNA_property_override_library_status(
544 CTX_data_main(C), &ptr, prop, index);
545
546 return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE));
547}
548
550{
552 PropertyRNA *prop;
553 int index;
554 bool created;
555 const bool all = RNA_boolean_get(op->ptr, "all");
556 const int op_type = RNA_enum_get(op->ptr, "type");
557
558 short operation;
559
560 switch (op_type) {
562 operation = LIBOVERRIDE_OP_NOOP;
563 break;
565 operation = LIBOVERRIDE_OP_REPLACE;
566 break;
568 /* override code will automatically switch to subtract if needed. */
569 operation = LIBOVERRIDE_OP_ADD;
570 break;
572 operation = LIBOVERRIDE_OP_MULTIPLY;
573 break;
574 default:
575 operation = LIBOVERRIDE_OP_REPLACE;
576 BLI_assert(0);
577 break;
578 }
579
580 /* try to reset the nominated setting to its default value */
581 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
582
583 BLI_assert(ptr.owner_id != nullptr);
584
585 if (all) {
586 index = -1;
587 }
588
590 CTX_data_main(C), &ptr, prop, operation, index, true, nullptr, &created);
591
592 if (opop == nullptr) {
593 /* Sometimes e.g. RNA cannot generate a path to the given property. */
594 BKE_reportf(op->reports, RPT_WARNING, "Failed to create the override operation");
595 return OPERATOR_CANCELLED;
596 }
597
598 if (!created) {
599 opop->operation = operation;
600 }
601
602 /* Outliner e.g. has to be aware of this change. */
604
605 return operator_button_property_finish(C, &ptr, prop);
606}
607
608static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
609{
610#if 0 /* Disabled for now */
612#else
614 return override_type_set_button_exec(C, op);
615#endif
616}
617
619{
620 /* identifiers */
621 ot->name = "Define Override Type";
622 ot->idname = "UI_OT_override_type_set_button";
623 ot->description = "Create an override operation, or set the type of an existing one";
624
625 /* callbacks */
629
630 /* flags */
632
633 /* properties */
635 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
637 "type",
640 "Type",
641 "Type of override operation");
642 /* TODO: add itemf callback, not all options are available for all data types... */
643}
644
646{
648 PropertyRNA *prop;
649 int index;
650
651 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
652
653 const uint override_status = RNA_property_override_library_status(
654 CTX_data_main(C), &ptr, prop, index);
655
656 return (ptr.data && ptr.owner_id && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN));
657}
658
660{
661 Main *bmain = CTX_data_main(C);
662 PointerRNA ptr, src;
663 PropertyRNA *prop;
664 int index;
665 const bool all = RNA_boolean_get(op->ptr, "all");
666
667 /* try to reset the nominated setting to its default value */
668 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
669
670 ID *id = ptr.owner_id;
672 BLI_assert(oprop != nullptr);
673 BLI_assert(id != nullptr && id->override_library != nullptr);
674
675 /* The source (i.e. linked data) is required to restore values of deleted overrides. */
676 PropertyRNA *src_prop;
677 PointerRNA id_refptr = RNA_id_pointer_create(id->override_library->reference);
678 if (!RNA_path_resolve_property(&id_refptr, oprop->rna_path, &src, &src_prop)) {
679 BLI_assert_msg(0, "Failed to create matching source (linked data) RNA pointer");
680 }
681
682 if (!all && index != -1) {
683 bool is_strict_find;
684 /* Remove override operation for given item,
685 * add singular operations for the other items as needed. */
687 oprop, nullptr, nullptr, {}, {}, index, index, false, &is_strict_find);
688 BLI_assert(opop != nullptr);
689 if (!is_strict_find) {
690 /* No specific override operation, we have to get generic one,
691 * and create item-specific override operations for all but given index,
692 * before removing generic one. */
693 for (int idx = RNA_property_array_length(&ptr, prop); idx--;) {
694 if (idx != index) {
696 oprop, opop->operation, nullptr, nullptr, {}, {}, idx, idx, true, nullptr, nullptr);
697 }
698 }
699 }
701 RNA_property_copy(bmain, &ptr, &src, prop, index);
702 if (BLI_listbase_is_empty(&oprop->operations)) {
703 BKE_lib_override_library_property_delete(id->override_library, oprop);
704 }
705 }
706 else {
707 /* Just remove whole generic override operation of this property. */
708 BKE_lib_override_library_property_delete(id->override_library, oprop);
709 RNA_property_copy(bmain, &ptr, &src, prop, -1);
710 }
711
712 /* Outliner e.g. has to be aware of this change. */
714
715 return operator_button_property_finish(C, &ptr, prop);
716}
717
719{
720 /* identifiers */
721 ot->name = "Remove Override";
722 ot->idname = "UI_OT_override_remove_button";
723 ot->description = "Remove an override operation";
724
725 /* callbacks */
728
729 /* flags */
731
732 /* properties */
734 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
735}
736
738 bContext *C, ID **r_owner_id, ID **r_id, PointerRNA *r_owner_ptr, PropertyRNA **r_prop)
739{
740 PointerRNA owner_ptr;
741 PropertyRNA *prop;
742 UI_context_active_but_prop_get_templateID(C, &owner_ptr, &prop);
743
744 if (owner_ptr.data == nullptr || prop == nullptr) {
745 *r_owner_id = *r_id = nullptr;
746 if (r_owner_ptr != nullptr) {
747 *r_owner_ptr = PointerRNA_NULL;
748 }
749 if (r_prop != nullptr) {
750 *r_prop = nullptr;
751 }
752 return;
753 }
754
755 *r_owner_id = owner_ptr.owner_id;
756 PointerRNA idptr = RNA_property_pointer_get(&owner_ptr, prop);
757 *r_id = static_cast<ID *>(idptr.data);
758 if (r_owner_ptr != nullptr) {
759 *r_owner_ptr = owner_ptr;
760 }
761 if (r_prop != nullptr) {
762 *r_prop = prop;
763 }
764}
765
766static bool override_idtemplate_poll(bContext *C, const bool is_create_op)
767{
768 ID *owner_id, *id;
769 override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
770
771 if (owner_id == nullptr || id == nullptr) {
772 return false;
773 }
774
775 if (is_create_op) {
776 if (!ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
777 return false;
778 }
779 return true;
780 }
781
782 /* Reset/Clear operations. */
784 return false;
785 }
786 return true;
787}
788
790{
791 return override_idtemplate_poll(C, true);
792}
793
795{
796 ID *owner_id, *id;
797 PointerRNA owner_ptr;
798 PropertyRNA *prop;
799 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
800 if (ELEM(nullptr, owner_id, id)) {
801 return OPERATOR_CANCELLED;
802 }
803
805 C, CTX_data_main(C), owner_id, id, nullptr);
806
807 if (id_override == nullptr) {
808 return OPERATOR_CANCELLED;
809 }
810
811 /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
812 * to ensure remapping of the owner property from the linked data to the newly created
813 * liboverride (note that in theory this remapping has already been done by code above), but
814 * only in case owner ID was already local ID (override or pure local data).
815 *
816 * Otherwise, owner ID will also have been overridden, and remapped already to use it's
817 * override of the data too. */
818 if (!ID_IS_LINKED(owner_id)) {
819 PointerRNA idptr = RNA_id_pointer_create(id_override);
820 RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
821 }
822 RNA_property_update(C, &owner_ptr, prop);
823
824 /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
825 * used ID, relying on the property update code only is not always enough. */
827 WM_event_add_notifier(C, NC_WINDOW, nullptr);
830
831 return OPERATOR_FINISHED;
832}
833
835{
836 /* identifiers */
837 ot->name = "Make Library Override";
838 ot->idname = "UI_OT_override_idtemplate_make";
839 ot->description =
840 "Create a local override of the selected linked data-block, and its hierarchy of "
841 "dependencies";
842
843 /* callbacks */
846
847 /* flags */
849}
850
852{
853 return override_idtemplate_poll(C, false);
854}
855
857{
858 ID *owner_id, *id;
859 PointerRNA owner_ptr;
860 PropertyRNA *prop;
861 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
862 if (ELEM(nullptr, owner_id, id)) {
863 return OPERATOR_CANCELLED;
864 }
865
867 return OPERATOR_CANCELLED;
868 }
869
871
872 /* `idptr` is re-assigned to owner property to ensure proper updates etc. */
874 RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
875 RNA_property_update(C, &owner_ptr, prop);
876
877 /* No need for 'security' extra tagging here, since this process will never affect the owner ID.
878 */
879
880 return OPERATOR_FINISHED;
881}
882
884{
885 /* identifiers */
886 ot->name = "Reset Library Override";
887 ot->idname = "UI_OT_override_idtemplate_reset";
888 ot->description = "Reset the selected local override to its linked reference values";
889
890 /* callbacks */
893
894 /* flags */
896}
897
899{
900 return override_idtemplate_poll(C, false);
901}
902
904{
905 ID *owner_id, *id;
906 PointerRNA owner_ptr;
907 PropertyRNA *prop;
908 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
909 if (ELEM(nullptr, owner_id, id)) {
910 return OPERATOR_CANCELLED;
911 }
912
913 if (ID_IS_LINKED(id)) {
914 return OPERATOR_CANCELLED;
915 }
916
917 Main *bmain = CTX_data_main(C);
918 ViewLayer *view_layer = CTX_data_view_layer(C);
919 Scene *scene = CTX_data_scene(C);
920 ID *id_new = id;
921
923 id_new = id->override_library->reference;
924 bool do_remap_active = false;
925 BKE_view_layer_synced_ensure(scene, view_layer);
926 if (BKE_view_layer_active_object_get(view_layer) == (Object *)id) {
927 BLI_assert(GS(id->name) == ID_OB);
928 BLI_assert(GS(id_new->name) == ID_OB);
929 do_remap_active = true;
930 }
932 if (do_remap_active) {
933 Object *ref_object = (Object *)id_new;
934 Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
935 if (basact != nullptr) {
936 view_layer->basact = basact;
937 }
939 }
940 BKE_id_delete(bmain, id);
941 }
942 else {
943 BKE_lib_override_library_id_reset(bmain, id, true);
944 }
945
946 /* Here the affected ID may remain the same, or be replaced by its linked reference. In either
947 * case, the owner ID remains unchanged, and remapping is already handled by internal code, so
948 * calling `RNA_property_update` on it is enough to ensure proper notifiers are sent. */
949 RNA_property_update(C, &owner_ptr, prop);
950
951 /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
952 * used ID, relying on the property update code only is not always enough. */
954 WM_event_add_notifier(C, NC_WINDOW, nullptr);
957
958 return OPERATOR_FINISHED;
959}
960
962{
963 /* identifiers */
964 ot->name = "Clear Library Override";
965 ot->idname = "UI_OT_override_idtemplate_clear";
966 ot->description =
967 "Delete the selected local override and relink its usages to the linked data-block if "
968 "possible, else reset it and mark it as non editable";
969
970 /* callbacks */
973
974 /* flags */
976}
977
978static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType * /*mt*/)
979{
980 bContext *C = (bContext *)C_const;
981 ID *owner_id, *id;
982 override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
983
984 if (owner_id == nullptr || id == nullptr) {
985 return false;
986 }
987
988 if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY_REAL(id))) {
989 return false;
990 }
991 return true;
992}
993
994static void override_idtemplate_menu_draw(const bContext * /*C*/, Menu *menu)
995{
996 uiLayout *layout = menu->layout;
997 uiItemO(layout, IFACE_("Make"), ICON_NONE, "UI_OT_override_idtemplate_make");
998 uiItemO(layout, IFACE_("Reset"), ICON_NONE, "UI_OT_override_idtemplate_reset");
999 uiItemO(layout, IFACE_("Clear"), ICON_NONE, "UI_OT_override_idtemplate_clear");
1000}
1001
1003{
1004 MenuType *mt;
1005
1006 mt = MEM_cnew<MenuType>(__func__);
1007 STRNCPY(mt->idname, "UI_MT_idtemplate_liboverride");
1008 STRNCPY(mt->label, N_("Library Override"));
1011 WM_menutype_add(mt);
1012}
1013
1016/* -------------------------------------------------------------------- */
1020#define NOT_NULL(assignment) ((assignment) != nullptr)
1021#define NOT_RNA_NULL(assignment) ((assignment).data != nullptr)
1022
1024{
1025 blender::Vector<PointerRNA> lb = CTX_data_collection_get(C, "selected_pose_bones");
1026
1027 if (!lb.is_empty()) {
1028 for (PointerRNA &ptr : lb) {
1029 bPoseChannel *pchan = static_cast<bPoseChannel *>(ptr.data);
1030 ptr = RNA_pointer_create(ptr.owner_id, &RNA_Bone, pchan->bone);
1031 }
1032 }
1033
1034 *r_lb = std::move(lb);
1035}
1036
1039 FModifier *source)
1040{
1041 blender::Vector<PointerRNA> fcurve_links;
1042 fcurve_links = CTX_data_collection_get(C, "selected_editable_fcurves");
1043 if (fcurve_links.is_empty()) {
1044 return;
1045 }
1046 r_lb->clear();
1047 for (const PointerRNA &ptr : fcurve_links) {
1048 const FCurve *fcu = static_cast<const FCurve *>(ptr.data);
1050 if (STREQ(mod->name, source->name) && mod->type == source->type) {
1051 r_lb->append(RNA_pointer_create(ptr.owner_id, &RNA_FModifier, mod));
1052 /* Since names are unique it is safe to break here. */
1053 break;
1054 }
1055 }
1056 }
1057}
1058
1060 PointerRNA *ptr,
1061 PropertyRNA *prop,
1063 bool *r_use_path_from_id,
1064 std::optional<std::string> *r_path)
1065{
1066 *r_use_path_from_id = false;
1067 *r_path = std::nullopt;
1068 /* special case for bone constraints */
1069 const bool is_rna = !RNA_property_is_idprop(prop);
1070 /* Remove links from the collection list which don't contain 'prop'. */
1071 bool ensure_list_items_contain_prop = false;
1072
1073 /* PropertyGroup objects don't have a reference to the struct that actually owns
1074 * them, so it is normally necessary to do a brute force search to find it. This
1075 * handles the search for non-ID owners by using the 'active' reference as a hint
1076 * to preserve efficiency. Only properties defined through RNA are handled, as
1077 * custom properties cannot be assumed to be valid for all instances.
1078 *
1079 * Properties owned by the ID are handled by the 'if (ptr->owner_id)' case below.
1080 */
1081 if (is_rna && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) {
1082 PointerRNA owner_ptr;
1083 std::optional<std::string> idpath;
1084
1085 /* First, check the active PoseBone and PoseBone->Bone. */
1086 if (NOT_RNA_NULL(owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone)))
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_pose_bones");
1092 }
1093 else {
1094 bPoseChannel *pchan = static_cast<bPoseChannel *>(owner_ptr.data);
1095 owner_ptr = RNA_pointer_create(owner_ptr.owner_id, &RNA_Bone, pchan->bone);
1096 idpath = RNA_path_from_struct_to_idproperty(&owner_ptr,
1097 static_cast<const IDProperty *>(ptr->data));
1098 if (idpath) {
1100 }
1101 }
1102 }
1103
1104 if (!idpath) {
1105 /* Check the active EditBone if in edit mode. */
1106 idpath = RNA_path_from_struct_to_idproperty(&owner_ptr,
1107 static_cast<const IDProperty *>(ptr->data));
1108 if (NOT_RNA_NULL(
1109 owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)) &&
1110 idpath)
1111 {
1112 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
1113 }
1114
1115 /* Add other simple cases here (Node, NodeSocket, Sequence, ViewLayer etc). */
1116 }
1117
1118 if (idpath) {
1119 *r_path = fmt::format("{}.{}", *idpath, RNA_property_identifier(prop));
1120 return true;
1121 }
1122 }
1123
1124 if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
1125 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
1126 }
1127 else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
1128 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1129 }
1130 else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
1132 }
1133 else if (RNA_struct_is_a(ptr->type, &RNA_BoneColor)) {
1134 /* Get the things that own the bone color (bones, pose bones, or edit bones). */
1135 /* First this will be bones, then gets remapped to colors. */
1136 blender::Vector<PointerRNA> list_of_things = {};
1137 switch (GS(ptr->owner_id->name)) {
1138 case ID_OB:
1139 list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
1140 break;
1141 case ID_AR: {
1142 /* Armature-owned bones can be accessed from both edit mode and pose mode.
1143 * - Edit mode: visit selected edit bones.
1144 * - Pose mode: visit the armature bones of selected pose bones.
1145 */
1146 const bArmature *arm = reinterpret_cast<bArmature *>(ptr->owner_id);
1147 if (arm->edbo) {
1148 list_of_things = CTX_data_collection_get(C, "selected_editable_bones");
1149 }
1150 else {
1151 list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
1152 CTX_data_collection_remap_property(list_of_things, "bone");
1153 }
1154 break;
1155 }
1156 default:
1157 printf("BoneColor is unexpectedly owned by %s '%s'\n",
1159 ptr->owner_id->name + 2);
1160 BLI_assert_msg(false,
1161 "expected BoneColor to be owned by the Armature "
1162 "(bone & edit bone) or the Object (pose bone)");
1163 return false;
1164 }
1165
1166 /* Remap from some bone to its color, to ensure the items of r_lb are of
1167 * type ptr->type. Since all three structs `bPoseChan`, `Bone`, and
1168 * `EditBone` have the same name for their embedded `BoneColor` struct, this
1169 * code is suitable for all of them. */
1170 CTX_data_collection_remap_property(list_of_things, "color");
1171
1172 *r_lb = list_of_things;
1173 }
1174 else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
1175 /* Special case when we do this for 'Sequence.lock'.
1176 * (if the sequence is locked, it won't be in "selected_editable_sequences"). */
1177 const char *prop_id = RNA_property_identifier(prop);
1178 if (STREQ(prop_id, "lock")) {
1179 *r_lb = CTX_data_collection_get(C, "selected_sequences");
1180 }
1181 else {
1182 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
1183 }
1184
1185 if (is_rna) {
1186 /* Account for properties only being available for some sequence types. */
1187 ensure_list_items_contain_prop = true;
1188 }
1189 }
1190 else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
1191 *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
1192 }
1193 else if (RNA_struct_is_a(ptr->type, &RNA_FModifier)) {
1194 FModifier *mod = static_cast<FModifier *>(ptr->data);
1196 }
1197 else if (RNA_struct_is_a(ptr->type, &RNA_Keyframe)) {
1198 *r_lb = CTX_data_collection_get(C, "selected_editable_keyframes");
1199 }
1200 else if (RNA_struct_is_a(ptr->type, &RNA_Action)) {
1201 *r_lb = CTX_data_collection_get(C, "selected_editable_actions");
1202 }
1203 else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
1204 *r_lb = CTX_data_collection_get(C, "selected_nla_strips");
1205 }
1206 else if (RNA_struct_is_a(ptr->type, &RNA_MovieTrackingTrack)) {
1207 *r_lb = CTX_data_collection_get(C, "selected_movieclip_tracks");
1208 }
1209 else if (const std::optional<std::string> path_from_bone =
1210 RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone);
1211 RNA_struct_is_a(ptr->type, &RNA_Constraint) && path_from_bone)
1212 {
1213 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1214 *r_path = path_from_bone;
1215 }
1216 else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
1218 std::optional<std::string> path;
1219 bNode *node = nullptr;
1220
1221 /* Get the node we're editing */
1222 if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
1223 bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
1224 bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data);
1225 if (blender::bke::node_find_node_try(ntree, sock, &node, nullptr)) {
1226 path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node);
1227 if (path) {
1228 /* we're good! */
1229 }
1230 else {
1231 node = nullptr;
1232 }
1233 }
1234 }
1235 else {
1236 node = static_cast<bNode *>(ptr->data);
1237 }
1238
1239 /* Now filter by type */
1240 if (node) {
1241 lb = CTX_data_collection_get(C, "selected_nodes");
1242 lb.remove_if([&](const PointerRNA &link) {
1243 bNode *node_data = static_cast<bNode *>(link.data);
1244 if (node_data->type != node->type) {
1245 return true;
1246 }
1247 return false;
1248 });
1249 }
1250
1251 *r_lb = lb;
1252 *r_path = path;
1253 }
1254 else if (ptr->owner_id) {
1255 ID *id = ptr->owner_id;
1256
1257 if (GS(id->name) == ID_OB) {
1258 *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
1259 *r_use_path_from_id = true;
1260 *r_path = RNA_path_from_ID_to_property(ptr, prop);
1261 }
1262 else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
1263 /* check we're using the active object */
1264 const short id_code = GS(id->name);
1265 blender::Vector<PointerRNA> lb = CTX_data_collection_get(C, "selected_editable_objects");
1266 const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
1267
1268 /* de-duplicate obdata */
1269 if (!lb.is_empty()) {
1270 for (const PointerRNA &ob_ptr : lb) {
1271 Object *ob = (Object *)ob_ptr.owner_id;
1272 if (ID *id_data = static_cast<ID *>(ob->data)) {
1273 id_data->tag |= ID_TAG_DOIT;
1274 }
1275 }
1276
1278 for (const PointerRNA &link : lb) {
1279 Object *ob = (Object *)link.owner_id;
1280 ID *id_data = static_cast<ID *>(ob->data);
1281 if ((id_data == nullptr) || (id_data->tag & ID_TAG_DOIT) == 0 ||
1282 !ID_IS_EDITABLE(id_data) || (GS(id_data->name) != id_code))
1283 {
1284 continue;
1285 }
1286 /* Avoid prepending 'data' to the path. */
1287 new_lb.append(RNA_id_pointer_create(id_data));
1288
1289 if (id_data) {
1290 id_data->tag &= ~ID_TAG_DOIT;
1291 }
1292 }
1293
1294 lb = std::move(new_lb);
1295 }
1296
1297 *r_lb = lb;
1298 *r_path = path;
1299 }
1300 else if (GS(id->name) == ID_SCE) {
1301 /* Sequencer's ID is scene :/ */
1302 /* Try to recursively find an RNA_Sequence ancestor,
1303 * to handle situations like #41062... */
1304 *r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence);
1305 if (r_path->has_value()) {
1306 /* Special case when we do this for 'Sequence.lock'.
1307 * (if the sequence is locked, it won't be in "selected_editable_sequences"). */
1308 const char *prop_id = RNA_property_identifier(prop);
1309 if (is_rna && STREQ(prop_id, "lock")) {
1310 *r_lb = CTX_data_collection_get(C, "selected_sequences");
1311 }
1312 else {
1313 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
1314 }
1315
1316 if (is_rna) {
1317 /* Account for properties only being available for some sequence types. */
1318 ensure_list_items_contain_prop = true;
1319 }
1320 }
1321 }
1322 return r_path->has_value();
1323 }
1324 else {
1325 return false;
1326 }
1327
1328 if (RNA_property_is_idprop(prop)) {
1329 if (!r_path->has_value()) {
1330 *r_path = RNA_path_from_ptr_to_property_index(ptr, prop, 0, -1);
1331 BLI_assert(*r_path);
1332 }
1333 /* Always resolve custom-properties because they can always exist per-item. */
1334 ensure_list_items_contain_prop = true;
1335 }
1336
1337 if (ensure_list_items_contain_prop) {
1338 if (is_rna) {
1339 const char *prop_id = RNA_property_identifier(prop);
1340 r_lb->remove_if([&](const PointerRNA &link) {
1341 if ((ptr->type != link.type) &&
1342 (RNA_struct_type_find_property(link.type, prop_id) != prop))
1343 {
1344 return true;
1345 }
1346 return false;
1347 });
1348 }
1349 else {
1350 const bool prop_is_array = RNA_property_array_check(prop);
1351 const int prop_array_len = prop_is_array ? RNA_property_array_length(ptr, prop) : -1;
1352 const PropertyType prop_type = RNA_property_type(prop);
1353 r_lb->remove_if([&](PointerRNA &link) {
1354 PointerRNA lptr;
1355 PropertyRNA *lprop = nullptr;
1357 &link, r_path->has_value() ? r_path->value().c_str() : nullptr, &lptr, &lprop);
1358
1359 if (lprop == nullptr) {
1360 return true;
1361 }
1362 if (!RNA_property_is_idprop(lprop)) {
1363 return true;
1364 }
1365 if (prop_type != RNA_property_type(lprop)) {
1366 return true;
1367 }
1368 if (prop_is_array != RNA_property_array_check(lprop)) {
1369 return true;
1370 }
1371 if (prop_is_array && (prop_array_len != RNA_property_array_length(&link, lprop))) {
1372 return true;
1373 }
1374 return false;
1375 });
1376 }
1377 }
1378
1379 return true;
1380}
1381
1383 PointerRNA *ptr_link,
1384 PropertyRNA *prop,
1385 const char *path,
1386 bool use_path_from_id,
1387 PointerRNA *r_ptr,
1388 PropertyRNA **r_prop)
1389{
1390 PropertyRNA *lprop;
1391 PointerRNA lptr;
1392
1393 if (ptr_link->data == ptr->data) {
1394 return false;
1395 }
1396
1397 if (use_path_from_id) {
1398 /* Path relative to ID. */
1399 lprop = nullptr;
1400 PointerRNA idptr = RNA_id_pointer_create(ptr_link->owner_id);
1401 RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
1402 }
1403 else if (path) {
1404 /* Path relative to elements from list. */
1405 lprop = nullptr;
1406 RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
1407 }
1408 else {
1410 lptr = *ptr_link;
1411 lprop = prop;
1412 }
1413
1414 if (lptr.data == ptr->data) {
1415 /* The source & destination are the same, so there is nothing to copy. */
1416 return false;
1417 }
1418
1419 /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
1420 * check but we are now more permissive when it comes to ID properties, see below. */
1421 if (lprop == nullptr) {
1422 return false;
1423 }
1424
1425 if (RNA_property_type(lprop) != RNA_property_type(prop)) {
1426 return false;
1427 }
1428
1429 /* Check property pointers matching.
1430 * For ID properties, these pointers match:
1431 * - If the property is API defined on an existing class (and they are equally named).
1432 * - Never for ID properties on specific ID (even if they are equally named).
1433 * - Never for NodesModifierSettings properties (even if they are equally named).
1434 *
1435 * Be permissive on ID properties in the following cases:
1436 * - #NodesModifierSettings properties
1437 * - (special check: only if the node-group matches, since the 'Input_n' properties are name
1438 * based and similar on potentially very different node-groups).
1439 * - ID properties on specific ID
1440 * - (no special check, copying seems OK [even if type does not match -- does not do anything
1441 * then])
1442 */
1443 bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
1444 if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
1445 RNA_struct_is_a(ptr->type, &RNA_NodesModifier))
1446 {
1447 ignore_prop_eq = false;
1448
1449 NodesModifierData *nmd_link = (NodesModifierData *)lptr.data;
1451 if (nmd_link->node_group == nmd_src->node_group) {
1452 ignore_prop_eq = true;
1453 }
1454 }
1455
1456 if ((lprop != prop) && !ignore_prop_eq) {
1457 return false;
1458 }
1459
1460 if (!RNA_property_editable(&lptr, lprop)) {
1461 return false;
1462 }
1463
1464 if (r_ptr) {
1465 *r_ptr = lptr;
1466 }
1467 if (r_prop) {
1468 *r_prop = lprop;
1469 }
1470
1471 return true;
1472}
1473
1481static bool copy_to_selected_button(bContext *C, bool all, bool poll)
1482{
1483 Main *bmain = CTX_data_main(C);
1484 PointerRNA ptr, lptr;
1485 PropertyRNA *prop, *lprop;
1486 int index;
1487
1488 /* try to reset the nominated setting to its default value */
1489 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1490
1491 /* if there is a valid property that is editable... */
1492 if (ptr.data == nullptr || prop == nullptr) {
1493 return false;
1494 }
1495
1496 bool success = false;
1497 std::optional<std::string> path;
1498 bool use_path_from_id;
1500
1501 if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) {
1502 for (PointerRNA &link : lb) {
1503 if (link.data == ptr.data) {
1504 continue;
1505 }
1506
1508 &link,
1509 prop,
1510 path.has_value() ? path->c_str() : nullptr,
1511 use_path_from_id,
1512 &lptr,
1513 &lprop))
1514 {
1515 continue;
1516 }
1517
1518 if (poll) {
1519 success = true;
1520 break;
1521 }
1522 if (RNA_property_copy(bmain, &lptr, &ptr, prop, (all) ? -1 : index)) {
1523 RNA_property_update(C, &lptr, prop);
1524 success = true;
1525 }
1526 }
1527 }
1528
1529 return success;
1530}
1531
1533{
1534 return copy_to_selected_button(C, false, true);
1535}
1536
1538{
1539 bool success;
1540
1541 const bool all = RNA_boolean_get(op->ptr, "all");
1542
1543 success = copy_to_selected_button(C, all, false);
1544
1545 return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1546}
1547
1549{
1550 /* identifiers */
1551 ot->name = "Copy to Selected";
1552 ot->idname = "UI_OT_copy_to_selected_button";
1553 ot->description =
1554 "Copy the property's value from the active item to the same property of all selected items "
1555 "if the same property exists";
1556
1557 /* callbacks */
1560
1561 /* flags */
1563
1564 /* properties */
1565 RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
1566}
1567
1570/* -------------------------------------------------------------------- */
1574/* Name-spaced for unit testing. Conceptually these functions should be static
1575 * and not be used outside this source file. But they need to be externally
1576 * accessible to add unit tests for them. */
1578
1580 PointerRNA *ptr, PropertyRNA *prop, const bool get_all, const int index, bool *r_is_array_prop)
1581{
1582 BLI_assert(ptr && prop);
1583
1584 const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
1585 if (!path.has_value()) {
1586 return {};
1587 }
1588
1590 if (!adt) {
1591 return {};
1592 }
1593
1594 blender::Vector<FCurve *> drivers = {};
1595 const bool is_array_prop = RNA_property_array_check(prop);
1596 if (!is_array_prop) {
1597 /* NOTE: by convention Blender assigns 0 as the index for drivers of
1598 * non-array properties, which is why we search for it here. Values > 0 are
1599 * not recognized by Blender's driver system in that case. Values < 0 are
1600 * recognized for driver evaluation, but `BKE_fcurve_find()` unconditionally
1601 * returns nullptr in that case so it wouldn't matter here anyway. */
1602 drivers.append(BKE_fcurve_find(&adt->drivers, path->c_str(), 0));
1603 }
1604 else {
1605 /* For array properties, we always allocate space for all elements of an
1606 * array property, and the unused ones just remain null. */
1607 drivers.resize(RNA_property_array_length(ptr, prop), nullptr);
1608 for (int i = 0; i < drivers.size(); i++) {
1609 if (get_all || i == index) {
1610 drivers[i] = BKE_fcurve_find(&adt->drivers, path->c_str(), i);
1611 }
1612 }
1613 }
1614
1615 /* If we didn't get any drivers to copy, instead of returning a vector of all
1616 * nullptr, return an empty vector for clarity. That way the caller gets
1617 * either a useful result or an empty one. */
1618 bool fetched_at_least_one = false;
1619 for (const FCurve *driver : drivers) {
1620 fetched_at_least_one |= driver != nullptr;
1621 }
1622 if (!fetched_at_least_one) {
1623 return {};
1624 }
1625
1626 if (r_is_array_prop) {
1627 *r_is_array_prop = is_array_prop;
1628 }
1629
1630 return drivers;
1631}
1632
1634 const bool is_array_prop,
1635 PointerRNA *dst_ptr,
1636 PropertyRNA *dst_prop)
1637{
1638 BLI_assert(src_drivers.size() > 0);
1639 BLI_assert(is_array_prop || src_drivers.size() == 1);
1640
1641 /* Get the RNA path and relevant animdata for the property we're copying to. */
1642 const std::optional<std::string> dst_path = RNA_path_from_ID_to_property(dst_ptr, dst_prop);
1643 if (!dst_path.has_value()) {
1644 return 0;
1645 }
1646 AnimData *dst_adt = BKE_animdata_ensure_id(dst_ptr->owner_id);
1647 if (!dst_adt) {
1648 return 0;
1649 }
1650
1651 /* Do the copying. */
1652 int paste_count = 0;
1653 for (int i = 0; i < src_drivers.size(); i++) {
1654 if (!src_drivers[i]) {
1655 continue;
1656 }
1657 const int dst_index = is_array_prop ? i : -1;
1658
1659 /* If it's already animated by something other than a driver, skip. This is
1660 * because Blender's UI assumes that properties are either animated *or*
1661 * driven, and things can get confusing for users otherwise. Additionally,
1662 * no other parts of Blender's UI allow users to (at least easily) add
1663 * drivers on already-animated properties, so this keeps things consistent
1664 * across driver-related operators. */
1665 bool driven;
1666 {
1667 const FCurve *fcu = BKE_fcurve_find_by_rna(
1668 dst_ptr, dst_prop, dst_index, nullptr, nullptr, &driven, nullptr);
1669 if (fcu && !driven) {
1670 continue;
1671 }
1672 }
1673
1674 /* If there's an existing matching driver, remove it first.
1675 *
1676 * TODO: in the context of `copy_driver_to_selected_button()` this has
1677 * quadratic complexity when the drivers are within the same ID, due to this
1678 * being inside of a loop and doing a linear scan of the drivers to find one
1679 * that matches. We should be able to make this more efficient with a
1680 * little cleverness .*/
1681 if (driven) {
1682 FCurve *old_driver = BKE_fcurve_find(&dst_adt->drivers, dst_path->c_str(), dst_index);
1683 if (old_driver) {
1684 BLI_remlink(&dst_adt->drivers, old_driver);
1685 BKE_fcurve_free(old_driver);
1686 }
1687 }
1688
1689 /* Create the new driver. */
1690 FCurve *new_driver = BKE_fcurve_copy(src_drivers[i]);
1691 BKE_fcurve_rnapath_set(*new_driver, dst_path.value());
1692 BLI_addtail(&dst_adt->drivers, new_driver);
1693
1694 paste_count++;
1695 }
1696
1697 return paste_count;
1698}
1699
1700} // namespace blender::interface::internal
1701
1723static bool copy_driver_to_selected_button(bContext *C, bool copy_entire_array, const bool poll)
1724{
1725 using namespace blender::interface::internal;
1726
1727 PropertyRNA *prop;
1729 int index;
1730
1731 /* Get the property of the clicked button. */
1732 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1733 if (!ptr.data || !ptr.owner_id || !prop) {
1734 return false;
1735 }
1736 copy_entire_array |= index == -1; /* -1 implies `copy_entire_array` for array properties. */
1737
1738 /* Get the property's driver(s). */
1739 bool is_array_prop = false;
1740 const blender::Vector<FCurve *> src_drivers = get_property_drivers(
1741 &ptr, prop, copy_entire_array, index, &is_array_prop);
1742 if (src_drivers.is_empty()) {
1743 return false;
1744 }
1745
1746 /* Build the list of properties to copy the driver(s) to, along with relevant
1747 * side data. */
1748 std::optional<std::string> path;
1749 bool use_path_from_id;
1750 blender::Vector<PointerRNA> target_properties;
1752 C, &ptr, prop, &target_properties, &use_path_from_id, &path))
1753 {
1754 return false;
1755 }
1756
1757 /* Copy the driver(s) to the list of target properties. */
1758 int total_copy_count = 0;
1759 for (PointerRNA &target_prop : target_properties) {
1760 if (target_prop.data == ptr.data) {
1761 continue;
1762 }
1763
1764 /* Get the target property and ensure that it's appropriate for adding
1765 * drivers. */
1766 PropertyRNA *dst_prop;
1767 PointerRNA dst_ptr;
1769 &target_prop,
1770 prop,
1771 path.has_value() ? path->c_str() : nullptr,
1772 use_path_from_id,
1773 &dst_ptr,
1774 &dst_prop))
1775 {
1776 continue;
1777 }
1778 if (!RNA_property_driver_editable(&dst_ptr, dst_prop)) {
1779 continue;
1780 }
1781
1782 /* If we're just polling, then we early-out on the first property we would
1783 * be able to copy to. */
1784 if (poll) {
1785 return true;
1786 }
1787
1788 const int paste_count = paste_property_drivers(
1789 src_drivers.as_span(), is_array_prop, &dst_ptr, dst_prop);
1790 if (paste_count == 0) {
1791 continue;
1792 }
1793
1794 RNA_property_update(C, &dst_ptr, dst_prop);
1795 total_copy_count += paste_count;
1796 }
1797
1798 return total_copy_count > 0;
1799}
1800
1802{
1803 return copy_driver_to_selected_button(C, false, true);
1804}
1805
1807{
1808 const bool all = RNA_boolean_get(op->ptr, "all");
1809
1810 if (!copy_driver_to_selected_button(C, all, false)) {
1811 return OPERATOR_CANCELLED;
1812 }
1813
1816 return OPERATOR_FINISHED;
1817}
1818
1820{
1821 /* Identifiers. */
1822 ot->name = "Copy Driver to Selected";
1823 ot->idname = "UI_OT_copy_driver_to_selected_button";
1824 ot->description =
1825 "Copy the property's driver from the active item to the same property "
1826 "of all selected items, if the same property exists";
1827
1828 /* Callbacks. */
1831
1832 /* Flags. */
1834
1835 /* Properties. */
1837 ot->srna, "all", false, "All", "Copy to selected the drivers of all elements of the array");
1838}
1839
1842/* -------------------------------------------------------------------- */
1847static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
1848{
1849 if (RNA_pointer_is_null(&ptr)) {
1850 return false;
1851 }
1852
1853 /* Verify pointer type. */
1854 char bone_name[MAXBONENAME];
1855 const StructRNA *target_type = nullptr;
1856
1857 if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) {
1858 RNA_string_get(&ptr, "name", bone_name);
1859 if (bone_name[0] != '\0') {
1860 target_type = &RNA_Bone;
1861 }
1862 }
1863 else if (RNA_struct_is_a(ptr.type, &RNA_Object)) {
1864 target_type = &RNA_Object;
1865 }
1866
1867 if (target_type == nullptr) {
1868 return false;
1869 }
1870
1871 /* Find the containing Object. */
1872 const Scene *scene = CTX_data_scene(C);
1873 ViewLayer *view_layer = CTX_data_view_layer(C);
1874 Base *base = nullptr;
1875 const short id_type = GS(ptr.owner_id->name);
1876 if (id_type == ID_OB) {
1877 BKE_view_layer_synced_ensure(scene, view_layer);
1878 base = BKE_view_layer_base_find(view_layer, (Object *)ptr.owner_id);
1879 }
1880 else if (OB_DATA_SUPPORT_ID(id_type)) {
1881 base = blender::ed::object::find_first_by_data_id(scene, view_layer, ptr.owner_id);
1882 }
1883
1884 bool ok = false;
1885 if ((base == nullptr) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) {
1886 /* pass */
1887 }
1888 else if (poll) {
1889 ok = true;
1890 }
1891 else {
1892 /* Make optional. */
1893 const bool reveal_hidden = true;
1894 /* Select and activate the target. */
1895 if (target_type == &RNA_Bone) {
1896 ok = blender::ed::object::jump_to_bone(C, base->object, bone_name, reveal_hidden);
1897 }
1898 else if (target_type == &RNA_Object) {
1899 ok = blender::ed::object::jump_to_object(C, base->object, reveal_hidden);
1900 }
1901 else {
1902 BLI_assert(0);
1903 }
1904 }
1905 return ok;
1906}
1907
1915static bool jump_to_target_button(bContext *C, bool poll)
1916{
1917 PointerRNA ptr, target_ptr;
1918 PropertyRNA *prop;
1919 int index;
1920
1921 const uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1922
1923 /* If there is a valid property... */
1924 if (ptr.data && prop) {
1925 const PropertyType type = RNA_property_type(prop);
1926
1927 /* For pointer properties, use their value directly. */
1928 if (type == PROP_POINTER) {
1929 target_ptr = RNA_property_pointer_get(&ptr, prop);
1930
1931 return jump_to_target_ptr(C, target_ptr, poll);
1932 }
1933 /* For string properties with prop_search, look up the search collection item. */
1934 if (type == PROP_STRING) {
1935 const uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but :
1936 nullptr;
1937
1938 if (search_but && search_but->items_update_fn == ui_rna_collection_search_update_fn) {
1939 uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(search_but->arg);
1940
1941 char str_buf[MAXBONENAME];
1942 char *str_ptr = RNA_property_string_get_alloc(
1943 &ptr, prop, str_buf, sizeof(str_buf), nullptr);
1944
1945 bool found = false;
1946 /* Jump to target only works with search properties currently, not search callbacks yet.
1947 * See ui_but_add_search. */
1948 if (coll_search->search_prop != nullptr) {
1950 &coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
1951 }
1952
1953 if (str_ptr != str_buf) {
1954 MEM_freeN(str_ptr);
1955 }
1956
1957 if (found) {
1958 return jump_to_target_ptr(C, target_ptr, poll);
1959 }
1960 }
1961 }
1962 }
1963
1964 return false;
1965}
1966
1968{
1969 return jump_to_target_button(C, true);
1970}
1971
1973{
1974 const bool success = jump_to_target_button(C, false);
1975
1976 return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1977}
1978
1980{
1981 /* identifiers */
1982 ot->name = "Jump to Target";
1983 ot->idname = "UI_OT_jump_to_target_button";
1984 ot->description = "Switch to the target object or bone";
1985
1986 /* callbacks */
1989
1990 /* flags */
1992}
1993
1996/* -------------------------------------------------------------------- */
2000#ifdef WITH_PYTHON
2001
2002/* ------------------------------------------------------------------------- */
2003/* EditSource Utility functions and operator,
2004 * NOTE: this includes utility functions and button matching checks. */
2005
2006struct uiEditSourceStore {
2007 uiBut but_orig;
2008 GHash *hash;
2009};
2010
2011struct uiEditSourceButStore {
2012 char py_dbg_fn[FILE_MAX];
2013 int py_dbg_line_number;
2014};
2015
2016/* should only ever be set while the edit source operator is running */
2017static uiEditSourceStore *ui_editsource_info = nullptr;
2018
2020{
2021 return (ui_editsource_info != nullptr);
2022}
2023
2024static void ui_editsource_active_but_set(uiBut *but)
2025{
2026 BLI_assert(ui_editsource_info == nullptr);
2027
2028 ui_editsource_info = MEM_new<uiEditSourceStore>(__func__);
2029 ui_editsource_info->but_orig = *but;
2030
2031 ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
2032}
2033
2034static void ui_editsource_active_but_clear()
2035{
2036 BLI_ghash_free(ui_editsource_info->hash, nullptr, MEM_freeN);
2037 MEM_delete(ui_editsource_info);
2038 ui_editsource_info = nullptr;
2039}
2040
2041static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
2042{
2043# if 0
2044 printf("matching buttons: '%s' == '%s'\n", but_a->drawstr, but_b->drawstr);
2045# endif
2046
2047 /* this just needs to be a 'good-enough' comparison so we can know beyond
2048 * reasonable doubt that these buttons are the same between redraws.
2049 * if this fails it only means edit-source fails - campbell */
2050 if (BLI_rctf_compare(&but_a->rect, &but_b->rect, FLT_EPSILON) && (but_a->type == but_b->type) &&
2051 (but_a->rnaprop == but_b->rnaprop) && (but_a->optype == but_b->optype) &&
2052 (but_a->unit_type == but_b->unit_type) && but_a->drawstr == but_b->drawstr)
2053 {
2054 return true;
2055 }
2056 return false;
2057}
2058
2059extern void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno);
2060
2062{
2063
2064 uiEditSourceButStore *but_store = MEM_cnew<uiEditSourceButStore>(__func__);
2065
2066 const char *fn;
2067 int line_number = -1;
2068
2069# if 0
2070 printf("comparing buttons: '%s' == '%s'\n", but->drawstr, ui_editsource_info->but_orig.drawstr);
2071# endif
2072
2073 PyC_FileAndNum_Safe(&fn, &line_number);
2074
2075 if (line_number != -1) {
2076 STRNCPY(but_store->py_dbg_fn, fn);
2077 but_store->py_dbg_line_number = line_number;
2078 }
2079 else {
2080 but_store->py_dbg_fn[0] = '\0';
2081 but_store->py_dbg_line_number = -1;
2082 }
2083
2084 BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
2085}
2086
2087void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
2088{
2089 uiEditSourceButStore *but_store = static_cast<uiEditSourceButStore *>(
2090 BLI_ghash_lookup(ui_editsource_info->hash, old_but));
2091 if (but_store) {
2092 BLI_ghash_remove(ui_editsource_info->hash, old_but, nullptr, nullptr);
2093 BLI_ghash_insert(ui_editsource_info->hash, new_but, but_store);
2094 }
2095}
2096
2097static int editsource_text_edit(bContext *C,
2098 wmOperator * /*op*/,
2099 const char filepath[FILE_MAX],
2100 const int line)
2101{
2102 wmOperatorType *ot = WM_operatortype_find("TEXT_OT_jump_to_file_at_point", true);
2103 PointerRNA op_props;
2104
2106 RNA_string_set(&op_props, "filepath", filepath);
2107 RNA_int_set(&op_props, "line", line - 1);
2108 RNA_int_set(&op_props, "column", 0);
2109
2110 int result = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props, nullptr);
2111 WM_operator_properties_free(&op_props);
2112 return result;
2113}
2114
2115static int editsource_exec(bContext *C, wmOperator *op)
2116{
2118
2119 if (but) {
2120 GHashIterator ghi;
2121 uiEditSourceButStore *but_store = nullptr;
2122
2123 ARegion *region = CTX_wm_region(C);
2124 int ret;
2125
2126 /* needed else the active button does not get tested */
2128
2129 // printf("%s: begin\n", __func__);
2130
2131 /* take care not to return before calling ui_editsource_active_but_clear */
2132 ui_editsource_active_but_set(but);
2133
2134 /* redraw and get active button python info */
2136
2137 for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
2138 BLI_ghashIterator_done(&ghi) == false;
2140 {
2141 uiBut *but_key = static_cast<uiBut *>(BLI_ghashIterator_getKey(&ghi));
2142 if (but_key && ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) {
2143 but_store = static_cast<uiEditSourceButStore *>(BLI_ghashIterator_getValue(&ghi));
2144 break;
2145 }
2146 }
2147
2148 if (but_store) {
2149 if (but_store->py_dbg_line_number != -1) {
2150 ret = editsource_text_edit(C, op, but_store->py_dbg_fn, but_store->py_dbg_line_number);
2151 }
2152 else {
2153 BKE_report(
2154 op->reports, RPT_ERROR, "Active button is not from a script, cannot edit source");
2156 }
2157 }
2158 else {
2159 BKE_report(op->reports, RPT_ERROR, "Active button match cannot be found");
2161 }
2162
2163 ui_editsource_active_but_clear();
2164
2165 // printf("%s: end\n", __func__);
2166
2167 return ret;
2168 }
2169
2170 BKE_report(op->reports, RPT_ERROR, "Active button not found");
2171 return OPERATOR_CANCELLED;
2172}
2173
2174static void UI_OT_editsource(wmOperatorType *ot)
2175{
2176 /* identifiers */
2177 ot->name = "Edit Source";
2178 ot->idname = "UI_OT_editsource";
2179 ot->description = "Edit UI source code of the active button";
2180
2181 /* callbacks */
2182 ot->exec = editsource_exec;
2183}
2184
2187#endif /* WITH_PYTHON */
2188
2189/* -------------------------------------------------------------------- */
2193static int reloadtranslation_exec(bContext * /*C*/, wmOperator * /*op*/)
2194{
2195 BLT_lang_init();
2197 BLT_lang_set(nullptr);
2199 return OPERATOR_FINISHED;
2200}
2201
2203{
2204 /* identifiers */
2205 ot->name = "Reload Translation";
2206 ot->idname = "UI_OT_reloadtranslation";
2207 ot->description = "Force a full reload of UI translation";
2208
2209 /* callbacks */
2211}
2212
2215/* -------------------------------------------------------------------- */
2219static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2220{
2221 bScreen *screen = CTX_wm_screen(C);
2222 const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
2223 ARegion *region_prev = CTX_wm_region(C);
2224 ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : nullptr;
2225
2226 if (region == nullptr) {
2227 region = region_prev;
2228 }
2229
2230 if (region == nullptr) {
2231 return OPERATOR_PASS_THROUGH;
2232 }
2233
2234 CTX_wm_region_set(C, region);
2236 CTX_wm_region_set(C, region_prev);
2237
2238 if (but == nullptr) {
2239 return OPERATOR_PASS_THROUGH;
2240 }
2241 if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) {
2242 return OPERATOR_PASS_THROUGH;
2243 }
2244
2245 /* Weak, this is a workaround for 'UI_but_is_tool', which checks the operator type,
2246 * having this avoids a minor drawing glitch. */
2247 void *but_optype = but->optype;
2248
2249 UI_but_execute(C, region, but);
2250
2251 but->optype = static_cast<wmOperatorType *>(but_optype);
2252
2254
2255 return OPERATOR_FINISHED;
2256}
2257
2259{
2260 ot->name = "Press Button";
2261 ot->idname = "UI_OT_button_execute";
2262 ot->description = "Presses active button";
2263
2266
2267 RNA_def_boolean(ot->srna, "skip_depressed", false, "Skip Depressed", "");
2268}
2269
2272/* -------------------------------------------------------------------- */
2277{
2279
2280 if (but) {
2282 }
2283
2284 return OPERATOR_FINISHED;
2285}
2286
2288{
2289 ot->name = "Clear Button String";
2290 ot->idname = "UI_OT_button_string_clear";
2291 ot->description = "Unsets the text of the active button";
2292
2296}
2297
2300/* -------------------------------------------------------------------- */
2304bool UI_drop_color_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
2305{
2306 /* should only return true for regions that include buttons, for now
2307 * return true always */
2308 if (drag->type == WM_DRAG_COLOR) {
2309 SpaceImage *sima = CTX_wm_space_image(C);
2310 ARegion *region = CTX_wm_region(C);
2311
2312 if (UI_but_active_drop_color(C)) {
2313 return true;
2314 }
2315
2316 if (sima && (sima->mode == SI_MODE_PAINT) && sima->image &&
2317 (region && region->regiontype == RGN_TYPE_WINDOW))
2318 {
2319 return true;
2320 }
2321 }
2322
2323 return false;
2324}
2325
2326void UI_drop_color_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
2327{
2328 uiDragColorHandle *drag_info = static_cast<uiDragColorHandle *>(drag->poin);
2329
2330 RNA_float_set_array(drop->ptr, "color", drag_info->color);
2331 RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
2332}
2333
2334static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2335{
2336 ARegion *region = CTX_wm_region(C);
2337 uiBut *but = nullptr;
2338 float color[4];
2339 bool gamma;
2340
2341 RNA_float_get_array(op->ptr, "color", color);
2342 gamma = RNA_boolean_get(op->ptr, "gamma");
2343
2344 /* find button under mouse, check if it has RNA color property and
2345 * if it does copy the data */
2346 but = ui_region_find_active_but(region);
2347
2348 if (but && but->type == UI_BTYPE_COLOR && but->rnaprop) {
2349 const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
2350 BLI_assert(color_len <= 4);
2351
2352 /* keep alpha channel as-is */
2353 if (color_len == 4) {
2354 color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2355 }
2356
2358 if (!gamma) {
2360 }
2361 RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
2362 RNA_property_update(C, &but->rnapoin, but->rnaprop);
2363 }
2364 else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
2365 if (gamma) {
2367 }
2368 RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
2369 RNA_property_update(C, &but->rnapoin, but->rnaprop);
2370 }
2371
2372 if (UI_but_flag_is_set(but, UI_BUT_UNDO)) {
2374 }
2375 }
2376 else {
2377 if (gamma) {
2378 srgb_to_linearrgb_v3_v3(color, color);
2379 }
2380
2381 ED_imapaint_bucket_fill(C, color, op, event->mval);
2382 }
2383
2384 ED_region_tag_redraw(region);
2385
2386 return OPERATOR_FINISHED;
2387}
2388
2390{
2391 ot->name = "Drop Color";
2392 ot->idname = "UI_OT_drop_color";
2393 ot->description = "Drop colors to buttons";
2394
2397
2399
2401 ot->srna, "color", 3, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
2403 ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected");
2404}
2405
2408/* -------------------------------------------------------------------- */
2413{
2414 if (!ED_operator_regionactive(C)) {
2415 return false;
2416 }
2417
2418 const uiBut *but = UI_but_active_drop_name_button(C);
2419 if (!but) {
2420 return false;
2421 }
2422
2423 if (but->flag & UI_BUT_DISABLED) {
2424 return false;
2425 }
2426
2427 return true;
2428}
2429
2430static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
2431{
2433 char *str = RNA_string_get_alloc(op->ptr, "string", nullptr, 0, nullptr);
2434
2435 if (str) {
2437 MEM_freeN(str);
2438 }
2439
2440 return OPERATOR_FINISHED;
2441}
2442
2444{
2445 ot->name = "Drop Name";
2446 ot->idname = "UI_OT_drop_name";
2447 ot->description = "Drop name to button";
2448
2452
2454 ot->srna, "string", nullptr, 0, "String", "The string value to drop into the button");
2455}
2456
2459/* -------------------------------------------------------------------- */
2464{
2465 const ARegion *region = CTX_wm_region(C);
2466 if (!region) {
2467 return false;
2468 }
2469 const wmWindow *win = CTX_wm_window(C);
2470 const uiList *list = UI_list_find_mouse_over(region, win->eventstate);
2471
2472 return list != nullptr;
2473}
2474
2480{
2481 if (list->filter_flag & UILST_FLT_SHOW) {
2482 /* Nothing to be done. */
2483 return false;
2484 }
2485
2486 list->filter_flag |= UILST_FLT_SHOW;
2487 return true;
2488}
2489
2490static int ui_list_start_filter_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
2491{
2492 ARegion *region = CTX_wm_region(C);
2493 uiList *list = UI_list_find_mouse_over(region, event);
2494 /* Poll should check. */
2495 BLI_assert(list != nullptr);
2496
2499 }
2500
2501 if (!UI_textbutton_activate_rna(C, region, list, "filter_name")) {
2502 return OPERATOR_CANCELLED;
2503 }
2504
2505 return OPERATOR_FINISHED;
2506}
2507
2509{
2510 ot->name = "List Filter";
2511 ot->idname = "UI_OT_list_start_filter";
2512 ot->description = "Start entering filter text for the list in focus";
2513
2516}
2517
2520/* -------------------------------------------------------------------- */
2525{
2526 const wmWindow *win = CTX_wm_window(C);
2527 if (!(win && win->eventstate)) {
2528 return nullptr;
2529 }
2530
2531 const ARegion *region = CTX_wm_region(C);
2532 if (!region) {
2533 return nullptr;
2534 }
2535 return UI_region_view_find_at(region, win->eventstate->xy, 0);
2536}
2537
2539{
2540 const AbstractView *view = get_view_focused(C);
2541 return view != nullptr;
2542}
2543
2544static int ui_view_start_filter_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
2545{
2546 const ARegion *region = CTX_wm_region(C);
2547 const blender::ui::AbstractView *hovered_view = UI_region_view_find_at(region, event->xy, 0);
2548
2549 if (!hovered_view->begin_filtering(*C)) {
2551 }
2552
2553 return OPERATOR_FINISHED;
2554}
2555
2557{
2558 ot->name = "View Filter";
2559 ot->idname = "UI_OT_view_start_filter";
2560 ot->description = "Start entering filter text for the data-set in focus";
2561
2564
2566}
2567
2570/* -------------------------------------------------------------------- */
2575{
2576 const wmWindow *win = CTX_wm_window(C);
2577 if (!(win && win->eventstate)) {
2578 return false;
2579 }
2580 const ARegion *region = CTX_wm_region(C);
2581 if (region == nullptr) {
2582 return false;
2583 }
2584 return region_views_find_drop_target_at(region, win->eventstate->xy) != nullptr;
2585}
2586
2587static int ui_view_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
2588{
2589 if (event->custom != EVT_DATA_DRAGDROP) {
2591 }
2592
2593 ARegion *region = CTX_wm_region(C);
2594 std::unique_ptr<DropTargetInterface> drop_target = region_views_find_drop_target_at(region,
2595 event->xy);
2596
2598 *C, *region, *event, *drop_target, *static_cast<const ListBase *>(event->customdata)))
2599 {
2601 }
2602
2603 ED_region_tag_redraw(region);
2604 return OPERATOR_FINISHED;
2605}
2606
2608{
2609 ot->name = "View Drop";
2610 ot->idname = "UI_OT_view_drop";
2611 ot->description = "Drag and drop onto a data-set or item within the data-set";
2612
2615
2617}
2618
2621/* -------------------------------------------------------------------- */
2626{
2627 const AbstractView *view = get_view_focused(C);
2628 if (!view) {
2629 return false;
2630 }
2631
2632 return view->supports_scrolling();
2633}
2634
2635static int ui_view_scroll_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
2636{
2637 ARegion *region = CTX_wm_region(C);
2638 int type = event->type;
2639 bool invert_direction = false;
2640
2641 if (type == MOUSEPAN) {
2642 int dummy_val;
2643 ui_pan_to_scroll(event, &type, &dummy_val);
2644
2645 /* 'ui_pan_to_scroll' gives the absolute direction. */
2646 if (event->flag & WM_EVENT_SCROLL_INVERT) {
2647 invert_direction = true;
2648 }
2649 }
2650
2651 AbstractView *view = get_view_focused(C);
2652 std::optional<ViewScrollDirection> direction =
2653 [type, invert_direction]() -> std::optional<ViewScrollDirection> {
2654 switch (type) {
2655 case WHEELUPMOUSE:
2656 return invert_direction ? ViewScrollDirection::DOWN : ViewScrollDirection::UP;
2657 case WHEELDOWNMOUSE:
2658 return invert_direction ? ViewScrollDirection::UP : ViewScrollDirection::DOWN;
2659 default:
2660 return std::nullopt;
2661 }
2662 }();
2663 if (!direction) {
2664 return OPERATOR_CANCELLED;
2665 }
2666
2667 BLI_assert(view->supports_scrolling());
2668 view->scroll(*direction);
2669
2670 ED_region_tag_redraw(region);
2671 return OPERATOR_FINISHED;
2672}
2673
2675{
2676 ot->name = "View Scroll";
2677 ot->idname = "UI_OT_view_scroll";
2678
2681
2683}
2684
2687/* -------------------------------------------------------------------- */
2697{
2698 const ARegion *region = CTX_wm_region(C);
2699 if (region == nullptr) {
2700 return false;
2701 }
2703 return active_item != nullptr && UI_view_item_can_rename(*active_item);
2704}
2705
2707{
2708 ARegion *region = CTX_wm_region(C);
2710
2711 UI_view_item_begin_rename(*active_item);
2712 ED_region_tag_redraw(region);
2713
2714 return OPERATOR_FINISHED;
2715}
2716
2718{
2719 ot->name = "Rename View Item";
2720 ot->idname = "UI_OT_view_item_rename";
2721 ot->description = "Rename the active item in the data-set view";
2722
2725 /* Could get a custom tooltip via the `get_description()` callback and another overridable
2726 * function of the view. */
2727
2729}
2732/* -------------------------------------------------------------------- */
2738{
2739 PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
2740 const Object *ob = static_cast<const Object *>(ptr.data);
2741 if (ob == nullptr) {
2742 return false;
2743 }
2744
2745 PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
2746 if (RNA_pointer_is_null(&mat_slot)) {
2747 return false;
2748 }
2749
2750 return true;
2751}
2752
2754{
2755 Main *bmain = CTX_data_main(C);
2756
2758 bmain, op->ptr, ID_MA);
2759 if (ma == nullptr) {
2760 return OPERATOR_CANCELLED;
2761 }
2762
2763 PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
2764 Object *ob = static_cast<Object *>(ptr.data);
2765 BLI_assert(ob);
2766
2767 PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
2768 BLI_assert(mat_slot.data);
2769 const int target_slot = RNA_int_get(&mat_slot, "slot_index") + 1;
2770
2771 /* only drop grease pencil material on grease pencil objects */
2772 if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL_LEGACY)) {
2773 return OPERATOR_CANCELLED;
2774 }
2775
2776 BKE_object_material_assign(bmain, ob, ma, target_slot, BKE_MAT_ASSIGN_USERPREF);
2777
2782
2783 return OPERATOR_FINISHED;
2784}
2785
2787{
2788 ot->name = "Drop Material in Material slots";
2789 ot->description = "Drag material to Material slots in Properties";
2790 ot->idname = "UI_OT_drop_material";
2791
2795
2797}
2798
2801/* -------------------------------------------------------------------- */
2806{
2807 using namespace blender::ui;
2820#ifdef WITH_PYTHON
2821 WM_operatortype_append(UI_OT_editsource);
2822#endif
2826
2828
2833
2840
2841 /* external */
2850}
2851
2853{
2854 WM_keymap_ensure(keyconf, "User Interface", SPACE_EMPTY, RGN_TYPE_WINDOW);
2855
2856 eyedropper_modal_keymap(keyconf);
2858}
2859
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:103
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
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)
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:168
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)
@ ID_REMAP_SKIP_INDIRECT_USAGE
void void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, int remap_flags) ATTR_NONNULL(1
General operations, lookup, etc. for materials.
void BKE_object_material_assign(struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type)
@ BKE_MAT_ASSIGN_USERPREF
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
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:99
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition BLI_ghash.c:911
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:303
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.c:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
Definition BLI_ghash.c:895
BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:311
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
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)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned int uint
#define UNUSED_VARS(...)
#define ELEM(...)
#define STREQ(a, b)
void BLT_lang_set(const char *)
Definition blt_lang.cc:251
void BLT_lang_init()
Definition blt_lang.cc:182
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_SELECT
Definition DNA_ID.h:1068
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1071
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:676
#define ID_CHECK_UNDO(id)
Definition DNA_ID.h:644
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ LIBOVERRIDE_OP_NOOP
Definition DNA_ID.h:227
@ LIBOVERRIDE_OP_ADD
Definition DNA_ID.h:232
@ LIBOVERRIDE_OP_REPLACE
Definition DNA_ID.h:229
@ LIBOVERRIDE_OP_MULTIPLY
Definition DNA_ID.h:236
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
@ ID_AR
@ ID_SCE
@ ID_MA
@ ID_OB
#define MAXBONENAME
Object is a sort of wrapper for general info.
#define OB_DATA_SUPPORT_ID(_id_type)
@ OB_ARMATURE
@ OB_GPENCIL_LEGACY
@ UILST_FLT_SHOW
@ RGN_TYPE_WINDOW
#define RGN_TYPE_ANY
@ SPACE_EMPTY
@ SI_MODE_PAINT
@ OPERATOR_PASS_THROUGH
void ED_imapaint_bucket_fill(bContext *C, const float color[3], wmOperator *op, const int mouse[2])
bool ED_operator_regionactive(bContext *C)
Definition screen_ops.cc:94
void ED_region_do_layout(bContext *C, ARegion *region)
Definition area.cc:476
void ED_region_do_draw(bContext *C, ARegion *region)
Definition area.cc:499
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
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:64
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_INT
Definition RNA_types.hh:66
@ PROP_STRING
Definition RNA_types.hh:68
@ PROP_POINTER
Definition RNA_types.hh:70
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_COLOR
Definition RNA_types.hh:163
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:175
constexpr PointerRNA PointerRNA_NULL
Definition RNA_types.hh:45
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)
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)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
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)
@ UI_BTYPE_SEARCH_MENU
@ UI_BTYPE_COLOR
bool UI_but_flag_is_set(uiBut *but, int flag)
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_WINDOW
Definition WM_types.hh:342
@ WM_EVENT_SCROLL_INVERT
Definition WM_types.hh:643
#define NC_WM
Definition WM_types.hh:341
#define NC_ANIMATION
Definition WM_types.hh:355
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:386
#define ND_KEYFRAME_PROP
Definition WM_types.hh:462
#define NC_MATERIAL
Definition WM_types.hh:347
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
@ WM_DRAG_COLOR
Definition WM_types.hh:1170
#define ND_OB_SHADING
Definition WM_types.hh:424
#define ND_SPACE_VIEW3D
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:346
#define ND_SHADING_LINKS
Definition WM_types.hh:446
#define NC_SPACE
Definition WM_types.hh:359
constexpr int64_t size() const
Definition BLI_span.hh:253
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 bool begin_filtering(const bContext &C) const
#define printf
void ANIM_copy_as_driver(ID *target_id, const char *target_path, const char *var_name)
Definition drivers.cc:785
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)
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)
@ UI_SELECT_DRAW
@ UI_SELECT
uiBut * ui_region_find_active_but(ARegion *region) ATTR_WARN_UNUSED_RESULT
void ui_rna_collection_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first)
static bool ui_list_unhide_filter_options(uiList *list)
static void UI_OT_override_type_set_button(wmOperatorType *ot)
static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
static bool override_type_set_button_poll(bContext *C)
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 int assign_default_button_exec(bContext *C, wmOperator *)
static bool ui_view_focused_poll(bContext *C)
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 int ui_view_scroll_invoke(bContext *C, wmOperator *, const wmEvent *event)
@ UIOverride_Type_Replace
@ UIOverride_Type_Difference
@ UIOverride_Type_NOOP
@ UIOverride_Type_Factor
static void ui_region_redraw_immediately(bContext *C, ARegion *region)
static int override_type_set_button_exec(bContext *C, wmOperator *op)
static int override_idtemplate_clear_exec(bContext *C, wmOperator *)
static bool reset_default_button_poll(bContext *C)
static int operator_button_property_finish(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
static int copy_driver_to_selected_button_exec(bContext *C, wmOperator *op)
static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType *)
static int button_string_clear_exec(bContext *C, wmOperator *)
static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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 int reset_default_button_exec(bContext *C, wmOperator *op)
bool ui_jump_to_target_button_poll(bContext *C)
static int unset_property_button_exec(bContext *C, wmOperator *)
static int ui_list_start_filter_invoke(bContext *C, wmOperator *, const wmEvent *event)
static int copy_python_command_button_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 void UI_OT_override_idtemplate_clear(wmOperatorType *ot)
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 int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int override_idtemplate_reset_exec(bContext *C, wmOperator *)
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
static int override_idtemplate_make_exec(bContext *C, wmOperator *)
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 int ui_view_item_rename_exec(bContext *C, wmOperator *)
static int ui_view_start_filter_invoke(bContext *C, wmOperator *, const wmEvent *event)
static void UI_OT_copy_driver_to_selected_button(wmOperatorType *ot)
static int override_remove_button_exec(bContext *C, wmOperator *op)
static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *)
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 bool jump_to_target_button(bContext *C, bool poll)
static void UI_OT_override_remove_button(wmOperatorType *ot)
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 int copy_data_path_button_exec(bContext *C, wmOperator *op)
static void UI_OT_reset_default_button(wmOperatorType *ot)
void ED_keymap_ui(wmKeyConfig *keyconf)
User Interface Keymap.
static void UI_OT_override_idtemplate_make(wmOperatorType *ot)
static bool assign_default_button_poll(bContext *C)
static int ui_drop_material_exec(bContext *C, wmOperator *op)
static void UI_OT_view_drop(wmOperatorType *ot)
static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
static bool override_idtemplate_clear_poll(bContext *C)
static EnumPropertyItem override_type_items[]
static int copy_as_driver_button_exec(bContext *C, wmOperator *op)
static void ui_context_fcurve_modifiers_via_fcurve(bContext *C, blender::Vector< PointerRNA > *r_lb, FModifier *source)
static bool ui_drop_material_poll(bContext *C)
static int reloadtranslation_exec(bContext *, wmOperator *)
static bool copy_as_driver_button_poll(bContext *C)
static int operator_button_property_finish_with_undo(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
static int jump_to_target_button_exec(bContext *C, wmOperator *)
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 int ui_view_drop_invoke(bContext *C, wmOperator *, const wmEvent *event)
static bool override_idtemplate_make_poll(bContext *C)
static bool override_idtemplate_poll(bContext *C, const bool is_create_op)
static void ui_context_selected_bones_via_pose(bContext *C, blender::Vector< PointerRNA > *r_lb)
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
bool node_find_node_try(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
Definition node.cc:2459
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:154
void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno)
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)
float RNA_property_float_get_index(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)
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)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
bool RNA_pointer_is_null(const PointerRNA *ptr)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_ui_name(const PropertyRNA *prop)
bool RNA_property_is_idprop(const PropertyRNA *prop)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
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_enum_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
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_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
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:913
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:1171
std::optional< std::string > RNA_path_full_property_py_ex(const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
Definition rna_path.cc:1276
std::optional< std::string > RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, PropertyRNA *prop, const StructRNA *type)
Definition rna_path.cc:1189
std::optional< std::string > RNA_path_full_struct_py(const PointerRNA *ptr)
Definition rna_path.cc:1260
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:1149
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1166
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
std::string RNA_path_from_ptr_to_property_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
Definition rna_path.cc:1141
#define FLT_MAX
Definition stdcycles.h:14
ListBase drivers
struct Object * object
ListBase modifiers
char name[64]
struct ID * reference
Definition DNA_ID.h:333
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
char name[66]
Definition DNA_ID.h:425
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
struct bNodeTree * node_group
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
struct Image * image
struct Base * basact
ListBase * edbo
int16_t type
struct Bone * bone
uiButSearchUpdateFn items_update_fn
PropertyRNA * rnaprop
wmOperatorType * optype
eButType type
uchar unit_type
std::string drawstr
PointerRNA rnapoin
eWM_DragDataType type
Definition WM_types.hh:1282
void * poin
Definition WM_types.hh:1283
PointerRNA * ptr
Definition WM_types.hh:1368
short custom
Definition WM_types.hh:758
int xy[2]
Definition WM_types.hh:726
int mval[2]
Definition WM_types.hh:728
eWM_EventFlag flag
Definition WM_types.hh:753
void * customdata
Definition WM_types.hh:772
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
struct wmEvent * eventstate
ccl_device_inline int mod(int x, int m)
Definition util/math.h:520
#define N_(msgid)
void WM_draw_region_viewport_unbind(ARegion *region)
Definition wm_draw.cc:1657
void WM_draw_region_viewport_bind(ARegion *region)
Definition wm_draw.cc:1652
void WM_main_add_notifier(uint type, void *reference)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
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:4126
wmOperatorType * ot
Definition wm_files.cc:4125
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:897
bool WM_menutype_add(MenuType *mt)
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)
int WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext)
std::string WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args, wmOperatorType *ot, PointerRNA *opptr)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_clipboard_text_set(const char *buf, bool selection)