diff options
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_select.c')
-rw-r--r-- | source/blender/editors/space_outliner/outliner_select.c | 395 |
1 files changed, 186 insertions, 209 deletions
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 9f79b575966..670be7611e4 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -44,12 +44,14 @@ #include "BLI_listbase.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_object.h" +#include "BKE_layer.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_armature.h" +#include "DEG_depsgraph.h" + #include "ED_armature.h" #include "ED_object.h" #include "ED_screen.h" @@ -68,61 +70,12 @@ #include "outliner_intern.h" -/* ****************************************************** */ -/* Outliner Selection (gray-blue highlight for rows) */ - -static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting) -{ - TreeElement *te; - TreeStoreElem *tselem; - bool changed = false; - - for (te = lb->first; te && *index >= 0; te = te->next, (*index)--) { - tselem = TREESTORE(te); - - /* if we've encountered the right item, set its 'Outliner' selection status */ - if (*index == 0) { - /* this should be the last one, so no need to do anything with index */ - if ((te->flag & TE_ICONROW) == 0) { - /* -1 value means toggle testing for now... */ - if (*selecting == -1) { - if (tselem->flag & TSE_SELECTED) - *selecting = 0; - else - *selecting = 1; - } - - /* set selection */ - if (*selecting) - tselem->flag |= TSE_SELECTED; - else - tselem->flag &= ~TSE_SELECTED; - - changed |= true; - } - } - else if (TSELEM_OPEN(tselem, soops)) { - /* Only try selecting sub-elements if we haven't hit the right element yet - * - * Hack warning: - * Index must be reduced before supplying it to the sub-tree to try to do - * selection, however, we need to increment it again for the next loop to - * function correctly - */ - (*index)--; - changed |= outliner_select(soops, &te->subtree, index, selecting); - (*index)++; - } - } - - return changed; -} /* ****************************************************** */ /* Outliner Element Selection/Activation on Click */ static eOLDrawState tree_element_active_renderlayer( - bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { Scene *sce; @@ -146,14 +99,14 @@ static eOLDrawState tree_element_active_renderlayer( * CTRL+LMB: Select/Deselect object and all cildren * CTRL+SHIFT+LMB: Add/Remove object and all children */ -static void do_outliner_object_select_recursive(Scene *scene, Object *ob_parent, bool select) +static void do_outliner_object_select_recursive(SceneLayer *sl, Object *ob_parent, bool select) { Base *base; - for (base = FIRSTBASE; base; base = base->next) { + for (base = FIRSTBASE(sl); base; base = base->next) { Object *ob = base->object; - if ((((ob->restrictflag & OB_RESTRICT_VIEW) == 0) && BKE_object_is_child_recursive(ob_parent, ob))) { - ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); + if ((((base->flag & BASE_VISIBLED) == 0) && BKE_object_is_child_recursive(ob_parent, ob))) { + ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); } } } @@ -184,7 +137,7 @@ static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_p } static eOLDrawState tree_element_set_active_object( - bContext *C, Scene *scene, SpaceOops *soops, + bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set, bool recursive) { TreeStoreElem *tselem = TREESTORE(te); @@ -198,7 +151,7 @@ static eOLDrawState tree_element_set_active_object( } else { ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == OBACT) { + if (ob == OBACT(sl)) { return OL_DRAWSEL_NONE; } } @@ -208,34 +161,34 @@ static eOLDrawState tree_element_set_active_object( sce = (Scene *)outliner_search_back(soops, te, ID_SCE); if (sce && scene != sce) { - ED_screen_set_scene(C, CTX_wm_screen(C), sce); + WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce); scene = sce; } /* find associated base in current scene */ - base = BKE_scene_base_find(scene, ob); + base = BKE_scene_layer_base_find(sl, ob); if (base) { if (set == OL_SETSEL_EXTEND) { /* swap select */ - if (base->flag & SELECT) - ED_base_object_select(base, BA_DESELECT); + if (base->flag & BASE_SELECTED) + ED_object_base_select(base, BA_DESELECT); else - ED_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); } else { /* deleselect all */ - BKE_scene_base_deselect_all(scene); - ED_base_object_select(base, BA_SELECT); + BKE_scene_layer_base_deselect_all(sl); + ED_object_base_select(base, BA_SELECT); } if (recursive) { /* Recursive select/deselect for Object hierarchies */ - do_outliner_object_select_recursive(scene, ob, (ob->flag & SELECT) != 0); + do_outliner_object_select_recursive(sl, ob, (ob->flag & SELECT) != 0); } - if (C) { - ED_base_object_activate(C, base); /* adds notifier */ + if (set != OL_SETSEL_NONE) { + ED_object_base_activate(C, base); /* adds notifier */ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } } @@ -247,7 +200,7 @@ static eOLDrawState tree_element_set_active_object( } static eOLDrawState tree_element_active_material( - bContext *C, Scene *scene, SpaceOops *soops, + bContext *C, Scene *UNUSED(scene), SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set) { TreeElement *tes; @@ -256,7 +209,7 @@ static eOLDrawState tree_element_active_material( /* we search for the object parent */ ob = (Object *)outliner_search_back(soops, te, ID_OB); // note: ob->matbits can be NULL when a local object points to a library mesh. - if (ob == NULL || ob != OBACT || ob->matbits == NULL) { + if (ob == NULL || ob != OBACT(sl) || ob->matbits == NULL) { return OL_DRAWSEL_NONE; /* just paranoia */ } @@ -293,19 +246,19 @@ static eOLDrawState tree_element_active_material( /* Tagging object for update seems a bit stupid here, but looks like we have to do it * for render views to update. See T42973. * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */ - DAG_id_tag_update((ID *)ob, OB_RECALC_OB); + DEG_id_tag_update((ID *)ob, OB_RECALC_OB); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); } return OL_DRAWSEL_NONE; } static eOLDrawState tree_element_active_texture( - bContext *C, Scene *scene, SpaceOops *UNUSED(soops), + bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *UNUSED(soops), TreeElement *te, const eOLSetState set) { TreeElement *tep; TreeStoreElem /* *tselem,*/ *tselemp; - Object *ob = OBACT; + Object *ob = OBACT(sl); SpaceButs *sbuts = NULL; if (ob == NULL) { @@ -387,14 +340,14 @@ static eOLDrawState tree_element_active_texture( static eOLDrawState tree_element_active_lamp( - bContext *UNUSED(C), Scene *scene, SpaceOops *soops, + bContext *UNUSED(C), Scene *UNUSED(scene), SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set) { Object *ob; /* we search for the object parent */ ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == NULL || ob != OBACT) { + if (ob == NULL || ob != OBACT(sl)) { /* just paranoia */ return OL_DRAWSEL_NONE; } @@ -410,7 +363,7 @@ static eOLDrawState tree_element_active_lamp( } static eOLDrawState tree_element_active_camera( - bContext *UNUSED(C), Scene *scene, SpaceOops *soops, + bContext *UNUSED(C), Scene *scene, SceneLayer *UNUSED(sl), SpaceOops *soops, TreeElement *te, const eOLSetState set) { Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); @@ -423,7 +376,7 @@ static eOLDrawState tree_element_active_camera( } static eOLDrawState tree_element_active_world( - bContext *C, Scene *scene, SpaceOops *UNUSED(soops), + bContext *C, Scene *scene, SceneLayer *UNUSED(sl), SpaceOops *UNUSED(soops), TreeElement *te, const eOLSetState set) { TreeElement *tep; @@ -440,7 +393,7 @@ static eOLDrawState tree_element_active_world( if (set != OL_SETSEL_NONE) { /* make new scene active */ if (sce && scene != sce) { - ED_screen_set_scene(C, CTX_wm_screen(C), sce); + WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce); } } @@ -456,7 +409,7 @@ static eOLDrawState tree_element_active_world( } static eOLDrawState tree_element_active_defgroup( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) + bContext *C, SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { Object *ob; @@ -466,21 +419,20 @@ static eOLDrawState tree_element_active_defgroup( BLI_assert(te->index + 1 >= 0); ob->actdef = te->index + 1; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); } else { - if (ob == OBACT) { + if (ob == OBACT(sl)) if (ob->actdef == te->index + 1) { return OL_DRAWSEL_NORMAL; } - } } return OL_DRAWSEL_NONE; } static eOLDrawState tree_element_active_posegroup( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { Object *ob = (Object *)tselem->id; @@ -491,7 +443,7 @@ static eOLDrawState tree_element_active_posegroup( } } else { - if (ob == OBACT && ob->pose) { + if (ob == OBACT(sl) && ob->pose) { if (ob->pose->active_group == te->index + 1) { return OL_DRAWSEL_NORMAL; } @@ -501,7 +453,7 @@ static eOLDrawState tree_element_active_posegroup( } static eOLDrawState tree_element_active_posechannel( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) + bContext *C, Scene *UNUSED(scene), SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) { Object *ob = (Object *)tselem->id; bArmature *arm = ob->data; @@ -535,7 +487,7 @@ static eOLDrawState tree_element_active_posechannel( } } else { - if (ob == OBACT && ob->pose) { + if (ob == OBACT(sl) && ob->pose) { if (pchan->bone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; } @@ -545,14 +497,14 @@ static eOLDrawState tree_element_active_posechannel( } static eOLDrawState tree_element_active_bone( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) + bContext *C, SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) { bArmature *arm = (bArmature *)tselem->id; Bone *bone = te->directdata; if (set != OL_SETSEL_NONE) { if (!(bone->flag & BONE_HIDDEN_P)) { - Object *ob = OBACT; + Object *ob = OBACT(sl); if (ob) { if (set != OL_SETSEL_EXTEND) { /* single select forces all other bones to get unselected */ @@ -581,7 +533,7 @@ static eOLDrawState tree_element_active_bone( } } else { - Object *ob = OBACT; + Object *ob = OBACT(sl); if (ob && ob->data == arm) { if (bone->flag & BONE_SELECTED) { @@ -654,7 +606,7 @@ static eOLDrawState tree_element_active_ebone( } static eOLDrawState tree_element_active_modifier( - bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) { if (set != OL_SETSEL_NONE) { Object *ob = (Object *)tselem->id; @@ -682,7 +634,7 @@ static eOLDrawState tree_element_active_psys( } static int tree_element_active_constraint( - bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) { if (set != OL_SETSEL_NONE) { Object *ob = (Object *)tselem->id; @@ -695,7 +647,7 @@ static int tree_element_active_constraint( } static eOLDrawState tree_element_active_text( - bContext *UNUSED(C), Scene *UNUSED(scene), SpaceOops *UNUSED(soops), + bContext *UNUSED(C), Scene *UNUSED(scene), SceneLayer *UNUSED(sl), SpaceOops *UNUSED(soops), TreeElement *UNUSED(te), int UNUSED(set)) { // XXX removed @@ -703,10 +655,10 @@ static eOLDrawState tree_element_active_text( } static eOLDrawState tree_element_active_pose( - bContext *C, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) + bContext *C, Scene *scene, SceneLayer *sl, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) { Object *ob = (Object *)tselem->id; - Base *base = BKE_scene_base_find(scene, ob); + Base *base = BKE_scene_layer_base_find(sl, ob); if (base == NULL) { /* Armature not instantiated in current scene (e.g. inside an appended group...). */ @@ -792,7 +744,7 @@ static eOLDrawState tree_element_active_sequence_dup( } static eOLDrawState tree_element_active_keymap_item( - bContext *UNUSED(C), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) + bContext *UNUSED(C), Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) { wmKeyMapItem *kmi = te->directdata; @@ -808,84 +760,116 @@ static eOLDrawState tree_element_active_keymap_item( return OL_DRAWSEL_NONE; } +static eOLDrawState tree_element_active_collection( + bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) +{ + if (set == OL_SETSEL_NONE) { + LayerCollection *active = CTX_data_layer_collection(C); + + /* sometimes the renderlayer has no LayerCollection at all */ + if (active == NULL) { + return OL_DRAWSEL_NONE; + } + + if ((tselem->type == TSE_SCENE_COLLECTION && active->scene_collection == te->directdata) || + (tselem->type == TSE_LAYER_COLLECTION && active == te->directdata)) + { + return OL_DRAWSEL_NORMAL; + } + } + /* don't allow selecting a scene collection, it can have multiple layer collection + * instances (which one would the user want to be selected then?) */ + else if (tselem->type == TSE_LAYER_COLLECTION) { + SceneLayer *sl = CTX_data_scene_layer(C); + LayerCollection *lc = te->directdata; + const int collection_index = BKE_layer_collection_findindex(sl, lc); + + BLI_assert(collection_index >= 0); + sl->active_collection = collection_index; + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + } + + return OL_DRAWSEL_NONE; +} + /* ---------------------------------------------- */ /* generic call for ID data check or make/check active in UI */ -eOLDrawState tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, +eOLDrawState tree_element_active(bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *soops, TreeElement *te, const eOLSetState set, const bool handle_all_types) { switch (te->idcode) { /* Note: ID_OB only if handle_all_type is true, else objects are handled specially to allow multiple - * selection. See do_outliner_item_activate_from_cursor. */ + * selection. See do_outliner_item_activate. */ case ID_OB: if (handle_all_types) { - return tree_element_set_active_object(C, scene, soops, te, set, false); + return tree_element_set_active_object(C, scene, sl, soops, te, set, false); } break; case ID_MA: - return tree_element_active_material(C, scene, soops, te, set); + return tree_element_active_material(C, scene, sl, soops, te, set); case ID_WO: - return tree_element_active_world(C, scene, soops, te, set); + return tree_element_active_world(C, scene, sl, soops, te, set); case ID_LA: - return tree_element_active_lamp(C, scene, soops, te, set); + return tree_element_active_lamp(C, scene, sl, soops, te, set); case ID_TE: - return tree_element_active_texture(C, scene, soops, te, set); + return tree_element_active_texture(C, scene, sl, soops, te, set); case ID_TXT: - return tree_element_active_text(C, scene, soops, te, set); + return tree_element_active_text(C, scene, sl, soops, te, set); case ID_CA: - return tree_element_active_camera(C, scene, soops, te, set); + return tree_element_active_camera(C, scene, sl, soops, te, set); } return OL_DRAWSEL_NONE; } /** * Generic call for non-id data to make/check active in UI - * - * \note Context can be NULL when ``(set == OL_SETSEL_NONE)`` */ eOLDrawState tree_element_type_active( - bContext *C, Scene *scene, SpaceOops *soops, + bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) { switch (tselem->type) { case TSE_DEFGROUP: - return tree_element_active_defgroup(C, scene, te, tselem, set); + return tree_element_active_defgroup(C, sl, te, tselem, set); case TSE_BONE: - return tree_element_active_bone(C, scene, te, tselem, set, recursive); + return tree_element_active_bone(C, sl, te, tselem, set, recursive); case TSE_EBONE: return tree_element_active_ebone(C, scene, te, tselem, set, recursive); case TSE_MODIFIER: - return tree_element_active_modifier(C, te, tselem, set); + return tree_element_active_modifier(C, scene, sl, te, tselem, set); case TSE_LINKED_OB: if (set != OL_SETSEL_NONE) { - tree_element_set_active_object(C, scene, soops, te, set, false); + tree_element_set_active_object(C, scene, sl, soops, te, set, false); } - else if (tselem->id == (ID *)OBACT) { + else if (tselem->id == (ID *)OBACT(sl)) { return OL_DRAWSEL_NORMAL; } break; case TSE_LINKED_PSYS: return tree_element_active_psys(C, scene, te, tselem, set); case TSE_POSE_BASE: - return tree_element_active_pose(C, scene, te, tselem, set); + return tree_element_active_pose(C, scene, sl, te, tselem, set); case TSE_POSE_CHANNEL: - return tree_element_active_posechannel(C, scene, te, tselem, set, recursive); + return tree_element_active_posechannel(C, scene, sl, te, tselem, set, recursive); case TSE_CONSTRAINT: - return tree_element_active_constraint(C, te, tselem, set); + return tree_element_active_constraint(C, scene, sl, te, tselem, set); case TSE_R_LAYER: - return tree_element_active_renderlayer(C, te, tselem, set); + return tree_element_active_renderlayer(C, scene, sl, te, tselem, set); case TSE_POSEGRP: - return tree_element_active_posegroup(C, scene, te, tselem, set); + return tree_element_active_posegroup(C, scene, sl, te, tselem, set); case TSE_SEQUENCE: return tree_element_active_sequence(C, scene, te, tselem, set); case TSE_SEQUENCE_DUP: return tree_element_active_sequence_dup(scene, te, tselem, set); case TSE_KEYMAP_ITEM: - return tree_element_active_keymap_item(C, te, tselem, set); + return tree_element_active_keymap_item(C, scene, sl, te, tselem, set); case TSE_GP_LAYER: - //return tree_element_active_gplayer(C, scene, te, tselem, set); + //return tree_element_active_gplayer(C, scene, s, te, tselem, set); break; - + case TSE_SCENE_COLLECTION: + case TSE_LAYER_COLLECTION: + return tree_element_active_collection(C, te, tselem, set); } return OL_DRAWSEL_NONE; } @@ -899,16 +883,16 @@ eOLDrawState tree_element_type_active( * Needed to run from operators accessed from a menu. */ static void do_outliner_item_activate_tree_element( - bContext *C, Scene *scene, SpaceOops *soops, + bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, - bool extend, bool recursive) + const bool extend, const bool recursive) { /* always makes active object, except for some specific types. * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want * to switch out of edit mode (see T48328 for details). */ - if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) { + if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE, TSE_LAYER_COLLECTION)) { tree_element_set_active_object( - C, scene, soops, te, + C, scene, sl, soops, te, (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive && tselem->type == 0); } @@ -917,7 +901,7 @@ static void do_outliner_item_activate_tree_element( /* editmode? */ if (te->idcode == ID_SCE) { if (scene != (Scene *)tselem->id) { - ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id); + WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id); } } else if (te->idcode == ID_GR) { @@ -934,83 +918,79 @@ static void do_outliner_item_activate_tree_element( } for (gob = gr->gobject.first; gob; gob = gob->next) { - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel); + ED_object_base_select(BKE_scene_layer_base_find(sl, gob->ob), sel); } } else { - BKE_scene_base_deselect_all(scene); + BKE_scene_layer_base_deselect_all(sl); for (gob = gr->gobject.first; gob; gob = gob->next) { - if ((gob->ob->flag & SELECT) == 0) - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT); + Base *base = BKE_scene_layer_base_find(sl, gob->ob); + /* Object may not be in this scene */ + if (base != NULL) { + if ((base->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base, BA_SELECT); + } + } } } - + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); } else { // rest of types - tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false); + tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NORMAL, false); } } else { - tree_element_type_active( - C, scene, soops, te, tselem, - extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive); + tree_element_type_active(C, scene, sl, soops, te, tselem, + extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive); } } /** - * Activates tree items, also handles clicking on arrows. + * \param extend: Don't deselect other items, only modify \a te. + * \param toggle: Select \a te when not selected, deselect when selected. */ -static bool do_outliner_item_activate_from_cursor( - bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, bool extend, bool recursive, const float mval[2]) +static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle) { - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); - bool openclose = false; - - /* open close icon */ - if ((te->flag & TE_ICONROW) == 0) { // hidden icon, no open/close - if (mval[0] > te->xs && mval[0] < te->xs + UI_UNIT_X) - openclose = true; - } - - if (openclose) { - /* all below close/open? */ - if (extend) { - tselem->flag &= ~TSE_CLOSED; - outliner_set_flag(&te->subtree, TSE_CLOSED, !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1)); - } - else { - if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED; - else tselem->flag |= TSE_CLOSED; - - } - - return true; - } - /* name and first icon */ - else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) { - do_outliner_item_activate_tree_element( - C, scene, soops, - te, tselem, - extend, recursive); - return true; - } + TreeStoreElem *tselem = TREESTORE(te); + const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED); + + if (extend == false) { + outliner_set_flag(&soops->tree, TSE_SELECTED, false); } - - for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_activate_from_cursor(C, scene, ar, soops, te, extend, recursive, mval)) { - return true; - } + tselem->flag = new_flag; +} + +static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children) +{ + TreeStoreElem *tselem = TREESTORE(te); + if (toggle_children) { + tselem->flag &= ~TSE_CLOSED; + + const bool all_opened = !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1); + outliner_set_flag(&te->subtree, TSE_CLOSED, all_opened); + } + else { + tselem->flag ^= TSE_CLOSED; } - return false; +} + +static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x) +{ + return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X); +} + +static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x) +{ + return (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && + !(soops->flag & SO_HIDE_RESTRICTCOLS) && + (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); } /** @@ -1024,10 +1004,11 @@ void outliner_item_do_activate_from_tree_element( bool extend, bool recursive) { Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); SpaceOops *soops = CTX_wm_space_outliner(C); do_outliner_item_activate_tree_element( - C, scene, soops, + C, scene, sl, soops, te, tselem, extend, recursive); } @@ -1041,56 +1022,52 @@ int outliner_item_do_activate_from_cursor( bContext *C, const int mval[2], bool extend, bool recursive) { - Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); TreeElement *te; - float fmval[2]; + float view_mval[2]; + bool changed = false, rebuild_tree = false; - UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]); - if (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && - !(soops->flag & SO_HIDE_RESTRICTCOLS) && - (fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)) - { + if (outliner_is_co_within_restrict_columns(soops, ar, view_mval[0])) { return OPERATOR_CANCELLED; } - for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_activate_from_cursor(C, scene, ar, soops, te, extend, recursive, fmval)) { - break; - } + if (!(te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]))) { + /* skip */ } - - if (te) { - ED_undo_push(C, "Outliner click event"); + else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { + outliner_item_toggle_closed(te, extend); + changed = true; + rebuild_tree = true; } else { - short selecting = -1; - int row; - - /* get row number - 100 here is just a dummy value since we don't need the column */ - UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, - fmval[0], fmval[1], NULL, &row); - - /* select relevant row */ - if (outliner_select(soops, &soops->tree, &row, &selecting)) { - + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); + /* the row may also contain children, if one is hovered we want this instead of current te */ + TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]); + TreeStoreElem *activate_tselem = TREESTORE(activate_te); + + outliner_item_select(soops, activate_te, extend, extend); + do_outliner_item_activate_tree_element(C, scene, sl, soops, activate_te, activate_tselem, extend, recursive); + changed = true; + } + + if (changed) { + if (!rebuild_tree) { + /* only needs to redraw, no rebuild */ soops->storeflag |= SO_TREESTORE_REDRAW; - - /* no need for undo push here, only changing outliner data which is - * scene level - campbell */ - /* ED_undo_push(C, "Outliner selection event"); */ } + ED_undo_push(C, "Outliner selection change"); + ED_region_tag_redraw(ar); } - - ED_region_tag_redraw(ar); return OPERATOR_FINISHED; } /* event can enterkey, then it opens/closes */ -static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *event) +static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bool extend = RNA_boolean_get(op->ptr, "extend"); bool recursive = RNA_boolean_get(op->ptr, "recursive"); @@ -1103,7 +1080,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot) ot->idname = "OUTLINER_OT_item_activate"; ot->description = "Handle mouse clicks to activate/select items"; - ot->invoke = outliner_item_activate; + ot->invoke = outliner_item_activate_invoke; ot->poll = ED_operator_outliner_active; |