Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/editors/include/ED_node.h5
-rw-r--r--source/blender/editors/include/UI_view2d.h75
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/view2d_edge_pan.c345
-rw-r--r--source/blender/editors/interface/view2d_ops.c160
-rw-r--r--source/blender/editors/space_node/node_intern.h4
-rw-r--r--source/blender/editors/space_node/node_relationships.cc11
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c2
-rw-r--r--source/blender/editors/transform/transform.h3
-rw-r--r--source/blender/editors/transform/transform_convert_node.c66
-rw-r--r--source/blender/editors/transform/transform_ops.c5
11 files changed, 514 insertions, 163 deletions
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 67a50b83bd6..ba65840dc99 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -49,6 +49,11 @@ typedef enum {
} NodeBorder;
#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 */
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 64f881052a1..999f42efe65 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -105,8 +105,12 @@ struct ScrArea;
struct bContext;
struct bScreen;
struct rctf;
+struct rcti;
+struct wmEvent;
struct wmGizmoGroupType;
struct wmKeyConfig;
+struct wmOperator;
+struct wmOperatorType;
typedef struct View2DScrollers View2DScrollers;
@@ -287,6 +291,77 @@ void UI_view2d_smooth_view(struct bContext *C,
/* Caller passes in own 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
}
#endif
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 421019bebb8..5011a50ed73 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -75,6 +75,7 @@ set(SRC
resources.c
view2d.c
view2d_draw.c
+ view2d_edge_pan.c
view2d_gizmo_navigate.c
view2d_ops.c
diff --git a/source/blender/editors/interface/view2d_edge_pan.c b/source/blender/editors/interface/view2d_edge_pan.c
new file mode 100644
index 00000000000..38364a687fd
--- /dev/null
+++ b/source/blender/editors/interface/view2d_edge_pan.c
@@ -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 = &region->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 edge panning operators. */
+ 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"));
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 40c510af7e5..7ad28cd6069 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -341,162 +341,37 @@ static void VIEW2D_OT_pan(wmOperatorType *ot)
* 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 */
static int view_edge_pan_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- /* Set up customdata. */
- view_pan_init(C, 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();
+ op->customdata = MEM_callocN(sizeof(View2DEdgePanData), "View2DEdgePanData");
+ View2DEdgePanData *vpd = op->customdata;
+ UI_view2d_edge_pan_operator_init(C, vpd, op);
WM_event_add_modal_handler(C, op);
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)
{
- v2dViewPanData *vpd = op->customdata;
- ARegion *region = vpd->region;
+ View2DEdgePanData *vpd = op->customdata;
if (event->val == KM_RELEASE || event->type == EVT_ESCKEY) {
- view_pan_exit(op);
+ MEM_SAFE_FREE(op->customdata);
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
- /* Only mousemove events matter here, ignore others. */
- if (event->type != MOUSEMOVE) {
- return OPERATOR_PASS_THROUGH;
- }
+
+ UI_view2d_edge_pan_apply_event(C, vpd, event);
/* This operator is supposed to run together with some drag action.
* On successful handling, always pass events on to other handlers. */
- const int success_retval = 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;
+ return OPERATOR_PASS_THROUGH;
}
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)
@@ -510,26 +385,13 @@ static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
ot->invoke = view_edge_pan_invoke;
ot->modal = view_edge_pan_modal;
ot->cancel = view_edge_pan_cancel;
- ot->poll = view_pan_poll;
+ ot->poll = UI_view2d_edge_pan_poll;
/* operator is modal */
ot->flag = OPTYPE_INTERNAL;
- RNA_def_int(ot->srna,
- "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);
+ UI_view2d_edge_pan_operator_properties(ot);
}
-#undef EDGE_PAN_REGION_PAD
-#undef EDGE_PAN_SPEED_PER_PIXEL
-#undef EDGE_PAN_DELAY
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 2fcc59cde0b..8dfc43333e3 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -25,6 +25,7 @@
#include "BKE_node.h"
#include "UI_interface.h"
+#include "UI_view2d.h"
#include <stddef.h> /* for size_t */
/* internal exports only */
@@ -64,6 +65,9 @@ typedef struct bNodeLinkDrag {
/** Temporarily stores the last hovered socket for multi-input socket operator.
* Store it to recalculate sorting after it is no longer hovered. */
struct bNode *last_node_hovered_while_dragging_a_link;
+
+ /* Data for edge panning */
+ View2DEdgePanData pan_data;
} bNodeLinkDrag;
typedef struct SpaceNode_Runtime {
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 57dc0b6fef2..a1b8e4e3395 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -973,6 +973,8 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
float cursor[2];
+ UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
+
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
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);
if (nldrag) {
+ UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
+
op->customdata = nldrag;
BLI_addtail(&snode->runtime->linkdrag, nldrag);
@@ -1193,6 +1197,13 @@ void NODE_OT_link(wmOperatorType *ot)
UI_PRECISION_FLOAT_MAX);
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);
}
/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 7d889eed612..8021b45ac77 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -1365,7 +1365,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
wmOperatorType *ot = WM_operatortype_find("VIEW2D_OT_edge_pan", true);
PointerRNA op_ptr;
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_properties_free(&op_ptr);
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index f0ced665679..2b26ef3b3e4 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -149,6 +149,9 @@ typedef enum {
T_AUTOMERGE = 1 << 20,
/** Runs auto-merge & splits. */
T_AUTOSPLIT = 1 << 21,
+
+ /** No cursor wrapping on region bounds */
+ T_NO_CURSOR_WRAP = 1 << 23,
} eTFlag;
/** #TransInfo.modifiers */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index 12c4d0816ae..9d2d3713bf0 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -27,6 +27,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rect.h"
#include "BKE_context.h"
#include "BKE_node.h"
@@ -35,6 +36,7 @@
#include "ED_node.h"
#include "UI_interface.h"
+#include "UI_view2d.h"
#include "transform.h"
#include "transform_convert.h"
@@ -44,6 +46,12 @@
/** \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 */
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;
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);
tc->data_len = 0;
@@ -150,6 +176,19 @@ void flushTransNodes(TransInfo *t)
{
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) {
applyGridAbsolute(t);
@@ -159,23 +198,28 @@ void flushTransNodes(TransInfo *t)
TransData2D *td2d = &tc->data_2d[i];
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
- float locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
- float locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
-#else
- float locx = td2d->loc[0] / dpi_fac;
- float locy = td2d->loc[1] / dpi_fac;
+ loc[0] -= 0.5f * BLI_rctf_size_x(&node->totr);
+ loc[1] += 0.5f * BLI_rctf_size_y(&node->totr);
#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) */
if (node->parent) {
- nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
- }
- else {
- node->locx = locx;
- node->locy = locy;
+ nodeFromView(node->parent, loc[0], loc[1], &loc[0], &loc[1]);
}
+
+ node->locx = loc[0];
+ node->locy = loc[1];
}
/* handle intersection with noodles */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 9b5f15a2574..d7bcf8dcf90 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -519,10 +519,11 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* add temp handler */
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. */
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))) {
transformApply(C, t);
}