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