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/interface/interface_panel.c34
-rw-r--r--source/blender/editors/interface/view2d_ops.c185
2 files changed, 209 insertions, 10 deletions
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 54f60a05cfd..33f600f30a1 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -107,6 +107,7 @@ typedef struct uiHandlePanelData {
int startx, starty;
int startofsx, startofsy;
int startsizex, startsizey;
+ float start_cur_xmin, start_cur_ymin;
} uiHandlePanelData;
typedef struct PanelSort {
@@ -1731,21 +1732,22 @@ static void check_panel_overlap(ARegion *region, Panel *panel)
/************************ panel dragging ****************************/
+#define DRAG_REGION_PAD (PNL_HEADER * 0.5)
static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
{
uiHandlePanelData *data = panel->activedata;
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- short align = panel_aligned(area, region), dx = 0, dy = 0;
+ short align = panel_aligned(area, region);
- /* first clip for window, no dragging outside */
- if (!BLI_rcti_isect_pt_v(&region->winrct, &event->x)) {
- return;
- }
+ /* Keep the drag position in the region with a small pad to keep the panel visible. */
+ int x = clamp_i(event->x, region->winrct.xmin, region->winrct.xmax + DRAG_REGION_PAD);
+ int y = clamp_i(event->y, region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD);
- dx = (event->x - data->startx);
- dy = (event->y - data->starty);
+ float dx = (float)(x - data->startx);
+ float dy = (float)(y - data->starty);
+ /* Adjust for region zoom. */
dx *= (float)BLI_rctf_size_x(&region->v2d.cur) / (float)BLI_rcti_size_x(&region->winrct);
dy *= (float)BLI_rctf_size_y(&region->v2d.cur) / (float)BLI_rcti_size_y(&region->winrct);
@@ -1763,17 +1765,21 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
/* reset the panel snapping, to allow dragging away from snapped edges */
panel->snap = PNL_SNAP_NONE;
- panel->ofsx = data->startofsx + dx;
- panel->ofsy = data->startofsy + dy;
+ /* Add the movement of the view due to edge scrolling while dragging. */
+ dx += ((float)region->v2d.cur.xmin - data->start_cur_xmin);
+ dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin);
+ panel->ofsx = data->startofsx + round_fl_to_int(dx);
+ panel->ofsy = data->startofsy + round_fl_to_int(dy);
check_panel_overlap(region, panel);
if (align) {
- uiAlignPanelStep(area, region, 0.2, true);
+ uiAlignPanelStep(area, region, 0.2f, true);
}
}
ED_region_tag_redraw(region);
}
+#undef DRAG_REGION_PAD
/******************* region level panel interaction *****************/
@@ -2967,6 +2973,12 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL);
}
+ /* Initiate edge panning during drags so we can move beyond the initial region view. */
+ if (state == PANEL_STATE_DRAG) {
+ wmOperatorType *ot = WM_operatortype_find("VIEW2D_OT_edge_pan", true);
+ ui_handle_afterfunc_add_operator(ot, WM_OP_INVOKE_DEFAULT, true);
+ }
+
data->state = state;
data->startx = win->eventstate->x;
data->starty = win->eventstate->y;
@@ -2974,6 +2986,8 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
data->startofsy = panel->ofsy;
data->startsizex = panel->sizex;
data->startsizey = panel->sizey;
+ data->start_cur_xmin = region->v2d.cur.xmin;
+ data->start_cur_ymin = region->v2d.cur.ymin;
data->starttime = PIL_check_seconds_timer();
/* Remember drag drop state even when animating to the aligned position after dragging. */
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 5b1e5f746ef..ff35b25e488 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -100,6 +100,10 @@ typedef struct v2dViewPanData {
/** for MMB in scrollers (old feature in past, but now not that useful) */
short in_scroller;
+
+ /* View2D Edge Panning */
+ double edge_pan_last_time;
+ double edge_pan_start_time_x, edge_pan_start_time_y;
} v2dViewPanData;
/* initialize panning customdata */
@@ -357,6 +361,186 @@ static void VIEW2D_OT_pan(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name View Edge Pan Operator (modal)
+ *
+ * Scroll the region if the mouse is dragged to an edge. "Invisible" operator that always
+ * 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. */
+ if (!view_pan_init(C, op)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ 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);
+
+ 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. */
+ int min = x_dir ? region->winrct.xmin : region->winrct.ymin + EDGE_PAN_REGION_PAD;
+ 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. */
+ double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y;
+ 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;
+
+ if (event->val == KM_RELEASE || event->type == EVT_ESCKEY) {
+ view_pan_exit(op);
+ return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
+ }
+ /* Only mousemove events matter here, ignore others. */
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ /* 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;
+
+ /* Find whether the mouse is beyond X and Y edges. */
+ int pan_dir_x = 0;
+ int pan_dir_y = 0;
+ 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. */
+ float dtime = (float)(current_time - vpd->edge_pan_last_time);
+ float dx = 0.0f, dy = 0.0f;
+ if (pan_dir_x != 0) {
+ float speed = edge_pan_speed(vpd, event->x, true, current_time);
+ dx = dtime * speed * (float)pan_dir_x;
+ }
+ if (pan_dir_y != 0) {
+ 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)
+{
+ view_pan_exit(op);
+}
+
+static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Edge Pan";
+ ot->description = "Pan the view when the mouse is held at an edge";
+ ot->idname = "VIEW2D_OT_edge_pan";
+
+ /* api callbacks */
+ ot->invoke = view_edge_pan_invoke;
+ ot->modal = view_edge_pan_modal;
+ ot->cancel = view_edge_pan_cancel;
+
+ /* operator is modal */
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+#undef EDGE_PAN_REGION_PAD
+#undef EDGE_PAN_SPEED_PER_PIXEL
+#undef EDGE_PAN_DELAY
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name View Pan Operator (single step)
* \{ */
@@ -2246,6 +2430,7 @@ static void VIEW2D_OT_reset(wmOperatorType *ot)
void ED_operatortypes_view2d(void)
{
WM_operatortype_append(VIEW2D_OT_pan);
+ WM_operatortype_append(VIEW2D_OT_edge_pan);
WM_operatortype_append(VIEW2D_OT_scroll_left);
WM_operatortype_append(VIEW2D_OT_scroll_right);