}
fputs(buf, debug_fp);
fflush(debug_fp);
+ OutputDebugString(buf);
}
void debug_printf(char *fmt, ...)
#ifndef _WIN32_WCE
#define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \
- (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED))
+ (WS_MAXIMIZEBOX | WS_OVERLAPPED))
#else
#define WINFLAGS (WS_CAPTION | WS_SYSMENU)
#endif
HBRUSH *brushes;
HPEN *pens;
HRGN clip;
+ HMENU gamemenu, typemenu;
UINT timer;
DWORD timer_last_tickcount;
int npresets;
int fontstart;
int linewidth;
drawing *dr;
+ int xmin, ymin;
};
+static void update_type_menu_tick(frontend *fe);
+static void update_copy_menu_greying(frontend *fe);
+
void fatal(char *fmt, ...)
{
char buf[2048];
if (fe->drawstatus == PRINTING) {
int hatch;
float r, g, b;
- print_get_colour(fe->dr, colour, &hatch, &r, &g, &b);
- if (fe->printcolour)
- SetTextColor(fe->hdc, RGB(r * 255, g * 255, b * 255));
- else
- SetTextColor(fe->hdc,
- hatch == HATCH_CLEAR ? RGB(255,255,255) : RGB(0,0,0));
+ print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b);
+
+ /*
+ * Displaying text in hatched colours is not permitted.
+ */
+ assert(hatch < 0);
+
+ SetTextColor(fe->hdc, RGB(r * 255, g * 255, b * 255));
} else {
SetTextColor(fe->hdc, fe->colours[colour]);
}
if (fe->drawstatus == PRINTING) {
int hatch;
float r, g, b;
- print_get_colour(fe->dr, colour, &hatch, &r, &g, &b);
+ print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b);
- if (fe->printcolour) {
+ if (hatch < 0) {
br = CreateSolidBrush(RGB(r * 255, g * 255, b * 255));
- } else if (hatch == HATCH_SOLID) {
- br = CreateSolidBrush(RGB(0,0,0));
- } else if (hatch == HATCH_CLEAR) {
- br = CreateSolidBrush(RGB(255,255,255));
} else {
#ifdef _WIN32_WCE
/*
float r, g, b;
int width = thin ? 0 : fe->linewidth;
- print_get_colour(fe->dr, colour, &hatch, &r, &g, &b);
- if (fe->printcolour)
- pen = CreatePen(PS_SOLID, width,
- RGB(r * 255, g * 255, b * 255));
- else if (hatch == HATCH_SOLID)
- pen = CreatePen(PS_SOLID, width, RGB(0, 0, 0));
- else if (hatch == HATCH_CLEAR)
- pen = CreatePen(PS_SOLID, width, RGB(255,255,255));
- else {
- assert(!"This shouldn't happen");
- pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
- }
+ print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b);
+ /*
+ * Stroking in hatched colours is not permitted.
+ */
+ assert(hatch < 0);
+ pen = CreatePen(PS_SOLID, width, RGB(r * 255, g * 255, b * 255));
} else {
pen = fe->pens[colour];
}
xy.y -= tm.tmAscent;
}
#ifndef _WIN32_WCE
- if (GetTextExtentPoint32(fe->hdc, text, strlen(text), &size)) {
+ if (GetTextExtentPoint32(fe->hdc, text, strlen(text), &size))
#else
- if (GetTextExtentPoint32(fe->hdc, wText, wcslen(wText), &size)) {
+ if (GetTextExtentPoint32(fe->hdc, wText, wcslen(wText), &size))
#endif
+ {
if (align & ALIGN_HCENTRE)
xy.x -= size.cx / 2;
else if (align & ALIGN_HRIGHT)
* Work out what that comes to in pixels.
*/
pox = (int)(mmox * (float)ppw / mmpw);
- poy = (int)(mmoy * (float)ppw / mmpw);
+ poy = (int)(mmoy * (float)pph / mmph);
/*
* And determine the scale.
* call HH_UNINITIALIZE.) */
}
-static void check_window_size(frontend *fe, int *px, int *py)
+static int get_statusbar_height(frontend *fe)
{
- RECT r;
- int x, y, sy;
-
+ int sy;
if (fe->statusbar) {
RECT sr;
GetWindowRect(fe->statusbar, &sr);
} else {
sy = 0;
}
+ return sy;
+}
+
+static void adjust_statusbar(frontend *fe, RECT *r)
+{
+ int sy;
+
+ if (!fe->statusbar) return;
+
+ sy = get_statusbar_height(fe);
+#ifndef _WIN32_WCE
+ SetWindowPos(fe->statusbar, NULL, 0, r->bottom-r->top-sy, r->right-r->left,
+ sy, SWP_NOZORDER);
+#endif
+}
+
+static void get_menu_size(HWND wh, RECT *r)
+{
+ HMENU bar = GetMenu(wh);
+ RECT rect;
+ int i;
+
+ SetRect(r, 0, 0, 0, 0);
+ for (i = 0; i < GetMenuItemCount(bar); i++) {
+ GetMenuItemRect(wh, bar, i, &rect);
+ UnionRect(r, r, &rect);
+ }
+}
+
+/*
+ * Given a proposed new puzzle size (cx,cy), work out the actual
+ * puzzle size that would be (px,py) and the window size including
+ * furniture (wx,wy).
+ */
+
+static int check_window_resize(frontend *fe, int cx, int cy,
+ int *px, int *py,
+ int *wx, int *wy, int resize)
+{
+ RECT r;
+ int x, y, sy = get_statusbar_height(fe), changed = 0;
+
+ /* disallow making window thinner than menu bar */
+ x = max(cx, fe->xmin);
+ y = max(cy - sy, fe->ymin);
/*
* See if we actually got the window size we wanted, and adjust
* the puzzle size if not.
*/
- GetClientRect(fe->hwnd, &r);
- x = r.right - r.left;
- y = r.bottom - r.top - sy;
- midend_size(fe->me, &x, &y, FALSE);
- if (x != r.right - r.left || y != r.bottom - r.top) {
- /*
- * Resize the window, now we know what size we _really_
- * want it to be.
- */
- r.left = r.top = 0;
- r.right = x;
- r.bottom = y + sy;
- AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
-#ifndef _WIN32_WCE
- SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top,
- SWP_NOMOVE | SWP_NOZORDER);
-#endif
+ midend_size(fe->me, &x, &y, resize);
+ if (x != cx || y != cy) {
+ /*
+ * Resize the window, now we know what size we _really_
+ * want it to be.
+ */
+ r.left = r.top = 0;
+ r.right = x;
+ r.bottom = y + sy;
+ AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
+ *wx = r.right - r.left;
+ *wy = r.bottom - r.top;
+ changed = 1;
}
- if (fe->statusbar) {
- GetClientRect(fe->hwnd, &r);
-#ifndef _WIN32_WCE
- SetWindowPos(fe->statusbar, NULL, 0, r.bottom-r.top-sy, r.right-r.left,
- sy, SWP_NOZORDER);
+ *px = x;
+ *py = y;
+
+ return changed;
+}
+
+/*
+ * Given the current window size, make sure it's sane for the
+ * current puzzle and resize if necessary.
+ */
+
+static void check_window_size(frontend *fe, int *px, int *py)
+{
+ RECT r;
+ int wx, wy, cx, cy;
+
+ GetClientRect(fe->hwnd, &r);
+ cx = r.right - r.left;
+ cy = r.bottom - r.top;
+
+ if (check_window_resize(fe, cx, cy, px, py, &wx, &wy, FALSE)) {
+#ifdef _WIN32_WCE
+ SetWindowPos(fe->hwnd, NULL, 0, 0, wx, wy,
+ SWP_NOMOVE | SWP_NOZORDER);
#endif
+ ;
}
- *px = x;
- *py = y;
+ GetClientRect(fe->hwnd, &r);
+ adjust_statusbar(fe, &r);
}
static void get_max_puzzle_size(frontend *fe, int *x, int *y)
#else
fe->hwnd = CreateWindowEx(0, thegame.name, thegame.name,
WS_OVERLAPPEDWINDOW &~
- (WS_THICKFRAME | WS_MAXIMIZEBOX),
+ (WS_MAXIMIZEBOX),
CW_USEDEFAULT, CW_USEDEFAULT,
r.right - r.left, r.bottom - r.top,
NULL, NULL, inst, NULL);
#ifndef _WIN32_WCE
HMENU bar = CreateMenu();
HMENU menu = CreateMenu();
+ RECT menusize;
- AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Game");
+ AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "&Game");
#else
HMENU menu = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_GAME);
DeleteMenu(menu, 0, MF_BYPOSITION);
#endif
- AppendMenu(menu, MF_ENABLED, IDM_NEW, TEXT("New"));
- AppendMenu(menu, MF_ENABLED, IDM_RESTART, TEXT("Restart"));
+ fe->gamemenu = menu;
+ AppendMenu(menu, MF_ENABLED, IDM_NEW, TEXT("&New"));
+ AppendMenu(menu, MF_ENABLED, IDM_RESTART, TEXT("&Restart"));
#ifndef _WIN32_WCE
- AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Specific..."));
- AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Random Seed..."));
+ /* ...here I run out of sensible accelerator characters. */
+ AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Speci&fic..."));
+ AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Rando&m Seed..."));
#endif
if ((fe->npresets = midend_num_presets(fe->me)) > 0 ||
#ifndef _WIN32_WCE
HMENU sub = CreateMenu();
- AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "Type");
+ AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "&Type");
#else
HMENU sub = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_TYPE);
DeleteMenu(sub, 0, MF_BYPOSITION);
#endif
}
if (thegame.can_configure) {
- AppendMenu(sub, MF_ENABLED, IDM_CONFIG, TEXT("Custom..."));
+ AppendMenu(sub, MF_ENABLED, IDM_CONFIG, TEXT("&Custom..."));
}
- }
+
+ fe->typemenu = sub;
+ } else
+ fe->typemenu = INVALID_HANDLE_VALUE;
AppendMenu(menu, MF_SEPARATOR, 0, 0);
#ifndef _WIN32_WCE
- AppendMenu(menu, MF_ENABLED, IDM_LOAD, TEXT("Load..."));
- AppendMenu(menu, MF_ENABLED, IDM_SAVE, TEXT("Save..."));
+ AppendMenu(menu, MF_ENABLED, IDM_LOAD, TEXT("&Load..."));
+ AppendMenu(menu, MF_ENABLED, IDM_SAVE, TEXT("&Save..."));
AppendMenu(menu, MF_SEPARATOR, 0, 0);
if (thegame.can_print) {
- AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("Print..."));
+ AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("&Print..."));
AppendMenu(menu, MF_SEPARATOR, 0, 0);
}
#endif
AppendMenu(menu, MF_ENABLED, IDM_UNDO, TEXT("Undo"));
AppendMenu(menu, MF_ENABLED, IDM_REDO, TEXT("Redo"));
#ifndef _WIN32_WCE
- if (thegame.can_format_as_text) {
+ if (thegame.can_format_as_text_ever) {
AppendMenu(menu, MF_SEPARATOR, 0, 0);
- AppendMenu(menu, MF_ENABLED, IDM_COPY, TEXT("Copy"));
+ AppendMenu(menu, MF_ENABLED, IDM_COPY, TEXT("&Copy"));
}
#endif
if (thegame.can_solve) {
AppendMenu(menu, MF_SEPARATOR, 0, 0);
- AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Solve"));
+ AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Sol&ve"));
}
AppendMenu(menu, MF_SEPARATOR, 0, 0);
#ifndef _WIN32_WCE
- AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("Exit"));
+ AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("E&xit"));
menu = CreateMenu();
- AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, TEXT("Help"));
+ AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, TEXT("&Help"));
#endif
- AppendMenu(menu, MF_ENABLED, IDM_ABOUT, TEXT("About"));
+ AppendMenu(menu, MF_ENABLED, IDM_ABOUT, TEXT("&About"));
#ifndef _WIN32_WCE
if (help_type != NONE) {
AppendMenu(menu, MF_SEPARATOR, 0, 0);
- AppendMenu(menu, MF_ENABLED, IDM_HELPC, TEXT("Contents"));
+ AppendMenu(menu, MF_ENABLED, IDM_HELPC, TEXT("&Contents"));
if (help_topic) {
char *item;
assert(thegame.name);
- item = snewn(9+strlen(thegame.name), char); /*ick*/
- sprintf(item, "Help on %s", thegame.name);
+ item = snewn(10+strlen(thegame.name), char); /*ick*/
+ sprintf(item, "&Help on %s", thegame.name);
AppendMenu(menu, MF_ENABLED, IDM_GAMEHELP, item);
sfree(item);
}
}
SetMenu(fe->hwnd, bar);
+ get_menu_size(fe->hwnd, &menusize);
+ fe->xmin = (menusize.right - menusize.left) + 25;
#endif
}
ShowWindow(fe->hwnd, SW_SHOWNORMAL);
SetForegroundWindow(fe->hwnd);
+ update_type_menu_tick(fe);
+ update_copy_menu_greying(fe);
+
midend_redraw(fe->me);
return fe;
y += height/2; /* extra space before OK */
mkctrl(fe, width*2, maxwid+width*2, y, y+height*7/4, "BUTTON",
- BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
+ BS_PUSHBUTTON | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
"OK", IDOK);
SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0);
y += height/2; /* extra space before OK and Cancel */
mkctrl(fe, col1l, (col1l+col2r)/2-width, y, y+height*7/4, "BUTTON",
- BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
+ BS_PUSHBUTTON | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
"OK", IDOK);
mkctrl(fe, (col1l+col2r)/2+width, col2r, y, y+height*7/4, "BUTTON",
- BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP, 0, "Cancel", IDCANCEL);
+ BS_PUSHBUTTON | WS_TABSTOP, 0, "Cancel", IDCANCEL);
SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0);
}
#endif
+static void new_bitmap(frontend *fe, int x, int y)
+{
+ HDC hdc;
+
+ if (fe->bitmap) DeleteObject(fe->bitmap);
+
+ hdc = GetDC(fe->hwnd);
+ fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
+ calculate_bitmap_position(fe, x, y);
+ ReleaseDC(fe->hwnd, hdc);
+}
+
static void new_game_size(frontend *fe)
{
RECT r, sr;
- HDC hdc;
int x, y;
get_max_puzzle_size(fe, &x, &y);
midend_size(fe->me, &x, &y, FALSE);
+ fe->ymin = (fe->xmin * y) / x;
r.left = r.top = 0;
r.right = x;
sr.bottom - sr.top, SWP_NOZORDER);
#endif
- if (fe->bitmap) DeleteObject(fe->bitmap);
-
- hdc = GetDC(fe->hwnd);
- fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
- calculate_bitmap_position(fe, x, y);
- ReleaseDC(fe->hwnd, hdc);
+ new_bitmap(fe, x, y);
#ifdef _WIN32_WCE
InvalidateRect(fe->hwnd, NULL, TRUE);
midend_redraw(fe->me);
}
+/*
+ * Given a proposed new window rect, work out the resulting
+ * difference in client size (from current), and use to try
+ * and resize the puzzle, returning (wx,wy) as the actual
+ * new window size.
+ */
+
+static void adjust_game_size(frontend *fe, RECT *proposed, int isedge,
+ int *wx_r, int *wy_r)
+{
+ RECT cr, wr;
+ int nx, ny, xdiff, ydiff, wx, wy;
+
+ /* Work out the current window sizing, and thus the
+ * difference in size we're asking for. */
+ GetClientRect(fe->hwnd, &cr);
+ wr = cr;
+ AdjustWindowRectEx(&wr, WINFLAGS, TRUE, 0);
+
+ xdiff = (proposed->right - proposed->left) - (wr.right - wr.left);
+ ydiff = (proposed->bottom - proposed->top) - (wr.bottom - wr.top);
+
+ if (isedge) {
+ /* These next four lines work around the fact that midend_size
+ * is happy to shrink _but not grow_ if you change one dimension
+ * but not the other. */
+ if (xdiff > 0 && ydiff == 0)
+ ydiff = (xdiff * (wr.right - wr.left)) / (wr.bottom - wr.top);
+ if (xdiff == 0 && ydiff > 0)
+ xdiff = (ydiff * (wr.bottom - wr.top)) / (wr.right - wr.left);
+ }
+
+ if (check_window_resize(fe,
+ (cr.right - cr.left) + xdiff,
+ (cr.bottom - cr.top) + ydiff,
+ &nx, &ny, &wx, &wy, TRUE)) {
+ new_bitmap(fe, nx, ny);
+ midend_force_redraw(fe->me);
+ } else {
+ /* reset size to current window size */
+ wx = wr.right - wr.left;
+ wy = wr.bottom - wr.top;
+ }
+ /* Re-fetch rectangle; size limits mean we might not have
+ * taken it quite to the mouse drag positions. */
+ GetClientRect(fe->hwnd, &cr);
+ adjust_statusbar(fe, &cr);
+
+ *wx_r = wx; *wy_r = wy;
+}
+
+static void update_type_menu_tick(frontend *fe)
+{
+ int total, n, i;
+
+ if (fe->typemenu == INVALID_HANDLE_VALUE)
+ return;
+
+ total = GetMenuItemCount(fe->typemenu);
+ n = midend_which_preset(fe->me);
+ if (n < 0)
+ n = total - 1; /* "Custom" item */
+
+ for (i = 0; i < total; i++) {
+ int flag = (i == n ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(fe->typemenu, i, MF_BYPOSITION | flag);
+ }
+
+ DrawMenuBar(fe->hwnd);
+}
+
+static void update_copy_menu_greying(frontend *fe)
+{
+ UINT enable = (midend_can_format_as_text_now(fe->me) ?
+ MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(fe->gamemenu, IDM_COPY, MF_BYCOMMAND | enable);
+}
+
static void new_game_type(frontend *fe)
{
midend_new_game(fe->me);
new_game_size(fe);
+ update_type_menu_tick(fe);
+ update_copy_menu_greying(fe);
}
static int is_alt_pressed(void)
fe->timer_last_tickcount = now;
}
return 0;
+#ifndef _WIN32_WCE
+ case WM_SIZING:
+ {
+ RECT *sr = (RECT *)lParam;
+ int wx, wy, isedge = 0;
+
+ if (wParam == WMSZ_TOP ||
+ wParam == WMSZ_RIGHT ||
+ wParam == WMSZ_BOTTOM ||
+ wParam == WMSZ_LEFT) isedge = 1;
+ adjust_game_size(fe, sr, isedge, &wx, &wy);
+
+ /* Given the window size the puzzles constrain
+ * us to, work out which edge we should be moving. */
+ if (wParam == WMSZ_TOP ||
+ wParam == WMSZ_TOPLEFT ||
+ wParam == WMSZ_TOPRIGHT) {
+ sr->top = sr->bottom - wy;
+ } else {
+ sr->bottom = sr->top + wy;
+ }
+ if (wParam == WMSZ_LEFT ||
+ wParam == WMSZ_TOPLEFT ||
+ wParam == WMSZ_BOTTOMLEFT) {
+ sr->left = sr->right - wx;
+ } else {
+ sr->right = sr->left + wx;
+ }
+ return TRUE;
+ }
+ break;
+#endif
}
return DefWindowProc(hwnd, message, wParam, lParam);