Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/object/object_select.c
| Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_rand.h" | #include "BLI_rand.h" | ||||
| #include "BLI_string_utils.h" | #include "BLI_string_utils.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "BKE_collection.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_group.h" | |||||
| #include "BKE_layer.h" | #include "BKE_layer.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_material.h" | #include "BKE_material.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_particle.h" | #include "BKE_particle.h" | ||||
| #include "BKE_paint.h" | #include "BKE_paint.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| ▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | static bool object_select_all_by_material(bContext *C, Material *mat) | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static bool object_select_all_by_dup_group(bContext *C, Object *ob) | static bool object_select_all_by_dup_group(bContext *C, Object *ob) | ||||
| { | { | ||||
| bool changed = false; | bool changed = false; | ||||
| Group *dup_group = (ob->transflag & OB_DUPLIGROUP) ? ob->dup_group : NULL; | Collection *dup_group = (ob->transflag & OB_DUPLIGROUP) ? ob->dup_group : NULL; | ||||
| CTX_DATA_BEGIN (C, Base *, base, visible_bases) | CTX_DATA_BEGIN (C, Base *, base, visible_bases) | ||||
| { | { | ||||
| if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { | if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { | ||||
| Group *dup_group_other = (base->object->transflag & OB_DUPLIGROUP) ? base->object->dup_group : NULL; | Collection *dup_group_other = (base->object->transflag & OB_DUPLIGROUP) ? base->object->dup_group : NULL; | ||||
| if (dup_group == dup_group_other) { | if (dup_group == dup_group_other) { | ||||
| ED_object_base_select(base, BA_SELECT); | ED_object_base_select(base, BA_SELECT); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| ▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | |||||
| enum { | enum { | ||||
| OBJECT_GRPSEL_CHILDREN_RECURSIVE = 0, | OBJECT_GRPSEL_CHILDREN_RECURSIVE = 0, | ||||
| OBJECT_GRPSEL_CHILDREN = 1, | OBJECT_GRPSEL_CHILDREN = 1, | ||||
| OBJECT_GRPSEL_PARENT = 2, | OBJECT_GRPSEL_PARENT = 2, | ||||
| OBJECT_GRPSEL_SIBLINGS = 3, | OBJECT_GRPSEL_SIBLINGS = 3, | ||||
| OBJECT_GRPSEL_TYPE = 4, | OBJECT_GRPSEL_TYPE = 4, | ||||
| OBJECT_GRPSEL_COLLECTION = 5, | OBJECT_GRPSEL_COLLECTION = 5, | ||||
| OBJECT_GRPSEL_GROUP = 6, | |||||
| OBJECT_GRPSEL_HOOK = 7, | OBJECT_GRPSEL_HOOK = 7, | ||||
| OBJECT_GRPSEL_PASS = 8, | OBJECT_GRPSEL_PASS = 8, | ||||
| OBJECT_GRPSEL_COLOR = 9, | OBJECT_GRPSEL_COLOR = 9, | ||||
| OBJECT_GRPSEL_KEYINGSET = 10, | OBJECT_GRPSEL_KEYINGSET = 10, | ||||
| OBJECT_GRPSEL_LAMP_TYPE = 11, | OBJECT_GRPSEL_LAMP_TYPE = 11, | ||||
| }; | }; | ||||
| static const EnumPropertyItem prop_select_grouped_types[] = { | static const EnumPropertyItem prop_select_grouped_types[] = { | ||||
| {OBJECT_GRPSEL_CHILDREN_RECURSIVE, "CHILDREN_RECURSIVE", 0, "Children", ""}, | {OBJECT_GRPSEL_CHILDREN_RECURSIVE, "CHILDREN_RECURSIVE", 0, "Children", ""}, | ||||
| {OBJECT_GRPSEL_CHILDREN, "CHILDREN", 0, "Immediate Children", ""}, | {OBJECT_GRPSEL_CHILDREN, "CHILDREN", 0, "Immediate Children", ""}, | ||||
| {OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""}, | {OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""}, | ||||
| {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"}, | {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"}, | ||||
| {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"}, | {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"}, | ||||
| {OBJECT_GRPSEL_COLLECTION, "COLLECTION", 0, "Collection", "Shared collection"}, | {OBJECT_GRPSEL_COLLECTION, "COLLECTION", 0, "Collection", "Shared collection"}, | ||||
| {OBJECT_GRPSEL_GROUP, "GROUP", 0, "Group", "Shared group"}, | |||||
| {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""}, | {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""}, | ||||
| {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"}, | {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"}, | ||||
| {OBJECT_GRPSEL_COLOR, "COLOR", 0, "Color", "Object Color"}, | {OBJECT_GRPSEL_COLOR, "COLOR", 0, "Color", "Object Color"}, | ||||
| {OBJECT_GRPSEL_KEYINGSET, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"}, | {OBJECT_GRPSEL_KEYINGSET, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"}, | ||||
| {OBJECT_GRPSEL_LAMP_TYPE, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"}, | {OBJECT_GRPSEL_LAMP_TYPE, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"}, | ||||
| {0, NULL, 0, NULL, NULL} | {0, NULL, 0, NULL, NULL} | ||||
| }; | }; | ||||
| Show All 35 Lines | if (baspar && BASE_SELECTABLE(baspar)) { | ||||
| ED_object_base_select(baspar, BA_SELECT); | ED_object_base_select(baspar, BA_SELECT); | ||||
| ED_object_base_activate(C, baspar); | ED_object_base_activate(C, baspar); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| #define GROUP_MENU_MAX 24 | #define COLLECTION_MENU_MAX 24 | ||||
| static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in the same group as the active */ | static bool select_grouped_collection(bContext *C, Object *ob) /* Select objects in the same group as the active */ | ||||
| { | { | ||||
| bool changed = false; | bool changed = false; | ||||
| Group *group, *ob_groups[GROUP_MENU_MAX]; | Collection *collection, *ob_collections[COLLECTION_MENU_MAX]; | ||||
| int group_count = 0, i; | int collection_count = 0, i; | ||||
| uiPopupMenu *pup; | uiPopupMenu *pup; | ||||
| uiLayout *layout; | uiLayout *layout; | ||||
| for (group = CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group = group->id.next) { | for (collection = CTX_data_main(C)->collection.first; collection && collection_count < COLLECTION_MENU_MAX; collection = collection->id.next) { | ||||
| if (BKE_group_object_exists(group, ob)) { | if (BKE_collection_has_object(collection, ob)) { | ||||
| ob_groups[group_count] = group; | ob_collections[collection_count] = collection; | ||||
| group_count++; | collection_count++; | ||||
| } | } | ||||
| } | } | ||||
| if (!group_count) | if (!collection_count) | ||||
| return 0; | return 0; | ||||
| else if (group_count == 1) { | else if (collection_count == 1) { | ||||
| group = ob_groups[0]; | collection = ob_collections[0]; | ||||
| CTX_DATA_BEGIN (C, Base *, base, visible_bases) | CTX_DATA_BEGIN (C, Base *, base, visible_bases) | ||||
| { | { | ||||
| if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { | if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { | ||||
| if (BKE_group_object_exists(group, base->object)) { | if (BKE_collection_has_object(collection, base->object)) { | ||||
| ED_object_base_select(base, BA_SELECT); | ED_object_base_select(base, BA_SELECT); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /* build the menu. */ | /* build the menu. */ | ||||
| pup = UI_popup_menu_begin(C, IFACE_("Select Group"), ICON_NONE); | pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); | ||||
| layout = UI_popup_menu_layout(pup); | layout = UI_popup_menu_layout(pup); | ||||
| for (i = 0; i < group_count; i++) { | for (i = 0; i < collection_count; i++) { | ||||
| group = ob_groups[i]; | collection = ob_collections[i]; | ||||
| uiItemStringO(layout, group->id.name + 2, 0, "OBJECT_OT_select_same_group", "group", group->id.name + 2); | uiItemStringO(layout, collection->id.name + 2, 0, "OBJECT_OT_select_same_collection", "collection", collection->id.name + 2); | ||||
| } | } | ||||
| UI_popup_menu_end(C, pup); | UI_popup_menu_end(C, pup); | ||||
| return changed; /* The operator already handle this! */ | return changed; /* The operator already handle this! */ | ||||
| } | } | ||||
| static bool select_grouped_object_hooks(bContext *C, Object *ob) | static bool select_grouped_object_hooks(bContext *C, Object *ob) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | if ((base->object->type == ob->type) && ((base->flag & BASE_SELECTED) == 0)) { | ||||
| ED_object_base_select(base, BA_SELECT); | ED_object_base_select(base, BA_SELECT); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| #define COLLECTION_MENU_MAX 24 | |||||
| static bool select_grouped_collection(bContext *C, Object *ob) /* Select objects in the same collection as the active */ | |||||
| { | |||||
| typedef struct EnumeratedCollection { | |||||
| struct SceneCollection *collection; | |||||
| int index; | |||||
| } EnumeratedCollection; | |||||
| bool changed = false; | |||||
| SceneCollection *collection; | |||||
| EnumeratedCollection ob_collections[COLLECTION_MENU_MAX]; | |||||
| int collection_count = 0, i; | |||||
| uiPopupMenu *pup; | |||||
| uiLayout *layout; | |||||
| i = 0; | |||||
| FOREACH_SCENE_COLLECTION_BEGIN(CTX_data_scene(C), scene_collection) | |||||
| { | |||||
| if (BKE_collection_object_exists(scene_collection, ob)) { | |||||
| ob_collections[collection_count].index = i; | |||||
| ob_collections[collection_count].collection = scene_collection; | |||||
| if (++collection_count >= COLLECTION_MENU_MAX) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| i++; | |||||
| } | |||||
| FOREACH_SCENE_COLLECTION_END; | |||||
| if (!collection_count) { | |||||
| return 0; | |||||
| } | |||||
| else if (collection_count == 1) { | |||||
| collection = ob_collections[0].collection; | |||||
| return BKE_collection_objects_select(CTX_data_view_layer(C), collection); | |||||
| } | |||||
| /* build the menu. */ | |||||
| pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); | |||||
| layout = UI_popup_menu_layout(pup); | |||||
| for (i = 0; i < collection_count; i++) { | |||||
| uiItemIntO(layout, | |||||
| ob_collections[i].collection->name, | |||||
| ICON_NONE, | |||||
| "OBJECT_OT_select_same_collection", | |||||
| "collection_index", | |||||
| ob_collections[i].index); | |||||
| } | |||||
| UI_popup_menu_end(C, pup); | |||||
| return changed; /* The operator already handle this! */ | |||||
| } | |||||
| static bool select_grouped_index_object(bContext *C, Object *ob) | static bool select_grouped_index_object(bContext *C, Object *ob) | ||||
| { | { | ||||
| bool changed = false; | bool changed = false; | ||||
| CTX_DATA_BEGIN (C, Base *, base, selectable_bases) | CTX_DATA_BEGIN (C, Base *, base, selectable_bases) | ||||
| { | { | ||||
| if ((base->object->index == ob->index) && ((base->flag & BASE_SELECTED) == 0)) { | if ((base->object->index == ob->index) && ((base->flag & BASE_SELECTED) == 0)) { | ||||
| ED_object_base_select(base, BA_SELECT); | ED_object_base_select(base, BA_SELECT); | ||||
| ▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | case OBJECT_GRPSEL_SIBLINGS: | ||||
| changed |= select_grouped_siblings(C, ob); | changed |= select_grouped_siblings(C, ob); | ||||
| break; | break; | ||||
| case OBJECT_GRPSEL_TYPE: | case OBJECT_GRPSEL_TYPE: | ||||
| changed |= select_grouped_type(C, ob); | changed |= select_grouped_type(C, ob); | ||||
| break; | break; | ||||
| case OBJECT_GRPSEL_COLLECTION: | case OBJECT_GRPSEL_COLLECTION: | ||||
| changed |= select_grouped_collection(C, ob); | changed |= select_grouped_collection(C, ob); | ||||
| break; | break; | ||||
| case OBJECT_GRPSEL_GROUP: | |||||
| changed |= select_grouped_group(C, ob); | |||||
| break; | |||||
| case OBJECT_GRPSEL_HOOK: | case OBJECT_GRPSEL_HOOK: | ||||
| changed |= select_grouped_object_hooks(C, ob); | changed |= select_grouped_object_hooks(C, ob); | ||||
| break; | break; | ||||
| case OBJECT_GRPSEL_PASS: | case OBJECT_GRPSEL_PASS: | ||||
| changed |= select_grouped_index_object(C, ob); | changed |= select_grouped_index_object(C, ob); | ||||
| break; | break; | ||||
| case OBJECT_GRPSEL_COLOR: | case OBJECT_GRPSEL_COLOR: | ||||
| changed |= select_grouped_color(C, ob); | changed |= select_grouped_color(C, ob); | ||||
| ▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | void OBJECT_OT_select_all(wmOperatorType *ot) | ||||
| ot->poll = objects_selectable_poll; | ot->poll = objects_selectable_poll; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| WM_operator_properties_select_all(ot); | WM_operator_properties_select_all(ot); | ||||
| } | } | ||||
| /**************************** Select In The Same Group ****************************/ | /**************************** Select In The Same Collection ****************************/ | ||||
| static int object_select_same_group_exec(bContext *C, wmOperator *op) | static int object_select_same_collection_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Group *group; | Collection *collection; | ||||
| char group_name[MAX_ID_NAME]; | char collection_name[MAX_ID_NAME]; | ||||
| /* passthrough if no objects are visible */ | /* passthrough if no objects are visible */ | ||||
| if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; | if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; | ||||
| RNA_string_get(op->ptr, "group", group_name); | RNA_string_get(op->ptr, "collection", collection_name); | ||||
| group = (Group *)BKE_libblock_find_name(ID_GR, group_name); | collection = (Collection *)BKE_libblock_find_name(ID_GR, collection_name); | ||||
| if (!group) { | if (!collection) { | ||||
| return OPERATOR_PASS_THROUGH; | return OPERATOR_PASS_THROUGH; | ||||
| } | } | ||||
| CTX_DATA_BEGIN (C, Base *, base, visible_bases) | CTX_DATA_BEGIN (C, Base *, base, visible_bases) | ||||
| { | { | ||||
| if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { | if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { | ||||
| if (BKE_group_object_exists(group, base->object)) { | if (BKE_collection_has_object(collection, base->object)) { | ||||
| ED_object_base_select(base, BA_SELECT); | ED_object_base_select(base, BA_SELECT); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); | WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void OBJECT_OT_select_same_group(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Select Same Group"; | |||||
| ot->description = "Select object in the same group"; | |||||
| ot->idname = "OBJECT_OT_select_same_group"; | |||||
| /* api callbacks */ | |||||
| ot->exec = object_select_same_group_exec; | |||||
| ot->poll = objects_selectable_poll; | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| RNA_def_string(ot->srna, "group", NULL, MAX_ID_NAME, "Group", "Name of the group to select"); | |||||
| } | |||||
| /**************************** Select In The Same Collection ****************************/ | |||||
| static int object_select_same_collection_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| SceneCollection *collection; | |||||
| /* passthrough if no objects are visible */ | |||||
| if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; | |||||
| int collection_index = RNA_int_get(op->ptr, "collection_index"); | |||||
| collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); | |||||
| if (!collection) { | |||||
| return OPERATOR_PASS_THROUGH; | |||||
| } | |||||
| if (BKE_collection_objects_select(CTX_data_view_layer(C), collection)) { | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); | |||||
| } | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void OBJECT_OT_select_same_collection(wmOperatorType *ot) | void OBJECT_OT_select_same_collection(wmOperatorType *ot) | ||||
| { | { | ||||
| PropertyRNA *prop; | |||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Same Collection"; | ot->name = "Select Same Collection"; | ||||
| ot->description = "Select object in the same collection"; | ot->description = "Select object in the same collection"; | ||||
| ot->idname = "OBJECT_OT_select_same_collection"; | ot->idname = "OBJECT_OT_select_same_collection"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->exec = object_select_same_collection_exec; | ot->exec = object_select_same_collection_exec; | ||||
| ot->poll = objects_selectable_poll; | ot->poll = objects_selectable_poll; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, | RNA_def_string(ot->srna, "collection", NULL, MAX_ID_NAME, "Collection", "Name of the collection to select"); | ||||
| "Collection Index", "Index of the collection to select", 0, INT_MAX); | |||||
| RNA_def_property_flag(prop, PROP_SKIP_SAVE); | |||||
| } | } | ||||
| /**************************** Select Mirror ****************************/ | /**************************** Select Mirror ****************************/ | ||||
| static int object_select_mirror_exec(bContext *C, wmOperator *op) | static int object_select_mirror_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| bool extend; | bool extend; | ||||
| extend = RNA_boolean_get(op->ptr, "extend"); | extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| ▲ Show 20 Lines • Show All 208 Lines • Show Last 20 Lines | |||||