]>
Commit | Line | Data |
---|---|---|
df62e023 | 1 | /* |
0a539fe4 | 2 | * Copyright (c) 2001, 2002, 2003 Gary R. Van Sickle. |
df62e023 RC |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by Gary R. Van Sickle <g.r.vansickle@worldnet.att.net> | |
13 | * | |
14 | */ | |
15 | ||
16 | // This is the implementation of the Window class. It serves both as a window class | |
17 | // in its own right and as a base class for other window-like classes (e.g. PropertyPage, | |
18 | // PropSheet). | |
19 | ||
20 | #include <windows.h> | |
21 | #include "window.h" | |
58db1046 | 22 | #include "String++.h" |
0a539fe4 | 23 | #include "RECTWrapper.h" |
df62e023 RC |
24 | |
25 | ATOM Window::WindowClassAtom = 0; | |
26 | HINSTANCE Window::AppInstance = NULL; | |
27 | ||
df62e023 RC |
28 | Window::Window () |
29 | { | |
30 | WindowHandle = NULL; | |
31 | Parent = NULL; | |
b7301c43 | 32 | FontCounter = 0; |
df62e023 RC |
33 | } |
34 | ||
35 | Window::~Window () | |
36 | { | |
b7301c43 RC |
37 | // Delete any fonts we created. |
38 | int i; | |
39 | for (i = 0; i < FontCounter; i++) | |
40 | { | |
41 | DeleteObject (Fonts[i]); | |
42 | } | |
43 | FontCounter = 0; | |
44 | ||
df62e023 RC |
45 | // FIXME: Maybe do some reference counting and do this Unregister |
46 | // when there are no more of us left. Not real critical unless | |
47 | // we're in a DLL which we're not right now. | |
48 | //UnregisterClass(WindowClassAtom, InstanceHandle); | |
49 | } | |
50 | ||
51 | LRESULT CALLBACK | |
52 | Window::FirstWindowProcReflector (HWND hwnd, UINT uMsg, WPARAM wParam, | |
53 | LPARAM lParam) | |
54 | { | |
63c82708 | 55 | Window *wnd = NULL; |
df62e023 | 56 | |
63c82708 | 57 | if(uMsg == WM_NCCREATE) |
df62e023 | 58 | { |
63c82708 RC |
59 | // This is the first message a window gets (so MSDN says anyway). |
60 | // Take this opportunity to "link" the HWND to the 'this' ptr, steering | |
61 | // messages to the class instance's WindowProc(). | |
62 | wnd = reinterpret_cast<Window *>(((LPCREATESTRUCT)lParam)->lpCreateParams); | |
df62e023 RC |
63 | |
64 | // Set a backreference to this class instance in the HWND. | |
0a539fe4 | 65 | SetWindowLongPtr (hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(wnd)); |
df62e023 RC |
66 | |
67 | // Set a new WindowProc now that we have the peliminaries done. | |
63c82708 RC |
68 | // We could instead simply do the contents of Window::WindowProcReflector |
69 | // in the 'else' clause below, but this way we eliminate an unnecessary 'if/else' on | |
70 | // every message. Yeah, it's probably not worth the trouble. | |
71 | SetWindowLongPtr (hwnd, GWL_WNDPROC, (LONG_PTR) & Window::WindowProcReflector); | |
72 | } | |
73 | else | |
74 | { | |
75 | // Should never get here. | |
76 | abort(); | |
df62e023 RC |
77 | } |
78 | ||
63c82708 | 79 | return wnd->WindowProc (uMsg, wParam, lParam); |
df62e023 RC |
80 | } |
81 | ||
82 | LRESULT CALLBACK | |
83 | Window::WindowProcReflector (HWND hwnd, UINT uMsg, WPARAM wParam, | |
84 | LPARAM lParam) | |
85 | { | |
86 | Window *This; | |
87 | ||
88 | // Get our this pointer | |
0a539fe4 | 89 | This = reinterpret_cast<Window *>(GetWindowLongPtr (hwnd, GWL_USERDATA)); |
df62e023 RC |
90 | |
91 | return This->WindowProc (uMsg, wParam, lParam); | |
92 | } | |
93 | ||
94 | bool Window::Create (Window * parent, DWORD Style) | |
95 | { | |
96 | // First register the window class, if we haven't already | |
97 | if (RegisterWindowClass () == false) | |
98 | { | |
99 | // Registration failed | |
100 | return false; | |
101 | } | |
102 | ||
0a539fe4 | 103 | // Save our parent, we'll probably need it eventually. |
df62e023 RC |
104 | Parent = parent; |
105 | ||
106 | // Create the window instance | |
63c82708 RC |
107 | WindowHandle = CreateWindowEx ( |
108 | // Extended Style | |
109 | 0, | |
110 | "MainWindowClass", //MAKEINTATOM(WindowClassAtom), // window class atom (name) | |
df62e023 RC |
111 | "Hello", // no title-bar string yet |
112 | // Style bits | |
113 | Style, | |
114 | // Default positions and size | |
115 | CW_USEDEFAULT, | |
116 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, | |
117 | // Parent Window | |
118 | parent == | |
119 | NULL ? (HWND) NULL : parent->GetHWND (), | |
120 | // use class menu | |
121 | (HMENU) NULL, | |
122 | // The application instance | |
63c82708 RC |
123 | GetInstance (), |
124 | // The this ptr, which we'll use to set up the WindowProc reflection. | |
125 | (LPVOID) this); | |
df62e023 RC |
126 | |
127 | if (WindowHandle == NULL) | |
128 | { | |
129 | // Failed | |
130 | return false; | |
131 | } | |
132 | ||
133 | return true; | |
134 | } | |
135 | ||
136 | bool Window::RegisterWindowClass () | |
137 | { | |
138 | if (WindowClassAtom == 0) | |
139 | { | |
140 | // We're not registered yet | |
141 | WNDCLASSEX | |
142 | wc; | |
143 | ||
144 | wc.cbSize = sizeof (wc); | |
145 | // Some sensible style defaults | |
146 | wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; | |
147 | // Our default window procedure. This replaces itself | |
148 | // on the first call with the simpler Window::WindowProcReflector(). | |
149 | wc.lpfnWndProc = Window::FirstWindowProcReflector; | |
150 | // No class bytes | |
151 | wc.cbClsExtra = 0; | |
152 | // One pointer to REFLECTION_INFO in the extra window instance bytes | |
153 | wc.cbWndExtra = 4; | |
154 | // The app instance | |
155 | wc.hInstance = GetInstance (); | |
156 | // Use a bunch of system defaults for the GUI elements | |
157 | wc.hIcon = NULL; | |
158 | wc.hIconSm = NULL; | |
159 | wc.hCursor = NULL; | |
160 | wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); | |
161 | // No menu | |
162 | wc.lpszMenuName = NULL; | |
163 | // We'll get a little crazy here with the class name | |
164 | wc.lpszClassName = "MainWindowClass"; | |
165 | ||
166 | // All set, try to register | |
167 | WindowClassAtom = RegisterClassEx (&wc); | |
168 | ||
169 | if (WindowClassAtom == 0) | |
170 | { | |
171 | // Failed | |
172 | return false; | |
173 | } | |
174 | } | |
175 | ||
176 | // We're registered, or already were before the call, | |
177 | // return success in either case. | |
178 | return true; | |
179 | } | |
180 | ||
181 | void | |
182 | Window::Show (int State) | |
183 | { | |
184 | ::ShowWindow (WindowHandle, State); | |
185 | } | |
186 | ||
63c82708 RC |
187 | RECT |
188 | Window::GetWindowRect() const | |
189 | { | |
190 | RECT retval; | |
191 | ::GetWindowRect(WindowHandle, &retval); | |
192 | return retval; | |
193 | } | |
194 | ||
195 | RECT | |
196 | Window::GetClientRect() const | |
197 | { | |
198 | RECT retval; | |
199 | ::GetClientRect(WindowHandle, &retval); | |
200 | return retval; | |
201 | } | |
202 | ||
203 | bool | |
204 | Window::MoveWindow(long x, long y, long w, long h, bool Repaint) | |
205 | { | |
206 | return ::MoveWindow (WindowHandle, x, y, w, h, Repaint); | |
207 | } | |
208 | ||
0a539fe4 MB |
209 | bool |
210 | Window::MoveWindow(const RECTWrapper &r, bool Repaint) | |
211 | { | |
212 | return ::MoveWindow (WindowHandle, r.left, r.top, r.width(), r.height(), Repaint); | |
213 | } | |
214 | ||
df62e023 RC |
215 | void |
216 | Window::CenterWindow () | |
217 | { | |
218 | RECT WindowRect, ParentRect; | |
219 | int WindowWidth, WindowHeight; | |
220 | POINT p; | |
221 | ||
222 | // Get the window rectangle | |
63c82708 | 223 | WindowRect = GetWindowRect (); |
df62e023 RC |
224 | |
225 | if (GetParent () == NULL) | |
226 | { | |
227 | // Center on desktop window | |
63c82708 | 228 | ::GetWindowRect (GetDesktopWindow (), &ParentRect); |
df62e023 RC |
229 | } |
230 | else | |
231 | { | |
232 | // Center on client area of parent | |
63c82708 | 233 | ::GetClientRect (GetParent ()->GetHWND (), &ParentRect); |
df62e023 RC |
234 | } |
235 | ||
236 | WindowWidth = WindowRect.right - WindowRect.left; | |
237 | WindowHeight = WindowRect.bottom - WindowRect.top; | |
238 | ||
239 | // Find center of area we're centering on | |
240 | p.x = (ParentRect.right - ParentRect.left) / 2; | |
241 | p.y = (ParentRect.bottom - ParentRect.top) / 2; | |
242 | ||
243 | // Convert that to screen coords | |
244 | if (GetParent () == NULL) | |
245 | { | |
246 | ClientToScreen (GetDesktopWindow (), &p); | |
247 | } | |
248 | else | |
249 | { | |
250 | ClientToScreen (GetParent ()->GetHWND (), &p); | |
251 | } | |
252 | ||
253 | // Calculate new top left corner for window | |
254 | p.x -= WindowWidth / 2; | |
255 | p.y -= WindowHeight / 2; | |
256 | ||
257 | // And finally move the window | |
63c82708 | 258 | MoveWindow (p.x, p.y, WindowWidth, WindowHeight); |
df62e023 RC |
259 | } |
260 | ||
261 | LRESULT Window::WindowProc (UINT uMsg, WPARAM wParam, LPARAM lParam) | |
262 | { | |
263 | switch (uMsg) | |
264 | { | |
265 | default: | |
266 | return DefWindowProc (WindowHandle, uMsg, wParam, lParam); | |
267 | } | |
268 | ||
269 | return 0; | |
270 | } | |
271 | ||
272 | bool Window::MessageLoop () | |
273 | { | |
274 | MSG | |
275 | msg; | |
276 | ||
277 | while (GetMessage (&msg, NULL, 0, 0) != 0 | |
278 | && GetMessage (&msg, (HWND) NULL, 0, 0) != -1) | |
279 | { | |
280 | if (!IsWindow (WindowHandle) || !IsDialogMessage (WindowHandle, &msg)) | |
281 | { | |
282 | TranslateMessage (&msg); | |
283 | DispatchMessage (&msg); | |
284 | } | |
285 | } | |
286 | ||
287 | return true; | |
288 | } | |
289 | ||
290 | void | |
291 | Window::PostMessage (UINT uMsg, WPARAM wParam, LPARAM lParam) | |
292 | { | |
293 | ::PostMessage (GetHWND (), uMsg, wParam, lParam); | |
294 | } | |
b7301c43 RC |
295 | |
296 | UINT Window::IsButtonChecked (int nIDButton) const | |
297 | { | |
0a539fe4 | 298 | return ::IsDlgButtonChecked (GetHWND (), nIDButton); |
b7301c43 RC |
299 | } |
300 | ||
301 | bool | |
302 | Window::SetDlgItemFont (int id, const TCHAR * fontname, int Pointsize, | |
303 | int Weight, bool Italic, bool Underline, | |
304 | bool Strikeout) | |
305 | { | |
306 | HWND ctrl; | |
63c82708 | 307 | |
b7301c43 RC |
308 | ctrl = GetDlgItem (id); |
309 | if (ctrl == NULL) | |
310 | { | |
311 | // Couldn't get that ID | |
312 | return false; | |
313 | } | |
314 | ||
315 | // We need the DC for the point size calculation. | |
316 | HDC hdc = GetDC (ctrl); | |
317 | ||
318 | // Create the font. We have to keep it around until the dialog item | |
319 | // goes away - basically until we're destroyed. | |
320 | HFONT hfnt; | |
321 | hfnt = | |
322 | CreateFont (-MulDiv (Pointsize, GetDeviceCaps (hdc, LOGPIXELSY), 72), 0, | |
323 | 0, 0, Weight, Italic ? TRUE : FALSE, | |
324 | Underline ? TRUE : FALSE, Strikeout ? TRUE : FALSE, | |
325 | ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, | |
326 | PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname); | |
327 | if (hfnt == NULL) | |
328 | { | |
329 | // Font creation failed | |
330 | return false; | |
331 | } | |
332 | ||
0a539fe4 | 333 | // Set the new font, and redraw any text which was already in the item. |
b7301c43 RC |
334 | SendMessage (ctrl, WM_SETFONT, (WPARAM) hfnt, TRUE); |
335 | ||
336 | // Save it for later. | |
337 | Fonts[FontCounter] = hfnt; | |
338 | FontCounter++; | |
339 | ||
340 | return true; | |
341 | } | |
58db1046 RC |
342 | |
343 | void | |
344 | Window::SetWindowText (const String & s) | |
345 | { | |
346 | ::SetWindowText (WindowHandle, s.cstr_oneuse ()); | |
347 | } | |
63c82708 RC |
348 | |
349 | RECT | |
350 | Window::ScreenToClient(const RECT &r) const | |
351 | { | |
352 | POINT tl; | |
353 | POINT br; | |
354 | ||
355 | tl.y = r.top; | |
356 | tl.x = r.left; | |
357 | ::ScreenToClient(GetHWND(), &tl); | |
358 | br.y = r.bottom; | |
359 | br.x = r.right; | |
360 | ::ScreenToClient(GetHWND(), &br); | |
361 | ||
362 | RECT ret; | |
363 | ||
364 | ret.top = tl.y; | |
365 | ret.left = tl.x; | |
366 | ret.bottom = br.y; | |
367 | ret.right = br.x; | |
368 | ||
369 | return ret; | |
370 | } | |
371 |