diff options
9 files changed, 412 insertions, 64 deletions
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 3f6a5f0a514..798bdc1fe01 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -709,11 +709,24 @@ def km_outliner(params): ("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True}, {"properties": [("extend", True), ("recursive", True)]}), ("outliner.select_box", {"type": 'B', "value": 'PRESS'}, None), - ("outliner.item_openclose", {"type": 'RET', "value": 'PRESS'}, + ("outliner.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'UP')]}), + ("outliner.select_walk", {"type": 'UP_ARROW', "value": 'PRESS', "shift": True}, + {"properties": [("direction", 'UP'), ("extend", True)]}), + ("outliner.select_walk", {"type": 'DOWN_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'DOWN')]}), + ("outliner.select_walk", {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True}, + {"properties": [("direction", 'DOWN'), ("extend", True)]}), + ("outliner.select_walk", {"type": 'LEFT_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'LEFT')]}), + ("outliner.select_walk", {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": [("direction", 'LEFT'), ("toggle_all", True)]}), + ("outliner.select_walk", {"type": 'RIGHT_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'RIGHT')]}), + ("outliner.select_walk", {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": [("direction", 'RIGHT'), ("toggle_all", True)]}), + ("outliner.item_openclose", {"type": 'LEFTMOUSE', "value": 'CLICK'}, {"properties": [("all", False)]}), - ("outliner.item_openclose", {"type": 'RET', "value": 'PRESS', "shift": True}, + ("outliner.item_openclose", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True}, {"properties": [("all", True)]}), - ("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("outliner.item_openclose", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, + {"properties": [("all", False)]}), ("outliner.operation", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None), ("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None), ("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True}, None), diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 842502ec82f..60b5dbdfc50 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -140,59 +140,108 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot) /* Toggle Open/Closed ------------------------------------------- */ -static int do_outliner_item_openclose( - bContext *C, SpaceOutliner *soops, TreeElement *te, const bool all, const float mval[2]) +/* Open or close a tree element, optionally toggling all children recursively */ +void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all) { + TreeStoreElem *tselem = TREESTORE(te); - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); + if (open) { + tselem->flag &= ~TSE_CLOSED; + } + else { + tselem->flag |= TSE_CLOSED; + } - /* all below close/open? */ - if (all) { - tselem->flag &= ~TSE_CLOSED; - outliner_flag_set( - &te->subtree, TSE_CLOSED, !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)); - } - else { - if (tselem->flag & TSE_CLOSED) { - tselem->flag &= ~TSE_CLOSED; - } - else { - tselem->flag |= TSE_CLOSED; + if (toggle_all) { + outliner_flag_set(&te->subtree, TSE_CLOSED, !open); + } +} + +typedef struct OpenCloseData { + TreeStoreElem *prev_tselem; + bool open; + int x_location; +} OpenCloseData; + +static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + + float view_mval[2]; + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); + + if (event->type == MOUSEMOVE) { + TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]); + + OpenCloseData *data = (OpenCloseData *)op->customdata; + + /* Only openclose if mouse is not over the previously toggled element */ + if (te && TREESTORE(te) != data->prev_tselem) { + + /* Only toggle openclose on the same level as the first clicked element */ + if (te->xs == data->x_location) { + outliner_item_openclose(te, data->open, false); + ED_region_tag_redraw(ar); } } - return 1; + if (te) { + data->prev_tselem = TREESTORE(te); + } + else { + data->prev_tselem = NULL; + } } + else if (event->val == KM_RELEASE) { + MEM_freeN(op->customdata); - for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_openclose(C, soops, te, all, mval)) { - return 1; - } + return OPERATOR_FINISHED; } - return 0; + + return OPERATOR_RUNNING_MODAL; } -/* event can enterkey, then it opens/closes */ -static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event) +static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te; - float fmval[2]; - const bool all = RNA_boolean_get(op->ptr, "all"); - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + const bool toggle_all = RNA_boolean_get(op->ptr, "all"); - for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_openclose(C, soops, te, all, fmval)) { - break; + float view_mval[2]; + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); + + TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]); + + if (te && outliner_item_is_co_within_close_toggle(te, view_mval[0])) { + TreeStoreElem *tselem = TREESTORE(te); + + const bool open = (tselem->flag & TSE_CLOSED) || + (toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1))); + + outliner_item_openclose(te, open, toggle_all); + ED_region_tag_redraw(ar); + + /* Only toggle once for single click toggling */ + if (event->type == LEFTMOUSE) { + return OPERATOR_FINISHED; } - } - ED_region_tag_redraw(ar); + /* Store last expanded tselem and x coordinate of disclosure triangle */ + OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data"); + toggle_data->prev_tselem = tselem; + toggle_data->open = open; + toggle_data->x_location = te->xs; - return OPERATOR_FINISHED; + /* Store the first clicked on element */ + op->customdata = toggle_data; + + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } void OUTLINER_OT_item_openclose(wmOperatorType *ot) @@ -201,11 +250,12 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) ot->idname = "OUTLINER_OT_item_openclose"; ot->description = "Toggle whether item under cursor is enabled or closed"; - ot->invoke = outliner_item_openclose; + ot->invoke = outliner_item_openclose_invoke; + ot->modal = outliner_item_openclose_modal; ot->poll = ED_operator_outliner_active; - RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items"); + RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items"); } /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 72cd8dc6424..e37f3519653 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -50,6 +50,14 @@ typedef enum TreeElementInsertType { TE_INSERT_INTO, } TreeElementInsertType; +/* Use generic walk select after D4771 is committed */ +typedef enum WalkSelectDirection { + OUTLINER_SELECT_WALK_UP, + OUTLINER_SELECT_WALK_DOWN, + OUTLINER_SELECT_WALK_LEFT, + OUTLINER_SELECT_WALK_RIGHT, +} WalkSelectDirection; + typedef enum TreeTraversalAction { /* Continue traversal regularly, don't skip children. */ TRAVERSE_CONTINUE = 0, @@ -346,6 +354,8 @@ void item_object_mode_exit_cb(struct bContext *C, void outliner_set_coordinates(struct ARegion *ar, struct SpaceOutliner *soops); +void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all); + /* outliner_dragdrop.c */ void outliner_dropboxes(void); @@ -373,6 +383,7 @@ void OUTLINER_OT_show_active(struct wmOperatorType *ot); void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot); void OUTLINER_OT_select_box(struct wmOperatorType *ot); +void OUTLINER_OT_select_walk(struct wmOperatorType *ot); void OUTLINER_OT_select_all(struct wmOperatorType *ot); void OUTLINER_OT_expanded_toggle(struct wmOperatorType *ot); @@ -470,6 +481,9 @@ bool outliner_tree_traverse(const SpaceOutliner *soops, TreeTraversalFunc func, void *customdata); float outliner_restrict_columns_width(const struct SpaceOutliner *soops); +TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag); +bool outliner_is_element_visible(const TreeElement *te); +void outliner_scroll_view(struct ARegion *ar, int delta_y); /* outliner_sync.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index f155a2d5f89..4b57d4ad771 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -50,6 +50,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_highlight_update); WM_operatortype_append(OUTLINER_OT_item_activate); WM_operatortype_append(OUTLINER_OT_select_box); + WM_operatortype_append(OUTLINER_OT_select_walk); WM_operatortype_append(OUTLINER_OT_item_openclose); WM_operatortype_append(OUTLINER_OT_item_rename); WM_operatortype_append(OUTLINER_OT_item_drag_drop); diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index ddb943d6c66..6e70cdcddcd 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -1087,8 +1087,8 @@ 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) { - outliner_flag_set(&soops->tree, TSE_ACTIVE, false); - tselem->flag |= TSE_ACTIVE; + outliner_flag_set(&soops->tree, TSE_ACTIVE | TSE_ACTIVE_WALK, false); + tselem->flag |= TSE_ACTIVE | TSE_ACTIVE_WALK; } /** @@ -1232,20 +1232,6 @@ void outliner_item_select(SpaceOutliner *soops, 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_flag_is_any_test(&te->subtree, TSE_CLOSED, 1); - outliner_flag_set(&te->subtree, TSE_CLOSED, all_opened); - } - else { - tselem->flag ^= TSE_CLOSED; - } -} - static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, const ARegion *ar, float view_co_x) @@ -1254,7 +1240,7 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, } /** - * A version of #outliner_item_do_acticate_from_cursor that takes the tree element directly. + * 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. @@ -1299,10 +1285,10 @@ static int outliner_item_do_activate_from_cursor(bContext *C, changed = true; } } - else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { - outliner_item_toggle_closed(te, extend); - changed = true; - rebuild_tree = true; + /* Don't allow selection on disclosure triangles */ + else if ((TREESTORE(te)->type != TSE_VIEW_COLLECTION_BASE) && + outliner_item_is_co_within_close_toggle(te, view_mval[0])) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } else { Scene *scene = CTX_data_scene(C); @@ -1454,3 +1440,229 @@ void OUTLINER_OT_select_box(wmOperatorType *ot) } /* ****************************************************** */ + +/* **************** Walk Select Tool ****************** */ + +/* Given a tree element return the rightmost child that is visible in the outliner */ +static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *soops, TreeElement *te) +{ + while (te->subtree.last) { + if (TSELEM_OPEN(TREESTORE(te), soops)) { + te = te->subtree.last; + } + else { + break; + } + } + return te; +} + +/* Find previous visible element in the tree */ +static TreeElement *outliner_find_previous_element(SpaceOutliner *soops, TreeElement *walk_element) +{ + if (walk_element->prev) { + walk_element = outliner_find_rightmost_visible_child(soops, walk_element->prev); + } + else if (walk_element->parent) { + /* Use parent if at beginning of list */ + walk_element = walk_element->parent; + } + + return walk_element; +} + +/* Recursively search up the tree until a successor to a given element is found */ +static TreeElement *outliner_element_find_successor_in_parents(TreeElement *te) +{ + TreeElement *successor = te; + while (successor->parent) { + if (successor->parent->next) { + te = successor->parent->next; + break; + } + else { + successor = successor->parent; + } + } + + return te; +} + +/* Find next visible element in the tree */ +static TreeElement *outliner_find_next_element(SpaceOutliner *soops, TreeElement *walk_element) +{ + TreeStoreElem *tselem = TREESTORE(walk_element); + + if (TSELEM_OPEN(tselem, soops) && walk_element->subtree.first) { + walk_element = walk_element->subtree.first; + } + else if (walk_element->next) { + walk_element = walk_element->next; + } + else { + walk_element = outliner_element_find_successor_in_parents(walk_element); + } + + return walk_element; +} + +static TreeElement *do_outliner_select_walk(SpaceOutliner *soops, + TreeElement *walk_element, + const int direction, + const bool extend, + const bool toggle_all) +{ + TreeStoreElem *tselem = TREESTORE(walk_element); + + if (!extend) { + outliner_flag_set(&soops->tree, TSE_SELECTED, false); + } + tselem->flag &= ~TSE_ACTIVE_WALK; + + switch (direction) { + case OUTLINER_SELECT_WALK_UP: + walk_element = outliner_find_previous_element(soops, walk_element); + break; + case OUTLINER_SELECT_WALK_DOWN: + walk_element = outliner_find_next_element(soops, walk_element); + break; + case OUTLINER_SELECT_WALK_LEFT: + outliner_item_openclose(walk_element, false, toggle_all); + break; + case OUTLINER_SELECT_WALK_RIGHT: + outliner_item_openclose(walk_element, true, toggle_all); + break; + } + + TreeStoreElem *tselem_new = TREESTORE(walk_element); + + /* If new element is already selected, deselect the previous element */ + if (extend) { + tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) : + (tselem->flag | TSE_SELECTED); + } + + tselem_new->flag |= TSE_SELECTED | TSE_ACTIVE_WALK; + + return walk_element; +} + +/* Find walk select element, or set it if it does not exist. + * Changed is set to true if walk element is found, false if it was set */ +static TreeElement *find_walk_select_start_element(SpaceOutliner *soops, bool *changed) +{ + TreeElement *walk_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE_WALK); + + *changed = false; + + /* If no walk element exists, start from active */ + if (!walk_element) { + TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE); + + /* If no active element exists, use the first element in the tree */ + if (!active_element) { + walk_element = soops->tree.first; + } + else { + walk_element = active_element; + } + + *changed = true; + } + + /* If walk element is not visible, set that element's first visible parent as walk element */ + if (!outliner_is_element_visible(walk_element)) { + TREESTORE(walk_element)->flag &= ~TSE_ACTIVE_WALK; + + while (!outliner_is_element_visible(walk_element)) { + walk_element = walk_element->parent; + } + *changed = true; + } + + return walk_element; +} + +/* Scroll the outliner when the walk element reaches the top or bottom boundary */ +static void outliner_walk_scroll(ARegion *ar, TreeElement *te) +{ + /* Account for the header height */ + int y_max = ar->v2d.cur.ymax - UI_UNIT_Y; + int y_min = ar->v2d.cur.ymin; + + /* Scroll if walked position is beyond the border */ + if (te->ys > y_max) { + outliner_scroll_view(ar, te->ys - y_max); + } + else if (te->ys < y_min) { + outliner_scroll_view(ar, -(y_min - te->ys)); + } +} + +static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + + const short direction = RNA_enum_get(op->ptr, "direction"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all"); + + bool changed; + TreeElement *walk_element = find_walk_select_start_element(soops, &changed); + + /* If finding the starting walk select element did not move the element, proceed to walk */ + if (!changed) { + walk_element = do_outliner_select_walk(soops, walk_element, direction, extend, toggle_all); + } + else { + TREESTORE(walk_element)->flag |= TSE_SELECTED | TSE_ACTIVE_WALK; + } + + /* Scroll outliner to focus on walk element */ + outliner_walk_scroll(ar, walk_element); + + if (soops->flag & SO_SYNC_SELECT) { + ED_outliner_select_sync_from_outliner(C, soops); + } + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_select_walk(wmOperatorType *ot) +{ + static const EnumPropertyItem direction_items[] = { + {OUTLINER_SELECT_WALK_UP, "UP", 0, "Up", ""}, + {OUTLINER_SELECT_WALK_DOWN, "DOWN", 0, "Down", ""}, + {OUTLINER_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""}, + {OUTLINER_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Walk Select"; + ot->idname = "OUTLINER_OT_select_walk"; + ot->description = "Use walk navigation to select tree elements"; + + /* api callbacks */ + ot->invoke = outliner_walk_select_invoke; + ot->poll = ED_operator_outliner_active; + + /* properties */ + PropertyRNA *prop; + prop = RNA_def_enum(ot->srna, + "direction", + direction_items, + 0, + "Walk Direction", + "Select element in this direction"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection on walk"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "toggle_all", false, "Toggle All", "Toggle open/close hierarchy"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/* ****************************************************** */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 7107b5539c8..605b5383aec 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -297,7 +297,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops, ViewLayer *view_layer; for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0); + TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, ten, TSE_R_LAYER, 0); tenlay->name = view_layer->name; tenlay->directdata = view_layer; } @@ -314,7 +314,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops, ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); ten->name = IFACE_("Objects"); FOREACH_SCENE_OBJECT_BEGIN (sce, ob) { - outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0); + outliner_add_element(soops, &ten->subtree, ob, ten, 0, 0); } FOREACH_SCENE_OBJECT_END; outliner_make_object_parent_hierarchy(&ten->subtree); diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index d39a9387a6a..5dfdf6f129b 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -327,12 +327,68 @@ float outliner_restrict_columns_width(const SpaceOutliner *soops) return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH); } +/* Find first tree element in tree with matching treestore flag */ +TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag) +{ + for (TreeElement *te = lb->first; te; te = te->next) { + if ((TREESTORE(te)->flag & flag) == flag) { + return te; + } + TreeElement *active_element = outliner_find_element_with_flag(&te->subtree, flag); + if (active_element) { + return active_element; + } + } + return NULL; +} + +/* Find if element is visible in the outliner tree */ +bool outliner_is_element_visible(const TreeElement *te) +{ + TreeStoreElem *tselem; + + while (te->parent) { + tselem = TREESTORE(te->parent); + + if (tselem->flag & TSE_CLOSED) { + return false; + } + else { + te = te->parent; + } + } + + return true; +} + /* Find if x coordinate is over element disclosure toggle */ bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x) { return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X); } +/* Scroll view vertically while keeping within total bounds */ +void outliner_scroll_view(ARegion *ar, int delta_y) +{ + int y_min = MIN2(ar->v2d.cur.ymin, ar->v2d.tot.ymin); + + ar->v2d.cur.ymax += delta_y; + ar->v2d.cur.ymin += delta_y; + + /* Adjust view if delta placed view outside total area */ + int offset; + if (ar->v2d.cur.ymax > -UI_UNIT_Y) { + offset = ar->v2d.cur.ymax; + ar->v2d.cur.ymax -= offset; + ar->v2d.cur.ymin -= offset; + } + else if (ar->v2d.cur.ymin < y_min) { + offset = y_min - ar->v2d.cur.ymin; + ar->v2d.cur.ymax += offset; + ar->v2d.cur.ymin += offset; + } +} + /* Get base of object under cursor. Used for eyedropper tool */ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) { diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 2455d953053..3ac09b8bcf8 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -415,7 +415,7 @@ void ED_spacetype_outliner(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); art->regionid = RGN_TYPE_WINDOW; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; art->init = outliner_main_region_init; art->draw = outliner_main_region_draw; @@ -428,7 +428,7 @@ void ED_spacetype_outliner(void) art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; art->init = outliner_header_region_init; art->draw = outliner_header_region_draw; diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 6e830987725..9776063f220 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -62,6 +62,8 @@ enum { TSE_DRAG_AFTER = (1 << 8), /* Needed because outliner-only elements can be active */ TSE_ACTIVE = (1 << 9), + /* Needed because walk selection should not activate */ + TSE_ACTIVE_WALK = (1 << 10), TSE_DRAG_ANY = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER), }; |