From a02c8c4177486c1ae04b8d8cd0d15089039f7be0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 Mar 2013 03:29:57 +0000 Subject: [PATCH] move toggle drag into a UI handler (was modal operator) --- .../editors/interface/interface_handlers.c | 170 ++++++++++++++- .../blender/editors/interface/interface_ops.c | 200 ------------------ source/blender/windowmanager/WM_api.h | 2 +- .../windowmanager/intern/wm_event_system.c | 2 +- 4 files changed, 161 insertions(+), 213 deletions(-) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index b199e5f66ca..e0d6c293be5 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -740,6 +740,153 @@ static void ui_apply_but_CHARTAB(bContext *C, uiBut *but, uiHandleButtonData *da /* ****************** drag drop code *********************** */ +#ifdef USE_DRAG_TOGGLE + +typedef struct uiDragToggleHandle { + /* init */ + bool is_set; + float but_cent_start[2]; + eButType but_type_start; + + bool xy_lock[2]; + int xy_last[2]; +} uiDragToggleHandle; + +static bool ui_drag_toggle_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start, + const int xy_src[2], const int xy_dst[2]) +{ + bool change = false; + uiBlock *block; + + for (block = ar->uiblocks.first; block; block = block->next) { + uiBut *but; + + float xy_a_block[2] = {UNPACK2(xy_src)}; + float xy_b_block[2] = {UNPACK2(xy_dst)}; + + ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]); + ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]); + + for (but = block->buttons.first; but; but = but->next) { + if (ui_is_but_interactive(but)) { + if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) { + + /* execute the button */ + if (ui_is_but_bool(but) && but->type == but_type_start) { + /* is it pressed? */ + bool is_set_but = ui_is_but_push(but); + BLI_assert(ui_is_but_bool(but) == true); + if (is_set_but != is_set) { + uiButExecute(C, but); + change = true; + } + } + /* done */ + + } + } + } + } + + return change; +} + +static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const int xy_input[2]) +{ + ARegion *ar = CTX_wm_region(C); + bool do_draw = false; + int xy[2]; + + /** + * Initialize Locking: + * + * Check if we need to initialize the lock axis by finding if the first + * button we mouse over is X or Y aligned, then lock the mouse to that axis after. + */ + if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) { + ARegion *ar = CTX_wm_region(C); + + /* first store the buttons original coords */ + uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]); + if (but) { + const float but_cent_new[2] = {BLI_rctf_cent_x(&but->rect), + BLI_rctf_cent_y(&but->rect)}; + + /* check if this is a different button, chances are high the button wont move about :) */ + if (len_manhattan_v2v2(drag_info->but_cent_start, but_cent_new) > 1.0f) { + if (fabsf(drag_info->but_cent_start[0] - but_cent_new[0]) < + fabsf(drag_info->but_cent_start[1] - but_cent_new[1])) + { + drag_info->xy_lock[0] = true; + } + else { + drag_info->xy_lock[1] = true; + } + } + } + } + /* done with axis locking */ + + + xy[0] = (drag_info->xy_lock[0] == false) ? xy_input[0] : drag_info->xy_last[0]; + xy[1] = (drag_info->xy_lock[1] == false) ? xy_input[1] : drag_info->xy_last[1]; + + + /* touch all buttons between last mouse coord and this one */ + do_draw = ui_drag_toggle_set_xy_xy(C, ar, drag_info->is_set, drag_info->but_type_start, drag_info->xy_last, xy); + + if (do_draw) { + ED_region_tag_redraw(ar); + } + + copy_v2_v2_int(drag_info->xy_last, xy); +} + +static void ui_handler_region_drag_toggle_remove(bContext *UNUSED(C), void *userdata) +{ + uiDragToggleHandle *drag_info = userdata; + MEM_freeN(drag_info); +} + +static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void *userdata) +{ + uiDragToggleHandle *drag_info = userdata; + bool done = false; + + switch (event->type) { + case LEFTMOUSE: + { + if (event->val != KM_PRESS) { + done = true; + } + break; + } + case MOUSEMOVE: + { + ui_drag_toggle_set(C, drag_info, &event->x); + break; + } + } + + if (done) { + wmWindow *win = CTX_wm_window(C); + WM_event_remove_ui_handler(&win->modalhandlers, + ui_handler_region_drag_toggle, + ui_handler_region_drag_toggle_remove, + drag_info, false); + ui_handler_region_drag_toggle_remove(C, drag_info); + + WM_event_add_mousemove(C); + return WM_UI_HANDLER_BREAK; + } + else { + return WM_UI_HANDLER_CONTINUE; + } +} + +#endif /* USE_DRAG_TOGGLE */ + + static int ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *event) { rcti rect; @@ -775,17 +922,18 @@ static int ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data, data->cancel = TRUE; #ifdef USE_DRAG_TOGGLE if (ui_is_but_bool(but)) { - /* assumes button has already been pressed */ - const bool is_set = ui_is_but_push(but); - PointerRNA ptr; - /* auto-key is typically called on mouse-up, but we'r leaving the button so call here */ - ui_apply_autokey(C, but); - WM_operator_properties_create(&ptr, "UI_OT_drag_toggle"); - RNA_boolean_set(&ptr, "state", is_set); - RNA_int_set(&ptr, "last_x", data->dragstartx); - RNA_int_set(&ptr, "last_y", data->dragstarty); - WM_operator_name_call(C, "UI_OT_drag_toggle", WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); + uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__); + + drag_info->is_set = ui_is_but_push(but); + drag_info->but_cent_start[0] = BLI_rctf_cent_x(&but->rect); + drag_info->but_cent_start[1] = BLI_rctf_cent_y(&but->rect); + drag_info->but_type_start = but->type; + copy_v2_v2_int(drag_info->xy_last, &event->x); + + WM_event_add_ui_handler(C, &data->window->modalhandlers, + ui_handler_region_drag_toggle, + ui_handler_region_drag_toggle_remove, + drag_info); } else #endif diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index f59d970b39a..3298859ee0c 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1071,205 +1071,6 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot) ot->exec = reloadtranslation_exec; } - -/* -------------------------------------------------------------------- */ -/* Toggle Drag Operator */ - -typedef struct DragOpInfo { - bool xy_lock[2]; - float but_cent_start[2]; - eButType but_type_start; -} DragOpInfo; - -static bool ui_but_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start, - const int xy_src[2], const int xy_dst[2]) -{ - bool change = false; - uiBlock *block; - - for (block = ar->uiblocks.first; block; block = block->next) { - uiBut *but; - - float xy_a_block[2] = {UNPACK2(xy_src)}; - float xy_b_block[2] = {UNPACK2(xy_dst)}; - - ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]); - ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]); - - for (but = block->buttons.first; but; but = but->next) { - if (ui_is_but_interactive(but)) { - if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) { - - /* execute the button */ - if (ui_is_but_bool(but) && but->type == but_type_start) { - /* is it pressed? */ - bool is_set_but = ui_is_but_push(but); - BLI_assert(ui_is_but_bool(but) == true); - if (is_set_but != is_set) { - uiButExecute(C, but); - change = true; - } - } - /* done */ - - } - } - } - } - - return change; -} - - -static void ui_drag_but_set(bContext *C, wmOperator *op, const int xy_input[2]) -{ - ARegion *ar = CTX_wm_region(C); - DragOpInfo *drag_info = op->customdata; - bool do_draw = false; - - const bool is_set = RNA_boolean_get(op->ptr, "state"); - const int xy_last[2] = {RNA_int_get(op->ptr, "last_x"), - RNA_int_get(op->ptr, "last_y")}; - - int xy[2]; - - /** - * Initialize Locking: - * - * Check if we need to initialize the lock axis by finding if the first - * button we mouse over is X or Y aligned, then lock the mouse to that axis after. - */ - if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) { - ARegion *ar = CTX_wm_region(C); - - /* first store the buttons original coords */ - uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]); - if (but) { - const float but_cent_new[2] = {BLI_rctf_cent_x(&but->rect), - BLI_rctf_cent_y(&but->rect)}; - - /* check if this is a different button, chances are high the button wont move about :) */ - if (len_manhattan_v2v2(drag_info->but_cent_start, but_cent_new) > 1.0f) { - if (fabsf(drag_info->but_cent_start[0] - but_cent_new[0]) < - fabsf(drag_info->but_cent_start[1] - but_cent_new[1])) - { - drag_info->xy_lock[0] = true; - } - else { - drag_info->xy_lock[1] = true; - } - } - } - } - /* done with axis locking */ - - - xy[0] = (drag_info->xy_lock[0] == false) ? xy_input[0] : xy_last[0]; - xy[1] = (drag_info->xy_lock[1] == false) ? xy_input[1] : xy_last[1]; - - - /* touch all buttons between last mouse coord and this one */ - do_draw = ui_but_set_xy_xy(C, ar, is_set, drag_info->but_type_start, xy_last, xy); - - if (do_draw) { - ED_region_tag_redraw(ar); - } - - RNA_int_set(op->ptr, "last_x", xy[0]); - RNA_int_set(op->ptr, "last_y", xy[1]); -} - -static int ui_drag_toggle_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - int xy_last[2] = {RNA_int_get(op->ptr, "last_x"), - RNA_int_get(op->ptr, "last_y")}; - - float but_cent_start[2]; - eButType but_type_start; - DragOpInfo *drag_info; - - { - /* find the button where we started dragging */ - ARegion *ar = CTX_wm_region(C); - uiBut *but = ui_but_find_mouse_over(ar, xy_last[0], xy_last[1]); - if (but) { - but_cent_start[0] = BLI_rctf_cent_x(&but->rect); - but_cent_start[1] = BLI_rctf_cent_y(&but->rect); - but_type_start = but->type; - } - else { - return OPERATOR_CANCELLED; - } - } - - drag_info = op->customdata = MEM_callocN(sizeof(DragOpInfo), __func__); - copy_v2_v2(drag_info->but_cent_start, but_cent_start); - drag_info->but_type_start = but_type_start; - - /* set the initial button */ - ui_drag_but_set(C, op, xy_last); - ui_drag_but_set(C, op, &event->x); - - WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; -} - -static int ui_drag_toggle_modal(bContext *C, wmOperator *op, wmEvent *event) -{ - bool done = false; - - switch (event->type) { - case LEFTMOUSE: - { - if (event->val != KM_PRESS) { - done = true; - } - break; - } - case MOUSEMOVE: - { - ui_drag_but_set(C, op, &event->x); - break; - } - } - - if (done) { - WM_event_add_mousemove(C); - MEM_freeN(op->customdata); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_RUNNING_MODAL; - } -} - -static int ui_drag_toggle_cancel(bContext *UNUSED(C), wmOperator *op) -{ - MEM_freeN(op->customdata); - return OPERATOR_CANCELLED; -} - -static void UI_OT_drag_toggle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Button Drag Toggle"; - ot->description = ""; - ot->idname = "UI_OT_drag_toggle"; - - /* api callbacks */ - ot->invoke = ui_drag_toggle_invoke; - ot->modal = ui_drag_toggle_modal; - ot->cancel = ui_drag_toggle_cancel; - - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - - /* properties */ - RNA_def_boolean(ot->srna, "state", true, "State", ""); - RNA_def_int(ot->srna, "last_x", 0, 0, INT_MAX, "X", "", 0, INT_MAX); - RNA_def_int(ot->srna, "last_y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX); -} - /* ********************************************************* */ /* Registration */ @@ -1287,5 +1088,4 @@ void UI_buttons_operatortypes(void) WM_operatortype_append(UI_OT_edittranslation_init); #endif WM_operatortype_append(UI_OT_reloadtranslation); - WM_operatortype_append(UI_OT_drag_toggle); } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index a1437b70090..57fe518dd46 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -308,7 +308,7 @@ void WM_gestures_remove(struct bContext *C); void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op); void WM_event_fileselect_event(struct bContext *C, void *ophandle, int eventval); #ifndef NDEBUG -void WM_event_print(struct wmEvent *event); +void WM_event_print(const struct wmEvent *event); #endif void WM_operator_region_active_win_set(struct bContext *C); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 206297d2c95..4e181ec930b 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -472,7 +472,7 @@ void WM_operator_region_active_win_set(bContext *C) /* for debugging only, getting inspecting events manually is tedious */ #ifndef NDEBUG -void WM_event_print(wmEvent *event) +void WM_event_print(const wmEvent *event) { if (event) { const char *unknown = "UNKNOWN";