2017-10-17 15:09:29 +11:00
|
|
|
/*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2007 Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup wm
|
2017-10-17 15:09:29 +11:00
|
|
|
*
|
|
|
|
|
* Default operator callbacks for use with gestures (border/circle/lasso/straightline).
|
|
|
|
|
* Operators themselves are defined elsewhere.
|
|
|
|
|
*
|
|
|
|
|
* - Keymaps are in ``wm_operators.c``.
|
|
|
|
|
* - Property definitions are in ``wm_operator_props.c``.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include "DNA_windowmanager_types.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_math.h"
|
2020-10-20 22:16:55 +02:00
|
|
|
#include "BLI_rect.h"
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "WM_types.h"
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
#include "wm.h"
|
|
|
|
|
#include "wm_event_system.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "wm_event_types.h"
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
#include "ED_screen.h"
|
2018-08-14 10:28:41 +10:00
|
|
|
#include "ED_select_utils.h"
|
2017-10-17 15:09:29 +11:00
|
|
|
|
2020-10-20 22:32:56 +02:00
|
|
|
#include "UI_interface.h"
|
|
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
#include "RNA_access.h"
|
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Internal Gesture Utilities
|
|
|
|
|
*
|
|
|
|
|
* Border gesture has two types:
|
|
|
|
|
* -# #WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border.
|
|
|
|
|
* -# #WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends.
|
|
|
|
|
*
|
|
|
|
|
* It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type).
|
|
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void gesture_modal_end(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-10-17 15:09:29 +11:00
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_gesture_end(win, gesture); /* frees gesture itself, and unregisters from window */
|
2017-10-17 15:09:29 +11:00
|
|
|
op->customdata = NULL;
|
|
|
|
|
|
|
|
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
|
|
|
|
|
|
|
|
if (RNA_struct_find_property(op->ptr, "cursor")) {
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_cursor_modal_restore(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-12 14:26:43 +11:00
|
|
|
static void gesture_modal_state_to_operator(wmOperator *op, int modal_state)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
|
|
|
|
PropertyRNA *prop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
switch (modal_state) {
|
|
|
|
|
case GESTURE_MODAL_SELECT:
|
|
|
|
|
case GESTURE_MODAL_DESELECT:
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) {
|
2018-12-12 14:26:43 +11:00
|
|
|
RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT));
|
2018-08-14 10:28:41 +10:00
|
|
|
}
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
|
2018-12-12 14:26:43 +11:00
|
|
|
RNA_property_enum_set(
|
|
|
|
|
op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT) ? SEL_OP_SUB : SEL_OP_ADD);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GESTURE_MODAL_IN:
|
|
|
|
|
case GESTURE_MODAL_OUT:
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) {
|
2018-12-12 14:26:43 +11:00
|
|
|
RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_OUT));
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-12 14:26:43 +11:00
|
|
|
static int UNUSED_FUNCTION(gesture_modal_state_from_operator)(wmOperator *op)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
|
|
|
|
PropertyRNA *prop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) {
|
|
|
|
|
if (RNA_property_is_set(op->ptr, prop)) {
|
|
|
|
|
return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_DESELECT :
|
|
|
|
|
GESTURE_MODAL_SELECT;
|
2018-08-14 10:28:41 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
|
|
|
|
|
if (RNA_property_is_set(op->ptr, prop)) {
|
|
|
|
|
return RNA_property_enum_get(op->ptr, prop) == SEL_OP_SUB ? GESTURE_MODAL_DESELECT :
|
|
|
|
|
GESTURE_MODAL_SELECT;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) {
|
|
|
|
|
if (RNA_property_is_set(op->ptr, prop)) {
|
|
|
|
|
return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_OUT : GESTURE_MODAL_IN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return GESTURE_MODAL_NOP;
|
|
|
|
|
}
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Border Gesture
|
|
|
|
|
*
|
|
|
|
|
* Border gesture has two types:
|
|
|
|
|
* -# #WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border.
|
|
|
|
|
* -# #WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends.
|
|
|
|
|
*
|
|
|
|
|
* It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type).
|
|
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
static bool gesture_box_apply_rect(wmOperator *op)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
rcti *rect = gesture->customdata;
|
|
|
|
|
|
2019-04-13 09:15:15 +02:00
|
|
|
if (rect->xmin == rect->xmax || rect->ymin == rect->ymax) {
|
2017-10-17 15:09:29 +11:00
|
|
|
return 0;
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
/* operator arguments and storage. */
|
|
|
|
|
RNA_int_set(op->ptr, "xmin", min_ii(rect->xmin, rect->xmax));
|
|
|
|
|
RNA_int_set(op->ptr, "ymin", min_ii(rect->ymin, rect->ymax));
|
|
|
|
|
RNA_int_set(op->ptr, "xmax", max_ii(rect->xmin, rect->xmax));
|
|
|
|
|
RNA_int_set(op->ptr, "ymax", max_ii(rect->ymin, rect->ymax));
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
static bool gesture_box_apply(bContext *C, wmOperator *op)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
|
|
|
|
|
int retval;
|
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
if (!gesture_box_apply_rect(op)) {
|
2017-10-17 15:09:29 +11:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-12 14:26:43 +11:00
|
|
|
if (gesture->wait_for_input) {
|
|
|
|
|
gesture_modal_state_to_operator(op, gesture->modal_state);
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
retval = op->type->exec(C, op);
|
|
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
const ARegion *region = CTX_wm_region(C);
|
2018-12-12 14:26:43 +11:00
|
|
|
const bool wait_for_input = !ISTWEAK(event->type) && RNA_boolean_get(op->ptr, "wait_for_input");
|
2020-03-06 16:22:28 +01:00
|
|
|
|
2018-12-12 14:26:43 +11:00
|
|
|
if (wait_for_input) {
|
2020-03-06 16:56:42 +01:00
|
|
|
op->customdata = WM_gesture_new(win, region, event, WM_GESTURE_CROSS_RECT);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
op->customdata = WM_gesture_new(win, region, event, WM_GESTURE_RECT);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
2018-12-12 14:26:43 +11:00
|
|
|
{
|
2017-10-17 15:09:29 +11:00
|
|
|
wmGesture *gesture = op->customdata;
|
2018-12-12 14:26:43 +11:00
|
|
|
gesture->wait_for_input = wait_for_input;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add modal handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-10-17 15:09:29 +11:00
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
rcti *rect = gesture->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 12:48:06 +11:00
|
|
|
if (event->type == EVT_MODAL_MAP) {
|
2017-10-17 15:09:29 +11:00
|
|
|
switch (event->val) {
|
2020-10-21 12:48:06 +11:00
|
|
|
case GESTURE_MODAL_MOVE: {
|
2020-10-20 22:16:55 +02:00
|
|
|
gesture->move = !gesture->move;
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_BEGIN: {
|
2017-10-17 15:09:29 +11:00
|
|
|
if (gesture->type == WM_GESTURE_CROSS_RECT && gesture->is_active == false) {
|
|
|
|
|
gesture->is_active = true;
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
case GESTURE_MODAL_SELECT:
|
|
|
|
|
case GESTURE_MODAL_DESELECT:
|
|
|
|
|
case GESTURE_MODAL_IN:
|
2020-10-21 12:48:06 +11:00
|
|
|
case GESTURE_MODAL_OUT: {
|
2017-10-17 15:09:29 +11:00
|
|
|
if (gesture->wait_for_input) {
|
|
|
|
|
gesture->modal_state = event->val;
|
|
|
|
|
}
|
2018-10-05 10:27:04 +10:00
|
|
|
if (gesture_box_apply(C, op)) {
|
2017-10-17 15:09:29 +11:00
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_CANCEL: {
|
2017-10-17 15:09:29 +11:00
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-21 12:48:06 +11:00
|
|
|
else {
|
|
|
|
|
switch (event->type) {
|
|
|
|
|
case MOUSEMOVE: {
|
|
|
|
|
if (gesture->type == WM_GESTURE_CROSS_RECT && gesture->is_active == false) {
|
|
|
|
|
rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
|
|
|
|
|
}
|
|
|
|
|
else if (gesture->move) {
|
|
|
|
|
BLI_rcti_translate(rect,
|
|
|
|
|
(event->x - gesture->winrct.xmin) - rect->xmax,
|
|
|
|
|
(event->y - gesture->winrct.ymin) - rect->ymax);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rect->xmax = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymax = event->y - gesture->winrct.ymin;
|
|
|
|
|
}
|
|
|
|
|
gesture_box_apply_rect(op);
|
|
|
|
|
|
|
|
|
|
wm_gesture_tag_redraw(win);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
#ifdef WITH_INPUT_NDOF
|
2020-10-21 12:48:06 +11:00
|
|
|
case NDOF_MOTION: {
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
#endif
|
|
|
|
|
|
2020-10-21 12:48:06 +11:00
|
|
|
#if 0 /* This allows view navigation, keep disabled as it's too unpredictable. */
|
|
|
|
|
default:
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
2017-10-17 15:09:29 +11:00
|
|
|
#endif
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
|
2019-03-01 23:00:11 +11:00
|
|
|
gesture->is_active_prev = gesture->is_active;
|
2017-10-17 15:09:29 +11:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Circle Gesture
|
|
|
|
|
*
|
|
|
|
|
* Currently only used for selection or modal paint stuff,
|
2020-06-27 14:34:16 +10:00
|
|
|
* calls #wmOperatorType.exec while hold mouse, exits on release
|
2019-04-20 10:02:28 +02:00
|
|
|
* (with no difference between cancel and confirm).
|
2017-10-17 15:09:29 +11:00
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void gesture_circle_apply(bContext *C, wmOperator *op);
|
|
|
|
|
|
|
|
|
|
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2018-12-12 14:26:43 +11:00
|
|
|
const bool wait_for_input = !ISTWEAK(event->type) && RNA_boolean_get(op->ptr, "wait_for_input");
|
2017-10-17 15:09:29 +11:00
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_CIRCLE);
|
2017-10-17 15:09:29 +11:00
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
rcti *rect = gesture->customdata;
|
|
|
|
|
|
|
|
|
|
/* Default or previously stored value. */
|
|
|
|
|
rect->xmax = RNA_int_get(op->ptr, "radius");
|
|
|
|
|
|
2018-12-12 14:26:43 +11:00
|
|
|
gesture->wait_for_input = wait_for_input;
|
|
|
|
|
|
2019-04-20 10:02:28 +02:00
|
|
|
/* Starting with the mode starts immediately,
|
|
|
|
|
* like having 'wait_for_input' disabled (some tools use this). */
|
2018-12-12 14:26:43 +11:00
|
|
|
if (gesture->wait_for_input == false) {
|
2017-10-17 15:09:29 +11:00
|
|
|
gesture->is_active = true;
|
|
|
|
|
gesture_circle_apply(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add modal handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void gesture_circle_apply(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
rcti *rect = gesture->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-12 14:26:43 +11:00
|
|
|
if (gesture->wait_for_input && (gesture->modal_state == GESTURE_MODAL_NOP)) {
|
2017-10-17 15:09:29 +11:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
/* operator arguments and storage. */
|
|
|
|
|
RNA_int_set(op->ptr, "x", rect->xmin);
|
|
|
|
|
RNA_int_set(op->ptr, "y", rect->ymin);
|
|
|
|
|
RNA_int_set(op->ptr, "radius", rect->xmax);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-20 10:02:28 +02:00
|
|
|
/* When 'wait_for_input' is false,
|
|
|
|
|
* use properties to get the selection state (typically tool settings).
|
|
|
|
|
* This is done so executing as a mode can select & de-select, see: T58594. */
|
2018-12-12 14:26:43 +11:00
|
|
|
if (gesture->wait_for_input) {
|
|
|
|
|
gesture_modal_state_to_operator(op, gesture->modal_state);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (op->type->exec) {
|
|
|
|
|
int retval;
|
|
|
|
|
retval = op->type->exec(C, op);
|
|
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-10-17 15:09:29 +11:00
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
rcti *rect = gesture->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (event->type == MOUSEMOVE) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-02-16 22:41:46 +01:00
|
|
|
rect->xmin = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymin = event->y - gesture->winrct.ymin;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (gesture->is_active) {
|
|
|
|
|
gesture_circle_apply(C, op);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (event->type == EVT_MODAL_MAP) {
|
|
|
|
|
bool is_circle_size = false;
|
|
|
|
|
bool is_finished = false;
|
|
|
|
|
float fac;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
switch (event->val) {
|
|
|
|
|
case GESTURE_MODAL_CIRCLE_SIZE:
|
|
|
|
|
fac = 0.3f * (event->y - event->prevy);
|
2019-04-13 09:15:15 +02:00
|
|
|
if (fac > 0) {
|
2017-10-17 15:09:29 +11:00
|
|
|
rect->xmax += ceil(fac);
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2017-10-17 15:09:29 +11:00
|
|
|
rect->xmax += floor(fac);
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
|
|
|
|
if (rect->xmax < 1) {
|
|
|
|
|
rect->xmax = 1;
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
is_circle_size = true;
|
|
|
|
|
break;
|
|
|
|
|
case GESTURE_MODAL_CIRCLE_ADD:
|
|
|
|
|
rect->xmax += 2 + rect->xmax / 10;
|
|
|
|
|
is_circle_size = true;
|
|
|
|
|
break;
|
|
|
|
|
case GESTURE_MODAL_CIRCLE_SUB:
|
|
|
|
|
rect->xmax -= 2 + rect->xmax / 10;
|
2019-04-13 09:15:15 +02:00
|
|
|
if (rect->xmax < 1) {
|
|
|
|
|
rect->xmax = 1;
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
is_circle_size = true;
|
|
|
|
|
break;
|
|
|
|
|
case GESTURE_MODAL_SELECT:
|
|
|
|
|
case GESTURE_MODAL_DESELECT:
|
|
|
|
|
case GESTURE_MODAL_NOP: {
|
|
|
|
|
if (gesture->wait_for_input) {
|
|
|
|
|
gesture->modal_state = event->val;
|
|
|
|
|
}
|
|
|
|
|
if (event->val == GESTURE_MODAL_NOP) {
|
|
|
|
|
/* Single action, click-drag & release to exit. */
|
|
|
|
|
if (gesture->wait_for_input == false) {
|
|
|
|
|
is_finished = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* apply first click */
|
|
|
|
|
gesture->is_active = true;
|
2019-03-01 23:00:11 +11:00
|
|
|
gesture_circle_apply(C, op);
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_CANCEL:
|
|
|
|
|
case GESTURE_MODAL_CONFIRM:
|
|
|
|
|
is_finished = true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (is_finished) {
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_FINISHED; /* use finish or we don't get an undo */
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (is_circle_size) {
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
/* So next use remembers last seen size, even if we didn't apply it. */
|
|
|
|
|
RNA_int_set(op->ptr, "radius", rect->xmax);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#ifdef WITH_INPUT_NDOF
|
|
|
|
|
else if (event->type == NDOF_MOTION) {
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* Allow view navigation??? */
|
|
|
|
|
/* note, this gives issues:
|
2018-10-05 10:27:04 +10:00
|
|
|
* 1) other modal ops run on top (box select),
|
2019-06-12 09:04:10 +10:00
|
|
|
* 2) middle-mouse is used now 3) tablet/trackpad? */
|
2017-10-17 15:09:29 +11:00
|
|
|
else {
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-03-01 23:00:11 +11:00
|
|
|
gesture->is_active_prev = gesture->is_active;
|
2017-10-17 15:09:29 +11:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WM_gesture_circle_cancel(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* template to copy from */
|
|
|
|
|
void WM_OT_circle_gesture(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
ot->name = "Circle Gesture";
|
|
|
|
|
ot->idname = "WM_OT_circle_gesture";
|
|
|
|
|
ot->description = "Enter rotate mode with a circular gesture";
|
|
|
|
|
|
|
|
|
|
ot->invoke = WM_gesture_circle_invoke;
|
|
|
|
|
ot->modal = WM_gesture_circle_modal;
|
|
|
|
|
ot->poll = WM_operator_winactive;
|
|
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
|
WM_operator_properties_gesture_circle(ot);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Tweak Gesture
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void gesture_tweak_modal(bContext *C, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
wmWindow *window = CTX_wm_window(C);
|
|
|
|
|
wmGesture *gesture = window->tweak;
|
|
|
|
|
rcti *rect = gesture->customdata;
|
2020-01-09 10:36:53 +11:00
|
|
|
bool gesture_end = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
switch (event->type) {
|
|
|
|
|
case MOUSEMOVE:
|
2020-01-09 10:36:53 +11:00
|
|
|
case INBETWEEN_MOUSEMOVE: {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-02-16 22:41:46 +01:00
|
|
|
rect->xmax = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymax = event->y - gesture->winrct.ymin;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-01-09 10:36:53 +11:00
|
|
|
const int val = wm_gesture_evaluate(gesture, event);
|
|
|
|
|
if (val != 0) {
|
2017-10-17 15:09:29 +11:00
|
|
|
wmEvent tevent;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
wm_event_init_from_window(window, &tevent);
|
2019-04-20 10:02:28 +02:00
|
|
|
/* We want to get coord from start of drag,
|
|
|
|
|
* not from point where it becomes a tweak event, see T40549. */
|
2018-02-16 22:41:46 +01:00
|
|
|
tevent.x = rect->xmin + gesture->winrct.xmin;
|
|
|
|
|
tevent.y = rect->ymin + gesture->winrct.ymin;
|
2019-04-13 09:15:15 +02:00
|
|
|
if (gesture->event_type == LEFTMOUSE) {
|
2017-10-17 15:09:29 +11:00
|
|
|
tevent.type = EVT_TWEAK_L;
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
|
|
|
|
else if (gesture->event_type == RIGHTMOUSE) {
|
2017-10-17 15:09:29 +11:00
|
|
|
tevent.type = EVT_TWEAK_R;
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2017-10-17 15:09:29 +11:00
|
|
|
tevent.type = EVT_TWEAK_M;
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
tevent.val = val;
|
2020-10-21 20:43:25 +11:00
|
|
|
tevent.is_repeat = false;
|
2017-10-17 15:09:29 +11:00
|
|
|
/* mouse coords! */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
/* important we add immediately after this event, so future mouse releases
|
|
|
|
|
* (which may be in the queue already), are handled in order, see T44740 */
|
|
|
|
|
wm_event_add_ex(window, &tevent, event);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-01-09 10:36:53 +11:00
|
|
|
gesture_end = true;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
break;
|
2020-01-09 10:36:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
case LEFTMOUSE:
|
|
|
|
|
case RIGHTMOUSE:
|
|
|
|
|
case MIDDLEMOUSE:
|
|
|
|
|
if (gesture->event_type == event->type) {
|
2020-01-09 10:36:53 +11:00
|
|
|
gesture_end = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
/* when tweak fails we should give the other keymap entries a chance */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
/* XXX, assigning to readonly, BAD JUJU! */
|
|
|
|
|
((wmEvent *)event)->val = KM_RELEASE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (!ISTIMER(event->type) && event->type != EVENT_NONE) {
|
2020-01-09 10:36:53 +11:00
|
|
|
gesture_end = true;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-01-09 10:36:53 +11:00
|
|
|
|
|
|
|
|
if (gesture_end) {
|
|
|
|
|
/* Frees gesture itself, and unregisters from window. */
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_gesture_end(window, gesture);
|
2020-01-09 11:00:22 +11:00
|
|
|
|
|
|
|
|
/* This isn't very nice but needed to redraw gizmos which are hidden while tweaking,
|
|
|
|
|
* See #WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK for details. */
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
|
if ((region != NULL) && (region->gizmo_map != NULL)) {
|
|
|
|
|
if (WM_gizmomap_tag_delay_refresh_for_tweak_check(region->gizmo_map)) {
|
|
|
|
|
ED_region_tag_redraw(region);
|
2020-01-09 11:00:22 +11:00
|
|
|
}
|
|
|
|
|
}
|
2020-01-09 10:36:53 +11:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* standard tweak, called after window handlers passed on event */
|
|
|
|
|
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
|
|
|
|
|
{
|
|
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (win->tweak == NULL) {
|
2020-03-06 16:56:42 +01:00
|
|
|
const ARegion *region = CTX_wm_region(C);
|
2020-03-06 16:22:28 +01:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region) {
|
2017-10-17 15:09:29 +11:00
|
|
|
if (event->val == KM_PRESS) {
|
|
|
|
|
if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
|
2020-03-06 16:56:42 +01:00
|
|
|
win->tweak = WM_gesture_new(win, region, event, WM_GESTURE_TWEAK);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* no tweaks if event was handled */
|
|
|
|
|
if ((action & WM_HANDLER_BREAK)) {
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_gesture_end(win, win->tweak);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2019-04-13 09:15:15 +02:00
|
|
|
else {
|
2017-10-17 15:09:29 +11:00
|
|
|
gesture_tweak_modal(C, event);
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Lasso Gesture
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-10-17 15:09:29 +11:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_LASSO);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
/* add modal handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) {
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_cursor_modal_set(win, RNA_property_int_get(op->ptr, prop));
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-10-17 15:09:29 +11:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_LINES);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
/* add modal handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) {
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_cursor_modal_set(win, RNA_property_int_get(op->ptr, prop));
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 09:41:22 -03:00
|
|
|
static int gesture_lasso_apply(bContext *C, wmOperator *op)
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
2020-09-14 09:41:22 -03:00
|
|
|
int retval = OPERATOR_FINISHED;
|
2017-10-17 15:09:29 +11:00
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
PointerRNA itemptr;
|
|
|
|
|
float loc[2];
|
|
|
|
|
int i;
|
|
|
|
|
const short *lasso = gesture->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
/* operator storage as path. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
RNA_collection_clear(op->ptr, "path");
|
|
|
|
|
for (i = 0; i < gesture->points; i++, lasso += 2) {
|
|
|
|
|
loc[0] = lasso[0];
|
|
|
|
|
loc[1] = lasso[1];
|
|
|
|
|
RNA_collection_add(op->ptr, "path", &itemptr);
|
|
|
|
|
RNA_float_set_array(&itemptr, "loc", loc);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
gesture_modal_end(C, op);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (op->type->exec) {
|
2020-09-14 09:41:22 -03:00
|
|
|
retval = op->type->exec(C, op);
|
2017-10-17 15:09:29 +11:00
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
|
}
|
2020-09-14 09:41:22 -03:00
|
|
|
|
|
|
|
|
return retval;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 12:48:06 +11:00
|
|
|
if (event->type == EVT_MODAL_MAP) {
|
|
|
|
|
switch (event->val) {
|
|
|
|
|
case GESTURE_MODAL_MOVE: {
|
|
|
|
|
gesture->move = !gesture->move;
|
|
|
|
|
break;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
switch (event->type) {
|
|
|
|
|
case MOUSEMOVE:
|
|
|
|
|
case INBETWEEN_MOUSEMOVE: {
|
|
|
|
|
wm_gesture_tag_redraw(CTX_wm_window(C));
|
|
|
|
|
|
|
|
|
|
if (gesture->points == gesture->points_alloc) {
|
|
|
|
|
gesture->points_alloc *= 2;
|
|
|
|
|
gesture->customdata = MEM_reallocN(gesture->customdata,
|
|
|
|
|
sizeof(short[2]) * gesture->points_alloc);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 12:48:06 +11:00
|
|
|
{
|
2020-10-21 12:57:50 +11:00
|
|
|
short(*lasso)[2] = gesture->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 12:57:50 +11:00
|
|
|
const int x = ((event->x - gesture->winrct.xmin) - lasso[gesture->points - 1][0]);
|
|
|
|
|
const int y = ((event->y - gesture->winrct.ymin) - lasso[gesture->points - 1][1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 12:48:06 +11:00
|
|
|
/* move the lasso */
|
|
|
|
|
if (gesture->move) {
|
|
|
|
|
for (int i = 0; i < gesture->points; i++) {
|
2020-10-21 12:57:50 +11:00
|
|
|
lasso[i][0] += x;
|
|
|
|
|
lasso[i][1] += y;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-21 12:57:50 +11:00
|
|
|
/* Make a simple distance check to get a smoother lasso
|
|
|
|
|
* add only when at least 2 pixels between this and previous location. */
|
2020-10-21 12:48:06 +11:00
|
|
|
else if ((x * x + y * y) > pow2f(2.0f * UI_DPI_FAC)) {
|
2020-10-21 12:57:50 +11:00
|
|
|
lasso[gesture->points][0] = event->x - gesture->winrct.xmin;
|
|
|
|
|
lasso[gesture->points][1] = event->y - gesture->winrct.ymin;
|
2020-10-21 12:48:06 +11:00
|
|
|
gesture->points++;
|
2020-10-20 22:16:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-21 12:48:06 +11:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LEFTMOUSE:
|
|
|
|
|
case MIDDLEMOUSE:
|
|
|
|
|
case RIGHTMOUSE: {
|
|
|
|
|
if (event->val == KM_RELEASE) { /* key release */
|
|
|
|
|
return gesture_lasso_apply(C, op);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2020-10-21 12:48:06 +11:00
|
|
|
break;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2020-10-21 12:48:06 +11:00
|
|
|
case EVT_ESCKEY: {
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-01 23:00:11 +11:00
|
|
|
gesture->is_active_prev = gesture->is_active;
|
2017-10-17 15:09:29 +11:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WM_gesture_lines_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
return WM_gesture_lasso_modal(C, op, event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* helper function, we may want to add options for conversion to view space
|
|
|
|
|
*
|
|
|
|
|
* caller must free.
|
|
|
|
|
*/
|
|
|
|
|
const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
|
|
|
|
|
wmOperator *op,
|
2020-05-04 19:50:06 +10:00
|
|
|
int *r_mcoords_len))[2]
|
2017-10-17 15:09:29 +11:00
|
|
|
{
|
|
|
|
|
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "path");
|
2020-05-04 19:50:06 +10:00
|
|
|
int(*mcoords)[2] = NULL;
|
2017-10-17 15:09:29 +11:00
|
|
|
BLI_assert(prop != NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (prop) {
|
|
|
|
|
const int len = RNA_property_collection_length(op->ptr, prop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
if (len) {
|
|
|
|
|
int i = 0;
|
2020-05-04 19:50:06 +10:00
|
|
|
mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
|
|
|
|
|
float loc[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
RNA_float_get_array(&itemptr, "loc", loc);
|
2020-05-04 19:50:06 +10:00
|
|
|
mcoords[i][0] = (int)loc[0];
|
|
|
|
|
mcoords[i][1] = (int)loc[1];
|
2017-10-17 15:09:29 +11:00
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
RNA_PROP_END;
|
|
|
|
|
}
|
2020-05-04 19:50:06 +10:00
|
|
|
*r_mcoords_len = len;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2020-05-04 19:50:06 +10:00
|
|
|
*r_mcoords_len = 0;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
/* cast for 'const' */
|
2020-05-04 19:50:06 +10:00
|
|
|
return mcoords;
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* template to copy from */
|
|
|
|
|
|
|
|
|
|
static int gesture_lasso_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2019-04-17 08:24:14 +02:00
|
|
|
RNA_BEGIN (op->ptr, itemptr, "path") {
|
2017-10-17 15:09:29 +11:00
|
|
|
float loc[2];
|
|
|
|
|
|
|
|
|
|
RNA_float_get_array(&itemptr, "loc", loc);
|
|
|
|
|
printf("Location: %f %f\n", loc[0], loc[1]);
|
|
|
|
|
}
|
|
|
|
|
RNA_END;
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WM_OT_lasso_gesture(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
|
|
ot->name = "Lasso Gesture";
|
|
|
|
|
ot->idname = "WM_OT_lasso_gesture";
|
|
|
|
|
ot->description = "Select objects within the lasso as you move the pointer";
|
|
|
|
|
|
|
|
|
|
ot->invoke = WM_gesture_lasso_invoke;
|
|
|
|
|
ot->modal = WM_gesture_lasso_modal;
|
|
|
|
|
ot->exec = gesture_lasso_exec;
|
|
|
|
|
|
|
|
|
|
ot->poll = WM_operator_winactive;
|
|
|
|
|
|
|
|
|
|
prop = RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
|
2020-11-17 12:56:26 +01:00
|
|
|
RNA_def_property_struct_runtime(ot->srna, prop, &RNA_OperatorMousePath);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Straight Line Gesture
|
2020-09-26 21:59:30 +02:00
|
|
|
*
|
2020-09-29 13:58:16 +10:00
|
|
|
* Gesture defined by the start and end points of a line that is created between the position of
|
2020-09-26 21:59:30 +02:00
|
|
|
* the initial event and the position of the current event.
|
|
|
|
|
*
|
|
|
|
|
* Straight Line Gesture has two modal callbacks depending on the tool that is being implemented: a
|
|
|
|
|
* regular modal callback intended to update the data during the execution of the gesture and a
|
2020-09-29 13:58:16 +10:00
|
|
|
* one-shot callback that only updates the data once when the gesture finishes.
|
2020-09-26 21:59:30 +02:00
|
|
|
*
|
2020-09-29 13:58:16 +10:00
|
|
|
* It stores 4 values: `xstart, ystart, xend, yend`.
|
2017-10-17 15:09:29 +11:00
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static bool gesture_straightline_apply(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
rcti *rect = gesture->customdata;
|
|
|
|
|
|
2019-04-13 09:15:15 +02:00
|
|
|
if (rect->xmin == rect->xmax && rect->ymin == rect->ymax) {
|
2017-10-17 15:09:29 +11:00
|
|
|
return 0;
|
2019-04-13 09:15:15 +02:00
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
/* operator arguments and storage. */
|
|
|
|
|
RNA_int_set(op->ptr, "xstart", rect->xmin);
|
|
|
|
|
RNA_int_set(op->ptr, "ystart", rect->ymin);
|
|
|
|
|
RNA_int_set(op->ptr, "xend", rect->xmax);
|
|
|
|
|
RNA_int_set(op->ptr, "yend", rect->ymax);
|
2020-10-21 17:44:00 +02:00
|
|
|
RNA_boolean_set(op->ptr, "flip", gesture->use_flip);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
if (op->type->exec) {
|
|
|
|
|
int retval = op->type->exec(C, op);
|
|
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-10-17 15:09:29 +11:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_STRAIGHTLINE);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
if (ISTWEAK(event->type)) {
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
gesture->is_active = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add modal handler */
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) {
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_cursor_modal_set(win, RNA_property_int_get(op->ptr, prop));
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
2020-10-05 17:19:28 +02:00
|
|
|
/**
|
|
|
|
|
* This invoke callback starts the straightline gesture with a viewport preview to the right side
|
|
|
|
|
* of the line.
|
|
|
|
|
*/
|
|
|
|
|
int WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
WM_gesture_straightline_invoke(C, op, event);
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
gesture->draw_active_side = true;
|
2020-10-21 17:44:00 +02:00
|
|
|
gesture->use_flip = false;
|
2020-10-05 17:19:28 +02:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
|
2020-10-05 21:05:45 +02:00
|
|
|
#define STRAIGHTLINE_SNAP_DEG 15.0f
|
|
|
|
|
static void wm_gesture_straightline_do_angle_snap(rcti *rect)
|
|
|
|
|
{
|
|
|
|
|
const float line_start[2] = {rect->xmin, rect->ymin};
|
|
|
|
|
const float line_end[2] = {rect->xmax, rect->ymax};
|
|
|
|
|
const float x_axis[2] = {1.0f, 0.0f};
|
|
|
|
|
|
|
|
|
|
float line_direction[2];
|
|
|
|
|
sub_v2_v2v2(line_direction, line_end, line_start);
|
|
|
|
|
const float line_length = normalize_v2(line_direction);
|
|
|
|
|
|
|
|
|
|
const float angle = angle_signed_v2v2(x_axis, line_direction);
|
|
|
|
|
const float angle_deg = RAD2DEG(angle) + (STRAIGHTLINE_SNAP_DEG / 2.0f);
|
|
|
|
|
const float angle_snapped_deg = -floorf(angle_deg / STRAIGHTLINE_SNAP_DEG) *
|
|
|
|
|
STRAIGHTLINE_SNAP_DEG;
|
|
|
|
|
const float angle_snapped = DEG2RAD(angle_snapped_deg);
|
|
|
|
|
|
|
|
|
|
float line_snapped_end[2];
|
|
|
|
|
rotate_v2_v2fl(line_snapped_end, x_axis, angle_snapped);
|
|
|
|
|
mul_v2_fl(line_snapped_end, line_length);
|
|
|
|
|
add_v2_v2(line_snapped_end, line_start);
|
|
|
|
|
|
|
|
|
|
rect->xmax = (int)line_snapped_end[0];
|
|
|
|
|
rect->ymax = (int)line_snapped_end[1];
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-26 21:59:30 +02:00
|
|
|
/**
|
|
|
|
|
* This modal callback calls exec once per mouse move event while the gesture is active with the
|
|
|
|
|
* updated line start and end values, so it can be used for tools that have a real time preview
|
|
|
|
|
* (like a gradient updating in real time over the mesh).
|
|
|
|
|
*/
|
2017-10-17 15:09:29 +11:00
|
|
|
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2017-10-17 15:09:29 +11:00
|
|
|
rcti *rect = gesture->customdata;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-21 12:48:06 +11:00
|
|
|
if (event->type == EVT_MODAL_MAP) {
|
2017-10-17 15:09:29 +11:00
|
|
|
switch (event->val) {
|
2020-10-21 12:48:06 +11:00
|
|
|
case GESTURE_MODAL_MOVE: {
|
2020-10-20 22:16:55 +02:00
|
|
|
gesture->move = !gesture->move;
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_BEGIN: {
|
2017-10-17 15:09:29 +11:00
|
|
|
if (gesture->is_active == false) {
|
|
|
|
|
gesture->is_active = true;
|
2020-03-06 16:22:28 +01:00
|
|
|
wm_gesture_tag_redraw(win);
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_SNAP: {
|
2020-10-05 21:05:45 +02:00
|
|
|
/* Toggle snapping on/off. */
|
|
|
|
|
gesture->use_snap = !gesture->use_snap;
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
2020-10-21 17:44:00 +02:00
|
|
|
case GESTURE_MODAL_FLIP: {
|
|
|
|
|
/* Toggle snapping on/off. */
|
|
|
|
|
gesture->use_flip = !gesture->use_flip;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-10-21 12:48:06 +11:00
|
|
|
case GESTURE_MODAL_SELECT: {
|
2017-10-17 15:09:29 +11:00
|
|
|
if (gesture_straightline_apply(C, op)) {
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_CANCEL: {
|
2017-10-17 15:09:29 +11:00
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
switch (event->type) {
|
|
|
|
|
case MOUSEMOVE: {
|
|
|
|
|
if (gesture->is_active == false) {
|
|
|
|
|
rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
|
|
|
|
|
}
|
|
|
|
|
else if (gesture->move) {
|
|
|
|
|
BLI_rcti_translate(rect,
|
|
|
|
|
(event->x - gesture->winrct.xmin) - rect->xmax,
|
|
|
|
|
(event->y - gesture->winrct.ymin) - rect->ymax);
|
|
|
|
|
gesture_straightline_apply(C, op);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rect->xmax = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymax = event->y - gesture->winrct.ymin;
|
|
|
|
|
gesture_straightline_apply(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gesture->use_snap) {
|
|
|
|
|
wm_gesture_straightline_do_angle_snap(rect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wm_gesture_tag_redraw(win);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-17 15:09:29 +11:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-01 23:00:11 +11:00
|
|
|
gesture->is_active_prev = gesture->is_active;
|
2017-10-17 15:09:29 +11:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-26 21:59:30 +02:00
|
|
|
/**
|
2020-09-29 13:58:16 +10:00
|
|
|
* This modal one-shot callback only calls exec once after the gesture finishes without any updates
|
2020-09-26 21:59:30 +02:00
|
|
|
* during the gesture execution. Should be used for operations that are intended to be applied once
|
|
|
|
|
* without real time preview (like a trimming tool that only applies the bisect operation once
|
|
|
|
|
* after finishing the gesture as the bisect operation is too heavy to be computed in real time for
|
|
|
|
|
* a preview).
|
|
|
|
|
*/
|
|
|
|
|
int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
|
wmWindow *win = CTX_wm_window(C);
|
|
|
|
|
rcti *rect = gesture->customdata;
|
|
|
|
|
|
2020-10-21 12:48:06 +11:00
|
|
|
if (event->type == EVT_MODAL_MAP) {
|
2020-09-26 21:59:30 +02:00
|
|
|
switch (event->val) {
|
2020-10-21 12:48:06 +11:00
|
|
|
case GESTURE_MODAL_MOVE: {
|
2020-10-20 22:16:55 +02:00
|
|
|
gesture->move = !gesture->move;
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_BEGIN: {
|
2020-09-26 21:59:30 +02:00
|
|
|
if (gesture->is_active == false) {
|
|
|
|
|
gesture->is_active = true;
|
|
|
|
|
wm_gesture_tag_redraw(win);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_SNAP: {
|
2020-10-05 21:05:45 +02:00
|
|
|
/* Toggle snapping on/off. */
|
|
|
|
|
gesture->use_snap = !gesture->use_snap;
|
|
|
|
|
break;
|
2020-10-21 17:44:00 +02:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_FLIP: {
|
|
|
|
|
/* Toggle flip on/off. */
|
|
|
|
|
gesture->use_flip = !gesture->use_flip;
|
|
|
|
|
break;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
2020-09-26 21:59:30 +02:00
|
|
|
case GESTURE_MODAL_SELECT:
|
|
|
|
|
case GESTURE_MODAL_DESELECT:
|
|
|
|
|
case GESTURE_MODAL_IN:
|
2020-10-21 12:48:06 +11:00
|
|
|
case GESTURE_MODAL_OUT: {
|
2020-09-26 21:59:30 +02:00
|
|
|
if (gesture->wait_for_input) {
|
|
|
|
|
gesture->modal_state = event->val;
|
|
|
|
|
}
|
|
|
|
|
if (gesture_straightline_apply(C, op)) {
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
case GESTURE_MODAL_CANCEL: {
|
2020-09-26 21:59:30 +02:00
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2020-10-21 12:48:06 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
switch (event->type) {
|
|
|
|
|
case MOUSEMOVE: {
|
|
|
|
|
if (gesture->is_active == false) {
|
|
|
|
|
rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
|
|
|
|
|
}
|
|
|
|
|
else if (gesture->move) {
|
|
|
|
|
BLI_rcti_translate(rect,
|
|
|
|
|
(event->x - gesture->winrct.xmin) - rect->xmax,
|
|
|
|
|
(event->y - gesture->winrct.ymin) - rect->ymax);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rect->xmax = event->x - gesture->winrct.xmin;
|
|
|
|
|
rect->ymax = event->y - gesture->winrct.ymin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gesture->use_snap) {
|
|
|
|
|
wm_gesture_straightline_do_angle_snap(rect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wm_gesture_tag_redraw(win);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-26 21:59:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gesture->is_active_prev = gesture->is_active;
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-17 15:09:29 +11:00
|
|
|
void WM_gesture_straightline_cancel(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
gesture_modal_end(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* template to copy from */
|
|
|
|
|
void WM_OT_straightline_gesture(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
|
|
ot->name = "Straight Line Gesture";
|
|
|
|
|
ot->idname = "WM_OT_straightline_gesture";
|
|
|
|
|
ot->description = "Draw a straight line as you move the pointer";
|
|
|
|
|
|
|
|
|
|
ot->invoke = WM_gesture_straightline_invoke;
|
|
|
|
|
ot->modal = WM_gesture_straightline_modal;
|
|
|
|
|
ot->exec = gesture_straightline_exec;
|
|
|
|
|
|
|
|
|
|
ot->poll = WM_operator_winactive;
|
|
|
|
|
|
|
|
|
|
WM_operator_properties_gesture_straightline(ot, 0);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** \} */
|