Blender  V2.59
outliner_select.c
Go to the documentation of this file.
00001 /*
00002  * $Id: outliner_select.c 39294 2011-08-11 06:40:04Z gsrb3d $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2004 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Joshua Leung
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00034 #include <math.h>
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include <stddef.h>
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "DNA_anim_types.h"
00042 #include "DNA_armature_types.h"
00043 #include "DNA_constraint_types.h"
00044 #include "DNA_camera_types.h"
00045 #include "DNA_group_types.h"
00046 #include "DNA_key_types.h"
00047 #include "DNA_lamp_types.h"
00048 #include "DNA_material_types.h"
00049 #include "DNA_mesh_types.h"
00050 #include "DNA_meta_types.h"
00051 #include "DNA_particle_types.h"
00052 #include "DNA_scene_types.h"
00053 #include "DNA_world_types.h"
00054 #include "DNA_sequence_types.h"
00055 #include "DNA_object_types.h"
00056 
00057 #include "BLI_blenlib.h"
00058 #include "BLI_utildefines.h"
00059 #include "BLI_math_base.h"
00060 
00061 #if defined WIN32 && !defined _LIBC
00062 # include "BLI_fnmatch.h" /* use fnmatch included in blenlib */
00063 #else
00064 #  ifndef _GNU_SOURCE
00065 #    define _GNU_SOURCE
00066 #  endif
00067 # include <fnmatch.h>
00068 #endif
00069 
00070 
00071 #include "BKE_animsys.h"
00072 #include "BKE_context.h"
00073 #include "BKE_deform.h"
00074 #include "BKE_depsgraph.h"
00075 #include "BKE_fcurve.h"
00076 #include "BKE_global.h"
00077 #include "BKE_group.h"
00078 #include "BKE_library.h"
00079 #include "BKE_main.h"
00080 #include "BKE_modifier.h"
00081 #include "BKE_report.h"
00082 #include "BKE_scene.h"
00083 #include "BKE_sequencer.h"
00084 
00085 #include "ED_armature.h"
00086 #include "ED_object.h"
00087 #include "ED_screen.h"
00088 #include "ED_util.h"
00089 
00090 #include "WM_api.h"
00091 #include "WM_types.h"
00092 
00093 #include "BIF_gl.h"
00094 #include "BIF_glutil.h"
00095 
00096 #include "UI_interface.h"
00097 #include "UI_interface_icons.h"
00098 #include "UI_resources.h"
00099 #include "UI_view2d.h"
00100 
00101 #include "RNA_access.h"
00102 #include "RNA_define.h"
00103 
00104 #include "outliner_intern.h"
00105 
00106 /* ****************************************************** */
00107 /* Outliner Selection (grey-blue highlight for rows) */
00108 
00109 void outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting)
00110 {
00111         TreeElement *te;
00112         TreeStoreElem *tselem;
00113         
00114         for (te= lb->first; te && *index >= 0; te=te->next, (*index)--) {
00115                 tselem= TREESTORE(te);
00116                 
00117                 /* if we've encountered the right item, set its 'Outliner' selection status */
00118                 if (*index == 0) {
00119                         /* this should be the last one, so no need to do anything with index */
00120                         if ((te->flag & TE_ICONROW)==0) {
00121                                 /* -1 value means toggle testing for now... */
00122                                 if (*selecting == -1) {
00123                                         if (tselem->flag & TSE_SELECTED) 
00124                                                 *selecting= 0;
00125                                         else 
00126                                                 *selecting= 1;
00127                                 }
00128                                 
00129                                 /* set selection */
00130                                 if (*selecting) 
00131                                         tselem->flag |= TSE_SELECTED;
00132                                 else 
00133                                         tselem->flag &= ~TSE_SELECTED;
00134                         }
00135                 }
00136                 else if ((tselem->flag & TSE_CLOSED)==0) {
00137                         /* Only try selecting sub-elements if we haven't hit the right element yet
00138                          *
00139                          * Hack warning:
00140                          *      Index must be reduced before supplying it to the sub-tree to try to do
00141                          *      selection, however, we need to increment it again for the next loop to 
00142                          *      function correctly
00143                          */
00144                         (*index)--;
00145                         outliner_select(soops, &te->subtree, index, selecting);
00146                         (*index)++;
00147                 }
00148         }
00149 }
00150 
00151 /* ****************************************************** */
00152 /* Outliner Element Selection/Activation on Click */
00153 
00154 static int tree_element_active_renderlayer(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set)
00155 {
00156         Scene *sce;
00157         
00158         /* paranoia check */
00159         if(te->idcode!=ID_SCE)
00160                 return 0;
00161         sce= (Scene *)tselem->id;
00162         
00163         if(set) {
00164                 sce->r.actlay= tselem->nr;
00165                 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, sce);
00166         }
00167         else {
00168                 return sce->r.actlay==tselem->nr;
00169         }
00170         return 0;
00171 }
00172 
00173 static int  tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
00174 {
00175         TreeStoreElem *tselem= TREESTORE(te);
00176         Scene *sce;
00177         Base *base;
00178         Object *ob= NULL;
00179         
00180         /* if id is not object, we search back */
00181         if(te->idcode==ID_OB) ob= (Object *)tselem->id;
00182         else {
00183                 ob= (Object *)outliner_search_back(soops, te, ID_OB);
00184                 if(ob==OBACT) return 0;
00185         }
00186         if(ob==NULL) return 0;
00187         
00188         sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
00189         if(sce && scene != sce) {
00190                 ED_screen_set_scene(C, sce);
00191         }
00192         
00193         /* find associated base in current scene */
00194         base= object_in_scene(ob, scene);
00195 
00196         if(base) {
00197                 if(set==2) {
00198                         /* swap select */
00199                         if(base->flag & SELECT)
00200                                 ED_base_object_select(base, BA_DESELECT);
00201                         else 
00202                                 ED_base_object_select(base, BA_SELECT);
00203                 }
00204                 else {
00205                         /* deleselect all */
00206                         scene_deselect_all(scene);
00207                         ED_base_object_select(base, BA_SELECT);
00208                 }
00209                 if(C) {
00210                         ED_base_object_activate(C, base); /* adds notifier */
00211                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
00212                 }
00213         }
00214         
00215         if(ob!=scene->obedit) 
00216                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
00217                 
00218         return 1;
00219 }
00220 
00221 static int tree_element_active_material(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
00222 {
00223         TreeElement *tes;
00224         Object *ob;
00225         
00226         /* we search for the object parent */
00227         ob= (Object *)outliner_search_back(soops, te, ID_OB);
00228         // note: ob->matbits can be NULL when a local object points to a library mesh.
00229         if(ob==NULL || ob!=OBACT || ob->matbits==NULL) return 0;        // just paranoia
00230         
00231         /* searching in ob mat array? */
00232         tes= te->parent;
00233         if(tes->idcode==ID_OB) {
00234                 if(set) {
00235                         ob->actcol= te->index+1;
00236                         ob->matbits[te->index]= 1;      // make ob material active too
00237                         ob->colbits |= (1<<te->index);
00238                 }
00239                 else {
00240                         if(ob->actcol == te->index+1) 
00241                                 if(ob->matbits[te->index]) return 1;
00242                 }
00243         }
00244         /* or we search for obdata material */
00245         else {
00246                 if(set) {
00247                         ob->actcol= te->index+1;
00248                         ob->matbits[te->index]= 0;      // make obdata material active too
00249                         ob->colbits &= ~(1<<te->index);
00250                 }
00251                 else {
00252                         if(ob->actcol == te->index+1)
00253                                 if(ob->matbits[te->index]==0) return 1;
00254                 }
00255         }
00256         if(set) {
00257                 WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, NULL);
00258         }
00259         return 0;
00260 }
00261 
00262 static int tree_element_active_texture(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
00263 {
00264         TreeElement *tep;
00265         TreeStoreElem /* *tselem,*/ *tselemp;
00266         Object *ob=OBACT;
00267         SpaceButs *sbuts=NULL;
00268         
00269         if(ob==NULL) return 0; // no active object
00270         
00271         /*tselem= TREESTORE(te);*/ /*UNUSED*/
00272         
00273         /* find buttons area (note, this is undefined really still, needs recode in blender) */
00274         /* XXX removed finding sbuts */
00275         
00276         /* where is texture linked to? */
00277         tep= te->parent;
00278         tselemp= TREESTORE(tep);
00279         
00280         if(tep->idcode==ID_WO) {
00281                 World *wrld= (World *)tselemp->id;
00282 
00283                 if(set) {
00284                         if(sbuts) {
00285                                 // XXX sbuts->tabo= TAB_SHADING_TEX;    // hack from header_buttonswin.c
00286                                 // XXX sbuts->texfrom= 1;
00287                         }
00288 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
00289                         wrld->texact= te->index;
00290                 }
00291                 else if(tselemp->id == (ID *)(scene->world)) {
00292                         if(wrld->texact==te->index) return 1;
00293                 }
00294         }
00295         else if(tep->idcode==ID_LA) {
00296                 Lamp *la= (Lamp *)tselemp->id;
00297                 if(set) {
00298                         if(sbuts) {
00299                                 // XXX sbuts->tabo= TAB_SHADING_TEX;    // hack from header_buttonswin.c
00300                                 // XXX sbuts->texfrom= 2;
00301                         }
00302 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
00303                         la->texact= te->index;
00304                 }
00305                 else {
00306                         if(tselemp->id == ob->data) {
00307                                 if(la->texact==te->index) return 1;
00308                         }
00309                 }
00310         }
00311         else if(tep->idcode==ID_MA) {
00312                 Material *ma= (Material *)tselemp->id;
00313                 if(set) {
00314                         if(sbuts) {
00315                                 //sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
00316                                 // XXX sbuts->texfrom= 0;
00317                         }
00318 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
00319                         ma->texact= (char)te->index;
00320                         
00321                         /* also set active material */
00322                         ob->actcol= tep->index+1;
00323                 }
00324                 else if(tep->flag & TE_ACTIVE) {        // this is active material
00325                         if(ma->texact==te->index) return 1;
00326                 }
00327         }
00328         
00329         if(set)
00330                 WM_event_add_notifier(C, NC_TEXTURE, NULL);
00331 
00332         return 0;
00333 }
00334 
00335 
00336 static int tree_element_active_lamp(bContext *UNUSED(C), Scene *scene, SpaceOops *soops, TreeElement *te, int set)
00337 {
00338         Object *ob;
00339         
00340         /* we search for the object parent */
00341         ob= (Object *)outliner_search_back(soops, te, ID_OB);
00342         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
00343         
00344         if(set) {
00345 // XXX          extern_set_butspace(F5KEY, 0);
00346         }
00347         else return 1;
00348         
00349         return 0;
00350 }
00351 
00352 static int tree_element_active_camera(bContext *UNUSED(C), Scene *scene, SpaceOops *soops, TreeElement *te, int set)
00353 {
00354         Object *ob= (Object *)outliner_search_back(soops, te, ID_OB);
00355 
00356         if(set)
00357                 return 0;
00358 
00359         return scene->camera == ob;
00360 }
00361 
00362 static int tree_element_active_world(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
00363 {
00364         TreeElement *tep;
00365         TreeStoreElem *tselem=NULL;
00366         Scene *sce=NULL;
00367         
00368         tep= te->parent;
00369         if(tep) {
00370                 tselem= TREESTORE(tep);
00371                 sce= (Scene *)tselem->id;
00372         }
00373         
00374         if(set) {       // make new scene active
00375                 if(sce && scene != sce) {
00376                         ED_screen_set_scene(C, sce);
00377                 }
00378         }
00379         
00380         if(tep==NULL || tselem->id == (ID *)scene) {
00381                 if(set) {
00382 // XXX                  extern_set_butspace(F8KEY, 0);
00383                 }
00384                 else {
00385                         return 1;
00386                 }
00387         }
00388         return 0;
00389 }
00390 
00391 static int tree_element_active_defgroup(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
00392 {
00393         Object *ob;
00394         
00395         /* id in tselem is object */
00396         ob= (Object *)tselem->id;
00397         if(set) {
00398                 ob->actdef= te->index+1;
00399                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
00400                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
00401         }
00402         else {
00403                 if(ob==OBACT)
00404                         if(ob->actdef== te->index+1) return 1;
00405         }
00406         return 0;
00407 }
00408 
00409 static int tree_element_active_posegroup(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
00410 {
00411         Object *ob= (Object *)tselem->id;
00412         
00413         if(set) {
00414                 if (ob->pose) {
00415                         ob->pose->active_group= te->index+1;
00416                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
00417                 }
00418         }
00419         else {
00420                 if(ob==OBACT && ob->pose) {
00421                         if (ob->pose->active_group== te->index+1) return 1;
00422                 }
00423         }
00424         return 0;
00425 }
00426 
00427 static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
00428 {
00429         Object *ob= (Object *)tselem->id;
00430         bArmature *arm= ob->data;
00431         bPoseChannel *pchan= te->directdata;
00432         
00433         if(set) {
00434                 if(!(pchan->bone->flag & BONE_HIDDEN_P)) {
00435                         
00436                         if(set==2) ED_pose_deselectall(ob, 2);  // 2 = clear active tag
00437                         else ED_pose_deselectall(ob, 0);        // 0 = deselect 
00438                         
00439                         if(set==2 && (pchan->bone->flag & BONE_SELECTED)) {
00440                                 pchan->bone->flag &= ~BONE_SELECTED;
00441                         } else {
00442                                 pchan->bone->flag |= BONE_SELECTED;
00443                                 arm->act_bone= pchan->bone;
00444                         }
00445                         
00446                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, ob);
00447 
00448                 }
00449         }
00450         else {
00451                 if(ob==OBACT && ob->pose) {
00452                         if (pchan->bone->flag & BONE_SELECTED) return 1;
00453                 }
00454         }
00455         return 0;
00456 }
00457 
00458 static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
00459 {
00460         bArmature *arm= (bArmature *)tselem->id;
00461         Bone *bone= te->directdata;
00462         
00463         if(set) {
00464                 if(!(bone->flag & BONE_HIDDEN_P)) {
00465                         if(set==2) ED_pose_deselectall(OBACT, 2);       // 2 is clear active tag
00466                         else ED_pose_deselectall(OBACT, 0);
00467                         
00468                         if(set==2 && (bone->flag & BONE_SELECTED)) {
00469                                 bone->flag &= ~BONE_SELECTED;
00470                         } else {
00471                                 bone->flag |= BONE_SELECTED;
00472                                 arm->act_bone= bone;
00473                         }
00474                         
00475                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, OBACT);
00476                 }
00477         }
00478         else {
00479                 Object *ob= OBACT;
00480                 
00481                 if(ob && ob->data==arm) {
00482                         if (bone->flag & BONE_SELECTED) return 1;
00483                 }
00484         }
00485         return 0;
00486 }
00487 
00488 
00489 /* ebones only draw in editmode armature */
00490 static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature *arm, EditBone *ebone, short sel)
00491 {
00492         if(sel) {
00493                 ebone->flag |= BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL;
00494                 arm->act_edbone= ebone;
00495                 // flush to parent?
00496                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag |= BONE_TIPSEL;
00497         }
00498         else {
00499                 ebone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL);
00500                 // flush to parent?
00501                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag &= ~BONE_TIPSEL;
00502         }
00503 
00504         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, scene->obedit);
00505 }
00506 static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
00507 {
00508         bArmature *arm= scene->obedit->data;
00509         EditBone *ebone= te->directdata;
00510 
00511         if(set==1) {
00512                 if(!(ebone->flag & BONE_HIDDEN_A)) {
00513                         ED_armature_deselect_all(scene->obedit, 0);     // deselect
00514                         tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
00515                         return 1;
00516                 }
00517         }
00518         else if (set==2) {
00519                 if(!(ebone->flag & BONE_HIDDEN_A)) {
00520                         if(!(ebone->flag & BONE_SELECTED)) {
00521                                 tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
00522                                 return 1;
00523                         }
00524                         else {
00525                                 /* entirely selected, so de-select */
00526                                 tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE);
00527                                 return 0;
00528                         }
00529                 }
00530         }
00531         else if (ebone->flag & BONE_SELECTED) {
00532                 return 1;
00533         }
00534         return 0;
00535 }
00536 
00537 static int tree_element_active_modifier(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
00538 {
00539         if(set) {
00540                 Object *ob= (Object *)tselem->id;
00541                 
00542                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
00543 
00544 // XXX          extern_set_butspace(F9KEY, 0);
00545         }
00546         
00547         return 0;
00548 }
00549 
00550 static int tree_element_active_psys(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
00551 {
00552         if(set) {
00553                 Object *ob= (Object *)tselem->id;
00554                 
00555                 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
00556                 
00557 // XXX          extern_set_butspace(F7KEY, 0);
00558         }
00559         
00560         return 0;
00561 }
00562 
00563 static int tree_element_active_constraint(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
00564 {
00565         if(set) {
00566                 Object *ob= (Object *)tselem->id;
00567                 
00568                 WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
00569 // XXX          extern_set_butspace(F7KEY, 0);
00570         }
00571         
00572         return 0;
00573 }
00574 
00575 static int tree_element_active_text(bContext *UNUSED(C), Scene *UNUSED(scene), SpaceOops *UNUSED(soops), TreeElement *UNUSED(te), int UNUSED(set))
00576 {
00577         // XXX removed
00578         return 0;
00579 }
00580 
00581 static int tree_element_active_pose(bContext *C, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
00582 {
00583         Object *ob= (Object *)tselem->id;
00584         Base *base= object_in_scene(ob, scene);
00585         
00586         if(set) {
00587                 if(scene->obedit) 
00588                         ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
00589                 
00590                 if(ob->mode & OB_MODE_POSE) 
00591                         ED_armature_exit_posemode(C, base);
00592                 else 
00593                         ED_armature_enter_posemode(C, base);
00594         }
00595         else {
00596                 if(ob->mode & OB_MODE_POSE) return 1;
00597         }
00598         return 0;
00599 }
00600 
00601 static int tree_element_active_sequence(TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
00602 {
00603         Sequence *seq= (Sequence*) te->directdata;
00604 
00605         if(set) {
00606 // XXX          select_single_seq(seq, 1);
00607         }
00608         else {
00609                 if(seq->flag & SELECT)
00610                         return(1);
00611         }
00612         return(0);
00613 }
00614 
00615 static int tree_element_active_sequence_dup(Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
00616 {
00617         Sequence *seq, *p;
00618         Editing *ed= seq_give_editing(scene, FALSE);
00619 
00620         seq= (Sequence*)te->directdata;
00621         if(set==0) {
00622                 if(seq->flag & SELECT)
00623                         return(1);
00624                 return(0);
00625         }
00626 
00627 // XXX  select_single_seq(seq, 1);
00628         p= ed->seqbasep->first;
00629         while(p) {
00630                 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
00631                         p= p->next;
00632                         continue;
00633                 }
00634 
00635 //              if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
00636 // XXX                  select_single_seq(p, 0);
00637                 p= p->next;
00638         }
00639         return(0);
00640 }
00641 
00642 static int tree_element_active_keymap_item(bContext *UNUSED(C), TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
00643 {
00644         wmKeyMapItem *kmi= te->directdata;
00645         
00646         if(set==0) {
00647                 if(kmi->flag & KMI_INACTIVE) return 0;
00648                 return 1;
00649         }
00650         else {
00651                 kmi->flag ^= KMI_INACTIVE;
00652         }
00653         return 0;
00654 }
00655 
00656 /* ---------------------------------------------- */
00657 
00658 /* generic call for ID data check or make/check active in UI */
00659 int tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
00660 {
00661 
00662         switch(te->idcode) {
00663                 case ID_OB:
00664                         return tree_element_set_active_object(C, scene, soops, te, set);
00665                 case ID_MA:
00666                         return tree_element_active_material(C, scene, soops, te, set);
00667                 case ID_WO:
00668                         return tree_element_active_world(C, scene, soops, te, set);
00669                 case ID_LA:
00670                         return tree_element_active_lamp(C, scene, soops, te, set);
00671                 case ID_TE:
00672                         return tree_element_active_texture(C, scene, soops, te, set);
00673                 case ID_TXT:
00674                         return tree_element_active_text(C, scene, soops, te, set);
00675                 case ID_CA:
00676                         return tree_element_active_camera(C, scene, soops, te, set);
00677         }
00678         return 0;
00679 }
00680 
00681 /* generic call for non-id data to make/check active in UI */
00682 /* Context can be NULL when set==0 */
00683 int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set)
00684 {
00685         switch(tselem->type) {
00686                 case TSE_DEFGROUP:
00687                         return tree_element_active_defgroup(C, scene, te, tselem, set);
00688                 case TSE_BONE:
00689                         return tree_element_active_bone(C, scene, te, tselem, set);
00690                 case TSE_EBONE:
00691                         return tree_element_active_ebone(C, scene, te, tselem, set);
00692                 case TSE_MODIFIER:
00693                         return tree_element_active_modifier(C, te, tselem, set);
00694                 case TSE_LINKED_OB:
00695                         if(set) tree_element_set_active_object(C, scene, soops, te, set);
00696                         else if(tselem->id==(ID *)OBACT) return 1;
00697                         break;
00698                 case TSE_LINKED_PSYS:
00699                         return tree_element_active_psys(C, scene, te, tselem, set);
00700                 case TSE_POSE_BASE:
00701                         return tree_element_active_pose(C, scene, te, tselem, set);
00702                 case TSE_POSE_CHANNEL:
00703                         return tree_element_active_posechannel(C, scene, te, tselem, set);
00704                 case TSE_CONSTRAINT:
00705                         return tree_element_active_constraint(C, te, tselem, set);
00706                 case TSE_R_LAYER:
00707                         return tree_element_active_renderlayer(C, te, tselem, set);
00708                 case TSE_POSEGRP:
00709                         return tree_element_active_posegroup(C, scene, te, tselem, set);
00710                 case TSE_SEQUENCE:
00711                         return tree_element_active_sequence(te, tselem, set);
00712                 case TSE_SEQUENCE_DUP:
00713                         return tree_element_active_sequence_dup(scene, te, tselem, set);
00714                 case TSE_KEYMAP_ITEM:
00715                         return tree_element_active_keymap_item(C, te, tselem, set);
00716                         
00717         }
00718         return 0;
00719 }
00720 
00721 /* ================================================ */
00722 
00723 static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, int extend, const float mval[2])
00724 {
00725         
00726         if(mval[1]>te->ys && mval[1]<te->ys+UI_UNIT_Y) {
00727                 TreeStoreElem *tselem= TREESTORE(te);
00728                 int openclose= 0;
00729                 
00730                 /* open close icon */
00731                 if((te->flag & TE_ICONROW)==0) {                                // hidden icon, no open/close
00732                         if( mval[0]>te->xs && mval[0]<te->xs+UI_UNIT_X) 
00733                                 openclose= 1;
00734                 }
00735                 
00736                 if(openclose) {
00737                         /* all below close/open? */
00738                         if(extend) {
00739                                 tselem->flag &= ~TSE_CLOSED;
00740                                 outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
00741                         }
00742                         else {
00743                                 if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
00744                                 else tselem->flag |= TSE_CLOSED;
00745                                 
00746                         }
00747                         
00748                         return 1;
00749                 }
00750                 /* name and first icon */
00751                 else if(mval[0]>te->xs+UI_UNIT_X && mval[0]<te->xend) {
00752                         
00753                         /* always makes active object */
00754                         if(tselem->type!=TSE_SEQUENCE && tselem->type!=TSE_SEQ_STRIP && tselem->type!=TSE_SEQUENCE_DUP)
00755                                 tree_element_set_active_object(C, scene, soops, te, 1 + (extend!=0 && tselem->type==0));
00756                         
00757                         if(tselem->type==0) { // the lib blocks
00758                                 /* editmode? */
00759                                 if(te->idcode==ID_SCE) {
00760                                         if(scene!=(Scene *)tselem->id) {
00761                                                 ED_screen_set_scene(C, (Scene *)tselem->id);
00762                                         }
00763                                 }
00764                                 else if(te->idcode==ID_GR) {
00765                                         Group *gr= (Group *)tselem->id;
00766                                         GroupObject *gob;
00767                                         
00768                                         if(extend) {
00769                                                 int sel= BA_SELECT;
00770                                                 for(gob= gr->gobject.first; gob; gob= gob->next) {
00771                                                         if(gob->ob->flag & SELECT) {
00772                                                                 sel= BA_DESELECT;
00773                                                                 break;
00774                                                         }
00775                                                 }
00776                                                 
00777                                                 for(gob= gr->gobject.first; gob; gob= gob->next) {
00778                                                         ED_base_object_select(object_in_scene(gob->ob, scene), sel);
00779                                                 }
00780                                         }
00781                                         else {
00782                                                 scene_deselect_all(scene);
00783                                                 
00784                                                 for(gob= gr->gobject.first; gob; gob= gob->next) {
00785                                                         if((gob->ob->flag & SELECT) == 0)
00786                                                                 ED_base_object_select(object_in_scene(gob->ob, scene), BA_SELECT);
00787                                                 }
00788                                         }
00789                                         
00790                                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
00791                                 }
00792                                 else if(ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
00793                                         WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
00794                                 } else {        // rest of types
00795                                         tree_element_active(C, scene, soops, te, 1);
00796                                 }
00797                                 
00798                         }
00799                         else tree_element_type_active(C, scene, soops, te, tselem, 1+(extend!=0));
00800                         
00801                         return 1;
00802                 }
00803         }
00804         
00805         for(te= te->subtree.first; te; te= te->next) {
00806                 if(do_outliner_item_activate(C, scene, ar, soops, te, extend, mval)) return 1;
00807         }
00808         return 0;
00809 }
00810 
00811 /* event can enterkey, then it opens/closes */
00812 static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event)
00813 {
00814         Scene *scene= CTX_data_scene(C);
00815         ARegion *ar= CTX_wm_region(C);
00816         SpaceOops *soops= CTX_wm_space_outliner(C);
00817         TreeElement *te;
00818         float fmval[2];
00819         int extend= RNA_boolean_get(op->ptr, "extend");
00820 
00821         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval+1);
00822 
00823         if(!ELEM3(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF, SO_KEYMAP) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)
00824                 return OPERATOR_CANCELLED;
00825 
00826         for(te= soops->tree.first; te; te= te->next) {
00827                 if(do_outliner_item_activate(C, scene, ar, soops, te, extend, fmval)) break;
00828         }
00829         
00830         if(te) {
00831                 ED_undo_push(C, "Outliner click event");
00832         }
00833         else {
00834                 short selecting= -1;
00835                 int row;
00836                 
00837                 /* get row number - 100 here is just a dummy value since we don't need the column */
00838                 UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, 
00839                                                 fmval[0], fmval[1], NULL, &row);
00840                 
00841                 /* select relevant row */
00842                 outliner_select(soops, &soops->tree, &row, &selecting);
00843                 
00844                 soops->storeflag |= SO_TREESTORE_REDRAW;
00845                 
00846                 ED_undo_push(C, "Outliner selection event");
00847         }
00848         
00849         ED_region_tag_redraw(ar);
00850 
00851         return OPERATOR_FINISHED;
00852 }
00853 
00854 void OUTLINER_OT_item_activate(wmOperatorType *ot)
00855 {
00856         ot->name= "Activate Item";
00857         ot->idname= "OUTLINER_OT_item_activate";
00858         ot->description= "Handle mouse clicks to activate/select items";
00859         
00860         ot->invoke= outliner_item_activate;
00861         
00862         ot->poll= ED_operator_outliner_active;
00863         
00864         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection for activation.");
00865 }
00866 
00867 /* ****************************************************** */