Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_outliner/outliner_select.c
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { | else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { | ||||
| outliner_item_toggle_closed(te, extend); | outliner_item_toggle_closed(te, false); | ||||
| changed = true; | changed = true; | ||||
| rebuild_tree = true; | rebuild_tree = true; | ||||
| } | } | ||||
| Context not available. | |||||
| /* **************** Box Select Tool ****************** */ | /* **************** Box Select Tool ****************** */ | ||||
| static void outliner_item_box_select( | static void outliner_item_box_select( | ||||
| SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select) | SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select, bContext *C, bool *extend, float *initial_y_pos) | ||||
| { | { | ||||
| TreeStoreElem *tselem = TREESTORE(te); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| TreeStoreElem *tselem = TREESTORE(te); | |||||
| if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) { | |||||
| if (select) { | |||||
| if (!(tselem->flag & TSE_SELECTED)) { | |||||
| tselem->flag |= TSE_SELECTED; | |||||
| do_outliner_item_activate_tree_element(C, scene, view_layer, soops, te, tselem, extend, true); | |||||
| *extend = true; | |||||
| } | |||||
| } | |||||
| else if (tselem->flag & TSE_SELECTED) { | |||||
| do_outliner_item_activate_tree_element(C, scene, view_layer, soops, te, tselem, extend, false); | |||||
| tselem->flag &= ~TSE_SELECTED; | |||||
| } | |||||
| } | |||||
| /* Look at its children. */ | |||||
| if (TSELEM_OPEN(tselem, soops)) { | |||||
| if (rectf->ymin < *initial_y_pos) { | |||||
| for (te = te->subtree.first; te; te = te->next) { | |||||
| outliner_item_box_select(soops, scene, rectf, te, select, C, extend, initial_y_pos); | |||||
| } | |||||
| } | |||||
| else { | |||||
| for (te = te->subtree.last; te; te = te->prev) { | |||||
| outliner_item_box_select(soops, scene, rectf, te, select, C, extend, initial_y_pos); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) { | static int outliner_box_select_exec(bContext *C, wmOperator *op) | ||||
| if (select) { | { | ||||
| tselem->flag |= TSE_SELECTED; | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| } | Scene *scene = CTX_data_scene(C); | ||||
| else { | SpaceOutliner *soops = CTX_wm_space_outliner(C); | ||||
| tselem->flag &= ~TSE_SELECTED; | ARegion *ar = CTX_wm_region(C); | ||||
| } | rctf rectf; | ||||
| } | bool extend = false; | ||||
| const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); | |||||
| const bool select = (sel_op != SEL_OP_SUB); | |||||
| if (SEL_OP_USE_PRE_DESELECT(sel_op)) { | |||||
| outliner_flag_set(&soops->tree, TSE_SELECTED, 0); | |||||
| BKE_view_layer_base_deselect_all(view_layer); | |||||
| if (sel_op == SEL_OP_ADD) { | |||||
| extend = true; | |||||
| } | |||||
| } | |||||
| WM_operator_properties_border_to_rctf(op, &rectf); | |||||
| UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); | |||||
| float initial_y_pos = RNA_float_get(op->ptr, "initial_y_pos"); | |||||
| for (TreeElement *te = soops->tree.first; te; te = te->next) { | |||||
| outliner_item_box_select(soops, scene, &rectf, te, select, C, &extend, &initial_y_pos); | |||||
| } | |||||
| 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; | |||||
| } | |||||
| /* Look at its children. */ | static int outliner_box_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| if (TSELEM_OPEN(tselem, soops)) { | { | ||||
| for (te = te->subtree.first; te; te = te->next) { | ARegion *ar = CTX_wm_region(C); | ||||
| outliner_item_box_select(soops, scene, rectf, te, select); | float fmval[2]; | ||||
| } | |||||
| } | UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); | ||||
| RNA_float_set(op->ptr, "initial_y_pos", fmval[1]); | |||||
| return WM_gesture_box_invoke(C, op, event); | |||||
| } | } | ||||
| static int outliner_box_select_exec(bContext *C, wmOperator *op) | void OUTLINER_OT_select_box(wmOperatorType *ot) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | /* identifiers */ | ||||
| SpaceOutliner *soops = CTX_wm_space_outliner(C); | ot->name = "Box Select"; | ||||
| ARegion *ar = CTX_wm_region(C); | ot->idname = "OUTLINER_OT_select_box"; | ||||
| rctf rectf; | ot->description = "Use box selection to select tree elements"; | ||||
| const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); | /* api callbacks */ | ||||
| const bool select = (sel_op != SEL_OP_SUB); | ot->invoke = outliner_box_invoke; | ||||
| if (SEL_OP_USE_PRE_DESELECT(sel_op)) { | ot->exec = outliner_box_select_exec; | ||||
| outliner_flag_set(&soops->tree, TSE_SELECTED, 0); | ot->modal = WM_gesture_box_modal; | ||||
| } | ot->cancel = WM_gesture_box_cancel; | ||||
| WM_operator_properties_border_to_rctf(op, &rectf); | ot->poll = ED_operator_outliner_active; | ||||
| UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); | |||||
| for (TreeElement *te = soops->tree.first; te; te = te->next) { | /* flags */ | ||||
| outliner_item_box_select(soops, scene, &rectf, te, select); | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | |||||
| DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); | /* properties */ | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); | PropertyRNA *prop; | ||||
| ED_region_tag_redraw(ar); | |||||
| return OPERATOR_FINISHED; | prop = RNA_def_float(ot->srna, "initial_y_pos" , 0, MINAFRAME, MAXFRAME, "Initial Y Position", "", MINAFRAME, MAXFRAME); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | |||||
| WM_operator_properties_gesture_box(ot); | |||||
| WM_operator_properties_select_operation_simple(ot); | |||||
| } | } | ||||
| void OUTLINER_OT_select_box(wmOperatorType *ot) | /* ****************************************************** */ | ||||
| static int get_active_element(TreeElement *te, TreeElement *te_res) | |||||
| { | { | ||||
| /* identifiers */ | TreeStoreElem *tselem = TREESTORE(te); | ||||
| ot->name = "Box Select"; | |||||
| ot->idname = "OUTLINER_OT_select_box"; | |||||
| ot->description = "Use box selection to select tree elements"; | |||||
| /* api callbacks */ | if (tselem->flag & TSE_ACTIVE) { | ||||
| ot->invoke = WM_gesture_box_invoke; | *te_res = *te; | ||||
| ot->exec = outliner_box_select_exec; | |||||
| ot->modal = WM_gesture_box_modal; | |||||
| ot->cancel = WM_gesture_box_cancel; | |||||
| ot->poll = ED_operator_outliner_active; | return 1; | ||||
| } | |||||
| /* flags */ | for (te = te->subtree.first; te; te = te->next) { | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | if (get_active_element(te, te_res)) { | ||||
| return 1; | |||||
| } | |||||
| } | |||||
| /* properties */ | return 0; | ||||
| WM_operator_properties_gesture_box(ot); | |||||
| WM_operator_properties_select_operation_simple(ot); | |||||
| } | } | ||||
| /* ****************************************************** */ | static int outliner_items_range_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| ARegion *ar = CTX_wm_region(C); | |||||
| SpaceOutliner *soops = CTX_wm_space_outliner(C); | |||||
| TreeElement *te; | |||||
| float fmval[2]; | |||||
| UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); | |||||
| int y1 = 0; // to store y position of active element | |||||
| int y2 = 0; // to store y position of elem under the cursor | |||||
| TreeElement te_res; | |||||
| bool is_active_elem = false; | |||||
| for (te = soops->tree.first; te; te = te->next) { | |||||
| if (get_active_element(te, &te_res)) { | |||||
| is_active_elem = true; | |||||
| y1 = te_res.ys; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!(te = outliner_find_item_at_y(soops, &soops->tree, fmval[1]))) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| y2 = te->ys; | |||||
| if (outliner_item_is_co_within_close_toggle(te, fmval[0])) { | |||||
| outliner_item_toggle_closed(te, true); | |||||
| } | |||||
| else { | |||||
| outliner_flag_set(&soops->tree, TSE_SELECTED, 0); | |||||
| BKE_view_layer_base_deselect_all(view_layer); | |||||
| if (!is_active_elem){ | |||||
| te->store_elem->flag |= TSE_ACTIVE; | |||||
| y1 = y2; | |||||
| } | |||||
| rctf rect; | |||||
| rect.ymin = y2 < y1 ? y2 + UI_UNIT_Y : y1 + UI_UNIT_Y; | |||||
| rect.ymax = y2 > y1 ? y2 : y1; | |||||
| bool extend = false; | |||||
| float initial_y_pos = y1 + UI_UNIT_Y; | |||||
| for (TreeElement *te = soops->tree.first; te; te = te->next) { | |||||
| outliner_item_box_select(soops, scene, &rect, te, true, C, &extend, &initial_y_pos); | |||||
| } | |||||
| } | |||||
| 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_range(wmOperatorType *ot) | |||||
| { | |||||
| ot->name = "Selects Range"; | |||||
| ot->idname = "OUTLINER_OT_select_range"; | |||||
| ot->description = "Handle mouse clicks to select a range of items"; | |||||
| ot->invoke = outliner_items_range_invoke; | |||||
| ot->poll = ED_operator_outliner_active; | |||||
| } | |||||
| Context not available. | |||||