diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9029653ba14..75733e8d6d1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5078,6 +5078,7 @@ static void do_versions_windowmanager_2_50(bScreen *screen) ar->v2d.scroll &= ~V2D_SCROLL_LEFT; ar->v2d.scroll |= V2D_SCROLL_RIGHT; ar->v2d.align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_POS_Y); + ar->v2d.keepzoom |= (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y); } break; case SPACE_TIME: diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 36028c64ee1..a8640bcc1d2 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -33,7 +33,7 @@ #define UI_VIEW2D_H /* ------------------------------------------ */ -/* Settings: */ +/* Settings and Defines: */ /* generic value to use when coordinate lies out of view when converting */ #define V2D_IS_CLIPPED 12000 @@ -41,6 +41,7 @@ /* 'dummy' argument to pass when argument is irrelevant */ #define V2D_ARG_DUMMY -1 + /* grid-units (for drawing time) */ #define V2D_UNIT_SECONDS 0 #define V2D_UNIT_FRAMES 1 diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 300c5f710f6..836228eb184 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -732,7 +732,10 @@ void UI_view2d_grid_free(View2DGrid *grid) /* *********************************************************************** */ /* Scrollbars */ -/* View2DScrollers is typedef'd in UI_view2d.h */ +/* View2DScrollers is typedef'd in UI_view2d.h + * WARNING: the start of this struct must not change, as view2d_ops.c uses this too. + * For now, we don't need to have a separate (internal) header for structs like this... + */ struct View2DScrollers { /* focus bubbles */ int vert_min, vert_max; /* vertical scrollbar */ @@ -769,11 +772,11 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short scrollsize= hor.xmax - hor.xmin; fac= (v2d->cur.xmin- v2d->tot.xmin) / totsize; - //if (fac < 0.0f) fac= 0.0f; + if (fac < 0.0f) fac= 0.0f; scrollers->hor_min= hor.xmin + (fac * scrollsize); fac= (v2d->cur.xmax - v2d->tot.xmin) / totsize; - //if (fac > 1.0f) fac= 1.0f; + if (fac > 1.0f) fac= 1.0f; scrollers->hor_max= hor.xmin + (fac * scrollsize); if (scrollers->hor_min > scrollers->hor_max) @@ -787,11 +790,11 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short scrollsize= vert.ymax - vert.ymin; fac= (v2d->cur.ymin- v2d->tot.ymin) / totsize; - //if (fac < 0.0f) fac= 0.0f; + if (fac < 0.0f) fac= 0.0f; scrollers->vert_min= vert.ymin + (fac * scrollsize); fac= (v2d->cur.ymax - v2d->tot.ymin) / totsize; - //if (fac > 1.0f) fac= 1.0f; + if (fac > 1.0f) fac= 1.0f; scrollers->vert_max= vert.ymin + (fac * scrollsize); if (scrollers->vert_min > scrollers->vert_max) @@ -806,11 +809,15 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short scrollers->yclamp= yclamp; scrollers->yunits= yunits; - /* calculate grid */ - if (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) - scrollers->grid= UI_view2d_grid_calc(C, v2d, xunits, xclamp, (hor.xmax - hor.xmin), (vert.ymax - vert.ymin)); - else if (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) - scrollers->grid= UI_view2d_grid_calc(C, v2d, yunits, yclamp, (hor.xmax - hor.xmin), (vert.ymax - vert.ymin)); + /* calculate grid only if clamping + units are valid arguments */ + if ( !((xclamp == V2D_ARG_DUMMY) && (xunits == V2D_ARG_DUMMY) && (yclamp == V2D_ARG_DUMMY) && (yunits == V2D_ARG_DUMMY)) ) { + /* if both axes show scale, give priority to horizontal.. */ + // FIXME: this doesn't do justice to the vertical scroller calculations... + if (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) + scrollers->grid= UI_view2d_grid_calc(C, v2d, xunits, xclamp, (hor.xmax - hor.xmin), (vert.ymax - vert.ymin)); + else if (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) + scrollers->grid= UI_view2d_grid_calc(C, v2d, yunits, yclamp, (hor.xmax - hor.xmin), (vert.ymax - vert.ymin)); + } } /* return scrollers */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 44f1655af95..68541fc9690 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -98,7 +98,6 @@ static short mouse_in_v2d_scrollers (const bContext *C, View2D *v2d, int x, int /* temp customdata for operator */ typedef struct v2dViewPanData { - ARegion *region; /* region we're operating in */ View2D *v2d; /* view2d we're operating in */ float facx, facy; /* amount to move view relative to zoom */ @@ -107,7 +106,7 @@ typedef struct v2dViewPanData { int startx, starty; /* mouse x/y values in window when operator was initiated */ int lastx, lasty; /* previous x/y values of mouse in window */ - short in_scroller; /* activated in scrollbar */ + short in_scroller; /* for MMB in scrollers (old feature in past, but now not that useful) */ } v2dViewPanData; /* initialise panning customdata */ @@ -121,13 +120,13 @@ static int view_pan_init(bContext *C, wmOperator *op) /* regions now have v2d-data by default, so check for region */ if (C->region == NULL) return 0; + ar= C->region; /* set custom-data for operator */ vpd= MEM_callocN(sizeof(v2dViewPanData), "v2dViewPanData"); op->customdata= vpd; /* set pointers to owners */ - vpd->region= ar= C->region; vpd->v2d= v2d= &ar->v2d; /* calculate translation factor - based on size of view */ @@ -160,6 +159,9 @@ static void view_pan_apply(bContext *C, wmOperator *op) v2d->cur.ymax += dy; } + /* validate that view is in valid configuration after this operation */ + UI_view2d_status_enforce(v2d); + /* request updates to be done... */ WM_event_add_notifier(C, WM_NOTE_AREA_REDRAW, 0, NULL); /* XXX: add WM_NOTE_TIME_CHANGED? */ @@ -299,6 +301,9 @@ void ED_View2D_OT_view_pan(wmOperatorType *ot) ot->invoke= view_pan_invoke; ot->modal= view_pan_modal; + /* operator is repeatable */ + ot->flag= OPTYPE_REGISTER; + /* rna - must keep these in sync with the other operators */ prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE); prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE); @@ -335,6 +340,9 @@ void ED_View2D_OT_view_scrollright(wmOperatorType *ot) /* api callbacks */ ot->exec= view_scrollright_exec; + /* operator is repeatable */ + ot->flag= OPTYPE_REGISTER; + /* rna - must keep these in sync with the other operators */ prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE); prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE); @@ -371,6 +379,9 @@ void ED_View2D_OT_view_scrollleft(wmOperatorType *ot) /* api callbacks */ ot->exec= view_scrollleft_exec; + /* operator is repeatable */ + ot->flag= OPTYPE_REGISTER; + /* rna - must keep these in sync with the other operators */ prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE); prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE); @@ -405,6 +416,9 @@ void ED_View2D_OT_view_scrolldown(wmOperatorType *ot) /* api callbacks */ ot->exec= view_scrolldown_exec; + /* operator is repeatable */ + ot->flag= OPTYPE_REGISTER; + /* rna - must keep these in sync with the other operators */ prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE); prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE); @@ -441,60 +455,34 @@ void ED_View2D_OT_view_scrollup(wmOperatorType *ot) /* api callbacks */ ot->exec= view_scrollup_exec; + /* operator is repeatable */ + ot->flag= OPTYPE_REGISTER; + /* rna - must keep these in sync with the other operators */ prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE); prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE); } /* ********************************************************* */ -/* VIEW ZOOMING OPERATOR */ +/* SINGLE-STEP VIEW ZOOMING OPERATOR */ /* This group of operators come in several forms: - * 1) Modal 'dragging' with MMB - where movement of mouse dictates amount to zoom view by - * 2) Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount + * 1) Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount + * 2) Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y) // XXX this could be implemented... * 3) Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount * * In order to make sure this works, each operator must define the following RNA-Operator Props: - * zoomfacx, zoomfacy - sometimes it's still useful to have non-uniform scaling + * zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling. + * It is safe to scale by 0, as these factors are used to determine + * amount to enlarge 'cur' by */ -/* ------------------ Shared 'core' stuff ---------------------- */ - -/* temp customdata for operator */ -typedef struct v2dViewZoomData { - ARegion *region; /* region we're operating in */ - View2D *v2d; /* view2d we're operating in */ - - int startx, starty; /* mouse x/y values in window when operator was initiated */ - int lastx, lasty; /* previous x/y values of mouse in window */ -} v2dViewZoomData; +/* ------------------ 'Shared' stuff ------------------------ */ -/* initialise zooming customdata */ -static int view_zoom_init(bContext *C, wmOperator *op) -{ - v2dViewZoomData *vzd; - ARegion *ar; - - /* regions now have v2d-data by default, so check for region */ - if (C->region == NULL) - return 0; - - /* set custom-data for operator */ - vzd= MEM_callocN(sizeof(v2dViewZoomData), "v2dViewZoomData"); - op->customdata= vzd; - - /* set pointers to owners */ - vzd->region= ar= C->region; - vzd->v2d= &ar->v2d; - - return 1; -} - /* apply transform to view (i.e. adjust 'cur' rect) */ static void view_zoom_apply(bContext *C, wmOperator *op) { - v2dViewZoomData *vzd= op->customdata; - View2D *v2d= vzd->v2d; + View2D *v2d= &C->region->v2d; float dx, dy; /* calculate amount to move view by */ @@ -502,7 +490,6 @@ static void view_zoom_apply(bContext *C, wmOperator *op) dy= (v2d->cur.ymax - v2d->cur.ymin) * (float)RNA_float_get(op->ptr, "zoomfacy"); /* only move view on an axis if change is allowed */ - // FIXME: this still only allows for zooming around 'center' of view... userdefined center is more useful! if ((v2d->keepofs & V2D_LOCKOFS_X)==0) { v2d->cur.xmin += dx; v2d->cur.xmax -= dx; @@ -512,37 +499,29 @@ static void view_zoom_apply(bContext *C, wmOperator *op) v2d->cur.ymax -= dy; } + /* validate that view is in valid configuration after this operation */ + UI_view2d_status_enforce(v2d); + /* request updates to be done... */ WM_event_add_notifier(C, WM_NOTE_AREA_REDRAW, 0, NULL); /* XXX: add WM_NOTE_TIME_CHANGED? */ } -/* cleanup temp customdata */ -static void view_zoom_exit(bContext *C, wmOperator *op) -{ - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata= NULL; - } -} +/* --------------- Individual Operators ------------------- */ -/* ------------------ Single-step non-modal zoom (2 and 3) ---------------------- */ - -/* this operator only needs this single callback, where it callsthe view_zoom_*() methods */ -// FIXME: this should be invoke (with event pointer), so that we can do non-modal but require pointer for centerpoint +/* this operator only needs this single callback, where it calls the view_zoom_*() methods */ static int view_zoomin_exec(bContext *C, wmOperator *op) { - /* initialise default settings (and validate if ok to run) */ - if (!view_zoom_init(C, op)) + /* check that there's an active region, as View2D data resides there */ + if (C->region == NULL) return OPERATOR_CANCELLED; /* set RNA-Props - zooming in by uniform factor */ - RNA_float_set(op->ptr, "zoomfacx", 0.0375); - RNA_float_set(op->ptr, "zoomfacy", 0.0375); + RNA_float_set(op->ptr, "zoomfacx", 0.0375f); + RNA_float_set(op->ptr, "zoomfacy", 0.0375f); /* apply movement, then we're done */ view_zoom_apply(C, op); - view_zoom_exit(C, op); return OPERATOR_FINISHED; } @@ -558,6 +537,9 @@ void ED_View2D_OT_view_zoomin(wmOperatorType *ot) /* api callbacks */ ot->exec= view_zoomin_exec; + /* operator is repeatable */ + ot->flag= OPTYPE_REGISTER; + /* rna - must keep these in sync with the other operators */ prop= RNA_def_property(ot->srna, "zoomfacx", PROP_FLOAT, PROP_NONE); prop= RNA_def_property(ot->srna, "zoomfacy", PROP_FLOAT, PROP_NONE); @@ -566,20 +548,18 @@ void ED_View2D_OT_view_zoomin(wmOperatorType *ot) /* this operator only needs this single callback, where it callsthe view_zoom_*() methods */ -// FIXME: this should be invoke (with event pointer), so that we can do non-modal but require pointer for centerpoint static int view_zoomout_exec(bContext *C, wmOperator *op) { - /* initialise default settings (and validate if ok to run) */ - if (!view_zoom_init(C, op)) + /* check that there's an active region, as View2D data resides there */ + if (C->region == NULL) return OPERATOR_CANCELLED; /* set RNA-Props - zooming in by uniform factor */ - RNA_float_set(op->ptr, "zoomfacx", -0.0375); - RNA_float_set(op->ptr, "zoomfacy", -0.0375); + RNA_float_set(op->ptr, "zoomfacx", -0.0375f); + RNA_float_set(op->ptr, "zoomfacy", -0.0375f); /* apply movement, then we're done */ view_zoom_apply(C, op); - view_zoom_exit(C, op); return OPERATOR_FINISHED; } @@ -595,6 +575,9 @@ void ED_View2D_OT_view_zoomout(wmOperatorType *ot) /* api callbacks */ ot->exec= view_zoomout_exec; + /* operator is repeatable */ + ot->flag= OPTYPE_REGISTER; + /* rna - must keep these in sync with the other operators */ prop= RNA_def_property(ot->srna, "zoomfacx", PROP_FLOAT, PROP_NONE); prop= RNA_def_property(ot->srna, "zoomfacy", PROP_FLOAT, PROP_NONE); @@ -603,6 +586,306 @@ void ED_View2D_OT_view_zoomout(wmOperatorType *ot) /* ********************************************************* */ /* Scrollers */ +/* customdata for scroller-invoke data */ +typedef struct v2dScrollerMove { + View2D *v2d; /* View2D data that this operation affects */ + + short scroller; /* scroller that mouse is in ('h' or 'v') */ + short zone; /* -1 is min zoomer, 0 is bar, 1 is max zoomer */ // XXX find some way to provide visual feedback of this (active colour?) + + float fac; /* view adjustment factor, based on size of region */ + float delta; /* amount moved by mouse on axis of interest */ + + int lastx, lasty; /* previous mouse coordinates (in screen coordinates) for determining movement */ +} v2dScrollerMove; + + +/* View2DScrollers is typedef'd in UI_view2d.h + * This is a CUT DOWN VERSION of the 'real' version, which is defined in view2d.c, as we only need focus bubble info + * WARNING: the start of this struct must not change, so that it stays in sync with the 'real' version + * For now, we don't need to have a separate (internal) header for structs like this... + */ +struct View2DScrollers { + /* focus bubbles */ + int vert_min, vert_max; /* vertical scrollbar */ + int hor_min, hor_max; /* horizontal scrollbar */ +}; + +/* quick enum for vsm->zone (scroller handles) */ +enum { + SCROLLHANDLE_MIN= -1, + SCROLLHANDLE_BAR, + SCROLLHANDLE_MAX +} eV2DScrollerHandle_Zone; + +/* ------------------------ */ + +/* check if mouse is within scroller handle + * - mouse = relevant mouse coordinate in region space + * - sc_min, sc_max = extents of scroller + * - sh_min, sh_max = positions of scroller handles + */ +static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max) +{ + short in_min, in_max; + + /* firstly, check if 'bubble' fills entire scroller */ + // XXX this isn't so good for anim-editors... + if ((sh_min <= sc_min) && (sh_max >= sc_max)) { + /* use midpoint to determine which handle to use (favour 'max' handle) */ + if (mouse >= ((sc_max + sc_min) / 2)) + return SCROLLHANDLE_MAX; + else + return SCROLLHANDLE_MIN; + } + + /* check if mouse is in or past either handle */ + in_max= (mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)); + in_min= (mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)); + + /* check if overlap --> which means user clicked on bar, as bar is within handles region */ + if (in_max && in_min) + return SCROLLHANDLE_BAR; + if (in_max) + return SCROLLHANDLE_MAX; + else if (in_min) + return SCROLLHANDLE_MIN; + + /* unlikely to happen, though we just cover it in case */ + else + return SCROLLHANDLE_BAR; +} + +/* initialise customdata for scroller manipulation operator */ +static void scroller_activate_init(bContext *C, wmOperator *op, wmEvent *event, short in_scroller) +{ + v2dScrollerMove *vsm; + View2DScrollers *scrollers; + ARegion *ar= C->region; + View2D *v2d= &ar->v2d; + float mask_size; + int x, y; + + /* set custom-data for operator */ + vsm= MEM_callocN(sizeof(v2dScrollerMove), "v2dScrollerMove"); + op->customdata= vsm; + + /* set general data */ + vsm->v2d= v2d; + vsm->scroller= in_scroller; + + /* store mouse-coordinates, and convert mouse/screen coordinates to region coordinates */ + vsm->lastx = event->x; + vsm->lasty = event->y; + x= event->x - ar->winrct.xmin; + y= event->y - ar->winrct.ymin; + + /* 'zone' depends on where mouse is relative to bubble + * - zooming must be allowed on this axis, otherwise, default to pan + */ + scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); + if (in_scroller == 'h') { + /* horizontal scroller - calculate adjustment factor first */ + mask_size= (float)(v2d->hor.xmax - v2d->hor.xmin); + vsm->fac= (v2d->tot.xmax - v2d->tot.xmin) / mask_size; + + /* get 'zone' (i.e. which part of scroller is activated) */ + if (v2d->keepzoom & V2D_LOCKZOOM_X) { + /* default to scroll, as handles not usable */ + vsm->zone= SCROLLHANDLE_BAR; + } + else { + /* check which handle we're in */ + vsm->zone= mouse_in_scroller_handle(x, v2d->hor.xmin, v2d->hor.xmax, scrollers->hor_min, scrollers->hor_max); + } + } + else { + /* vertical scroller - calculate adjustment factor first */ + mask_size= (float)(v2d->vert.ymax - v2d->vert.ymin); + vsm->fac= (v2d->tot.ymax - v2d->tot.ymin) / mask_size; + + /* get 'zone' (i.e. which part of scroller is activated) */ + if (v2d->keepzoom & V2D_LOCKZOOM_Y) { + /* default to scroll, as handles not usable */ + vsm->zone= SCROLLHANDLE_BAR; + } + else { + /* check which handle we're in */ + vsm->zone= mouse_in_scroller_handle(y, v2d->vert.xmin, v2d->vert.xmax, scrollers->vert_min, scrollers->vert_max); + } + } + UI_view2d_scrollers_free(scrollers); +} + +/* cleanup temp customdata */ +static void scroller_activate_exit(bContext *C, wmOperator *op) +{ + if (op->customdata) { + MEM_freeN(op->customdata); + op->customdata= NULL; + } +} + +/* apply transform to view (i.e. adjust 'cur' rect) */ +static void scroller_activate_apply(bContext *C, wmOperator *op) +{ + v2dScrollerMove *vsm= op->customdata; + View2D *v2d= vsm->v2d; + float temp; + + /* calculate amount to move view by */ + temp= vsm->fac * vsm->delta; + + /* type of movement */ + switch (vsm->zone) { + case SCROLLHANDLE_MIN: + /* only expand view on axis if zoom is allowed */ + if ((vsm->scroller == 'h') && !(v2d->keepzoom & V2D_LOCKZOOM_X)) + v2d->cur.xmin -= temp; + if ((vsm->scroller == 'v') && !(v2d->keepzoom & V2D_LOCKZOOM_Y)) + v2d->cur.ymin -= temp; + break; + + case SCROLLHANDLE_MAX: + /* only expand view on axis if zoom is allowed */ + if ((vsm->scroller == 'h') && !(v2d->keepzoom & V2D_LOCKZOOM_X)) + v2d->cur.xmax += temp; + if ((vsm->scroller == 'v') && !(v2d->keepzoom & V2D_LOCKZOOM_Y)) + v2d->cur.ymax += temp; + break; + + default: /* SCROLLHANDLE_BAR */ + /* only move view on an axis if panning is allowed */ + if ((vsm->scroller == 'h') && !(v2d->keepofs & V2D_LOCKOFS_X)) { + v2d->cur.xmin += temp; + v2d->cur.xmax += temp; + } + if ((vsm->scroller == 'v') && !(v2d->keepofs & V2D_LOCKOFS_Y)) { + v2d->cur.ymin += temp; + v2d->cur.ymax += temp; + } + break; + } + + /* validate that view is in valid configuration after this operation */ + UI_view2d_status_enforce(v2d); + + /* request updates to be done... */ + WM_event_add_notifier(C, WM_NOTE_AREA_REDRAW, 0, NULL); + /* XXX: add WM_NOTE_TIME_CHANGED? */ +} + +/* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */ +static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + v2dScrollerMove *vsm= op->customdata; + + /* execute the events */ + switch (event->type) { + case MOUSEMOVE: + { + /* calculate new delta transform, then store mouse-coordinates for next-time */ + if (vsm->zone != SCROLLHANDLE_MIN) { + /* if using bar (i.e. 'panning') or 'max' zoom widget */ + switch (vsm->scroller) { + case 'h': /* horizontal scroller - so only horizontal movement ('cur' moves opposite to mouse) */ + vsm->delta= (float)(event->x - vsm->lastx); + break; + case 'v': /* vertical scroller - so only vertical movement ('cur' moves opposite to mouse) */ + vsm->delta= (float)(event->y - vsm->lasty); + break; + } + } + else { + /* using 'min' zoom widget */ + switch (vsm->scroller) { + case 'h': /* horizontal scroller - so only horizontal movement ('cur' moves with mouse) */ + vsm->delta= (float)(vsm->lastx - event->x); + break; + case 'v': /* vertical scroller - so only vertical movement ('cur' moves with to mouse) */ + vsm->delta= (float)(vsm->lasty - event->y); + break; + } + } + + /* store previous coordinates */ + vsm->lastx= event->x; + vsm->lasty= event->y; + + scroller_activate_apply(C, op); + } + break; + + case LEFTMOUSE: + if (event->val==0) { + scroller_activate_exit(C, op); + return OPERATOR_FINISHED; + } + break; + } + + return OPERATOR_RUNNING_MODAL; +} + + +/* a click (or click drag in progress) should have occurred, so check if it happened in scrollbar */ +static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + View2D *v2d= NULL; + short in_scroller= 0; + + /* firstly, check context to see if mouse is actually in region */ + // XXX isn't this the job of poll() callbacks which can't check events, but only context? + if (C->region == NULL) + return OPERATOR_CANCELLED; + else + v2d= &C->region->v2d; + + /* check if mouse in scrollbars, if they're enabled */ + in_scroller= mouse_in_v2d_scrollers(C, v2d, event->x, event->y); + + /* if in a scroller, init customdata then set modal handler which will catch mousedown to start doing useful stuff */ + if (in_scroller) { + v2dScrollerMove *vsm; + + /* initialise customdata */ + scroller_activate_init(C, op, event, in_scroller); + vsm= (v2dScrollerMove *)op->customdata; + + /* check if zone is inappropriate (i.e. 'bar' but panning is banned), so cannot continue */ + if (vsm->zone == SCROLLHANDLE_BAR) { + if ( ((vsm->scroller=='h') && (v2d->keepofs & V2D_LOCKOFS_X)) || + ((vsm->scroller=='v') && (v2d->keepofs & V2D_LOCKOFS_Y)) ) + { + /* free customdata initialised */ + scroller_activate_exit(C, op); + + /* can't catch this event for ourselves, so let it go to someone else? */ + return OPERATOR_PASS_THROUGH; + } + } + + /* still ok, so can add */ + WM_event_add_modal_handler(C, &C->window->handlers, op); + return OPERATOR_RUNNING_MODAL; + } + else { + /* not in scroller, so nothing happened... (pass through let's something else catch event) */ + return OPERATOR_PASS_THROUGH; + } +} + +/* LMB-Drag in Scrollers - not repeatable operator! */ +void ED_View2D_OT_scroller_activate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Scroller Activate"; + ot->idname= "ED_View2D_OT_scroller_activate"; + + /* api callbacks */ + ot->invoke= scroller_activate_invoke; + ot->modal= scroller_activate_modal; +} /* ********************************************************* */ /* Registration */ @@ -618,6 +901,8 @@ void ui_view2d_operatortypes(void) WM_operatortype_append(ED_View2D_OT_view_zoomin); WM_operatortype_append(ED_View2D_OT_view_zoomout); + + WM_operatortype_append(ED_View2D_OT_scroller_activate); } void UI_view2d_keymap(wmWindowManager *wm) @@ -633,14 +918,13 @@ void UI_view2d_keymap(wmWindowManager *wm) WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_downscroll", WHEELDOWNMOUSE, KM_ANY, KM_SHIFT, 0); WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_upscroll", WHEELUPMOUSE, KM_ANY, KM_SHIFT, 0); - /* zoom */ + /* zoom - single step */ WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_zoomout", WHEELUPMOUSE, KM_ANY, 0, 0); WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_zoomin", WHEELDOWNMOUSE, KM_ANY, 0, 0); WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_zoomout", PADMINUS, KM_PRESS, 0, 0); WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_zoomin", PADPLUSKEY, KM_PRESS, 0, 0); - - /* scrollbars */ - //WM_keymap_add_item(&wm->view2dkeymap, "ED_V2D_OT_scrollbar_activate", MOUSEMOVE, 0, 0, 0); + /* scrollers */ + WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_scroller_activate", LEFTMOUSE, KM_PRESS, 0, 0); } diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h index 34a329a0646..4d027f2efea 100644 --- a/source/blender/makesdna/DNA_view2d_types.h +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -77,11 +77,16 @@ typedef struct View2D { /* within region view2d vertical locking */ #define V2D_VIEWSYNC_Y (1<<1) -/* scrollbar thickness */ + +/* scroller thickness */ #define V2D_SCROLL_HEIGHT 16 #define V2D_SCROLL_WIDTH 16 -/* scrollbar flags for View2D (v2d->scroll) */ +/* half the size (in pixels) of scroller 'handles' */ +#define V2D_SCROLLER_HANDLE_SIZE 8 + + +/* scroller flags for View2D (v2d->scroll) */ /* left scrollbar */ #define V2D_SCROLL_LEFT (1<<0) #define V2D_SCROLL_RIGHT (1<<1) @@ -104,7 +109,7 @@ typedef struct View2D { /* alignment flags for totrect, flags use 'shading-out' convention (v2d->align) */ /* all quadrants free */ -#define V2D_ALIGN_FREE 0 +#define V2D_ALIGN_FREE 0 /* horizontal restrictions */ #define V2D_ALIGN_NO_POS_X (1<<0) #define V2D_ALIGN_NO_NEG_X (1<<1)