Blender V4.5
interface_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10
11#include <fmt/format.h>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_armature_types.h"
16#include "DNA_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 "ANIM_keyframing.hh"
22
23#include "BLI_listbase.h"
24#include "BLI_math_color.h"
25#include "BLI_rect.h"
26#include "BLI_string.h"
27
28#include "BLF_api.hh"
29#include "BLT_lang.hh"
30#include "BLT_translation.hh"
31
32#include "BKE_anim_data.hh"
33#include "BKE_context.hh"
34#include "BKE_fcurve.hh"
35#include "BKE_idtype.hh"
36#include "BKE_layer.hh"
37#include "BKE_lib_id.hh"
38#include "BKE_lib_override.hh"
39#include "BKE_lib_remap.hh"
40#include "BKE_library.hh"
41#include "BKE_material.hh"
42#include "BKE_node.hh"
43#include "BKE_report.hh"
44#include "BKE_screen.hh"
45
47
48#include "DEG_depsgraph.hh"
50
51#include "RNA_access.hh"
52#include "RNA_define.hh"
53#include "RNA_path.hh"
54#include "RNA_prototypes.hh"
55
56#include "UI_abstract_view.hh"
57#include "UI_interface.hh"
58
59#include "interface_intern.hh"
60
61#include "WM_api.hh"
62#include "WM_types.hh"
63
64#include "ED_object.hh"
65#include "ED_paint.hh"
66#include "ED_undo.hh"
67
68/* for Copy As Driver */
69#include "ED_keyframing.hh"
70
71/* Only for #UI_OT_editsource. */
72#include "BLI_ghash.h"
73#include "ED_screen.hh"
74
75using namespace blender::ui;
76
77/* -------------------------------------------------------------------- */
91
93{
94 ED_region_do_layout(C, region);
96 ED_region_do_draw(C, region);
98 region->runtime->do_draw = 0;
99}
100
102
103/* -------------------------------------------------------------------- */
106
108{
110 PropertyRNA *prop;
111 int index;
112
113 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
114
115 if (ptr.owner_id && ptr.data && prop) {
116 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
117 UNUSED_VARS(path);
118 return true;
119 }
120 }
121
122 return false;
123}
124
126{
127 Main *bmain = CTX_data_main(C);
129 PropertyRNA *prop;
130 int index;
131 ID *id;
132
133 const bool full_path = RNA_boolean_get(op->ptr, "full_path");
134
135 /* try to create driver using property retrieved from UI */
136 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
137
138 std::optional<std::string> path;
139 if (ptr.owner_id != nullptr) {
140 if (full_path) {
141 if (prop) {
142 path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
143 }
144 else {
146 }
147 }
148 else {
149 const int index_dim = (index != -1 && RNA_property_array_check(prop)) ? 1 : 0;
150 path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, index_dim, index, &id);
151
152 if (!path) {
153 path = RNA_path_from_ID_to_property_index(&ptr, prop, index_dim, index);
154 }
155 }
156
157 if (path) {
158 WM_clipboard_text_set(path->c_str(), false);
159 return OPERATOR_FINISHED;
160 }
161 }
162
163 return OPERATOR_CANCELLED;
164}
165
167{
168 PropertyRNA *prop;
169
170 /* identifiers */
171 ot->name = "Copy Data Path";
172 ot->idname = "UI_OT_copy_data_path_button";
173 ot->description = "Copy the RNA data path for this property to the clipboard";
174
175 /* callbacks */
178
179 /* flags */
180 ot->flag = OPTYPE_REGISTER;
181
182 /* properties */
183 prop = RNA_def_boolean(ot->srna, "full_path", false, "full_path", "Copy full data path");
185}
186
188
189/* -------------------------------------------------------------------- */
192
194{
196 PropertyRNA *prop;
197 int index;
198
199 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
200
201 if (ptr.owner_id && ptr.data && prop &&
203 (index >= 0 || !RNA_property_array_check(prop)))
204 {
205 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
206 UNUSED_VARS(path);
207 return true;
208 }
209 }
210
211 return false;
212}
213
215{
216 Main *bmain = CTX_data_main(C);
218 PropertyRNA *prop;
219 int index;
220
221 /* try to create driver using property retrieved from UI */
222 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
223
224 if (ptr.owner_id && ptr.data && prop) {
225 ID *id;
226 const int dim = RNA_property_array_dimension(&ptr, prop, nullptr);
227 if (const std::optional<std::string> path = RNA_path_from_real_ID_to_property_index(
228 bmain, &ptr, prop, dim, index, &id))
229 {
230 ANIM_copy_as_driver(id, path->c_str(), RNA_property_identifier(prop));
231 return OPERATOR_FINISHED;
232 }
233
234 BKE_reportf(op->reports, RPT_ERROR, "Could not compute a valid data path");
235 return OPERATOR_CANCELLED;
236 }
237
238 return OPERATOR_CANCELLED;
239}
240
242{
243 /* identifiers */
244 ot->name = "Copy as New Driver";
245 ot->idname = "UI_OT_copy_as_driver_button";
246 ot->description =
247 "Create a new driver with this property as input, and copy it to the "
248 "internal clipboard. Use Paste Driver to add it to the target property, "
249 "or Paste Driver Variables to extend an existing driver";
250
251 /* callbacks */
254
255 /* flags */
256 ot->flag = OPTYPE_REGISTER;
257}
258
260
261/* -------------------------------------------------------------------- */
264
266{
268
269 if (but && (but->optype != nullptr)) {
270 return true;
271 }
272
273 return false;
274}
275
277{
279
280 if (but && (but->optype != nullptr)) {
281 /* allocated when needed, the button owns it */
283
284 std::string str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
285
286 WM_clipboard_text_set(str.c_str(), false);
287
288 return OPERATOR_FINISHED;
289 }
290
291 return OPERATOR_CANCELLED;
292}
293
295{
296 /* identifiers */
297 ot->name = "Copy Python Command";
298 ot->idname = "UI_OT_copy_python_command_button";
299 ot->description = "Copy the Python command matching this button";
300
301 /* callbacks */
304
305 /* flags */
306 ot->flag = OPTYPE_REGISTER;
307}
308
310
311/* -------------------------------------------------------------------- */
314
317 PropertyRNA *prop)
318{
319 /* Assign before executing logic in the unlikely event the ID is freed. */
320 const bool is_undo = ptr->owner_id && ID_CHECK_UNDO(ptr->owner_id);
321
322 /* perform updates required for this property */
323 RNA_property_update(C, ptr, prop);
324
325 /* as if we pressed the button */
327
328 /* Since we don't want to undo _all_ edits to settings, eg window
329 * edits on the screen or on operator settings.
330 * it might be better to move undo's inline - campbell */
331 if (is_undo) {
332 /* do nothing, go ahead with undo */
333 return OPERATOR_FINISHED;
334 }
335 return OPERATOR_CANCELLED;
336}
337
340 PropertyRNA *prop)
341{
342 /* Perform updates required for this property. */
343 RNA_property_update(C, ptr, prop);
344
345 /* As if we pressed the button. */
347
348 return OPERATOR_FINISHED;
349}
350
352{
354 PropertyRNA *prop;
355 int index;
356
357 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
358
359 return (ptr.data && prop && RNA_property_editable(&ptr, prop));
360}
361
363{
365 PropertyRNA *prop;
366 int index;
367 const bool all = RNA_boolean_get(op->ptr, "all");
368
369 /* try to reset the nominated setting to its default value */
370 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
371
372 /* if there is a valid property that is editable... */
373 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
374 const int array_index = (all) ? -1 : index;
375 if (RNA_property_reset(&ptr, prop, array_index)) {
376
377 /* Apply auto keyframe when property is successfully reset. */
378 Scene *scene = CTX_data_scene(C);
380 C, scene, &ptr, prop, array_index, scene->r.cfra, true);
381
383 }
384 }
385
386 return OPERATOR_CANCELLED;
387}
388
390{
391 /* identifiers */
392 ot->name = "Reset to Default Value";
393 ot->idname = "UI_OT_reset_default_button";
394 ot->description = "Reset this property's value to its default value";
395
396 /* callbacks */
399
400 /* flags */
401 /* Don't set #OPTYPE_UNDO because #operator_button_property_finish_with_undo
402 * is responsible for the undo push. */
403 ot->flag = OPTYPE_REGISTER;
404
405 /* properties */
407 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
408}
409
411
412/* -------------------------------------------------------------------- */
415
417{
419 PropertyRNA *prop;
420 int index;
421
422 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
423
424 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
425 const PropertyType type = RNA_property_type(prop);
426
427 return RNA_property_is_idprop(prop) && !RNA_property_array_check(prop) &&
428 ELEM(type, PROP_INT, PROP_FLOAT);
429 }
430
431 return false;
432}
433
435{
437 PropertyRNA *prop;
438 int index;
439
440 /* try to reset the nominated setting to its default value */
441 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
442
443 /* if there is a valid property that is editable... */
444 if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
445 if (RNA_property_assign_default(&ptr, prop)) {
446 return operator_button_property_finish(C, &ptr, prop);
447 }
448 }
449
450 return OPERATOR_CANCELLED;
451}
452
454{
455 /* identifiers */
456 ot->name = "Assign Value as Default";
457 ot->idname = "UI_OT_assign_default_button";
458 ot->description = "Set this property's current value as the new default";
459
460 /* callbacks */
463
464 /* flags */
465 ot->flag = OPTYPE_UNDO;
466}
467
469
470/* -------------------------------------------------------------------- */
473
475{
477 PropertyRNA *prop;
478 int index;
479
480 /* try to unset the nominated property */
481 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
482
483 /* if there is a valid property that is editable... */
484 if (ptr.data && prop && RNA_property_editable(&ptr, prop) &&
485 /* RNA_property_is_idprop(prop) && */
486 RNA_property_is_set(&ptr, prop))
487 {
488 RNA_property_unset(&ptr, prop);
489 return operator_button_property_finish(C, &ptr, prop);
490 }
491
492 return OPERATOR_CANCELLED;
493}
494
496{
497 /* identifiers */
498 ot->name = "Unset Property";
499 ot->idname = "UI_OT_unset_property_button";
500 ot->description = "Clear the property and use default or generated value in operators";
501
502 /* callbacks */
505
506 /* flags */
507 ot->flag = OPTYPE_UNDO;
508}
509
511
512/* -------------------------------------------------------------------- */
515
516/* Note that we use different values for UI/UX than 'real' override operations, user does not care
517 * whether it's added or removed for the differential operation e.g. */
518enum {
521 UIOverride_Type_Difference = 2, /* Add/subtract */
522 UIOverride_Type_Factor = 3, /* Multiply */
523 /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */
524};
525
528 "NOOP",
529 0,
530 "NoOp",
531 "'No-Operation', place holder preventing automatic override to ever affect the property"},
533 "REPLACE",
534 0,
535 "Replace",
536 "Completely replace value from linked data by local one"},
538 "DIFFERENCE",
539 0,
540 "Difference",
541 "Store difference to linked data value"},
543 "FACTOR",
544 0,
545 "Factor",
546 "Store factor to linked data value (useful e.g. for scale)"},
547 {0, nullptr, 0, nullptr, nullptr},
548};
549
551{
553 PropertyRNA *prop;
554 int index;
555
556 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
557
558 const uint override_status = RNA_property_override_library_status(
559 CTX_data_main(C), &ptr, prop, index);
560
561 return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE));
562}
563
565{
567 PropertyRNA *prop;
568 int index;
569 bool created;
570 const bool all = RNA_boolean_get(op->ptr, "all");
571 const int op_type = RNA_enum_get(op->ptr, "type");
572
573 short operation;
574
575 switch (op_type) {
577 operation = LIBOVERRIDE_OP_NOOP;
578 break;
580 operation = LIBOVERRIDE_OP_REPLACE;
581 break;
583 /* override code will automatically switch to subtract if needed. */
584 operation = LIBOVERRIDE_OP_ADD;
585 break;
587 operation = LIBOVERRIDE_OP_MULTIPLY;
588 break;
589 default:
590 operation = LIBOVERRIDE_OP_REPLACE;
591 BLI_assert(0);
592 break;
593 }
594
595 /* try to reset the nominated setting to its default value */
596 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
597
598 BLI_assert(ptr.owner_id != nullptr);
599
600 if (all) {
601 index = -1;
602 }
603
605 CTX_data_main(C), &ptr, prop, operation, index, true, nullptr, &created);
606
607 if (opop == nullptr) {
608 /* Sometimes e.g. RNA cannot generate a path to the given property. */
609 BKE_reportf(op->reports, RPT_WARNING, "Failed to create the override operation");
610 return OPERATOR_CANCELLED;
611 }
612
613 if (!created) {
614 opop->operation = operation;
615 }
616
617 /* Outliner e.g. has to be aware of this change. */
619
620 return operator_button_property_finish(C, &ptr, prop);
621}
622
624 wmOperator *op,
625 const wmEvent * /*event*/)
626{
627#if 0 /* Disabled for now */
629#else
632#endif
633}
634
636{
637 /* identifiers */
638 ot->name = "Define Override Type";
639 ot->idname = "UI_OT_override_type_set_button";
640 ot->description = "Create an override operation, or set the type of an existing one";
641
642 /* callbacks */
646
647 /* flags */
648 ot->flag = OPTYPE_UNDO;
649
650 /* properties */
652 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
653 ot->prop = RNA_def_enum(ot->srna,
654 "type",
657 "Type",
658 "Type of override operation");
659 /* TODO: add itemf callback, not all options are available for all data types... */
660}
661
663{
665 PropertyRNA *prop;
666 int index;
667
668 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
669
670 const uint override_status = RNA_property_override_library_status(
671 CTX_data_main(C), &ptr, prop, index);
672
673 return (ptr.data && ptr.owner_id && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN));
674}
675
677{
678 Main *bmain = CTX_data_main(C);
679 PointerRNA ptr, src;
680 PropertyRNA *prop;
681 int index;
682 const bool all = RNA_boolean_get(op->ptr, "all");
683
684 /* try to reset the nominated setting to its default value */
685 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
686
687 ID *id = ptr.owner_id;
689 BLI_assert(oprop != nullptr);
690 BLI_assert(id != nullptr && id->override_library != nullptr);
691
692 /* The source (i.e. linked data) is required to restore values of deleted overrides. */
693 PropertyRNA *src_prop;
695 if (!RNA_path_resolve_property(&id_refptr, oprop->rna_path, &src, &src_prop)) {
696 BLI_assert_msg(0, "Failed to create matching source (linked data) RNA pointer");
697 }
698
699 if (!all && index != -1) {
700 bool is_strict_find;
701 /* Remove override operation for given item,
702 * add singular operations for the other items as needed. */
704 oprop, nullptr, nullptr, {}, {}, index, index, false, &is_strict_find);
705 BLI_assert(opop != nullptr);
706 if (!is_strict_find) {
707 /* No specific override operation, we have to get generic one,
708 * and create item-specific override operations for all but given index,
709 * before removing generic one. */
710 for (int idx = RNA_property_array_length(&ptr, prop); idx--;) {
711 if (idx != index) {
713 oprop, opop->operation, nullptr, nullptr, {}, {}, idx, idx, true, nullptr, nullptr);
714 }
715 }
716 }
718 RNA_property_copy(bmain, &ptr, &src, prop, index);
719 if (BLI_listbase_is_empty(&oprop->operations)) {
721 }
722 }
723 else {
724 /* Just remove whole generic override operation of this property. */
726 RNA_property_copy(bmain, &ptr, &src, prop, -1);
727 }
728
729 /* Outliner e.g. has to be aware of this change. */
731
732 return operator_button_property_finish(C, &ptr, prop);
733}
734
736{
737 /* identifiers */
738 ot->name = "Remove Override";
739 ot->idname = "UI_OT_override_remove_button";
740 ot->description = "Remove an override operation";
741
742 /* callbacks */
745
746 /* flags */
747 ot->flag = OPTYPE_UNDO;
748
749 /* properties */
751 ot->srna, "all", true, "All", "Reset to default values all elements of the array");
752}
753
755 bContext *C, ID **r_owner_id, ID **r_id, PointerRNA *r_owner_ptr, PropertyRNA **r_prop)
756{
757 PointerRNA owner_ptr;
758 PropertyRNA *prop;
760
761 if (owner_ptr.data == nullptr || prop == nullptr) {
762 *r_owner_id = *r_id = nullptr;
763 if (r_owner_ptr != nullptr) {
764 *r_owner_ptr = PointerRNA_NULL;
765 }
766 if (r_prop != nullptr) {
767 *r_prop = nullptr;
768 }
769 return;
770 }
771
772 *r_owner_id = owner_ptr.owner_id;
773 PointerRNA idptr = RNA_property_pointer_get(&owner_ptr, prop);
774 *r_id = static_cast<ID *>(idptr.data);
775 if (r_owner_ptr != nullptr) {
776 *r_owner_ptr = owner_ptr;
777 }
778 if (r_prop != nullptr) {
779 *r_prop = prop;
780 }
781}
782
783static bool override_idtemplate_poll(bContext *C, const bool is_create_op)
784{
785 ID *owner_id, *id;
786 override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
787
788 if (owner_id == nullptr || id == nullptr) {
789 return false;
790 }
791
792 if (is_create_op) {
793 if (!ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
794 return false;
795 }
796 return true;
797 }
798
799 /* Reset/Clear operations. */
801 return false;
802 }
803 return true;
804}
805
807{
808 return override_idtemplate_poll(C, true);
809}
810
812{
813 ID *owner_id, *id;
814 PointerRNA owner_ptr;
815 PropertyRNA *prop;
816 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
817 if (ELEM(nullptr, owner_id, id)) {
818 return OPERATOR_CANCELLED;
819 }
820
822 C, CTX_data_main(C), owner_id, id, nullptr);
823
824 if (id_override == nullptr) {
825 return OPERATOR_CANCELLED;
826 }
827
828 /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
829 * to ensure remapping of the owner property from the linked data to the newly created
830 * liboverride (note that in theory this remapping has already been done by code above), but
831 * only in case owner ID was already local ID (override or pure local data).
832 *
833 * Otherwise, owner ID will also have been overridden, and remapped already to use it's
834 * override of the data too. */
835 if (!ID_IS_LINKED(owner_id)) {
836 PointerRNA idptr = RNA_id_pointer_create(id_override);
837 RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
838 }
839 RNA_property_update(C, &owner_ptr, prop);
840
841 /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
842 * used ID, relying on the property update code only is not always enough. */
847
848 return OPERATOR_FINISHED;
849}
850
852{
853 /* identifiers */
854 ot->name = "Make Library Override";
855 ot->idname = "UI_OT_override_idtemplate_make";
856 ot->description =
857 "Create a local override of the selected linked data-block, and its hierarchy of "
858 "dependencies";
859
860 /* callbacks */
863
864 /* flags */
865 ot->flag = OPTYPE_UNDO;
866}
867
869{
870 return override_idtemplate_poll(C, false);
871}
872
874{
875 ID *owner_id, *id;
876 PointerRNA owner_ptr;
877 PropertyRNA *prop;
878 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
879 if (ELEM(nullptr, owner_id, id)) {
880 return OPERATOR_CANCELLED;
881 }
882
884 return OPERATOR_CANCELLED;
885 }
886
888
889 /* `idptr` is re-assigned to owner property to ensure proper updates etc. */
891 RNA_property_pointer_set(&owner_ptr, prop, idptr, nullptr);
892 RNA_property_update(C, &owner_ptr, prop);
893
894 /* No need for 'security' extra tagging here, since this process will never affect the owner ID.
895 */
896
897 return OPERATOR_FINISHED;
898}
899
901{
902 /* identifiers */
903 ot->name = "Reset Library Override";
904 ot->idname = "UI_OT_override_idtemplate_reset";
905 ot->description = "Reset the selected local override to its linked reference values";
906
907 /* callbacks */
910
911 /* flags */
912 ot->flag = OPTYPE_UNDO;
913}
914
916{
917 return override_idtemplate_poll(C, false);
918}
919
921{
922 ID *owner_id, *id;
923 PointerRNA owner_ptr;
924 PropertyRNA *prop;
925 override_idtemplate_ids_get(C, &owner_id, &id, &owner_ptr, &prop);
926 if (ELEM(nullptr, owner_id, id)) {
927 return OPERATOR_CANCELLED;
928 }
929
930 if (ID_IS_LINKED(id)) {
931 return OPERATOR_CANCELLED;
932 }
933
934 Main *bmain = CTX_data_main(C);
935 ViewLayer *view_layer = CTX_data_view_layer(C);
936 Scene *scene = CTX_data_scene(C);
937 ID *id_new = id;
938
940 id_new = id->override_library->reference;
941 bool do_remap_active = false;
942 BKE_view_layer_synced_ensure(scene, view_layer);
943 if (BKE_view_layer_active_object_get(view_layer) == (Object *)id) {
944 BLI_assert(GS(id->name) == ID_OB);
945 BLI_assert(GS(id_new->name) == ID_OB);
946 do_remap_active = true;
947 }
949 if (do_remap_active) {
950 Object *ref_object = (Object *)id_new;
951 Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
952 if (basact != nullptr) {
953 view_layer->basact = basact;
954 }
956 }
957 BKE_id_delete(bmain, id);
958 }
959 else {
960 BKE_lib_override_library_id_reset(bmain, id, true);
961 }
962
963 /* Here the affected ID may remain the same, or be replaced by its linked reference. In either
964 * case, the owner ID remains unchanged, and remapping is already handled by internal code, so
965 * calling `RNA_property_update` on it is enough to ensure proper notifiers are sent. */
966 RNA_property_update(C, &owner_ptr, prop);
967
968 /* 'Security' extra tagging, since this process may also affect the owner ID and not only the
969 * used ID, relying on the property update code only is not always enough. */
974
975 return OPERATOR_FINISHED;
976}
977
979{
980 /* identifiers */
981 ot->name = "Clear Library Override";
982 ot->idname = "UI_OT_override_idtemplate_clear";
983 ot->description =
984 "Delete the selected local override and relink its usages to the linked data-block if "
985 "possible, else reset it and mark it as non editable";
986
987 /* callbacks */
990
991 /* flags */
992 ot->flag = OPTYPE_UNDO;
993}
994
995static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType * /*mt*/)
996{
997 bContext *C = (bContext *)C_const;
998 ID *owner_id, *id;
999 override_idtemplate_ids_get(C, &owner_id, &id, nullptr, nullptr);
1000
1001 if (owner_id == nullptr || id == nullptr) {
1002 return false;
1003 }
1004
1005 if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY_REAL(id))) {
1006 return false;
1007 }
1008 return true;
1009}
1010
1011static void override_idtemplate_menu_draw(const bContext * /*C*/, Menu *menu)
1012{
1013 uiLayout *layout = menu->layout;
1014 layout->op("UI_OT_override_idtemplate_make", IFACE_("Make"), ICON_NONE);
1015 layout->op("UI_OT_override_idtemplate_reset", IFACE_("Reset"), ICON_NONE);
1016 layout->op("UI_OT_override_idtemplate_clear", IFACE_("Clear"), ICON_NONE);
1017}
1018
1020{
1021 MenuType *mt;
1022
1023 mt = MEM_callocN<MenuType>(__func__);
1024 STRNCPY(mt->idname, "UI_MT_idtemplate_liboverride");
1025 STRNCPY(mt->label, N_("Library Override"));
1028 WM_menutype_add(mt);
1029}
1030
1032
1033/* -------------------------------------------------------------------- */
1036
1037#define NOT_RNA_NULL(assignment) ((assignment).data != nullptr)
1038
1046{
1047 bPoseChannel *pchan = static_cast<bPoseChannel *>(pchan_ptr.data);
1048
1049 BLI_assert(GS(pchan_ptr.owner_id->name) == ID_OB);
1050 Object *object = reinterpret_cast<Object *>(pchan_ptr.owner_id);
1051
1052 BLI_assert(GS(static_cast<ID *>(object->data)->name) == ID_AR);
1053 bArmature *armature = static_cast<bArmature *>(object->data);
1054
1055 return RNA_pointer_create_discrete(&armature->id, &RNA_Bone, pchan->bone);
1056}
1057
1059{
1060 blender::Vector<PointerRNA> lb = CTX_data_collection_get(C, "selected_pose_bones");
1061
1062 for (PointerRNA &ptr : lb) {
1064 }
1065
1066 *r_lb = std::move(lb);
1067}
1068
1071 FModifier *source)
1072{
1073 blender::Vector<PointerRNA> fcurve_links;
1074 fcurve_links = CTX_data_collection_get(C, "selected_editable_fcurves");
1075 if (fcurve_links.is_empty()) {
1076 return;
1077 }
1078 r_lb->clear();
1079 for (const PointerRNA &ptr : fcurve_links) {
1080 const FCurve *fcu = static_cast<const FCurve *>(ptr.data);
1082 if (STREQ(mod->name, source->name) && mod->type == source->type) {
1083 r_lb->append(RNA_pointer_create_discrete(ptr.owner_id, &RNA_FModifier, mod));
1084 /* Since names are unique it is safe to break here. */
1085 break;
1086 }
1087 }
1088 }
1089}
1090
1092 PointerRNA *ptr,
1093 PropertyRNA *prop,
1095 bool *r_use_path_from_id,
1096 std::optional<std::string> *r_path)
1097{
1098 *r_use_path_from_id = false;
1099 *r_path = std::nullopt;
1100 /* special case for bone constraints */
1101 const bool is_rna = !RNA_property_is_idprop(prop);
1102 /* Remove links from the collection list which don't contain 'prop'. */
1103 bool ensure_list_items_contain_prop = false;
1104
1105 /* PropertyGroup objects don't have a reference to the struct that actually owns
1106 * them, so it is normally necessary to do a brute force search to find it. This
1107 * handles the search for non-ID owners by using the 'active' reference as a hint
1108 * to preserve efficiency. Only properties defined through RNA are handled, as
1109 * custom properties cannot be assumed to be valid for all instances.
1110 *
1111 * Properties owned by the ID are handled by the 'if (ptr->owner_id)' case below.
1112 */
1113 if (is_rna && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) {
1114 PointerRNA owner_ptr;
1115 std::optional<std::string> idpath;
1116
1117 /* First, check the active PoseBone and PoseBone->Bone. */
1118 if (NOT_RNA_NULL(owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone)))
1119 {
1120 idpath = RNA_path_from_struct_to_idproperty(&owner_ptr,
1121 static_cast<const IDProperty *>(ptr->data));
1122 if (idpath) {
1123 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1124 }
1125 else {
1126 PointerRNA bone_ptr = rnapointer_pchan_to_bone(owner_ptr);
1127 idpath = RNA_path_from_struct_to_idproperty(&bone_ptr,
1128 static_cast<const IDProperty *>(ptr->data));
1129 if (idpath) {
1131 }
1132 }
1133 }
1134
1135 if (!idpath) {
1136 /* Check the active EditBone if in edit mode. */
1137 if (NOT_RNA_NULL(
1138 owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)))
1139 {
1140 idpath = RNA_path_from_struct_to_idproperty(&owner_ptr,
1141 static_cast<const IDProperty *>(ptr->data));
1142 if (idpath) {
1143 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
1144 }
1145 }
1146
1147 /* Add other simple cases here (Node, NodeSocket, Sequence, ViewLayer etc). */
1148 }
1149
1150 if (idpath) {
1151 *r_path = fmt::format("{}.{}", *idpath, RNA_property_identifier(prop));
1152 return true;
1153 }
1154 }
1155
1156 if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
1157 /* Special case when we do this for #edit_bone.lock.
1158 * (if the edit_bone is locked, it is not included in "selected_editable_bones"). */
1159 const char *prop_id = RNA_property_identifier(prop);
1160 if (STREQ(prop_id, "lock")) {
1161 *r_lb = CTX_data_collection_get(C, "selected_bones");
1162 }
1163 else {
1164 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
1165 }
1166 }
1167 else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
1168 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1169 }
1170 else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
1171 /* "selected_bones" or "selected_editable_bones" will only yield anything in Armature Edit
1172 * mode. In other modes, it'll be empty, and the only way to get the selected bones is via
1173 * "selected_pose_bones". */
1175 }
1176 else if (RNA_struct_is_a(ptr->type, &RNA_BoneColor)) {
1177 /* Get the things that own the bone color (bones, pose bones, or edit bones). */
1178 /* First this will be bones, then gets remapped to colors. */
1179 blender::Vector<PointerRNA> list_of_things = {};
1180 switch (GS(ptr->owner_id->name)) {
1181 case ID_OB:
1182 list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
1183 break;
1184 case ID_AR: {
1185 /* Armature-owned bones can be accessed from both edit mode and pose mode.
1186 * - Edit mode: visit selected edit bones.
1187 * - Pose mode: visit the armature bones of selected pose bones.
1188 */
1189 const bArmature *arm = reinterpret_cast<bArmature *>(ptr->owner_id);
1190 if (arm->edbo) {
1191 list_of_things = CTX_data_collection_get(C, "selected_editable_bones");
1192 }
1193 else {
1194 list_of_things = CTX_data_collection_get(C, "selected_pose_bones");
1195 CTX_data_collection_remap_property(list_of_things, "bone");
1196 }
1197 break;
1198 }
1199 default:
1200 printf("BoneColor is unexpectedly owned by %s '%s'\n",
1201 BKE_idtype_idcode_to_name(GS(ptr->owner_id->name)),
1202 ptr->owner_id->name + 2);
1203 BLI_assert_msg(false,
1204 "expected BoneColor to be owned by the Armature "
1205 "(bone & edit bone) or the Object (pose bone)");
1206 return false;
1207 }
1208
1209 /* Remap from some bone to its color, to ensure the items of r_lb are of
1210 * type ptr->type. Since all three structs `bPoseChan`, `Bone`, and
1211 * `EditBone` have the same name for their embedded `BoneColor` struct, this
1212 * code is suitable for all of them. */
1213 CTX_data_collection_remap_property(list_of_things, "color");
1214
1215 *r_lb = list_of_things;
1216 }
1217 else if (RNA_struct_is_a(ptr->type, &RNA_Strip)) {
1218 /* Special case when we do this for 'Strip.lock'.
1219 * (if the strip is locked, it won't be in "selected_editable_strips"). */
1220 const char *prop_id = RNA_property_identifier(prop);
1221 if (STREQ(prop_id, "lock")) {
1222 *r_lb = CTX_data_collection_get(C, "selected_strips");
1223 }
1224 else {
1225 *r_lb = CTX_data_collection_get(C, "selected_editable_strips");
1226 }
1227
1228 if (is_rna) {
1229 /* Account for properties only being available for some sequence types. */
1230 ensure_list_items_contain_prop = true;
1231 }
1232 }
1233 else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
1234 *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
1235 }
1236 else if (RNA_struct_is_a(ptr->type, &RNA_FModifier)) {
1237 FModifier *mod = static_cast<FModifier *>(ptr->data);
1239 }
1240 else if (RNA_struct_is_a(ptr->type, &RNA_Keyframe)) {
1241 *r_lb = CTX_data_collection_get(C, "selected_editable_keyframes");
1242 }
1243 else if (RNA_struct_is_a(ptr->type, &RNA_Action)) {
1244 *r_lb = CTX_data_collection_get(C, "selected_editable_actions");
1245 }
1246 else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
1247 *r_lb = CTX_data_collection_get(C, "selected_nla_strips");
1248 }
1249 else if (RNA_struct_is_a(ptr->type, &RNA_MovieTrackingTrack)) {
1250 *r_lb = CTX_data_collection_get(C, "selected_movieclip_tracks");
1251 }
1252 else if (const std::optional<std::string> path_from_bone =
1253 RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone);
1254 RNA_struct_is_a(ptr->type, &RNA_Constraint) && path_from_bone)
1255 {
1256 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
1257 *r_path = path_from_bone;
1258 }
1259 else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
1261 std::optional<std::string> path;
1262 bNode *node = nullptr;
1263
1264 /* Get the node we're editing */
1265 if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
1266 bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
1267 bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data);
1268 node = &blender::bke::node_find_node(*ntree, *sock);
1269 path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node);
1270 if (path) {
1271 /* we're good! */
1272 }
1273 else {
1274 node = nullptr;
1275 }
1276 }
1277 else {
1278 node = static_cast<bNode *>(ptr->data);
1279 }
1280
1281 /* Now filter out non-matching nodes (by idname). */
1282 if (node) {
1283 const blender::StringRef node_idname = node->idname;
1284 lb = CTX_data_collection_get(C, "selected_nodes");
1285 lb.remove_if([&](const PointerRNA &link) {
1286 bNode *node_data = static_cast<bNode *>(link.data);
1287 if (node_data->idname != node_idname) {
1288 return true;
1289 }
1290 return false;
1291 });
1292 }
1293
1294 *r_lb = lb;
1295 *r_path = path;
1296 }
1297 else if (ptr->owner_id) {
1298 ID *id = ptr->owner_id;
1299
1300 if (GS(id->name) == ID_OB) {
1301 *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
1302 *r_use_path_from_id = true;
1303 *r_path = RNA_path_from_ID_to_property(ptr, prop);
1304 }
1305 else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
1306 /* check we're using the active object */
1307 const short id_code = GS(id->name);
1308 blender::Vector<PointerRNA> lb = CTX_data_collection_get(C, "selected_editable_objects");
1309 const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
1310
1311 /* de-duplicate obdata */
1312 if (!lb.is_empty()) {
1313 for (const PointerRNA &ob_ptr : lb) {
1314 Object *ob = (Object *)ob_ptr.owner_id;
1315 if (ID *id_data = static_cast<ID *>(ob->data)) {
1316 id_data->tag |= ID_TAG_DOIT;
1317 }
1318 }
1319
1321 for (const PointerRNA &link : lb) {
1322 Object *ob = (Object *)link.owner_id;
1323 ID *id_data = static_cast<ID *>(ob->data);
1324 if ((id_data == nullptr) || (id_data->tag & ID_TAG_DOIT) == 0 ||
1325 !ID_IS_EDITABLE(id_data) || (GS(id_data->name) != id_code))
1326 {
1327 continue;
1328 }
1329 /* Avoid prepending 'data' to the path. */
1330 new_lb.append(RNA_id_pointer_create(id_data));
1331
1332 if (id_data) {
1333 id_data->tag &= ~ID_TAG_DOIT;
1334 }
1335 }
1336
1337 lb = std::move(new_lb);
1338 }
1339
1340 *r_lb = lb;
1341 *r_path = path;
1342 }
1343 else if (GS(id->name) == ID_SCE) {
1344 /* Sequencer's ID is scene :/ */
1345 /* Try to recursively find an RNA_Strip ancestor,
1346 * to handle situations like #41062... */
1347 *r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Strip);
1348 if (r_path->has_value()) {
1349 /* Special case when we do this for 'Strip.lock'.
1350 * (if the strip is locked, it won't be in "selected_editable_strips"). */
1351 const char *prop_id = RNA_property_identifier(prop);
1352 if (is_rna && STREQ(prop_id, "lock")) {
1353 *r_lb = CTX_data_collection_get(C, "selected_strips");
1354 }
1355 else {
1356 *r_lb = CTX_data_collection_get(C, "selected_editable_strips");
1357 }
1358
1359 if (is_rna) {
1360 /* Account for properties only being available for some sequence types. */
1361 ensure_list_items_contain_prop = true;
1362 }
1363 }
1364 }
1365 return r_path->has_value();
1366 }
1367 else {
1368 return false;
1369 }
1370
1371 if (RNA_property_is_idprop(prop)) {
1372 if (!r_path->has_value()) {
1373 *r_path = RNA_path_from_ptr_to_property_index(ptr, prop, 0, -1);
1374 BLI_assert(*r_path);
1375 }
1376 /* Always resolve custom-properties because they can always exist per-item. */
1377 ensure_list_items_contain_prop = true;
1378 }
1379
1380 if (ensure_list_items_contain_prop) {
1381 if (is_rna) {
1382 const char *prop_id = RNA_property_identifier(prop);
1383 r_lb->remove_if([&](const PointerRNA &link) {
1384 if ((ptr->type != link.type) &&
1385 (RNA_struct_type_find_property(link.type, prop_id) != prop))
1386 {
1387 return true;
1388 }
1389 return false;
1390 });
1391 }
1392 else {
1393 const bool prop_is_array = RNA_property_array_check(prop);
1394 const int prop_array_len = prop_is_array ? RNA_property_array_length(ptr, prop) : -1;
1395 const PropertyType prop_type = RNA_property_type(prop);
1396 r_lb->remove_if([&](PointerRNA &link) {
1397 PointerRNA lptr;
1398 PropertyRNA *lprop = nullptr;
1400 &link, r_path->has_value() ? r_path->value().c_str() : nullptr, &lptr, &lprop);
1401
1402 if (lprop == nullptr) {
1403 return true;
1404 }
1405 if (!RNA_property_is_idprop(lprop)) {
1406 return true;
1407 }
1408 if (prop_type != RNA_property_type(lprop)) {
1409 return true;
1410 }
1411 if (prop_is_array != RNA_property_array_check(lprop)) {
1412 return true;
1413 }
1414 if (prop_is_array && (prop_array_len != RNA_property_array_length(&link, lprop))) {
1415 return true;
1416 }
1417 return false;
1418 });
1419 }
1420 }
1421
1422 return true;
1423}
1424
1426 PointerRNA *ptr_link,
1427 PropertyRNA *prop,
1428 const char *path,
1429 bool use_path_from_id,
1430 PointerRNA *r_ptr,
1431 PropertyRNA **r_prop)
1432{
1433 PropertyRNA *lprop;
1434 PointerRNA lptr;
1435
1436 if (ptr_link->data == ptr->data) {
1437 return false;
1438 }
1439
1440 if (use_path_from_id) {
1441 /* Path relative to ID. */
1442 lprop = nullptr;
1443 PointerRNA idptr = RNA_id_pointer_create(ptr_link->owner_id);
1444 RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
1445 }
1446 else if (path) {
1447 /* Path relative to elements from list. */
1448 lprop = nullptr;
1449 RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
1450 }
1451 else {
1453 lptr = *ptr_link;
1454 lprop = prop;
1455 }
1456
1457 if (lptr.data == ptr->data) {
1458 /* The source & destination are the same, so there is nothing to copy. */
1459 return false;
1460 }
1461
1462 /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
1463 * check but we are now more permissive when it comes to ID properties, see below. */
1464 if (lprop == nullptr) {
1465 return false;
1466 }
1467
1468 if (RNA_property_type(lprop) != RNA_property_type(prop)) {
1469 return false;
1470 }
1471
1472 /* Check property pointers matching.
1473 * For ID properties, these pointers match:
1474 * - If the property is API defined on an existing class (and they are equally named).
1475 * - Never for ID properties on specific ID (even if they are equally named).
1476 * - Never for NodesModifierSettings properties (even if they are equally named).
1477 *
1478 * Be permissive on ID properties in the following cases:
1479 * - #NodesModifierSettings properties
1480 * - (special check: only if the node-group matches, since the 'Input_n' properties are name
1481 * based and similar on potentially very different node-groups).
1482 * - ID properties on specific ID
1483 * - (no special check, copying seems OK [even if type does not match -- does not do anything
1484 * then])
1485 */
1486 bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
1487 if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
1488 RNA_struct_is_a(ptr->type, &RNA_NodesModifier))
1489 {
1490 ignore_prop_eq = false;
1491
1492 NodesModifierData *nmd_link = (NodesModifierData *)lptr.data;
1493 NodesModifierData *nmd_src = (NodesModifierData *)ptr->data;
1494 if (nmd_link->node_group == nmd_src->node_group) {
1495 ignore_prop_eq = true;
1496 }
1497 }
1498
1499 if ((lprop != prop) && !ignore_prop_eq) {
1500 return false;
1501 }
1502
1503 if (!RNA_property_editable(&lptr, lprop)) {
1504 return false;
1505 }
1506
1507 if (r_ptr) {
1508 *r_ptr = lptr;
1509 }
1510 if (r_prop) {
1511 *r_prop = lprop;
1512 }
1513
1514 return true;
1515}
1516
1524static bool copy_to_selected_button(bContext *C, bool all, bool poll)
1525{
1526 Main *bmain = CTX_data_main(C);
1527 PointerRNA ptr, lptr;
1528 PropertyRNA *prop, *lprop;
1529 int index;
1530
1531 /* try to reset the nominated setting to its default value */
1532 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1533
1534 /* if there is a valid property that is editable... */
1535 if (ptr.data == nullptr || prop == nullptr) {
1536 return false;
1537 }
1538
1539 bool success = false;
1540 std::optional<std::string> path;
1541 bool use_path_from_id;
1543
1544 if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) {
1545 for (PointerRNA &link : lb) {
1546 if (link.data == ptr.data) {
1547 continue;
1548 }
1549
1551 &link,
1552 prop,
1553 path.has_value() ? path->c_str() : nullptr,
1554 use_path_from_id,
1555 &lptr,
1556 &lprop))
1557 {
1558 continue;
1559 }
1560
1561 if (poll) {
1562 success = true;
1563 break;
1564 }
1565 if (RNA_property_copy(bmain, &lptr, &ptr, prop, (all) ? -1 : index)) {
1566 RNA_property_update(C, &lptr, prop);
1567 success = true;
1568 }
1569 }
1570 }
1571
1572 return success;
1573}
1574
1576{
1577 return copy_to_selected_button(C, false, true);
1578}
1579
1581{
1582 bool success;
1583
1584 const bool all = RNA_boolean_get(op->ptr, "all");
1585
1586 success = copy_to_selected_button(C, all, false);
1587
1588 return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1589}
1590
1592{
1593 /* identifiers */
1594 ot->name = "Copy to Selected";
1595 ot->idname = "UI_OT_copy_to_selected_button";
1596 ot->description =
1597 "Copy the property's value from the active item to the same property of all selected items "
1598 "if the same property exists";
1599
1600 /* callbacks */
1603
1604 /* flags */
1605 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1606
1607 /* properties */
1608 RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
1609}
1610
1612
1613/* -------------------------------------------------------------------- */
1616
1617/* Name-spaced for unit testing. Conceptually these functions should be static
1618 * and not be used outside this source file. But they need to be externally
1619 * accessible to add unit tests for them. */
1621
1623 PointerRNA *ptr, PropertyRNA *prop, const bool get_all, const int index, bool *r_is_array_prop)
1624{
1625 BLI_assert(ptr && prop);
1626
1627 const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
1628 if (!path.has_value()) {
1629 return {};
1630 }
1631
1632 AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
1633 if (!adt) {
1634 return {};
1635 }
1636
1637 blender::Vector<FCurve *> drivers = {};
1638 const bool is_array_prop = RNA_property_array_check(prop);
1639 if (!is_array_prop) {
1640 /* NOTE: by convention Blender assigns 0 as the index for drivers of
1641 * non-array properties, which is why we search for it here. Values > 0 are
1642 * not recognized by Blender's driver system in that case. Values < 0 are
1643 * recognized for driver evaluation, but `BKE_fcurve_find()` unconditionally
1644 * returns nullptr in that case so it wouldn't matter here anyway. */
1645 drivers.append(BKE_fcurve_find(&adt->drivers, path->c_str(), 0));
1646 }
1647 else {
1648 /* For array properties, we always allocate space for all elements of an
1649 * array property, and the unused ones just remain null. */
1650 drivers.resize(RNA_property_array_length(ptr, prop), nullptr);
1651 for (int i = 0; i < drivers.size(); i++) {
1652 if (get_all || i == index) {
1653 drivers[i] = BKE_fcurve_find(&adt->drivers, path->c_str(), i);
1654 }
1655 }
1656 }
1657
1658 /* If we didn't get any drivers to copy, instead of returning a vector of all
1659 * nullptr, return an empty vector for clarity. That way the caller gets
1660 * either a useful result or an empty one. */
1661 bool fetched_at_least_one = false;
1662 for (const FCurve *driver : drivers) {
1663 fetched_at_least_one |= driver != nullptr;
1664 }
1665 if (!fetched_at_least_one) {
1666 return {};
1667 }
1668
1669 if (r_is_array_prop) {
1670 *r_is_array_prop = is_array_prop;
1671 }
1672
1673 return drivers;
1674}
1675
1677 const bool is_array_prop,
1678 PointerRNA *dst_ptr,
1679 PropertyRNA *dst_prop)
1680{
1681 BLI_assert(src_drivers.size() > 0);
1682 BLI_assert(is_array_prop || src_drivers.size() == 1);
1683
1684 /* Get the RNA path and relevant animdata for the property we're copying to. */
1685 const std::optional<std::string> dst_path = RNA_path_from_ID_to_property(dst_ptr, dst_prop);
1686 if (!dst_path.has_value()) {
1687 return 0;
1688 }
1689 AnimData *dst_adt = BKE_animdata_ensure_id(dst_ptr->owner_id);
1690 if (!dst_adt) {
1691 return 0;
1692 }
1693
1694 /* Do the copying. */
1695 int paste_count = 0;
1696 for (int i = 0; i < src_drivers.size(); i++) {
1697 if (!src_drivers[i]) {
1698 continue;
1699 }
1700 const int dst_index = is_array_prop ? i : -1;
1701
1702 /* If it's already animated by something other than a driver, skip. This is
1703 * because Blender's UI assumes that properties are either animated *or*
1704 * driven, and things can get confusing for users otherwise. Additionally,
1705 * no other parts of Blender's UI allow users to (at least easily) add
1706 * drivers on already-animated properties, so this keeps things consistent
1707 * across driver-related operators. */
1708 bool driven;
1709 {
1710 const FCurve *fcu = BKE_fcurve_find_by_rna(
1711 dst_ptr, dst_prop, dst_index, nullptr, nullptr, &driven, nullptr);
1712 if (fcu && !driven) {
1713 continue;
1714 }
1715 }
1716
1717 /* If there's an existing matching driver, remove it first.
1718 *
1719 * TODO: in the context of `copy_driver_to_selected_button()` this has
1720 * quadratic complexity when the drivers are within the same ID, due to this
1721 * being inside of a loop and doing a linear scan of the drivers to find one
1722 * that matches. We should be able to make this more efficient with a
1723 * little cleverness. */
1724 if (driven) {
1725 FCurve *old_driver = BKE_fcurve_find(&dst_adt->drivers, dst_path->c_str(), dst_index);
1726 if (old_driver) {
1727 BLI_remlink(&dst_adt->drivers, old_driver);
1728 BKE_fcurve_free(old_driver);
1729 }
1730 }
1731
1732 /* Create the new driver. */
1733 FCurve *new_driver = BKE_fcurve_copy(src_drivers[i]);
1734 BKE_fcurve_rnapath_set(*new_driver, dst_path.value());
1735 BLI_addtail(&dst_adt->drivers, new_driver);
1736
1737 paste_count++;
1738 }
1739
1740 return paste_count;
1741}
1742
1743} // namespace blender::interface::internal
1744
1766static bool copy_driver_to_selected_button(bContext *C, bool copy_entire_array, const bool poll)
1767{
1768 using namespace blender::interface::internal;
1769
1770 PropertyRNA *prop;
1772 int index;
1773
1774 /* Get the property of the clicked button. */
1775 UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1776 if (!ptr.data || !ptr.owner_id || !prop) {
1777 return false;
1778 }
1779 copy_entire_array |= index == -1; /* -1 implies `copy_entire_array` for array properties. */
1780
1781 /* Get the property's driver(s). */
1782 bool is_array_prop = false;
1784 &ptr, prop, copy_entire_array, index, &is_array_prop);
1785 if (src_drivers.is_empty()) {
1786 return false;
1787 }
1788
1789 /* Build the list of properties to copy the driver(s) to, along with relevant
1790 * side data. */
1791 std::optional<std::string> path;
1792 bool use_path_from_id;
1793 blender::Vector<PointerRNA> target_properties;
1795 C, &ptr, prop, &target_properties, &use_path_from_id, &path))
1796 {
1797 return false;
1798 }
1799
1800 /* Copy the driver(s) to the list of target properties. */
1801 int total_copy_count = 0;
1802 for (PointerRNA &target_prop : target_properties) {
1803 if (target_prop.data == ptr.data) {
1804 continue;
1805 }
1806
1807 /* Get the target property and ensure that it's appropriate for adding
1808 * drivers. */
1809 PropertyRNA *dst_prop;
1810 PointerRNA dst_ptr;
1812 &target_prop,
1813 prop,
1814 path.has_value() ? path->c_str() : nullptr,
1815 use_path_from_id,
1816 &dst_ptr,
1817 &dst_prop))
1818 {
1819 continue;
1820 }
1821 if (!RNA_property_driver_editable(&dst_ptr, dst_prop)) {
1822 continue;
1823 }
1824
1825 /* If we're just polling, then we early-out on the first property we would
1826 * be able to copy to. */
1827 if (poll) {
1828 return true;
1829 }
1830
1831 const int paste_count = paste_property_drivers(
1832 src_drivers.as_span(), is_array_prop, &dst_ptr, dst_prop);
1833 if (paste_count == 0) {
1834 continue;
1835 }
1836
1837 RNA_property_update(C, &dst_ptr, dst_prop);
1838 total_copy_count += paste_count;
1839 }
1840
1841 return total_copy_count > 0;
1842}
1843
1845{
1846 return copy_driver_to_selected_button(C, false, true);
1847}
1848
1850{
1851 const bool all = RNA_boolean_get(op->ptr, "all");
1852
1853 if (!copy_driver_to_selected_button(C, all, false)) {
1854 return OPERATOR_CANCELLED;
1855 }
1856
1859 return OPERATOR_FINISHED;
1860}
1861
1863{
1864 /* Identifiers. */
1865 ot->name = "Copy Driver to Selected";
1866 ot->idname = "UI_OT_copy_driver_to_selected_button";
1867 ot->description =
1868 "Copy the property's driver from the active item to the same property "
1869 "of all selected items, if the same property exists";
1870
1871 /* Callbacks. */
1874
1875 /* Flags. */
1876 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1877
1878 /* Properties. */
1880 ot->srna, "all", false, "All", "Copy to selected the drivers of all elements of the array");
1881}
1882
1884
1885/* -------------------------------------------------------------------- */
1888
1890static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
1891{
1892 if (RNA_pointer_is_null(&ptr)) {
1893 return false;
1894 }
1895
1896 /* Verify pointer type. */
1897 char bone_name[MAXBONENAME];
1898 const StructRNA *target_type = nullptr;
1899
1900 if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) {
1901 RNA_string_get(&ptr, "name", bone_name);
1902 if (bone_name[0] != '\0') {
1903 target_type = &RNA_Bone;
1904 }
1905 }
1906 else if (RNA_struct_is_a(ptr.type, &RNA_Object)) {
1907 target_type = &RNA_Object;
1908 }
1909
1910 if (target_type == nullptr) {
1911 return false;
1912 }
1913
1914 /* Find the containing Object. */
1915 const Scene *scene = CTX_data_scene(C);
1916 ViewLayer *view_layer = CTX_data_view_layer(C);
1917 Base *base = nullptr;
1918 const short id_type = GS(ptr.owner_id->name);
1919 if (id_type == ID_OB) {
1920 BKE_view_layer_synced_ensure(scene, view_layer);
1921 base = BKE_view_layer_base_find(view_layer, (Object *)ptr.owner_id);
1922 }
1923 else if (OB_DATA_SUPPORT_ID(id_type)) {
1924 base = blender::ed::object::find_first_by_data_id(scene, view_layer, ptr.owner_id);
1925 }
1926
1927 bool ok = false;
1928 if ((base == nullptr) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) {
1929 /* pass */
1930 }
1931 else if (poll) {
1932 ok = true;
1933 }
1934 else {
1935 /* Make optional. */
1936 const bool reveal_hidden = true;
1937 /* Select and activate the target. */
1938 if (target_type == &RNA_Bone) {
1939 ok = blender::ed::object::jump_to_bone(C, base->object, bone_name, reveal_hidden);
1940 }
1941 else if (target_type == &RNA_Object) {
1942 ok = blender::ed::object::jump_to_object(C, base->object, reveal_hidden);
1943 }
1944 else {
1945 BLI_assert(0);
1946 }
1947 }
1948 return ok;
1949}
1950
1958static bool jump_to_target_button(bContext *C, bool poll)
1959{
1960 PointerRNA ptr, target_ptr;
1961 PropertyRNA *prop;
1962 int index;
1963
1964 const uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1965
1966 /* If there is a valid property... */
1967 if (ptr.data && prop) {
1968 const PropertyType type = RNA_property_type(prop);
1969
1970 /* For pointer properties, use their value directly. */
1971 if (type == PROP_POINTER) {
1972 target_ptr = RNA_property_pointer_get(&ptr, prop);
1973
1974 return jump_to_target_ptr(C, target_ptr, poll);
1975 }
1976 /* For string properties with prop_search, look up the search collection item. */
1977 if (type == PROP_STRING) {
1978 const uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but :
1979 nullptr;
1980
1981 if (search_but && search_but->items_update_fn == ui_rna_collection_search_update_fn) {
1982 uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(search_but->arg);
1983
1984 char str_buf[MAXBONENAME];
1985 char *str_ptr = RNA_property_string_get_alloc(
1986 &ptr, prop, str_buf, sizeof(str_buf), nullptr);
1987
1988 bool found = false;
1989 /* Jump to target only works with search properties currently, not search callbacks yet.
1990 * See ui_but_add_search. */
1991 if (coll_search->search_prop != nullptr) {
1993 &coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
1994 }
1995
1996 if (str_ptr != str_buf) {
1997 MEM_freeN(str_ptr);
1998 }
1999
2000 if (found) {
2001 return jump_to_target_ptr(C, target_ptr, poll);
2002 }
2003 }
2004 }
2005 }
2006
2007 return false;
2008}
2009
2011{
2012 return jump_to_target_button(C, true);
2013}
2014
2016{
2017 const bool success = jump_to_target_button(C, false);
2018
2019 return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2020}
2021
2023{
2024 /* identifiers */
2025 ot->name = "Jump to Target";
2026 ot->idname = "UI_OT_jump_to_target_button";
2027 ot->description = "Switch to the target object or bone";
2028
2029 /* callbacks */
2032
2033 /* flags */
2034 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2035}
2036
2038
2039/* -------------------------------------------------------------------- */
2042
2043#ifdef WITH_PYTHON
2044
2045/* ------------------------------------------------------------------------- */
2046/* EditSource Utility functions and operator,
2047 * NOTE: this includes utility functions and button matching checks. */
2048
2049struct uiEditSourceStore {
2050 uiBut but_orig;
2051 GHash *hash;
2052};
2053
2054struct uiEditSourceButStore {
2055 char py_dbg_fn[FILE_MAX];
2056 int py_dbg_line_number;
2057};
2058
2059/* should only ever be set while the edit source operator is running */
2060static uiEditSourceStore *ui_editsource_info = nullptr;
2061
2063{
2064 return (ui_editsource_info != nullptr);
2065}
2066
2067static void ui_editsource_active_but_set(uiBut *but)
2068{
2069 BLI_assert(ui_editsource_info == nullptr);
2070
2071 ui_editsource_info = MEM_new<uiEditSourceStore>(__func__);
2072 ui_editsource_info->but_orig = *but;
2073
2074 ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
2075}
2076
2077static void ui_editsource_active_but_clear()
2078{
2079 BLI_ghash_free(ui_editsource_info->hash, nullptr, MEM_freeN);
2080 MEM_delete(ui_editsource_info);
2081 ui_editsource_info = nullptr;
2082}
2083
2084static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
2085{
2086# if 0
2087 printf("matching buttons: '%s' == '%s'\n", but_a->drawstr, but_b->drawstr);
2088# endif
2089
2090 /* this just needs to be a 'good-enough' comparison so we can know beyond
2091 * reasonable doubt that these buttons are the same between redraws.
2092 * if this fails it only means edit-source fails - campbell */
2093 if (BLI_rctf_compare(&but_a->rect, &but_b->rect, FLT_EPSILON) && (but_a->type == but_b->type) &&
2094 (but_a->rnaprop == but_b->rnaprop) && (but_a->optype == but_b->optype) &&
2095 (but_a->unit_type == but_b->unit_type) && but_a->drawstr == but_b->drawstr)
2096 {
2097 return true;
2098 }
2099 return false;
2100}
2101
2102extern void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno);
2103
2105{
2106
2107 uiEditSourceButStore *but_store = MEM_callocN<uiEditSourceButStore>(__func__);
2108
2109 const char *fn;
2110 int line_number = -1;
2111
2112# if 0
2113 printf("comparing buttons: '%s' == '%s'\n", but->drawstr, ui_editsource_info->but_orig.drawstr);
2114# endif
2115
2116 PyC_FileAndNum_Safe(&fn, &line_number);
2117
2118 if (line_number != -1) {
2119 STRNCPY(but_store->py_dbg_fn, fn);
2120 but_store->py_dbg_line_number = line_number;
2121 }
2122 else {
2123 but_store->py_dbg_fn[0] = '\0';
2124 but_store->py_dbg_line_number = -1;
2125 }
2126
2127 BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
2128}
2129
2130void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
2131{
2132 uiEditSourceButStore *but_store = static_cast<uiEditSourceButStore *>(
2133 BLI_ghash_lookup(ui_editsource_info->hash, old_but));
2134 if (but_store) {
2135 BLI_ghash_remove(ui_editsource_info->hash, old_but, nullptr, nullptr);
2136 BLI_ghash_insert(ui_editsource_info->hash, new_but, but_store);
2137 }
2138}
2139
2140static wmOperatorStatus editsource_text_edit(bContext *C,
2141 wmOperator * /*op*/,
2142 const char filepath[FILE_MAX],
2143 const int line)
2144{
2145 wmOperatorType *ot = WM_operatortype_find("TEXT_OT_jump_to_file_at_point", true);
2146 PointerRNA op_props;
2147
2149 RNA_string_set(&op_props, "filepath", filepath);
2150 RNA_int_set(&op_props, "line", line - 1);
2151 RNA_int_set(&op_props, "column", 0);
2152
2154 C, ot, WM_OP_EXEC_DEFAULT, &op_props, nullptr);
2155 WM_operator_properties_free(&op_props);
2156 return result;
2157}
2158
2159static wmOperatorStatus editsource_exec(bContext *C, wmOperator *op)
2160{
2162
2163 if (but) {
2164 GHashIterator ghi;
2165 uiEditSourceButStore *but_store = nullptr;
2166
2167 ARegion *region = CTX_wm_region(C);
2169
2170 /* needed else the active button does not get tested */
2172
2173 // printf("%s: begin\n", __func__);
2174
2175 /* take care not to return before calling ui_editsource_active_but_clear */
2176 ui_editsource_active_but_set(but);
2177
2178 /* redraw and get active button python info */
2180
2181 /* It's possible the key button referenced in `ui_editsource_info` has been freed.
2182 * This typically happens with popovers but could happen in other situations, see: #140439. */
2183 blender::Set<const uiBut *> valid_buttons_in_region;
2184 LISTBASE_FOREACH (uiBlock *, block_base, &region->runtime->uiblocks) {
2185 uiBlock *block_pair[2] = {block_base, block_base->oldblock};
2186 for (uiBlock *block : blender::Span(block_pair, block_pair[1] ? 2 : 1)) {
2187 for (int i = 0; i < block->buttons.size(); i++) {
2188 const uiBut *but = block->buttons[i].get();
2189 valid_buttons_in_region.add(but);
2190 }
2191 }
2192 }
2193
2194 for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
2195 BLI_ghashIterator_done(&ghi) == false;
2197 {
2198 uiBut *but_key = static_cast<uiBut *>(BLI_ghashIterator_getKey(&ghi));
2199 if (but_key == nullptr) {
2200 continue;
2201 }
2202
2203 if (!valid_buttons_in_region.contains(but_key)) {
2204 continue;
2205 }
2206
2207 if (ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) {
2208 but_store = static_cast<uiEditSourceButStore *>(BLI_ghashIterator_getValue(&ghi));
2209 break;
2210 }
2211 }
2212
2213 if (but_store) {
2214 if (but_store->py_dbg_line_number != -1) {
2215 ret = editsource_text_edit(C, op, but_store->py_dbg_fn, but_store->py_dbg_line_number);
2216 }
2217 else {
2218 BKE_report(
2219 op->reports, RPT_ERROR, "Active button is not from a script, cannot edit source");
2221 }
2222 }
2223 else {
2224 BKE_report(op->reports, RPT_ERROR, "Active button match cannot be found");
2226 }
2227
2228 ui_editsource_active_but_clear();
2229
2230 // printf("%s: end\n", __func__);
2231
2232 return ret;
2233 }
2234
2235 BKE_report(op->reports, RPT_ERROR, "Active button not found");
2236 return OPERATOR_CANCELLED;
2237}
2238
2239static void UI_OT_editsource(wmOperatorType *ot)
2240{
2241 /* identifiers */
2242 ot->name = "Edit Source";
2243 ot->idname = "UI_OT_editsource";
2244 ot->description = "Edit UI source code of the active button";
2245
2246 /* callbacks */
2247 ot->exec = editsource_exec;
2248}
2249
2251
2252#endif /* WITH_PYTHON */
2253
2254/* -------------------------------------------------------------------- */
2257
2259{
2260 BLT_lang_init();
2262 BLT_lang_set(nullptr);
2264 return OPERATOR_FINISHED;
2265}
2266
2268{
2269 /* identifiers */
2270 ot->name = "Reload Translation";
2271 ot->idname = "UI_OT_reloadtranslation";
2272 ot->description = "Force a full reload of UI translation";
2273
2274 /* callbacks */
2275 ot->exec = reloadtranslation_exec;
2276}
2277
2279
2280/* -------------------------------------------------------------------- */
2283
2285{
2286 bScreen *screen = CTX_wm_screen(C);
2287 const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
2288 ARegion *region_prev = CTX_wm_region(C);
2289 ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : nullptr;
2290
2291 if (region == nullptr) {
2292 region = region_prev;
2293 }
2294
2295 if (region == nullptr) {
2296 return OPERATOR_PASS_THROUGH;
2297 }
2298
2299 CTX_wm_region_set(C, region);
2301 CTX_wm_region_set(C, region_prev);
2302
2303 if (but == nullptr) {
2304 return OPERATOR_PASS_THROUGH;
2305 }
2306 if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) {
2307 return OPERATOR_PASS_THROUGH;
2308 }
2309
2310 /* Weak, this is a workaround for 'UI_but_is_tool', which checks the operator type,
2311 * having this avoids a minor drawing glitch. */
2312 void *but_optype = but->optype;
2313
2314 UI_but_execute(C, region, but);
2315
2316 but->optype = static_cast<wmOperatorType *>(but_optype);
2317
2319
2320 return OPERATOR_FINISHED;
2321}
2322
2324{
2325 ot->name = "Press Button";
2326 ot->idname = "UI_OT_button_execute";
2327 ot->description = "Presses active button";
2328
2329 ot->invoke = ui_button_press_invoke;
2330 ot->flag = OPTYPE_INTERNAL;
2331
2332 RNA_def_boolean(ot->srna, "skip_depressed", false, "Skip Depressed", "");
2333}
2334
2336
2337/* -------------------------------------------------------------------- */
2340
2342{
2344
2345 if (but) {
2347 }
2348
2349 return OPERATOR_FINISHED;
2350}
2351
2353{
2354 ot->name = "Clear Button String";
2355 ot->idname = "UI_OT_button_string_clear";
2356 ot->description = "Unsets the text of the active button";
2357
2360 ot->flag = OPTYPE_INTERNAL;
2361}
2362
2364
2365/* -------------------------------------------------------------------- */
2368
2369bool UI_drop_color_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
2370{
2371 /* should only return true for regions that include buttons, for now
2372 * return true always */
2373 if (drag->type == WM_DRAG_COLOR) {
2375 ARegion *region = CTX_wm_region(C);
2376
2378 return true;
2379 }
2380
2381 if (sima && (sima->mode == SI_MODE_PAINT) && sima->image &&
2382 (region && region->regiontype == RGN_TYPE_WINDOW))
2383 {
2384 return true;
2385 }
2386 }
2387
2388 return false;
2389}
2390
2391void UI_drop_color_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
2392{
2393 uiDragColorHandle *drag_info = static_cast<uiDragColorHandle *>(drag->poin);
2394
2395 RNA_float_set_array(drop->ptr, "color", drag_info->color);
2396 RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
2397 RNA_boolean_set(drop->ptr, "has_alpha", drag_info->has_alpha);
2398}
2399
2401{
2402 ARegion *region = CTX_wm_region(C);
2403 uiBut *but = nullptr;
2404
2405 float color[4];
2406 RNA_float_get_array(op->ptr, "color", color);
2407
2408 const bool gamma = RNA_boolean_get(op->ptr, "gamma");
2409 const bool has_alpha = RNA_boolean_get(op->ptr, "has_alpha");
2410
2411 /* find button under mouse, check if it has RNA color property and
2412 * if it does copy the data */
2413 but = ui_region_find_active_but(region);
2414
2415 if (but && but->type == UI_BTYPE_COLOR && but->rnaprop) {
2416 if (!has_alpha) {
2417 color[3] = 1.0f;
2418 }
2419
2421 if (!gamma) {
2423 }
2425 RNA_property_update(C, &but->rnapoin, but->rnaprop);
2426 }
2427 else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
2428 if (gamma) {
2430 }
2432 RNA_property_update(C, &but->rnapoin, but->rnaprop);
2433 }
2434
2435 if (UI_but_flag_is_set(but, UI_BUT_UNDO)) {
2437 }
2438 }
2439 else {
2440 if (!gamma) {
2442 }
2443
2444 ED_imapaint_bucket_fill(C, color, op, event->mval);
2445 }
2446
2447 ED_region_tag_redraw(region);
2448
2449 return OPERATOR_FINISHED;
2450}
2451
2453{
2454 ot->name = "Drop Color";
2455 ot->idname = "UI_OT_drop_color";
2456 ot->description = "Drop colors to buttons";
2457
2458 ot->invoke = drop_color_invoke;
2460
2461 ot->flag = OPTYPE_INTERNAL;
2462
2464 ot->srna, "color", 4, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
2466 ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected");
2468 ot->srna, "has_alpha", false, "Has Alpha", "The source color contains an Alpha component");
2469}
2470
2472
2473/* -------------------------------------------------------------------- */
2476
2478{
2480 return false;
2481 }
2482
2484 if (!but) {
2485 return false;
2486 }
2487
2488 if (but->flag & UI_BUT_DISABLED) {
2489 return false;
2490 }
2491
2492 return true;
2493}
2494
2496{
2498 char *str = RNA_string_get_alloc(op->ptr, "string", nullptr, 0, nullptr);
2499
2500 if (str) {
2502 MEM_freeN(str);
2503 }
2504
2505 return OPERATOR_FINISHED;
2506}
2507
2509{
2510 ot->name = "Drop Name";
2511 ot->idname = "UI_OT_drop_name";
2512 ot->description = "Drop name to button";
2513
2514 ot->poll = drop_name_poll;
2515 ot->invoke = drop_name_invoke;
2516 ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
2517
2519 ot->srna, "string", nullptr, 0, "String", "The string value to drop into the button");
2520}
2521
2523
2524/* -------------------------------------------------------------------- */
2527
2529{
2530 const ARegion *region = CTX_wm_region(C);
2531 if (!region) {
2532 return false;
2533 }
2534 const wmWindow *win = CTX_wm_window(C);
2535 const uiList *list = UI_list_find_mouse_over(region, win->eventstate);
2536
2537 return list != nullptr;
2538}
2539
2545{
2546 if (list->filter_flag & UILST_FLT_SHOW) {
2547 /* Nothing to be done. */
2548 return false;
2549 }
2550
2551 list->filter_flag |= UILST_FLT_SHOW;
2552 return true;
2553}
2554
2556 wmOperator * /*op*/,
2557 const wmEvent *event)
2558{
2559 ARegion *region = CTX_wm_region(C);
2560 uiList *list = UI_list_find_mouse_over(region, event);
2561 /* Poll should check. */
2562 BLI_assert(list != nullptr);
2563
2566 }
2567
2568 if (!UI_textbutton_activate_rna(C, region, list, "filter_name")) {
2569 return OPERATOR_CANCELLED;
2570 }
2571
2572 return OPERATOR_FINISHED;
2573}
2574
2576{
2577 ot->name = "List Filter";
2578 ot->idname = "UI_OT_list_start_filter";
2579 ot->description = "Start entering filter text for the list in focus";
2580
2582 ot->poll = ui_list_focused_poll;
2583}
2584
2586
2587/* -------------------------------------------------------------------- */
2590
2592{
2593 const wmWindow *win = CTX_wm_window(C);
2594 if (!(win && win->eventstate)) {
2595 return nullptr;
2596 }
2597
2598 const ARegion *region = CTX_wm_region(C);
2599 if (!region) {
2600 return nullptr;
2601 }
2602 return UI_region_view_find_at(region, win->eventstate->xy, 0);
2603}
2604
2606{
2608 return view != nullptr;
2609}
2610
2612 wmOperator * /*op*/,
2613 const wmEvent *event)
2614{
2615 const ARegion *region = CTX_wm_region(C);
2616 const blender::ui::AbstractView *hovered_view = UI_region_view_find_at(region, event->xy, 0);
2617
2618 if (!hovered_view->begin_filtering(*C)) {
2620 }
2621
2622 return OPERATOR_FINISHED;
2623}
2624
2626{
2627 ot->name = "View Filter";
2628 ot->idname = "UI_OT_view_start_filter";
2629 ot->description = "Start entering filter text for the data-set in focus";
2630
2632 ot->poll = ui_view_focused_poll;
2633
2634 ot->flag = OPTYPE_INTERNAL;
2635}
2636
2638
2639/* -------------------------------------------------------------------- */
2642
2644{
2645 const wmWindow *win = CTX_wm_window(C);
2646 if (!(win && win->eventstate)) {
2647 return false;
2648 }
2649 const ARegion *region = CTX_wm_region(C);
2650 if (region == nullptr) {
2651 return false;
2652 }
2653 return region_views_find_drop_target_at(region, win->eventstate->xy) != nullptr;
2654}
2655
2657{
2658 if (event->custom != EVT_DATA_DRAGDROP) {
2660 }
2661
2662 ARegion *region = CTX_wm_region(C);
2663 std::unique_ptr<DropTargetInterface> drop_target = region_views_find_drop_target_at(region,
2664 event->xy);
2665
2667 *C, *region, *event, *drop_target, *static_cast<const ListBase *>(event->customdata)))
2668 {
2670 }
2671
2672 ED_region_tag_redraw(region);
2673 return OPERATOR_FINISHED;
2674}
2675
2677{
2678 ot->name = "View Drop";
2679 ot->idname = "UI_OT_view_drop";
2680 ot->description = "Drag and drop onto a data-set or item within the data-set";
2681
2682 ot->invoke = ui_view_drop_invoke;
2683 ot->poll = ui_view_drop_poll;
2684
2685 ot->flag = OPTYPE_INTERNAL;
2686}
2687
2689
2690/* -------------------------------------------------------------------- */
2693
2695{
2697 if (!view) {
2698 return false;
2699 }
2700
2701 return view->supports_scrolling();
2702}
2703
2705 wmOperator * /*op*/,
2706 const wmEvent *event)
2707{
2708 ARegion *region = CTX_wm_region(C);
2709 int type = event->type;
2710 bool invert_direction = false;
2711
2712 if (type == MOUSEPAN) {
2713 int dummy_val;
2714 ui_pan_to_scroll(event, &type, &dummy_val);
2715
2716 /* 'ui_pan_to_scroll' gives the absolute direction. */
2717 if (event->flag & WM_EVENT_SCROLL_INVERT) {
2718 invert_direction = true;
2719 }
2720 }
2721
2723 std::optional<ViewScrollDirection> direction =
2724 [type, invert_direction]() -> std::optional<ViewScrollDirection> {
2725 switch (type) {
2726 case WHEELUPMOUSE:
2727 return invert_direction ? ViewScrollDirection::DOWN : ViewScrollDirection::UP;
2728 case WHEELDOWNMOUSE:
2729 return invert_direction ? ViewScrollDirection::UP : ViewScrollDirection::DOWN;
2730 default:
2731 return std::nullopt;
2732 }
2733 }();
2734 if (!direction) {
2735 return OPERATOR_CANCELLED;
2736 }
2737
2738 BLI_assert(view->supports_scrolling());
2739 if (view->is_fully_visible()) {
2740 /* The view does not need scrolling currently, so pass the event through. This allows scrolling
2741 * e.g. the entire region even when hovering a tree-view that supports scrolling generally. */
2742 return OPERATOR_PASS_THROUGH;
2743 }
2744 view->scroll(*direction);
2745
2746 ED_region_tag_redraw(region);
2747 return OPERATOR_FINISHED;
2748}
2749
2751{
2752 ot->name = "View Scroll";
2753 ot->idname = "UI_OT_view_scroll";
2754
2755 ot->invoke = ui_view_scroll_invoke;
2756 ot->poll = ui_view_scroll_poll;
2757
2758 ot->flag = OPTYPE_INTERNAL;
2759}
2760
2762
2763/* -------------------------------------------------------------------- */
2771
2773{
2774 const ARegion *region = CTX_wm_region(C);
2775 if (region == nullptr) {
2776 return false;
2777 }
2779 return active_item != nullptr && UI_view_item_can_rename(*active_item);
2780}
2781
2783{
2784 ARegion *region = CTX_wm_region(C);
2786
2787 UI_view_item_begin_rename(*active_item);
2788 ED_region_tag_redraw(region);
2789
2790 return OPERATOR_FINISHED;
2791}
2792
2794{
2795 ot->name = "Rename View Item";
2796 ot->idname = "UI_OT_view_item_rename";
2797 ot->description = "Rename the active item in the data-set view";
2798
2801 /* Could get a custom tooltip via the `get_description()` callback and another overridable
2802 * function of the view. */
2803
2804 ot->flag = OPTYPE_INTERNAL;
2805}
2806
2807
2808/* -------------------------------------------------------------------- */
2812
2814{
2815 PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
2816 const Object *ob = static_cast<const Object *>(ptr.data);
2817 if (ob == nullptr) {
2818 return false;
2819 }
2820
2821 PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
2822 if (RNA_pointer_is_null(&mat_slot)) {
2823 return false;
2824 }
2825
2826 return true;
2827}
2828
2830{
2831 Main *bmain = CTX_data_main(C);
2832
2834 bmain, op->ptr, ID_MA);
2835 if (ma == nullptr) {
2836 return OPERATOR_CANCELLED;
2837 }
2838
2839 PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object);
2840 Object *ob = static_cast<Object *>(ptr.data);
2841 BLI_assert(ob);
2842
2843 PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
2844 BLI_assert(mat_slot.data);
2845 const int target_slot = RNA_int_get(&mat_slot, "slot_index") + 1;
2846
2847 /* only drop grease pencil material on grease pencil objects */
2848 if ((ma->gp_style != nullptr) && (ob->type != OB_GREASE_PENCIL)) {
2849 return OPERATOR_CANCELLED;
2850 }
2851
2852 BKE_object_material_assign(bmain, ob, ma, target_slot, BKE_MAT_ASSIGN_USERPREF);
2853
2858
2859 return OPERATOR_FINISHED;
2860}
2861
2863{
2864 ot->name = "Drop Material in Material slots";
2865 ot->description = "Drag material to Material slots in Properties";
2866 ot->idname = "UI_OT_drop_material";
2867
2868 ot->poll = ui_drop_material_poll;
2869 ot->exec = ui_drop_material_exec;
2871
2873}
2874
2876
2877/* -------------------------------------------------------------------- */
2880
2882{
2883 using namespace blender::ui;
2896#ifdef WITH_PYTHON
2897 WM_operatortype_append(UI_OT_editsource);
2898#endif
2902
2904
2909
2916
2917 /* external */
2926}
2927
2929{
2930 WM_keymap_ensure(keyconf, "User Interface", SPACE_EMPTY, RGN_TYPE_WINDOW);
2931
2932 eyedropper_modal_keymap(keyconf);
2934}
2935
Functions to insert, delete or modify keyframes.
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:96
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
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:165
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.
@ BKE_MAT_ASSIGN_USERPREF
void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
ARegion * BKE_screen_find_region_xy(const bScreen *screen, int regiontype, const int xy[2]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void BLF_cache_clear()
Definition blf.cc:98
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
struct GHash GHash
Definition BLI_ghash.h:39
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:295
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition BLI_ghash.cc:911
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
Definition BLI_ghash.cc:895
BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:307
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
#define FILE_MAX
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, float limit)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
unsigned int uint
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define ELEM(...)
#define STREQ(a, b)
void BLT_lang_set(const char *)
Definition blt_lang.cc:250
void BLT_lang_init()
Definition blt_lang.cc:192
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_SELECT
Definition DNA_ID.h:1009
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1012
@ LIBOVERRIDE_OP_NOOP
Definition DNA_ID.h:218
@ LIBOVERRIDE_OP_ADD
Definition DNA_ID.h:223
@ LIBOVERRIDE_OP_REPLACE
Definition DNA_ID.h:220
@ LIBOVERRIDE_OP_MULTIPLY
Definition DNA_ID.h:227
@ ID_TAG_DOIT
Definition DNA_ID.h:944
@ 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_GREASE_PENCIL
@ OB_ARMATURE
@ UILST_FLT_SHOW
@ RGN_TYPE_WINDOW
#define RGN_TYPE_ANY
@ SPACE_EMPTY
@ SI_MODE_PAINT
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ 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:98
void ED_region_do_layout(bContext *C, ARegion *region)
Definition area.cc:479
void ED_region_do_draw(bContext *C, ARegion *region)
Definition area.cc:502
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:99
static AppView * view
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
Read Guarded memory(de)allocation.
@ RNA_OVERRIDE_STATUS_OVERRIDABLE
@ RNA_OVERRIDE_STATUS_OVERRIDDEN
PropertyType
Definition RNA_types.hh:149
@ PROP_FLOAT
Definition RNA_types.hh:152
@ PROP_BOOLEAN
Definition RNA_types.hh:150
@ PROP_ENUM
Definition RNA_types.hh:154
@ PROP_INT
Definition RNA_types.hh:151
@ PROP_STRING
Definition RNA_types.hh:153
@ PROP_POINTER
Definition RNA_types.hh:155
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_COLOR
Definition RNA_types.hh:248
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:260
#define C
Definition RandGen.cpp:29
bool UI_view_item_can_rename(const blender::ui::AbstractViewItem &item)
bool UI_textbutton_activate_rna(const bContext *C, ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
uiList * UI_list_find_mouse_over(const ARegion *region, const wmEvent *event)
blender::ui::AbstractView * UI_region_view_find_at(const ARegion *region, const int xy[2], int pad)
bool UI_editsource_enable_check()
void UI_reinit_font()
uiBut * UI_context_active_but_get(const bContext *C)
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
void UI_but_execute(const bContext *C, ARegion *region, uiBut *but)
void UI_view_item_begin_rename(blender::ui::AbstractViewItem &item)
void UI_editsource_active_but_test(uiBut *but)
blender::ui::AbstractViewItem * UI_region_views_find_active_item(const ARegion *region)
uiBut * UI_context_active_but_prop_get(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
uiBut * UI_but_active_drop_name_button(const bContext *C)
uiBut * UI_context_active_but_get_respect_popup(const bContext *C)
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
void UI_context_active_but_prop_handle(bContext *C, bool handle_undo)
bool UI_but_active_drop_color(bContext *C)
void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen)
@ UI_BTYPE_SEARCH_MENU
@ UI_BTYPE_COLOR
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
bool UI_but_flag_is_set(uiBut *but, int flag)
#define NC_WINDOW
Definition WM_types.hh:372
@ WM_EVENT_SCROLL_INVERT
Definition WM_types.hh:674
#define NC_WM
Definition WM_types.hh:371
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_ANIMATION
Definition WM_types.hh:385
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:416
#define ND_KEYFRAME_PROP
Definition WM_types.hh:492
#define NC_MATERIAL
Definition WM_types.hh:377
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
@ WM_DRAG_COLOR
Definition WM_types.hh:1215
#define ND_OB_SHADING
Definition WM_types.hh:454
#define ND_SPACE_VIEW3D
Definition WM_types.hh:525
#define NC_OBJECT
Definition WM_types.hh:376
#define ND_SHADING_LINKS
Definition WM_types.hh:476
#define NC_SPACE
Definition WM_types.hh:389
std::swap * new_lb
Definition blendfile.cc:598
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:252
int64_t size() const
int64_t remove_if(Predicate &&predicate)
void append(const T &value)
bool is_empty() const
void resize(const int64_t new_size)
Span< T > as_span() const
virtual bool begin_filtering(const bContext &C) const
void ANIM_copy_as_driver(ID *target_id, const char *target_path, const char *var_name)
Definition drivers.cc:784
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)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
bool all(VecOp< bool, D >) RET
#define printf(...)
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
#define ID_CHECK_UNDO(id)
#define ID_IS_LINKED(_id)
#define ID_IS_EDITABLE(_id)
#define GS(a)
static bool ui_drop_material_poll(bContext *C, wmDrag *drag, const wmEvent *)
static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
wmKeyMap * eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
wmKeyMap * eyedropper_modal_keymap(wmKeyConfig *keyconf)
void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
@ UI_SELECT_DRAW
@ UI_SELECT
ID * ui_template_id_liboverride_hierarchy_make(bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
bool ui_jump_to_target_button_poll(bContext *C)
uiBut * ui_region_find_active_but(ARegion *region) ATTR_WARN_UNUSED_RESULT
void ui_rna_collection_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first)
static wmOperatorStatus ui_drop_material_exec(bContext *C, wmOperator *op)
static wmOperatorStatus drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus copy_to_selected_button_exec(bContext *C, wmOperator *op)
static bool ui_list_unhide_filter_options(uiList *list)
static void UI_OT_override_type_set_button(wmOperatorType *ot)
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 wmOperatorStatus reloadtranslation_exec(bContext *, wmOperator *)
static bool ui_view_focused_poll(bContext *C)
static wmOperatorStatus override_remove_button_exec(bContext *C, wmOperator *op)
static wmOperatorStatus ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool ui_list_focused_poll(bContext *C)
static void UI_OT_button_execute(wmOperatorType *ot)
static bool override_remove_button_poll(bContext *C)
static bool ui_view_drop_poll(bContext *C)
static void ui_region_redraw_immediately(bContext *C, ARegion *region)
static wmOperatorStatus jump_to_target_button_exec(bContext *C, wmOperator *)
static PointerRNA rnapointer_pchan_to_bone(const PointerRNA &pchan_ptr)
static wmOperatorStatus operator_button_property_finish(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
static wmOperatorStatus copy_as_driver_button_exec(bContext *C, wmOperator *op)
static bool reset_default_button_poll(bContext *C)
static bool override_idtemplate_menu_poll(const bContext *C_const, MenuType *)
static bool copy_driver_to_selected_button_poll(bContext *C)
static void UI_OT_copy_data_path_button(wmOperatorType *ot)
static void UI_OT_reloadtranslation(wmOperatorType *ot)
bool ui_jump_to_target_button_poll(bContext *C)
static wmOperatorStatus operator_button_property_finish_with_undo(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
static wmOperatorStatus ui_view_item_rename_exec(bContext *C, wmOperator *)
static bool copy_data_path_button_poll(bContext *C)
static void UI_OT_copy_python_command_button(wmOperatorType *ot)
static void UI_OT_assign_default_button(wmOperatorType *ot)
static bool ui_view_scroll_poll(bContext *C)
static wmOperatorStatus override_idtemplate_make_exec(bContext *C, wmOperator *)
static void UI_OT_override_idtemplate_clear(wmOperatorType *ot)
static wmOperatorStatus override_idtemplate_clear_exec(bContext *C, wmOperator *)
void ED_operatortypes_ui()
bool UI_drop_color_poll(bContext *C, wmDrag *drag, const wmEvent *)
static void UI_OT_list_start_filter(wmOperatorType *ot)
static bool copy_driver_to_selected_button(bContext *C, bool copy_entire_array, const bool poll)
static bool copy_to_selected_button_poll(bContext *C)
static wmOperatorStatus reset_default_button_exec(bContext *C, wmOperator *op)
static wmOperatorStatus button_string_clear_exec(bContext *C, wmOperator *)
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
static wmOperatorStatus override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *)
void UI_drop_color_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static wmOperatorStatus override_type_set_button_exec(bContext *C, wmOperator *op)
static AbstractView * get_view_focused(bContext *C)
static void UI_OT_view_start_filter(wmOperatorType *ot)
static void UI_OT_jump_to_target_button(wmOperatorType *ot)
static void UI_OT_drop_name(wmOperatorType *ot)
static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
static wmOperatorStatus ui_view_drop_invoke(bContext *C, wmOperator *, const wmEvent *event)
static void UI_OT_copy_driver_to_selected_button(wmOperatorType *ot)
static void override_idtemplate_menu_draw(const bContext *, Menu *menu)
static void UI_OT_drop_material(wmOperatorType *ot)
static void UI_OT_view_scroll(wmOperatorType *ot)
static bool override_idtemplate_reset_poll(bContext *C)
static wmOperatorStatus override_idtemplate_reset_exec(bContext *C, wmOperator *)
static bool jump_to_target_button(bContext *C, bool poll)
static void UI_OT_override_remove_button(wmOperatorType *ot)
static void UI_OT_button_string_clear(wmOperatorType *ot)
@ UIOverride_Type_Replace
@ UIOverride_Type_Difference
@ UIOverride_Type_NOOP
@ UIOverride_Type_Factor
static bool drop_name_poll(bContext *C)
bool UI_context_copy_to_selected_list(bContext *C, PointerRNA *ptr, PropertyRNA *prop, blender::Vector< PointerRNA > *r_lb, bool *r_use_path_from_id, std::optional< std::string > *r_path)
#define NOT_RNA_NULL(assignment)
static bool copy_python_command_button_poll(bContext *C)
static wmOperatorStatus copy_driver_to_selected_button_exec(bContext *C, wmOperator *op)
static wmOperatorStatus copy_python_command_button_exec(bContext *C, wmOperator *)
static void UI_OT_reset_default_button(wmOperatorType *ot)
static wmOperatorStatus unset_property_button_exec(bContext *C, wmOperator *)
void ED_keymap_ui(wmKeyConfig *keyconf)
User Interface Keymap.
static void UI_OT_override_idtemplate_make(wmOperatorType *ot)
static wmOperatorStatus ui_list_start_filter_invoke(bContext *C, wmOperator *, const wmEvent *event)
static bool assign_default_button_poll(bContext *C)
static void UI_OT_view_drop(wmOperatorType *ot)
static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
static bool override_idtemplate_clear_poll(bContext *C)
static EnumPropertyItem override_type_items[]
static wmOperatorStatus ui_view_start_filter_invoke(bContext *C, wmOperator *, const wmEvent *event)
static void ui_context_fcurve_modifiers_via_fcurve(bContext *C, blender::Vector< PointerRNA > *r_lb, FModifier *source)
static wmOperatorStatus ui_view_scroll_invoke(bContext *C, wmOperator *, const wmEvent *event)
static bool ui_drop_material_poll(bContext *C)
static wmOperatorStatus assign_default_button_exec(bContext *C, wmOperator *)
static bool copy_as_driver_button_poll(bContext *C)
static wmOperatorStatus drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void override_idtemplate_menu()
static void UI_OT_drop_color(wmOperatorType *ot)
bool UI_context_copy_to_selected_check(PointerRNA *ptr, PointerRNA *ptr_link, PropertyRNA *prop, const char *path, bool use_path_from_id, PointerRNA *r_ptr, PropertyRNA **r_prop)
static bool ui_view_item_rename_poll(bContext *C)
static void UI_OT_view_item_rename(wmOperatorType *ot)
static bool override_idtemplate_make_poll(bContext *C)
static wmOperatorStatus copy_data_path_button_exec(bContext *C, wmOperator *op)
static bool override_idtemplate_poll(bContext *C, const bool is_create_op)
static void ui_context_selected_bones_via_pose(bContext *C, blender::Vector< PointerRNA > *r_lb)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
bNode & node_find_node(bNodeTree &ntree, bNodeSocket &socket)
Definition node.cc:3613
bool jump_to_object(bContext *C, Object *ob, bool reveal_hidden)
Base * find_first_by_data_id(const Scene *scene, ViewLayer *view_layer, ID *id)
bool jump_to_bone(bContext *C, Object *ob, const char *bone_name, bool reveal_hidden)
blender::Vector< FCurve * > get_property_drivers(PointerRNA *ptr, PropertyRNA *prop, bool get_all, int index, bool *r_is_array_prop)
int paste_property_drivers(blender::Span< FCurve * > src_drivers, bool is_array_prop, PointerRNA *dst_ptr, PropertyRNA *dst_prop)
void UI_OT_eyedropper_colorramp(wmOperatorType *ot)
void UI_OT_eyedropper_colorramp_point(wmOperatorType *ot)
bool drop_target_apply_drop(bContext &C, const ARegion &region, const wmEvent &event, const DropTargetInterface &drop_target, const ListBase &drags)
void UI_OT_eyedropper_bone(wmOperatorType *ot)
std::unique_ptr< DropTargetInterface > region_views_find_drop_target_at(const ARegion *region, const int xy[2])
#define hash
Definition noise_c.cc:154
void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno)
return ret
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
bool RNA_property_array_check(PropertyRNA *prop)
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
PropertyType RNA_property_type(PropertyRNA *prop)
const PointerRNA PointerRNA_NULL
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set_array_at_most(PointerRNA *ptr, PropertyRNA *prop, const float *values, int values_num)
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)
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_discrete(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:920
std::optional< std::string > RNA_path_from_real_ID_to_property_index(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, ID **r_real_id)
Definition rna_path.cc:1178
std::optional< std::string > RNA_path_full_property_py_ex(const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
Definition rna_path.cc:1283
std::optional< std::string > RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, PropertyRNA *prop, const StructRNA *type)
Definition rna_path.cc:1196
std::optional< std::string > RNA_path_full_struct_py(const PointerRNA *ptr)
Definition rna_path.cc:1267
std::optional< std::string > RNA_path_from_ID_to_property_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
Definition rna_path.cc:1156
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1173
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:560
std::string RNA_path_from_ptr_to_property_index(const PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
Definition rna_path.cc:1148
#define FLT_MAX
Definition stdcycles.h:14
ARegionRuntimeHandle * runtime
ListBase drivers
struct Object * object
ListBase modifiers
char name[64]
struct ID * reference
Definition DNA_ID.h:324
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
char name[66]
Definition DNA_ID.h:415
struct MaterialGPencilStyle * gp_style
char label[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, MenuType *mt)
char idname[BKE_ST_MAXNAME]
void(* draw)(const bContext *C, Menu *menu)
uiLayout * layout
ustring name
Definition graph/node.h:177
struct bNodeTree * node_group
ID * owner_id
Definition RNA_types.hh:51
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
struct RenderData r
struct Image * image
struct Base * basact
ListBase * edbo
char idname[64]
struct Bone * bone
uiButSearchUpdateFn items_update_fn
PropertyRNA * rnaprop
wmOperatorType * optype
eButType type
uchar unit_type
std::string drawstr
PointerRNA rnapoin
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, wmOperatorCallContext context, eUI_Item_Flag flag)
eWM_DragDataType type
Definition WM_types.hh:1327
void * poin
Definition WM_types.hh:1328
PointerRNA * ptr
Definition WM_types.hh:1415
short custom
Definition WM_types.hh:790
int xy[2]
Definition WM_types.hh:758
int mval[2]
Definition WM_types.hh:760
eWM_EventFlag flag
Definition WM_types.hh:785
void * customdata
Definition WM_types.hh:804
struct ReportList * reports
struct PointerRNA * ptr
struct wmEvent * eventstate
i
Definition text_draw.cc:230
#define N_(msgid)
void WM_draw_region_viewport_unbind(ARegion *region)
Definition wm_draw.cc:1697
void WM_draw_region_viewport_bind(ARegion *region)
Definition wm_draw.cc:1692
void WM_main_add_notifier(uint type, void *reference)
wmOperatorStatus 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:4226
wmOperatorType * ot
Definition wm_files.cc:4225
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:893
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)
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)
wmOperatorStatus WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_clipboard_text_set(const char *buf, bool selection)