Blender  V2.93
wm_gesture_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) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
30 #include "MEM_guardedalloc.h"
31 
33 
34 #include "BLI_math.h"
35 #include "BLI_rect.h"
36 
37 #include "BKE_context.h"
38 
39 #include "WM_api.h"
40 #include "WM_types.h"
41 
42 #include "wm.h"
43 #include "wm_event_system.h"
44 #include "wm_event_types.h"
45 
46 #include "ED_screen.h"
47 #include "ED_select_utils.h"
48 
49 #include "UI_interface.h"
50 
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53 
54 /* -------------------------------------------------------------------- */
66 {
67  wmWindow *win = CTX_wm_window(C);
68  wmGesture *gesture = op->customdata;
69 
70  WM_gesture_end(win, gesture); /* frees gesture itself, and unregisters from window */
71  op->customdata = NULL;
72 
74 
75  if (RNA_struct_find_property(op->ptr, "cursor")) {
77  }
78 }
79 
80 static void gesture_modal_state_to_operator(wmOperator *op, int modal_state)
81 {
82  PropertyRNA *prop;
83 
84  switch (modal_state) {
87  if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) {
88  RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT));
89  }
90  if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
92  op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT) ? SEL_OP_SUB : SEL_OP_ADD);
93  }
94  break;
95  case GESTURE_MODAL_IN:
96  case GESTURE_MODAL_OUT:
97  if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) {
98  RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_OUT));
99  }
100  break;
101  }
102 }
103 
105 {
106  PropertyRNA *prop;
107 
108  if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) {
109  if (RNA_property_is_set(op->ptr, prop)) {
110  return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_DESELECT :
112  }
113  }
114  if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
115  if (RNA_property_is_set(op->ptr, prop)) {
116  return RNA_property_enum_get(op->ptr, prop) == SEL_OP_SUB ? GESTURE_MODAL_DESELECT :
118  }
119  }
120  if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) {
121  if (RNA_property_is_set(op->ptr, prop)) {
123  }
124  }
125  return GESTURE_MODAL_NOP;
126 }
129 /* -------------------------------------------------------------------- */
141 {
142  wmGesture *gesture = op->customdata;
143  rcti *rect = gesture->customdata;
144 
145  if (rect->xmin == rect->xmax || rect->ymin == rect->ymax) {
146  return 0;
147  }
148 
149  /* operator arguments and storage. */
150  RNA_int_set(op->ptr, "xmin", min_ii(rect->xmin, rect->xmax));
151  RNA_int_set(op->ptr, "ymin", min_ii(rect->ymin, rect->ymax));
152  RNA_int_set(op->ptr, "xmax", max_ii(rect->xmin, rect->xmax));
153  RNA_int_set(op->ptr, "ymax", max_ii(rect->ymin, rect->ymax));
154 
155  return 1;
156 }
157 
159 {
160  wmGesture *gesture = op->customdata;
161 
162  int retval;
163 
164  if (!gesture_box_apply_rect(op)) {
165  return 0;
166  }
167 
168  if (gesture->wait_for_input) {
170  }
171 
172  retval = op->type->exec(C, op);
173  OPERATOR_RETVAL_CHECK(retval);
174 
175  return 1;
176 }
177 
179 {
180  wmWindow *win = CTX_wm_window(C);
181  const ARegion *region = CTX_wm_region(C);
182  const bool wait_for_input = !ISTWEAK(event->type) && RNA_boolean_get(op->ptr, "wait_for_input");
183 
184  if (wait_for_input) {
185  op->customdata = WM_gesture_new(win, region, event, WM_GESTURE_CROSS_RECT);
186  }
187  else {
188  op->customdata = WM_gesture_new(win, region, event, WM_GESTURE_RECT);
189  }
190 
191  {
192  wmGesture *gesture = op->customdata;
193  gesture->wait_for_input = wait_for_input;
194  }
195 
196  /* add modal handler */
198 
200 
201  return OPERATOR_RUNNING_MODAL;
202 }
203 
205 {
206  wmWindow *win = CTX_wm_window(C);
207  wmGesture *gesture = op->customdata;
208  rcti *rect = gesture->customdata;
209 
210  if (event->type == EVT_MODAL_MAP) {
211  switch (event->val) {
212  case GESTURE_MODAL_MOVE: {
213  gesture->move = !gesture->move;
214  break;
215  }
216  case GESTURE_MODAL_BEGIN: {
217  if (gesture->type == WM_GESTURE_CROSS_RECT && gesture->is_active == false) {
218  gesture->is_active = true;
220  }
221  break;
222  }
225  case GESTURE_MODAL_IN:
226  case GESTURE_MODAL_OUT: {
227  if (gesture->wait_for_input) {
228  gesture->modal_state = event->val;
229  }
230  if (gesture_box_apply(C, op)) {
231  gesture_modal_end(C, op);
232  return OPERATOR_FINISHED;
233  }
234  gesture_modal_end(C, op);
235  return OPERATOR_CANCELLED;
236  }
237  case GESTURE_MODAL_CANCEL: {
238  gesture_modal_end(C, op);
239  return OPERATOR_CANCELLED;
240  }
241  }
242  }
243  else {
244  switch (event->type) {
245  case MOUSEMOVE: {
246  if (gesture->type == WM_GESTURE_CROSS_RECT && gesture->is_active == false) {
247  rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
248  rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
249  }
250  else if (gesture->move) {
251  BLI_rcti_translate(rect,
252  (event->x - gesture->winrct.xmin) - rect->xmax,
253  (event->y - gesture->winrct.ymin) - rect->ymax);
254  }
255  else {
256  rect->xmax = event->x - gesture->winrct.xmin;
257  rect->ymax = event->y - gesture->winrct.ymin;
258  }
260 
262 
263  break;
264  }
265 #ifdef WITH_INPUT_NDOF
266  case NDOF_MOTION: {
267  return OPERATOR_PASS_THROUGH;
268  }
269 #endif
270 
271 #if 0 /* This allows view navigation, keep disabled as it's too unpredictable. */
272  default:
273  return OPERATOR_PASS_THROUGH;
274 #endif
275  }
276  }
277 
278  gesture->is_active_prev = gesture->is_active;
279  return OPERATOR_RUNNING_MODAL;
280 }
281 
283 {
284  gesture_modal_end(C, op);
285 }
286 
289 /* -------------------------------------------------------------------- */
298 static void gesture_circle_apply(bContext *C, wmOperator *op);
299 
301 {
302  wmWindow *win = CTX_wm_window(C);
303  const bool wait_for_input = !ISTWEAK(event->type) && RNA_boolean_get(op->ptr, "wait_for_input");
304 
306  wmGesture *gesture = op->customdata;
307  rcti *rect = gesture->customdata;
308 
309  /* Default or previously stored value. */
310  rect->xmax = RNA_int_get(op->ptr, "radius");
311 
312  gesture->wait_for_input = wait_for_input;
313 
314  /* Starting with the mode starts immediately,
315  * like having 'wait_for_input' disabled (some tools use this). */
316  if (gesture->wait_for_input == false) {
317  gesture->is_active = true;
318  gesture_circle_apply(C, op);
319  }
320 
321  /* add modal handler */
323 
325 
326  return OPERATOR_RUNNING_MODAL;
327 }
328 
330 {
331  wmGesture *gesture = op->customdata;
332  rcti *rect = gesture->customdata;
333 
334  if (gesture->wait_for_input && (gesture->modal_state == GESTURE_MODAL_NOP)) {
335  return;
336  }
337 
338  /* operator arguments and storage. */
339  RNA_int_set(op->ptr, "x", rect->xmin);
340  RNA_int_set(op->ptr, "y", rect->ymin);
341  RNA_int_set(op->ptr, "radius", rect->xmax);
342 
343  /* When 'wait_for_input' is false,
344  * use properties to get the selection state (typically tool settings).
345  * This is done so executing as a mode can select & de-select, see: T58594. */
346  if (gesture->wait_for_input) {
348  }
349 
350  if (op->type->exec) {
351  int retval;
352  retval = op->type->exec(C, op);
353  OPERATOR_RETVAL_CHECK(retval);
354  }
355 }
356 
358 {
359  wmWindow *win = CTX_wm_window(C);
360  wmGesture *gesture = op->customdata;
361  rcti *rect = gesture->customdata;
362 
363  if (event->type == MOUSEMOVE) {
364 
365  rect->xmin = event->x - gesture->winrct.xmin;
366  rect->ymin = event->y - gesture->winrct.ymin;
367 
369 
370  if (gesture->is_active) {
371  gesture_circle_apply(C, op);
372  }
373  }
374  else if (event->type == EVT_MODAL_MAP) {
375  bool is_circle_size = false;
376  bool is_finished = false;
377  float fac;
378 
379  switch (event->val) {
381  fac = 0.3f * (event->y - event->prevy);
382  if (fac > 0) {
383  rect->xmax += ceil(fac);
384  }
385  else {
386  rect->xmax += floor(fac);
387  }
388  if (rect->xmax < 1) {
389  rect->xmax = 1;
390  }
391  is_circle_size = true;
392  break;
394  rect->xmax += 2 + rect->xmax / 10;
395  is_circle_size = true;
396  break;
398  rect->xmax -= 2 + rect->xmax / 10;
399  if (rect->xmax < 1) {
400  rect->xmax = 1;
401  }
402  is_circle_size = true;
403  break;
406  case GESTURE_MODAL_NOP: {
407  if (gesture->wait_for_input) {
408  gesture->modal_state = event->val;
409  }
410  if (event->val == GESTURE_MODAL_NOP) {
411  /* Single action, click-drag & release to exit. */
412  if (gesture->wait_for_input == false) {
413  is_finished = true;
414  }
415  }
416  else {
417  /* apply first click */
418  gesture->is_active = true;
419  gesture_circle_apply(C, op);
421  }
422  break;
423  }
426  is_finished = true;
427  }
428 
429  if (is_finished) {
430  gesture_modal_end(C, op);
431  return OPERATOR_FINISHED; /* use finish or we don't get an undo */
432  }
433 
434  if (is_circle_size) {
436 
437  /* So next use remembers last seen size, even if we didn't apply it. */
438  RNA_int_set(op->ptr, "radius", rect->xmax);
439  }
440  }
441 #ifdef WITH_INPUT_NDOF
442  else if (event->type == NDOF_MOTION) {
443  return OPERATOR_PASS_THROUGH;
444  }
445 #endif
446 
447 #if 0
448  /* Allow view navigation??? */
449  /* note, this gives issues:
450  * 1) other modal ops run on top (box select),
451  * 2) middle-mouse is used now 3) tablet/trackpad? */
452  else {
453  return OPERATOR_PASS_THROUGH;
454  }
455 #endif
456 
457  gesture->is_active_prev = gesture->is_active;
458  return OPERATOR_RUNNING_MODAL;
459 }
460 
462 {
463  gesture_modal_end(C, op);
464 }
465 
466 #if 0
467 /* template to copy from */
468 void WM_OT_circle_gesture(wmOperatorType *ot)
469 {
470  ot->name = "Circle Gesture";
471  ot->idname = "WM_OT_circle_gesture";
472  ot->description = "Enter rotate mode with a circular gesture";
473 
477 
478  /* properties */
480 }
481 #endif
482 
485 /* -------------------------------------------------------------------- */
489 static void gesture_tweak_modal(bContext *C, const wmEvent *event)
490 {
491  wmWindow *window = CTX_wm_window(C);
492  wmGesture *gesture = window->tweak;
493  rcti *rect = gesture->customdata;
494  bool gesture_end = false;
495 
496  switch (event->type) {
497  case MOUSEMOVE:
498  case INBETWEEN_MOUSEMOVE: {
499 
500  rect->xmax = event->x - gesture->winrct.xmin;
501  rect->ymax = event->y - gesture->winrct.ymin;
502 
503  const int val = wm_gesture_evaluate(gesture, event);
504  if (val != 0) {
505  wmEvent tevent;
506 
507  wm_event_init_from_window(window, &tevent);
508  /* We want to get coord from start of drag,
509  * not from point where it becomes a tweak event, see T40549. */
510  tevent.x = rect->xmin + gesture->winrct.xmin;
511  tevent.y = rect->ymin + gesture->winrct.ymin;
512  if (gesture->event_type == LEFTMOUSE) {
513  tevent.type = EVT_TWEAK_L;
514  }
515  else if (gesture->event_type == RIGHTMOUSE) {
516  tevent.type = EVT_TWEAK_R;
517  }
518  else {
519  tevent.type = EVT_TWEAK_M;
520  }
521  tevent.val = val;
522  tevent.is_repeat = false;
523  /* mouse coords! */
524 
525  /* important we add immediately after this event, so future mouse releases
526  * (which may be in the queue already), are handled in order, see T44740 */
527  wm_event_add_ex(window, &tevent, event);
528 
529  gesture_end = true;
530  }
531 
532  break;
533  }
534 
535  case LEFTMOUSE:
536  case RIGHTMOUSE:
537  case MIDDLEMOUSE:
538  if (gesture->event_type == event->type) {
539  gesture_end = true;
540 
541  /* when tweak fails we should give the other keymap entries a chance */
542 
543  /* XXX, assigning to readonly, BAD JUJU! */
544  ((wmEvent *)event)->val = KM_RELEASE;
545  }
546  break;
547  default:
548  if (!ISTIMER(event->type) && event->type != EVENT_NONE) {
549  gesture_end = true;
550  }
551  break;
552  }
553 
554  if (gesture_end) {
555  /* Frees gesture itself, and unregisters from window. */
556  WM_gesture_end(window, gesture);
557 
558  /* This isn't very nice but needed to redraw gizmos which are hidden while tweaking,
559  * See #WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK for details. */
560  ARegion *region = CTX_wm_region(C);
561  if ((region != NULL) && (region->gizmo_map != NULL)) {
563  ED_region_tag_redraw(region);
564  }
565  }
566  }
567 }
568 
569 /* standard tweak, called after window handlers passed on event */
570 void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
571 {
572  wmWindow *win = CTX_wm_window(C);
573 
574  if (win->tweak == NULL) {
575  const ARegion *region = CTX_wm_region(C);
576 
577  if (region) {
578  if (event->val == KM_PRESS) {
579  if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
580  win->tweak = WM_gesture_new(win, region, event, WM_GESTURE_TWEAK);
581  }
582  }
583  }
584  }
585  else {
586  /* no tweaks if event was handled */
587  if ((action & WM_HANDLER_BREAK)) {
588  WM_gesture_end(win, win->tweak);
589  }
590  else {
591  gesture_tweak_modal(C, event);
592  }
593  }
594 }
595 
598 /* -------------------------------------------------------------------- */
603 {
604  wmWindow *win = CTX_wm_window(C);
605  PropertyRNA *prop;
606 
608 
609  /* add modal handler */
611 
613 
614  if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) {
616  }
617 
618  return OPERATOR_RUNNING_MODAL;
619 }
620 
622 {
623  wmWindow *win = CTX_wm_window(C);
624  PropertyRNA *prop;
625 
627 
628  /* add modal handler */
630 
632 
633  if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) {
635  }
636 
637  return OPERATOR_RUNNING_MODAL;
638 }
639 
641 {
642  int retval = OPERATOR_FINISHED;
643  wmGesture *gesture = op->customdata;
644  PointerRNA itemptr;
645  float loc[2];
646  int i;
647  const short *lasso = gesture->customdata;
648 
649  /* operator storage as path. */
650 
651  RNA_collection_clear(op->ptr, "path");
652  for (i = 0; i < gesture->points; i++, lasso += 2) {
653  loc[0] = lasso[0];
654  loc[1] = lasso[1];
655  RNA_collection_add(op->ptr, "path", &itemptr);
656  RNA_float_set_array(&itemptr, "loc", loc);
657  }
658 
659  gesture_modal_end(C, op);
660 
661  if (op->type->exec) {
662  retval = op->type->exec(C, op);
663  OPERATOR_RETVAL_CHECK(retval);
664  }
665 
666  return retval;
667 }
668 
670 {
671  wmGesture *gesture = op->customdata;
672 
673  if (event->type == EVT_MODAL_MAP) {
674  switch (event->val) {
675  case GESTURE_MODAL_MOVE: {
676  gesture->move = !gesture->move;
677  break;
678  }
679  }
680  }
681  else {
682  switch (event->type) {
683  case MOUSEMOVE:
684  case INBETWEEN_MOUSEMOVE: {
686 
687  if (gesture->points == gesture->points_alloc) {
688  gesture->points_alloc *= 2;
689  gesture->customdata = MEM_reallocN(gesture->customdata,
690  sizeof(short[2]) * gesture->points_alloc);
691  }
692 
693  {
694  short(*lasso)[2] = gesture->customdata;
695 
696  const int x = ((event->x - gesture->winrct.xmin) - lasso[gesture->points - 1][0]);
697  const int y = ((event->y - gesture->winrct.ymin) - lasso[gesture->points - 1][1]);
698 
699  /* move the lasso */
700  if (gesture->move) {
701  for (int i = 0; i < gesture->points; i++) {
702  lasso[i][0] += x;
703  lasso[i][1] += y;
704  }
705  }
706  /* Make a simple distance check to get a smoother lasso
707  * add only when at least 2 pixels between this and previous location. */
708  else if ((x * x + y * y) > pow2f(2.0f * UI_DPI_FAC)) {
709  lasso[gesture->points][0] = event->x - gesture->winrct.xmin;
710  lasso[gesture->points][1] = event->y - gesture->winrct.ymin;
711  gesture->points++;
712  }
713  }
714  break;
715  }
716  case LEFTMOUSE:
717  case MIDDLEMOUSE:
718  case RIGHTMOUSE: {
719  if (event->val == KM_RELEASE) { /* key release */
720  return gesture_lasso_apply(C, op);
721  }
722  break;
723  }
724  case EVT_ESCKEY: {
725  gesture_modal_end(C, op);
726  return OPERATOR_CANCELLED;
727  }
728  }
729  }
730 
731  gesture->is_active_prev = gesture->is_active;
732  return OPERATOR_RUNNING_MODAL;
733 }
734 
736 {
737  return WM_gesture_lasso_modal(C, op, event);
738 }
739 
741 {
742  gesture_modal_end(C, op);
743 }
744 
746 {
747  gesture_modal_end(C, op);
748 }
749 
756  wmOperator *op,
757  int *r_mcoords_len))[2]
758 {
759  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "path");
760  int(*mcoords)[2] = NULL;
761  BLI_assert(prop != NULL);
762 
763  if (prop) {
764  const int len = RNA_property_collection_length(op->ptr, prop);
765 
766  if (len) {
767  int i = 0;
768  mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__);
769 
770  RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
771  float loc[2];
772 
773  RNA_float_get_array(&itemptr, "loc", loc);
774  mcoords[i][0] = (int)loc[0];
775  mcoords[i][1] = (int)loc[1];
776  i++;
777  }
778  RNA_PROP_END;
779  }
780  *r_mcoords_len = len;
781  }
782  else {
783  *r_mcoords_len = 0;
784  }
785 
786  /* cast for 'const' */
787  return mcoords;
788 }
789 
790 #if 0
791 /* template to copy from */
792 
793 static int gesture_lasso_exec(bContext *C, wmOperator *op)
794 {
795  RNA_BEGIN (op->ptr, itemptr, "path") {
796  float loc[2];
797 
798  RNA_float_get_array(&itemptr, "loc", loc);
799  printf("Location: %f %f\n", loc[0], loc[1]);
800  }
801  RNA_END;
802 
803  return OPERATOR_FINISHED;
804 }
805 
806 void WM_OT_lasso_gesture(wmOperatorType *ot)
807 {
808  PropertyRNA *prop;
809 
810  ot->name = "Lasso Gesture";
811  ot->idname = "WM_OT_lasso_gesture";
812  ot->description = "Select objects within the lasso as you move the pointer";
813 
816  ot->exec = gesture_lasso_exec;
817 
819 
820  prop = RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
822 }
823 #endif
824 
827 /* -------------------------------------------------------------------- */
841 {
842  wmGesture *gesture = op->customdata;
843  rcti *rect = gesture->customdata;
844 
845  if (rect->xmin == rect->xmax && rect->ymin == rect->ymax) {
846  return 0;
847  }
848 
849  /* operator arguments and storage. */
850  RNA_int_set(op->ptr, "xstart", rect->xmin);
851  RNA_int_set(op->ptr, "ystart", rect->ymin);
852  RNA_int_set(op->ptr, "xend", rect->xmax);
853  RNA_int_set(op->ptr, "yend", rect->ymax);
854  RNA_boolean_set(op->ptr, "flip", gesture->use_flip);
855 
856  if (op->type->exec) {
857  int retval = op->type->exec(C, op);
858  OPERATOR_RETVAL_CHECK(retval);
859  }
860 
861  return 1;
862 }
863 
865 {
866  wmWindow *win = CTX_wm_window(C);
867  PropertyRNA *prop;
868 
870 
871  if (ISTWEAK(event->type)) {
872  wmGesture *gesture = op->customdata;
873  gesture->is_active = true;
874  }
875 
876  /* add modal handler */
878 
880 
881  if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) {
883  }
884 
885  return OPERATOR_RUNNING_MODAL;
886 }
892 {
893  WM_gesture_straightline_invoke(C, op, event);
894  wmGesture *gesture = op->customdata;
895  gesture->draw_active_side = true;
896  gesture->use_flip = false;
897  return OPERATOR_RUNNING_MODAL;
898 }
899 
900 #define STRAIGHTLINE_SNAP_DEG 15.0f
902 {
903  const float line_start[2] = {rect->xmin, rect->ymin};
904  const float line_end[2] = {rect->xmax, rect->ymax};
905  const float x_axis[2] = {1.0f, 0.0f};
906 
907  float line_direction[2];
908  sub_v2_v2v2(line_direction, line_end, line_start);
909  const float line_length = normalize_v2(line_direction);
910 
911  const float angle = angle_signed_v2v2(x_axis, line_direction);
912  const float angle_deg = RAD2DEG(angle) + (STRAIGHTLINE_SNAP_DEG / 2.0f);
913  const float angle_snapped_deg = -floorf(angle_deg / STRAIGHTLINE_SNAP_DEG) *
915  const float angle_snapped = DEG2RAD(angle_snapped_deg);
916 
917  float line_snapped_end[2];
918  rotate_v2_v2fl(line_snapped_end, x_axis, angle_snapped);
919  mul_v2_fl(line_snapped_end, line_length);
920  add_v2_v2(line_snapped_end, line_start);
921 
922  rect->xmax = (int)line_snapped_end[0];
923  rect->ymax = (int)line_snapped_end[1];
924 }
925 
932 {
933  wmGesture *gesture = op->customdata;
934  wmWindow *win = CTX_wm_window(C);
935  rcti *rect = gesture->customdata;
936 
937  if (event->type == EVT_MODAL_MAP) {
938  switch (event->val) {
939  case GESTURE_MODAL_MOVE: {
940  gesture->move = !gesture->move;
941  break;
942  }
943  case GESTURE_MODAL_BEGIN: {
944  if (gesture->is_active == false) {
945  gesture->is_active = true;
947  }
948  break;
949  }
950  case GESTURE_MODAL_SNAP: {
951  /* Toggle snapping on/off. */
952  gesture->use_snap = !gesture->use_snap;
953  break;
954  }
955  case GESTURE_MODAL_FLIP: {
956  /* Toggle snapping on/off. */
957  gesture->use_flip = !gesture->use_flip;
958  break;
959  }
960  case GESTURE_MODAL_SELECT: {
961  if (gesture_straightline_apply(C, op)) {
962  gesture_modal_end(C, op);
963  return OPERATOR_FINISHED;
964  }
965  gesture_modal_end(C, op);
966  return OPERATOR_CANCELLED;
967  }
968  case GESTURE_MODAL_CANCEL: {
969  gesture_modal_end(C, op);
970  return OPERATOR_CANCELLED;
971  }
972  }
973  }
974  else {
975  switch (event->type) {
976  case MOUSEMOVE: {
977  if (gesture->is_active == false) {
978  rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
979  rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
980  }
981  else if (gesture->move) {
982  BLI_rcti_translate(rect,
983  (event->x - gesture->winrct.xmin) - rect->xmax,
984  (event->y - gesture->winrct.ymin) - rect->ymax);
986  }
987  else {
988  rect->xmax = event->x - gesture->winrct.xmin;
989  rect->ymax = event->y - gesture->winrct.ymin;
991  }
992 
993  if (gesture->use_snap) {
996  }
997 
999 
1000  break;
1001  }
1002  }
1003  }
1004 
1005  gesture->is_active_prev = gesture->is_active;
1006  return OPERATOR_RUNNING_MODAL;
1007 }
1008 
1017 {
1018  wmGesture *gesture = op->customdata;
1019  wmWindow *win = CTX_wm_window(C);
1020  rcti *rect = gesture->customdata;
1021 
1022  if (event->type == EVT_MODAL_MAP) {
1023  switch (event->val) {
1024  case GESTURE_MODAL_MOVE: {
1025  gesture->move = !gesture->move;
1026  break;
1027  }
1028  case GESTURE_MODAL_BEGIN: {
1029  if (gesture->is_active == false) {
1030  gesture->is_active = true;
1031  wm_gesture_tag_redraw(win);
1032  }
1033  break;
1034  }
1035  case GESTURE_MODAL_SNAP: {
1036  /* Toggle snapping on/off. */
1037  gesture->use_snap = !gesture->use_snap;
1038  break;
1039  }
1040  case GESTURE_MODAL_FLIP: {
1041  /* Toggle flip on/off. */
1042  gesture->use_flip = !gesture->use_flip;
1043  break;
1044  }
1045  case GESTURE_MODAL_SELECT:
1047  case GESTURE_MODAL_IN:
1048  case GESTURE_MODAL_OUT: {
1049  if (gesture->wait_for_input) {
1050  gesture->modal_state = event->val;
1051  }
1052  if (gesture_straightline_apply(C, op)) {
1053  gesture_modal_end(C, op);
1054  return OPERATOR_FINISHED;
1055  }
1056  gesture_modal_end(C, op);
1057  return OPERATOR_CANCELLED;
1058  }
1059  case GESTURE_MODAL_CANCEL: {
1060  gesture_modal_end(C, op);
1061  return OPERATOR_CANCELLED;
1062  }
1063  }
1064  }
1065  else {
1066  switch (event->type) {
1067  case MOUSEMOVE: {
1068  if (gesture->is_active == false) {
1069  rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
1070  rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
1071  }
1072  else if (gesture->move) {
1073  BLI_rcti_translate(rect,
1074  (event->x - gesture->winrct.xmin) - rect->xmax,
1075  (event->y - gesture->winrct.ymin) - rect->ymax);
1076  }
1077  else {
1078  rect->xmax = event->x - gesture->winrct.xmin;
1079  rect->ymax = event->y - gesture->winrct.ymin;
1080  }
1081 
1082  if (gesture->use_snap) {
1084  }
1085 
1086  wm_gesture_tag_redraw(win);
1087 
1088  break;
1089  }
1090  }
1091  }
1092 
1093  gesture->is_active_prev = gesture->is_active;
1094  return OPERATOR_RUNNING_MODAL;
1095 }
1096 
1098 {
1099  gesture_modal_end(C, op);
1100 }
1101 
1102 #if 0
1103 /* template to copy from */
1104 void WM_OT_straightline_gesture(wmOperatorType *ot)
1105 {
1106  PropertyRNA *prop;
1107 
1108  ot->name = "Straight Line Gesture";
1109  ot->idname = "WM_OT_straightline_gesture";
1110  ot->description = "Draw a straight line as you move the pointer";
1111 
1114  ot->exec = gesture_straightline_exec;
1115 
1117 
1119 }
1120 #endif
1121 
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE int min_ii(int a, int b)
MINLINE float pow2f(float x)
MINLINE int max_ii(int a, int b)
#define DEG2RAD(_deg)
#define RAD2DEG(_rad)
void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
Definition: math_vector.c:914
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void add_v2_v2(float r[2], const float a[2])
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:499
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float normalize_v2(float r[2])
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition: rct.c:597
#define UNUSED_FUNCTION(x)
#define UNUSED(x)
#define ELEM(...)
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
#define OPERATOR_RETVAL_CHECK(ret)
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:745
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
@ SEL_OP_ADD
@ SEL_OP_SUB
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
#define RNA_PROP_END
Definition: RNA_access.h:1268
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:1248
#define RNA_END
Definition: RNA_access.h:1255
#define RNA_PROP_BEGIN(sptr, itemptr, prop)
Definition: RNA_access.h:1261
StructRNA RNA_OperatorMousePath
@ PROP_COLLECTION
Definition: RNA_types.h:79
@ PROP_NONE
Definition: RNA_types.h:113
#define C
Definition: RandGen.cpp:39
#define UI_DPI_FAC
Definition: UI_interface.h:309
#define WM_GESTURE_RECT
Definition: WM_types.h:477
#define WM_GESTURE_STRAIGHTLINE
Definition: WM_types.h:481
#define KM_PRESS
Definition: WM_types.h:242
#define WM_GESTURE_LINES
Definition: WM_types.h:476
#define WM_GESTURE_LASSO
Definition: WM_types.h:479
#define WM_GESTURE_TWEAK
Definition: WM_types.h:475
#define WM_GESTURE_CIRCLE
Definition: WM_types.h:480
#define WM_GESTURE_CROSS_RECT
Definition: WM_types.h:478
#define KM_RELEASE
Definition: WM_types.h:243
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
#define floorf(x)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
void RNA_collection_clear(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6622
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
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
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3562
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2331
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2607
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
Definition: rna_access.c:6610
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2358
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3543
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3903
void RNA_def_property_struct_runtime(StructOrFunctionRNA *cont, PropertyRNA *prop, StructRNA *type)
Definition: rna_define.c:1820
PropertyRNA * RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier, int type, int subtype)
Definition: rna_define.c:1279
struct wmGizmoMap * gizmo_map
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
int y
Definition: WM_types.h:581
short val
Definition: WM_types.h:579
int x
Definition: WM_types.h:581
short type
Definition: WM_types.h:577
char is_repeat
Definition: WM_types.h:599
uint wait_for_input
Definition: WM_types.h:512
uint use_snap
Definition: WM_types.h:517
int event_type
Definition: WM_types.h:490
uint is_active_prev
Definition: WM_types.h:510
int modal_state
Definition: WM_types.h:499
void * customdata
Definition: WM_types.h:529
int points_alloc
Definition: WM_types.h:498
uint move
Definition: WM_types.h:514
int type
Definition: WM_types.h:492
bool draw_active_side
Definition: WM_types.h:501
uint use_flip
Definition: WM_types.h:520
uint is_active
Definition: WM_types.h:508
rcti winrct
Definition: WM_types.h:494
int points
Definition: WM_types.h:496
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
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 wmOperatorType * type
struct PointerRNA * ptr
struct wmGesture * tweak
ccl_device_inline float2 floor(const float2 &a)
ccl_device_inline float3 ceil(const float3 &a)
uint len
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
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
wmEvent * wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
void wm_event_init_from_window(wmWindow *win, wmEvent *event)
#define WM_HANDLER_BREAK
#define ISTWEAK(event_type)
@ RIGHTMOUSE
@ EVT_MODAL_MAP
@ EVT_TWEAK_M
@ EVENT_NONE
@ MOUSEMOVE
@ EVT_TWEAK_R
@ LEFTMOUSE
@ NDOF_MOTION
@ MIDDLEMOUSE
@ EVT_ESCKEY
@ EVT_TWEAK_L
@ INBETWEEN_MOUSEMOVE
@ GESTURE_MODAL_CIRCLE_SIZE
@ GESTURE_MODAL_OUT
@ GESTURE_MODAL_SNAP
@ GESTURE_MODAL_CIRCLE_ADD
@ GESTURE_MODAL_CANCEL
@ GESTURE_MODAL_CIRCLE_SUB
@ GESTURE_MODAL_MOVE
@ GESTURE_MODAL_NOP
@ GESTURE_MODAL_DESELECT
@ GESTURE_MODAL_CONFIRM
@ GESTURE_MODAL_IN
@ GESTURE_MODAL_FLIP
@ GESTURE_MODAL_BEGIN
@ GESTURE_MODAL_SELECT
#define ISTIMER(event_type)
wmOperatorType * ot
Definition: wm_files.c:3156
wmGesture * WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent *event, int type)
Definition: wm_gesture.c:54
void wm_gesture_tag_redraw(wmWindow *win)
Definition: wm_gesture.c:559
int wm_gesture_evaluate(wmGesture *gesture, const wmEvent *event)
Definition: wm_gesture.c:133
void WM_gesture_end(wmWindow *win, wmGesture *gesture)
Definition: wm_gesture.c:99
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define STRAIGHTLINE_SNAP_DEG
static bool gesture_box_apply(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lines_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void gesture_modal_end(bContext *C, wmOperator *op)
static int UNUSED_FUNCTION() gesture_modal_state_from_operator(wmOperator *op)
void WM_gesture_straightline_cancel(bContext *C, wmOperator *op)
void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool gesture_straightline_apply(bContext *C, wmOperator *op)
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
void WM_gesture_circle_cancel(bContext *C, wmOperator *op)
static void gesture_circle_apply(bContext *C, wmOperator *op)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool gesture_box_apply_rect(wmOperator *op)
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void gesture_tweak_modal(bContext *C, const wmEvent *event)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const int(* WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int *r_mcoords_len))[2]
static void gesture_modal_state_to_operator(wmOperator *op, int modal_state)
static int gesture_lasso_apply(bContext *C, wmOperator *op)
int WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void wm_gesture_straightline_do_angle_snap(rcti *rect)
int WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool WM_gizmomap_tag_delay_refresh_for_tweak_check(wmGizmoMap *gzmap)
Definition: wm_gizmo_map.c:332
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
bool WM_operator_winactive(bContext *C)