2 * windows.c: Windows front end for my puzzle collection.
14 #define IDM_NEW 0x0010
15 #define IDM_RESTART 0x0020
16 #define IDM_UNDO 0x0030
17 #define IDM_REDO 0x0040
18 #define IDM_QUIT 0x0050
19 #define IDM_PRESETS 0x0100
24 HBITMAP bitmap
, prevbm
;
31 game_params
**presets
;
34 void fatal(char *fmt
, ...)
40 vsprintf(buf
, fmt
, ap
);
43 MessageBox(NULL
, buf
, "Fatal error", MB_ICONEXCLAMATION
| MB_OK
);
48 void frontend_default_colour(frontend
*fe
, float *output
)
50 DWORD c
= GetSysColor(COLOR_MENU
); /* ick */
52 output
[0] = (float)(GetRValue(c
) / 255.0);
53 output
[1] = (float)(GetGValue(c
) / 255.0);
54 output
[2] = (float)(GetBValue(c
) / 255.0);
57 void draw_rect(frontend
*fe
, int x
, int y
, int w
, int h
, int colour
)
59 if (w
== 1 && h
== 1) {
61 * Rectangle() appears to get uppity if asked to draw a 1x1
62 * rectangle, presumably on the grounds that that's beneath
63 * its dignity and you ought to be using SetPixel instead.
66 SetPixel(fe
->hdc_bm
, x
, y
, fe
->colours
[colour
]);
68 HBRUSH oldbrush
= SelectObject(fe
->hdc_bm
, fe
->brushes
[colour
]);
69 HPEN oldpen
= SelectObject(fe
->hdc_bm
, fe
->pens
[colour
]);
70 Rectangle(fe
->hdc_bm
, x
, y
, x
+w
, y
+h
);
71 SelectObject(fe
->hdc_bm
, oldbrush
);
72 SelectObject(fe
->hdc_bm
, oldpen
);
76 void draw_line(frontend
*fe
, int x1
, int y1
, int x2
, int y2
, int colour
)
78 HPEN oldpen
= SelectObject(fe
->hdc_bm
, fe
->pens
[colour
]);
79 MoveToEx(fe
->hdc_bm
, x1
, y1
, NULL
);
80 LineTo(fe
->hdc_bm
, x2
, y2
);
81 SetPixel(fe
->hdc_bm
, x2
, y2
, fe
->colours
[colour
]);
82 SelectObject(fe
->hdc_bm
, oldpen
);
85 void draw_polygon(frontend
*fe
, int *coords
, int npoints
,
88 POINT
*pts
= snewn(npoints
+1, POINT
);
91 for (i
= 0; i
<= npoints
; i
++) {
92 int j
= (i
< npoints ? i
: 0);
93 pts
[i
].x
= coords
[j
*2];
94 pts
[i
].y
= coords
[j
*2+1];
98 HBRUSH oldbrush
= SelectObject(fe
->hdc_bm
, fe
->brushes
[colour
]);
99 HPEN oldpen
= SelectObject(fe
->hdc_bm
, fe
->pens
[colour
]);
100 Polygon(fe
->hdc_bm
, pts
, npoints
);
101 SelectObject(fe
->hdc_bm
, oldbrush
);
102 SelectObject(fe
->hdc_bm
, oldpen
);
104 HPEN oldpen
= SelectObject(fe
->hdc_bm
, fe
->pens
[colour
]);
105 Polyline(fe
->hdc_bm
, pts
, npoints
+1);
106 SelectObject(fe
->hdc_bm
, oldpen
);
112 void start_draw(frontend
*fe
)
115 hdc_win
= GetDC(fe
->hwnd
);
116 fe
->hdc_bm
= CreateCompatibleDC(hdc_win
);
117 fe
->prevbm
= SelectObject(fe
->hdc_bm
, fe
->bitmap
);
118 ReleaseDC(fe
->hwnd
, hdc_win
);
121 void draw_update(frontend
*fe
, int x
, int y
, int w
, int h
)
130 InvalidateRect(fe
->hwnd
, &r
, FALSE
);
133 void end_draw(frontend
*fe
)
135 SelectObject(fe
->hdc_bm
, fe
->prevbm
);
136 DeleteDC(fe
->hdc_bm
);
139 void deactivate_timer(frontend
*fe
)
141 KillTimer(fe
->hwnd
, fe
->timer
);
145 void activate_timer(frontend
*fe
)
147 fe
->timer
= SetTimer(fe
->hwnd
, fe
->timer
, 20, NULL
);
150 static frontend
*new_window(HINSTANCE inst
)
158 fe
->me
= midend_new(fe
);
159 midend_new_game(fe
->me
, NULL
);
160 midend_size(fe
->me
, &x
, &y
);
168 colours
= midend_colours(fe
->me
, &ncolours
);
170 fe
->colours
= snewn(ncolours
, COLORREF
);
171 fe
->brushes
= snewn(ncolours
, HBRUSH
);
172 fe
->pens
= snewn(ncolours
, HPEN
);
174 for (i
= 0; i
< ncolours
; i
++) {
175 fe
->colours
[i
] = RGB(255 * colours
[i
*3+0],
176 255 * colours
[i
*3+1],
177 255 * colours
[i
*3+2]);
178 fe
->brushes
[i
] = CreateSolidBrush(fe
->colours
[i
]);
180 MessageBox(fe
->hwnd
, "ooh", "eck", MB_OK
);
181 fe
->pens
[i
] = CreatePen(PS_SOLID
, 1, fe
->colours
[i
]);
188 AdjustWindowRectEx(&r
, WS_OVERLAPPEDWINDOW
&~
189 (WS_THICKFRAME
| WS_MAXIMIZEBOX
| WS_OVERLAPPED
),
192 fe
->hwnd
= CreateWindowEx(0, "puzzle", "puzzle",
193 WS_OVERLAPPEDWINDOW
&~
194 (WS_THICKFRAME
| WS_MAXIMIZEBOX
),
195 CW_USEDEFAULT
, CW_USEDEFAULT
,
196 r
.right
- r
.left
, r
.bottom
- r
.top
,
197 NULL
, NULL
, inst
, NULL
);
200 HMENU bar
= CreateMenu();
201 HMENU menu
= CreateMenu();
203 AppendMenu(bar
, MF_ENABLED
|MF_POPUP
, (UINT
)menu
, "Game");
204 AppendMenu(menu
, MF_ENABLED
, IDM_NEW
, "New");
205 AppendMenu(menu
, MF_ENABLED
, IDM_RESTART
, "Restart");
207 if ((fe
->npresets
= midend_num_presets(fe
->me
)) > 0) {
208 HMENU sub
= CreateMenu();
211 AppendMenu(menu
, MF_ENABLED
|MF_POPUP
, (UINT
)sub
, "Type");
213 fe
->presets
= snewn(fe
->npresets
, game_params
*);
215 for (i
= 0; i
< fe
->npresets
; i
++) {
218 midend_fetch_preset(fe
->me
, i
, &name
, &fe
->presets
[i
]);
221 * FIXME: we ought to go through and do something
222 * with ampersands here.
225 AppendMenu(sub
, MF_ENABLED
, IDM_PRESETS
+ 0x10 * i
, name
);
229 AppendMenu(menu
, MF_SEPARATOR
, 0, 0);
230 AppendMenu(menu
, MF_ENABLED
, IDM_UNDO
, "Undo");
231 AppendMenu(menu
, MF_ENABLED
, IDM_REDO
, "Redo");
232 AppendMenu(menu
, MF_SEPARATOR
, 0, 0);
233 AppendMenu(menu
, MF_ENABLED
, IDM_QUIT
, "Exit");
234 SetMenu(fe
->hwnd
, bar
);
237 hdc
= GetDC(fe
->hwnd
);
238 fe
->bitmap
= CreateCompatibleBitmap(hdc
, x
, y
);
239 ReleaseDC(fe
->hwnd
, hdc
);
241 SetWindowLong(fe
->hwnd
, GWL_USERDATA
, (LONG
)fe
);
243 ShowWindow(fe
->hwnd
, SW_NORMAL
);
244 SetForegroundWindow(fe
->hwnd
);
246 midend_redraw(fe
->me
);
251 static LRESULT CALLBACK
WndProc(HWND hwnd
, UINT message
,
252 WPARAM wParam
, LPARAM lParam
)
254 frontend
*fe
= (frontend
*)GetWindowLong(hwnd
, GWL_USERDATA
);
261 switch (wParam
& ~0xF) { /* low 4 bits reserved to Windows */
263 if (!midend_process_key(fe
->me
, 0, 0, 'n'))
267 if (!midend_process_key(fe
->me
, 0, 0, 'r'))
271 if (!midend_process_key(fe
->me
, 0, 0, 'u'))
275 if (!midend_process_key(fe
->me
, 0, 0, '\x12'))
279 if (!midend_process_key(fe
->me
, 0, 0, 'q'))
284 int p
= ((wParam
&~ 0xF) - IDM_PRESETS
) / 0x10;
286 if (p
>= 0 && p
< fe
->npresets
) {
291 midend_set_params(fe
->me
, fe
->presets
[p
]);
292 midend_new_game(fe
->me
, NULL
);
293 midend_size(fe
->me
, &x
, &y
);
298 AdjustWindowRectEx(&r
, WS_OVERLAPPEDWINDOW
&~
299 (WS_THICKFRAME
| WS_MAXIMIZEBOX
|
303 SetWindowPos(fe
->hwnd
, NULL
, 0, 0,
304 r
.right
- r
.left
, r
.bottom
- r
.top
,
305 SWP_NOMOVE
| SWP_NOZORDER
);
307 DeleteObject(fe
->bitmap
);
309 hdc
= GetDC(fe
->hwnd
);
310 fe
->bitmap
= CreateCompatibleBitmap(hdc
, x
, y
);
311 ReleaseDC(fe
->hwnd
, hdc
);
313 midend_redraw(fe
->me
);
328 hdc
= BeginPaint(hwnd
, &p
);
329 hdc2
= CreateCompatibleDC(hdc
);
330 prevbm
= SelectObject(hdc2
, fe
->bitmap
);
332 p
.rcPaint
.left
, p
.rcPaint
.top
,
333 p
.rcPaint
.right
- p
.rcPaint
.left
,
334 p
.rcPaint
.bottom
- p
.rcPaint
.top
,
336 p
.rcPaint
.left
, p
.rcPaint
.top
,
338 SelectObject(hdc2
, prevbm
);
348 case VK_LEFT
: key
= CURSOR_LEFT
; break;
349 case VK_RIGHT
: key
= CURSOR_RIGHT
; break;
350 case VK_UP
: key
= CURSOR_UP
; break;
351 case VK_DOWN
: key
= CURSOR_DOWN
; break;
355 if (!midend_process_key(fe
->me
, 0, 0, key
))
363 if (!midend_process_key(fe
->me
, LOWORD(lParam
), HIWORD(lParam
),
364 (message
== WM_LBUTTONDOWN ? LEFT_BUTTON
:
365 message
== WM_RBUTTONDOWN ? RIGHT_BUTTON
:
371 if (!midend_process_key(fe
->me
, 0, 0, (unsigned char)wParam
))
376 midend_timer(fe
->me
, (float)0.02);
380 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
383 int WINAPI
WinMain(HINSTANCE inst
, HINSTANCE prev
, LPSTR cmdline
, int show
)
393 wndclass
.lpfnWndProc
= WndProc
;
394 wndclass
.cbClsExtra
= 0;
395 wndclass
.cbWndExtra
= 0;
396 wndclass
.hInstance
= inst
;
397 wndclass
.hIcon
= LoadIcon(inst
, IDI_APPLICATION
);
398 wndclass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
399 wndclass
.hbrBackground
= NULL
;
400 wndclass
.lpszMenuName
= NULL
;
401 wndclass
.lpszClassName
= "puzzle";
403 RegisterClass(&wndclass
);
408 while (GetMessage(&msg
, NULL
, 0, 0)) {
409 TranslateMessage(&msg
);
410 DispatchMessage(&msg
);