From ed3b7a5cd4597274f523d832494eabdf153aa597 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 20 Nov 2017 16:01:04 +1100 Subject: Fix T53342: Outliner 'select hierarchy' broken Was using cursor position from within menu, clicking on the same position for every selected item (toggling). Now operate on each selected outliner element, without toggling. --- .../editors/space_outliner/outliner_select.c | 186 +++++++++++++-------- 1 file changed, 116 insertions(+), 70 deletions(-) (limited to 'source/blender/editors/space_outliner/outliner_select.c') diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 5cc83d3ee94..9f79b575966 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -816,7 +816,7 @@ eOLDrawState tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, Tr { 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. */ + * selection. See do_outliner_item_activate_from_cursor. */ case ID_OB: if (handle_all_types) { return tree_element_set_active_object(C, scene, soops, te, set, false); @@ -892,10 +892,85 @@ eOLDrawState tree_element_type_active( /* ================================================ */ -static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, bool extend, bool recursive, const float mval[2]) +/** + * Action when clicking to activate an item (typically under the mouse cursor), + * but don't do any cursor intersection checks. + * + * Needed to run from operators accessed from a menu. + */ +static void do_outliner_item_activate_tree_element( + bContext *C, Scene *scene, SpaceOops *soops, + TreeElement *te, TreeStoreElem *tselem, + bool extend, 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)) { + tree_element_set_active_object( + C, scene, soops, te, + (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive && tselem->type == 0); + } + + if (tselem->type == 0) { // the lib blocks + /* editmode? */ + if (te->idcode == ID_SCE) { + if (scene != (Scene *)tselem->id) { + ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id); + } + } + else if (te->idcode == ID_GR) { + Group *gr = (Group *)tselem->id; + GroupObject *gob; + + if (extend) { + int sel = BA_SELECT; + for (gob = gr->gobject.first; gob; gob = gob->next) { + if (gob->ob->flag & SELECT) { + sel = BA_DESELECT; + break; + } + } + + for (gob = gr->gobject.first; gob; gob = gob->next) { + ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel); + } + } + else { + BKE_scene_base_deselect_all(scene); + + 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); + } + } + + 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); + } + + } + else { + tree_element_type_active( + C, scene, soops, te, tselem, + extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive); + } +} + +/** + * Activates tree items, also handles clicking on arrows. + */ +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]) { - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); bool openclose = false; @@ -922,78 +997,49 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp } /* name and first icon */ else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) { - - /* 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)) { - tree_element_set_active_object(C, scene, soops, te, - (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive && tselem->type == 0); - } - - if (tselem->type == 0) { // the lib blocks - /* editmode? */ - if (te->idcode == ID_SCE) { - if (scene != (Scene *)tselem->id) { - ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id); - } - } - else if (te->idcode == ID_GR) { - Group *gr = (Group *)tselem->id; - GroupObject *gob; - - if (extend) { - int sel = BA_SELECT; - for (gob = gr->gobject.first; gob; gob = gob->next) { - if (gob->ob->flag & SELECT) { - sel = BA_DESELECT; - break; - } - } - - for (gob = gr->gobject.first; gob; gob = gob->next) { - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel); - } - } - else { - BKE_scene_base_deselect_all(scene); - - 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); - } - } - - 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); - } - - } - else { - tree_element_type_active(C, scene, soops, te, tselem, - extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive); - } - + do_outliner_item_activate_tree_element( + C, scene, soops, + te, tselem, + extend, recursive); return true; } } for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, mval)) { + if (do_outliner_item_activate_from_cursor(C, scene, ar, soops, te, extend, recursive, mval)) { return true; } } return false; } -int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recursive) +/** + * A version of #outliner_item_do_acticate_from_cursor that takes the tree element directly. + * and doesn't depend on the pointer position. + * + * This allows us to simulate clicking on an item without dealing with the mouse cursor. + */ +void outliner_item_do_activate_from_tree_element( + bContext *C, TreeElement *te, TreeStoreElem *tselem, + bool extend, bool recursive) +{ + Scene *scene = CTX_data_scene(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + + do_outliner_item_activate_tree_element( + C, scene, soops, + te, tselem, + extend, recursive); +} + +/** + * Action to run when clicking in the outliner, + * + * May expend/collapse branches or activate items. + * */ +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); @@ -1001,7 +1047,7 @@ int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recur TreeElement *te; float fmval[2]; - UI_view2d_region_to_view(&ar->v2d, x, y, &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fmval[0], &fmval[1]); if (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && @@ -1011,7 +1057,9 @@ int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recur } for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, fmval)) break; + if (do_outliner_item_activate_from_cursor(C, scene, ar, soops, te, extend, recursive, fmval)) { + break; + } } if (te) { @@ -1046,9 +1094,7 @@ static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *ev { bool extend = RNA_boolean_get(op->ptr, "extend"); bool recursive = RNA_boolean_get(op->ptr, "recursive"); - int x = event->mval[0]; - int y = event->mval[1]; - return outliner_item_do_activate(C, x, y, extend, recursive); + return outliner_item_do_activate_from_cursor(C, event->mval, extend, recursive); } void OUTLINER_OT_item_activate(wmOperatorType *ot) -- cgit v1.2.3