#include <windows.h>
#include <commctrl.h>
+#ifndef NO_HTMLHELP
+#include <htmlhelp.h>
+#endif /* NO_HTMLHELP */
#include <stdio.h>
#include <assert.h>
#define HELP_FILE_NAME "puzzles.hlp"
#define HELP_CNT_NAME "puzzles.cnt"
+#ifndef NO_HTMLHELP
+#define CHM_FILE_NAME "puzzles.chm"
+#endif /* NO_HTMLHELP */
+
+#ifndef NO_HTMLHELP
+typedef HWND (CALLBACK *htmlhelp_t)(HWND, LPCSTR, UINT, DWORD);
+static htmlhelp_t htmlhelp;
+static HINSTANCE hh_dll;
+#endif /* NO_HTMLHELP */
+enum { NONE, HLP, CHM } help_type;
+char *help_path;
+const char *help_topic;
+int help_has_contents;
#ifdef DEBUGGING
static FILE *debug_fp = NULL;
va_list ap;
va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
+ _vsnprintf(buf, 4095, fmt, ap);
dputs(buf);
va_end(ap);
}
#endif
+#define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \
+ (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED))
+
+static void new_game_size(frontend *fe);
+
struct font {
HFONT font;
int type;
HFONT cfgfont;
HBRUSH oldbr;
HPEN oldpen;
- char *help_path;
- int help_has_contents;
- char *laststatus;
+ int help_running;
enum { DRAWING, PRINTING, NOTHING } drawstatus;
DOCINFO di;
int printcount, printw, printh, printsolns, printcurr, printcolour;
static void win_status_bar(void *handle, char *text)
{
frontend *fe = (frontend *)handle;
- char *rewritten;
- rewritten = midend_rewrite_statusbar(fe->me, text);
- if (!fe->laststatus || strcmp(rewritten, fe->laststatus)) {
- SetWindowText(fe->statusbar, rewritten);
- sfree(fe->laststatus);
- fe->laststatus = rewritten;
- } else {
- sfree(rewritten);
- }
+ SetWindowText(fe->statusbar, text);
}
static blitter *win_blitter_new(void *handle, int w, int h)
fe->drawstatus = PRINTING;
fe->hdc = pd.hDC;
- fe->dr = drawing_init(&win_drawing, fe);
+ fe->dr = drawing_new(&win_drawing, NULL, fe);
document_print(doc, fe->dr);
drawing_free(fe->dr);
fe->dr = NULL;
}
/*
- * See if we can find a help file.
+ * Set up Help and see if we can find a help file.
*/
-static void find_help_file(frontend *fe)
+static void init_help(void)
{
char b[2048], *p, *q, *r;
FILE *fp;
- if (!fe->help_path) {
- GetModuleFileName(NULL, b, sizeof(b) - 1);
- r = b;
- p = strrchr(b, '\\');
- if (p && p >= r) r = p+1;
- q = strrchr(b, ':');
- if (q && q >= r) r = q+1;
- strcpy(r, HELP_FILE_NAME);
- if ( (fp = fopen(b, "r")) != NULL) {
- fe->help_path = dupstr(b);
- fclose(fp);
- } else
- fe->help_path = NULL;
- strcpy(r, HELP_CNT_NAME);
- if ( (fp = fopen(b, "r")) != NULL) {
- fe->help_has_contents = TRUE;
- fclose(fp);
- } else
- fe->help_has_contents = FALSE;
+
+ /*
+ * Find the executable file path, so we can look alongside
+ * it for help files. Trim the filename off the end.
+ */
+ GetModuleFileName(NULL, b, sizeof(b) - 1);
+ r = b;
+ p = strrchr(b, '\\');
+ if (p && p >= r) r = p+1;
+ q = strrchr(b, ':');
+ if (q && q >= r) r = q+1;
+
+#ifndef NO_HTMLHELP
+ /*
+ * Try HTML Help first.
+ */
+ strcpy(r, CHM_FILE_NAME);
+ if ( (fp = fopen(b, "r")) != NULL) {
+ fclose(fp);
+
+ /*
+ * We have a .CHM. See if we can use it.
+ */
+ hh_dll = LoadLibrary("hhctrl.ocx");
+ if (hh_dll) {
+ htmlhelp = (htmlhelp_t)GetProcAddress(hh_dll, "HtmlHelpA");
+ if (!htmlhelp)
+ FreeLibrary(hh_dll);
+ }
+ if (htmlhelp) {
+ help_path = dupstr(b);
+ help_type = CHM;
+ help_topic = thegame.htmlhelp_topic;
+ return;
+ }
}
+#endif /* NO_HTMLHELP */
+
+ /*
+ * Now try old-style .HLP.
+ */
+ strcpy(r, HELP_FILE_NAME);
+ if ( (fp = fopen(b, "r")) != NULL) {
+ fclose(fp);
+
+ help_path = dupstr(b);
+ help_type = HLP;
+
+ help_topic = thegame.winhelp_topic;
+
+ /*
+ * See if there's a .CNT file alongside it.
+ */
+ strcpy(r, HELP_CNT_NAME);
+ if ( (fp = fopen(b, "r")) != NULL) {
+ fclose(fp);
+ help_has_contents = TRUE;
+ } else
+ help_has_contents = FALSE;
+
+ return;
+ }
+
+ help_type = NONE; /* didn't find any */
+}
+
+/*
+ * Start Help.
+ */
+static void start_help(frontend *fe, const char *topic)
+{
+ char *str = NULL;
+ int cmd;
+
+ switch (help_type) {
+ case HLP:
+ assert(help_path);
+ if (topic) {
+ str = snewn(10+strlen(topic), char);
+ sprintf(str, "JI(`',`%s')", topic);
+ cmd = HELP_COMMAND;
+ } else if (help_has_contents) {
+ cmd = HELP_FINDER;
+ } else {
+ cmd = HELP_CONTENTS;
+ }
+ WinHelp(fe->hwnd, help_path, cmd, (DWORD)str);
+ fe->help_running = TRUE;
+ break;
+ case CHM:
+#ifndef NO_HTMLHELP
+ assert(help_path);
+ assert(htmlhelp);
+ if (topic) {
+ str = snewn(20 + strlen(topic) + strlen(help_path), char);
+ sprintf(str, "%s::/%s.html>main", help_path, topic);
+ } else {
+ str = dupstr(help_path);
+ }
+ htmlhelp(fe->hwnd, str, HH_DISPLAY_TOPIC, 0);
+ fe->help_running = TRUE;
+ break;
+#endif /* NO_HTMLHELP */
+ case NONE:
+ assert(!"This shouldn't happen");
+ break;
+ }
+
+ sfree(str);
+}
+
+/*
+ * Stop Help on window cleanup.
+ */
+static void stop_help(frontend *fe)
+{
+ if (fe->help_running) {
+ switch (help_type) {
+ case HLP:
+ WinHelp(fe->hwnd, help_path, HELP_QUIT, 0);
+ break;
+ case CHM:
+#ifndef NO_HTMLHELP
+ assert(htmlhelp);
+ htmlhelp(NULL, NULL, HH_CLOSE_ALL, 0);
+ break;
+#endif /* NO_HTMLHELP */
+ case NONE:
+ assert(!"This shouldn't happen");
+ break;
+ }
+ fe->help_running = FALSE;
+ }
+}
+
+/*
+ * Terminate Help on process exit.
+ */
+static void cleanup_help(void)
+{
+ /* Nothing to do currently.
+ * (If we were running HTML Help single-threaded, this is where we'd
+ * call HH_UNINITIALIZE.) */
}
static void check_window_size(frontend *fe, int *px, int *py)
r.left = r.top = 0;
r.right = x;
r.bottom = y + sy;
- AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~
- (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED),
- TRUE, 0);
+ AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top,
SWP_NOMOVE | SWP_NOZORDER);
}
*py = y;
}
+static void get_max_puzzle_size(frontend *fe, int *x, int *y)
+{
+ RECT r, sr;
+
+ if (SystemParametersInfo(SPI_GETWORKAREA, 0, &sr, FALSE)) {
+ *x = sr.right - sr.left;
+ *y = sr.bottom - sr.top;
+ r.left = 100;
+ r.right = 200;
+ r.top = 100;
+ r.bottom = 200;
+ AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
+ *x -= r.right - r.left - 100;
+ *y -= r.bottom - r.top - 100;
+ } else {
+ *x = *y = INT_MAX;
+ }
+
+ if (fe->statusbar != NULL) {
+ GetWindowRect(fe->statusbar, &sr);
+ *y -= sr.bottom - sr.top;
+ }
+}
+
static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
{
frontend *fe;
int x, y;
RECT r;
- HDC hdc;
fe = snew(frontend);
}
}
- fe->help_path = NULL;
- find_help_file(fe);
-
fe->inst = inst;
fe->timer = 0;
fe->hwnd = NULL;
+ fe->help_running = FALSE;
+
fe->drawstatus = NOTHING;
fe->dr = NULL;
fe->fontstart = 0;
fe->fonts = NULL;
fe->nfonts = fe->fontsize = 0;
- fe->laststatus = NULL;
-
{
int i, ncolours;
float *colours;
sfree(colours);
}
- x = y = INT_MAX; /* find puzzle's preferred size */
+ if (midend_wants_statusbar(fe->me)) {
+ fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
+ WS_CHILD | WS_VISIBLE,
+ 0, 0, 0, 0, /* status bar does these */
+ NULL, NULL, inst, NULL);
+ } else
+ fe->statusbar = NULL;
+
+ get_max_puzzle_size(fe, &x, &y);
midend_size(fe->me, &x, &y, FALSE);
r.left = r.top = 0;
r.right = x;
r.bottom = y;
- AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~
- (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED),
- TRUE, 0);
+ AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
fe->hwnd = CreateWindowEx(0, thegame.name, thegame.name,
WS_OVERLAPPEDWINDOW &~
if (midend_wants_statusbar(fe->me)) {
RECT sr;
+ DestroyWindow(fe->statusbar);
fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, /* status bar does these */
}
AppendMenu(menu, MF_SEPARATOR, 0, 0);
- AppendMenu(menu, MF_ENABLED, IDM_LOAD, "Load");
- AppendMenu(menu, MF_ENABLED, IDM_SAVE, "Save");
+ AppendMenu(menu, MF_ENABLED, IDM_LOAD, "Load...");
+ AppendMenu(menu, MF_ENABLED, IDM_SAVE, "Save...");
AppendMenu(menu, MF_SEPARATOR, 0, 0);
if (thegame.can_print) {
- AppendMenu(menu, MF_ENABLED, IDM_PRINT, "Print");
+ AppendMenu(menu, MF_ENABLED, IDM_PRINT, "Print...");
AppendMenu(menu, MF_SEPARATOR, 0, 0);
}
AppendMenu(menu, MF_ENABLED, IDM_UNDO, "Undo");
menu = CreateMenu();
AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Help");
AppendMenu(menu, MF_ENABLED, IDM_ABOUT, "About");
- if (fe->help_path) {
+ if (help_type != NONE) {
AppendMenu(menu, MF_SEPARATOR, 0, 0);
AppendMenu(menu, MF_ENABLED, IDM_HELPC, "Contents");
- if (thegame.winhelp_topic) {
+ if (help_topic) {
char *item;
assert(thegame.name);
item = snewn(9+strlen(thegame.name), char); /*ick*/
SetMenu(fe->hwnd, bar);
}
+ fe->bitmap = NULL;
+ new_game_size(fe); /* initialises fe->bitmap */
check_window_size(fe, &x, &y);
- hdc = GetDC(fe->hwnd);
- fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
- ReleaseDC(fe->hwnd, hdc);
-
SetWindowLong(fe->hwnd, GWL_USERDATA, (LONG)fe);
ShowWindow(fe->hwnd, SW_NORMAL);
HDC hdc;
int x, y;
- x = y = INT_MAX;
+ get_max_puzzle_size(fe, &x, &y);
midend_size(fe->me, &x, &y, FALSE);
r.left = r.top = 0;
r.right = x;
r.bottom = y;
- AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~
- (WS_THICKFRAME | WS_MAXIMIZEBOX |
- WS_OVERLAPPED),
- TRUE, 0);
+ AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
if (fe->statusbar != NULL) {
GetWindowRect(fe->statusbar, &sr);
SetWindowPos(fe->statusbar, NULL, 0, y, x,
sr.bottom - sr.top, SWP_NOZORDER);
- DeleteObject(fe->bitmap);
+ if (fe->bitmap) DeleteObject(fe->bitmap);
hdc = GetDC(fe->hwnd);
fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
break;
case IDM_HELPC:
- assert(fe->help_path);
- WinHelp(hwnd, fe->help_path,
- fe->help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0);
- break;
+ start_help(fe, NULL);
+ break;
case IDM_GAMEHELP:
- assert(fe->help_path);
- assert(thegame.winhelp_topic);
- {
- char *cmd = snewn(10+strlen(thegame.winhelp_topic), char);
- sprintf(cmd, "JI(`',`%s')", thegame.winhelp_topic);
- WinHelp(hwnd, fe->help_path, HELP_COMMAND, (DWORD)cmd);
- sfree(cmd);
- }
+ start_help(fe, help_topic);
break;
default:
{
}
break;
case WM_DESTROY:
+ stop_help(fe);
PostQuitMessage(0);
return 0;
case WM_PAINT:
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = inst;
- wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION);
+ wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200));
+ if (!wndclass.hIcon) /* in case resource file is absent */
+ wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
while (*cmdline && isspace((unsigned char)*cmdline))
cmdline++;
+ init_help();
+
if (!new_window(inst, *cmdline ? cmdline : NULL, &error)) {
char buf[128];
sprintf(buf, "%.100s Error", thegame.name);
DispatchMessage(&msg);
}
+ cleanup_help();
+
return msg.wParam;
}