Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2009-09-09 15:52:56 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2009-09-09 15:52:56 +0400
commit3daa283604930167be0bc2dad5d1684a871ca254 (patch)
tree96ee0481d6a7124e38c327e919d74995fe332e3e /source/blender/editors/object/object_select.c
parent8878c30b9b032f1a630c13c5ebb260cb9029ce3c (diff)
2.5: Object module
* Split object_edit.c into multiple files: object_add.c, object_edit.c, object_hook.c, object_relations.c, object_select.c, object_transform.c. * Rename files to have consistent object_ and mball_ prefix: object_shapekey.c, object_lattice.c, object_vgroup.c, mball_edit.c. * Added operators: * vertex group menu and set active * apply location, rotation, scale, visual transform (location is new) * make local * make vertex parent * move to layer * convert to curve/mesh (not finished yet) * Many small fixes for marked issues, but still much code to be cleaned up here...
Diffstat (limited to 'source/blender/editors/object/object_select.c')
-rw-r--r--source/blender/editors/object/object_select.c974
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");
+}
+
+