Compare commits
20 Commits
refactor-v
...
node-edito
Author | SHA1 | Date | |
---|---|---|---|
d85adbe929 | |||
f1f53f9122 | |||
542aed8d55 | |||
e65a0ee1e1 | |||
f186e7f47f | |||
594bdf1cc0 | |||
9be38c1fbf | |||
e1418ad7a1 | |||
f964d80b82 | |||
a967780fd7 | |||
c6ae967059 | |||
d2e9ce2a46 | |||
ab333aaac5 | |||
d8c24c165f | |||
687b653797 | |||
a5f221cc2f | |||
fa01599de7 | |||
cfbf277e37 | |||
76bfcb34fb | |||
![]() |
b67c7f89ff |
@@ -49,6 +49,11 @@ typedef enum {
|
|||||||
} NodeBorder;
|
} NodeBorder;
|
||||||
|
|
||||||
#define NODE_GRID_STEPS 5
|
#define NODE_GRID_STEPS 5
|
||||||
|
#define NODE_EDGE_PAN_INSIDE_PAD 2
|
||||||
|
#define NODE_EDGE_PAN_OUTSIDE_PAD 0 /* Disable clamping for node panning, use whole screen */
|
||||||
|
#define NODE_EDGE_PAN_SPEED_RAMP 1
|
||||||
|
#define NODE_EDGE_PAN_MAX_SPEED 40 /* In UI units per second, slower than default */
|
||||||
|
#define NODE_EDGE_PAN_DELAY 1.0f
|
||||||
|
|
||||||
/* space_node.c */
|
/* space_node.c */
|
||||||
|
|
||||||
|
@@ -105,8 +105,12 @@ struct ScrArea;
|
|||||||
struct bContext;
|
struct bContext;
|
||||||
struct bScreen;
|
struct bScreen;
|
||||||
struct rctf;
|
struct rctf;
|
||||||
|
struct rcti;
|
||||||
|
struct wmEvent;
|
||||||
struct wmGizmoGroupType;
|
struct wmGizmoGroupType;
|
||||||
struct wmKeyConfig;
|
struct wmKeyConfig;
|
||||||
|
struct wmOperator;
|
||||||
|
struct wmOperatorType;
|
||||||
|
|
||||||
typedef struct View2DScrollers View2DScrollers;
|
typedef struct View2DScrollers View2DScrollers;
|
||||||
|
|
||||||
@@ -287,6 +291,77 @@ void UI_view2d_smooth_view(struct bContext *C,
|
|||||||
/* Caller passes in own idname. */
|
/* Caller passes in own idname. */
|
||||||
void VIEW2D_GGT_navigate_impl(struct wmGizmoGroupType *gzgt, const char *idname);
|
void VIEW2D_GGT_navigate_impl(struct wmGizmoGroupType *gzgt, const char *idname);
|
||||||
|
|
||||||
|
/* Edge pan */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom-data for view panning operators.
|
||||||
|
*/
|
||||||
|
typedef struct View2DEdgePanData {
|
||||||
|
/** Screen where view pan was initiated. */
|
||||||
|
struct bScreen *screen;
|
||||||
|
/** Area where view pan was initiated. */
|
||||||
|
struct ScrArea *area;
|
||||||
|
/** Region where view pan was initiated. */
|
||||||
|
struct ARegion *region;
|
||||||
|
/** View2d we're operating in. */
|
||||||
|
struct View2D *v2d;
|
||||||
|
|
||||||
|
/** Inside distance in UI units from the edge of the region within which to start panning. */
|
||||||
|
float inside_pad;
|
||||||
|
/** Outside distance in UI units from the edge of the region at which to stop panning. */
|
||||||
|
float outside_pad;
|
||||||
|
/**
|
||||||
|
* Width of the zone in UI units where speed increases with distance from the edge.
|
||||||
|
* At the end of this zone max speed is reached.
|
||||||
|
*/
|
||||||
|
float speed_ramp;
|
||||||
|
/** Maximum speed in UI units per second. */
|
||||||
|
float max_speed;
|
||||||
|
/** Delay in seconds before maximum speed is reached. */
|
||||||
|
float delay;
|
||||||
|
|
||||||
|
/** Amount to move view relative to zoom. */
|
||||||
|
float facx, facy;
|
||||||
|
|
||||||
|
/* Timers. */
|
||||||
|
double edge_pan_last_time;
|
||||||
|
double edge_pan_start_time_x, edge_pan_start_time_y;
|
||||||
|
} View2DEdgePanData;
|
||||||
|
|
||||||
|
bool UI_view2d_edge_pan_poll(struct bContext *C);
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_init(struct bContext *C,
|
||||||
|
struct View2DEdgePanData *vpd,
|
||||||
|
float inside_pad,
|
||||||
|
float outside_pad,
|
||||||
|
float speed_ramp,
|
||||||
|
float max_speed,
|
||||||
|
float delay);
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_reset(struct View2DEdgePanData *vpd);
|
||||||
|
|
||||||
|
/* Apply transform to view (i.e. adjust 'cur' rect). */
|
||||||
|
void UI_view2d_edge_pan_apply(struct bContext *C, struct View2DEdgePanData *vpd, int x, int y);
|
||||||
|
|
||||||
|
/* Apply transform to view using mouse events. */
|
||||||
|
void UI_view2d_edge_pan_apply_event(struct bContext *C,
|
||||||
|
struct View2DEdgePanData *vpd,
|
||||||
|
const struct wmEvent *event);
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_operator_properties(struct wmOperatorType *ot);
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot,
|
||||||
|
float inside_pad,
|
||||||
|
float outside_pad,
|
||||||
|
float speed_ramp,
|
||||||
|
float max_speed,
|
||||||
|
float delay);
|
||||||
|
|
||||||
|
/* Initialize panning data with operator settings. */
|
||||||
|
void UI_view2d_edge_pan_operator_init(struct bContext *C,
|
||||||
|
struct View2DEdgePanData *vpd,
|
||||||
|
struct wmOperator *op);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -75,6 +75,7 @@ set(SRC
|
|||||||
resources.c
|
resources.c
|
||||||
view2d.c
|
view2d.c
|
||||||
view2d_draw.c
|
view2d_draw.c
|
||||||
|
view2d_edge_pan.c
|
||||||
view2d_gizmo_navigate.c
|
view2d_gizmo_navigate.c
|
||||||
view2d_ops.c
|
view2d_ops.c
|
||||||
|
|
||||||
|
345
source/blender/editors/interface/view2d_edge_pan.c
Normal file
345
source/blender/editors/interface/view2d_edge_pan.c
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
/*
|
||||||
|
* 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) 2021 Blender Foundation
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup spnode
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BKE_context.h"
|
||||||
|
|
||||||
|
#include "BLI_math.h"
|
||||||
|
#include "BLI_rect.h"
|
||||||
|
|
||||||
|
#include "ED_screen.h"
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "PIL_time.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_define.h"
|
||||||
|
|
||||||
|
#include "UI_interface.h"
|
||||||
|
#include "UI_view2d.h"
|
||||||
|
|
||||||
|
#include "WM_api.h"
|
||||||
|
#include "WM_types.h"
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Edge Pan Operator Utilties
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
bool UI_view2d_edge_pan_poll(bContext *C)
|
||||||
|
{
|
||||||
|
ARegion *region = CTX_wm_region(C);
|
||||||
|
|
||||||
|
/* check if there's a region in context to work with */
|
||||||
|
if (region == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
View2D *v2d = ®ion->v2d;
|
||||||
|
|
||||||
|
/* check that 2d-view can pan */
|
||||||
|
if ((v2d->keepofs & V2D_LOCKOFS_X) && (v2d->keepofs & V2D_LOCKOFS_Y)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* view can pan */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_init(bContext *C,
|
||||||
|
View2DEdgePanData *vpd,
|
||||||
|
float inside_pad,
|
||||||
|
float outside_pad,
|
||||||
|
float speed_ramp,
|
||||||
|
float max_speed,
|
||||||
|
float delay)
|
||||||
|
{
|
||||||
|
if (!UI_view2d_edge_pan_poll(C)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set pointers to owners */
|
||||||
|
vpd->screen = CTX_wm_screen(C);
|
||||||
|
vpd->area = CTX_wm_area(C);
|
||||||
|
vpd->region = CTX_wm_region(C);
|
||||||
|
vpd->v2d = &vpd->region->v2d;
|
||||||
|
|
||||||
|
BLI_assert(speed_ramp > 0.0f);
|
||||||
|
vpd->inside_pad = inside_pad;
|
||||||
|
vpd->outside_pad = outside_pad;
|
||||||
|
vpd->speed_ramp = speed_ramp;
|
||||||
|
vpd->max_speed = max_speed;
|
||||||
|
vpd->delay = delay;
|
||||||
|
|
||||||
|
/* calculate translation factor - based on size of view */
|
||||||
|
const float winx = (float)(BLI_rcti_size_x(&vpd->region->winrct) + 1);
|
||||||
|
const float winy = (float)(BLI_rcti_size_y(&vpd->region->winrct) + 1);
|
||||||
|
vpd->facx = (BLI_rctf_size_x(&vpd->v2d->cur)) / winx;
|
||||||
|
vpd->facy = (BLI_rctf_size_y(&vpd->v2d->cur)) / winy;
|
||||||
|
|
||||||
|
UI_view2d_edge_pan_reset(vpd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_reset(View2DEdgePanData *vpd)
|
||||||
|
{
|
||||||
|
vpd->edge_pan_start_time_x = 0.0;
|
||||||
|
vpd->edge_pan_start_time_y = 0.0;
|
||||||
|
vpd->edge_pan_last_time = PIL_check_seconds_timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the edge pan timers if the mouse isn't in the scroll zone and
|
||||||
|
* start the timers when the mouse enters a scroll zone.
|
||||||
|
*/
|
||||||
|
static void edge_pan_manage_delay_timers(View2DEdgePanData *vpd,
|
||||||
|
int pan_dir_x,
|
||||||
|
int pan_dir_y,
|
||||||
|
const double current_time)
|
||||||
|
{
|
||||||
|
if (pan_dir_x == 0) {
|
||||||
|
vpd->edge_pan_start_time_x = 0.0;
|
||||||
|
}
|
||||||
|
else if (vpd->edge_pan_start_time_x == 0.0) {
|
||||||
|
vpd->edge_pan_start_time_x = current_time;
|
||||||
|
}
|
||||||
|
if (pan_dir_y == 0) {
|
||||||
|
vpd->edge_pan_start_time_y = 0.0;
|
||||||
|
}
|
||||||
|
else if (vpd->edge_pan_start_time_y == 0.0) {
|
||||||
|
vpd->edge_pan_start_time_y = current_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to calculate a "fade in" factor for edge panning to make the interaction feel smooth
|
||||||
|
* and more purposeful.
|
||||||
|
*
|
||||||
|
* \note Assumes a domain_min of 0.0f.
|
||||||
|
*/
|
||||||
|
static float smootherstep(const float domain_max, float x)
|
||||||
|
{
|
||||||
|
x = clamp_f(x / domain_max, 0.0, 1.0);
|
||||||
|
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float edge_pan_speed(View2DEdgePanData *vpd,
|
||||||
|
int event_loc,
|
||||||
|
bool x_dir,
|
||||||
|
const double current_time)
|
||||||
|
{
|
||||||
|
ARegion *region = vpd->region;
|
||||||
|
|
||||||
|
/* Find the distance from the start of the drag zone. */
|
||||||
|
const int pad = vpd->inside_pad * U.widget_unit;
|
||||||
|
const int min = (x_dir ? region->winrct.xmin : region->winrct.ymin) + pad;
|
||||||
|
const int max = (x_dir ? region->winrct.xmax : region->winrct.ymax) - pad;
|
||||||
|
int distance = 0.0;
|
||||||
|
if (event_loc > max) {
|
||||||
|
distance = event_loc - max;
|
||||||
|
}
|
||||||
|
else if (event_loc < min) {
|
||||||
|
distance = min - event_loc;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_assert(!"Calculating speed outside of pan zones");
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
float distance_factor = distance / (vpd->speed_ramp * U.widget_unit);
|
||||||
|
CLAMP(distance_factor, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
/* Apply a fade in to the speed based on a start time delay. */
|
||||||
|
const double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y;
|
||||||
|
const float delay_factor = smootherstep(vpd->delay, (float)(current_time - start_time));
|
||||||
|
|
||||||
|
return distance_factor * delay_factor * vpd->max_speed * U.widget_unit * (float)U.dpi_fac;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void edge_pan_apply_delta(bContext *C, View2DEdgePanData *vpd, float dx, float dy)
|
||||||
|
{
|
||||||
|
View2D *v2d = vpd->v2d;
|
||||||
|
if (!v2d) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate amount to move view by */
|
||||||
|
dx *= vpd->facx;
|
||||||
|
dy *= vpd->facy;
|
||||||
|
|
||||||
|
/* only move view on an axis if change is allowed */
|
||||||
|
if ((v2d->keepofs & V2D_LOCKOFS_X) == 0) {
|
||||||
|
v2d->cur.xmin += dx;
|
||||||
|
v2d->cur.xmax += dx;
|
||||||
|
}
|
||||||
|
if ((v2d->keepofs & V2D_LOCKOFS_Y) == 0) {
|
||||||
|
v2d->cur.ymin += dy;
|
||||||
|
v2d->cur.ymax += dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inform v2d about changes after this operation. */
|
||||||
|
UI_view2d_curRect_changed(C, v2d);
|
||||||
|
|
||||||
|
/* don't rebuild full tree in outliner, since we're just changing our view */
|
||||||
|
ED_region_tag_redraw_no_rebuild(vpd->region);
|
||||||
|
|
||||||
|
/* request updates to be done... */
|
||||||
|
WM_event_add_mousemove(CTX_wm_window(C));
|
||||||
|
|
||||||
|
UI_view2d_sync(vpd->screen, vpd->area, v2d, V2D_LOCK_COPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, int x, int y)
|
||||||
|
{
|
||||||
|
ARegion *region = vpd->region;
|
||||||
|
|
||||||
|
rcti inside_rect, outside_rect;
|
||||||
|
inside_rect = region->winrct;
|
||||||
|
outside_rect = region->winrct;
|
||||||
|
BLI_rcti_pad(&inside_rect, -vpd->inside_pad * U.widget_unit, -vpd->inside_pad * U.widget_unit);
|
||||||
|
BLI_rcti_pad(&outside_rect, vpd->outside_pad * U.widget_unit, vpd->outside_pad * U.widget_unit);
|
||||||
|
|
||||||
|
int pan_dir_x = 0;
|
||||||
|
int pan_dir_y = 0;
|
||||||
|
if ((vpd->outside_pad == 0) || BLI_rcti_isect_pt(&outside_rect, x, y)) {
|
||||||
|
/* Find whether the mouse is beyond X and Y edges. */
|
||||||
|
if (x > inside_rect.xmax) {
|
||||||
|
pan_dir_x = 1;
|
||||||
|
}
|
||||||
|
else if (x < inside_rect.xmin) {
|
||||||
|
pan_dir_x = -1;
|
||||||
|
}
|
||||||
|
if (y > inside_rect.ymax) {
|
||||||
|
pan_dir_y = 1;
|
||||||
|
}
|
||||||
|
else if (y < inside_rect.ymin) {
|
||||||
|
pan_dir_y = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const double current_time = PIL_check_seconds_timer();
|
||||||
|
edge_pan_manage_delay_timers(vpd, pan_dir_x, pan_dir_y, current_time);
|
||||||
|
|
||||||
|
/* Calculate the delta since the last time the operator was called. */
|
||||||
|
const float dtime = (float)(current_time - vpd->edge_pan_last_time);
|
||||||
|
float dx = 0.0f, dy = 0.0f;
|
||||||
|
if (pan_dir_x != 0) {
|
||||||
|
const float speed = edge_pan_speed(vpd, x, true, current_time);
|
||||||
|
dx = dtime * speed * (float)pan_dir_x;
|
||||||
|
}
|
||||||
|
if (pan_dir_y != 0) {
|
||||||
|
const float speed = edge_pan_speed(vpd, y, false, current_time);
|
||||||
|
dy = dtime * speed * (float)pan_dir_y;
|
||||||
|
}
|
||||||
|
vpd->edge_pan_last_time = current_time;
|
||||||
|
|
||||||
|
/* Pan, clamping inside the regions's total bounds. */
|
||||||
|
edge_pan_apply_delta(C, vpd, dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_apply_event(bContext *C, View2DEdgePanData *vpd, const wmEvent *event)
|
||||||
|
{
|
||||||
|
/* Only mousemove events matter here, ignore others. */
|
||||||
|
if (event->type != MOUSEMOVE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UI_view2d_edge_pan_apply(C, vpd, event->x, event->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_operator_properties(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* Default values for */
|
||||||
|
UI_view2d_edge_pan_operator_properties_ex(ot,
|
||||||
|
/*inside_pad*/ 1.0f,
|
||||||
|
/*outside_pad*/ 0.0f,
|
||||||
|
/*speed_ramp*/ 1.0f,
|
||||||
|
/*max_speed*/ 500.0f,
|
||||||
|
/*delay*/ 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot,
|
||||||
|
float inside_pad,
|
||||||
|
float outside_pad,
|
||||||
|
float speed_ramp,
|
||||||
|
float max_speed,
|
||||||
|
float delay)
|
||||||
|
{
|
||||||
|
RNA_def_float(
|
||||||
|
ot->srna,
|
||||||
|
"inside_padding",
|
||||||
|
inside_pad,
|
||||||
|
0.0f,
|
||||||
|
100.0f,
|
||||||
|
"Inside Padding",
|
||||||
|
"Inside distance in UI units from the edge of the region within which to start panning",
|
||||||
|
0.0f,
|
||||||
|
100.0f);
|
||||||
|
RNA_def_float(
|
||||||
|
ot->srna,
|
||||||
|
"outside_padding",
|
||||||
|
outside_pad,
|
||||||
|
0.0f,
|
||||||
|
100.0f,
|
||||||
|
"Outside Padding",
|
||||||
|
"Outside distance in UI units from the edge of the region at which to stop panning",
|
||||||
|
0.0f,
|
||||||
|
100.0f);
|
||||||
|
RNA_def_float(ot->srna,
|
||||||
|
"speed_ramp",
|
||||||
|
speed_ramp,
|
||||||
|
0.0f,
|
||||||
|
100.0f,
|
||||||
|
"Speed Ramp",
|
||||||
|
"Width of the zone in UI units where speed increases with distance from the edge",
|
||||||
|
0.0f,
|
||||||
|
100.0f);
|
||||||
|
RNA_def_float(ot->srna,
|
||||||
|
"max_speed",
|
||||||
|
max_speed,
|
||||||
|
0.0f,
|
||||||
|
10000.0f,
|
||||||
|
"Max Speed",
|
||||||
|
"Maximum speed in UI units per second",
|
||||||
|
0.0f,
|
||||||
|
10000.0f);
|
||||||
|
RNA_def_float(ot->srna,
|
||||||
|
"delay",
|
||||||
|
delay,
|
||||||
|
0.0f,
|
||||||
|
10.0f,
|
||||||
|
"Delay",
|
||||||
|
"Delay in seconds before maximum speed is reached",
|
||||||
|
0.0f,
|
||||||
|
10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI_view2d_edge_pan_operator_init(bContext *C, View2DEdgePanData *vpd, wmOperator *op)
|
||||||
|
{
|
||||||
|
UI_view2d_edge_pan_init(C,
|
||||||
|
vpd,
|
||||||
|
RNA_float_get(op->ptr, "inside_padding"),
|
||||||
|
RNA_float_get(op->ptr, "outside_padding"),
|
||||||
|
RNA_float_get(op->ptr, "speed_ramp"),
|
||||||
|
RNA_float_get(op->ptr, "max_speed"),
|
||||||
|
RNA_float_get(op->ptr, "delay"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
@@ -341,162 +341,37 @@ static void VIEW2D_OT_pan(wmOperatorType *ot)
|
|||||||
* passes through.
|
* passes through.
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
/** Distance from the edge of the region within which to start panning. */
|
|
||||||
#define EDGE_PAN_REGION_PAD (U.widget_unit)
|
|
||||||
/** Speed factor in pixels per second per pixel of distance from edge pan zone beginning. */
|
|
||||||
#define EDGE_PAN_SPEED_PER_PIXEL (25.0f * (float)U.dpi_fac)
|
|
||||||
/** Delay before drag panning in seconds. */
|
|
||||||
#define EDGE_PAN_DELAY 1.0f
|
|
||||||
|
|
||||||
/* set up modal operator and relevant settings */
|
/* set up modal operator and relevant settings */
|
||||||
static int view_edge_pan_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
static int view_edge_pan_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||||
{
|
{
|
||||||
/* Set up customdata. */
|
op->customdata = MEM_callocN(sizeof(View2DEdgePanData), "View2DEdgePanData");
|
||||||
view_pan_init(C, op);
|
View2DEdgePanData *vpd = op->customdata;
|
||||||
|
UI_view2d_edge_pan_operator_init(C, vpd, op);
|
||||||
v2dViewPanData *vpd = op->customdata;
|
|
||||||
|
|
||||||
vpd->edge_pan_start_time_x = 0.0;
|
|
||||||
vpd->edge_pan_start_time_y = 0.0;
|
|
||||||
vpd->edge_pan_last_time = PIL_check_seconds_timer();
|
|
||||||
|
|
||||||
WM_event_add_modal_handler(C, op);
|
WM_event_add_modal_handler(C, op);
|
||||||
|
|
||||||
return (OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH);
|
return (OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the edge pan timers if the mouse isn't in the scroll zone and
|
|
||||||
* start the timers when the mouse enters a scroll zone.
|
|
||||||
*/
|
|
||||||
static void edge_pan_manage_delay_timers(v2dViewPanData *vpd,
|
|
||||||
int pan_dir_x,
|
|
||||||
int pan_dir_y,
|
|
||||||
const double current_time)
|
|
||||||
{
|
|
||||||
if (pan_dir_x == 0) {
|
|
||||||
vpd->edge_pan_start_time_x = 0.0;
|
|
||||||
}
|
|
||||||
else if (vpd->edge_pan_start_time_x == 0.0) {
|
|
||||||
vpd->edge_pan_start_time_x = current_time;
|
|
||||||
}
|
|
||||||
if (pan_dir_y == 0) {
|
|
||||||
vpd->edge_pan_start_time_y = 0.0;
|
|
||||||
}
|
|
||||||
else if (vpd->edge_pan_start_time_y == 0.0) {
|
|
||||||
vpd->edge_pan_start_time_y = current_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to calculate a "fade in" factor for edge panning to make the interaction feel smooth
|
|
||||||
* and more purposeful.
|
|
||||||
*
|
|
||||||
* \note Assumes a domain_min of 0.0f.
|
|
||||||
*/
|
|
||||||
static float smootherstep(const float domain_max, float x)
|
|
||||||
{
|
|
||||||
x = clamp_f(x / domain_max, 0.0, 1.0);
|
|
||||||
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float edge_pan_speed(v2dViewPanData *vpd,
|
|
||||||
int event_loc,
|
|
||||||
bool x_dir,
|
|
||||||
const double current_time)
|
|
||||||
{
|
|
||||||
ARegion *region = vpd->region;
|
|
||||||
|
|
||||||
/* Find the distance from the start of the drag zone. */
|
|
||||||
const int min = (x_dir ? region->winrct.xmin : region->winrct.ymin) + EDGE_PAN_REGION_PAD;
|
|
||||||
const int max = (x_dir ? region->winrct.xmax : region->winrct.ymax) - EDGE_PAN_REGION_PAD;
|
|
||||||
int distance = 0.0;
|
|
||||||
if (event_loc > max) {
|
|
||||||
distance = event_loc - max;
|
|
||||||
}
|
|
||||||
else if (event_loc < min) {
|
|
||||||
distance = min - event_loc;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BLI_assert(!"Calculating speed outside of pan zones");
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply a fade in to the speed based on a start time delay. */
|
|
||||||
const double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y;
|
|
||||||
const float delay_factor = smootherstep(EDGE_PAN_DELAY, (float)(current_time - start_time));
|
|
||||||
|
|
||||||
return distance * EDGE_PAN_SPEED_PER_PIXEL * delay_factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int view_edge_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
static int view_edge_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||||
{
|
{
|
||||||
v2dViewPanData *vpd = op->customdata;
|
View2DEdgePanData *vpd = op->customdata;
|
||||||
ARegion *region = vpd->region;
|
|
||||||
|
|
||||||
if (event->val == KM_RELEASE || event->type == EVT_ESCKEY) {
|
if (event->val == KM_RELEASE || event->type == EVT_ESCKEY) {
|
||||||
view_pan_exit(op);
|
MEM_SAFE_FREE(op->customdata);
|
||||||
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
|
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
|
||||||
}
|
}
|
||||||
/* Only mousemove events matter here, ignore others. */
|
|
||||||
if (event->type != MOUSEMOVE) {
|
UI_view2d_edge_pan_apply_event(C, vpd, event);
|
||||||
return OPERATOR_PASS_THROUGH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This operator is supposed to run together with some drag action.
|
/* This operator is supposed to run together with some drag action.
|
||||||
* On successful handling, always pass events on to other handlers. */
|
* On successful handling, always pass events on to other handlers. */
|
||||||
const int success_retval = OPERATOR_PASS_THROUGH;
|
return OPERATOR_PASS_THROUGH;
|
||||||
|
|
||||||
const int outside_padding = RNA_int_get(op->ptr, "outside_padding") * UI_UNIT_X;
|
|
||||||
rcti padding_rect;
|
|
||||||
if (outside_padding != 0) {
|
|
||||||
padding_rect = region->winrct;
|
|
||||||
BLI_rcti_pad(&padding_rect, outside_padding, outside_padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pan_dir_x = 0;
|
|
||||||
int pan_dir_y = 0;
|
|
||||||
if ((outside_padding == 0) || BLI_rcti_isect_pt(&padding_rect, event->x, event->y)) {
|
|
||||||
/* Find whether the mouse is beyond X and Y edges. */
|
|
||||||
if (event->x > region->winrct.xmax - EDGE_PAN_REGION_PAD) {
|
|
||||||
pan_dir_x = 1;
|
|
||||||
}
|
|
||||||
else if (event->x < region->winrct.xmin + EDGE_PAN_REGION_PAD) {
|
|
||||||
pan_dir_x = -1;
|
|
||||||
}
|
|
||||||
if (event->y > region->winrct.ymax - EDGE_PAN_REGION_PAD) {
|
|
||||||
pan_dir_y = 1;
|
|
||||||
}
|
|
||||||
else if (event->y < region->winrct.ymin + EDGE_PAN_REGION_PAD) {
|
|
||||||
pan_dir_y = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const double current_time = PIL_check_seconds_timer();
|
|
||||||
edge_pan_manage_delay_timers(vpd, pan_dir_x, pan_dir_y, current_time);
|
|
||||||
|
|
||||||
/* Calculate the delta since the last time the operator was called. */
|
|
||||||
const float dtime = (float)(current_time - vpd->edge_pan_last_time);
|
|
||||||
float dx = 0.0f, dy = 0.0f;
|
|
||||||
if (pan_dir_x != 0) {
|
|
||||||
const float speed = edge_pan_speed(vpd, event->x, true, current_time);
|
|
||||||
dx = dtime * speed * (float)pan_dir_x;
|
|
||||||
}
|
|
||||||
if (pan_dir_y != 0) {
|
|
||||||
const float speed = edge_pan_speed(vpd, event->y, false, current_time);
|
|
||||||
dy = dtime * speed * (float)pan_dir_y;
|
|
||||||
}
|
|
||||||
vpd->edge_pan_last_time = current_time;
|
|
||||||
|
|
||||||
/* Pan, clamping inside the regions's total bounds. */
|
|
||||||
view_pan_apply_ex(C, vpd, dx, dy);
|
|
||||||
|
|
||||||
return success_retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void view_edge_pan_cancel(bContext *UNUSED(C), wmOperator *op)
|
static void view_edge_pan_cancel(bContext *UNUSED(C), wmOperator *op)
|
||||||
{
|
{
|
||||||
view_pan_exit(op);
|
MEM_SAFE_FREE(op->customdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
|
static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
|
||||||
@@ -510,26 +385,13 @@ static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
|
|||||||
ot->invoke = view_edge_pan_invoke;
|
ot->invoke = view_edge_pan_invoke;
|
||||||
ot->modal = view_edge_pan_modal;
|
ot->modal = view_edge_pan_modal;
|
||||||
ot->cancel = view_edge_pan_cancel;
|
ot->cancel = view_edge_pan_cancel;
|
||||||
ot->poll = view_pan_poll;
|
ot->poll = UI_view2d_edge_pan_poll;
|
||||||
|
|
||||||
/* operator is modal */
|
/* operator is modal */
|
||||||
ot->flag = OPTYPE_INTERNAL;
|
ot->flag = OPTYPE_INTERNAL;
|
||||||
RNA_def_int(ot->srna,
|
UI_view2d_edge_pan_operator_properties(ot);
|
||||||
"outside_padding",
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
100,
|
|
||||||
"Outside Padding",
|
|
||||||
"Padding around the region in UI units within which panning is activated (0 to "
|
|
||||||
"disable boundary)",
|
|
||||||
0,
|
|
||||||
100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef EDGE_PAN_REGION_PAD
|
|
||||||
#undef EDGE_PAN_SPEED_PER_PIXEL
|
|
||||||
#undef EDGE_PAN_DELAY
|
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "BKE_node.h"
|
#include "BKE_node.h"
|
||||||
#include "UI_interface.h"
|
#include "UI_interface.h"
|
||||||
|
#include "UI_view2d.h"
|
||||||
#include <stddef.h> /* for size_t */
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
/* internal exports only */
|
/* internal exports only */
|
||||||
@@ -64,6 +65,9 @@ typedef struct bNodeLinkDrag {
|
|||||||
/** Temporarily stores the last hovered socket for multi-input socket operator.
|
/** Temporarily stores the last hovered socket for multi-input socket operator.
|
||||||
* Store it to recalculate sorting after it is no longer hovered. */
|
* Store it to recalculate sorting after it is no longer hovered. */
|
||||||
struct bNode *last_node_hovered_while_dragging_a_link;
|
struct bNode *last_node_hovered_while_dragging_a_link;
|
||||||
|
|
||||||
|
/* Data for edge panning */
|
||||||
|
View2DEdgePanData pan_data;
|
||||||
} bNodeLinkDrag;
|
} bNodeLinkDrag;
|
||||||
|
|
||||||
typedef struct SpaceNode_Runtime {
|
typedef struct SpaceNode_Runtime {
|
||||||
|
@@ -973,6 +973,8 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||||||
ARegion *region = CTX_wm_region(C);
|
ARegion *region = CTX_wm_region(C);
|
||||||
float cursor[2];
|
float cursor[2];
|
||||||
|
|
||||||
|
UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
|
||||||
|
|
||||||
UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
|
UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
@@ -1130,6 +1132,8 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||||||
bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);
|
bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);
|
||||||
|
|
||||||
if (nldrag) {
|
if (nldrag) {
|
||||||
|
UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
|
||||||
|
|
||||||
op->customdata = nldrag;
|
op->customdata = nldrag;
|
||||||
BLI_addtail(&snode->runtime->linkdrag, nldrag);
|
BLI_addtail(&snode->runtime->linkdrag, nldrag);
|
||||||
|
|
||||||
@@ -1193,6 +1197,13 @@ void NODE_OT_link(wmOperatorType *ot)
|
|||||||
UI_PRECISION_FLOAT_MAX);
|
UI_PRECISION_FLOAT_MAX);
|
||||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||||
|
|
||||||
|
UI_view2d_edge_pan_operator_properties_ex(ot,
|
||||||
|
NODE_EDGE_PAN_INSIDE_PAD,
|
||||||
|
NODE_EDGE_PAN_OUTSIDE_PAD,
|
||||||
|
NODE_EDGE_PAN_SPEED_RAMP,
|
||||||
|
NODE_EDGE_PAN_MAX_SPEED,
|
||||||
|
NODE_EDGE_PAN_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@@ -1370,7 +1370,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
|
|||||||
wmOperatorType *ot = WM_operatortype_find("VIEW2D_OT_edge_pan", true);
|
wmOperatorType *ot = WM_operatortype_find("VIEW2D_OT_edge_pan", true);
|
||||||
PointerRNA op_ptr;
|
PointerRNA op_ptr;
|
||||||
WM_operator_properties_create_ptr(&op_ptr, ot);
|
WM_operator_properties_create_ptr(&op_ptr, ot);
|
||||||
RNA_int_set(&op_ptr, "outside_padding", OUTLINER_DRAG_SCOLL_OUTSIDE_PAD);
|
RNA_float_set(&op_ptr, "outside_padding", OUTLINER_DRAG_SCOLL_OUTSIDE_PAD);
|
||||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_ptr);
|
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_ptr);
|
||||||
WM_operator_properties_free(&op_ptr);
|
WM_operator_properties_free(&op_ptr);
|
||||||
}
|
}
|
||||||
|
@@ -149,6 +149,9 @@ typedef enum {
|
|||||||
T_AUTOMERGE = 1 << 20,
|
T_AUTOMERGE = 1 << 20,
|
||||||
/** Runs auto-merge & splits. */
|
/** Runs auto-merge & splits. */
|
||||||
T_AUTOSPLIT = 1 << 21,
|
T_AUTOSPLIT = 1 << 21,
|
||||||
|
|
||||||
|
/** No cursor wrapping on region bounds */
|
||||||
|
T_NO_CURSOR_WRAP = 1 << 23,
|
||||||
} eTFlag;
|
} eTFlag;
|
||||||
|
|
||||||
/** #TransInfo.modifiers */
|
/** #TransInfo.modifiers */
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
|
#include "BLI_rect.h"
|
||||||
|
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_node.h"
|
#include "BKE_node.h"
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
#include "ED_node.h"
|
#include "ED_node.h"
|
||||||
|
|
||||||
#include "UI_interface.h"
|
#include "UI_interface.h"
|
||||||
|
#include "UI_view2d.h"
|
||||||
|
|
||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
#include "transform_convert.h"
|
#include "transform_convert.h"
|
||||||
@@ -44,6 +46,12 @@
|
|||||||
/** \name Node Transform Creation
|
/** \name Node Transform Creation
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
|
typedef struct NodeTransCustomData {
|
||||||
|
/* Initial rect of the view2d, used for computing offset during edge panning */
|
||||||
|
rctf initial_v2d_cur;
|
||||||
|
View2DEdgePanData edge_pan;
|
||||||
|
} NodeTransCustomData;
|
||||||
|
|
||||||
/* transcribe given node into TransData2D for Transforming */
|
/* transcribe given node into TransData2D for Transforming */
|
||||||
static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
|
static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
|
||||||
{
|
{
|
||||||
@@ -107,6 +115,24 @@ void createTransNodeData(TransInfo *t)
|
|||||||
const float dpi_fac = UI_DPI_FAC;
|
const float dpi_fac = UI_DPI_FAC;
|
||||||
SpaceNode *snode = t->area->spacedata.first;
|
SpaceNode *snode = t->area->spacedata.first;
|
||||||
|
|
||||||
|
if (t->mode == TFM_TRANSLATION) {
|
||||||
|
/* Disable cursor wrapping in the node editor for edge pan */
|
||||||
|
t->flag |= T_NO_CURSOR_WRAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom data to enable edge panning during the node transform */
|
||||||
|
NodeTransCustomData *customdata = MEM_callocN(sizeof(*customdata), __func__);
|
||||||
|
UI_view2d_edge_pan_init(t->context,
|
||||||
|
&customdata->edge_pan,
|
||||||
|
NODE_EDGE_PAN_INSIDE_PAD,
|
||||||
|
NODE_EDGE_PAN_OUTSIDE_PAD,
|
||||||
|
NODE_EDGE_PAN_SPEED_RAMP,
|
||||||
|
NODE_EDGE_PAN_MAX_SPEED,
|
||||||
|
NODE_EDGE_PAN_DELAY);
|
||||||
|
customdata->initial_v2d_cur = t->region->v2d.cur;
|
||||||
|
t->custom.type.data = customdata;
|
||||||
|
t->custom.type.use_free = true;
|
||||||
|
|
||||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||||
|
|
||||||
tc->data_len = 0;
|
tc->data_len = 0;
|
||||||
@@ -150,6 +176,19 @@ void flushTransNodes(TransInfo *t)
|
|||||||
{
|
{
|
||||||
const float dpi_fac = UI_DPI_FAC;
|
const float dpi_fac = UI_DPI_FAC;
|
||||||
|
|
||||||
|
NodeTransCustomData *customdata = (NodeTransCustomData *)t->custom.type.data;
|
||||||
|
|
||||||
|
if (t->mode == TFM_TRANSLATION) {
|
||||||
|
/* Edge panning functions expect window coordinates, mval is relative to region */
|
||||||
|
const float x = t->region->winrct.xmin + t->mval[0];
|
||||||
|
const float y = t->region->winrct.ymin + t->mval[1];
|
||||||
|
UI_view2d_edge_pan_apply(t->context, &customdata->edge_pan, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initial and current view2D rects for additional transform due to view panning and zooming */
|
||||||
|
const rctf *rect_src = &customdata->initial_v2d_cur;
|
||||||
|
const rctf *rect_dst = &t->region->v2d.cur;
|
||||||
|
|
||||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||||
applyGridAbsolute(t);
|
applyGridAbsolute(t);
|
||||||
|
|
||||||
@@ -159,23 +198,28 @@ void flushTransNodes(TransInfo *t)
|
|||||||
TransData2D *td2d = &tc->data_2d[i];
|
TransData2D *td2d = &tc->data_2d[i];
|
||||||
bNode *node = td->extra;
|
bNode *node = td->extra;
|
||||||
|
|
||||||
/* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
|
float loc[2];
|
||||||
|
copy_v2_v2(loc, td2d->loc);
|
||||||
|
|
||||||
|
/* additional offset due to change in view2D rect */
|
||||||
|
BLI_rctf_transform_pt_v(rect_dst, rect_src, loc, loc);
|
||||||
|
|
||||||
#ifdef USE_NODE_CENTER
|
#ifdef USE_NODE_CENTER
|
||||||
float locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
|
loc[0] -= 0.5f * BLI_rctf_size_x(&node->totr);
|
||||||
float locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
|
loc[1] += 0.5f * BLI_rctf_size_y(&node->totr);
|
||||||
#else
|
|
||||||
float locx = td2d->loc[0] / dpi_fac;
|
|
||||||
float locy = td2d->loc[1] / dpi_fac;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
|
||||||
|
loc[0] /= dpi_fac;
|
||||||
|
loc[1] /= dpi_fac;
|
||||||
|
|
||||||
/* account for parents (nested nodes) */
|
/* account for parents (nested nodes) */
|
||||||
if (node->parent) {
|
if (node->parent) {
|
||||||
nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
|
nodeFromView(node->parent, loc[0], loc[1], &loc[0], &loc[1]);
|
||||||
}
|
|
||||||
else {
|
|
||||||
node->locx = locx;
|
|
||||||
node->locy = locy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node->locx = loc[0];
|
||||||
|
node->locy = loc[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle intersection with noodles */
|
/* handle intersection with noodles */
|
||||||
|
@@ -519,10 +519,11 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||||||
/* add temp handler */
|
/* add temp handler */
|
||||||
WM_event_add_modal_handler(C, op);
|
WM_event_add_modal_handler(C, op);
|
||||||
|
|
||||||
op->flag |= OP_IS_MODAL_GRAB_CURSOR; /* XXX maybe we want this with the gizmo only? */
|
|
||||||
|
|
||||||
/* Use when modal input has some transformation to begin with. */
|
/* Use when modal input has some transformation to begin with. */
|
||||||
TransInfo *t = op->customdata;
|
TransInfo *t = op->customdata;
|
||||||
|
if ((t->flag & T_NO_CURSOR_WRAP) == 0) {
|
||||||
|
op->flag |= OP_IS_MODAL_GRAB_CURSOR; /* XXX maybe we want this with the gizmo only? */
|
||||||
|
}
|
||||||
if (UNLIKELY(!is_zero_v4(t->values_modal_offset))) {
|
if (UNLIKELY(!is_zero_v4(t->values_modal_offset))) {
|
||||||
transformApply(C, t);
|
transformApply(C, t);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user