move toggle drag into a UI handler (was modal operator)

This commit is contained in:
Campbell Barton 2013-03-03 03:29:57 +00:00
parent c6642b8ec8
commit a02c8c4177
4 changed files with 161 additions and 213 deletions

@ -740,6 +740,153 @@ static void ui_apply_but_CHARTAB(bContext *C, uiBut *but, uiHandleButtonData *da
/* ****************** drag drop code *********************** */ /* ****************** 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) static int ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *event)
{ {
rcti rect; rcti rect;
@ -775,17 +922,18 @@ static int ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
data->cancel = TRUE; data->cancel = TRUE;
#ifdef USE_DRAG_TOGGLE #ifdef USE_DRAG_TOGGLE
if (ui_is_but_bool(but)) { if (ui_is_but_bool(but)) {
/* assumes button has already been pressed */ uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
const bool is_set = ui_is_but_push(but);
PointerRNA ptr; drag_info->is_set = ui_is_but_push(but);
/* auto-key is typically called on mouse-up, but we'r leaving the button so call here */ drag_info->but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
ui_apply_autokey(C, but); drag_info->but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
WM_operator_properties_create(&ptr, "UI_OT_drag_toggle"); drag_info->but_type_start = but->type;
RNA_boolean_set(&ptr, "state", is_set); copy_v2_v2_int(drag_info->xy_last, &event->x);
RNA_int_set(&ptr, "last_x", data->dragstartx);
RNA_int_set(&ptr, "last_y", data->dragstarty); WM_event_add_ui_handler(C, &data->window->modalhandlers,
WM_operator_name_call(C, "UI_OT_drag_toggle", WM_OP_INVOKE_DEFAULT, &ptr); ui_handler_region_drag_toggle,
WM_operator_properties_free(&ptr); ui_handler_region_drag_toggle_remove,
drag_info);
} }
else else
#endif #endif

@ -1071,205 +1071,6 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
ot->exec = reloadtranslation_exec; 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 */ /* Registration */
@ -1287,5 +1088,4 @@ void UI_buttons_operatortypes(void)
WM_operatortype_append(UI_OT_edittranslation_init); WM_operatortype_append(UI_OT_edittranslation_init);
#endif #endif
WM_operatortype_append(UI_OT_reloadtranslation); WM_operatortype_append(UI_OT_reloadtranslation);
WM_operatortype_append(UI_OT_drag_toggle);
} }

@ -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_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct bContext *C, void *ophandle, int eventval); void WM_event_fileselect_event(struct bContext *C, void *ophandle, int eventval);
#ifndef NDEBUG #ifndef NDEBUG
void WM_event_print(struct wmEvent *event); void WM_event_print(const struct wmEvent *event);
#endif #endif
void WM_operator_region_active_win_set(struct bContext *C); void WM_operator_region_active_win_set(struct bContext *C);

@ -472,7 +472,7 @@ void WM_operator_region_active_win_set(bContext *C)
/* for debugging only, getting inspecting events manually is tedious */ /* for debugging only, getting inspecting events manually is tedious */
#ifndef NDEBUG #ifndef NDEBUG
void WM_event_print(wmEvent *event) void WM_event_print(const wmEvent *event)
{ {
if (event) { if (event) {
const char *unknown = "UNKNOWN"; const char *unknown = "UNKNOWN";