WM: improved area resize snapping
authormano-wii <germano.costa@ig.com.br>
Thu, 18 Jan 2018 00:22:58 +0000 (11:22 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 18 Jan 2018 00:33:51 +0000 (11:33 +1100)
Instead of 10px steps, snap to mid-point & adjacent edges.

Not yet implemented for split preview.

source/blender/editors/screen/screen_ops.c

index 908d218d35349e65781b36d3aff28af9a1960336..176bdc764a2ada0decb8fbbfd1423ceab47a3321 100644 (file)
@@ -87,8 +87,8 @@
 
 #define KM_MODAL_CANCEL     1
 #define KM_MODAL_APPLY      2
-#define KM_MODAL_STEP10     3
-#define KM_MODAL_STEP10_OFF 4
+#define KM_MODAL_SNAP_ON    3
+#define KM_MODAL_SNAP_OFF   4
 
 /* ************** Exported Poll tests ********************** */
 
@@ -1077,8 +1077,9 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot)
  */
 
 typedef struct sAreaMoveData {
-       int bigger, smaller, origval, step;
+       int bigger, smaller, origval;
        char dir;
+       bool do_snap;
 } sAreaMoveData;
 
 /* helper call to move area-edge, sets limits
@@ -1170,55 +1171,101 @@ static int area_move_init(bContext *C, wmOperator *op)
        return 1;
 }
 
+static int area_snap_calc_location(
+        const bScreen *sc, const int delta,
+        const int origval, const int dir,
+        const int bigger, const int smaller)
+{
+       int final_loc = -1;
+
+       const int m_loc = origval + delta;
+       const int axis = (dir == 'v') ? 0 : 1;
+       int snap_dist = INT_MAX;
+       int dist;
+       {
+               /* Test the snap to middle. */
+               int middle = origval + (bigger - smaller) / 2;
+               middle -= (middle % AREAGRID);
+
+               dist = abs(m_loc - middle);
+               if (dist <= snap_dist) {
+                       snap_dist = dist;
+                       final_loc = middle;
+               }
+       }
+
+       for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
+               if (v1->editflag) {
+                       const int v_loc = (&v1->vec.x)[!axis];
+
+                       for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
+                               if (!v2->editflag) {
+                                       if (v_loc == (&v2->vec.x)[!axis]) {
+                                               const int v_loc2 = (&v2->vec.x)[axis];
+                                               /* Do not snap to the vertices at the ends. */
+                                               if ((origval - smaller) < v_loc2 && v_loc2 < (origval + bigger)) {
+                                                       dist = abs(m_loc - v_loc2);
+                                                       if (dist <= snap_dist) {
+                                                               snap_dist = dist;
+                                                               final_loc = v_loc2;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return final_loc;
+}
+
 /* moves selected screen edge amount of delta, used by split & move */
-static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
+static void area_move_apply_do(
+        const bContext *C, int delta,
+        const int origval, const int dir,
+        const int bigger, const int smaller,
+        const bool do_snap)
 {
-       wmWindow *win = CTX_wm_window(C);
-       const int winsize_x = WM_window_pixels_x(win);
-       const int winsize_y = WM_window_pixels_y(win);
        bScreen *sc = CTX_wm_screen(C);
        ScrVert *v1;
-       ScrArea *sa;
-       int doredraw = 0;
-       int oldval;
-       
-       delta = CLAMPIS(delta, -smaller, bigger);
-       
+       bool doredraw = false;
+       CLAMP(delta, -smaller, bigger);
+
+       short final_loc = -1;
+
+       if (do_snap) {
+               final_loc = area_snap_calc_location(sc, delta, origval, dir, bigger, smaller);
+       }
+       else {
+               final_loc = origval + delta;
+               if (delta != bigger && delta != -smaller) {
+                       final_loc -= (final_loc % AREAGRID);
+               }
+       }
+
+       BLI_assert(final_loc != -1);
+       short axis = (dir == 'v') ? 0 : 1;
+
        for (v1 = sc->vertbase.first; v1; v1 = v1->next) {
                if (v1->editflag) {
-                       /* that way a nice AREAGRID  */
-                       if ((dir == 'v') && v1->vec.x > 0 && v1->vec.x < winsize_x - 1) {
-                               oldval = v1->vec.x;
-                               v1->vec.x = origval + delta;
-                               
-                               if (delta != bigger && delta != -smaller) {
-                                       v1->vec.x -= (v1->vec.x % AREAGRID);
-                                       v1->vec.x = CLAMPIS(v1->vec.x, origval - smaller, origval + bigger);
-                               }
-                               if (oldval != v1->vec.x)
-                                       doredraw = 1;
-                       }
-                       if ((dir == 'h') && v1->vec.y > 0 && v1->vec.y < winsize_y - 1) {
-                               oldval = v1->vec.y;
-                               v1->vec.y = origval + delta;
-                               
-                               if (delta != bigger && delta != smaller) {
-                                       v1->vec.y -= (v1->vec.y % AREAGRID);
-                                       v1->vec.y = CLAMPIS(v1->vec.y, origval - smaller, origval + bigger);
-                               }
-                               if (oldval != v1->vec.y)
-                                       doredraw = 1;
+                       short oldval = (&v1->vec.x)[axis];
+                       (&v1->vec.x)[axis] = final_loc;
+
+                       if (oldval == final_loc) {
+                               /* nothing will change to the other vertices either. */
+                               break;
                        }
+                       doredraw = true;
                }
        }
 
        /* only redraw if we actually moved a screen vert, for AREAGRID */
        if (doredraw) {
-               for (sa = sc->areabase.first; sa; sa = sa->next) {
-                       if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag)
+               for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+                       if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) {
                                ED_area_tag_redraw(sa);
+                       }
                }
-
                WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */
        }
 }
@@ -1226,10 +1273,9 @@ static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int
 static void area_move_apply(bContext *C, wmOperator *op)
 {
        sAreaMoveData *md = op->customdata;
-       int delta;
-       
-       delta = RNA_int_get(op->ptr, "delta");
-       area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
+       int delta = RNA_int_get(op->ptr, "delta");
+
+       area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->do_snap);
 }
 
 static void area_move_exit(bContext *C, wmOperator *op)
@@ -1291,7 +1337,6 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
                        y = RNA_int_get(op->ptr, "y");
                        
                        delta = (md->dir == 'v') ? event->x - x : event->y - y;
-                       if (md->step) delta = delta - (delta % md->step);
                        RNA_int_set(op->ptr, "delta", delta);
                        
                        area_move_apply(C, op);
@@ -1307,12 +1352,12 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
                                case KM_MODAL_CANCEL:
                                        area_move_cancel(C, op);
                                        return OPERATOR_CANCELLED;
-                                       
-                               case KM_MODAL_STEP10:
-                                       md->step = 10;
+
+                               case KM_MODAL_SNAP_ON:
+                                       md->do_snap = true;
                                        break;
-                               case KM_MODAL_STEP10_OFF:
-                                       md->step = 0;
+                               case KM_MODAL_SNAP_OFF:
+                                       md->do_snap = false;
                                        break;
                        }
                        break;
@@ -1388,6 +1433,7 @@ typedef struct sAreaSplitData {
        int delta;              /* delta move edge */
        int origmin, origsize;  /* to calculate fac, for property storage */
        int previewmode;        /* draw previewline, then split */
+       bool do_snap;
 
        ScrEdge *nedge;         /* new edge */
        ScrArea *sarea;         /* start area */
@@ -1686,8 +1732,9 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
                        
                        sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval;
                        if (sd->previewmode == 0)
-                               area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
+                               area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, sd->do_snap);
                        else {
+                               /* TODO: Snap in preview mode too. */
                                if (sd->sarea) {
                                        sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V);
                                        ED_area_tag_redraw(sd->sarea);
@@ -1766,6 +1813,10 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
                case ESCKEY:
                        area_split_cancel(C, op);
                        return OPERATOR_CANCELLED;
+
+               case LEFTCTRLKEY:
+                       sd->do_snap = event->val == KM_PRESS;
+                       break;
        }
        
        return OPERATOR_RUNNING_MODAL;
@@ -4298,8 +4349,8 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
        static const EnumPropertyItem modal_items[] = {
                {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
                {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
-               {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
-               {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
+               {KM_MODAL_SNAP_ON, "SNAP", 0, "Snap on", ""},
+               {KM_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap off", ""},
                {0, NULL, 0, NULL, NULL}};
        wmKeyMap *keymap;
        
@@ -4311,8 +4362,8 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
        WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
        WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
        
-       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
-       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
+       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_SNAP_ON);
+       WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_SNAP_OFF);
        
        WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");