-/*
- * wsnap.c -- Smart "snapping" for window moving and sizing
- *
- * Author: Alessandro Scotti
- *
- * ------------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * ------------------------------------------------------------------------
- */
-#include "wsnap.h"
-
-/* Imports from winboard.c */
-extern HINSTANCE hInst;
-
-extern HWND hwndMain;
-extern HWND moveHistoryDialog;
-extern HWND evalGraphDialog;
-extern HWND gameListDialog;
-
-static BOOL SnappingEnabled = TRUE;
-
-static void AddSnapPoint( int * grid, int * grid_len, int value )
-{
- int len = *grid_len;
-
- if( len < MAX_SNAP_POINTS ) {
- int i;
-
- for( i=0; i<len; i++ ) {
- if( grid[i] == value ) {
- return;
- }
- }
-
- grid[ len++ ] = value;
-
- *grid_len = len;
- }
-}
-
-static void AddSnapRectangle( SnapData * sd, RECT * rc )
-{
- AddSnapPoint( sd->x_grid, &sd->x_grid_len, rc->left );
- AddSnapPoint( sd->x_grid, &sd->x_grid_len, rc->right );
-
- AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->top );
- AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->bottom );
-}
-
-static void AddSnapWindow( HWND hWndCaller, SnapData * sd, HWND hWndSnapWindow )
-{
- if( hWndSnapWindow != NULL && hWndCaller != hWndSnapWindow && IsWindowVisible(hWndSnapWindow) ) {
- RECT rc;
-
- GetWindowRect( hWndSnapWindow, &rc );
-
- AddSnapRectangle( sd, &rc );
- }
-}
-
-static BOOL AdjustToSnapPoint( int * grid, int grid_len, int value, int * snap_size, int * delta )
-{
- BOOL result = FALSE;
- int i;
-
- for( i=0; i<grid_len; i++ ) {
- int distance = value - grid[i];
-
- if( distance < 0 ) distance = -distance;
-
- if( distance < *snap_size ) {
- result = TRUE;
- *snap_size = distance;
- *delta = grid[i] - value;
- }
- }
-
- return result;
-}
-
-LRESULT OnEnterSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )
-{
- RECT rc;
-
- snapData->x_grid_len = 0;
- snapData->y_grid_len = 0;
-
- /* Add desktop area */
- if( SystemParametersInfo( SPI_GETWORKAREA, 0, &rc, 0 ) ) {
- AddSnapRectangle( snapData, &rc );
- }
-
- if( hWnd != hwndMain ) {
- /* Add other windows */
- AddSnapWindow( hWnd, snapData, hwndMain );
- AddSnapWindow( hWnd, snapData, moveHistoryDialog );
- AddSnapWindow( hWnd, snapData, evalGraphDialog );
- AddSnapWindow( hWnd, snapData, gameListDialog );
- }
-
- return 0;
-}
-
-LRESULT OnMoving( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )
-{
- LPRECT lprc = (LPRECT) lParam;
- int delta_x = 0;
- int delta_y = 0;
- int snap_size_x = SNAP_DISTANCE;
- int snap_size_y = SNAP_DISTANCE;
-
- if( ! SnappingEnabled ) {
- return FALSE;
- }
-
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );
-
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );
-
- OffsetRect( lprc, delta_x, delta_y );
-
- return TRUE;
-}
-
-LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )
-{
- LPRECT lprc = (LPRECT) lParam;
- int delta_x = 0;
- int delta_y = 0;
- int snap_size_x = SNAP_DISTANCE;
- int snap_size_y = SNAP_DISTANCE;
-
- if( ! SnappingEnabled ) {
- return FALSE;
- }
-
- switch( wParam ) {
- case WMSZ_BOTTOM:
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );
- lprc->bottom += delta_y;
- break;
- case WMSZ_BOTTOMLEFT:
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );
- lprc->bottom += delta_y;
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );
- lprc->left += delta_x;
- break;
- case WMSZ_BOTTOMRIGHT:
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );
- lprc->bottom += delta_y;
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );
- lprc->right += delta_x;
- break;
- case WMSZ_LEFT:
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );
- lprc->left += delta_x;
- break;
- case WMSZ_RIGHT:
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );
- lprc->right += delta_x;
- break;
- case WMSZ_TOP:
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );
- lprc->top += delta_y;
- break;
- case WMSZ_TOPLEFT:
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );
- lprc->top += delta_y;
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );
- lprc->left += delta_x;
- break;
- case WMSZ_TOPRIGHT:
- AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );
- lprc->top += delta_y;
- AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );
- lprc->right += delta_x;
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-LRESULT OnExitSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )
-{
- return 0;
-}
+/*\r
+ * Smart "snapping" for window moving and sizing\r
+ *\r
+ * Author: Alessandro Scotti (Dec 2005)\r
+ *\r
+ * Copyright 2005 Alessandro Scotti\r
+ *\r
+ * ------------------------------------------------------------------------\r
+ *\r
+ * GNU XBoard is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or (at\r
+ * your option) any later version.\r
+ *\r
+ * GNU XBoard is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see http://www.gnu.org/licenses/. *\r
+ *\r
+ *------------------------------------------------------------------------\r
+ ** See the file ChangeLog for a revision history. */\r
+\r
+#include "wsnap.h"\r
+\r
+/* Imports from winboard.c */\r
+extern HINSTANCE hInst;\r
+\r
+extern HWND hwndMain;\r
+extern HWND moveHistoryDialog;\r
+extern HWND evalGraphDialog;\r
+extern HWND engineOutputDialog;\r
+extern HWND gameListDialog;\r
+\r
+static BOOL SnappingEnabled = TRUE;\r
+\r
+static void AddSnapPoint( int * grid, int * grid_len, int value )\r
+{\r
+ int len = *grid_len;\r
+\r
+ if( len < MAX_SNAP_POINTS ) {\r
+ int i;\r
+\r
+ for( i=0; i<len; i++ ) {\r
+ if( grid[i] == value ) {\r
+ return;\r
+ }\r
+ }\r
+\r
+ grid[ len++ ] = value;\r
+\r
+ *grid_len = len;\r
+ }\r
+}\r
+\r
+static void AddSnapRectangle( SnapData * sd, RECT * rc )\r
+{\r
+ AddSnapPoint( sd->x_grid, &sd->x_grid_len, rc->left );\r
+ AddSnapPoint( sd->x_grid, &sd->x_grid_len, rc->right );\r
+\r
+ AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->top );\r
+ 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 && IsWindowVisible(hWndSnapWindow) ) {\r
+ RECT rc;\r
+\r
+ GetWindowRect( hWndSnapWindow, &rc );\r
+ if(hWndSnapWindow == hwndMain) mainRect = rc;\r
+\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
+static BOOL AdjustToSnapPoint( int * grid, int grid_len, int value, int * snap_size, int * delta )\r
+{\r
+ BOOL result = FALSE;\r
+ int i;\r
+\r
+ for( i=0; i<grid_len; i++ ) {\r
+ int distance = value - grid[i];\r
+\r
+ if( distance < 0 ) distance = -distance;\r
+\r
+ if( distance < *snap_size ) {\r
+ result = TRUE;\r
+ *snap_size = distance;\r
+ *delta = grid[i] - value;\r
+ }\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+LRESULT OnEnterSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
+{\r
+ RECT rc;\r
+\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
+ AddSnapRectangle( snapData, &rc );\r
+ }\r
+\r
+ if( hWnd != hwndMain ) {\r
+ /* Add other windows */\r
+ AddSnapWindow( hWnd, snapData, hwndMain );\r
+ AddSnapWindow( hWnd, snapData, moveHistoryDialog );\r
+ AddSnapWindow( hWnd, snapData, evalGraphDialog );\r
+ AddSnapWindow( hWnd, snapData, engineOutputDialog );\r
+ AddSnapWindow( hWnd, snapData, gameListDialog );\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+LRESULT OnMoving( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
+{\r
+ LPRECT lprc = (LPRECT) lParam;\r
+ int delta_x = 0;\r
+ int delta_y = 0;\r
+ int snap_size_x = SNAP_DISTANCE;\r
+ int snap_size_y = SNAP_DISTANCE;\r
+\r
+ if( ! SnappingEnabled ) {\r
+ return FALSE;\r
+ }\r
+\r
+ AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
+ AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
+\r
+ AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
+ AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
+\r
+ OffsetRect( lprc, delta_x, delta_y );\r
+\r
+ return TRUE;\r
+}\r
+\r
+LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
+{\r
+ LPRECT lprc = (LPRECT) lParam;\r
+ int delta_x = 0;\r
+ int delta_y = 0;\r
+ int snap_size_x = SNAP_DISTANCE;\r
+ int snap_size_y = SNAP_DISTANCE;\r
+\r
+ if( ! SnappingEnabled ) {\r
+ return FALSE;\r
+ }\r
+\r
+ 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; 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
+ lprc->bottom += delta_y;\r
+ AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
+ lprc->left += delta_x;\r
+ break;\r
+ case WMSZ_BOTTOMRIGHT:\r
+ AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
+ lprc->bottom += delta_y;\r
+ AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
+ lprc->right += delta_x;\r
+ 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; 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; 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; 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
+ lprc->top += delta_y;\r
+ AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
+ lprc->left += delta_x;\r
+ break;\r
+ case WMSZ_TOPRIGHT:\r
+ AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
+ lprc->top += delta_y;\r
+ AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
+ lprc->right += delta_x;\r
+ break;\r
+ default:\r
+ return FALSE;\r
+ }\r
+\r
+ 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