diff options
4 files changed, 129 insertions, 97 deletions
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 32a67d57d0f..dae8f8a91ce 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -216,6 +216,16 @@ typedef struct TreeViewContext { Object *ob_pose; } TreeViewContext; +typedef enum TreeItemSelectAction { + OL_ITEM_DESELECT = 0, /* Deselect the item */ + OL_ITEM_SELECT = (1 << 0), /* Select the item */ + OL_ITEM_SELECT_DATA = (1 << 1), /* Select object data */ + OL_ITEM_ACTIVATE = (1 << 2), /* Activate the item */ + OL_ITEM_EXTEND = (1 << 3), /* Extend the current selection */ + OL_ITEM_RECURSIVE = (1 << 4), /* Select recursively */ + OL_ITEM_TOGGLE_MODE = (1 << 5) /* Temporary */ +} TreeItemSelectAction; + /* outliner_tree.c ----------------------------------------------- */ void outliner_free_tree(ListBase *tree); @@ -268,20 +278,17 @@ eOLDrawState tree_element_active(struct bContext *C, const eOLSetState set, const bool handle_all_types); -void outliner_item_do_activate_from_tree_element( - struct bContext *C, TreeElement *te, TreeStoreElem *tselem, bool extend, bool recursive); - -void outliner_item_select(struct SpaceOutliner *soops, - const struct TreeElement *te, - const bool extend, - const bool toggle); +void outliner_item_select(struct bContext *C, + struct SpaceOutliner *soops, + struct TreeElement *te, + const short select_flag); void outliner_object_mode_toggle(struct bContext *C, Scene *scene, ViewLayer *view_layer, Base *base); -void outliner_element_activate(struct SpaceOutliner *soops, struct TreeStoreElem *tselem); +void outliner_set_walk_element(struct SpaceOutliner *soops, struct TreeStoreElem *tselem); bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x); bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x); diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 40fb5c7be3a..d9db4edc88a 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -111,7 +111,7 @@ static bool do_outliner_activate_common(bContext *C, * If extend is used, we try to have the other compatible selected objects in the new mode as well. * Otherwise only the new object will be active, selected and in the edit mode. */ -static void do_outliner_activate_obdata( +static void do_outliner_item_editmode_toggle( bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) { Main *bmain = CTX_data_main(C); @@ -159,7 +159,7 @@ static void do_outliner_activate_obdata( } } -static void do_outliner_activate_pose( +static void do_outliner_item_posemode_toggle( bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) { Main *bmain = CTX_data_main(C); @@ -214,10 +214,42 @@ void outliner_object_mode_toggle(bContext *C, Scene *scene, ViewLayer *view_laye { Object *obact = OBACT(view_layer); if (obact->mode & OB_MODE_EDIT) { - do_outliner_activate_obdata(C, scene, view_layer, base, true); + do_outliner_item_editmode_toggle(C, scene, view_layer, base, true); } else if (obact->mode & OB_MODE_POSE) { - do_outliner_activate_pose(C, scene, view_layer, base, true); + do_outliner_item_posemode_toggle(C, scene, view_layer, base, true); + } +} + +/* Toggle the item's interaction mode if supported */ +static void outliner_item_mode_toggle(bContext *C, + TreeViewContext *tvc, + TreeElement *te, + const bool extend) +{ + TreeStoreElem *tselem = TREESTORE(te); + + if (tselem->type == 0) { + if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) { + Object *ob = (Object *)outliner_search_back(te, ID_OB); + if ((ob != NULL) && (ob->data == tselem->id)) { + Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); + if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { + do_outliner_item_editmode_toggle(C, tvc->scene, tvc->view_layer, base, extend); + } + } + } + else if (ELEM(te->idcode, ID_GD)) { + /* set grease pencil to object mode */ + WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } + } + else if (tselem->type == TSE_POSE_BASE) { + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); + if (base != NULL) { + do_outliner_item_posemode_toggle(C, tvc->scene, tvc->view_layer, base, extend); + } } } @@ -862,8 +894,8 @@ static eOLDrawState tree_element_active_text(bContext *UNUSED(C), return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_pose(bContext *C, - Scene *scene, +static eOLDrawState tree_element_active_pose(bContext *UNUSED(C), + Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *UNUSED(te), TreeStoreElem *tselem, @@ -878,7 +910,6 @@ static eOLDrawState tree_element_active_pose(bContext *C, } if (set != OL_SETSEL_NONE) { - do_outliner_activate_pose(C, scene, view_layer, base, (set == OL_SETSEL_EXTEND)); } else { if (ob->mode & OB_MODE_POSE) { @@ -1112,11 +1143,11 @@ eOLDrawState tree_element_type_active(bContext *C, /* ================================================ */ -/* Activate a tree store element and set the walk navigation start element */ -void outliner_element_activate(SpaceOutliner *soops, TreeStoreElem *tselem) +/* Set the walk navigation start element */ +void outliner_set_walk_element(SpaceOutliner *soops, TreeStoreElem *tselem) { - outliner_flag_set(&soops->tree, TSE_ACTIVE | TSE_ACTIVE_WALK, false); - tselem->flag |= TSE_ACTIVE | TSE_ACTIVE_WALK; + outliner_flag_set(&soops->tree, TSE_ACTIVE_WALK, false); + tselem->flag |= TSE_ACTIVE_WALK; } /** @@ -1132,9 +1163,8 @@ static void do_outliner_item_activate_tree_element(bContext *C, TreeStoreElem *tselem, const bool extend, const bool recursive, - const bool is_over_name_icons) + const bool do_activate_data) { - bool do_activate_data = soops->flag & SO_SYNC_SELECT || is_over_name_icons; /* Always makes active object, except for some specific types. */ if (ELEM(tselem->type, TSE_SEQUENCE, @@ -1152,7 +1182,6 @@ static void do_outliner_item_activate_tree_element(bContext *C, /* Support pose mode toggle, keeping the active object as is. */ } else if (do_activate_data) { - /* Only activate when synced selection is enabled */ tree_element_set_active_object(C, tvc->scene, tvc->view_layer, @@ -1163,8 +1192,7 @@ static void do_outliner_item_activate_tree_element(bContext *C, recursive && tselem->type == 0); } - /* Mark as active in the outliner */ - outliner_element_activate(soops, tselem); + outliner_set_walk_element(soops, tselem); if (tselem->type == 0) { // the lib blocks if (do_activate_data == false) { @@ -1215,19 +1243,6 @@ static void do_outliner_item_activate_tree_element(bContext *C, DEG_id_tag_update(&tvc->scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, tvc->scene); } - else if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) { - Object *ob = (Object *)outliner_search_back(te, ID_OB); - if ((ob != NULL) && (ob->data == tselem->id)) { - Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { - do_outliner_activate_obdata(C, tvc->scene, tvc->view_layer, base, extend); - } - } - } - else if (ELEM(te->idcode, ID_GD)) { - /* set grease pencil to object mode */ - WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } else { // rest of types tree_element_active(C, tvc, soops, te, OL_SETSEL_NORMAL, false); } @@ -1238,23 +1253,49 @@ static void do_outliner_item_activate_tree_element(bContext *C, } } -/** - * \param extend: Don't deselect other items, only modify \a te. - * \param toggle: Select \a te when not selected, deselect when selected. - */ -void outliner_item_select(SpaceOutliner *soops, - const TreeElement *te, - const bool extend, - const bool toggle) +/* Select the item using the set flags */ +void outliner_item_select(bContext *C, + SpaceOutliner *soops, + TreeElement *te, + const short select_flag) { TreeStoreElem *tselem = TREESTORE(te); - const short new_flag = (toggle && (tselem->flag & TSE_ACTIVE)) ? (tselem->flag ^ TSE_SELECTED) : - (tselem->flag | TSE_SELECTED); + const bool activate = select_flag & OL_ITEM_ACTIVATE; + const bool extend = select_flag & OL_ITEM_EXTEND; + const bool activate_data = select_flag & OL_ITEM_SELECT_DATA; - if (extend == false) { - outliner_flag_set(&soops->tree, TSE_SELECTED, false); + /* Clear previous active when activating and clear selection when not extending selection */ + const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED); + if (clear_flag) { + outliner_flag_set(&soops->tree, clear_flag, false); + } + + if (select_flag & OL_ITEM_SELECT) { + tselem->flag |= TSE_SELECTED; + } + else { + tselem->flag &= ~TSE_SELECTED; + } + + if (activate) { + TreeViewContext tvc; + outliner_viewcontext_init(C, &tvc); + + tselem->flag |= TSE_ACTIVE; + do_outliner_item_activate_tree_element(C, + &tvc, + soops, + te, + tselem, + extend, + select_flag & OL_ITEM_RECURSIVE, + activate_data || soops->flag & SO_SYNC_SELECT); + + /* Mode toggle on data activate for now, but move later */ + if (select_flag & OL_ITEM_TOGGLE_MODE) { + outliner_item_mode_toggle(C, &tvc, te, extend); + } } - tselem->flag = new_flag; } static bool do_outliner_range_select_recursive(ListBase *lb, @@ -1297,8 +1338,7 @@ static void do_outliner_range_select(bContext *C, /* If no active element exists, activate the element under the cursor */ if (!active) { - outliner_item_select(soops, cursor, false, false); - outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false); + outliner_item_select(C, soops, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE); return; } @@ -1311,14 +1351,13 @@ static void do_outliner_range_select(bContext *C, /* Select active if under cursor */ if (active == cursor) { - TREESTORE(cursor)->flag |= TSE_SELECTED; + outliner_item_select(C, soops, cursor, OL_ITEM_SELECT); return; } - /* If active is not selected, select the element under the cursor */ + /* If active is not selected or visible, select and activate the element under the cursor */ if (!active_selected || !outliner_is_element_visible(active)) { - outliner_item_select(soops, cursor, false, false); - outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false); + outliner_item_select(C, soops, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE); return; } @@ -1333,23 +1372,6 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, } /** - * A version of #outliner_item_do_activate_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) -{ - SpaceOutliner *soops = CTX_wm_space_outliner(C); - - TreeViewContext tvc; - outliner_viewcontext_init(C, &tvc); - - do_outliner_item_activate_tree_element(C, &tvc, soops, te, tselem, extend, recursive, false); -} - -/** * Action to run when clicking in the outliner, * * May expend/collapse branches or activate items. @@ -1401,14 +1423,17 @@ static int outliner_item_do_activate_from_cursor(bContext *C, do_outliner_range_select(C, soops, activate_te, extend); } else { - TreeViewContext tvc; - outliner_viewcontext_init(C, &tvc); - const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te, view_mval[0]); - outliner_item_select(soops, activate_te, extend, extend); - do_outliner_item_activate_tree_element( - C, &tvc, soops, activate_te, activate_tselem, extend, false, is_over_name_icons); + /* Always select unless already active and selected */ + const bool select = !extend || !(activate_tselem->flag & TSE_ACTIVE && + activate_tselem->flag & TSE_SELECTED); + + const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | + (is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) | + (extend ? OL_ITEM_EXTEND : 0) | OL_ITEM_TOGGLE_MODE; + + outliner_item_select(C, soops, activate_te, select_flag); } changed = true; @@ -1467,23 +1492,19 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot) /* **************** Box Select Tool ****************** */ static void outliner_item_box_select( - SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select) + bContext *C, SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select) { TreeStoreElem *tselem = TREESTORE(te); if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) { - if (select) { - tselem->flag |= TSE_SELECTED; - } - else { - tselem->flag &= ~TSE_SELECTED; - } + outliner_item_select( + C, soops, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND); } /* Look at its children. */ if (TSELEM_OPEN(tselem, soops)) { for (te = te->subtree.first; te; te = te->next) { - outliner_item_box_select(soops, scene, rectf, te, select); + outliner_item_box_select(C, soops, scene, rectf, te, select); } } } @@ -1505,7 +1526,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op) UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); LISTBASE_FOREACH (TreeElement *, te, &soops->tree) { - outliner_item_box_select(soops, scene, &rectf, te, select); + outliner_item_box_select(C, soops, scene, &rectf, te, select); } DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 852773d3979..943738680e6 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -403,7 +403,8 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer, const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); if (base && (ob == obact)) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; + outliner_set_walk_element(soops, tselem); } else { tselem->flag &= ~TSE_ACTIVE; @@ -425,7 +426,8 @@ static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops, EditBone *ebone = (EditBone *)te->directdata; if (ebone == ebone_active) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; + outliner_set_walk_element(soops, tselem); } else { tselem->flag &= ~TSE_ACTIVE; @@ -448,7 +450,8 @@ static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops, Bone *bone = pchan->bone; if (pchan == pchan_active) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; + outliner_set_walk_element(soops, tselem); } else { tselem->flag &= ~TSE_ACTIVE; @@ -469,7 +472,8 @@ static void outliner_select_sync_from_sequence(SpaceOutliner *soops, Sequence *seq = (Sequence *)tselem->id; if (seq == sequence_active) { - outliner_element_activate(soops, tselem); + tselem->flag |= TSE_ACTIVE; + outliner_set_walk_element(soops, tselem); } else { tselem->flag &= ~TSE_ACTIVE; @@ -525,7 +529,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer, } } else { - tselem->flag &= ~TSE_SELECTED; + tselem->flag &= ~(TSE_SELECTED | TSE_ACTIVE); } /* Sync subtree elements */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 4b780df1cbf..d04402f989c 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -574,8 +574,7 @@ static void merged_element_search_exec_fn(struct bContext *C, void *UNUSED(arg1) SpaceOutliner *soops = CTX_wm_space_outliner(C); TreeElement *te = (TreeElement *)element; - outliner_item_select(soops, te, false, false); - outliner_item_do_activate_from_tree_element(C, te, te->store_elem, false, false); + outliner_item_select(C, soops, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE); ED_outliner_select_sync_from_outliner(C, soops); } @@ -665,12 +664,13 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, + TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item. * it's especially confusing when multiple items are selected since some toggle on/off. */ - outliner_item_do_activate_from_tree_element(C, te, tselem, false, true); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + outliner_item_select(C, soops, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE | OL_ITEM_RECURSIVE); } static void object_deselect_cb(bContext *C, |