style cleanup: follow style guide for formatting of if/for/while loops, and else...
[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, CTX_wm_screen(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, CTX_wm_screen(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                         }
445                         else {
446                                 pchan->bone->flag |= BONE_SELECTED;
447                                 arm->act_bone= pchan->bone;
448                         }
449                         
450                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, ob);
451
452                 }
453         }
454         else {
455                 if (ob==OBACT && ob->pose) {
456                         if (pchan->bone->flag & BONE_SELECTED) return 1;
457                 }
458         }
459         return 0;
460 }
461
462 static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
463 {
464         bArmature *arm= (bArmature *)tselem->id;
465         Bone *bone= te->directdata;
466         
467         if (set) {
468                 if (!(bone->flag & BONE_HIDDEN_P)) {
469                         if (set==2) ED_pose_deselectall(OBACT, 2);      // 2 is clear active tag
470                         else ED_pose_deselectall(OBACT, 0);
471                         
472                         if (set==2 && (bone->flag & BONE_SELECTED)) {
473                                 bone->flag &= ~BONE_SELECTED;
474                         }
475                         else {
476                                 bone->flag |= BONE_SELECTED;
477                                 arm->act_bone= bone;
478                         }
479                         
480                         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, OBACT);
481                 }
482         }
483         else {
484                 Object *ob= OBACT;
485                 
486                 if (ob && ob->data==arm) {
487                         if (bone->flag & BONE_SELECTED) return 1;
488                 }
489         }
490         return 0;
491 }
492
493
494 /* ebones only draw in editmode armature */
495 static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature *arm, EditBone *ebone, short sel)
496 {
497         if (sel) {
498                 ebone->flag |= BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL;
499                 arm->act_edbone= ebone;
500                 // flush to parent?
501                 if (ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag |= BONE_TIPSEL;
502         }
503         else {
504                 ebone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL);
505                 // flush to parent?
506                 if (ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag &= ~BONE_TIPSEL;
507         }
508
509         WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, scene->obedit);
510 }
511 static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
512 {
513         bArmature *arm= scene->obedit->data;
514         EditBone *ebone= te->directdata;
515
516         if (set==1) {
517                 if (!(ebone->flag & BONE_HIDDEN_A)) {
518                         ED_armature_deselect_all(scene->obedit, 0);     // deselect
519                         tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
520                         return 1;
521                 }
522         }
523         else if (set==2) {
524                 if (!(ebone->flag & BONE_HIDDEN_A)) {
525                         if (!(ebone->flag & BONE_SELECTED)) {
526                                 tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE);
527                                 return 1;
528                         }
529                         else {
530                                 /* entirely selected, so de-select */
531                                 tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE);
532                                 return 0;
533                         }
534                 }
535         }
536         else if (ebone->flag & BONE_SELECTED) {
537                 return 1;
538         }
539         return 0;
540 }
541
542 static int tree_element_active_modifier(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
543 {
544         if (set) {
545                 Object *ob= (Object *)tselem->id;
546                 
547                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
548
549 // XXX          extern_set_butspace(F9KEY, 0);
550         }
551         
552         return 0;
553 }
554
555 static int tree_element_active_psys(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
556 {
557         if (set) {
558                 Object *ob= (Object *)tselem->id;
559                 
560                 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
561                 
562 // XXX          extern_set_butspace(F7KEY, 0);
563         }
564         
565         return 0;
566 }
567
568 static int tree_element_active_constraint(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
569 {
570         if (set) {
571                 Object *ob= (Object *)tselem->id;
572                 
573                 WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
574 // XXX          extern_set_butspace(F7KEY, 0);
575         }
576         
577         return 0;
578 }
579
580 static int tree_element_active_text(bContext *UNUSED(C), Scene *UNUSED(scene), SpaceOops *UNUSED(soops), TreeElement *UNUSED(te), int UNUSED(set))
581 {
582         // XXX removed
583         return 0;
584 }
585
586 static int tree_element_active_pose(bContext *C, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set)
587 {
588         Object *ob= (Object *)tselem->id;
589         Base *base= object_in_scene(ob, scene);
590         
591         if (set) {
592                 if (scene->obedit)
593                         ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
594                 
595                 if (ob->mode & OB_MODE_POSE)
596                         ED_armature_exit_posemode(C, base);
597                 else 
598                         ED_armature_enter_posemode(C, base);
599         }
600         else {
601                 if (ob->mode & OB_MODE_POSE) return 1;
602         }
603         return 0;
604 }
605
606 static int tree_element_active_sequence(TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
607 {
608         Sequence *seq= (Sequence*) te->directdata;
609
610         if (set) {
611 // XXX          select_single_seq(seq, 1);
612         }
613         else {
614                 if (seq->flag & SELECT)
615                         return(1);
616         }
617         return(0);
618 }
619
620 static int tree_element_active_sequence_dup(Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
621 {
622         Sequence *seq, *p;
623         Editing *ed= seq_give_editing(scene, FALSE);
624
625         seq= (Sequence*)te->directdata;
626         if (set==0) {
627                 if (seq->flag & SELECT)
628                         return(1);
629                 return(0);
630         }
631
632 // XXX  select_single_seq(seq, 1);
633         p= ed->seqbasep->first;
634         while(p) {
635                 if ((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
636                         p= p->next;
637                         continue;
638                 }
639
640 //              if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
641 // XXX                  select_single_seq(p, 0);
642                 p= p->next;
643         }
644         return(0);
645 }
646
647 static int tree_element_active_keymap_item(bContext *UNUSED(C), TreeElement *te, TreeStoreElem *UNUSED(tselem), int set)
648 {
649         wmKeyMapItem *kmi = te->directdata;
650         
651         if (set==0) {
652                 if (kmi->flag & KMI_INACTIVE) return 0;
653                 return 1;
654         }
655         else {
656                 kmi->flag ^= KMI_INACTIVE;
657         }
658         return 0;
659 }
660
661 /* ---------------------------------------------- */
662
663 /* generic call for ID data check or make/check active in UI */
664 int tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
665 {
666
667         switch(te->idcode) {
668                 /* Note: no ID_OB: objects are handled specially to allow multiple
669                  * selection. See do_outliner_item_activate. */
670                 case ID_MA:
671                         return tree_element_active_material(C, scene, soops, te, set);
672                 case ID_WO:
673                         return tree_element_active_world(C, scene, soops, te, set);
674                 case ID_LA:
675                         return tree_element_active_lamp(C, scene, soops, te, set);
676                 case ID_TE:
677                         return tree_element_active_texture(C, scene, soops, te, set);
678                 case ID_TXT:
679                         return tree_element_active_text(C, scene, soops, te, set);
680                 case ID_CA:
681                         return tree_element_active_camera(C, scene, soops, te, set);
682         }
683         return 0;
684 }
685
686 /* generic call for non-id data to make/check active in UI */
687 /* Context can be NULL when set==0 */
688 int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set)
689 {
690         switch(tselem->type) {
691                 case TSE_DEFGROUP:
692                         return tree_element_active_defgroup(C, scene, te, tselem, set);
693                 case TSE_BONE:
694                         return tree_element_active_bone(C, scene, te, tselem, set);
695                 case TSE_EBONE:
696                         return tree_element_active_ebone(C, scene, te, tselem, set);
697                 case TSE_MODIFIER:
698                         return tree_element_active_modifier(C, te, tselem, set);
699                 case TSE_LINKED_OB:
700                         if (set) tree_element_set_active_object(C, scene, soops, te, set);
701                         else if (tselem->id==(ID *)OBACT) return 1;
702                         break;
703                 case TSE_LINKED_PSYS:
704                         return tree_element_active_psys(C, scene, te, tselem, set);
705                 case TSE_POSE_BASE:
706                         return tree_element_active_pose(C, scene, te, tselem, set);
707                 case TSE_POSE_CHANNEL:
708                         return tree_element_active_posechannel(C, scene, te, tselem, set);
709                 case TSE_CONSTRAINT:
710                         return tree_element_active_constraint(C, te, tselem, set);
711                 case TSE_R_LAYER:
712                         return tree_element_active_renderlayer(C, te, tselem, set);
713                 case TSE_POSEGRP:
714                         return tree_element_active_posegroup(C, scene, te, tselem, set);
715                 case TSE_SEQUENCE:
716                         return tree_element_active_sequence(te, tselem, set);
717                 case TSE_SEQUENCE_DUP:
718                         return tree_element_active_sequence_dup(scene, te, tselem, set);
719                 case TSE_KEYMAP_ITEM:
720                         return tree_element_active_keymap_item(C, te, tselem, set);
721                         
722         }
723         return 0;
724 }
725
726 /* ================================================ */
727
728 static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, int extend, const float mval[2])
729 {
730         
731         if (mval[1]>te->ys && mval[1]<te->ys+UI_UNIT_Y) {
732                 TreeStoreElem *tselem= TREESTORE(te);
733                 int openclose= 0;
734                 
735                 /* open close icon */
736                 if ((te->flag & TE_ICONROW)==0) {                               // hidden icon, no open/close
737                         if ( mval[0]>te->xs && mval[0]<te->xs+UI_UNIT_X)
738                                 openclose= 1;
739                 }
740                 
741                 if (openclose) {
742                         /* all below close/open? */
743                         if (extend) {
744                                 tselem->flag &= ~TSE_CLOSED;
745                                 outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
746                         }
747                         else {
748                                 if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
749                                 else tselem->flag |= TSE_CLOSED;
750                                 
751                         }
752                         
753                         return 1;
754                 }
755                 /* name and first icon */
756                 else if (mval[0]>te->xs+UI_UNIT_X && mval[0]<te->xend) {
757                         
758                         /* always makes active object */
759                         if (tselem->type!=TSE_SEQUENCE && tselem->type!=TSE_SEQ_STRIP && tselem->type!=TSE_SEQUENCE_DUP)
760                                 tree_element_set_active_object(C, scene, soops, te, 1 + (extend!=0 && tselem->type==0));
761                         
762                         if (tselem->type==0) { // the lib blocks
763                                 /* editmode? */
764                                 if (te->idcode==ID_SCE) {
765                                         if (scene!=(Scene *)tselem->id) {
766                                                 ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id);
767                                         }
768                                 }
769                                 else if (te->idcode==ID_GR) {
770                                         Group *gr= (Group *)tselem->id;
771                                         GroupObject *gob;
772                                         
773                                         if (extend) {
774                                                 int sel= BA_SELECT;
775                                                 for (gob= gr->gobject.first; gob; gob= gob->next) {
776                                                         if (gob->ob->flag & SELECT) {
777                                                                 sel= BA_DESELECT;
778                                                                 break;
779                                                         }
780                                                 }
781                                                 
782                                                 for (gob= gr->gobject.first; gob; gob= gob->next) {
783                                                         ED_base_object_select(object_in_scene(gob->ob, scene), sel);
784                                                 }
785                                         }
786                                         else {
787                                                 scene_deselect_all(scene);
788                                                 
789                                                 for (gob= gr->gobject.first; gob; gob= gob->next) {
790                                                         if ((gob->ob->flag & SELECT) == 0)
791                                                                 ED_base_object_select(object_in_scene(gob->ob, scene), BA_SELECT);
792                                                 }
793                                         }
794                                         
795                                         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
796                                 }
797                                 else if (ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
798                                         WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
799                                 }
800                                 else {  // rest of types
801                                         tree_element_active(C, scene, soops, te, 1);
802                                 }
803                                 
804                         }
805                         else tree_element_type_active(C, scene, soops, te, tselem, 1+(extend!=0));
806                         
807                         return 1;
808                 }
809         }
810         
811         for (te= te->subtree.first; te; te= te->next) {
812                 if (do_outliner_item_activate(C, scene, ar, soops, te, extend, mval)) return 1;
813         }
814         return 0;
815 }
816
817 /* event can enterkey, then it opens/closes */
818 static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event)
819 {
820         Scene *scene= CTX_data_scene(C);
821         ARegion *ar= CTX_wm_region(C);
822         SpaceOops *soops= CTX_wm_space_outliner(C);
823         TreeElement *te;
824         float fmval[2];
825         int extend= RNA_boolean_get(op->ptr, "extend");
826
827         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval+1);
828
829         if ( !ELEM3(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF, SO_KEYMAP) &&
830              !(soops->flag & SO_HIDE_RESTRICTCOLS) &&
831              (fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX))
832         {
833                 return OPERATOR_CANCELLED;
834         }
835
836         for (te= soops->tree.first; te; te= te->next) {
837                 if (do_outliner_item_activate(C, scene, ar, soops, te, extend, fmval)) break;
838         }
839         
840         if (te) {
841                 ED_undo_push(C, "Outliner click event");
842         }
843         else {
844                 short selecting= -1;
845                 int row;
846                 
847                 /* get row number - 100 here is just a dummy value since we don't need the column */
848                 UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, 
849                                                 fmval[0], fmval[1], NULL, &row);
850                 
851                 /* select relevant row */
852                 if (outliner_select(soops, &soops->tree, &row, &selecting)) {
853                 
854                         soops->storeflag |= SO_TREESTORE_REDRAW;
855                 
856                         /* no need for undo push here, only changing outliner data which is
857                          * scene level - campbell */
858                         /* ED_undo_push(C, "Outliner selection event"); */
859                 }
860         }
861         
862         ED_region_tag_redraw(ar);
863
864         return OPERATOR_FINISHED;
865 }
866
867 void OUTLINER_OT_item_activate(wmOperatorType *ot)
868 {
869         ot->name = "Activate Item";
870         ot->idname = "OUTLINER_OT_item_activate";
871         ot->description = "Handle mouse clicks to activate/select items";
872         
873         ot->invoke = outliner_item_activate;
874         
875         ot->poll = ED_operator_outliner_active;
876         
877         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection for activation");
878 }
879
880 /* ****************************************************** */
881
882 /* **************** Border Select Tool ****************** */
883 static void outliner_item_border_select(Scene *scene, SpaceOops *soops, rctf *rectf, TreeElement *te, int gesture_mode)
884 {
885         TreeStoreElem *tselem= TREESTORE(te);
886
887         if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
888                 if (gesture_mode == GESTURE_MODAL_SELECT) {
889                         tselem->flag |= TSE_SELECTED;
890                 }
891                 else {
892                         tselem->flag &= ~TSE_SELECTED;
893                 }
894         }
895
896         /* Look at its children. */
897         if ((tselem->flag & TSE_CLOSED) == 0) {
898                 for (te = te->subtree.first; te; te = te->next) {
899                         outliner_item_border_select(scene, soops, rectf, te, gesture_mode);
900                 }
901         }
902         return;
903 }
904
905 static int outliner_border_select_exec(bContext *C, wmOperator *op)
906 {
907         Scene *scene= CTX_data_scene(C);
908         SpaceOops *soops= CTX_wm_space_outliner(C);
909         ARegion *ar= CTX_wm_region(C);
910         TreeElement *te;
911         rcti rect;
912         rctf rectf;
913         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
914
915         rect.xmin = RNA_int_get(op->ptr, "xmin");
916         rect.ymin = RNA_int_get(op->ptr, "ymin");
917         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
918
919         rect.xmax = RNA_int_get(op->ptr, "xmax");
920         rect.ymax = RNA_int_get(op->ptr, "ymax");
921         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
922
923         for (te= soops->tree.first; te; te= te->next) {
924                 outliner_item_border_select(scene, soops, &rectf, te, gesture_mode);
925         }
926
927         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
928         ED_region_tag_redraw(ar);
929
930         return OPERATOR_FINISHED;
931 }
932
933 void OUTLINER_OT_select_border(wmOperatorType *ot)
934 {
935         /* identifiers */
936         ot->name = "Border Select";
937         ot->idname = "OUTLINER_OT_select_border";
938         ot->description = "Use box selection to select tree elements";
939
940         /* api callbacks */
941         ot->invoke = WM_border_select_invoke;
942         ot->exec = outliner_border_select_exec;
943         ot->modal = WM_border_select_modal;
944         ot->cancel = WM_border_select_cancel;
945
946         ot->poll = ED_operator_outliner_active;
947
948         /* flags */
949         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
950
951         /* rna */
952         WM_operator_properties_gesture_border(ot, FALSE);
953 }
954
955 /* ****************************************************** */