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