diff options
Diffstat (limited to 'source/blender/editors/object/object_select.c')
-rw-r--r-- | source/blender/editors/object/object_select.c | 974 |
1 files changed, 974 insertions, 0 deletions
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c new file mode 100644 index 00000000000..50ba4ab2934 --- /dev/null +++ b/source/blender/editors/object/object_select.c @@ -0,0 +1,974 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2002-2008 full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "DNA_group_types.h" +#include "DNA_material_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_property_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "BLI_arithb.h" +#include "BLI_listbase.h" +#include "BLI_rand.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_particle.h" +#include "BKE_property.h" +#include "BKE_report.h" +#include "BKE_scene.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "object_intern.h" + +/************************ Exported **************************/ + +/* simple API for object selection, rather than just using the flag + * this takes into account the 'restrict selection in 3d view' flag. + * deselect works always, the restriction just prevents selection */ + +/* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! */ + +void ED_base_object_select(Base *base, short mode) +{ + if (base) { + if (mode==BA_SELECT) { + if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) + if (mode==BA_SELECT) base->flag |= SELECT; + } + else if (mode==BA_DESELECT) { + base->flag &= ~SELECT; + } + base->object->flag= base->flag; + } +} + +/* also to set active NULL */ +void ED_base_object_activate(bContext *C, Base *base) +{ + Scene *scene= CTX_data_scene(C); + Base *tbase; + + /* sets scene->basact */ + BASACT= base; + + if(base) { + + /* XXX old signals, remember to handle notifiers now! */ + // select_actionchannel_by_name(base->object->action, "Object", 1); + + /* disable temporal locks */ + for(tbase=FIRSTBASE; tbase; tbase= tbase->next) { + if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) { + tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK; + DAG_id_flush_update(&tbase->object->id, OB_RECALC_DATA); + } + } + WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); + } + else + WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL); +} + +/********************** Selection Operators **********************/ + +static EnumPropertyItem prop_select_types[] = { + {0, "EXCLUSIVE", 0, "Exclusive", ""}, + {1, "EXTEND", 0, "Extend", ""}, + {0, NULL, 0, NULL, NULL} +}; + +/************************ Select by Type *************************/ + +static int object_select_by_type_exec(bContext *C, wmOperator *op) +{ + short obtype, seltype; + + obtype = RNA_enum_get(op->ptr, "type"); + seltype = RNA_enum_get(op->ptr, "seltype"); + + if (seltype == 0) { + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + ED_base_object_select(base, BA_DESELECT); + } + CTX_DATA_END; + } + + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if(base->object->type==obtype) { + ED_base_object_select(base, BA_SELECT); + } + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_select_by_type(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select By Type"; + ot->description = "Select all visible objects that are of a type."; + ot->idname= "OBJECT_OT_select_by_type"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= object_select_by_type_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "seltype", prop_select_types, 0, "Selection", "Extend selection or clear selection then select"); + RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", ""); + +} + +/*********************** Selection by Links *********************/ + +static EnumPropertyItem prop_select_linked_types[] = { + {1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff... + {2, "OBDATA", 0, "Ob Data", ""}, + {3, "MATERIAL", 0, "Material", ""}, + {4, "TEXTURE", 0, "Texture", ""}, + {5, "DUPGROUP", 0, "Dupligroup", ""}, + {6, "PARTICLE", 0, "Particle System", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int object_select_linked_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Object *ob; + void *obdata = NULL; + Material *mat = NULL, *mat1; + Tex *tex=0; + int a, b; + int nr = RNA_enum_get(op->ptr, "type"); + short changed = 0, seltype; + /* events (nr): + * Object Ipo: 1 + * ObData: 2 + * Current Material: 3 + * Current Texture: 4 + * DupliGroup: 5 + * PSys: 6 + */ + + seltype = RNA_enum_get(op->ptr, "seltype"); + + if (seltype == 0) { + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + ED_base_object_select(base, BA_DESELECT); + } + CTX_DATA_END; + } + + ob= OBACT; + if(ob==0){ + BKE_report(op->reports, RPT_ERROR, "No Active Object"); + return OPERATOR_CANCELLED; + } + + if(nr==1) { + // XXX old animation system + //ipo= ob->ipo; + //if(ipo==0) return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; + } + else if(nr==2) { + if(ob->data==0) return OPERATOR_CANCELLED; + obdata= ob->data; + } + else if(nr==3 || nr==4) { + mat= give_current_material(ob, ob->actcol); + if(mat==0) return OPERATOR_CANCELLED; + if(nr==4) { + if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex; + if(tex==0) return OPERATOR_CANCELLED; + } + } + else if(nr==5) { + if(ob->dup_group==NULL) return OPERATOR_CANCELLED; + } + else if(nr==6) { + if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED; + } + else return OPERATOR_CANCELLED; + + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if(nr==1) { + // XXX old animation system + //if(base->object->ipo==ipo) base->flag |= SELECT; + //changed = 1; + } + else if(nr==2) { + if(base->object->data==obdata) base->flag |= SELECT; + changed = 1; + } + else if(nr==3 || nr==4) { + ob= base->object; + + for(a=1; a<=ob->totcol; a++) { + mat1= give_current_material(ob, a); + if(nr==3) { + if(mat1==mat) base->flag |= SELECT; + changed = 1; + } + else if(mat1 && nr==4) { + for(b=0; b<MAX_MTEX; b++) { + if(mat1->mtex[b]) { + if(tex==mat1->mtex[b]->tex) { + base->flag |= SELECT; + changed = 1; + break; + } + } + } + } + } + } + else if(nr==5) { + if(base->object->dup_group==ob->dup_group) { + base->flag |= SELECT; + changed = 1; + } + } + else if(nr==6) { + /* loop through other, then actives particles*/ + ParticleSystem *psys; + ParticleSystem *psys_act; + + for(psys=base->object->particlesystem.first; psys; psys=psys->next) { + for(psys_act=ob->particlesystem.first; psys_act; psys_act=psys_act->next) { + if (psys->part == psys_act->part) { + base->flag |= SELECT; + changed = 1; + break; + } + } + + if (base->flag & SELECT) { + break; + } + } + } + base->object->flag= base->flag; + } + CTX_DATA_END; + + if (changed) { + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Linked"; + ot->description = "Select all visible objects that are linked."; + ot->idname= "OBJECT_OT_select_linked"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= object_select_linked_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", ""); + RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); + +} + +/*********************** Selected Grouped ********************/ + +static EnumPropertyItem prop_select_grouped_types[] = { + {1, "CHILDREN_RECURSIVE", 0, "Children", ""}, + {2, "CHILDREN", 0, "Immediate Children", ""}, + {3, "PARENT", 0, "Parent", ""}, + {4, "SIBLINGS", 0, "Siblings", "Shared Parent"}, + {5, "TYPE", 0, "Type", "Shared object type"}, + {6, "LAYER", 0, "Layer", "Shared layers"}, + {7, "GROUP", 0, "Group", "Shared group"}, + {8, "HOOK", 0, "Hook", ""}, + {9, "PASS", 0, "Pass", "Render pass Index"}, + {10, "COLOR", 0, "Color", "Object Color"}, + {11, "PROPERTIES", 0, "Properties", "Game Properties"}, + {0, NULL, 0, NULL, NULL} +}; + +static short select_grouped_children(bContext *C, Object *ob, int recursive) +{ + short changed = 0; + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if (ob == base->object->parent) { + if (!(base->flag & SELECT)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + + if (recursive) + changed |= select_grouped_children(C, base->object, 1); + } + } + CTX_DATA_END; + return changed; +} + +static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */ +{ + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + + short changed = 0; + Base *baspar, *basact= CTX_data_active_base(C); + + if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */ + + baspar= object_in_scene(basact->object->parent, scene); + + /* can be NULL if parent in other scene */ + if(baspar && BASE_SELECTABLE(v3d, baspar)) { + ED_base_object_select(basact, BA_DESELECT); + ED_base_object_select(baspar, BA_SELECT); + ED_base_object_activate(C, baspar); + changed = 1; + } + return changed; +} + + +#define GROUP_MENU_MAX 24 +static short select_grouped_group(bContext *C, Object *ob) /* Select objects in the same group as the active */ +{ + short changed = 0; + Group *group, *ob_groups[GROUP_MENU_MAX]; + //char str[10 + (24*GROUP_MENU_MAX)]; + //char *p = str; + int group_count=0; //, menu, i; + + for ( group=G.main->group.first; + group && group_count < GROUP_MENU_MAX; + group=group->id.next + ) { + if (object_in_group (ob, group)) { + ob_groups[group_count] = group; + group_count++; + } + } + + if (!group_count) + return 0; + + else if (group_count == 1) { + group = ob_groups[0]; + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if (!(base->flag & SELECT) && object_in_group(base->object, group)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + CTX_DATA_END; + return changed; + } +#if 0 // XXX hows this work in 2.5? + /* build the menu. */ + p += sprintf(str, "Groups%%t"); + for (i=0; i<group_count; i++) { + group = ob_groups[i]; + p += sprintf (p, "|%s%%x%i", group->id.name+2, i); + } + + menu = pupmenu (str); + if (menu == -1) + return 0; + + group = ob_groups[menu]; + for (base= FIRSTBASE; base; base= base->next) { + if (!(base->flag & SELECT) && object_in_group(base->object, group)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } +#endif + return changed; +} + +static short select_grouped_object_hooks(bContext *C, Object *ob) +{ + Scene *scene= CTX_data_scene(C); + View3D *v3d= CTX_wm_view3d(C); + + short changed = 0; + Base *base; + ModifierData *md; + HookModifierData *hmd; + + for (md = ob->modifiers.first; md; md=md->next) { + if (md->type==eModifierType_Hook) { + hmd= (HookModifierData*) md; + if (hmd->object && !(hmd->object->flag & SELECT)) { + base= object_in_scene(hmd->object, scene); + if (base && (BASE_SELECTABLE(v3d, base))) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + } + } + return changed; +} + +/* Select objects woth the same parent as the active (siblings), + * parent can be NULL also */ +static short select_grouped_siblings(bContext *C, Object *ob) +{ + short changed = 0; + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if ((base->object->parent==ob->parent) && !(base->flag & SELECT)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + CTX_DATA_END; + return changed; +} + +static short select_grouped_type(bContext *C, Object *ob) +{ + short changed = 0; + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if ((base->object->type == ob->type) && !(base->flag & SELECT)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + CTX_DATA_END; + return changed; +} + +static short select_grouped_layer(bContext *C, Object *ob) +{ + char changed = 0; + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if ((base->lay & ob->lay) && !(base->flag & SELECT)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + CTX_DATA_END; + return changed; +} + +static short select_grouped_index_object(bContext *C, Object *ob) +{ + char changed = 0; + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if ((base->object->index == ob->index) && !(base->flag & SELECT)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + CTX_DATA_END; + return changed; +} + +static short select_grouped_color(bContext *C, Object *ob) +{ + char changed = 0; + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if (!(base->flag & SELECT) && (FloatCompare(base->object->col, ob->col, 0.005f))) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + CTX_DATA_END; + return changed; +} + +static short objects_share_gameprop(Object *a, Object *b) +{ + bProperty *prop; + /*make a copy of all its properties*/ + + for( prop= a->prop.first; prop; prop = prop->next ) { + if ( get_ob_property(b, prop->name) ) + return 1; + } + return 0; +} + +static short select_grouped_gameprops(bContext *C, Object *ob) +{ + char changed = 0; + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + CTX_DATA_END; + return changed; +} + +static int object_select_grouped_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Object *ob; + int nr = RNA_enum_get(op->ptr, "type"); + short changed = 0, seltype; + + seltype = RNA_enum_get(op->ptr, "seltype"); + + if (seltype == 0) { + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + ED_base_object_select(base, BA_DESELECT); + } + CTX_DATA_END; + } + + ob= OBACT; + if(ob==0){ + BKE_report(op->reports, RPT_ERROR, "No Active Object"); + return OPERATOR_CANCELLED; + } + + if(nr==1) changed = select_grouped_children(C, ob, 1); + else if(nr==2) changed = select_grouped_children(C, ob, 0); + else if(nr==3) changed = select_grouped_parent(C); + else if(nr==4) changed = select_grouped_siblings(C, ob); + else if(nr==5) changed = select_grouped_type(C, ob); + else if(nr==6) changed = select_grouped_layer(C, ob); + else if(nr==7) changed = select_grouped_group(C, ob); + else if(nr==8) changed = select_grouped_object_hooks(C, ob); + else if(nr==9) changed = select_grouped_index_object(C, ob); + else if(nr==10) changed = select_grouped_color(C, ob); + else if(nr==11) changed = select_grouped_gameprops(C, ob); + + if (changed) { + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_select_grouped(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Grouped"; + ot->description = "Select all visible objects grouped by various properties."; + ot->idname= "OBJECT_OT_select_grouped"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= object_select_grouped_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); + RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); +} + +/************************* Select by Layer **********************/ + +static int object_select_by_layer_exec(bContext *C, wmOperator *op) +{ + unsigned int layernum; + short seltype; + + seltype = RNA_enum_get(op->ptr, "seltype"); + layernum = RNA_int_get(op->ptr, "layer"); + + if (seltype == 0) { + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + ED_base_object_select(base, BA_DESELECT); + } + CTX_DATA_END; + } + + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if(base->lay == (1<< (layernum -1))) + ED_base_object_select(base, BA_SELECT); + } + CTX_DATA_END; + + /* undo? */ + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_select_by_layer(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "select by layer"; + ot->description = "Select all visible objects on a layer."; + ot->idname= "OBJECT_OT_select_by_layer"; + + /* api callbacks */ + /*ot->invoke = XXX - need a int grid popup*/ + ot->exec= object_select_by_layer_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_int(ot->srna, "layer", 1, 1, 20, "Layer", "", 1, 20); + RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); +} + +/************************** Select Inverse *************************/ + +static int object_select_inverse_exec(bContext *C, wmOperator *op) +{ + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if (base->flag & SELECT) + ED_base_object_select(base, BA_DESELECT); + else + ED_base_object_select(base, BA_SELECT); + } + CTX_DATA_END; + + /* undo? */ + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_select_inverse(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Select Inverse"; + ot->description = "Invert selection of all visible objects."; + ot->idname= "OBJECT_OT_select_inverse"; + + /* api callbacks */ + ot->exec= object_select_inverse_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + +} + +/**************************** (De)select All ****************************/ + +static int object_select_de_select_all_exec(bContext *C, wmOperator *op) +{ + + int a=0, ok=0; + + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if (base->flag & SELECT) { + ok= a= 1; + break; + } + else ok=1; + } + CTX_DATA_END; + + if (!ok) return OPERATOR_PASS_THROUGH; + + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if (a) ED_base_object_select(base, BA_DESELECT); + else ED_base_object_select(base, BA_SELECT); + } + CTX_DATA_END; + + /* undo? */ + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_select_all_toggle(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "deselect all"; + ot->description = "(de)select all visible objects in scene."; + ot->idname= "OBJECT_OT_select_all_toggle"; + + /* api callbacks */ + ot->exec= object_select_de_select_all_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + +} + +/**************************** Select Mirror ****************************/ + +/* finds the best possible flipped name. For renaming; check for unique names afterwards */ +/* if strip_number: removes number extensions */ +void object_flip_name (char *name) +{ + int len; + char prefix[128]={""}; /* The part before the facing */ + char suffix[128]={""}; /* The part after the facing */ + char replace[128]={""}; /* The replacement string */ + char number[128]={""}; /* The number extension string */ + char *index=NULL; + + len= strlen(name); + if(len<3) return; // we don't do names like .R or .L + + /* We first check the case with a .### extension, let's find the last period */ + if(isdigit(name[len-1])) { + index= strrchr(name, '.'); // last occurrance + if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever! + strcpy(number, index); + *index= 0; + len= strlen(name); + } + } + + strcpy (prefix, name); + +#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_') + + /* first case; separator . - _ with extensions r R l L */ + if( IS_SEPARATOR(name[len-2]) ) { + switch(name[len-1]) { + case 'l': + prefix[len-1]= 0; + strcpy(replace, "r"); + break; + case 'r': + prefix[len-1]= 0; + strcpy(replace, "l"); + break; + case 'L': + prefix[len-1]= 0; + strcpy(replace, "R"); + break; + case 'R': + prefix[len-1]= 0; + strcpy(replace, "L"); + break; + } + } + /* case; beginning with r R l L , with separator after it */ + else if( IS_SEPARATOR(name[1]) ) { + switch(name[0]) { + case 'l': + strcpy(replace, "r"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'r': + strcpy(replace, "l"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'L': + strcpy(replace, "R"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'R': + strcpy(replace, "L"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + } + } + else if(len > 5) { + /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ + index = BLI_strcasestr(prefix, "right"); + if (index==prefix || index==prefix+len-5) { + if(index[0]=='r') + strcpy (replace, "left"); + else { + if(index[1]=='I') + strcpy (replace, "LEFT"); + else + strcpy (replace, "Left"); + } + *index= 0; + strcpy (suffix, index+5); + } + else { + index = BLI_strcasestr(prefix, "left"); + if (index==prefix || index==prefix+len-4) { + if(index[0]=='l') + strcpy (replace, "right"); + else { + if(index[1]=='E') + strcpy (replace, "RIGHT"); + else + strcpy (replace, "Right"); + } + *index= 0; + strcpy (suffix, index+4); + } + } + } + +#undef IS_SEPARATOR + + sprintf (name, "%s%s%s%s", prefix, replace, suffix, number); +} + +static int object_select_mirror_exec(bContext *C, wmOperator *op) +{ + char tmpname[32]; + short seltype; + + seltype = RNA_enum_get(op->ptr, "seltype"); + + CTX_DATA_BEGIN(C, Base*, primbase, selected_bases) { + + strcpy(tmpname, primbase->object->id.name+2); + object_flip_name(tmpname); + + CTX_DATA_BEGIN(C, Base*, secbase, visible_bases) { + if(!strcmp(secbase->object->id.name+2, tmpname)) { + ED_base_object_select(secbase, BA_SELECT); + } + } + CTX_DATA_END; + + if (seltype == 0) ED_base_object_select(primbase, BA_DESELECT); + + } + CTX_DATA_END; + + /* undo? */ + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_select_mirror(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Select Mirror"; + ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword"; + ot->idname= "OBJECT_OT_select_mirror"; + + /* api callbacks */ + ot->exec= object_select_mirror_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); +} + +/**************************** Select Random ****************************/ + +static int object_select_random_exec(bContext *C, wmOperator *op) +{ + float percent; + short seltype; + + seltype = RNA_enum_get(op->ptr, "seltype"); + + if (seltype == 0) { + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + ED_base_object_select(base, BA_DESELECT); + } + CTX_DATA_END; + } + percent = RNA_float_get(op->ptr, "percent"); + + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + if (BLI_frand() < percent) { + ED_base_object_select(base, BA_SELECT); + } + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_select_random(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Random select"; + ot->description = "Set select on random visible objects."; + ot->idname= "OBJECT_OT_select_random"; + + /* api callbacks */ + /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/ + ot->exec = object_select_random_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "percentage of objects to randomly select", 0.0001f, 1.0f); + RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); +} + + |