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);