6d8430421a35beff612f17b8dee0b592a618f9f6
[xboard.git] / winboard / wsnap.c
1 /*\r
2  * Smart "snapping" for window moving and sizing\r
3  *\r
4  * Author: Alessandro Scotti (Dec 2005)\r
5  *\r
6  * ------------------------------------------------------------------------\r
7  * This program is free software; you can redistribute it and/or modify\r
8  * it under the terms of the GNU General Public License as published by\r
9  * the Free Software Foundation; either version 2 of the License, or\r
10  * (at your option) any later version.\r
11  *\r
12  * This program is distributed in the hope that it will be useful,\r
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15  * GNU General Public License for more details.\r
16  *\r
17  * You should have received a copy of the GNU General Public License\r
18  * along with this program; if not, write to the Free Software\r
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
20  * ------------------------------------------------------------------------\r
21  */\r
22 #include "wsnap.h"\r
23 \r
24 /* Imports from winboard.c */\r
25 extern HINSTANCE hInst;\r
26 \r
27 extern HWND hwndMain;\r
28 extern HWND moveHistoryDialog;\r
29 extern HWND evalGraphDialog;\r
30 extern HWND engineOutputDialog;\r
31 extern HWND gameListDialog;\r
32 \r
33 static BOOL SnappingEnabled = TRUE;\r
34 \r
35 static void AddSnapPoint( int * grid, int * grid_len, int value )\r
36 {\r
37     int len = *grid_len;\r
38 \r
39     if( len < MAX_SNAP_POINTS ) {\r
40         int i;\r
41 \r
42         for( i=0; i<len; i++ ) {\r
43             if( grid[i] == value ) {\r
44                 return;\r
45             }\r
46         }\r
47 \r
48         grid[ len++ ] = value;\r
49 \r
50         *grid_len = len;\r
51     }\r
52 }\r
53 \r
54 static void AddSnapRectangle( SnapData * sd, RECT * rc )\r
55 {\r
56     AddSnapPoint( sd->x_grid, &sd->x_grid_len, rc->left );\r
57     AddSnapPoint( sd->x_grid, &sd->x_grid_len, rc->right );\r
58 \r
59     AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->top );\r
60     AddSnapPoint( sd->y_grid, &sd->y_grid_len, rc->bottom );\r
61 }\r
62 \r
63 static void AddSnapWindow( HWND hWndCaller, SnapData * sd, HWND hWndSnapWindow )\r
64 {\r
65     if( hWndSnapWindow != NULL && hWndCaller != hWndSnapWindow && IsWindowVisible(hWndSnapWindow) ) {\r
66         RECT rc;\r
67 \r
68         GetWindowRect( hWndSnapWindow, &rc );\r
69 \r
70         AddSnapRectangle( sd, &rc );\r
71     }\r
72 }\r
73 \r
74 static BOOL AdjustToSnapPoint( int * grid, int grid_len, int value, int * snap_size, int * delta )\r
75 {\r
76     BOOL result = FALSE;\r
77     int i;\r
78 \r
79     for( i=0; i<grid_len; i++ ) {\r
80         int distance = value - grid[i];\r
81 \r
82         if( distance < 0 ) distance = -distance;\r
83 \r
84         if( distance < *snap_size ) {\r
85             result = TRUE;\r
86             *snap_size = distance;\r
87             *delta = grid[i] - value;\r
88         }\r
89     }\r
90 \r
91     return result;\r
92 }\r
93 \r
94 LRESULT OnEnterSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
95 {\r
96     RECT rc;\r
97 \r
98     snapData->x_grid_len = 0;\r
99     snapData->y_grid_len = 0;\r
100 \r
101     /* Add desktop area */\r
102     if( SystemParametersInfo( SPI_GETWORKAREA, 0, &rc, 0 ) ) {\r
103         AddSnapRectangle( snapData, &rc );\r
104     }\r
105 \r
106     if( hWnd != hwndMain ) {\r
107         /* Add other windows */\r
108         AddSnapWindow( hWnd, snapData, hwndMain );\r
109         AddSnapWindow( hWnd, snapData, moveHistoryDialog );\r
110         AddSnapWindow( hWnd, snapData, evalGraphDialog );\r
111         AddSnapWindow( hWnd, snapData, engineOutputDialog );\r
112         AddSnapWindow( hWnd, snapData, gameListDialog );\r
113     }\r
114 \r
115     return 0;\r
116 }\r
117 \r
118 LRESULT OnMoving( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
119 {\r
120     LPRECT lprc = (LPRECT) lParam;\r
121     int delta_x = 0;\r
122     int delta_y = 0;\r
123     int snap_size_x = SNAP_DISTANCE;\r
124     int snap_size_y = SNAP_DISTANCE;\r
125 \r
126     if( ! SnappingEnabled ) {\r
127         return FALSE;\r
128     }\r
129 \r
130     AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
131     AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
132 \r
133     AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
134     AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
135 \r
136     OffsetRect( lprc, delta_x, delta_y );\r
137 \r
138     return TRUE;\r
139 }\r
140 \r
141 LRESULT OnSizing( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
142 {\r
143     LPRECT lprc = (LPRECT) lParam;\r
144     int delta_x = 0;\r
145     int delta_y = 0;\r
146     int snap_size_x = SNAP_DISTANCE;\r
147     int snap_size_y = SNAP_DISTANCE;\r
148 \r
149     if( ! SnappingEnabled ) {\r
150         return FALSE;\r
151     }\r
152 \r
153     switch( wParam ) {\r
154     case WMSZ_BOTTOM:\r
155         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
156         lprc->bottom += delta_y;\r
157         break;\r
158     case WMSZ_BOTTOMLEFT:\r
159         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
160         lprc->bottom += delta_y;\r
161         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
162         lprc->left += delta_x;\r
163         break;\r
164     case WMSZ_BOTTOMRIGHT:\r
165         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->bottom, &snap_size_y, &delta_y );\r
166         lprc->bottom += delta_y;\r
167         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
168         lprc->right += delta_x;\r
169         break;\r
170     case WMSZ_LEFT:\r
171         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
172         lprc->left += delta_x;\r
173         break;\r
174     case WMSZ_RIGHT:\r
175         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
176         lprc->right += delta_x;\r
177         break;\r
178     case WMSZ_TOP:\r
179         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
180         lprc->top += delta_y;\r
181         break;\r
182     case WMSZ_TOPLEFT:\r
183         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
184         lprc->top += delta_y;\r
185         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->left, &snap_size_x, &delta_x );\r
186         lprc->left += delta_x;\r
187         break;\r
188     case WMSZ_TOPRIGHT:\r
189         AdjustToSnapPoint( snapData->y_grid, snapData->y_grid_len, lprc->top, &snap_size_y, &delta_y );\r
190         lprc->top += delta_y;\r
191         AdjustToSnapPoint( snapData->x_grid, snapData->x_grid_len, lprc->right, &snap_size_x, &delta_x );\r
192         lprc->right += delta_x;\r
193         break;\r
194     default:\r
195         return FALSE;\r
196     }\r
197 \r
198     return TRUE;\r
199 }\r
200 \r
201 LRESULT OnExitSizeMove( SnapData * snapData, HWND hWnd, WPARAM wParam, LPARAM lParam )\r
202 {\r
203     return 0;\r
204 }\r