Blender  V2.93
view2d_ops.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "DNA_userdef_types.h"
30 
31 #include "BLI_blenlib.h"
32 #include "BLI_math_base.h"
33 #include "BLI_math_vector.h"
34 #include "BLI_utildefines.h"
35 
36 #include "BKE_context.h"
37 
38 #include "RNA_access.h"
39 #include "RNA_define.h"
40 
41 #include "WM_api.h"
42 #include "WM_types.h"
43 
44 #include "ED_screen.h"
45 
46 #include "UI_interface.h"
47 #include "UI_view2d.h"
48 
49 #include "PIL_time.h" /* USER_ZOOM_CONTINUE */
50 
51 /* -------------------------------------------------------------------- */
55 static bool view2d_poll(bContext *C)
56 {
57  ARegion *region = CTX_wm_region(C);
58 
59  return (region != NULL) && (region->v2d.flag & V2D_IS_INIT);
60 }
61 
64 /* -------------------------------------------------------------------- */
80 typedef struct v2dViewPanData {
89 
91  float facx, facy;
92 
93  /* options for version 1 */
95  int startx, starty;
97  int lastx, lasty;
100 
102  short in_scroller;
103 
104  /* View2D Edge Panning */
108 
109 static bool view_pan_poll(bContext *C)
110 {
111  ARegion *region = CTX_wm_region(C);
112 
113  /* check if there's a region in context to work with */
114  if (region == NULL) {
115  return false;
116  }
117 
118  View2D *v2d = &region->v2d;
119 
120  /* check that 2d-view can pan */
121  if ((v2d->keepofs & V2D_LOCKOFS_X) && (v2d->keepofs & V2D_LOCKOFS_Y)) {
122  return false;
123  }
124 
125  /* view can pan */
126  return true;
127 }
128 
129 /* initialize panning customdata */
130 static void view_pan_init(bContext *C, wmOperator *op)
131 {
132  /* Should've been checked before. */
134 
135  /* set custom-data for operator */
136  v2dViewPanData *vpd = MEM_callocN(sizeof(v2dViewPanData), "v2dViewPanData");
137  op->customdata = vpd;
138 
139  /* set pointers to owners */
140  vpd->screen = CTX_wm_screen(C);
141  vpd->area = CTX_wm_area(C);
142  vpd->region = CTX_wm_region(C);
143  vpd->v2d = &vpd->region->v2d;
144 
145  /* calculate translation factor - based on size of view */
146  const float winx = (float)(BLI_rcti_size_x(&vpd->region->winrct) + 1);
147  const float winy = (float)(BLI_rcti_size_y(&vpd->region->winrct) + 1);
148  vpd->facx = (BLI_rctf_size_x(&vpd->v2d->cur)) / winx;
149  vpd->facy = (BLI_rctf_size_y(&vpd->v2d->cur)) / winy;
150 }
151 
152 /* apply transform to view (i.e. adjust 'cur' rect) */
153 static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float dy)
154 {
155  View2D *v2d = vpd->v2d;
156 
157  /* calculate amount to move view by */
158  dx *= vpd->facx;
159  dy *= vpd->facy;
160 
161  /* only move view on an axis if change is allowed */
162  if ((v2d->keepofs & V2D_LOCKOFS_X) == 0) {
163  v2d->cur.xmin += dx;
164  v2d->cur.xmax += dx;
165  }
166  if ((v2d->keepofs & V2D_LOCKOFS_Y) == 0) {
167  v2d->cur.ymin += dy;
168  v2d->cur.ymax += dy;
169  }
170 
171  /* Inform v2d about changes after this operation. */
173 
174  /* don't rebuild full tree in outliner, since we're just changing our view */
176 
177  /* request updates to be done... */
179 
180  UI_view2d_sync(vpd->screen, vpd->area, v2d, V2D_LOCK_COPY);
181 }
182 
184 {
185  v2dViewPanData *vpd = op->customdata;
186 
187  view_pan_apply_ex(C, vpd, RNA_int_get(op->ptr, "deltax"), RNA_int_get(op->ptr, "deltay"));
188 }
189 
190 /* cleanup temp customdata */
191 static void view_pan_exit(wmOperator *op)
192 {
194 }
195 
198 /* -------------------------------------------------------------------- */
202 /* for 'redo' only, with no user input */
204 {
205  view_pan_init(C, op);
206  view_pan_apply(C, op);
207  view_pan_exit(op);
208  return OPERATOR_FINISHED;
209 }
210 
211 /* set up modal operator and relevant settings */
212 static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
213 {
214  wmWindow *window = CTX_wm_window(C);
215 
216  /* set up customdata */
217  view_pan_init(C, op);
218 
219  v2dViewPanData *vpd = op->customdata;
220  View2D *v2d = vpd->v2d;
221 
222  /* set initial settings */
223  vpd->startx = vpd->lastx = event->x;
224  vpd->starty = vpd->lasty = event->y;
225  vpd->invoke_event = event->type;
226 
227  if (event->type == MOUSEPAN) {
228  RNA_int_set(op->ptr, "deltax", event->prevx - event->x);
229  RNA_int_set(op->ptr, "deltay", event->prevy - event->y);
230 
231  view_pan_apply(C, op);
232  view_pan_exit(op);
233  return OPERATOR_FINISHED;
234  }
235 
236  RNA_int_set(op->ptr, "deltax", 0);
237  RNA_int_set(op->ptr, "deltay", 0);
238 
239  if (v2d->keepofs & V2D_LOCKOFS_X) {
241  }
242  else if (v2d->keepofs & V2D_LOCKOFS_Y) {
244  }
245  else {
247  }
248 
249  /* add temp handler */
251 
252  return OPERATOR_RUNNING_MODAL;
253 }
254 
255 /* handle user input - calculations of mouse-movement
256  * need to be done here, not in the apply callback! */
257 static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
258 {
259  v2dViewPanData *vpd = op->customdata;
260 
261  /* execute the events */
262  switch (event->type) {
263  case MOUSEMOVE: {
264  /* calculate new delta transform, then store mouse-coordinates for next-time */
265  RNA_int_set(op->ptr, "deltax", (vpd->lastx - event->x));
266  RNA_int_set(op->ptr, "deltay", (vpd->lasty - event->y));
267 
268  vpd->lastx = event->x;
269  vpd->lasty = event->y;
270 
271  view_pan_apply(C, op);
272  break;
273  }
274  /* XXX - Mode switching isn't implemented. See comments in 36818.
275  * switch to zoom */
276 #if 0
277  case LEFTMOUSE:
278  if (event->val == KM_PRESS) {
279  /* calculate overall delta mouse-movement for redo */
280  RNA_int_set(op->ptr, "deltax", (vpd->startx - vpd->lastx));
281  RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty));
282 
283  view_pan_exit(op);
285  WM_operator_name_call(C, "VIEW2D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
286  return OPERATOR_FINISHED;
287  }
288 #endif
289  default:
290  if (ELEM(event->type, vpd->invoke_event, EVT_ESCKEY)) {
291  if (event->val == KM_RELEASE) {
292  /* calculate overall delta mouse-movement for redo */
293  RNA_int_set(op->ptr, "deltax", (vpd->startx - vpd->lastx));
294  RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty));
295 
296  view_pan_exit(op);
298 
299  return OPERATOR_FINISHED;
300  }
301  }
302  break;
303  }
304 
305  return OPERATOR_RUNNING_MODAL;
306 }
307 
309 {
310  view_pan_exit(op);
311 }
312 
314 {
315  /* identifiers */
316  ot->name = "Pan View";
317  ot->description = "Pan the view";
318  ot->idname = "VIEW2D_OT_pan";
319 
320  /* api callbacks */
321  ot->exec = view_pan_exec;
325  ot->poll = view_pan_poll;
326 
327  /* operator is modal */
329 
330  /* rna - must keep these in sync with the other operators */
331  RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
332  RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX);
333 }
334 
337 /* -------------------------------------------------------------------- */
345 #define EDGE_PAN_REGION_PAD (U.widget_unit)
347 #define EDGE_PAN_SPEED_PER_PIXEL (25.0f * (float)U.dpi_fac)
349 #define EDGE_PAN_DELAY 1.0f
350 
351 /* set up modal operator and relevant settings */
352 static int view_edge_pan_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
353 {
354  /* Set up customdata. */
355  view_pan_init(C, op);
356 
357  v2dViewPanData *vpd = op->customdata;
358 
359  vpd->edge_pan_start_time_x = 0.0;
360  vpd->edge_pan_start_time_y = 0.0;
362 
364 
366 }
367 
373  int pan_dir_x,
374  int pan_dir_y,
375  const double current_time)
376 {
377  if (pan_dir_x == 0) {
378  vpd->edge_pan_start_time_x = 0.0;
379  }
380  else if (vpd->edge_pan_start_time_x == 0.0) {
381  vpd->edge_pan_start_time_x = current_time;
382  }
383  if (pan_dir_y == 0) {
384  vpd->edge_pan_start_time_y = 0.0;
385  }
386  else if (vpd->edge_pan_start_time_y == 0.0) {
387  vpd->edge_pan_start_time_y = current_time;
388  }
389 }
390 
397 static float smootherstep(const float domain_max, float x)
398 {
399  x = clamp_f(x / domain_max, 0.0, 1.0);
400  return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
401 }
402 
403 static float edge_pan_speed(v2dViewPanData *vpd,
404  int event_loc,
405  bool x_dir,
406  const double current_time)
407 {
408  ARegion *region = vpd->region;
409 
410  /* Find the distance from the start of the drag zone. */
411  const int min = (x_dir ? region->winrct.xmin : region->winrct.ymin) + EDGE_PAN_REGION_PAD;
412  const int max = (x_dir ? region->winrct.xmax : region->winrct.ymax) - EDGE_PAN_REGION_PAD;
413  int distance = 0.0;
414  if (event_loc > max) {
415  distance = event_loc - max;
416  }
417  else if (event_loc < min) {
418  distance = min - event_loc;
419  }
420  else {
421  BLI_assert(!"Calculating speed outside of pan zones");
422  return 0.0f;
423  }
424 
425  /* Apply a fade in to the speed based on a start time delay. */
426  const double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y;
427  const float delay_factor = smootherstep(EDGE_PAN_DELAY, (float)(current_time - start_time));
428 
429  return distance * EDGE_PAN_SPEED_PER_PIXEL * delay_factor;
430 }
431 
432 static int view_edge_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
433 {
434  v2dViewPanData *vpd = op->customdata;
435  ARegion *region = vpd->region;
436 
437  if (event->val == KM_RELEASE || event->type == EVT_ESCKEY) {
438  view_pan_exit(op);
440  }
441  /* Only mousemove events matter here, ignore others. */
442  if (event->type != MOUSEMOVE) {
443  return OPERATOR_PASS_THROUGH;
444  }
445 
446  /* This operator is supposed to run together with some drag action.
447  * On successful handling, always pass events on to other handlers. */
448  const int success_retval = OPERATOR_PASS_THROUGH;
449 
450  const int outside_padding = RNA_int_get(op->ptr, "outside_padding") * UI_UNIT_X;
451  rcti padding_rect;
452  if (outside_padding != 0) {
453  padding_rect = region->winrct;
454  BLI_rcti_pad(&padding_rect, outside_padding, outside_padding);
455  }
456 
457  int pan_dir_x = 0;
458  int pan_dir_y = 0;
459  if ((outside_padding == 0) || BLI_rcti_isect_pt(&padding_rect, event->x, event->y)) {
460  /* Find whether the mouse is beyond X and Y edges. */
461  if (event->x > region->winrct.xmax - EDGE_PAN_REGION_PAD) {
462  pan_dir_x = 1;
463  }
464  else if (event->x < region->winrct.xmin + EDGE_PAN_REGION_PAD) {
465  pan_dir_x = -1;
466  }
467  if (event->y > region->winrct.ymax - EDGE_PAN_REGION_PAD) {
468  pan_dir_y = 1;
469  }
470  else if (event->y < region->winrct.ymin + EDGE_PAN_REGION_PAD) {
471  pan_dir_y = -1;
472  }
473  }
474 
475  const double current_time = PIL_check_seconds_timer();
476  edge_pan_manage_delay_timers(vpd, pan_dir_x, pan_dir_y, current_time);
477 
478  /* Calculate the delta since the last time the operator was called. */
479  const float dtime = (float)(current_time - vpd->edge_pan_last_time);
480  float dx = 0.0f, dy = 0.0f;
481  if (pan_dir_x != 0) {
482  const float speed = edge_pan_speed(vpd, event->x, true, current_time);
483  dx = dtime * speed * (float)pan_dir_x;
484  }
485  if (pan_dir_y != 0) {
486  const float speed = edge_pan_speed(vpd, event->y, false, current_time);
487  dy = dtime * speed * (float)pan_dir_y;
488  }
489  vpd->edge_pan_last_time = current_time;
490 
491  /* Pan, clamping inside the regions's total bounds. */
492  view_pan_apply_ex(C, vpd, dx, dy);
493 
494  return success_retval;
495 }
496 
498 {
499  view_pan_exit(op);
500 }
501 
503 {
504  /* identifiers */
505  ot->name = "View Edge Pan";
506  ot->description = "Pan the view when the mouse is held at an edge";
507  ot->idname = "VIEW2D_OT_edge_pan";
508 
509  /* api callbacks */
513  ot->poll = view_pan_poll;
514 
515  /* operator is modal */
518  "outside_padding",
519  0,
520  0,
521  100,
522  "Outside Padding",
523  "Padding around the region in UI units within which panning is activated (0 to "
524  "disable boundary)",
525  0,
526  100);
527 }
528 
529 #undef EDGE_PAN_REGION_PAD
530 #undef EDGE_PAN_SPEED_PER_PIXEL
531 #undef EDGE_PAN_DELAY
532 
535 /* -------------------------------------------------------------------- */
539 /* this operator only needs this single callback, where it calls the view_pan_*() methods */
541 {
542  v2dViewPanData *vpd;
543 
544  /* initialize default settings (and validate if ok to run) */
545  view_pan_init(C, op);
546 
547  /* also, check if can pan in horizontal axis */
548  vpd = op->customdata;
549  if (vpd->v2d->keepofs & V2D_LOCKOFS_X) {
550  view_pan_exit(op);
551  return OPERATOR_PASS_THROUGH;
552  }
553 
554  /* set RNA-Props - only movement in positive x-direction */
555  RNA_int_set(op->ptr, "deltax", 40);
556  RNA_int_set(op->ptr, "deltay", 0);
557 
558  /* apply movement, then we're done */
559  view_pan_apply(C, op);
560  view_pan_exit(op);
561 
562  return OPERATOR_FINISHED;
563 }
564 
566 {
567  /* identifiers */
568  ot->name = "Scroll Right";
569  ot->description = "Scroll the view right";
570  ot->idname = "VIEW2D_OT_scroll_right";
571 
572  /* api callbacks */
574  ot->poll = view_pan_poll;
575 
576  /* rna - must keep these in sync with the other operators */
577  RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
578  RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX);
579 }
580 
581 /* this operator only needs this single callback, where it calls the view_pan_*() methods */
583 {
584  v2dViewPanData *vpd;
585 
586  /* initialize default settings (and validate if ok to run) */
587  view_pan_init(C, op);
588 
589  /* also, check if can pan in horizontal axis */
590  vpd = op->customdata;
591  if (vpd->v2d->keepofs & V2D_LOCKOFS_X) {
592  view_pan_exit(op);
593  return OPERATOR_PASS_THROUGH;
594  }
595 
596  /* set RNA-Props - only movement in negative x-direction */
597  RNA_int_set(op->ptr, "deltax", -40);
598  RNA_int_set(op->ptr, "deltay", 0);
599 
600  /* apply movement, then we're done */
601  view_pan_apply(C, op);
602  view_pan_exit(op);
603 
604  return OPERATOR_FINISHED;
605 }
606 
608 {
609  /* identifiers */
610  ot->name = "Scroll Left";
611  ot->description = "Scroll the view left";
612  ot->idname = "VIEW2D_OT_scroll_left";
613 
614  /* api callbacks */
616  ot->poll = view_pan_poll;
617 
618  /* rna - must keep these in sync with the other operators */
619  RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
620  RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX);
621 }
622 
623 /* this operator only needs this single callback, where it calls the view_pan_*() methods */
625 {
626  v2dViewPanData *vpd;
627 
628  /* initialize default settings (and validate if ok to run) */
629  view_pan_init(C, op);
630 
631  /* also, check if can pan in vertical axis */
632  vpd = op->customdata;
633  if (vpd->v2d->keepofs & V2D_LOCKOFS_Y) {
634  view_pan_exit(op);
635  return OPERATOR_PASS_THROUGH;
636  }
637 
638  /* set RNA-Props */
639  RNA_int_set(op->ptr, "deltax", 0);
640  RNA_int_set(op->ptr, "deltay", -40);
641 
642  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
643  if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
644  ARegion *region = CTX_wm_region(C);
645  RNA_int_set(op->ptr, "deltay", region->v2d.mask.ymin - region->v2d.mask.ymax);
646  }
647 
648  /* apply movement, then we're done */
649  view_pan_apply(C, op);
650  view_pan_exit(op);
651 
652  return OPERATOR_FINISHED;
653 }
654 
656 {
657  /* identifiers */
658  ot->name = "Scroll Down";
659  ot->description = "Scroll the view down";
660  ot->idname = "VIEW2D_OT_scroll_down";
661 
662  /* api callbacks */
664  ot->poll = view_pan_poll;
665 
666  /* rna - must keep these in sync with the other operators */
667  RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
668  RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX);
669  RNA_def_boolean(ot->srna, "page", 0, "Page", "Scroll down one page");
670 }
671 
672 /* this operator only needs this single callback, where it calls the view_pan_*() methods */
674 {
675  v2dViewPanData *vpd;
676 
677  /* initialize default settings (and validate if ok to run) */
678  view_pan_init(C, op);
679 
680  /* also, check if can pan in vertical axis */
681  vpd = op->customdata;
682  if (vpd->v2d->keepofs & V2D_LOCKOFS_Y) {
683  view_pan_exit(op);
684  return OPERATOR_PASS_THROUGH;
685  }
686 
687  /* set RNA-Props */
688  RNA_int_set(op->ptr, "deltax", 0);
689  RNA_int_set(op->ptr, "deltay", 40);
690 
691  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
692  if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
693  ARegion *region = CTX_wm_region(C);
694  RNA_int_set(op->ptr, "deltay", BLI_rcti_size_y(&region->v2d.mask));
695  }
696 
697  /* apply movement, then we're done */
698  view_pan_apply(C, op);
699  view_pan_exit(op);
700 
701  return OPERATOR_FINISHED;
702 }
703 
705 {
706  /* identifiers */
707  ot->name = "Scroll Up";
708  ot->description = "Scroll the view up";
709  ot->idname = "VIEW2D_OT_scroll_up";
710 
711  /* api callbacks */
713  ot->poll = view_pan_poll;
714 
715  /* rna - must keep these in sync with the other operators */
716  RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
717  RNA_def_int(ot->srna, "deltay", 0, INT_MIN, INT_MAX, "Delta Y", "", INT_MIN, INT_MAX);
718  RNA_def_boolean(ot->srna, "page", 0, "Page", "Scroll up one page");
719 }
720 
723 /* -------------------------------------------------------------------- */
744 typedef struct v2dViewZoomData {
745  View2D *v2d; /* view2d we're operating in */
747 
748  /* needed for continuous zoom */
751 
752  int lastx, lasty; /* previous x/y values of mouse in window */
753  int invoke_event; /* event type that invoked, for modal exits */
754  float dx, dy; /* running tally of previous delta values (for obtaining final zoom) */
755  float mx_2d, my_2d; /* initial mouse location in v2d coords */
758 
763 static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2])
764 {
766 
767  r_do_zoom_xy[0] = true;
768  r_do_zoom_xy[1] = true;
769 
770  /* default not to zoom the sequencer vertically */
771  if (area && area->spacetype == SPACE_SEQ) {
772  ARegion *region = CTX_wm_region(C);
773 
774  if (region && region->regiontype == RGN_TYPE_WINDOW) {
775  r_do_zoom_xy[1] = false;
776  }
777  }
778 }
779 
780 /* check if step-zoom can be applied */
781 static bool view_zoom_poll(bContext *C)
782 {
783  ARegion *region = CTX_wm_region(C);
784 
785  /* check if there's a region in context to work with */
786  if (region == NULL) {
787  return false;
788  }
789 
790  /* Do not show that in 3DView context. */
791  if (CTX_wm_region_view3d(C)) {
792  return false;
793  }
794 
795  View2D *v2d = &region->v2d;
796 
797  /* check that 2d-view is zoomable */
798  if ((v2d->keepzoom & V2D_LOCKZOOM_X) && (v2d->keepzoom & V2D_LOCKZOOM_Y)) {
799  return false;
800  }
801 
802  /* view is zoomable */
803  return true;
804 }
805 
806 /* initialize panning customdata */
808 {
809  /* Should've been checked before. */
811 
812  /* set custom-data for operator */
813  v2dViewZoomData *vzd = MEM_callocN(sizeof(v2dViewZoomData), "v2dViewZoomData");
814  op->customdata = vzd;
815 
816  /* set pointers to owners */
817  vzd->region = CTX_wm_region(C);
818  vzd->v2d = &vzd->region->v2d;
819  /* False by default. Interactive callbacks (ie invoke()) can set it to true. */
820  vzd->zoom_to_mouse_pos = false;
821 }
822 
823 /* apply transform to view (i.e. adjust 'cur' rect) */
825  v2dViewZoomData *vzd,
826  const float facx,
827  const float facy)
828 {
829  ARegion *region = CTX_wm_region(C);
830  View2D *v2d = &region->v2d;
831  const rctf cur_old = v2d->cur;
832  const int snap_test = ED_region_snap_size_test(region);
833 
834  /* calculate amount to move view by, ensuring symmetry so the
835  * old zoom level is restored after zooming back the same amount
836  */
837  float dx, dy;
838  if (facx >= 0.0f) {
839  dx = BLI_rctf_size_x(&v2d->cur) * facx;
840  dy = BLI_rctf_size_y(&v2d->cur) * facy;
841  }
842  else {
843  dx = (BLI_rctf_size_x(&v2d->cur) / (1.0f + 2.0f * facx)) * facx;
844  dy = (BLI_rctf_size_y(&v2d->cur) / (1.0f + 2.0f * facy)) * facy;
845  }
846 
847  /* only resize view on an axis if change is allowed */
848  if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0) {
849  if (v2d->keepofs & V2D_LOCKOFS_X) {
850  v2d->cur.xmax -= 2 * dx;
851  }
852  else if (v2d->keepofs & V2D_KEEPOFS_X) {
853  if (v2d->align & V2D_ALIGN_NO_POS_X) {
854  v2d->cur.xmin += 2 * dx;
855  }
856  else {
857  v2d->cur.xmax -= 2 * dx;
858  }
859  }
860  else {
861 
862  v2d->cur.xmin += dx;
863  v2d->cur.xmax -= dx;
864 
865  if (vzd->zoom_to_mouse_pos) {
866  /* get zoom fac the same way as in
867  * ui_view2d_curRect_validate_resize - better keep in sync! */
868  const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
869 
870  /* only move view to mouse if zoom fac is inside minzoom/maxzoom */
871  if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
872  IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom)) {
873  const float mval_fac = (vzd->mx_2d - cur_old.xmin) / BLI_rctf_size_x(&cur_old);
874  const float mval_faci = 1.0f - mval_fac;
875  const float ofs = (mval_fac * dx) - (mval_faci * dx);
876 
877  v2d->cur.xmin += ofs;
878  v2d->cur.xmax += ofs;
879  }
880  }
881  }
882  }
883  if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0) {
884  if (v2d->keepofs & V2D_LOCKOFS_Y) {
885  v2d->cur.ymax -= 2 * dy;
886  }
887  else if (v2d->keepofs & V2D_KEEPOFS_Y) {
888  if (v2d->align & V2D_ALIGN_NO_POS_Y) {
889  v2d->cur.ymin += 2 * dy;
890  }
891  else {
892  v2d->cur.ymax -= 2 * dy;
893  }
894  }
895  else {
896 
897  v2d->cur.ymin += dy;
898  v2d->cur.ymax -= dy;
899 
900  if (vzd->zoom_to_mouse_pos) {
901  /* get zoom fac the same way as in
902  * ui_view2d_curRect_validate_resize - better keep in sync! */
903  const float zoomy = (float)(BLI_rcti_size_y(&v2d->mask) + 1) / BLI_rctf_size_y(&v2d->cur);
904 
905  /* only move view to mouse if zoom fac is inside minzoom/maxzoom */
906  if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
907  IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom)) {
908  const float mval_fac = (vzd->my_2d - cur_old.ymin) / BLI_rctf_size_y(&cur_old);
909  const float mval_faci = 1.0f - mval_fac;
910  const float ofs = (mval_fac * dy) - (mval_faci * dy);
911 
912  v2d->cur.ymin += ofs;
913  v2d->cur.ymax += ofs;
914  }
915  }
916  }
917  }
918 
919  /* Inform v2d about changes after this operation. */
921 
922  if (ED_region_snap_size_apply(region, snap_test)) {
926  }
927 
928  /* request updates to be done... */
931 }
932 
934 {
935  v2dViewZoomData *vzd = op->customdata;
937  C, vzd, RNA_float_get(op->ptr, "zoomfacx"), RNA_float_get(op->ptr, "zoomfacy"));
938 }
939 
942 /* -------------------------------------------------------------------- */
946 /* cleanup temp customdata */
948 {
950 
952 }
953 
954 /* this operator only needs this single callback, where it calls the view_zoom_*() methods */
956 {
957  if (op->customdata == NULL) { /* Might have been setup in _invoke() already. */
958  view_zoomdrag_init(C, op);
959  }
960 
961  bool do_zoom_xy[2];
962  view_zoom_axis_lock_defaults(C, do_zoom_xy);
963 
964  /* set RNA-Props - zooming in by uniform factor */
965  RNA_float_set(op->ptr, "zoomfacx", do_zoom_xy[0] ? 0.0375f : 0.0f);
966  RNA_float_set(op->ptr, "zoomfacy", do_zoom_xy[1] ? 0.0375f : 0.0f);
967 
968  /* apply movement, then we're done */
969  view_zoomstep_apply(C, op);
970 
971  view_zoomstep_exit(op);
972 
973  return OPERATOR_FINISHED;
974 }
975 
976 static int view_zoomin_invoke(bContext *C, wmOperator *op, const wmEvent *event)
977 {
978  view_zoomdrag_init(C, op);
979 
980  v2dViewZoomData *vzd = op->customdata;
981 
982  if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
983  ARegion *region = CTX_wm_region(C);
984 
985  /* store initial mouse position (in view space) */
987  &region->v2d, event->mval[0], event->mval[1], &vzd->mx_2d, &vzd->my_2d);
988  vzd->zoom_to_mouse_pos = true;
989  }
990 
991  return view_zoomin_exec(C, op);
992 }
993 
995 {
996  PropertyRNA *prop;
997 
998  /* identifiers */
999  ot->name = "Zoom In";
1000  ot->description = "Zoom in the view";
1001  ot->idname = "VIEW2D_OT_zoom_in";
1002 
1003  /* api callbacks */
1006  ot->poll = view_zoom_poll;
1007 
1008  /* rna - must keep these in sync with the other operators */
1009  prop = RNA_def_float(
1010  ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
1012  prop = RNA_def_float(
1013  ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
1015 }
1016 
1017 /* this operator only needs this single callback, where it calls the view_zoom_*() methods */
1019 {
1020  bool do_zoom_xy[2];
1021 
1022  if (op->customdata == NULL) { /* Might have been setup in _invoke() already. */
1023  view_zoomdrag_init(C, op);
1024  }
1025 
1026  view_zoom_axis_lock_defaults(C, do_zoom_xy);
1027 
1028  /* set RNA-Props - zooming in by uniform factor */
1029  RNA_float_set(op->ptr, "zoomfacx", do_zoom_xy[0] ? -0.0375f : 0.0f);
1030  RNA_float_set(op->ptr, "zoomfacy", do_zoom_xy[1] ? -0.0375f : 0.0f);
1031 
1032  /* apply movement, then we're done */
1033  view_zoomstep_apply(C, op);
1034 
1035  view_zoomstep_exit(op);
1036 
1037  return OPERATOR_FINISHED;
1038 }
1039 
1040 static int view_zoomout_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1041 {
1042  view_zoomdrag_init(C, op);
1043 
1044  v2dViewZoomData *vzd = op->customdata;
1045 
1046  if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1047  ARegion *region = CTX_wm_region(C);
1048 
1049  /* store initial mouse position (in view space) */
1051  &region->v2d, event->mval[0], event->mval[1], &vzd->mx_2d, &vzd->my_2d);
1052  vzd->zoom_to_mouse_pos = true;
1053  }
1054 
1055  return view_zoomout_exec(C, op);
1056 }
1057 
1059 {
1060  PropertyRNA *prop;
1061 
1062  /* identifiers */
1063  ot->name = "Zoom Out";
1064  ot->description = "Zoom out the view";
1065  ot->idname = "VIEW2D_OT_zoom_out";
1066 
1067  /* api callbacks */
1070 
1071  ot->poll = view_zoom_poll;
1072 
1073  /* rna - must keep these in sync with the other operators */
1074  prop = RNA_def_float(
1075  ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
1077  prop = RNA_def_float(
1078  ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
1080 }
1081 
1084 /* -------------------------------------------------------------------- */
1095 /* apply transform to view (i.e. adjust 'cur' rect) */
1097 {
1098  v2dViewZoomData *vzd = op->customdata;
1099  View2D *v2d = vzd->v2d;
1100  const int snap_test = ED_region_snap_size_test(vzd->region);
1101 
1102  const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
1103  const bool zoom_to_pos = use_cursor_init && vzd->zoom_to_mouse_pos;
1104 
1105  /* get amount to move view by */
1106  float dx = RNA_float_get(op->ptr, "deltax") / U.dpi_fac;
1107  float dy = RNA_float_get(op->ptr, "deltay") / U.dpi_fac;
1108 
1109  /* Check if the 'timer' is initialized, as zooming with the trackpad
1110  * never uses the "Continuous" zoom method, and the 'timer' is not initialized. */
1111  if ((U.viewzoom == USER_ZOOM_CONTINUE) && vzd->timer) { /* XXX store this setting as RNA prop? */
1112  const double time = PIL_check_seconds_timer();
1113  const float time_step = (float)(time - vzd->timer_lastdraw);
1114 
1115  dx *= time_step * 0.5f;
1116  dy *= time_step * 0.5f;
1117 
1118  vzd->timer_lastdraw = time;
1119  }
1120 
1121  /* only move view on an axis if change is allowed */
1122  if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0) {
1123  if (v2d->keepofs & V2D_LOCKOFS_X) {
1124  v2d->cur.xmax -= 2 * dx;
1125  }
1126  else {
1127  if (zoom_to_pos) {
1128  const float mval_fac = (vzd->mx_2d - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
1129  const float mval_faci = 1.0f - mval_fac;
1130  const float ofs = (mval_fac * dx) - (mval_faci * dx);
1131 
1132  v2d->cur.xmin += ofs + dx;
1133  v2d->cur.xmax += ofs - dx;
1134  }
1135  else {
1136  v2d->cur.xmin += dx;
1137  v2d->cur.xmax -= dx;
1138  }
1139  }
1140  }
1141  if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0) {
1142  if (v2d->keepofs & V2D_LOCKOFS_Y) {
1143  v2d->cur.ymax -= 2 * dy;
1144  }
1145  else {
1146  if (zoom_to_pos) {
1147  const float mval_fac = (vzd->my_2d - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur);
1148  const float mval_faci = 1.0f - mval_fac;
1149  const float ofs = (mval_fac * dy) - (mval_faci * dy);
1150 
1151  v2d->cur.ymin += ofs + dy;
1152  v2d->cur.ymax += ofs - dy;
1153  }
1154  else {
1155  v2d->cur.ymin += dy;
1156  v2d->cur.ymax -= dy;
1157  }
1158  }
1159  }
1160 
1161  /* Inform v2d about changes after this operation. */
1163 
1164  if (ED_region_snap_size_apply(vzd->region, snap_test)) {
1165  ScrArea *area = CTX_wm_area(C);
1168  }
1169 
1170  /* request updates to be done... */
1173 }
1174 
1175 /* cleanup temp customdata */
1177 {
1179 
1180  if (op->customdata) {
1181  v2dViewZoomData *vzd = op->customdata;
1182 
1183  if (vzd->timer) {
1185  }
1186 
1187  MEM_freeN(op->customdata);
1188  op->customdata = NULL;
1189  }
1190 }
1191 
1193 {
1194  view_zoomdrag_exit(C, op);
1195 }
1196 
1197 /* for 'redo' only, with no user input */
1199 {
1200  view_zoomdrag_init(C, op);
1201  view_zoomdrag_apply(C, op);
1202  view_zoomdrag_exit(C, op);
1203  return OPERATOR_FINISHED;
1204 }
1205 
1206 /* set up modal operator and relevant settings */
1207 static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1208 {
1209  wmWindow *window = CTX_wm_window(C);
1210 
1211  /* set up customdata */
1212  view_zoomdrag_init(C, op);
1213 
1214  v2dViewZoomData *vzd = op->customdata;
1215  View2D *v2d = vzd->v2d;
1216 
1217  if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1218  ARegion *region = CTX_wm_region(C);
1219 
1220  /* Store initial mouse position (in view space). */
1222  &region->v2d, event->mval[0], event->mval[1], &vzd->mx_2d, &vzd->my_2d);
1223  vzd->zoom_to_mouse_pos = true;
1224  }
1225 
1226  if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
1227  vzd->lastx = event->prevx;
1228  vzd->lasty = event->prevy;
1229 
1230  float facx, facy;
1231  float zoomfac = 0.01f;
1232 
1233  /* Some view2d's (graph) don't have min/max zoom, or extreme ones. */
1234  if (v2d->maxzoom > 0.0f) {
1235  zoomfac = clamp_f(0.001f * v2d->maxzoom, 0.001f, 0.01f);
1236  }
1237 
1238  if (event->type == MOUSEPAN) {
1239  facx = zoomfac * WM_event_absolute_delta_x(event);
1240  facy = zoomfac * WM_event_absolute_delta_y(event);
1241 
1242  if (U.uiflag & USER_ZOOM_INVERT) {
1243  facx *= -1.0f;
1244  facy *= -1.0f;
1245  }
1246  }
1247  else { /* MOUSEZOOM */
1248  facx = facy = zoomfac * WM_event_absolute_delta_x(event);
1249  }
1250 
1251  /* Only respect user setting zoom axis if the view does not have any zoom restrictions
1252  * any will be scaled uniformly. */
1253  if (((v2d->keepzoom & (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y)) == 0) &&
1254  (v2d->keepzoom & V2D_KEEPASPECT)) {
1255  if (U.uiflag & USER_ZOOM_HORIZ) {
1256  facy = 0.0f;
1257  }
1258  else {
1259  facx = 0.0f;
1260  }
1261  }
1262 
1263  /* support trackpad zoom to always zoom entirely - the v2d code uses portrait or
1264  * landscape exceptions */
1265  if (v2d->keepzoom & V2D_KEEPASPECT) {
1266  if (fabsf(facx) > fabsf(facy)) {
1267  facy = facx;
1268  }
1269  else {
1270  facx = facy;
1271  }
1272  }
1273 
1274  const float dx = facx * BLI_rctf_size_x(&v2d->cur);
1275  const float dy = facy * BLI_rctf_size_y(&v2d->cur);
1276 
1277  RNA_float_set(op->ptr, "deltax", dx);
1278  RNA_float_set(op->ptr, "deltay", dy);
1279 
1280  view_zoomdrag_apply(C, op);
1281  view_zoomdrag_exit(C, op);
1282  return OPERATOR_FINISHED;
1283  }
1284 
1285  /* set initial settings */
1286  vzd->lastx = event->x;
1287  vzd->lasty = event->y;
1288  RNA_float_set(op->ptr, "deltax", 0);
1289  RNA_float_set(op->ptr, "deltay", 0);
1290 
1291  /* for modal exit test */
1292  vzd->invoke_event = event->type;
1293 
1294  if (v2d->keepofs & V2D_LOCKOFS_X) {
1296  }
1297  else if (v2d->keepofs & V2D_LOCKOFS_Y) {
1299  }
1300  else {
1302  }
1303 
1304  /* add temp handler */
1306 
1307  if (U.viewzoom == USER_ZOOM_CONTINUE) {
1308  /* needs a timer to continue redrawing */
1309  vzd->timer = WM_event_add_timer(CTX_wm_manager(C), window, TIMER, 0.01f);
1311  }
1312 
1313  return OPERATOR_RUNNING_MODAL;
1314 }
1315 
1316 /* handle user input - calculations of mouse-movement need to be done here,
1317  * not in the apply callback! */
1318 static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event)
1319 {
1320  v2dViewZoomData *vzd = op->customdata;
1321  View2D *v2d = vzd->v2d;
1322 
1323  /* execute the events */
1324  if (event->type == TIMER && event->customdata == vzd->timer) {
1325  view_zoomdrag_apply(C, op);
1326  }
1327  else if (event->type == MOUSEMOVE) {
1328  float dx, dy;
1329  float zoomfac = 0.01f;
1330 
1331  /* some view2d's (graph) don't have min/max zoom, or extreme ones */
1332  if (v2d->maxzoom > 0.0f) {
1333  zoomfac = clamp_f(0.001f * v2d->maxzoom, 0.001f, 0.01f);
1334  }
1335 
1336  /* calculate new delta transform, based on zooming mode */
1337  if (U.viewzoom == USER_ZOOM_SCALE) {
1338  /* 'scale' zooming */
1339  float dist;
1340  float len_old[2];
1341  float len_new[2];
1342 
1343  /* x-axis transform */
1344  dist = BLI_rcti_size_x(&v2d->mask) / 2.0f;
1345  len_old[0] = zoomfac * fabsf(vzd->lastx - vzd->region->winrct.xmin - dist);
1346  len_new[0] = zoomfac * fabsf(event->x - vzd->region->winrct.xmin - dist);
1347 
1348  /* y-axis transform */
1349  dist = BLI_rcti_size_y(&v2d->mask) / 2.0f;
1350  len_old[1] = zoomfac * fabsf(vzd->lasty - vzd->region->winrct.ymin - dist);
1351  len_new[1] = zoomfac * fabsf(event->y - vzd->region->winrct.ymin - dist);
1352 
1353  /* Calculate distance */
1354  if (v2d->keepzoom & V2D_KEEPASPECT) {
1355  dist = len_v2(len_new) - len_v2(len_old);
1356  dx = dy = dist;
1357  }
1358  else {
1359  dx = len_new[0] - len_old[0];
1360  dy = len_new[1] - len_old[1];
1361  }
1362 
1363  dx *= BLI_rctf_size_x(&v2d->cur);
1364  dy *= BLI_rctf_size_y(&v2d->cur);
1365  }
1366  else { /* USER_ZOOM_CONTINUE or USER_ZOOM_DOLLY */
1367  float facx = zoomfac * (event->x - vzd->lastx);
1368  float facy = zoomfac * (event->y - vzd->lasty);
1369 
1370  /* Only respect user setting zoom axis if the view does not have any zoom restrictions
1371  * any will be scaled uniformly */
1372  if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && (v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 &&
1373  (v2d->keepzoom & V2D_KEEPASPECT)) {
1374  if (U.uiflag & USER_ZOOM_HORIZ) {
1375  facy = 0.0f;
1376  }
1377  else {
1378  facx = 0.0f;
1379  }
1380  }
1381 
1382  /* support zoom to always zoom entirely - the v2d code uses portrait or
1383  * landscape exceptions */
1384  if (v2d->keepzoom & V2D_KEEPASPECT) {
1385  if (fabsf(facx) > fabsf(facy)) {
1386  facy = facx;
1387  }
1388  else {
1389  facx = facy;
1390  }
1391  }
1392 
1393  dx = facx * BLI_rctf_size_x(&v2d->cur);
1394  dy = facy * BLI_rctf_size_y(&v2d->cur);
1395  }
1396 
1397  if (U.uiflag & USER_ZOOM_INVERT) {
1398  dx *= -1.0f;
1399  dy *= -1.0f;
1400  }
1401 
1402  /* set transform amount, and add current deltas to stored total delta (for redo) */
1403  RNA_float_set(op->ptr, "deltax", dx);
1404  RNA_float_set(op->ptr, "deltay", dy);
1405 
1406  vzd->dx += dx;
1407  vzd->dy += dy;
1408 
1409  /* Store mouse coordinates for next time, if not doing continuous zoom:
1410  * - Continuous zoom only depends on distance of mouse
1411  * to starting point to determine rate of change.
1412  */
1413  if (U.viewzoom != USER_ZOOM_CONTINUE) { /* XXX store this setting as RNA prop? */
1414  vzd->lastx = event->x;
1415  vzd->lasty = event->y;
1416  }
1417 
1418  /* apply zooming */
1419  view_zoomdrag_apply(C, op);
1420  }
1421  else if (ELEM(event->type, vzd->invoke_event, EVT_ESCKEY)) {
1422  if (event->val == KM_RELEASE) {
1423 
1424  /* for redo, store the overall deltas - need to respect zoom-locks here... */
1425  if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0) {
1426  RNA_float_set(op->ptr, "deltax", vzd->dx);
1427  }
1428  else {
1429  RNA_float_set(op->ptr, "deltax", 0);
1430  }
1431 
1432  if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0) {
1433  RNA_float_set(op->ptr, "deltay", vzd->dy);
1434  }
1435  else {
1436  RNA_float_set(op->ptr, "deltay", 0);
1437  }
1438 
1439  /* free customdata */
1440  view_zoomdrag_exit(C, op);
1442 
1443  return OPERATOR_FINISHED;
1444  }
1445  }
1446 
1447  return OPERATOR_RUNNING_MODAL;
1448 }
1449 
1451 {
1452  PropertyRNA *prop;
1453  /* identifiers */
1454  ot->name = "Zoom 2D View";
1455  ot->description = "Zoom in/out the view";
1456  ot->idname = "VIEW2D_OT_zoom";
1457 
1458  /* api callbacks */
1463 
1464  ot->poll = view_zoom_poll;
1465 
1466  /* operator is repeatable */
1468 
1469  /* rna - must keep these in sync with the other operators */
1470  prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
1472  prop = RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX);
1474 
1476 }
1477 
1480 /* -------------------------------------------------------------------- */
1496 {
1497  ARegion *region = CTX_wm_region(C);
1498  View2D *v2d = &region->v2d;
1499  rctf cur_new = v2d->cur;
1500  const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
1501 
1502  /* convert coordinates of rect to 'tot' rect coordinates */
1503  rctf rect;
1505  UI_view2d_region_to_view_rctf(v2d, &rect, &rect);
1506 
1507  /* check if zooming in/out view */
1508  const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
1509 
1510  if (zoom_in) {
1511  /* zoom in:
1512  * - 'cur' rect will be defined by the coordinates of the border region
1513  * - just set the 'cur' rect to have the same coordinates as the border region
1514  * if zoom is allowed to be changed
1515  */
1516  if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0) {
1517  cur_new.xmin = rect.xmin;
1518  cur_new.xmax = rect.xmax;
1519  }
1520  if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0) {
1521  cur_new.ymin = rect.ymin;
1522  cur_new.ymax = rect.ymax;
1523  }
1524  }
1525  else {
1526  /* zoom out:
1527  * - the current 'cur' rect coordinates are going to end up where the 'rect' ones are,
1528  * but the 'cur' rect coordinates will need to be adjusted to take in more of the view
1529  * - calculate zoom factor, and adjust using center-point
1530  */
1531  float zoom, center, size;
1532 
1533  /* TODO: is this zoom factor calculation valid?
1534  * It seems to produce same results every time... */
1535  if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0) {
1536  size = BLI_rctf_size_x(&cur_new);
1537  zoom = size / BLI_rctf_size_x(&rect);
1538  center = BLI_rctf_cent_x(&cur_new);
1539 
1540  cur_new.xmin = center - (size * zoom);
1541  cur_new.xmax = center + (size * zoom);
1542  }
1543  if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0) {
1544  size = BLI_rctf_size_y(&cur_new);
1545  zoom = size / BLI_rctf_size_y(&rect);
1546  center = BLI_rctf_cent_y(&cur_new);
1547 
1548  cur_new.ymin = center - (size * zoom);
1549  cur_new.ymax = center + (size * zoom);
1550  }
1551  }
1552 
1553  UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
1554 
1555  return OPERATOR_FINISHED;
1556 }
1557 
1559 {
1560  /* identifiers */
1561  ot->name = "Zoom to Border";
1562  ot->description = "Zoom in the view to the nearest item contained in the border";
1563  ot->idname = "VIEW2D_OT_zoom_border";
1564 
1565  /* api callbacks */
1570 
1571  ot->poll = view_zoom_poll;
1572 
1573  /* rna */
1575 }
1576 
1579 /* -------------------------------------------------------------------- */
1583 #ifdef WITH_INPUT_NDOF
1584 static int view2d_ndof_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1585 {
1586  if (event->type != NDOF_MOTION) {
1587  return OPERATOR_CANCELLED;
1588  }
1589 
1590  const wmNDOFMotionData *ndof = event->customdata;
1591 
1592  /* tune these until it feels right */
1593  const float zoom_sensitivity = 0.5f;
1594  const float speed = 10.0f; /* match view3d ortho */
1595  const bool has_translate = (ndof->tvec[0] && ndof->tvec[1]) && view_pan_poll(C);
1596  const bool has_zoom = (ndof->tvec[2] != 0.0f) && view_zoom_poll(C);
1597 
1598  if (has_translate) {
1599  float pan_vec[3];
1600 
1601  WM_event_ndof_pan_get(ndof, pan_vec, false);
1602 
1603  pan_vec[0] *= speed;
1604  pan_vec[1] *= speed;
1605 
1606  view_pan_init(C, op);
1607 
1608  v2dViewPanData *vpd = op->customdata;
1609  view_pan_apply_ex(C, vpd, pan_vec[0], pan_vec[1]);
1610 
1611  view_pan_exit(op);
1612  }
1613 
1614  if (has_zoom) {
1615  float zoom_factor = zoom_sensitivity * ndof->dt * -ndof->tvec[2];
1616 
1617  bool do_zoom_xy[2];
1618 
1619  if (U.ndof_flag & NDOF_ZOOM_INVERT) {
1620  zoom_factor = -zoom_factor;
1621  }
1622 
1623  view_zoom_axis_lock_defaults(C, do_zoom_xy);
1624 
1625  view_zoomdrag_init(C, op);
1626 
1627  v2dViewZoomData *vzd = op->customdata;
1629  C, vzd, do_zoom_xy[0] ? zoom_factor : 0.0f, do_zoom_xy[1] ? zoom_factor : 0.0f);
1630 
1631  view_zoomstep_exit(op);
1632  }
1633 
1634  return OPERATOR_FINISHED;
1635 }
1636 
1637 static void VIEW2D_OT_ndof(wmOperatorType *ot)
1638 {
1639  /* identifiers */
1640  ot->name = "NDOF Pan/Zoom";
1641  ot->idname = "VIEW2D_OT_ndof";
1642  ot->description = "Use a 3D mouse device to pan/zoom the view";
1643 
1644  /* api callbacks */
1645  ot->invoke = view2d_ndof_invoke;
1646  ot->poll = view2d_poll;
1647 
1648  /* flags */
1650 }
1651 #endif /* WITH_INPUT_NDOF */
1652 
1655 /* -------------------------------------------------------------------- */
1661 
1663 };
1664 
1673 static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
1674 {
1675  const float size_a[2] = {BLI_rctf_size_x(rect_a), BLI_rctf_size_y(rect_a)};
1676  const float size_b[2] = {BLI_rctf_size_x(rect_b), BLI_rctf_size_y(rect_b)};
1677  const float cent_a[2] = {BLI_rctf_cent_x(rect_a), BLI_rctf_cent_y(rect_a)};
1678  const float cent_b[2] = {BLI_rctf_cent_x(rect_b), BLI_rctf_cent_y(rect_b)};
1679 
1680  float fac_max = 0.0f;
1681 
1682  for (int i = 0; i < 2; i++) {
1683  /* axis translation normalized to scale */
1684  float tfac = fabsf(cent_a[i] - cent_b[i]) / min_ff(size_a[i], size_b[i]);
1685  fac_max = max_ff(fac_max, tfac);
1686  if (fac_max >= 1.0f) {
1687  break;
1688  }
1689 
1690  /* axis scale difference, x2 so doubling or half gives 1.0f */
1691  tfac = (1.0f - (min_ff(size_a[i], size_b[i]) / max_ff(size_a[i], size_b[i]))) * 2.0f;
1692  fac_max = max_ff(fac_max, tfac);
1693  if (fac_max >= 1.0f) {
1694  break;
1695  }
1696  }
1697  return min_ff(fac_max, 1.0f);
1698 }
1699 
1700 /* will start timer if appropriate */
1701 /* the arguments are the desired situation */
1702 void UI_view2d_smooth_view(bContext *C, ARegion *region, const rctf *cur, const int smooth_viewtx)
1703 {
1705  wmWindow *win = CTX_wm_window(C);
1706 
1707  View2D *v2d = &region->v2d;
1708  struct SmoothView2DStore sms = {{0}};
1709  bool ok = false;
1710  float fac = 1.0f;
1711 
1712  /* initialize sms */
1713  sms.new_cur = v2d->cur;
1714 
1715  /* store the options we want to end with */
1716  if (cur) {
1717  sms.new_cur = *cur;
1718  }
1719 
1720  if (cur) {
1721  fac = smooth_view_rect_to_fac(&v2d->cur, cur);
1722  }
1723 
1724  if (smooth_viewtx && fac > FLT_EPSILON) {
1725  bool changed = false;
1726 
1727  if (BLI_rctf_compare(&sms.new_cur, &v2d->cur, FLT_EPSILON) == false) {
1728  changed = true;
1729  }
1730 
1731  /* The new view is different from the old one
1732  * so animate the view */
1733  if (changed) {
1734  sms.orig_cur = v2d->cur;
1735 
1736  sms.time_allowed = (double)smooth_viewtx / 1000.0;
1737 
1738  /* scale the time allowed the change in view */
1739  sms.time_allowed *= (double)fac;
1740 
1741  /* keep track of running timer! */
1742  if (v2d->sms == NULL) {
1743  v2d->sms = MEM_mallocN(sizeof(struct SmoothView2DStore), "smoothview v2d");
1744  }
1745  *v2d->sms = sms;
1746  if (v2d->smooth_timer) {
1747  WM_event_remove_timer(wm, win, v2d->smooth_timer);
1748  }
1749  /* TIMER1 is hard-coded in key-map. */
1750  v2d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0);
1751 
1752  ok = true;
1753  }
1754  }
1755 
1756  /* if we get here nothing happens */
1757  if (ok == false) {
1758  v2d->cur = sms.new_cur;
1759 
1763  }
1764 }
1765 
1766 /* only meant for timer usage */
1768 {
1769  wmWindow *win = CTX_wm_window(C);
1770  ARegion *region = CTX_wm_region(C);
1771  View2D *v2d = &region->v2d;
1772  struct SmoothView2DStore *sms = v2d->sms;
1773 
1774  /* escape if not our timer */
1775  if (v2d->smooth_timer == NULL || v2d->smooth_timer != event->customdata) {
1776  return OPERATOR_PASS_THROUGH;
1777  }
1778 
1779  float step;
1780  if (sms->time_allowed != 0.0) {
1781  step = (float)((v2d->smooth_timer->duration) / sms->time_allowed);
1782  }
1783  else {
1784  step = 1.0f;
1785  }
1786 
1787  /* end timer */
1788  if (step >= 1.0f) {
1789  v2d->cur = sms->new_cur;
1790 
1791  MEM_freeN(v2d->sms);
1792  v2d->sms = NULL;
1793 
1795  v2d->smooth_timer = NULL;
1796 
1797  /* Event handling won't know if a UI item has been moved under the pointer. */
1799  }
1800  else {
1801  /* ease in/out */
1802  step = (3.0f * step * step - 2.0f * step * step * step);
1803 
1804  BLI_rctf_interp(&v2d->cur, &sms->orig_cur, &sms->new_cur, step);
1805  }
1806 
1810 
1811  if (v2d->sms == NULL) {
1813  }
1814 
1815  return OPERATOR_FINISHED;
1816 }
1817 
1819 {
1820  /* identifiers */
1821  ot->name = "Smooth View 2D";
1822  ot->idname = "VIEW2D_OT_smoothview";
1823 
1824  /* api callbacks */
1826  ot->poll = view2d_poll;
1827 
1828  /* flags */
1829  ot->flag = OPTYPE_INTERNAL;
1830 
1831  /* rna */
1833 }
1834 
1837 /* -------------------------------------------------------------------- */
1851 /* customdata for scroller-invoke data */
1852 typedef struct v2dScrollerMove {
1857 
1859  char scroller;
1860 
1861  /* XXX find some way to provide visual feedback of this (active color?) */
1863  short zone;
1864 
1866  float fac;
1868  float fac_round;
1870  float delta;
1871 
1876 
1878  int lastx, lasty;
1880 
1890 struct View2DScrollers {
1891  /* focus bubbles */
1892  int vert_min, vert_max; /* vertical scrollbar */
1893  int hor_min, hor_max; /* horizontal scrollbar */
1894 
1895  /* These values are written into, even if we don't use them. */
1897 };
1898 
1899 /* quick enum for vsm->zone (scroller handles) */
1900 enum {
1906 } /*eV2DScrollerHandle_Zone*/;
1907 
1915 static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max)
1916 {
1917  /* firstly, check if
1918  * - 'bubble' fills entire scroller
1919  * - 'bubble' completely out of view on either side
1920  */
1921  bool in_view = true;
1922  if (sh_min <= sc_min && sc_max <= sh_max) {
1923  in_view = false;
1924  }
1925  else if (sh_max <= sc_min || sc_max <= sh_min) {
1926  in_view = false;
1927  }
1928 
1929  if (!in_view) {
1930  return SCROLLHANDLE_BAR;
1931  }
1932 
1933  /* check if mouse is in or past either handle */
1934  /* TODO: check if these extents are still valid or not */
1935  bool in_max = ((mouse >= (sh_max - V2D_SCROLL_HANDLE_SIZE_HOTSPOT)) &&
1936  (mouse <= (sh_max + V2D_SCROLL_HANDLE_SIZE_HOTSPOT)));
1937  bool in_min = ((mouse <= (sh_min + V2D_SCROLL_HANDLE_SIZE_HOTSPOT)) &&
1938  (mouse >= (sh_min - V2D_SCROLL_HANDLE_SIZE_HOTSPOT)));
1939  bool in_bar = ((mouse < (sh_max - V2D_SCROLL_HANDLE_SIZE_HOTSPOT)) &&
1940  (mouse > (sh_min + V2D_SCROLL_HANDLE_SIZE_HOTSPOT)));
1941  const bool out_min = mouse < (sh_min - V2D_SCROLL_HANDLE_SIZE_HOTSPOT);
1942  const bool out_max = mouse > (sh_max + V2D_SCROLL_HANDLE_SIZE_HOTSPOT);
1943 
1944  if (in_bar) {
1945  return SCROLLHANDLE_BAR;
1946  }
1947  if (in_max) {
1948  return SCROLLHANDLE_MAX;
1949  }
1950  if (in_min) {
1951  return SCROLLHANDLE_MIN;
1952  }
1953  if (out_min) {
1954  return SCROLLHANDLE_MIN_OUTSIDE;
1955  }
1956  if (out_max) {
1957  return SCROLLHANDLE_MAX_OUTSIDE;
1958  }
1959 
1960  /* unlikely to happen, though we just cover it in case */
1961  return SCROLLHANDLE_BAR;
1962 }
1963 
1965 {
1966  if (!view2d_poll(C)) {
1967  return false;
1968  }
1969 
1970  wmWindow *win = CTX_wm_window(C);
1971  ARegion *region = CTX_wm_region(C);
1972  View2D *v2d = &region->v2d;
1973  wmEvent *event = win->eventstate;
1974 
1975  /* check if mouse in scrollbars, if they're enabled */
1976  return (UI_view2d_mouse_in_scrollers(region, v2d, event->x, event->y) != 0);
1977 }
1978 
1979 /* initialize customdata for scroller manipulation operator */
1981  wmOperator *op,
1982  const wmEvent *event,
1983  const char in_scroller)
1984 {
1985  ARegion *region = CTX_wm_region(C);
1986  View2D *v2d = &region->v2d;
1987 
1988  /* set custom-data for operator */
1989  v2dScrollerMove *vsm = MEM_callocN(sizeof(v2dScrollerMove), "v2dScrollerMove");
1990  op->customdata = vsm;
1991 
1992  /* set general data */
1993  vsm->v2d = v2d;
1994  vsm->region = region;
1995  vsm->scroller = in_scroller;
1996 
1997  /* store mouse-coordinates, and convert mouse/screen coordinates to region coordinates */
1998  vsm->lastx = event->x;
1999  vsm->lasty = event->y;
2000  /* 'zone' depends on where mouse is relative to bubble
2001  * - zooming must be allowed on this axis, otherwise, default to pan
2002  */
2003  View2DScrollers scrollers;
2004  UI_view2d_scrollers_calc(v2d, NULL, &scrollers);
2005 
2006  /* Use a union of 'cur' & 'tot' in case the current view is far outside 'tot'. In this cases
2007  * moving the scroll bars has far too little effect and the view can get stuck T31476. */
2008  rctf tot_cur_union = v2d->tot;
2009  BLI_rctf_union(&tot_cur_union, &v2d->cur);
2010 
2011  if (in_scroller == 'h') {
2012  /* horizontal scroller - calculate adjustment factor first */
2013  const float mask_size = (float)BLI_rcti_size_x(&v2d->hor);
2014  vsm->fac = BLI_rctf_size_x(&tot_cur_union) / mask_size;
2015 
2016  /* pixel rounding */
2017  vsm->fac_round = (BLI_rctf_size_x(&v2d->cur)) / (float)(BLI_rcti_size_x(&region->winrct) + 1);
2018 
2019  /* get 'zone' (i.e. which part of scroller is activated) */
2021  event->mval[0], v2d->hor.xmin, v2d->hor.xmax, scrollers.hor_min, scrollers.hor_max);
2022 
2024  /* default to scroll, as handles not usable */
2025  vsm->zone = SCROLLHANDLE_BAR;
2026  }
2027 
2028  vsm->scrollbarwidth = scrollers.hor_max - scrollers.hor_min;
2029  vsm->scrollbar_orig = ((scrollers.hor_max + scrollers.hor_min) / 2) + region->winrct.xmin;
2030  }
2031  else {
2032  /* vertical scroller - calculate adjustment factor first */
2033  const float mask_size = (float)BLI_rcti_size_y(&v2d->vert);
2034  vsm->fac = BLI_rctf_size_y(&tot_cur_union) / mask_size;
2035 
2036  /* pixel rounding */
2037  vsm->fac_round = (BLI_rctf_size_y(&v2d->cur)) / (float)(BLI_rcti_size_y(&region->winrct) + 1);
2038 
2039  /* get 'zone' (i.e. which part of scroller is activated) */
2041  event->mval[1], v2d->vert.ymin, v2d->vert.ymax, scrollers.vert_min, scrollers.vert_max);
2042 
2044  /* default to scroll, as handles not usable */
2045  vsm->zone = SCROLLHANDLE_BAR;
2046  }
2047 
2048  vsm->scrollbarwidth = scrollers.vert_max - scrollers.vert_min;
2049  vsm->scrollbar_orig = ((scrollers.vert_max + scrollers.vert_min) / 2) + region->winrct.ymin;
2050  }
2051 
2053 }
2054 
2055 /* cleanup temp customdata */
2057 {
2058  if (op->customdata) {
2059  v2dScrollerMove *vsm = op->customdata;
2060 
2062 
2063  MEM_freeN(op->customdata);
2064  op->customdata = NULL;
2065 
2067  }
2068 }
2069 
2071 {
2073 }
2074 
2075 /* apply transform to view (i.e. adjust 'cur' rect) */
2077 {
2078  v2dScrollerMove *vsm = op->customdata;
2079  View2D *v2d = vsm->v2d;
2080 
2081  /* calculate amount to move view by */
2082  float temp = vsm->fac * vsm->delta;
2083 
2084  /* round to pixel */
2085  temp = roundf(temp / vsm->fac_round) * vsm->fac_round;
2086 
2087  /* type of movement */
2088  switch (vsm->zone) {
2089  case SCROLLHANDLE_MIN:
2090  /* only expand view on axis if zoom is allowed */
2091  if ((vsm->scroller == 'h') && !(v2d->keepzoom & V2D_LOCKZOOM_X)) {
2092  v2d->cur.xmin -= temp;
2093  }
2094  if ((vsm->scroller == 'v') && !(v2d->keepzoom & V2D_LOCKZOOM_Y)) {
2095  v2d->cur.ymin -= temp;
2096  }
2097  break;
2098 
2099  case SCROLLHANDLE_MAX:
2100 
2101  /* only expand view on axis if zoom is allowed */
2102  if ((vsm->scroller == 'h') && !(v2d->keepzoom & V2D_LOCKZOOM_X)) {
2103  v2d->cur.xmax += temp;
2104  }
2105  if ((vsm->scroller == 'v') && !(v2d->keepzoom & V2D_LOCKZOOM_Y)) {
2106  v2d->cur.ymax += temp;
2107  }
2108  break;
2109 
2112  case SCROLLHANDLE_BAR:
2113  default:
2114  /* only move view on an axis if panning is allowed */
2115  if ((vsm->scroller == 'h') && !(v2d->keepofs & V2D_LOCKOFS_X)) {
2116  v2d->cur.xmin += temp;
2117  v2d->cur.xmax += temp;
2118  }
2119  if ((vsm->scroller == 'v') && !(v2d->keepofs & V2D_LOCKOFS_Y)) {
2120  v2d->cur.ymin += temp;
2121  v2d->cur.ymax += temp;
2122  }
2123  break;
2124  }
2125 
2126  /* Inform v2d about changes after this operation. */
2128 
2129  /* request updates to be done... */
2132 }
2133 
2138 static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event)
2139 {
2140  v2dScrollerMove *vsm = op->customdata;
2141 
2142  /* execute the events */
2143  switch (event->type) {
2144  case MOUSEMOVE: {
2145  /* calculate new delta transform, then store mouse-coordinates for next-time */
2147  /* if using bar (i.e. 'panning') or 'max' zoom widget */
2148  switch (vsm->scroller) {
2149  case 'h': /* horizontal scroller - so only horizontal movement
2150  * ('cur' moves opposite to mouse) */
2151  vsm->delta = (float)(event->x - vsm->lastx);
2152  break;
2153  case 'v': /* vertical scroller - so only vertical movement
2154  * ('cur' moves opposite to mouse) */
2155  vsm->delta = (float)(event->y - vsm->lasty);
2156  break;
2157  }
2158  }
2159  else if (vsm->zone == SCROLLHANDLE_MIN) {
2160  /* using 'min' zoom widget */
2161  switch (vsm->scroller) {
2162  case 'h': /* horizontal scroller - so only horizontal movement
2163  * ('cur' moves with mouse) */
2164  vsm->delta = (float)(vsm->lastx - event->x);
2165  break;
2166  case 'v': /* vertical scroller - so only vertical movement
2167  * ('cur' moves with to mouse) */
2168  vsm->delta = (float)(vsm->lasty - event->y);
2169  break;
2170  }
2171  }
2172 
2173  /* store previous coordinates */
2174  vsm->lastx = event->x;
2175  vsm->lasty = event->y;
2176 
2178  break;
2179  }
2180  case LEFTMOUSE:
2181  case MIDDLEMOUSE:
2182  if (event->val == KM_RELEASE) {
2183  /* single-click was in empty space outside bubble, so scroll by 1 'page' */
2185  if (vsm->zone == SCROLLHANDLE_MIN_OUTSIDE) {
2186  vsm->delta = -vsm->scrollbarwidth * 0.8f;
2187  }
2188  else if (vsm->zone == SCROLLHANDLE_MAX_OUTSIDE) {
2189  vsm->delta = vsm->scrollbarwidth * 0.8f;
2190  }
2191 
2194  return OPERATOR_FINISHED;
2195  }
2196 
2197  /* otherwise, end the drag action */
2198  if (vsm->lastx || vsm->lasty) {
2200  return OPERATOR_FINISHED;
2201  }
2202  }
2203  break;
2204  }
2205 
2206  return OPERATOR_RUNNING_MODAL;
2207 }
2208 
2209 /* a click (or click drag in progress)
2210  * should have occurred, so check if it happened in scrollbar */
2211 static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2212 {
2213  ARegion *region = CTX_wm_region(C);
2214  View2D *v2d = &region->v2d;
2215 
2216  /* check if mouse in scrollbars, if they're enabled */
2217  const char in_scroller = UI_view2d_mouse_in_scrollers(region, v2d, event->x, event->y);
2218 
2219  /* if in a scroller, init customdata then set modal handler which will
2220  * catch mouse-down to start doing useful stuff */
2221  if (in_scroller) {
2222  /* initialize customdata */
2223  scroller_activate_init(C, op, event, in_scroller);
2225 
2226  /* Support for quick jump to location - GTK and QT do this on Linux. */
2227  if (event->type == MIDDLEMOUSE) {
2228  switch (vsm->scroller) {
2229  case 'h': /* horizontal scroller - so only horizontal movement
2230  * ('cur' moves opposite to mouse) */
2231  vsm->delta = (float)(event->x - vsm->scrollbar_orig);
2232  break;
2233  case 'v': /* vertical scroller - so only vertical movement
2234  * ('cur' moves opposite to mouse) */
2235  vsm->delta = (float)(event->y - vsm->scrollbar_orig);
2236  break;
2237  }
2239 
2240  vsm->zone = SCROLLHANDLE_BAR;
2241  }
2242 
2243  /* check if zoom zones are inappropriate (i.e. zoom widgets not shown), so cannot continue
2244  * NOTE: see view2d.c for latest conditions, and keep this in sync with that
2245  */
2247  if (((vsm->scroller == 'h') && (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0) ||
2248  ((vsm->scroller == 'v') && (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) {
2249  /* switch to bar (i.e. no scaling gets handled) */
2250  vsm->zone = SCROLLHANDLE_BAR;
2251  }
2252  }
2253 
2254  /* check if zone is inappropriate (i.e. 'bar' but panning is banned), so cannot continue */
2255  if (vsm->zone == SCROLLHANDLE_BAR) {
2256  if (((vsm->scroller == 'h') && (v2d->keepofs & V2D_LOCKOFS_X)) ||
2257  ((vsm->scroller == 'v') && (v2d->keepofs & V2D_LOCKOFS_Y))) {
2258  /* free customdata initialized */
2260 
2261  /* can't catch this event for ourselves, so let it go to someone else? */
2262  return OPERATOR_PASS_THROUGH;
2263  }
2264  }
2265 
2266  /* zone is also inappropriate if scroller is not visible... */
2267  if (((vsm->scroller == 'h') && (v2d->scroll & V2D_SCROLL_HORIZONTAL_FULLR)) ||
2268  ((vsm->scroller == 'v') && (v2d->scroll & V2D_SCROLL_VERTICAL_FULLR))) {
2269  /* free customdata initialized */
2271 
2272  /* can't catch this event for ourselves, so let it go to someone else? */
2273  /* XXX note: if handlers use mask rect to clip input, input will fail for this case */
2274  return OPERATOR_PASS_THROUGH;
2275  }
2276 
2277  /* activate the scroller */
2278  if (vsm->scroller == 'h') {
2280  }
2281  else {
2283  }
2284 
2285  /* still ok, so can add */
2287  return OPERATOR_RUNNING_MODAL;
2288  }
2289 
2290  /* not in scroller, so nothing happened...
2291  * (pass through let's something else catch event) */
2292  return OPERATOR_PASS_THROUGH;
2293 }
2294 
2295 /* LMB-Drag in Scrollers - not repeatable operator! */
2297 {
2298  /* identifiers */
2299  ot->name = "Scroller Activate";
2300  ot->description = "Scroll view by mouse click and drag";
2301  ot->idname = "VIEW2D_OT_scroller_activate";
2302 
2303  /* flags */
2304  ot->flag = OPTYPE_BLOCKING;
2305 
2306  /* api callbacks */
2310 
2312 }
2313 
2316 /* -------------------------------------------------------------------- */
2321 {
2322  const uiStyle *style = UI_style_get();
2323  ARegion *region = CTX_wm_region(C);
2324  View2D *v2d = &region->v2d;
2325  const int snap_test = ED_region_snap_size_test(region);
2326 
2327  /* zoom 1.0 */
2328  const int winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1);
2329  const int winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1);
2330 
2331  v2d->cur.xmax = v2d->cur.xmin + winx;
2332  v2d->cur.ymax = v2d->cur.ymin + winy;
2333 
2334  /* align */
2335  if (v2d->align) {
2336  /* posx and negx flags are mutually exclusive, so watch out */
2337  if ((v2d->align & V2D_ALIGN_NO_POS_X) && !(v2d->align & V2D_ALIGN_NO_NEG_X)) {
2338  v2d->cur.xmax = 0.0f;
2339  v2d->cur.xmin = -winx * style->panelzoom;
2340  }
2341  else if ((v2d->align & V2D_ALIGN_NO_NEG_X) && !(v2d->align & V2D_ALIGN_NO_POS_X)) {
2342  v2d->cur.xmax = winx * style->panelzoom;
2343  v2d->cur.xmin = 0.0f;
2344  }
2345 
2346  /* - posx and negx flags are mutually exclusive, so watch out */
2347  if ((v2d->align & V2D_ALIGN_NO_POS_Y) && !(v2d->align & V2D_ALIGN_NO_NEG_Y)) {
2348  v2d->cur.ymax = 0.0f;
2349  v2d->cur.ymin = -winy * style->panelzoom;
2350  }
2351  else if ((v2d->align & V2D_ALIGN_NO_NEG_Y) && !(v2d->align & V2D_ALIGN_NO_POS_Y)) {
2352  v2d->cur.ymax = winy * style->panelzoom;
2353  v2d->cur.ymin = 0.0f;
2354  }
2355  }
2356 
2357  /* Inform v2d about changes after this operation. */
2359 
2360  if (ED_region_snap_size_apply(region, snap_test)) {
2361  ScrArea *area = CTX_wm_area(C);
2364  }
2365 
2366  /* request updates to be done... */
2367  ED_region_tag_redraw(region);
2369 
2371 
2372  return OPERATOR_FINISHED;
2373 }
2374 
2376 {
2377  /* identifiers */
2378  ot->name = "Reset View";
2379  ot->description = "Reset the view";
2380  ot->idname = "VIEW2D_OT_reset";
2381 
2382  /* api callbacks */
2383  ot->exec = reset_exec;
2384  ot->poll = view2d_poll;
2385 }
2386 
2389 /* -------------------------------------------------------------------- */
2394 {
2397 
2402 
2405 
2408 
2409 #ifdef WITH_INPUT_NDOF
2410  WM_operatortype_append(VIEW2D_OT_ndof);
2411 #endif
2412 
2414 
2416 
2418 }
2419 
2421 {
2422  WM_keymap_ensure(keyconf, "View2D", 0, 0);
2423 }
2424 
typedef float(TangentPoint)[2]
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition: BLI_rect.h:157
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition: BLI_rect.h:148
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition: BLI_rect.h:144
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y)
Definition: rct.c:646
bool BLI_rcti_isect_pt(const struct rcti *rect, const int x, const int y)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:153
void BLI_rctf_interp(struct rctf *rect, const struct rctf *rect_a, const struct rctf *rect_b, const float fac)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:161
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:165
void BLI_rctf_union(struct rctf *rct1, const struct rctf *rct2)
#define UNUSED(x)
#define ELEM(...)
#define IN_RANGE_INCL(a, b, c)
typedef double(DMatrix)[4][4]
@ RGN_TYPE_WINDOW
@ SPACE_SEQ
@ USER_ZOOM_INVERT
@ USER_ZOOM_TO_MOUSEPOS
@ USER_ZOOM_HORIZ
@ USER_ZOOM_SCALE
@ USER_ZOOM_CONTINUE
@ NDOF_ZOOM_INVERT
@ V2D_IS_INIT
@ V2D_SCROLL_V_ACTIVE
@ V2D_SCROLL_H_ACTIVE
@ V2D_SCROLL_HORIZONTAL_FULLR
@ V2D_SCROLL_VERTICAL_FULLR
@ V2D_SCROLL_VERTICAL_HANDLES
@ V2D_SCROLL_HORIZONTAL_HANDLES
@ V2D_ALIGN_NO_NEG_X
@ V2D_ALIGN_NO_NEG_Y
@ V2D_ALIGN_NO_POS_Y
@ V2D_ALIGN_NO_POS_X
@ V2D_LIMITZOOM
@ V2D_LOCKZOOM_X
@ V2D_KEEPASPECT
@ V2D_LOCKZOOM_Y
@ V2D_LOCKOFS_X
@ V2D_LOCKOFS_Y
@ V2D_KEEPOFS_Y
@ V2D_KEEPOFS_X
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:745
int ED_region_snap_size_test(const struct ARegion *region)
void ED_region_tag_redraw_no_rebuild(struct ARegion *region)
Definition: area.c:686
bool ED_region_snap_size_apply(struct ARegion *region, int snap_flag)
Definition: area.c:3794
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
NSNotificationCenter * center
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Platform independent time functions.
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
const struct uiStyle * UI_style_get(void)
#define UI_UNIT_X
#define V2D_LOCK_COPY
Definition: UI_view2d.h:84
char UI_view2d_mouse_in_scrollers(const struct ARegion *region, const struct View2D *v2d, int x, int y)
void UI_view2d_region_to_view_rctf(const struct View2D *v2d, const struct rctf *rect_src, struct rctf *rect_dst) ATTR_NONNULL()
#define V2D_SCROLL_HANDLE_SIZE_HOTSPOT
Definition: UI_view2d.h:74
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
void UI_view2d_zoom_cache_reset(void)
Definition: view2d.c:1057
void UI_view2d_sync(struct bScreen *screen, struct ScrArea *area, struct View2D *v2dcur, int flag)
Definition: view2d.c:876
void UI_view2d_curRect_changed(const struct bContext *C, struct View2D *v2d)
void UI_view2d_scrollers_calc(struct View2D *v2d, const struct rcti *mask_custom, struct View2DScrollers *r_scrollers)
@ OPTYPE_INTERNAL
Definition: WM_types.h:175
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_LOCK_BYPASS
Definition: WM_types.h:178
@ OPTYPE_GRAB_CURSOR_XY
Definition: WM_types.h:161
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:197
#define NC_SCREEN
Definition: WM_types.h:278
#define NA_EDITED
Definition: WM_types.h:462
#define KM_PRESS
Definition: WM_types.h:242
#define KM_RELEASE
Definition: WM_types.h:243
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
double time
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static void area(int d1, int d2, int e1, int e2, float weights[2])
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2331
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:6366
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
#define min(a, b)
Definition: sort.c:51
short regiontype
short flag
float minzoom
struct SmoothView2DStore * sms
short align
short scroll_ui
short keepzoom
struct wmTimer * smooth_timer
short keepofs
short scroll
float maxzoom
float xmax
Definition: DNA_vec_types.h:85
float xmin
Definition: DNA_vec_types.h:85
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79
float scrollbarwidth
Definition: view2d_ops.c:1873
ARegion * region
Definition: view2d_ops.c:1856
bScreen * screen
Definition: view2d_ops.c:82
View2D * v2d
Definition: view2d_ops.c:88
ARegion * region
Definition: view2d_ops.c:86
ScrArea * area
Definition: view2d_ops.c:84
double edge_pan_last_time
Definition: view2d_ops.c:105
short in_scroller
Definition: view2d_ops.c:102
double edge_pan_start_time_x
Definition: view2d_ops.c:106
double edge_pan_start_time_y
Definition: view2d_ops.c:106
wmTimer * timer
Definition: view2d_ops.c:749
double timer_lastdraw
Definition: view2d_ops.c:750
View2D * v2d
Definition: view2d_ops.c:745
ARegion * region
Definition: view2d_ops.c:746
bool zoom_to_mouse_pos
Definition: view2d_ops.c:756
int y
Definition: WM_types.h:581
short val
Definition: WM_types.h:579
int mval[2]
Definition: WM_types.h:583
int prevy
Definition: WM_types.h:614
int x
Definition: WM_types.h:581
int prevx
Definition: WM_types.h:614
short type
Definition: WM_types.h:577
void * customdata
Definition: WM_types.h:631
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct PointerRNA * ptr
double duration
Definition: WM_types.h:705
struct wmEvent * eventstate
double PIL_check_seconds_timer(void)
Definition: time.c:80
float max
ccl_device_inline float distance(const float2 &a, const float2 &b)
static void VIEW2D_OT_scroll_up(wmOperatorType *ot)
Definition: view2d_ops.c:704
static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
Definition: view2d_ops.c:1767
struct v2dViewZoomData v2dViewZoomData
static int view_scrollup_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:673
static void VIEW2D_OT_scroll_left(wmOperatorType *ot)
Definition: view2d_ops.c:607
struct v2dViewPanData v2dViewPanData
static void view_pan_cancel(bContext *UNUSED(C), wmOperator *op)
Definition: view2d_ops.c:308
static void scroller_activate_apply(bContext *C, wmOperator *op)
Definition: view2d_ops.c:2076
static bool view_zoom_poll(bContext *C)
Definition: view2d_ops.c:781
static int view_scrolldown_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:624
static int view_zoomout_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:1040
static void VIEW2D_OT_scroller_activate(wmOperatorType *ot)
Definition: view2d_ops.c:2296
struct v2dScrollerMove v2dScrollerMove
static int view_zoomin_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:976
static int view_edge_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:432
static int view_scrollleft_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:582
static void VIEW2D_OT_scroll_down(wmOperatorType *ot)
Definition: view2d_ops.c:655
static void edge_pan_manage_delay_timers(v2dViewPanData *vpd, int pan_dir_x, int pan_dir_y, const double current_time)
Definition: view2d_ops.c:372
static void view_zoomstep_apply(bContext *C, wmOperator *op)
Definition: view2d_ops.c:933
static void VIEW2D_OT_pan(wmOperatorType *ot)
Definition: view2d_ops.c:313
static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const float facx, const float facy)
Definition: view2d_ops.c:824
static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
Definition: view2d_ops.c:1058
static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float dy)
Definition: view2d_ops.c:153
static void scroller_activate_exit(bContext *C, wmOperator *op)
Definition: view2d_ops.c:2056
static int view_zoomin_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:955
static int view_pan_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:203
#define EDGE_PAN_REGION_PAD
Definition: view2d_ops.c:345
static void VIEW2D_OT_zoom_border(wmOperatorType *ot)
Definition: view2d_ops.c:1558
static void view_pan_exit(wmOperator *op)
Definition: view2d_ops.c:191
static int view_scrollright_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:540
static void VIEW2D_OT_zoom(wmOperatorType *ot)
Definition: view2d_ops.c:1450
static bool view2d_poll(bContext *C)
Definition: view2d_ops.c:55
static void view_zoomdrag_exit(bContext *C, wmOperator *op)
Definition: view2d_ops.c:1176
static float smootherstep(const float domain_max, float x)
Definition: view2d_ops.c:397
static void VIEW2D_OT_zoom_in(wmOperatorType *ot)
Definition: view2d_ops.c:994
static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:1318
static void view_zoomdrag_apply(bContext *C, wmOperator *op)
Definition: view2d_ops.c:1096
#define EDGE_PAN_SPEED_PER_PIXEL
Definition: view2d_ops.c:347
@ SCROLLHANDLE_BAR
Definition: view2d_ops.c:1902
@ SCROLLHANDLE_MIN_OUTSIDE
Definition: view2d_ops.c:1904
@ SCROLLHANDLE_MAX
Definition: view2d_ops.c:1903
@ SCROLLHANDLE_MIN
Definition: view2d_ops.c:1901
@ SCROLLHANDLE_MAX_OUTSIDE
Definition: view2d_ops.c:1905
static void scroller_activate_cancel(bContext *C, wmOperator *op)
Definition: view2d_ops.c:2070
#define EDGE_PAN_DELAY
Definition: view2d_ops.c:349
void ED_keymap_view2d(wmKeyConfig *keyconf)
Definition: view2d_ops.c:2420
static void view_edge_pan_cancel(bContext *UNUSED(C), wmOperator *op)
Definition: view2d_ops.c:497
static int view_zoomout_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:1018
static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
Definition: view2d_ops.c:1673
static int view_borderzoom_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:1495
void UI_view2d_smooth_view(bContext *C, ARegion *region, const rctf *cur, const int smooth_viewtx)
Definition: view2d_ops.c:1702
static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:1207
static void view_pan_init(bContext *C, wmOperator *op)
Definition: view2d_ops.c:130
static int view_edge_pan_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: view2d_ops.c:352
static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:2211
static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:212
static float edge_pan_speed(v2dViewPanData *vpd, int event_loc, bool x_dir, const double current_time)
Definition: view2d_ops.c:403
static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:257
void ED_operatortypes_view2d(void)
Definition: view2d_ops.c:2393
static void VIEW2D_OT_scroll_right(wmOperatorType *ot)
Definition: view2d_ops.c:565
static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max)
Definition: view2d_ops.c:1915
static void view_pan_apply(bContext *C, wmOperator *op)
Definition: view2d_ops.c:183
static bool view_pan_poll(bContext *C)
Definition: view2d_ops.c:109
static void VIEW2D_OT_edge_pan(wmOperatorType *ot)
Definition: view2d_ops.c:502
static void view_zoomdrag_cancel(bContext *C, wmOperator *op)
Definition: view2d_ops.c:1192
static void VIEW2D_OT_reset(wmOperatorType *ot)
Definition: view2d_ops.c:2375
static int view_zoomdrag_exec(bContext *C, wmOperator *op)
Definition: view2d_ops.c:1198
static bool scroller_activate_poll(bContext *C)
Definition: view2d_ops.c:1964
static void VIEW2D_OT_smoothview(wmOperatorType *ot)
Definition: view2d_ops.c:1818
static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: view2d_ops.c:2138
static int reset_exec(bContext *C, wmOperator *UNUSED(op))
Definition: view2d_ops.c:2320
static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *event, const char in_scroller)
Definition: view2d_ops.c:1980
static void view_zoomdrag_init(bContext *C, wmOperator *op)
Definition: view2d_ops.c:807
static void view_zoomstep_exit(wmOperator *op)
Definition: view2d_ops.c:947
static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2])
Definition: view2d_ops.c:763
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:207
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:216
@ WM_CURSOR_NSEW_SCROLL
Definition: wm_cursors.h:67
@ WM_CURSOR_NS_SCROLL
Definition: wm_cursors.h:68
@ WM_CURSOR_EW_SCROLL
Definition: wm_cursors.h:69
int WM_event_absolute_delta_y(const struct wmEvent *event)
int WM_event_absolute_delta_x(const struct wmEvent *event)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_event_add_mousemove(wmWindow *win)
@ MOUSEPAN
@ TIMER
@ MOUSEZOOM
@ TIMER1
@ MOUSEMOVE
@ LEFTMOUSE
@ NDOF_MOTION
@ MIDDLEMOUSE
@ EVT_ESCKEY
wmOperatorType * ot
Definition: wm_files.c:3156
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition: wm_keymap.c:852
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_use_cursor_init(wmOperatorType *ot)
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
int WM_operator_smooth_viewtx_get(const wmOperator *op)
Definition: wm_operators.c:944
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1669
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1632