replace fixed sizes with sizeof when passing string length since size wasn't always...
[blender.git] / source / blender / editors / space_outliner / outliner_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2004 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_outliner/outliner_select.c
29  *  \ingroup spoutliner
30  */
31
32 #include <math.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stddef.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_anim_types.h"
40 #include "DNA_armature_types.h"
41 #include "DNA_constraint_types.h"
42 #include "DNA_camera_types.h"
43 #include "DNA_group_types.h"
44 #include "DNA_key_types.h"
45 #include "DNA_lamp_types.h"
46 #include "DNA_material_types.h"
47 #include "DNA_mesh_types.h"
48 #include "DNA_meta_types.h"
49 #include "DNA_particle_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_world_types.h"
52 #include "DNA_sequence_types.h"
53 #include "DNA_object_types.h"
54
55 #include "BLI_blenlib.h"
56 #include "BLI_utildefines.h"
57 #include "BLI_math_base.h"
58
59 #if defined WIN32 && !defined _LIBC
60 # include "BLI_fnmatch.h" /* use fnmatch included in blenlib */
61 #else
62 #  ifndef _GNU_SOURCE
63 #    define _GNU_SOURCE
64 #  endif
65 # include <fnmatch.h>
66 #endif
67
68
69 #include "BKE_animsys.h"
70 #include "BKE_context.h"
71 #include "BKE_deform.h"
72 #include "BKE_depsgraph.h"
73 #include "BKE_fcurve.h"
74 #include "BKE_global.h"
75 #include "BKE_group.h"
76 #include "BKE_library.h"
77 #include "BKE_main.h"
78 #include "BKE_modifier.h"
79 #include "BKE_report.h"
80 #include "BKE_scene.h"
81 #include "BKE_sequencer.h"
82
83 #include "ED_armature.h"
84 #include "ED_object.h"
85 #include "ED_screen.h"
86 #include "ED_util.h"
87
88 #include "WM_api.h"
89 #include "WM_types.h"
90
91 #include "BIF_gl.h"
92 #include "BIF_glutil.h"
93
94 #include "UI_interface.h"
95 #include "UI_interface_icons.h"
96 #include "UI_resources.h"
97 #include "UI_view2d.h"
98
99 #include "RNA_access.h"
100 #include "RNA_define.h"
101
102 #include "outliner_intern.h"
103
104 /* ****************************************************** */
105 /* Outliner Selection (grey-blue highlight for rows) */
106
107 static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting)
108 {
109         TreeElement *te;
110         TreeStoreElem *tselem;
111         int change= 0;
112         
113         for (te= lb->first; te && *index >= 0; te=te->next, (*index)--) {
114                 tselem= TREESTORE(te);
115                 
116                 /* if we've encountered the right item, set its 'Outliner' selection status */
117                 if (*index == 0) {
118                         /* this should be the last one, so no need to do anything with index */
119                         if ((te->flag & TE_ICONROW)==0) {
120                                 /* -1 value means toggle testing for now... */
121                                 if (*selecting == -1) {
122                                         if (tselem->flag & TSE_SELECTED) 
123                                                 *selecting= 0;
124                                         else 
125                                                 *selecting= 1;
126                                 }
127                                 
128                                 /* set selection */
129                                 if (*selecting) 
130                                         tselem->flag |= TSE_SELECTED;
131                                 else 
132                                         tselem->flag &= ~TSE_SELECTED;
133
134                                 change |= 1;
135                         }
136                 }
137                 else if (TSELEM_OPEN(tselem,soops)) {
138                         /* Only try selecting sub-elements if we haven't hit the right element yet
139                          *
140                          * Hack warning:
141                          *      Index must be reduced before supplying it to the sub-tree to try to do
142                          *      selection, however, we need to increment it again for the next loop to 
143                          *      function correctly
144                          */
145                         (*index)--;
146                         change |= outliner_select(soops, &te->subtree, index, selecting);
147                         (*index)++;
148                 }
149         }
150
151         return change;
152 }
153
154 /* ****************************************************** */
155 /* Outliner Element Selection/Activation on Click */
156
157 static int tree_element_active_renderlayer(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set)
158 {
159         Scene *sce;
160         
161         /* paranoia check */
162         if(te->idcode!=ID_SCE)
163                 return 0;
164         sce= (Scene *)tselem->id;
165         
166         if(set) {
167                 sce->r.actlay= tselem->nr;
168                 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, sce);
169         }
170         else {
171                 return sce->r.actlay==tselem->nr;
172         }
173         return 0;
174 }
175
176 static int  tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
177 {
178         TreeStoreElem *tselem= TREESTORE(te);
179         Scene *sce;
180         Base *base;
181         Object *ob= NULL;
182         
183         /* if id is not object, we search back */
184         if(te->idcode==ID_OB) ob= (Object *)tselem->id;
185         else {
186                 ob= (Object *)outliner_search_back(soops, te, ID_OB);
187                 if(ob==OBACT) return 0;
188         }
189         if(ob==NULL) return 0;
190         
191         sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
192         if(sce && scene != sce) {
193                 ED_screen_set_scene(C, sce);
194         }
195         
196         /* find associated base in current scene */
197         base= object_in_scene(ob, scene);
198
199         if(base) {
200                 if(set==2) {
201                         /* swap select */
202                         if(base->flag & SELECT)
203                                 ED_base_object_select(base, BA_DESELECT);
204                         else 
205                                 ED_base_object_select(base, BA_SELECT);
206                 }
207                 else {
208                         /* deleselect all */
209                         scene_deselect_all(scene);
210                         ED_base_object_select(base, BA_SELECT);
211                 }
212                 if(C) {
213                         ED_base_object_activate(C, base); /* adds notifier */
214                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
215                 }
216         }
217         
218         if(ob!=scene->obedit) 
219                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
220                 
221         return 1;
222 }
223
224 static int tree_element_active_material(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
225 {
226         TreeElement *tes;
227         Object *ob;
228         
229         /* we search for the object parent */
230         ob= (Object *)outliner_search_back(soops, te, ID_OB);
231         // note: ob->matbits can be NULL when a local object points to a library mesh.
232         if(ob==NULL || ob!=OBACT || ob->matbits==NULL) return 0;        // just paranoia
233         
234         /* searching in ob mat array? */
235         tes= te->parent;
236         if(tes->idcode==ID_OB) {
237                 if(set) {
238                         ob->actcol= te->index+1;
239                         ob->matbits[te->index]= 1;      // make ob material active too
240                 }
241                 else {
242                         if(ob->actcol == te->index+1) 
243                                 if(ob->matbits[te->index]) return 1;
244                 }
245         }
246         /* or we search for obdata material */
247         else {
248                 if(set) {
249                         ob->actcol= te->index+1;
250                         ob->matbits[te->index]= 0;      // make obdata material active too
251                 }
252                 else {
253                         if(ob->actcol == te->index+1)
254                                 if(ob->matbits[te->index]==0) return 1;
255                 }
256         }
257         if(set) {
258                 WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, NULL);
259         }
260         return 0;
261 }
262
263 static int tree_element_active_texture(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
264 {
265         TreeElement *tep;
266         TreeStoreElem /* *tselem,*/ *tselemp;
267         Object *ob=OBACT;
268         SpaceButs *sbuts=NULL;
269         
270         if(ob==NULL) return 0; // no active object
271         
272         /*tselem= TREESTORE(te);*/ /*UNUSED*/
273         
274         /* find buttons area (note, this is undefined really still, needs recode in blender) */
275         /* XXX removed finding sbuts */
276         
277         /* where is texture linked to? */
278         tep= te->parent;
279         tselemp= TREESTORE(tep);
280         
281         if(tep->idcode==ID_WO) {
282                 World *wrld= (World *)tselemp->id;
283
284                 if(set) {
285                         if(sbuts) {
286                                 // XXX sbuts->tabo= TAB_SHADING_TEX;    // hack from header_buttonswin.c
287                                 // XXX sbuts->texfrom= 1;
288                         }
289 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
290                         wrld->texact= te->index;
291                 }
292                 else if(tselemp->id == (ID *)(scene->world)) {
293                         if(wrld->texact==te->index) return 1;
294                 }
295         }
296         else if(tep->idcode==ID_LA) {
297                 Lamp *la= (Lamp *)tselemp->id;
298                 if(set) {
299                         if(sbuts) {
300                                 // XXX sbuts->tabo= TAB_SHADING_TEX;    // hack from header_buttonswin.c
301                                 // XXX sbuts->texfrom= 2;
302                         }
303 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
304                         la->texact= te->index;
305                 }
306                 else {
307                         if(tselemp->id == ob->data) {
308                                 if(la->texact==te->index) return 1;
309                         }
310                 }
311         }
312         else if(tep->idcode==ID_MA) {
313                 Material *ma= (Material *)tselemp->id;
314                 if(set) {
315                         if(sbuts) {
316                                 //sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
317                                 // XXX sbuts->texfrom= 0;
318                         }
319 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
320                         ma->texact= (char)te->index;
321                         
322                         /* also set active material */
323                         ob->actcol= tep->index+1;
324                 }
325                 else if(tep->flag & TE_ACTIVE) {        // this is active material
326                         if(ma->texact==te->index) return 1;
327                 }
328         }
329         
330         if(set)
331                 WM_event_add_notifier(C, NC_TEXTURE, NULL);
332
333         return 0;
334 }
335
336
337 static int tree_element_active_lamp(bContext *UNUSED(C), Scene *scene, SpaceOops *soops, TreeElement *te, int set)
338 {
339         Object *ob;
340         
341         /* we search for the object parent */
342         ob= (Object *)outliner_search_back(soops, te, ID_OB);
343         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
344         
345         if(set) {
346 // XXX          extern_set_butspace(F5KEY, 0);
347         }
348         else return 1;
349         
350         return 0;
351 }
352
353 static int tree_element_active_camera(bContext *UNUSED(C), Scene *scene, SpaceOops *soops, TreeElement *te, int set)
354 {
355         Object *ob= (Object *)outliner_search_back(soops, te, ID_OB);
356
357         if(set)
358                 return 0;
359
360         return scene->camera == ob;
361 }
362
363 static int tree_element_active_world(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
364 {
365         TreeElement *tep;
366         TreeStoreElem *tselem=NULL;
367         Scene *sce=NULL;
368         
369         tep= te->parent;
370         if(tep) {
371                 tselem= TREESTORE(tep);
372                 sce= (Scene *)tselem->id;
373         }
374         
375         if(set) {       // make new scene active
376                 if(sce && scene != sce) {
377                         ED_screen_set_scene(C, sce);
378                 }
379         }
380         
381         if(tep==NULL || tselem->id == (ID *)scene) {
382                 if(set) {
383 // XXX                  extern_set_butspace(F8KEY, 0);
384                 }
385                 else {
386                         return 1;
387                 }
388         }
389         return 0;
390 }
391
392 static int tree_element_active_defgroup(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
393 {
394         Object *ob;
395         
396         /* id in tselem is object */
397         ob= (Object *)tselem->id;
398         if(set) {
399                 BLI_assert(te->index+1 >= 0);
400                 ob->actdef= te->index+1;
401
402                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
403                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
404         }
405         else {
406                 if(ob==OBACT)
407                         if(ob->actdef== te->index+1) return 1;
408         }
409         return 0;
410 }
411
412 static int tree_element_active_posegroup(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
413 {
414         Object *ob= (Object *)tselem->id;
415         
416         if(set) {
417                 if (ob->pose) {
418                         ob->pose->active_group= te->index+1;
419                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
420                 }
421         }
422         else {
423                 if(ob==OBACT && ob->pose) {
424                         if (ob->pose->active_group== te->index+1) return 1;
425                 }
426         }
427         return 0;
428 }
429
430 static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
431 {
432         Object *ob= (Object *)tselem->id;
433         bArmature *arm= ob->data;
434         bPoseChannel *pchan= te->directdata;
435         
436         if(set) {
437                 if(!(pchan->bone->flag & BONE_HIDDEN_P)) {
438                         
439                         if(set==2) ED_pose_deselectall(ob, 2);  // 2 = clear active tag
440                         else ED_pose_deselectall(ob, 0);        // 0 = deselect 
441                         
442                         if(set==2 && (pchan->bone->flag & BONE_SELECTED)) {
443                                 pchan->bone->flag &= ~BONE_SELECTED;
444                         } else {
445                                 pchan->bone->flag |= BONE_SELECTED;
446                                 arm->act_bone= pchan->bone;
447                         }
448                         
449                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, ob);
450
451                 }
452         }
453         else {
454                 if(ob==OBACT && ob->pose) {
455                         if (pchan->bone->flag & BONE_SELECTED) return 1;
456                 }
457         }
458         return 0;
459 }
460
461 static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
462 {
463         bArmature *arm= (bArmature *)tselem->id;
464         Bone *bone= te->directdata;
465         
466         if(set) {
467                 if(!(bone->flag & BONE_HIDDEN_P)) {
468                         if(set==2) ED_pose_deselectall(OBACT, 2);       // 2 is clear active tag
469                         else ED_pose_deselectall(OBACT, 0);
470                         
471                         if(set==2 && (bone->flag & BONE_SELECTED)) {
472                                 bone->flag &= ~BONE_SELECTED;
473                         } else {
474                                 bone->flag |= BONE_SELECTED;
475                                 arm->act_bone= bone;
476                         }
477                         
478                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, OBACT);
479                 }
480         }
481         else {
482                 Object *ob= OBACT;
483                 
484                 if(ob && ob->data==arm) {
485                         if (bone->flag & BONE_SELECTED) return 1;
486                 }
487         }
488         return 0;
489 }
490
491
492 /* ebones only draw in editmode armature */
493 static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature *arm, EditBone *ebone, short sel)
494 {
495         if(sel) {
496                 ebone->flag |= BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL;
497                 arm->act_edbone= ebone;
498                 // flush to parent?
499                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag |= BONE_TIPSEL;
500         }
501         else {
502                 ebone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL);
503                 // flush to parent?
504                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag &= ~BONE_TIPSEL;
505         }
506
507         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, scene->obedit);
508 }
509 static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
510 {
511         bArmature *arm= scene->obedit->data;
512         EditBone *ebone= te->directdata;
513
514         if(set==1) {
515                 if(!(ebone->flag & BONE_HIDDEN_A)) {
516                         ED_armature_deselect_all(scene->obedit, 0);     // deselect
517                         tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
518                         return 1;
519                 }
520         }
521         else if (set==2) {
522                 if(!(ebone->flag & BONE_HIDDEN_A)) {
523                         if(!(ebone->flag & BONE_SELECTED)) {
524                                 tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
525                                 return 1;
526                         }
527                         else {
528                                 /* entirely selected, so de-select */
529                                 tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE);
530                                 return 0;
531                         }
532                 }
533         }
534         else if (ebone->flag & BONE_SELECTED) {
535                 return 1;
536         }
537         return 0;
538 }
539
540 static int tree_element_active_modifier(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
541 {
542         if(set) {
543                 Object *ob= (Object *)tselem->id;
544                 
545                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
546
547 // XXX          extern_set_butspace(F9KEY, 0);
548         }
549         
550         return 0;
551 }
552
553 static int tree_element_active_psys(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
554 {
555         if(set) {
556                 Object *ob= (Object *)tselem->id;
557                 
558                 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
559                 
560 // XXX          extern_set_butspace(F7KEY, 0);
561         }
562         
563         return 0;
564 }
565
566 static int tree_element_active_constraint(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
567 {
568         if(set) {
569                 Object *ob= (Object *)tselem->id;
570                 
571                 WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
572 // XXX          extern_set_butspace(F7KEY, 0);
573         }
574         
575         return 0;
576 }
577
578 static int tree_element_active_text(bContext *UNUSED(C), Scene *UNUSED(scene), SpaceOops *UNUSED(soops), TreeElement *UNUSED(te), int UNUSED(set))
579 {
580         // XXX removed
581         return 0;
582 }
583
584 static int tree_element_active_pose(bContext *C, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
585 {
586         Object *ob= (Object *)tselem->id;
587         Base *base= object_in_scene(ob, scene);
588         
589         if(set) {
590                 if(scene->obedit) 
591                         ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
592                 
593                 if(ob->mode & OB_MODE_POSE) 
594                         ED_armature_exit_posemode(C, base);
595                 else 
596                         ED_armature_enter_posemode(C, base);
597         }
598         else {
599                 if(ob->mode & OB_MODE_POSE) return 1;
600         }
601         return 0;
602 }
603
604 static int tree_element_active_sequence(TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
605 {
606         Sequence *seq= (Sequence*) te->directdata;
607
608         if(set) {
609 // XXX          select_single_seq(seq, 1);
610         }
611         else {
612                 if(seq->flag & SELECT)
613                         return(1);
614         }
615         return(0);
616 }
617
618 static int tree_element_active_sequence_dup(Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
619 {
620         Sequence *seq, *p;
621         Editing *ed= seq_give_editing(scene, FALSE);
622
623         seq= (Sequence*)te->directdata;
624         if(set==0) {
625                 if(seq->flag & SELECT)
626                         return(1);
627                 return(0);
628         }
629
630 // XXX  select_single_seq(seq, 1);
631         p= ed->seqbasep->first;
632         while(p) {
633                 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
634                         p= p->next;
635                         continue;
636                 }
637
638 //              if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
639 // XXX                  select_single_seq(p, 0);
640                 p= p->next;
641         }
642         return(0);
643 }
644
645 static int tree_element_active_keymap_item(bContext *UNUSED(C), TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
646 {
647         wmKeyMapItem *kmi= te->directdata;
648         
649         if(set==0) {
650                 if(kmi->flag & KMI_INACTIVE) return 0;
651                 return 1;
652         }
653         else {
654                 kmi->flag ^= KMI_INACTIVE;
655         }
656         return 0;
657 }
658
659 /* ---------------------------------------------- */
660
661 /* generic call for ID data check or make/check active in UI */
662 int tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
663 {
664
665         switch(te->idcode) {
666                 /* Note: no ID_OB: objects are handled specially to allow multiple
667                    selection. See do_outliner_item_activate. */
668                 case ID_MA:
669                         return tree_element_active_material(C, scene, soops, te, set);
670                 case ID_WO:
671                         return tree_element_active_world(C, scene, soops, te, set);
672                 case ID_LA:
673                         return tree_element_active_lamp(C, scene, soops, te, set);
674                 case ID_TE:
675                         return tree_element_active_texture(C, scene, soops, te, set);
676                 case ID_TXT:
677                         return tree_element_active_text(C, scene, soops, te, set);
678                 case ID_CA:
679                         return tree_element_active_camera(C, scene, soops, te, set);
680         }
681         return 0;
682 }
683
684 /* generic call for non-id data to make/check active in UI */
685 /* Context can be NULL when set==0 */
686 int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set)
687 {
688         switch(tselem->type) {
689                 case TSE_DEFGROUP:
690                         return tree_element_active_defgroup(C, scene, te, tselem, set);
691                 case TSE_BONE:
692                         return tree_element_active_bone(C, scene, te, tselem, set);
693                 case TSE_EBONE:
694                         return tree_element_active_ebone(C, scene, te, tselem, set);
695                 case TSE_MODIFIER:
696                         return tree_element_active_modifier(C, te, tselem, set);
697                 case TSE_LINKED_OB:
698                         if(set) tree_element_set_active_object(C, scene, soops, te, set);
699                         else if(tselem->id==(ID *)OBACT) return 1;
700                         break;
701                 case TSE_LINKED_PSYS:
702                         return tree_element_active_psys(C, scene, te, tselem, set);
703                 case TSE_POSE_BASE:
704                         return tree_element_active_pose(C, scene, te, tselem, set);
705                 case TSE_POSE_CHANNEL:
706                         return tree_element_active_posechannel(C, scene, te, tselem, set);
707                 case TSE_CONSTRAINT:
708                         return tree_element_active_constraint(C, te, tselem, set);
709                 case TSE_R_LAYER:
710                         return tree_element_active_renderlayer(C, te, tselem, set);
711                 case TSE_POSEGRP:
712                         return tree_element_active_posegroup(C, scene, te, tselem, set);
713                 case TSE_SEQUENCE:
714                         return tree_element_active_sequence(te, tselem, set);
715                 case TSE_SEQUENCE_DUP:
716                         return tree_element_active_sequence_dup(scene, te, tselem, set);
717                 case TSE_KEYMAP_ITEM:
718                         return tree_element_active_keymap_item(C, te, tselem, set);
719                         
720         }
721         return 0;
722 }
723
724 /* ================================================ */
725
726 static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, int extend, const float mval[2])
727 {
728         
729         if(mval[1]>te->ys && mval[1]<te->ys+UI_UNIT_Y) {
730                 TreeStoreElem *tselem= TREESTORE(te);
731                 int openclose= 0;
732                 
733                 /* open close icon */
734                 if((te->flag & TE_ICONROW)==0) {                                // hidden icon, no open/close
735                         if( mval[0]>te->xs && mval[0]<te->xs+UI_UNIT_X) 
736                                 openclose= 1;
737                 }
738                 
739                 if(openclose) {
740                         /* all below close/open? */
741                         if(extend) {
742                                 tselem->flag &= ~TSE_CLOSED;
743                                 outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
744                         }
745                         else {
746                                 if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
747                                 else tselem->flag |= TSE_CLOSED;
748                                 
749                         }
750                         
751                         return 1;
752                 }
753                 /* name and first icon */
754                 else if(mval[0]>te->xs+UI_UNIT_X && mval[0]<te->xend) {
755                         
756                         /* always makes active object */
757                         if(tselem->type!=TSE_SEQUENCE && tselem->type!=TSE_SEQ_STRIP && tselem->type!=TSE_SEQUENCE_DUP)
758                                 tree_element_set_active_object(C, scene, soops, te, 1 + (extend!=0 && tselem->type==0));
759                         
760                         if(tselem->type==0) { // the lib blocks
761                                 /* editmode? */
762                                 if(te->idcode==ID_SCE) {
763                                         if(scene!=(Scene *)tselem->id) {
764                                                 ED_screen_set_scene(C, (Scene *)tselem->id);
765                                         }
766                                 }
767                                 else if(te->idcode==ID_GR) {
768                                         Group *gr= (Group *)tselem->id;
769                                         GroupObject *gob;
770                                         
771                                         if(extend) {
772                                                 int sel= BA_SELECT;
773                                                 for(gob= gr->gobject.first; gob; gob= gob->next) {
774                                                         if(gob->ob->flag & SELECT) {
775                                                                 sel= BA_DESELECT;
776                                                                 break;
777                                                         }
778                                                 }
779                                                 
780                                                 for(gob= gr->gobject.first; gob; gob= gob->next) {
781                                                         ED_base_object_select(object_in_scene(gob->ob, scene), sel);
782                                                 }
783                                         }
784                                         else {
785                                                 scene_deselect_all(scene);
786                                                 
787                                                 for(gob= gr->gobject.first; gob; gob= gob->next) {
788                                                         if((gob->ob->flag & SELECT) == 0)
789                                                                 ED_base_object_select(object_in_scene(gob->ob, scene), BA_SELECT);
790                                                 }
791                                         }
792                                         
793                                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
794                                 }
795                                 else if(ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
796                                         WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
797                                 } else {        // rest of types
798                                         tree_element_active(C, scene, soops, te, 1);
799                                 }
800                                 
801                         }
802                         else tree_element_type_active(C, scene, soops, te, tselem, 1+(extend!=0));
803                         
804                         return 1;
805                 }
806         }
807         
808         for(te= te->subtree.first; te; te= te->next) {
809                 if(do_outliner_item_activate(C, scene, ar, soops, te, extend, mval)) return 1;
810         }
811         return 0;
812 }
813
814 /* event can enterkey, then it opens/closes */
815 static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event)
816 {
817         Scene *scene= CTX_data_scene(C);
818         ARegion *ar= CTX_wm_region(C);
819         SpaceOops *soops= CTX_wm_space_outliner(C);
820         TreeElement *te;
821         float fmval[2];
822         int extend= RNA_boolean_get(op->ptr, "extend");
823
824         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval+1);
825
826         if ( !ELEM3(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF, SO_KEYMAP) &&
827              !(soops->flag & SO_HIDE_RESTRICTCOLS) &&
828              (fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX))
829         {
830                 return OPERATOR_CANCELLED;
831         }
832
833         for(te= soops->tree.first; te; te= te->next) {
834                 if(do_outliner_item_activate(C, scene, ar, soops, te, extend, fmval)) break;
835         }
836         
837         if(te) {
838                 ED_undo_push(C, "Outliner click event");
839         }
840         else {
841                 short selecting= -1;
842                 int row;
843                 
844                 /* get row number - 100 here is just a dummy value since we don't need the column */
845                 UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, 
846                                                 fmval[0], fmval[1], NULL, &row);
847                 
848                 /* select relevant row */
849                 if(outliner_select(soops, &soops->tree, &row, &selecting)) {
850                 
851                         soops->storeflag |= SO_TREESTORE_REDRAW;
852                 
853                         /* no need for undo push here, only changing outliner data which is
854                          * scene level - campbell */
855                         /* ED_undo_push(C, "Outliner selection event"); */
856                 }
857         }
858         
859         ED_region_tag_redraw(ar);
860
861         return OPERATOR_FINISHED;
862 }
863
864 void OUTLINER_OT_item_activate(wmOperatorType *ot)
865 {
866         ot->name= "Activate Item";
867         ot->idname= "OUTLINER_OT_item_activate";
868         ot->description= "Handle mouse clicks to activate/select items";
869         
870         ot->invoke= outliner_item_activate;
871         
872         ot->poll= ED_operator_outliner_active;
873         
874         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection for activation");
875 }
876
877 /* ****************************************************** */