Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_outliner/outliner_select.c
| Context not available. | |||||
| } | } | ||||
| /* ****************************************************** */ | /* ****************************************************** */ | ||||
| typedef enum WalkSelectDirection { | |||||
| OUTLINER_SELECT_WALK_UP, | |||||
| OUTLINER_SELECT_WALK_DOWN, | |||||
| } WalkSelectDirections; | |||||
| TreeElement get_last_item(TreeElement *te_temp, SpaceOutliner *soops) { | |||||
| TreeStoreElem *tselem = TREESTORE(te_temp); | |||||
| if (TSELEM_OPEN(tselem, soops)) { | |||||
| te_temp = te_temp->subtree.last; | |||||
| return get_last_item(te_temp, soops); | |||||
| } | |||||
| return *te_temp; | |||||
| } | |||||
| TreeElement get_nested_last_item(TreeElement *te_temp, SpaceOutliner *soops) { | |||||
| te_temp = te_temp->subtree.last; | |||||
| TreeStoreElem *tselem = TREESTORE(te_temp); | |||||
| if (TSELEM_OPEN(tselem, soops)) { | |||||
| return get_nested_last_item(te_temp, soops); | |||||
| } | |||||
| return *te_temp; | |||||
| } | |||||
| TreeElement get_parent_next_item(TreeElement *te_temp) { | |||||
| if (te_temp->parent) { | |||||
| te_temp = te_temp->parent; | |||||
| if (te_temp->next) { | |||||
| te_temp = te_temp->next; | |||||
| } else { | |||||
| return get_parent_next_item(te_temp); | |||||
| } | |||||
| } | |||||
| return *te_temp; | |||||
| } | |||||
| static int item_walk_select_do(bContext *C, TreeElement *te, int direction, | |||||
| bool *isLoop, bool *isActive) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| SpaceOutliner *soops = CTX_wm_space_outliner(C); | |||||
| TreeElement *te_temp = te; | |||||
| TreeStoreElem *tselem = TREESTORE(te_temp); | |||||
| if (tselem->flag & TSE_ACTIVE) { | |||||
| outliner_flag_set(&soops->tree, TSE_ACTIVE, 0); | |||||
| outliner_flag_set(&soops->tree, TSE_SELECTED, 0); | |||||
| BKE_view_layer_base_deselect_all(view_layer); | |||||
| if (direction == OUTLINER_SELECT_WALK_UP) { | |||||
| if (te_temp->prev) { | |||||
| te_temp = te_temp->prev; | |||||
| tselem = TREESTORE(te_temp); | |||||
| if (TSELEM_OPEN(tselem, soops)) { | |||||
| TreeElement elem = get_nested_last_item(te_temp, soops); | |||||
| te_temp = &elem; | |||||
| } | |||||
| } else if (te_temp->parent) { | |||||
| te_temp = te_temp->parent; | |||||
| } else { | |||||
| TreeElement elem = get_last_item(te, soops); | |||||
| te_temp = &elem; | |||||
| } | |||||
| } else if (direction == OUTLINER_SELECT_WALK_DOWN) { | |||||
| if (TSELEM_OPEN(tselem, soops) && *isLoop) { | |||||
| te_temp = te_temp->subtree.first; | |||||
| } else if (te_temp->next && *isLoop) { | |||||
| te_temp = te_temp->next; | |||||
| } else if (*isLoop) { | |||||
| TreeElement elem = get_parent_next_item(te); | |||||
| te_temp = &elem; | |||||
| *isLoop = false; | |||||
| } | |||||
| } | |||||
| tselem = TREESTORE(te_temp); | |||||
| tselem->flag |= TSE_ACTIVE; | |||||
| tselem->flag |= TSE_SELECTED; | |||||
| do_outliner_item_activate_tree_element(C, scene, view_layer, soops, te_temp, tselem, false, true); | |||||
| *isActive = true; | |||||
| return 1; | |||||
| } | |||||
| tselem = TREESTORE(te); | |||||
| if (TSELEM_OPEN(tselem, soops)) { | |||||
| for (te = te->subtree.first; te; te = te->next) { | |||||
| if (item_walk_select_do(C, te, direction, isLoop, isActive)) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void activate_elem(TreeElement *te, bContext *C, int direction) { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| SpaceOutliner *soops = CTX_wm_space_outliner(C); | |||||
| if (direction == OUTLINER_SELECT_WALK_UP) { | |||||
| te = soops->tree.first; | |||||
| } else if (direction == OUTLINER_SELECT_WALK_DOWN) { | |||||
| TreeElement elem = get_last_item(te, soops); | |||||
| te = &elem; | |||||
| } | |||||
| TreeStoreElem *tselem = TREESTORE(te); | |||||
| tselem->flag |= TSE_ACTIVE; | |||||
| tselem->flag |= TSE_SELECTED; | |||||
| do_outliner_item_activate_tree_element(C, scene, view_layer, soops, te, tselem, false, true); | |||||
| } | |||||
| static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ARegion *ar = CTX_wm_region(C); | |||||
| SpaceOutliner *soops = CTX_wm_space_outliner(C); | |||||
| TreeElement *te = soops->tree.first; | |||||
| const int direction = RNA_enum_get(op->ptr, "direction"); | |||||
| bool isLoop = true; | |||||
| bool isActive = false; | |||||
| item_walk_select_do(C, te, direction, &isLoop, &isActive); | |||||
| if (!isActive) { | |||||
| activate_elem(te, C, direction); | |||||
| } | |||||
| DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); | |||||
| 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, "Prev", ""}, | |||||
| {OUTLINER_SELECT_WALK_DOWN, "DOWN", 0, "Next", ""}, | |||||
| {0, NULL, 0}, | |||||
| }; | |||||
| /* identifiers */ | |||||
| ot->name = "Walk Select/Deselect Item"; | |||||
| ot->description = "Select/Deselect items by walking through them"; | |||||
| ot->idname = "OUTLINER_OT_select_walk"; | |||||
| /* 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/Deselect item in this direction"); | |||||
| RNA_def_property_flag(prop, PROP_SKIP_SAVE); | |||||
| } | |||||
| Context not available. | |||||