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