Drag touching edges together (WB)
[xboard.git] / winboard / wsnap.c
index 5492e80..683aa15 100644 (file)
@@ -64,14 +64,22 @@ static void AddSnapRectangle( SnapData * sd, RECT * rc )
     AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->bottom );\r
 }\r
 \r
+static RECT activeRect, mainRect;\r
+static int side, loc; // code for edge we were dragging, and its latest coordinate\r
+\r
 static void AddSnapWindow( HWND hWndCaller, SnapData * sd, HWND hWndSnapWindow )\r
 {\r
-    if( hWndSnapWindow != NULL && hWndCaller != hWndSnapWindow && IsWindowVisible(hWndSnapWindow) ) {\r
+    if( hWndSnapWindow != NULL && IsWindowVisible(hWndSnapWindow) ) {\r
         RECT rc;\r
 \r
         GetWindowRect( hWndSnapWindow, &rc );\r
+       if(hWndSnapWindow == hwndMain) mainRect = rc;\r
 \r
-        AddSnapRectangle( sd, &rc );\r
+       if(hWndCaller != hWndSnapWindow) {\r
+            AddSnapRectangle( sd, &rc );\r
+       } else {\r
+           activeRect = rc; // [HGM] glue: remember original geometry of dragged window\r
+       }\r
     }\r
 }\r
 \r
@@ -101,6 +109,7 @@ LRESULT OnEnterSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM l
 \r
     snapData->x_grid_len = 0;\r
     snapData->y_grid_len = 0;\r
+    side = 0;\r
 \r
     /* Add desktop area */\r
     if( SystemParametersInfo( SPI_GETWORKAREA, 0, &rc, 0 ) ) {\r
@@ -157,7 +166,7 @@ LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )
     switch( wParam ) {\r
     case WMSZ_BOTTOM:\r
         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
-        lprc->bottom += delta_y;\r
+        lprc->bottom += delta_y; side = 4; loc = lprc->bottom;\r
         break;\r
     case WMSZ_BOTTOMLEFT:\r
         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
@@ -173,15 +182,15 @@ LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )
         break;\r
     case WMSZ_LEFT:\r
         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
-        lprc->left += delta_x;\r
+        lprc->left += delta_x; side = 1; loc = lprc->left;\r
         break;\r
     case WMSZ_RIGHT:\r
         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
-        lprc->right += delta_x;\r
+        lprc->right += delta_x; side = 2; loc = lprc->right;\r
         break;\r
     case WMSZ_TOP:\r
         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
-        lprc->top += delta_y;\r
+        lprc->top += delta_y; side = 3; loc = lprc->top;\r
         break;\r
     case WMSZ_TOPLEFT:\r
         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
@@ -202,7 +211,60 @@ LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )
     return TRUE;\r
 }\r
 \r
+static int Adjust( LONG *data, int new, int old , int vertical)\r
+{\r
+    // protect edges that also touch main window\r
+    if(!vertical && (old == mainRect.left || old == mainRect.right))  return 0;\r
+    if( vertical && (old == mainRect.top  || old == mainRect.bottom)) return 0;\r
+    // if the coordinate was the same as the old, now make it the same as the new edge position\r
+    if(*data == old) { *data = new; return 1; }\r
+    return 0;\r
+}\r
+\r
+static void KeepTouching( int side, int new, int old, HWND hWnd )\r
+{   // if the mentioned window was touching on the moved edge, move its touching edge too\r
+    if( IsWindowVisible(hWnd) ) {\r
+        RECT rc;\r
+       int i = 0;\r
+\r
+        GetWindowRect( hWnd, &rc );\r
+\r
+       switch(side) { // figure out which edge we might need to drag along (if any)\r
+         case 1: i = Adjust(&rc.right,  new, old, 0); break;\r
+         case 2: i = Adjust(&rc.left,   new, old, 0); break;\r
+         case 3: i = Adjust(&rc.bottom, new, old, 1); break;\r
+         case 4: i = Adjust(&rc.top,    new, old, 1); break;\r
+       }\r
+\r
+       if(i) { // the correct edge was touching, and is adjusted\r
+           SetWindowPos(hWnd, HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER );\r
+       }\r
+    }\r
+}\r
+\r
 LRESULT OnExitSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
 {\r
+    if(side && hWnd != hwndMain) { // [HGM] glue: we have been sizing, by dragging an edge\r
+       int *grid = (side > 2 ? snapData->y_grid : snapData->x_grid);\r
+       int i, pos = -1, len = (side > 2 ? snapData->y_grid_len : snapData->x_grid_len);\r
+\r
+       switch(side) {\r
+         case 1: pos = activeRect.left; break;\r
+         case 2: pos = activeRect.right; break;\r
+         case 3: pos = activeRect.top; break;\r
+         case 4: pos = activeRect.bottom; break;\r
+       }\r
+\r
+       for(i=0; i<len; i++) {\r
+           if(grid[i] == pos) break; // the dragged side originally touched another auxiliary window\r
+       }\r
+\r
+       if(i < len) { // we were touching another sticky window: figure out how, and adapt it if needed\r
+               KeepTouching(side, loc, pos, moveHistoryDialog);\r
+               KeepTouching(side, loc, pos, evalGraphDialog);\r
+               KeepTouching(side, loc, pos, engineOutputDialog);\r
+               KeepTouching(side, loc, pos, gameListDialog);\r
+       }\r
+    }\r
     return 0;\r
 }\r