Blender V2.61 - r43446

outliner_select.c

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