|
Blender
V2.59
|
00001 /* 00002 * $Id: view2d_ops.c 37246 2011-06-06 11:04:54Z nazgul $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2008 Blender Foundation. 00021 * All rights reserved. 00022 * 00023 * Contributor(s): Blender Foundation, Joshua Leung 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <math.h> 00034 00035 #include "MEM_guardedalloc.h" 00036 00037 #include "DNA_userdef_types.h" 00038 00039 #include "BLI_blenlib.h" 00040 #include "BLI_utildefines.h" 00041 00042 #include "BKE_context.h" 00043 00044 #include "RNA_access.h" 00045 #include "RNA_define.h" 00046 00047 #include "WM_api.h" 00048 #include "WM_types.h" 00049 00050 00051 #include "ED_screen.h" 00052 00053 #include "UI_view2d.h" 00054 00055 #include "PIL_time.h" /* USER_ZOOM_CONT */ 00056 00057 static int view2d_poll(bContext *C) 00058 { 00059 ARegion *ar= CTX_wm_region(C); 00060 00061 return (ar != NULL) && (ar->v2d.flag & V2D_IS_INITIALISED); 00062 } 00063 00064 /* ********************************************************* */ 00065 /* VIEW PANNING OPERATOR */ 00066 00067 /* This group of operators come in several forms: 00068 * 1) Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by 00069 * 2) Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount 00070 * 00071 * In order to make sure this works, each operator must define the following RNA-Operator Props: 00072 * deltax, deltay - define how much to move view by (relative to zoom-correction factor) 00073 */ 00074 00075 /* ------------------ Shared 'core' stuff ---------------------- */ 00076 00077 /* temp customdata for operator */ 00078 typedef struct v2dViewPanData { 00079 bScreen *sc; /* screen where view pan was initiated */ 00080 ScrArea *sa; /* area where view pan was initiated */ 00081 ARegion *ar; /* region where view pan was initiated */ 00082 View2D *v2d; /* view2d we're operating in */ 00083 00084 float facx, facy; /* amount to move view relative to zoom */ 00085 00086 /* options for version 1 */ 00087 int startx, starty; /* mouse x/y values in window when operator was initiated */ 00088 int lastx, lasty; /* previous x/y values of mouse in window */ 00089 int invoke_event; /* event starting pan, for modal exit */ 00090 00091 short in_scroller; /* for MMB in scrollers (old feature in past, but now not that useful) */ 00092 } v2dViewPanData; 00093 00094 /* initialise panning customdata */ 00095 static int view_pan_init(bContext *C, wmOperator *op) 00096 { 00097 ARegion *ar= CTX_wm_region(C); 00098 v2dViewPanData *vpd; 00099 View2D *v2d; 00100 float winx, winy; 00101 00102 /* regions now have v2d-data by default, so check for region */ 00103 if (ar == NULL) 00104 return 0; 00105 00106 /* check if panning is allowed at all */ 00107 v2d= &ar->v2d; 00108 if ((v2d->keepofs & V2D_LOCKOFS_X) && (v2d->keepofs & V2D_LOCKOFS_Y)) 00109 return 0; 00110 00111 /* set custom-data for operator */ 00112 vpd= MEM_callocN(sizeof(v2dViewPanData), "v2dViewPanData"); 00113 op->customdata= vpd; 00114 00115 /* set pointers to owners */ 00116 vpd->sc= CTX_wm_screen(C); 00117 vpd->sa= CTX_wm_area(C); 00118 vpd->v2d= v2d; 00119 vpd->ar = ar; 00120 00121 /* calculate translation factor - based on size of view */ 00122 winx= (float)(ar->winrct.xmax - ar->winrct.xmin + 1); 00123 winy= (float)(ar->winrct.ymax - ar->winrct.ymin + 1); 00124 vpd->facx= (v2d->cur.xmax - v2d->cur.xmin) / winx; 00125 vpd->facy= (v2d->cur.ymax - v2d->cur.ymin) / winy; 00126 00127 return 1; 00128 } 00129 00130 /* apply transform to view (i.e. adjust 'cur' rect) */ 00131 static void view_pan_apply(wmOperator *op) 00132 { 00133 v2dViewPanData *vpd= op->customdata; 00134 View2D *v2d= vpd->v2d; 00135 float dx, dy; 00136 00137 /* calculate amount to move view by */ 00138 dx= vpd->facx * (float)RNA_int_get(op->ptr, "deltax"); 00139 dy= vpd->facy * (float)RNA_int_get(op->ptr, "deltay"); 00140 00141 /* only move view on an axis if change is allowed */ 00142 if ((v2d->keepofs & V2D_LOCKOFS_X)==0) { 00143 v2d->cur.xmin += dx; 00144 v2d->cur.xmax += dx; 00145 } 00146 if ((v2d->keepofs & V2D_LOCKOFS_Y)==0) { 00147 v2d->cur.ymin += dy; 00148 v2d->cur.ymax += dy; 00149 } 00150 00151 /* validate that view is in valid configuration after this operation */ 00152 UI_view2d_curRect_validate(v2d); 00153 00154 /* request updates to be done... */ 00155 ED_region_tag_redraw(vpd->ar); 00156 00157 UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY); 00158 00159 /* exceptions */ 00160 if (vpd->sa->spacetype==SPACE_OUTLINER) { 00161 /* don't rebuild full tree, since we're just changing our view */ 00162 SpaceOops *soops= vpd->sa->spacedata.first; 00163 soops->storeflag |= SO_TREESTORE_REDRAW; 00164 } 00165 } 00166 00167 /* cleanup temp customdata */ 00168 static void view_pan_exit(wmOperator *op) 00169 { 00170 if (op->customdata) { 00171 MEM_freeN(op->customdata); 00172 op->customdata= NULL; 00173 } 00174 } 00175 00176 /* ------------------ Modal Drag Version (1) ---------------------- */ 00177 00178 /* for 'redo' only, with no user input */ 00179 static int view_pan_exec(bContext *C, wmOperator *op) 00180 { 00181 if (!view_pan_init(C, op)) 00182 return OPERATOR_CANCELLED; 00183 00184 view_pan_apply(op); 00185 view_pan_exit(op); 00186 return OPERATOR_FINISHED; 00187 } 00188 00189 /* set up modal operator and relevant settings */ 00190 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) 00191 { 00192 wmWindow *window= CTX_wm_window(C); 00193 v2dViewPanData *vpd; 00194 View2D *v2d; 00195 00196 /* set up customdata */ 00197 if (!view_pan_init(C, op)) 00198 return OPERATOR_PASS_THROUGH; 00199 00200 vpd= op->customdata; 00201 v2d= vpd->v2d; 00202 00203 /* set initial settings */ 00204 vpd->startx= vpd->lastx= event->x; 00205 vpd->starty= vpd->lasty= event->y; 00206 vpd->invoke_event= event->type; 00207 00208 if (event->type == MOUSEPAN) { 00209 RNA_int_set(op->ptr, "deltax", event->prevx - event->x); 00210 RNA_int_set(op->ptr, "deltay", event->prevy - event->y); 00211 00212 view_pan_apply(op); 00213 view_pan_exit(op); 00214 return OPERATOR_FINISHED; 00215 } 00216 00217 RNA_int_set(op->ptr, "deltax", 0); 00218 RNA_int_set(op->ptr, "deltay", 0); 00219 00220 if (v2d->keepofs & V2D_LOCKOFS_X) 00221 WM_cursor_modal(window, BC_NS_SCROLLCURSOR); 00222 else if (v2d->keepofs & V2D_LOCKOFS_Y) 00223 WM_cursor_modal(window, BC_EW_SCROLLCURSOR); 00224 else 00225 WM_cursor_modal(window, BC_NSEW_SCROLLCURSOR); 00226 00227 /* add temp handler */ 00228 WM_event_add_modal_handler(C, op); 00229 00230 return OPERATOR_RUNNING_MODAL; 00231 } 00232 00233 /* handle user input - calculations of mouse-movement need to be done here, not in the apply callback! */ 00234 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) 00235 { 00236 v2dViewPanData *vpd= op->customdata; 00237 00238 /* execute the events */ 00239 switch (event->type) { 00240 case MOUSEMOVE: 00241 { 00242 /* calculate new delta transform, then store mouse-coordinates for next-time */ 00243 RNA_int_set(op->ptr, "deltax", (vpd->lastx - event->x)); 00244 RNA_int_set(op->ptr, "deltay", (vpd->lasty - event->y)); 00245 00246 vpd->lastx= event->x; 00247 vpd->lasty= event->y; 00248 00249 view_pan_apply(op); 00250 } 00251 break; 00252 00253 case LEFTMOUSE: 00254 /* switch to zoom */ 00255 if (event->val==KM_PRESS) { 00256 /* calculate overall delta mouse-movement for redo */ 00257 RNA_int_set(op->ptr, "deltax", (vpd->startx - vpd->lastx)); 00258 RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty)); 00259 00260 view_pan_exit(op); 00261 WM_cursor_restore(CTX_wm_window(C)); 00262 00263 WM_operator_name_call(C, "VIEW2D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL); 00264 return OPERATOR_FINISHED; 00265 } 00266 00267 default: 00268 if (event->type == vpd->invoke_event || event->type==ESCKEY) { 00269 if (event->val==KM_RELEASE) { 00270 /* calculate overall delta mouse-movement for redo */ 00271 RNA_int_set(op->ptr, "deltax", (vpd->startx - vpd->lastx)); 00272 RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty)); 00273 00274 view_pan_exit(op); 00275 WM_cursor_restore(CTX_wm_window(C)); 00276 00277 return OPERATOR_FINISHED; 00278 } 00279 } 00280 break; 00281 } 00282 00283 return OPERATOR_RUNNING_MODAL; 00284 } 00285 00286 static int view_pan_cancel(bContext *UNUSED(C), wmOperator *op) 00287 { 00288 view_pan_exit(op); 00289 return OPERATOR_CANCELLED; 00290 } 00291 00292 static void VIEW2D_OT_pan(wmOperatorType *ot) 00293 { 00294 /* identifiers */ 00295 ot->name= "Pan View"; 00296 ot->description= "Pan the view"; 00297 ot->idname= "VIEW2D_OT_pan"; 00298 00299 /* api callbacks */ 00300 ot->exec= view_pan_exec; 00301 ot->invoke= view_pan_invoke; 00302 ot->modal= view_pan_modal; 00303 ot->cancel= view_pan_cancel; 00304 00305 /* operator is modal */ 00306 ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER; 00307 00308 /* rna - must keep these in sync with the other operators */ 00309 RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX); 00310 RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX); 00311 } 00312 00313 /* ------------------ Scrollwheel Versions (2) ---------------------- */ 00314 00315 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */ 00316 static int view_scrollright_exec(bContext *C, wmOperator *op) 00317 { 00318 v2dViewPanData *vpd; 00319 00320 /* initialise default settings (and validate if ok to run) */ 00321 if (!view_pan_init(C, op)) 00322 return OPERATOR_PASS_THROUGH; 00323 00324 /* also, check if can pan in horizontal axis */ 00325 vpd= op->customdata; 00326 if (vpd->v2d->keepofs & V2D_LOCKOFS_X) { 00327 view_pan_exit(op); 00328 return OPERATOR_PASS_THROUGH; 00329 } 00330 00331 /* set RNA-Props - only movement in positive x-direction */ 00332 RNA_int_set(op->ptr, "deltax", 20); 00333 RNA_int_set(op->ptr, "deltay", 0); 00334 00335 /* apply movement, then we're done */ 00336 view_pan_apply(op); 00337 view_pan_exit(op); 00338 00339 return OPERATOR_FINISHED; 00340 } 00341 00342 static void VIEW2D_OT_scroll_right(wmOperatorType *ot) 00343 { 00344 /* identifiers */ 00345 ot->name= "Scroll Right"; 00346 ot->description= "Scroll the view right"; 00347 ot->idname= "VIEW2D_OT_scroll_right"; 00348 00349 /* api callbacks */ 00350 ot->exec= view_scrollright_exec; 00351 00352 /* rna - must keep these in sync with the other operators */ 00353 RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX); 00354 RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX); 00355 } 00356 00357 00358 00359 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */ 00360 static int view_scrollleft_exec(bContext *C, wmOperator *op) 00361 { 00362 v2dViewPanData *vpd; 00363 00364 /* initialise default settings (and validate if ok to run) */ 00365 if (!view_pan_init(C, op)) 00366 return OPERATOR_PASS_THROUGH; 00367 00368 /* also, check if can pan in horizontal axis */ 00369 vpd= op->customdata; 00370 if (vpd->v2d->keepofs & V2D_LOCKOFS_X) { 00371 view_pan_exit(op); 00372 return OPERATOR_PASS_THROUGH; 00373 } 00374 00375 /* set RNA-Props - only movement in negative x-direction */ 00376 RNA_int_set(op->ptr, "deltax", -20); 00377 RNA_int_set(op->ptr, "deltay", 0); 00378 00379 /* apply movement, then we're done */ 00380 view_pan_apply(op); 00381 view_pan_exit(op); 00382 00383 return OPERATOR_FINISHED; 00384 } 00385 00386 static void VIEW2D_OT_scroll_left(wmOperatorType *ot) 00387 { 00388 /* identifiers */ 00389 ot->name= "Scroll Left"; 00390 ot->description= "Scroll the view left"; 00391 ot->idname= "VIEW2D_OT_scroll_left"; 00392 00393 /* api callbacks */ 00394 ot->exec= view_scrollleft_exec; 00395 00396 /* rna - must keep these in sync with the other operators */ 00397 RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX); 00398 RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX); 00399 } 00400 00401 00402 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */ 00403 static int view_scrolldown_exec(bContext *C, wmOperator *op) 00404 { 00405 v2dViewPanData *vpd; 00406 00407 /* initialise default settings (and validate if ok to run) */ 00408 if (!view_pan_init(C, op)) 00409 return OPERATOR_PASS_THROUGH; 00410 00411 /* also, check if can pan in vertical axis */ 00412 vpd= op->customdata; 00413 if (vpd->v2d->keepofs & V2D_LOCKOFS_Y) { 00414 view_pan_exit(op); 00415 return OPERATOR_PASS_THROUGH; 00416 } 00417 00418 /* set RNA-Props */ 00419 RNA_int_set(op->ptr, "deltax", 0); 00420 RNA_int_set(op->ptr, "deltay", -40); 00421 00422 if(RNA_boolean_get(op->ptr, "page")) { 00423 ARegion *ar= CTX_wm_region(C); 00424 RNA_int_set(op->ptr, "deltay", ar->v2d.mask.ymin - ar->v2d.mask.ymax); 00425 } 00426 00427 /* apply movement, then we're done */ 00428 view_pan_apply(op); 00429 view_pan_exit(op); 00430 00431 return OPERATOR_FINISHED; 00432 } 00433 00434 static void VIEW2D_OT_scroll_down(wmOperatorType *ot) 00435 { 00436 /* identifiers */ 00437 ot->name= "Scroll Down"; 00438 ot->description= "Scroll the view down"; 00439 ot->idname= "VIEW2D_OT_scroll_down"; 00440 00441 /* api callbacks */ 00442 ot->exec= view_scrolldown_exec; 00443 00444 /* rna - must keep these in sync with the other operators */ 00445 RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX); 00446 RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX); 00447 RNA_def_boolean(ot->srna, "page", 0, "Page", "Scroll down one page."); 00448 } 00449 00450 00451 00452 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */ 00453 static int view_scrollup_exec(bContext *C, wmOperator *op) 00454 { 00455 v2dViewPanData *vpd; 00456 00457 /* initialise default settings (and validate if ok to run) */ 00458 if (!view_pan_init(C, op)) 00459 return OPERATOR_PASS_THROUGH; 00460 00461 /* also, check if can pan in vertical axis */ 00462 vpd= op->customdata; 00463 if (vpd->v2d->keepofs & V2D_LOCKOFS_Y) { 00464 view_pan_exit(op); 00465 return OPERATOR_PASS_THROUGH; 00466 } 00467 00468 /* set RNA-Props */ 00469 RNA_int_set(op->ptr, "deltax", 0); 00470 RNA_int_set(op->ptr, "deltay", 40); 00471 00472 if(RNA_boolean_get(op->ptr, "page")) { 00473 ARegion *ar= CTX_wm_region(C); 00474 RNA_int_set(op->ptr, "deltay", ar->v2d.mask.ymax - ar->v2d.mask.ymin); 00475 } 00476 00477 /* apply movement, then we're done */ 00478 view_pan_apply(op); 00479 view_pan_exit(op); 00480 00481 return OPERATOR_FINISHED; 00482 } 00483 00484 static void VIEW2D_OT_scroll_up(wmOperatorType *ot) 00485 { 00486 /* identifiers */ 00487 ot->name= "Scroll Up"; 00488 ot->description= "Scroll the view up"; 00489 ot->idname= "VIEW2D_OT_scroll_up"; 00490 00491 /* api callbacks */ 00492 ot->exec= view_scrollup_exec; 00493 00494 /* rna - must keep these in sync with the other operators */ 00495 RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX); 00496 RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX); 00497 RNA_def_boolean(ot->srna, "page", 0, "Page", "Scroll up one page."); 00498 } 00499 00500 /* ********************************************************* */ 00501 /* SINGLE-STEP VIEW ZOOMING OPERATOR */ 00502 00503 /* This group of operators come in several forms: 00504 * 1) Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount 00505 * 2) Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y) // XXX this could be implemented... 00506 * 3) Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount 00507 * 00508 * In order to make sure this works, each operator must define the following RNA-Operator Props: 00509 * zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling. 00510 * It is safe to scale by 0, as these factors are used to determine 00511 * amount to enlarge 'cur' by 00512 */ 00513 00514 /* ------------------ 'Shared' stuff ------------------------ */ 00515 00516 /* temp customdata for operator */ 00517 typedef struct v2dViewZoomData { 00518 View2D *v2d; /* view2d we're operating in */ 00519 ARegion *ar; 00520 00521 /* needed for continuous zoom */ 00522 wmTimer *timer; 00523 double timer_lastdraw; 00524 00525 int lastx, lasty; /* previous x/y values of mouse in window */ 00526 int invoke_event; /* event type that invoked, for modal exits */ 00527 float dx, dy; /* running tally of previous delta values (for obtaining final zoom) */ 00528 float mx_2d, my_2d; /* initial mouse location in v2d coords */ 00529 } v2dViewZoomData; 00530 00531 00532 /* initialise panning customdata */ 00533 static int view_zoomdrag_init(bContext *C, wmOperator *op) 00534 { 00535 ARegion *ar= CTX_wm_region(C); 00536 v2dViewZoomData *vzd; 00537 View2D *v2d; 00538 00539 /* regions now have v2d-data by default, so check for region */ 00540 if (ar == NULL) 00541 return 0; 00542 v2d= &ar->v2d; 00543 00544 /* check that 2d-view is zoomable */ 00545 if ((v2d->keepzoom & V2D_LOCKZOOM_X) && (v2d->keepzoom & V2D_LOCKZOOM_Y)) 00546 return 0; 00547 00548 /* set custom-data for operator */ 00549 vzd= MEM_callocN(sizeof(v2dViewZoomData), "v2dViewZoomData"); 00550 op->customdata= vzd; 00551 00552 /* set pointers to owners */ 00553 vzd->v2d= v2d; 00554 vzd->ar = ar; 00555 00556 return 1; 00557 } 00558 00559 /* check if step-zoom can be applied */ 00560 static int view_zoom_poll(bContext *C) 00561 { 00562 ARegion *ar= CTX_wm_region(C); 00563 View2D *v2d; 00564 00565 /* check if there's a region in context to work with */ 00566 if (ar == NULL) 00567 return 0; 00568 v2d= &ar->v2d; 00569 00570 /* check that 2d-view is zoomable */ 00571 if ((v2d->keepzoom & V2D_LOCKZOOM_X) && (v2d->keepzoom & V2D_LOCKZOOM_Y)) 00572 return 0; 00573 00574 /* view is zoomable */ 00575 return 1; 00576 } 00577 00578 /* apply transform to view (i.e. adjust 'cur' rect) */ 00579 static void view_zoomstep_apply(bContext *C, wmOperator *op) 00580 { 00581 v2dViewZoomData *vzd= op->customdata; 00582 ARegion *ar= CTX_wm_region(C); 00583 View2D *v2d= &ar->v2d; 00584 float dx, dy, facx, facy; 00585 00586 /* calculate amount to move view by, ensuring symmetry so the 00587 * old zoom level is restored after zooming back the same amount 00588 */ 00589 facx= RNA_float_get(op->ptr, "zoomfacx"); 00590 facy= RNA_float_get(op->ptr, "zoomfacy"); 00591 00592 if (facx >= 0.0f) { 00593 dx= (v2d->cur.xmax - v2d->cur.xmin) * facx; 00594 dy= (v2d->cur.ymax - v2d->cur.ymin) * facy; 00595 } 00596 else { 00597 dx= ((v2d->cur.xmax - v2d->cur.xmin)/(1.0f + 2.0f*facx)) * facx; 00598 dy= ((v2d->cur.ymax - v2d->cur.ymin)/(1.0f + 2.0f*facy)) * facy; 00599 } 00600 00601 /* only resize view on an axis if change is allowed */ 00602 if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) { 00603 if (v2d->keepofs & V2D_LOCKOFS_X) { 00604 v2d->cur.xmax -= 2*dx; 00605 } 00606 else if (v2d->keepofs & V2D_KEEPOFS_X) { 00607 if (v2d->align & V2D_ALIGN_NO_POS_X) 00608 v2d->cur.xmin += 2*dx; 00609 else 00610 v2d->cur.xmax -= 2*dx; 00611 } 00612 else { 00613 if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { 00614 float mval_fac = (vzd->mx_2d - v2d->cur.xmin) / (v2d->cur.xmax-v2d->cur.xmin); 00615 float mval_faci = 1.0f - mval_fac; 00616 float ofs= (mval_fac * dx) - (mval_faci * dx); 00617 00618 v2d->cur.xmin += ofs + dx; 00619 v2d->cur.xmax += ofs - dx; 00620 } 00621 else { 00622 v2d->cur.xmin += dx; 00623 v2d->cur.xmax -= dx; 00624 } 00625 } 00626 } 00627 if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) { 00628 if (v2d->keepofs & V2D_LOCKOFS_Y) { 00629 v2d->cur.ymax -= 2*dy; 00630 } 00631 else if (v2d->keepofs & V2D_KEEPOFS_Y) { 00632 if (v2d->align & V2D_ALIGN_NO_POS_Y) 00633 v2d->cur.ymin += 2*dy; 00634 else 00635 v2d->cur.ymax -= 2*dy; 00636 } 00637 else { 00638 if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { 00639 float mval_fac = (vzd->my_2d - v2d->cur.ymin) / (v2d->cur.ymax-v2d->cur.ymin); 00640 float mval_faci = 1.0f - mval_fac; 00641 float ofs= (mval_fac * dy) - (mval_faci * dy); 00642 00643 v2d->cur.ymin += ofs + dy; 00644 v2d->cur.ymax += ofs - dy; 00645 } 00646 else { 00647 v2d->cur.ymin += dy; 00648 v2d->cur.ymax -= dy; 00649 } 00650 } 00651 } 00652 00653 /* validate that view is in valid configuration after this operation */ 00654 UI_view2d_curRect_validate(v2d); 00655 00656 /* request updates to be done... */ 00657 ED_region_tag_redraw(vzd->ar); 00658 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); 00659 } 00660 00661 /* --------------- Individual Operators ------------------- */ 00662 00663 /* cleanup temp customdata */ 00664 static void view_zoomstep_exit(wmOperator *op) 00665 { 00666 if (op->customdata) { 00667 MEM_freeN(op->customdata); 00668 op->customdata= NULL; 00669 } 00670 } 00671 00672 /* this operator only needs this single callback, where it calls the view_zoom_*() methods */ 00673 static int view_zoomin_exec(bContext *C, wmOperator *op) 00674 { 00675 /* check that there's an active region, as View2D data resides there */ 00676 if (!view_zoom_poll(C)) 00677 return OPERATOR_PASS_THROUGH; 00678 00679 /* set RNA-Props - zooming in by uniform factor */ 00680 RNA_float_set(op->ptr, "zoomfacx", 0.0375f); 00681 RNA_float_set(op->ptr, "zoomfacy", 0.0375f); 00682 00683 /* apply movement, then we're done */ 00684 view_zoomstep_apply(C, op); 00685 00686 view_zoomstep_exit(op); 00687 00688 return OPERATOR_FINISHED; 00689 } 00690 00691 static int view_zoomin_invoke(bContext *C, wmOperator *op, wmEvent *event) 00692 { 00693 v2dViewZoomData *vzd; 00694 00695 if (!view_zoomdrag_init(C, op)) 00696 return OPERATOR_PASS_THROUGH; 00697 00698 vzd= op->customdata; 00699 00700 if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { 00701 ARegion *ar= CTX_wm_region(C); 00702 00703 /* store initial mouse position (in view space) */ 00704 UI_view2d_region_to_view(&ar->v2d, 00705 event->mval[0], event->mval[1], 00706 &vzd->mx_2d, &vzd->my_2d); 00707 } 00708 00709 return view_zoomin_exec(C, op); 00710 } 00711 00712 static void VIEW2D_OT_zoom_in(wmOperatorType *ot) 00713 { 00714 /* identifiers */ 00715 ot->name= "Zoom In"; 00716 ot->description= "Zoom in the view"; 00717 ot->idname= "VIEW2D_OT_zoom_in"; 00718 00719 /* api callbacks */ 00720 ot->invoke= view_zoomin_invoke; 00721 // ot->exec= view_zoomin_exec; // XXX, needs view_zoomdrag_init called first. 00722 ot->poll= view_zoom_poll; 00723 00724 /* rna - must keep these in sync with the other operators */ 00725 RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX); 00726 RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX); 00727 } 00728 00729 /* this operator only needs this single callback, where it callsthe view_zoom_*() methods */ 00730 static int view_zoomout_exec(bContext *C, wmOperator *op) 00731 { 00732 /* check that there's an active region, as View2D data resides there */ 00733 if (!view_zoom_poll(C)) 00734 return OPERATOR_PASS_THROUGH; 00735 00736 /* set RNA-Props - zooming in by uniform factor */ 00737 RNA_float_set(op->ptr, "zoomfacx", -0.0375f); 00738 RNA_float_set(op->ptr, "zoomfacy", -0.0375f); 00739 00740 /* apply movement, then we're done */ 00741 view_zoomstep_apply(C, op); 00742 00743 view_zoomstep_exit(op); 00744 00745 return OPERATOR_FINISHED; 00746 } 00747 00748 static int view_zoomout_invoke(bContext *C, wmOperator *op, wmEvent *event) 00749 { 00750 v2dViewZoomData *vzd; 00751 00752 if (!view_zoomdrag_init(C, op)) 00753 return OPERATOR_PASS_THROUGH; 00754 00755 vzd= op->customdata; 00756 00757 if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) { 00758 ARegion *ar= CTX_wm_region(C); 00759 00760 /* store initial mouse position (in view space) */ 00761 UI_view2d_region_to_view(&ar->v2d, 00762 event->mval[0], event->mval[1], 00763 &vzd->mx_2d, &vzd->my_2d); 00764 } 00765 00766 return view_zoomout_exec(C, op); 00767 } 00768 00769 static void VIEW2D_OT_zoom_out(wmOperatorType *ot) 00770 { 00771 /* identifiers */ 00772 ot->name= "Zoom Out"; 00773 ot->description= "Zoom out the view"; 00774 ot->idname= "VIEW2D_OT_zoom_out"; 00775 00776 /* api callbacks */ 00777 ot->invoke= view_zoomout_invoke; 00778 // ot->exec= view_zoomout_exec; // XXX, needs view_zoomdrag_init called first. 00779 ot->poll= view_zoom_poll; 00780 00781 /* rna - must keep these in sync with the other operators */ 00782 RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX); 00783 RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX); 00784 } 00785 00786 /* ********************************************************* */ 00787 /* DRAG-ZOOM OPERATOR */ 00788 00789 /* MMB Drag - allows non-uniform scaling by dragging mouse 00790 * 00791 * In order to make sure this works, each operator must define the following RNA-Operator Props: 00792 * deltax, deltay - amounts to add to each side of the 'cur' rect 00793 */ 00794 00795 /* apply transform to view (i.e. adjust 'cur' rect) */ 00796 static void view_zoomdrag_apply(bContext *C, wmOperator *op) 00797 { 00798 v2dViewZoomData *vzd= op->customdata; 00799 View2D *v2d= vzd->v2d; 00800 float dx, dy; 00801 00802 /* get amount to move view by */ 00803 dx= RNA_float_get(op->ptr, "deltax"); 00804 dy= RNA_float_get(op->ptr, "deltay"); 00805 00806 /* continous zoom shouldn't move that fast... */ 00807 if (U.viewzoom == USER_ZOOM_CONT) { // XXX store this setting as RNA prop? 00808 double time= PIL_check_seconds_timer(); 00809 float time_step= (float)(time - vzd->timer_lastdraw); 00810 00811 dx *= time_step * 0.5f; 00812 dy *= time_step * 0.5f; 00813 00814 vzd->timer_lastdraw= time; 00815 } 00816 00817 /* only move view on an axis if change is allowed */ 00818 if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) { 00819 if (v2d->keepofs & V2D_LOCKOFS_X) { 00820 v2d->cur.xmax -= 2*dx; 00821 } 00822 else { 00823 if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { 00824 float mval_fac = (vzd->mx_2d - v2d->cur.xmin) / (v2d->cur.xmax-v2d->cur.xmin); 00825 float mval_faci = 1.0f - mval_fac; 00826 float ofs= (mval_fac * dx) - (mval_faci * dx); 00827 00828 v2d->cur.xmin += ofs + dx; 00829 v2d->cur.xmax += ofs - dx; 00830 } 00831 else { 00832 v2d->cur.xmin += dx; 00833 v2d->cur.xmax -= dx; 00834 } 00835 } 00836 } 00837 if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) { 00838 if (v2d->keepofs & V2D_LOCKOFS_Y) { 00839 v2d->cur.ymax -= 2*dy; 00840 } 00841 else { 00842 if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { 00843 float mval_fac = (vzd->my_2d - v2d->cur.ymin) / (v2d->cur.ymax-v2d->cur.ymin); 00844 float mval_faci = 1.0f - mval_fac; 00845 float ofs= (mval_fac * dy) - (mval_faci * dy); 00846 00847 v2d->cur.ymin += ofs + dy; 00848 v2d->cur.ymax += ofs - dy; 00849 } 00850 else { 00851 v2d->cur.ymin += dy; 00852 v2d->cur.ymax -= dy; 00853 } 00854 } 00855 } 00856 00857 /* validate that view is in valid configuration after this operation */ 00858 UI_view2d_curRect_validate(v2d); 00859 00860 /* request updates to be done... */ 00861 ED_region_tag_redraw(vzd->ar); 00862 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); 00863 } 00864 00865 /* cleanup temp customdata */ 00866 static void view_zoomdrag_exit(bContext *C, wmOperator *op) 00867 { 00868 if (op->customdata) { 00869 v2dViewZoomData *vzd= op->customdata; 00870 00871 if(vzd->timer) 00872 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), vzd->timer); 00873 00874 MEM_freeN(op->customdata); 00875 op->customdata= NULL; 00876 } 00877 } 00878 00879 static int view_zoomdrag_cancel(bContext *C, wmOperator *op) 00880 { 00881 view_zoomdrag_exit(C, op); 00882 00883 return OPERATOR_CANCELLED; 00884 } 00885 00886 /* for 'redo' only, with no user input */ 00887 static int view_zoomdrag_exec(bContext *C, wmOperator *op) 00888 { 00889 if (!view_zoomdrag_init(C, op)) 00890 return OPERATOR_PASS_THROUGH; 00891 00892 view_zoomdrag_apply(C, op); 00893 view_zoomdrag_exit(C, op); 00894 return OPERATOR_FINISHED; 00895 } 00896 00897 /* set up modal operator and relevant settings */ 00898 static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) 00899 { 00900 wmWindow *window= CTX_wm_window(C); 00901 v2dViewZoomData *vzd; 00902 View2D *v2d; 00903 00904 /* set up customdata */ 00905 if (!view_zoomdrag_init(C, op)) 00906 return OPERATOR_PASS_THROUGH; 00907 00908 vzd= op->customdata; 00909 v2d= vzd->v2d; 00910 00911 if (event->type == MOUSEZOOM) { 00912 float dx, dy, fac; 00913 00914 vzd->lastx= event->prevx; 00915 vzd->lasty= event->prevy; 00916 00917 /* As we have only 1D information (magnify value), feed both axes 00918 * with magnify information that is stored in x axis 00919 */ 00920 fac= 0.01f * (event->x - event->prevx); 00921 dx= fac * (v2d->cur.xmax - v2d->cur.xmin) / 10.0f; 00922 dy= fac * (v2d->cur.ymax - v2d->cur.ymin) / 10.0f; 00923 00924 RNA_float_set(op->ptr, "deltax", dx); 00925 RNA_float_set(op->ptr, "deltay", dy); 00926 00927 view_zoomdrag_apply(C, op); 00928 view_zoomdrag_exit(C, op); 00929 return OPERATOR_FINISHED; 00930 } 00931 00932 /* set initial settings */ 00933 vzd->lastx= event->x; 00934 vzd->lasty= event->y; 00935 RNA_float_set(op->ptr, "deltax", 0); 00936 RNA_float_set(op->ptr, "deltay", 0); 00937 00938 /* for modal exit test */ 00939 vzd->invoke_event= event->type; 00940 00941 if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { 00942 ARegion *ar= CTX_wm_region(C); 00943 00944 /* store initial mouse position (in view space) */ 00945 UI_view2d_region_to_view(&ar->v2d, 00946 event->mval[0], event->mval[1], 00947 &vzd->mx_2d, &vzd->my_2d); 00948 } 00949 00950 if (v2d->keepofs & V2D_LOCKOFS_X) 00951 WM_cursor_modal(window, BC_NS_SCROLLCURSOR); 00952 else if (v2d->keepofs & V2D_LOCKOFS_Y) 00953 WM_cursor_modal(window, BC_EW_SCROLLCURSOR); 00954 else 00955 WM_cursor_modal(window, BC_NSEW_SCROLLCURSOR); 00956 00957 /* add temp handler */ 00958 WM_event_add_modal_handler(C, op); 00959 00960 if (U.viewzoom == USER_ZOOM_CONT) { 00961 /* needs a timer to continue redrawing */ 00962 vzd->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); 00963 vzd->timer_lastdraw= PIL_check_seconds_timer(); 00964 } 00965 00966 return OPERATOR_RUNNING_MODAL; 00967 } 00968 00969 /* handle user input - calculations of mouse-movement need to be done here, not in the apply callback! */ 00970 static int view_zoomdrag_modal(bContext *C, wmOperator *op, wmEvent *event) 00971 { 00972 v2dViewZoomData *vzd= op->customdata; 00973 View2D *v2d= vzd->v2d; 00974 00975 /* execute the events */ 00976 if (event->type == TIMER && event->customdata == vzd->timer) { 00977 view_zoomdrag_apply(C, op); 00978 } 00979 else if(event->type == MOUSEMOVE) { 00980 float dx, dy; 00981 00982 /* calculate new delta transform, based on zooming mode */ 00983 if (U.viewzoom == USER_ZOOM_SCALE) { 00984 /* 'scale' zooming */ 00985 float dist; 00986 00987 /* x-axis transform */ 00988 dist = (v2d->mask.xmax - v2d->mask.xmin) / 2.0f; 00989 dx= 1.0f - ((float)fabs(vzd->lastx - dist) + 2.0f) / ((float)fabs(event->x - dist) + 2.0f); 00990 dx*= 0.5f * (v2d->cur.xmax - v2d->cur.xmin); 00991 00992 /* y-axis transform */ 00993 dist = (v2d->mask.ymax - v2d->mask.ymin) / 2.0f; 00994 dy= 1.0f - ((float)fabs(vzd->lasty - dist) + 2.0f) / ((float)fabs(event->y - dist) + 2.0f); 00995 dy*= 0.5f * (v2d->cur.ymax - v2d->cur.ymin); 00996 } 00997 else { 00998 /* 'continuous' or 'dolly' */ 00999 float fac; 01000 01001 /* x-axis transform */ 01002 fac= 0.01f * (event->x - vzd->lastx); 01003 dx= fac * (v2d->cur.xmax - v2d->cur.xmin); 01004 01005 /* y-axis transform */ 01006 fac= 0.01f * (event->y - vzd->lasty); 01007 dy= fac * (v2d->cur.ymax - v2d->cur.ymin); 01008 #if 0 01009 /* continous zoom shouldn't move that fast... */ 01010 if (U.viewzoom == USER_ZOOM_CONT) { // XXX store this setting as RNA prop? 01011 double time= PIL_check_seconds_timer(); 01012 float time_step= (float)(time - vzd->timer_lastdraw); 01013 01014 dx /= (0.1f / time_step); 01015 dy /= (0.1f / time_step); 01016 01017 vzd->timer_lastdraw= time; 01018 } 01019 #endif 01020 } 01021 01022 /* set transform amount, and add current deltas to stored total delta (for redo) */ 01023 RNA_float_set(op->ptr, "deltax", dx); 01024 RNA_float_set(op->ptr, "deltay", dy); 01025 vzd->dx += dx; 01026 vzd->dy += dy; 01027 01028 /* store mouse coordinates for next time, if not doing continuous zoom 01029 * - continuous zoom only depends on distance of mouse to starting point to determine rate of change 01030 */ 01031 if (U.viewzoom != USER_ZOOM_CONT) { // XXX store this setting as RNA prop? 01032 vzd->lastx= event->x; 01033 vzd->lasty= event->y; 01034 } 01035 01036 /* apply zooming */ 01037 view_zoomdrag_apply(C, op); 01038 } 01039 else if (event->type == vzd->invoke_event || event->type==ESCKEY) { 01040 if (event->val == KM_RELEASE) { 01041 01042 /* for redo, store the overall deltas - need to respect zoom-locks here... */ 01043 if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) 01044 RNA_float_set(op->ptr, "deltax", vzd->dx); 01045 else 01046 RNA_float_set(op->ptr, "deltax", 0); 01047 01048 if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) 01049 RNA_float_set(op->ptr, "deltay", vzd->dy); 01050 else 01051 RNA_float_set(op->ptr, "deltay", 0); 01052 01053 /* free customdata */ 01054 view_zoomdrag_exit(C, op); 01055 WM_cursor_restore(CTX_wm_window(C)); 01056 01057 return OPERATOR_FINISHED; 01058 } 01059 } 01060 01061 return OPERATOR_RUNNING_MODAL; 01062 } 01063 01064 static void VIEW2D_OT_zoom(wmOperatorType *ot) 01065 { 01066 /* identifiers */ 01067 ot->name= "Zoom 2D View"; 01068 ot->description= "Zoom in/out the view"; 01069 ot->idname= "VIEW2D_OT_zoom"; 01070 01071 /* api callbacks */ 01072 ot->exec= view_zoomdrag_exec; 01073 ot->invoke= view_zoomdrag_invoke; 01074 ot->modal= view_zoomdrag_modal; 01075 ot->cancel= view_zoomdrag_cancel; 01076 01077 ot->poll= view_zoom_poll; 01078 01079 /* operator is repeatable */ 01080 // ot->flag= OPTYPE_BLOCKING; 01081 01082 /* rna - must keep these in sync with the other operators */ 01083 RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX); 01084 RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX); 01085 } 01086 01087 /* ********************************************************* */ 01088 /* BORDER-ZOOM */ 01089 01090 /* The user defines a rect using standard borderselect tools, and we use this rect to 01091 * define the new zoom-level of the view in the following ways: 01092 * 1) LEFTMOUSE - zoom in to view 01093 * 2) RIGHTMOUSE - zoom out of view 01094 * 01095 * Currently, these key mappings are hardcoded, but it shouldn't be too important to 01096 * have custom keymappings for this... 01097 */ 01098 01099 static int view_borderzoom_exec(bContext *C, wmOperator *op) 01100 { 01101 ARegion *ar= CTX_wm_region(C); 01102 View2D *v2d= &ar->v2d; 01103 rctf rect; 01104 int gesture_mode; 01105 01106 /* convert coordinates of rect to 'tot' rect coordinates */ 01107 UI_view2d_region_to_view(v2d, RNA_int_get(op->ptr, "xmin"), RNA_int_get(op->ptr, "ymin"), &rect.xmin, &rect.ymin); 01108 UI_view2d_region_to_view(v2d, RNA_int_get(op->ptr, "xmax"), RNA_int_get(op->ptr, "ymax"), &rect.xmax, &rect.ymax); 01109 01110 /* check if zooming in/out view */ 01111 gesture_mode= RNA_int_get(op->ptr, "gesture_mode"); 01112 01113 if (gesture_mode == GESTURE_MODAL_IN) { 01114 /* zoom in: 01115 * - 'cur' rect will be defined by the coordinates of the border region 01116 * - just set the 'cur' rect to have the same coordinates as the border region 01117 * if zoom is allowed to be changed 01118 */ 01119 if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) { 01120 v2d->cur.xmin= rect.xmin; 01121 v2d->cur.xmax= rect.xmax; 01122 } 01123 if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) { 01124 v2d->cur.ymin= rect.ymin; 01125 v2d->cur.ymax= rect.ymax; 01126 } 01127 } 01128 else /* if (gesture_mode == GESTURE_MODAL_OUT) */ { 01129 /* zoom out: 01130 * - the current 'cur' rect coordinates are going to end upwhere the 'rect' ones are, 01131 * but the 'cur' rect coordinates will need to be adjusted to take in more of the view 01132 * - calculate zoom factor, and adjust using center-point 01133 */ 01134 float zoom, center, size; 01135 01136 // TODO: is this zoom factor calculation valid? It seems to produce same results everytime... 01137 if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) { 01138 size= (v2d->cur.xmax - v2d->cur.xmin); 01139 zoom= size / (rect.xmax - rect.xmin); 01140 center= (v2d->cur.xmax + v2d->cur.xmin) * 0.5f; 01141 01142 v2d->cur.xmin= center - (size * zoom); 01143 v2d->cur.xmax= center + (size * zoom); 01144 } 01145 if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) { 01146 size= (v2d->cur.ymax - v2d->cur.ymin); 01147 zoom= size / (rect.ymax - rect.ymin); 01148 center= (v2d->cur.ymax + v2d->cur.ymin) * 0.5f; 01149 01150 v2d->cur.ymin= center - (size * zoom); 01151 v2d->cur.ymax= center + (size * zoom); 01152 } 01153 } 01154 01155 /* validate that view is in valid configuration after this operation */ 01156 UI_view2d_curRect_validate(v2d); 01157 01158 /* request updates to be done... */ 01159 ED_region_tag_redraw(ar); 01160 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); 01161 01162 return OPERATOR_FINISHED; 01163 } 01164 01165 static void VIEW2D_OT_zoom_border(wmOperatorType *ot) 01166 { 01167 /* identifiers */ 01168 ot->name= "Zoom to Border"; 01169 ot->description= "Zoom in the view to the nearest item contained in the border"; 01170 ot->idname= "VIEW2D_OT_zoom_border"; 01171 01172 /* api callbacks */ 01173 ot->invoke= WM_border_select_invoke; 01174 ot->exec= view_borderzoom_exec; 01175 ot->modal= WM_border_select_modal; 01176 ot->cancel= WM_border_select_cancel; 01177 01178 ot->poll= view_zoom_poll; 01179 01180 /* rna */ 01181 RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX); 01182 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX); 01183 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX); 01184 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); 01185 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); 01186 } 01187 01188 /* ********************************************************* */ 01189 /* SCROLLERS */ 01190 01191 /* Scrollers should behave in the following ways, when clicked on with LMB (and dragged): 01192 * 1) 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable, 01193 * enlarge 'cur' rect on the relevant side 01194 * 2) 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite) 01195 * 01196 * In order to make sure this works, each operator must define the following RNA-Operator Props: 01197 * deltax, deltay - define how much to move view by (relative to zoom-correction factor) 01198 */ 01199 01200 /* customdata for scroller-invoke data */ 01201 typedef struct v2dScrollerMove { 01202 View2D *v2d; /* View2D data that this operation affects */ 01203 ARegion *ar; /* region that the scroller is in */ 01204 01205 short scroller; /* scroller that mouse is in ('h' or 'v') */ 01206 short zone; /* -1 is min zoomer, 0 is bar, 1 is max zoomer */ // XXX find some way to provide visual feedback of this (active color?) 01207 01208 float fac; /* view adjustment factor, based on size of region */ 01209 float delta; /* amount moved by mouse on axis of interest */ 01210 01211 float scrollbarwidth; /* width of the scrollbar itself, used for page up/down clicks */ 01212 01213 int lastx, lasty; /* previous mouse coordinates (in screen coordinates) for determining movement */ 01214 } v2dScrollerMove; 01215 01216 01217 /* View2DScrollers is typedef'd in UI_view2d.h 01218 * This is a CUT DOWN VERSION of the 'real' version, which is defined in view2d.c, as we only need focus bubble info 01219 * WARNING: the start of this struct must not change, so that it stays in sync with the 'real' version 01220 * For now, we don't need to have a separate (internal) header for structs like this... 01221 */ 01222 struct View2DScrollers { 01223 /* focus bubbles */ 01224 int vert_min, vert_max; /* vertical scrollbar */ 01225 int hor_min, hor_max; /* horizontal scrollbar */ 01226 }; 01227 01228 /* quick enum for vsm->zone (scroller handles) */ 01229 enum { 01230 SCROLLHANDLE_MIN= -1, 01231 SCROLLHANDLE_BAR, 01232 SCROLLHANDLE_MAX, 01233 SCROLLHANDLE_MIN_OUTSIDE, 01234 SCROLLHANDLE_MAX_OUTSIDE 01235 } /*eV2DScrollerHandle_Zone*/; 01236 01237 /* ------------------------ */ 01238 01239 /* check if mouse is within scroller handle 01240 * - mouse = relevant mouse coordinate in region space 01241 * - sc_min, sc_max = extents of scroller 'groove' (potential available space for scroller) 01242 * - sh_min, sh_max = positions of scrollbar handles 01243 */ 01244 static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max) 01245 { 01246 short in_min, in_max, in_bar, out_min, out_max, in_view=1; 01247 01248 /* firstly, check if 01249 * - 'bubble' fills entire scroller 01250 * - 'bubble' completely out of view on either side 01251 */ 01252 if ((sh_min <= sc_min) && (sh_max >= sc_max)) in_view= 0; 01253 if (sh_min == sh_max) { 01254 if (sh_min <= sc_min) in_view= 0; 01255 if (sh_max >= sc_max) in_view= 0; 01256 } 01257 else { 01258 if (sh_max <= sc_min) in_view= 0; 01259 if (sh_min >= sc_max) in_view= 0; 01260 } 01261 01262 01263 if (in_view == 0) { 01264 return SCROLLHANDLE_BAR; 01265 } 01266 01267 /* check if mouse is in or past either handle */ 01268 // TODO: check if these extents are still valid or not 01269 in_max= ( (mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse <= (sh_max + V2D_SCROLLER_HANDLE_SIZE)) ); 01270 in_min= ( (mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)) && (mouse >= (sh_min - V2D_SCROLLER_HANDLE_SIZE)) ); 01271 in_bar= ( (mouse < (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse > (sh_min + V2D_SCROLLER_HANDLE_SIZE)) ); 01272 out_min= mouse < (sh_min - V2D_SCROLLER_HANDLE_SIZE); 01273 out_max= mouse > (sh_max + V2D_SCROLLER_HANDLE_SIZE); 01274 01275 if (in_bar) 01276 return SCROLLHANDLE_BAR; 01277 else if (in_max) 01278 return SCROLLHANDLE_MAX; 01279 else if (in_min) 01280 return SCROLLHANDLE_MIN; 01281 else if (out_min) 01282 return SCROLLHANDLE_MIN_OUTSIDE; 01283 else if (out_max) 01284 return SCROLLHANDLE_MAX_OUTSIDE; 01285 01286 /* unlikely to happen, though we just cover it in case */ 01287 return SCROLLHANDLE_BAR; 01288 } 01289 01290 /* initialise customdata for scroller manipulation operator */ 01291 static void scroller_activate_init(bContext *C, wmOperator *op, wmEvent *event, short in_scroller) 01292 { 01293 v2dScrollerMove *vsm; 01294 View2DScrollers *scrollers; 01295 ARegion *ar= CTX_wm_region(C); 01296 View2D *v2d= &ar->v2d; 01297 float mask_size; 01298 01299 /* set custom-data for operator */ 01300 vsm= MEM_callocN(sizeof(v2dScrollerMove), "v2dScrollerMove"); 01301 op->customdata= vsm; 01302 01303 /* set general data */ 01304 vsm->v2d= v2d; 01305 vsm->ar= ar; 01306 vsm->scroller= in_scroller; 01307 01308 /* store mouse-coordinates, and convert mouse/screen coordinates to region coordinates */ 01309 vsm->lastx = event->x; 01310 vsm->lasty = event->y; 01311 01312 /* 'zone' depends on where mouse is relative to bubble 01313 * - zooming must be allowed on this axis, otherwise, default to pan 01314 */ 01315 scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); 01316 if (in_scroller == 'h') { 01317 /* horizontal scroller - calculate adjustment factor first */ 01318 mask_size= (float)(v2d->hor.xmax - v2d->hor.xmin); 01319 vsm->fac= (v2d->tot.xmax - v2d->tot.xmin) / mask_size; 01320 01321 /* get 'zone' (i.e. which part of scroller is activated) */ 01322 vsm->zone= mouse_in_scroller_handle(event->mval[0], v2d->hor.xmin, v2d->hor.xmax, scrollers->hor_min, scrollers->hor_max); 01323 01324 if ((v2d->keepzoom & V2D_LOCKZOOM_X) && ELEM(vsm->zone, SCROLLHANDLE_MIN, SCROLLHANDLE_MAX)) { 01325 /* default to scroll, as handles not usable */ 01326 vsm->zone= SCROLLHANDLE_BAR; 01327 } 01328 01329 vsm->scrollbarwidth = scrollers->hor_max - scrollers->hor_min; 01330 } 01331 else { 01332 /* vertical scroller - calculate adjustment factor first */ 01333 mask_size= (float)(v2d->vert.ymax - v2d->vert.ymin); 01334 vsm->fac= (v2d->tot.ymax - v2d->tot.ymin) / mask_size; 01335 01336 /* get 'zone' (i.e. which part of scroller is activated) */ 01337 vsm->zone= mouse_in_scroller_handle(event->mval[1], v2d->vert.ymin, v2d->vert.ymax, scrollers->vert_min, scrollers->vert_max); 01338 01339 if ((v2d->keepzoom & V2D_LOCKZOOM_Y) && ELEM(vsm->zone, SCROLLHANDLE_MIN, SCROLLHANDLE_MAX)) { 01340 /* default to scroll, as handles not usable */ 01341 vsm->zone= SCROLLHANDLE_BAR; 01342 } 01343 01344 vsm->scrollbarwidth = scrollers->vert_max - scrollers->vert_min; 01345 } 01346 01347 UI_view2d_scrollers_free(scrollers); 01348 ED_region_tag_redraw(ar); 01349 } 01350 01351 /* cleanup temp customdata */ 01352 static void scroller_activate_exit(bContext *C, wmOperator *op) 01353 { 01354 if (op->customdata) { 01355 v2dScrollerMove *vsm= op->customdata; 01356 01357 vsm->v2d->scroll_ui &= ~(V2D_SCROLL_H_ACTIVE|V2D_SCROLL_V_ACTIVE); 01358 01359 MEM_freeN(op->customdata); 01360 op->customdata= NULL; 01361 01362 ED_region_tag_redraw(CTX_wm_region(C)); 01363 } 01364 } 01365 01366 static int scroller_activate_cancel(bContext *C, wmOperator *op) 01367 { 01368 scroller_activate_exit(C, op); 01369 01370 return OPERATOR_CANCELLED; 01371 } 01372 01373 /* apply transform to view (i.e. adjust 'cur' rect) */ 01374 static void scroller_activate_apply(bContext *C, wmOperator *op) 01375 { 01376 v2dScrollerMove *vsm= op->customdata; 01377 View2D *v2d= vsm->v2d; 01378 float temp; 01379 01380 /* calculate amount to move view by */ 01381 temp= vsm->fac * vsm->delta; 01382 01383 /* type of movement */ 01384 switch (vsm->zone) { 01385 case SCROLLHANDLE_MIN: 01386 /* only expand view on axis if zoom is allowed */ 01387 if ((vsm->scroller == 'h') && !(v2d->keepzoom & V2D_LOCKZOOM_X)) 01388 v2d->cur.xmin -= temp; 01389 if ((vsm->scroller == 'v') && !(v2d->keepzoom & V2D_LOCKZOOM_Y)) 01390 v2d->cur.ymin -= temp; 01391 break; 01392 01393 case SCROLLHANDLE_MAX: 01394 01395 /* only expand view on axis if zoom is allowed */ 01396 if ((vsm->scroller == 'h') && !(v2d->keepzoom & V2D_LOCKZOOM_X)) 01397 v2d->cur.xmax += temp; 01398 if ((vsm->scroller == 'v') && !(v2d->keepzoom & V2D_LOCKZOOM_Y)) 01399 v2d->cur.ymax += temp; 01400 break; 01401 01402 case SCROLLHANDLE_MIN_OUTSIDE: 01403 case SCROLLHANDLE_MAX_OUTSIDE: 01404 case SCROLLHANDLE_BAR: 01405 default: 01406 /* only move view on an axis if panning is allowed */ 01407 if ((vsm->scroller == 'h') && !(v2d->keepofs & V2D_LOCKOFS_X)) { 01408 v2d->cur.xmin += temp; 01409 v2d->cur.xmax += temp; 01410 } 01411 if ((vsm->scroller == 'v') && !(v2d->keepofs & V2D_LOCKOFS_Y)) { 01412 v2d->cur.ymin += temp; 01413 v2d->cur.ymax += temp; 01414 } 01415 break; 01416 01417 } 01418 01419 /* validate that view is in valid configuration after this operation */ 01420 UI_view2d_curRect_validate(v2d); 01421 01422 /* request updates to be done... */ 01423 ED_region_tag_redraw(vsm->ar); 01424 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); 01425 } 01426 01427 /* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */ 01428 static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event) 01429 { 01430 v2dScrollerMove *vsm= op->customdata; 01431 01432 /* execute the events */ 01433 switch (event->type) { 01434 case MOUSEMOVE: 01435 { 01436 /* calculate new delta transform, then store mouse-coordinates for next-time */ 01437 if (ELEM(vsm->zone, SCROLLHANDLE_BAR, SCROLLHANDLE_MAX)) { 01438 /* if using bar (i.e. 'panning') or 'max' zoom widget */ 01439 switch (vsm->scroller) { 01440 case 'h': /* horizontal scroller - so only horizontal movement ('cur' moves opposite to mouse) */ 01441 vsm->delta= (float)(event->x - vsm->lastx); 01442 break; 01443 case 'v': /* vertical scroller - so only vertical movement ('cur' moves opposite to mouse) */ 01444 vsm->delta= (float)(event->y - vsm->lasty); 01445 break; 01446 } 01447 } 01448 else if (vsm->zone == SCROLLHANDLE_MIN) { 01449 /* using 'min' zoom widget */ 01450 switch (vsm->scroller) { 01451 case 'h': /* horizontal scroller - so only horizontal movement ('cur' moves with mouse) */ 01452 vsm->delta= (float)(vsm->lastx - event->x); 01453 break; 01454 case 'v': /* vertical scroller - so only vertical movement ('cur' moves with to mouse) */ 01455 vsm->delta= (float)(vsm->lasty - event->y); 01456 break; 01457 } 01458 } 01459 01460 /* store previous coordinates */ 01461 vsm->lastx= event->x; 01462 vsm->lasty= event->y; 01463 01464 scroller_activate_apply(C, op); 01465 } 01466 break; 01467 01468 case LEFTMOUSE: 01469 if (event->val==KM_RELEASE) { 01470 /* single-click was in empty space outside bubble, so scroll by 1 'page' */ 01471 if (ELEM(vsm->zone, SCROLLHANDLE_MIN_OUTSIDE, SCROLLHANDLE_MAX_OUTSIDE)) { 01472 if (vsm->zone == SCROLLHANDLE_MIN_OUTSIDE) 01473 vsm->delta = -vsm->scrollbarwidth * 0.8f; 01474 else if (vsm->zone == SCROLLHANDLE_MAX_OUTSIDE) 01475 vsm->delta = vsm->scrollbarwidth * 0.8f; 01476 01477 scroller_activate_apply(C, op); 01478 scroller_activate_exit(C, op); 01479 return OPERATOR_FINISHED; 01480 } 01481 01482 /* otherwise, end the drag action */ 01483 if (vsm->lastx || vsm->lasty) { 01484 scroller_activate_exit(C, op); 01485 return OPERATOR_FINISHED; 01486 } 01487 } 01488 break; 01489 } 01490 01491 return OPERATOR_RUNNING_MODAL; 01492 } 01493 01494 01495 /* a click (or click drag in progress) should have occurred, so check if it happened in scrollbar */ 01496 static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) 01497 { 01498 ARegion *ar= CTX_wm_region(C); 01499 View2D *v2d= &ar->v2d; 01500 short in_scroller= 0; 01501 01502 /* check if mouse in scrollbars, if they're enabled */ 01503 in_scroller= UI_view2d_mouse_in_scrollers(C, v2d, event->x, event->y); 01504 01505 /* if in a scroller, init customdata then set modal handler which will catch mousedown to start doing useful stuff */ 01506 if (in_scroller) { 01507 v2dScrollerMove *vsm; 01508 01509 /* initialise customdata */ 01510 scroller_activate_init(C, op, event, in_scroller); 01511 vsm= (v2dScrollerMove *)op->customdata; 01512 01513 /* check if zoom zones are inappropriate (i.e. zoom widgets not shown), so cannot continue 01514 * NOTE: see view2d.c for latest conditions, and keep this in sync with that 01515 */ 01516 if (ELEM(vsm->zone, SCROLLHANDLE_MIN, SCROLLHANDLE_MAX)) { 01517 if ( ((vsm->scroller=='h') && (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)==0) || 01518 ((vsm->scroller=='v') && (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)==0) ) 01519 { 01520 /* switch to bar (i.e. no scaling gets handled) */ 01521 vsm->zone= SCROLLHANDLE_BAR; 01522 } 01523 } 01524 01525 /* check if zone is inappropriate (i.e. 'bar' but panning is banned), so cannot continue */ 01526 if (vsm->zone == SCROLLHANDLE_BAR) { 01527 if ( ((vsm->scroller=='h') && (v2d->keepofs & V2D_LOCKOFS_X)) || 01528 ((vsm->scroller=='v') && (v2d->keepofs & V2D_LOCKOFS_Y)) ) 01529 { 01530 /* free customdata initialised */ 01531 scroller_activate_exit(C, op); 01532 01533 /* can't catch this event for ourselves, so let it go to someone else? */ 01534 return OPERATOR_PASS_THROUGH; 01535 } 01536 } 01537 01538 /* zone is also inappropriate if scroller is not visible... */ 01539 if ( ((vsm->scroller=='h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE|V2D_SCROLL_HORIZONTAL_FULLR))) || 01540 ((vsm->scroller=='v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE|V2D_SCROLL_VERTICAL_FULLR))) ) 01541 { 01542 /* free customdata initialised */ 01543 scroller_activate_exit(C, op); 01544 01545 /* can't catch this event for ourselves, so let it go to someone else? */ 01546 /* XXX note: if handlers use mask rect to clip input, input will fail for this case */ 01547 return OPERATOR_PASS_THROUGH; 01548 } 01549 01550 /* activate the scroller */ 01551 if (vsm->scroller=='h') 01552 v2d->scroll_ui |= V2D_SCROLL_H_ACTIVE; 01553 else 01554 v2d->scroll_ui |= V2D_SCROLL_V_ACTIVE; 01555 01556 /* still ok, so can add */ 01557 WM_event_add_modal_handler(C, op); 01558 return OPERATOR_RUNNING_MODAL; 01559 } 01560 else { 01561 /* not in scroller, so nothing happened... (pass through let's something else catch event) */ 01562 return OPERATOR_PASS_THROUGH; 01563 } 01564 } 01565 01566 /* LMB-Drag in Scrollers - not repeatable operator! */ 01567 static void VIEW2D_OT_scroller_activate(wmOperatorType *ot) 01568 { 01569 /* identifiers */ 01570 ot->name= "Scroller Activate"; 01571 ot->description= "Scroll view by mouse click and drag"; 01572 ot->idname= "VIEW2D_OT_scroller_activate"; 01573 01574 /* flags */ 01575 ot->flag= OPTYPE_BLOCKING; 01576 01577 /* api callbacks */ 01578 ot->invoke= scroller_activate_invoke; 01579 ot->modal= scroller_activate_modal; 01580 ot->cancel= scroller_activate_cancel; 01581 01582 ot->poll= view2d_poll; 01583 } 01584 01585 /* ********************************************************* */ 01586 /* RESET */ 01587 01588 static int reset_exec(bContext *C, wmOperator *UNUSED(op)) 01589 { 01590 uiStyle *style= U.uistyles.first; 01591 ARegion *ar= CTX_wm_region(C); 01592 View2D *v2d= &ar->v2d; 01593 int winx, winy; 01594 01595 /* zoom 1.0 */ 01596 winx= (float)(v2d->mask.xmax - v2d->mask.xmin + 1); 01597 winy= (float)(v2d->mask.ymax - v2d->mask.ymin + 1); 01598 01599 v2d->cur.xmax= v2d->cur.xmin + winx; 01600 v2d->cur.ymax= v2d->cur.ymin + winy; 01601 01602 /* align */ 01603 if (v2d->align) { 01604 /* posx and negx flags are mutually exclusive, so watch out */ 01605 if ((v2d->align & V2D_ALIGN_NO_POS_X) && !(v2d->align & V2D_ALIGN_NO_NEG_X)) { 01606 v2d->cur.xmax= 0.0f; 01607 v2d->cur.xmin= -winx*style->panelzoom; 01608 } 01609 else if ((v2d->align & V2D_ALIGN_NO_NEG_X) && !(v2d->align & V2D_ALIGN_NO_POS_X)) { 01610 v2d->cur.xmax= winx*style->panelzoom; 01611 v2d->cur.xmin= 0.0f; 01612 } 01613 01614 /* - posx and negx flags are mutually exclusive, so watch out */ 01615 if ((v2d->align & V2D_ALIGN_NO_POS_Y) && !(v2d->align & V2D_ALIGN_NO_NEG_Y)) { 01616 v2d->cur.ymax= 0.0f; 01617 v2d->cur.ymin= -winy*style->panelzoom; 01618 } 01619 else if ((v2d->align & V2D_ALIGN_NO_NEG_Y) && !(v2d->align & V2D_ALIGN_NO_POS_Y)) { 01620 v2d->cur.ymax= winy*style->panelzoom; 01621 v2d->cur.ymin= 0.0f; 01622 } 01623 } 01624 01625 /* validate that view is in valid configuration after this operation */ 01626 UI_view2d_curRect_validate(v2d); 01627 01628 /* request updates to be done... */ 01629 ED_region_tag_redraw(ar); 01630 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); 01631 01632 return OPERATOR_FINISHED; 01633 } 01634 01635 static void VIEW2D_OT_reset(wmOperatorType *ot) 01636 { 01637 /* identifiers */ 01638 ot->name= "Reset View"; 01639 ot->description= "Reset the view"; 01640 ot->idname= "VIEW2D_OT_reset"; 01641 01642 /* api callbacks */ 01643 ot->exec= reset_exec; 01644 ot->poll= view2d_poll; 01645 } 01646 01647 /* ********************************************************* */ 01648 /* Registration */ 01649 01650 void UI_view2d_operatortypes(void) 01651 { 01652 WM_operatortype_append(VIEW2D_OT_pan); 01653 01654 WM_operatortype_append(VIEW2D_OT_scroll_left); 01655 WM_operatortype_append(VIEW2D_OT_scroll_right); 01656 WM_operatortype_append(VIEW2D_OT_scroll_up); 01657 WM_operatortype_append(VIEW2D_OT_scroll_down); 01658 01659 WM_operatortype_append(VIEW2D_OT_zoom_in); 01660 WM_operatortype_append(VIEW2D_OT_zoom_out); 01661 01662 WM_operatortype_append(VIEW2D_OT_zoom); 01663 WM_operatortype_append(VIEW2D_OT_zoom_border); 01664 01665 WM_operatortype_append(VIEW2D_OT_scroller_activate); 01666 01667 WM_operatortype_append(VIEW2D_OT_reset); 01668 } 01669 01670 void UI_view2d_keymap(wmKeyConfig *keyconf) 01671 { 01672 wmKeyMap *keymap= WM_keymap_find(keyconf, "View2D", 0, 0); 01673 01674 /* pan/scroll */ 01675 WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); 01676 WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); 01677 01678 WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MOUSEPAN, 0, 0, 0); 01679 01680 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0); 01681 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0); 01682 01683 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0); 01684 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0); 01685 01686 /* zoom - single step */ 01687 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0); 01688 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0); 01689 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0); 01690 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0); 01691 01692 /* scroll up/down - no modifiers, only when zoom fails */ 01693 /* these may fail if zoom is disallowed, in which case they should pass on event */ 01694 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, 0, 0); 01695 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, 0, 0); 01696 /* these may be necessary if vertical scroll is disallowed */ 01697 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", WHEELDOWNMOUSE, KM_PRESS, 0, 0); 01698 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", WHEELUPMOUSE, KM_PRESS, 0, 0); 01699 01700 /* alternatives for page up/down to scroll */ 01701 #if 0 // XXX disabled, since this causes conflicts with hotkeys in animation editors 01702 /* scroll up/down may fall through to left/right */ 01703 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", PAGEDOWNKEY, KM_PRESS, 0, 0); 01704 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", PAGEUPKEY, KM_PRESS, 0, 0); 01705 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", PAGEDOWNKEY, KM_PRESS, 0, 0); 01706 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", PAGEUPKEY, KM_PRESS, 0, 0); 01707 /* shift for moving view left/right with page up/down */ 01708 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0); 01709 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0); 01710 #endif 01711 01712 /* zoom - drag */ 01713 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); 01714 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0); 01715 01716 /* borderzoom - drag */ 01717 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0); 01718 01719 /* scrollers */ 01720 WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", LEFTMOUSE, KM_PRESS, 0, 0); 01721 01722 /* Alternative keymap for buttons listview */ 01723 keymap= WM_keymap_find(keyconf, "View2D Buttons List", 0, 0); 01724 WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); 01725 WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MOUSEPAN, 0, 0, 0); 01726 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, 0, 0); 01727 WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, 0, 0); 01728 01729 RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "page", 1); 01730 RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "page", 1); 01731 01732 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); 01733 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0); 01734 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0); 01735 WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0); 01736 WM_keymap_add_item(keymap, "VIEW2D_OT_reset", HOMEKEY, KM_PRESS, 0, 0); 01737 WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", LEFTMOUSE, KM_PRESS, 0, 0); 01738 } 01739