X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/35ee200129890bb76d15168c879bb0b0ca622296..c5e949657127f3c752cdc693cb71636711d9ecb1:/windows.c diff --git a/windows.c b/windows.c index 72d0120..ba0ed52 100644 --- a/windows.c +++ b/windows.c @@ -4,6 +4,14 @@ #include #include +#ifndef NO_HTMLHELP +#include +#endif /* NO_HTMLHELP */ + +#ifdef _WIN32_WCE +#include +#include +#endif #include #include @@ -15,6 +23,10 @@ #include "puzzles.h" +#ifdef _WIN32_WCE +#include "resource.h" +#endif + #define IDM_NEW 0x0010 #define IDM_RESTART 0x0020 #define IDM_UNDO 0x0030 @@ -33,8 +45,75 @@ #define IDM_PRINT 0x0100 #define IDM_PRESETS 0x0110 +#define IDM_KEYEMUL 0x0400 + #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; + +#ifndef FILENAME_MAX +#define FILENAME_MAX (260) +#endif + +#ifndef HGDI_ERROR +#define HGDI_ERROR ((HANDLE)GDI_ERROR) +#endif + +#ifdef _WIN32_WCE + +/* + * Wrapper implementations of functions not supplied by the + * PocketPC API. + */ + +#define SHGetSubMenu(hWndMB,ID_MENU) (HMENU)SendMessage((hWndMB), SHCMBM_GETSUBMENU, (WPARAM)0, (LPARAM)ID_MENU) + +#undef MessageBox + +int MessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) +{ + TCHAR wText[2048]; + TCHAR wCaption[2048]; + + MultiByteToWideChar (CP_ACP, 0, lpText, -1, wText, 2048); + MultiByteToWideChar (CP_ACP, 0, lpCaption, -1, wCaption, 2048); + + return MessageBoxW (hWnd, wText, wCaption, uType); +} + +BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPCSTR lpString) +{ + TCHAR wText[256]; + + MultiByteToWideChar (CP_ACP, 0, lpString, -1, wText, 256); + return SetDlgItemTextW(hDlg, nIDDlgItem, wText); +} + +LPCSTR getenv(LPCSTR buf) +{ + return NULL; +} + +BOOL GetKeyboardState(PBYTE pb) +{ + return FALSE; +} + +static TCHAR wGameName[256]; + +#endif #ifdef DEBUGGING static FILE *debug_fp = NULL; @@ -68,14 +147,18 @@ void debug_printf(char *fmt, ...) va_list ap; va_start(ap, fmt); - vsprintf(buf, fmt, ap); + _vsnprintf(buf, 4095, fmt, ap); dputs(buf); va_end(ap); } #endif +#ifndef _WIN32_WCE #define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \ (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED)) +#else +#define WINFLAGS (WS_CAPTION | WS_SYSMENU) +#endif static void new_game_size(frontend *fe); @@ -100,8 +183,12 @@ enum { CFG_PRINT = CFG_FRONTEND_SPECIFIC }; struct frontend { midend *me; HWND hwnd, statusbar, cfgbox; +#ifdef _WIN32_WCE + HWND numpad; /* window handle for the numeric pad */ +#endif HINSTANCE inst; HBITMAP bitmap, prevbm; + RECT bitmapPosition; /* game bitmap position within game window */ HDC hdc; COLORREF *colours; HBRUSH *brushes; @@ -119,9 +206,7 @@ struct frontend { 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; @@ -171,25 +256,29 @@ char *geterrstr(void) void get_random_seed(void **randseed, int *randseedsize) { - time_t *tp = snew(time_t); - time(tp); - *randseed = (void *)tp; - *randseedsize = sizeof(time_t); + SYSTEMTIME *st = snew(SYSTEMTIME); + + GetLocalTime(st); + + *randseed = (void *)st; + *randseedsize = sizeof(SYSTEMTIME); } static void win_status_bar(void *handle, char *text) { +#ifdef _WIN32_WCE + TCHAR wText[255]; +#endif 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); - } +#ifdef _WIN32_WCE + MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 255); + SendMessage(fe->statusbar, SB_SETTEXT, + (WPARAM) 255 | SBT_NOBORDERS, + (LPARAM) wText); +#else + SetWindowText(fe->statusbar, text); +#endif } static blitter *win_blitter_new(void *handle, int w, int h) @@ -328,13 +417,20 @@ static void win_set_brush(frontend *fe, int colour) float r, g, b; print_get_colour(fe->dr, colour, &hatch, &r, &g, &b); - if (fe->printcolour) + if (fe->printcolour) { br = CreateSolidBrush(RGB(r * 255, g * 255, b * 255)); - else if (hatch == HATCH_SOLID) + } else if (hatch == HATCH_SOLID) { br = CreateSolidBrush(RGB(0,0,0)); - else if (hatch == HATCH_CLEAR) + } else if (hatch == HATCH_CLEAR) { br = CreateSolidBrush(RGB(255,255,255)); - else + } else { +#ifdef _WIN32_WCE + /* + * This is only ever required during printing, and the + * PocketPC port doesn't support printing. + */ + fatal("CreateHatchBrush not supported"); +#else br = CreateHatchBrush(hatch == HATCH_BACKSLASH ? HS_FDIAGONAL : hatch == HATCH_SLASH ? HS_BDIAGONAL : hatch == HATCH_HORIZ ? HS_HORIZONTAL : @@ -342,6 +438,8 @@ static void win_set_brush(frontend *fe, int colour) hatch == HATCH_PLUS ? HS_CROSS : /* hatch == HATCH_X ? */ HS_DIAGCROSS, RGB(0,0,0)); +#endif + } } else { br = fe->brushes[colour]; } @@ -427,6 +525,7 @@ static void win_draw_text(void *handle, int x, int y, int fonttype, frontend *fe = (frontend *)handle; POINT xy; int i; + LOGFONT lf; if (fe->drawstatus == NOTHING) return; @@ -454,15 +553,21 @@ static void win_draw_text(void *handle, int x, int y, int fonttype, fe->fonts[i].type = fonttype; fe->fonts[i].size = fontsize; - fe->fonts[i].font = CreateFont(-fontsize, 0, 0, 0, - fe->drawstatus == PRINTING ? 0 : FW_BOLD, - FALSE, FALSE, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - (fonttype == FONT_FIXED ? - FIXED_PITCH | FF_DONTCARE : - VARIABLE_PITCH | FF_SWISS), - NULL); + memset (&lf, 0, sizeof(LOGFONT)); + lf.lfHeight = -fontsize; + lf.lfWeight = (fe->drawstatus == PRINTING ? 0 : FW_BOLD); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = (fonttype == FONT_FIXED ? + FIXED_PITCH | FF_DONTCARE : + VARIABLE_PITCH | FF_SWISS); +#ifdef _WIN32_WCE + wcscpy(lf.lfFaceName, TEXT("Tahoma")); +#endif + + fe->fonts[i].font = CreateFontIndirect(&lf); } /* @@ -472,6 +577,10 @@ static void win_draw_text(void *handle, int x, int y, int fonttype, HFONT oldfont; TEXTMETRIC tm; SIZE size; +#ifdef _WIN32_WCE + TCHAR wText[256]; + MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 256); +#endif oldfont = SelectObject(fe->hdc, fe->fonts[i].font); if (GetTextMetrics(fe->hdc, &tm)) { @@ -480,7 +589,11 @@ static void win_draw_text(void *handle, int x, int y, int fonttype, else xy.y -= tm.tmAscent; } +#ifndef _WIN32_WCE if (GetTextExtentPoint32(fe->hdc, text, strlen(text), &size)) { +#else + if (GetTextExtentPoint32(fe->hdc, wText, wcslen(wText), &size)) { +#endif if (align & ALIGN_HCENTRE) xy.x -= size.cx / 2; else if (align & ALIGN_HRIGHT) @@ -488,7 +601,11 @@ static void win_draw_text(void *handle, int x, int y, int fonttype, } SetBkMode(fe->hdc, TRANSPARENT); win_text_colour(fe, colour); +#ifndef _WIN32_WCE TextOut(fe->hdc, xy.x, xy.y, text, strlen(text)); +#else + ExtTextOut(fe->hdc, xy.x, xy.y, 0, NULL, wText, wcslen(wText), NULL); +#endif SelectObject(fe->hdc, oldfont); } } @@ -523,18 +640,17 @@ static void win_draw_rect(void *handle, int x, int y, int w, int h, int colour) static void win_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) { frontend *fe = (frontend *)handle; - POINT p, q; + POINT pp[2]; if (fe->drawstatus == NOTHING) return; win_set_pen(fe, colour, FALSE); - p = win_transform_point(fe, x1, y1); - q = win_transform_point(fe, x2, y2); - MoveToEx(fe->hdc, p.x, p.y, NULL); - LineTo(fe->hdc, q.x, q.y); + pp[0] = win_transform_point(fe, x1, y1); + pp[1] = win_transform_point(fe, x2, y2); + Polyline(fe->hdc, pp, 2); if (fe->drawstatus == DRAWING) - SetPixel(fe->hdc, q.x, q.y, fe->colours[colour]); + SetPixel(fe->hdc, pp[1].x, pp[1].y, fe->colours[colour]); win_reset_pen(fe); } @@ -542,29 +658,24 @@ static void win_draw_circle(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; - POINT p, q, r; + POINT p, q; assert(outlinecolour >= 0); if (fe->drawstatus == NOTHING) return; - if (fillcolour >= 0) { + if (fillcolour >= 0) win_set_brush(fe, fillcolour); - win_set_pen(fe, outlinecolour, FALSE); - p = win_transform_point(fe, cx - radius, cy - radius); - q = win_transform_point(fe, cx + radius, cy + radius); - Ellipse(fe->hdc, p.x, p.y, q.x+1, q.y+1); - win_reset_brush(fe); - win_reset_pen(fe); - } else { - win_set_pen(fe, outlinecolour, FALSE); - p = win_transform_point(fe, cx - radius, cy - radius); - q = win_transform_point(fe, cx + radius, cy + radius); - r = win_transform_point(fe, cx - radius, cy); - Arc(fe->hdc, p.x, p.y, q.x+1, q.y+1, r.x, r.y, r.x, r.y); - win_reset_pen(fe); - } + else + fe->oldbr = SelectObject(fe->hdc, GetStockObject(NULL_BRUSH)); + + win_set_pen(fe, outlinecolour, FALSE); + p = win_transform_point(fe, cx - radius, cy - radius); + q = win_transform_point(fe, cx + radius, cy + radius); + Ellipse(fe->hdc, p.x, p.y, q.x+1, q.y+1); + win_reset_brush(fe); + win_reset_pen(fe); } static void win_draw_polygon(void *handle, int *coords, int npoints, @@ -613,7 +724,9 @@ static void win_start_draw(void *handle) fe->prevbm = SelectObject(fe->hdc, fe->bitmap); ReleaseDC(fe->hwnd, hdc_win); fe->clip = NULL; +#ifndef _WIN32_WCE SetMapMode(fe->hdc, MM_TEXT); +#endif fe->drawstatus = DRAWING; } @@ -630,6 +743,7 @@ static void win_draw_update(void *handle, int x, int y, int w, int h) r.right = x + w; r.bottom = y + h; + OffsetRect(&r, fe->bitmapPosition.left, fe->bitmapPosition.top); InvalidateRect(fe->hwnd, &r, FALSE); } @@ -832,6 +946,7 @@ const struct drawing_api win_drawing = { void print(frontend *fe) { +#ifndef _WIN32_WCE PRINTDLG pd; char doctitle[256]; document *doc; @@ -913,7 +1028,7 @@ void print(frontend *fe) 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; @@ -922,6 +1037,7 @@ void print(frontend *fe) DeleteDC(pd.hDC); document_free(doc); +#endif } void deactivate_timer(frontend *fe) @@ -937,7 +1053,7 @@ void activate_timer(frontend *fe) if (!fe) return; /* for non-interactive midend */ if (!fe->timer) { - fe->timer = SetTimer(fe->hwnd, fe->timer, 20, NULL); + fe->timer = SetTimer(fe->hwnd, 1, 20, NULL); fe->timer_last_tickcount = GetTickCount(); } } @@ -990,32 +1106,161 @@ void write_clip(HWND hwnd, char *data) } /* - * 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) { +#ifndef _WIN32_WCE 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 */ +#endif +} + +#ifndef _WIN32_WCE + +/* + * 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; + } +} + +#endif + +/* + * 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) @@ -1048,14 +1293,18 @@ static void check_window_size(frontend *fe, int *px, int *py) 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 } 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); +#endif } *px = x; @@ -1086,12 +1335,28 @@ static void get_max_puzzle_size(frontend *fe, int *x, int *y) } } +#ifdef _WIN32_WCE +/* Toolbar buttons on the numeric pad */ +static TBBUTTON tbNumpadButtons[] = +{ + {0, IDM_KEYEMUL + '1', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {1, IDM_KEYEMUL + '2', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {2, IDM_KEYEMUL + '3', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {3, IDM_KEYEMUL + '4', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {4, IDM_KEYEMUL + '5', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {5, IDM_KEYEMUL + '6', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {6, IDM_KEYEMUL + '7', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {7, IDM_KEYEMUL + '8', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {8, IDM_KEYEMUL + '9', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, + {9, IDM_KEYEMUL + ' ', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1} +}; +#endif + static frontend *new_window(HINSTANCE inst, char *game_id, char **error) { frontend *fe; int x, y; RECT r; - HDC hdc; fe = snew(frontend); @@ -1106,14 +1371,13 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) } } - 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; @@ -1123,8 +1387,6 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) fe->fonts = NULL; fe->nfonts = fe->fontsize = 0; - fe->laststatus = NULL; - { int i, ncolours; float *colours; @@ -1146,11 +1408,12 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) } if (midend_wants_statusbar(fe->me)) { - fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh", + fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("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); @@ -1160,53 +1423,123 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) r.bottom = y; AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); +#ifdef _WIN32_WCE + fe->hwnd = CreateWindowEx(0, wGameName, wGameName, + WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, inst, NULL); + + { + SHMENUBARINFO mbi; + RECT rc, rcBar, rcTB, rcClient; + + memset (&mbi, 0, sizeof(SHMENUBARINFO)); + mbi.cbSize = sizeof(SHMENUBARINFO); + mbi.hwndParent = fe->hwnd; + mbi.nToolBarId = IDR_MENUBAR1; + mbi.hInstRes = inst; + + SHCreateMenuBar(&mbi); + + GetWindowRect(fe->hwnd, &rc); + GetWindowRect(mbi.hwndMB, &rcBar); + rc.bottom -= rcBar.bottom - rcBar.top; + MoveWindow(fe->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); + + if (thegame.flags & REQUIRE_NUMPAD) + { + fe->numpad = CreateToolbarEx (fe->hwnd, + WS_VISIBLE | WS_CHILD | CCS_NOPARENTALIGN | TBSTYLE_FLAT, + 0, 10, inst, IDR_PADTOOLBAR, + tbNumpadButtons, sizeof (tbNumpadButtons) / sizeof (TBBUTTON), + 0, 0, 14, 15, sizeof (TBBUTTON)); + GetWindowRect(fe->numpad, &rcTB); + GetClientRect(fe->hwnd, &rcClient); + MoveWindow(fe->numpad, + 0, + rcClient.bottom - (rcTB.bottom - rcTB.top) - 1, + rcClient.right, + rcTB.bottom - rcTB.top, + FALSE); + SendMessage(fe->numpad, TB_SETINDENT, (rcClient.right - (10 * 21)) / 2, 0); + } + else + fe->numpad = NULL; + } +#else fe->hwnd = CreateWindowEx(0, thegame.name, thegame.name, WS_OVERLAPPEDWINDOW &~ (WS_THICKFRAME | WS_MAXIMIZEBOX), CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, NULL, NULL, inst, NULL); +#endif if (midend_wants_statusbar(fe->me)) { RECT sr; DestroyWindow(fe->statusbar); - fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh", + fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("ooh"), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, /* status bar does these */ fe->hwnd, NULL, inst, NULL); +#ifdef _WIN32_WCE + /* Flat status bar looks better on the Pocket PC */ + SendMessage(fe->statusbar, SB_SIMPLE, (WPARAM) TRUE, 0); + SendMessage(fe->statusbar, SB_SETTEXT, + (WPARAM) 255 | SBT_NOBORDERS, + (LPARAM) L""); +#endif + /* * Now resize the window to take account of the status bar. */ GetWindowRect(fe->statusbar, &sr); GetWindowRect(fe->hwnd, &r); +#ifndef _WIN32_WCE SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top + sr.bottom - sr.top, SWP_NOMOVE | SWP_NOZORDER); +#endif } else { fe->statusbar = NULL; } { +#ifndef _WIN32_WCE HMENU bar = CreateMenu(); HMENU menu = CreateMenu(); AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Game"); - AppendMenu(menu, MF_ENABLED, IDM_NEW, "New"); - AppendMenu(menu, MF_ENABLED, IDM_RESTART, "Restart"); - AppendMenu(menu, MF_ENABLED, IDM_DESC, "Specific..."); - AppendMenu(menu, MF_ENABLED, IDM_SEED, "Random Seed..."); +#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")); +#ifndef _WIN32_WCE + AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Specific...")); + AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Random Seed...")); +#endif if ((fe->npresets = midend_num_presets(fe->me)) > 0 || thegame.can_configure) { - HMENU sub = CreateMenu(); int i; +#ifndef _WIN32_WCE + HMENU sub = CreateMenu(); AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "Type"); - +#else + HMENU sub = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_TYPE); + DeleteMenu(sub, 0, MF_BYPOSITION); +#endif fe->presets = snewn(fe->npresets, game_params *); for (i = 0; i < fe->npresets; i++) { char *name; +#ifdef _WIN32_WCE + TCHAR wName[255]; +#endif midend_fetch_preset(fe->me, i, &name, &fe->presets[i]); @@ -1215,41 +1548,52 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) * with ampersands here. */ +#ifndef _WIN32_WCE AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, name); +#else + MultiByteToWideChar (CP_ACP, 0, name, -1, wName, 255); + AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, wName); +#endif } - if (thegame.can_configure) { - AppendMenu(sub, MF_ENABLED, IDM_CONFIG, "Custom..."); + AppendMenu(sub, MF_ENABLED, IDM_CONFIG, TEXT("Custom...")); } } AppendMenu(menu, MF_SEPARATOR, 0, 0); - AppendMenu(menu, MF_ENABLED, IDM_LOAD, "Load"); - AppendMenu(menu, MF_ENABLED, IDM_SAVE, "Save"); +#ifndef _WIN32_WCE + 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, "Print"); + AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("Print...")); AppendMenu(menu, MF_SEPARATOR, 0, 0); } - AppendMenu(menu, MF_ENABLED, IDM_UNDO, "Undo"); - AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo"); +#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) { AppendMenu(menu, MF_SEPARATOR, 0, 0); - AppendMenu(menu, MF_ENABLED, IDM_COPY, "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, "Solve"); + AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Solve")); } AppendMenu(menu, MF_SEPARATOR, 0, 0); - AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit"); +#ifndef _WIN32_WCE + AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("Exit")); menu = CreateMenu(); - AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Help"); - AppendMenu(menu, MF_ENABLED, IDM_ABOUT, "About"); - if (fe->help_path) { + AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, TEXT("Help")); +#endif + 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, "Contents"); - if (thegame.winhelp_topic) { + AppendMenu(menu, MF_ENABLED, IDM_HELPC, TEXT("Contents")); + if (help_topic) { char *item; assert(thegame.name); item = snewn(9+strlen(thegame.name), char); /*ick*/ @@ -1259,18 +1603,16 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) } } SetMenu(fe->hwnd, bar); +#endif } - new_game_size(fe); + 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); + ShowWindow(fe->hwnd, SW_SHOWNORMAL); SetForegroundWindow(fe->hwnd); midend_redraw(fe->me); @@ -1278,6 +1620,36 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) return fe; } +#ifdef _WIN32_WCE +static HFONT dialog_title_font() +{ + static HFONT hf = NULL; + LOGFONT lf; + + if (hf) + return hf; + + memset (&lf, 0, sizeof(LOGFONT)); + lf.lfHeight = -11; /* - ((8 * GetDeviceCaps(hdc, LOGPIXELSY)) / 72) */ + lf.lfWeight = FW_BOLD; + wcscpy(lf.lfFaceName, TEXT("Tahoma")); + + return hf = CreateFontIndirect(&lf); +} + +static void make_dialog_full_screen(HWND hwnd) +{ + SHINITDLGINFO shidi; + + /* Make dialog full screen */ + shidi.dwMask = SHIDIM_FLAGS; + shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN | + SHIDIF_EMPTYMENU; + shidi.hDlg = hwnd; + SHInitDialog(&shidi); +} +#endif + static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -1285,17 +1657,39 @@ static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg, switch (msg) { case WM_INITDIALOG: - return 0; +#ifdef _WIN32_WCE + { + char title[256]; + + make_dialog_full_screen(hwnd); + + sprintf(title, "About %.250s", thegame.name); + SetDlgItemTextA(hwnd, IDC_ABOUT_CAPTION, title); + + SendDlgItemMessage(hwnd, IDC_ABOUT_CAPTION, WM_SETFONT, + (WPARAM) dialog_title_font(), 0); + + SetDlgItemTextA(hwnd, IDC_ABOUT_GAME, thegame.name); + SetDlgItemTextA(hwnd, IDC_ABOUT_VERSION, ver); + } +#endif + return TRUE; case WM_COMMAND: - if ((HIWORD(wParam) == BN_CLICKED || - HIWORD(wParam) == BN_DOUBLECLICKED) && - LOWORD(wParam) == IDOK) + if (LOWORD(wParam) == IDOK) +#ifdef _WIN32_WCE + EndDialog(hwnd, 1); +#else fe->dlg_done = 1; +#endif return 0; case WM_CLOSE: +#ifdef _WIN32_WCE + EndDialog(hwnd, 1); +#else fe->dlg_done = 1; +#endif return 0; } @@ -1402,6 +1796,117 @@ static char *frontend_set_config(frontend *fe, int which, config_item *cfg) } } +#ifdef _WIN32_WCE +/* Separate version of mkctrl function for the Pocket PC. */ +/* Control coordinates should be specified in dialog units. */ +HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, + LPCTSTR wclass, int wstyle, + int exstyle, const char *wtext, int wid) +{ + RECT rc; + TCHAR wwtext[256]; + + /* Convert dialog units into pixels */ + rc.left = x1; rc.right = x2; + rc.top = y1; rc.bottom = y2; + MapDialogRect(fe->cfgbox, &rc); + + MultiByteToWideChar (CP_ACP, 0, wtext, -1, wwtext, 256); + + return CreateWindowEx(exstyle, wclass, wwtext, + wstyle | WS_CHILD | WS_VISIBLE, + rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top, + fe->cfgbox, (HMENU) wid, fe->inst, NULL); +} + +static void create_config_controls(frontend * fe) +{ + int id, nctrls; + int col1l, col1r, col2l, col2r, y; + config_item *i; + struct cfg_aux *j; + HWND ctl; + + /* Control placement done in dialog units */ + col1l = 4; col1r = 96; /* Label column */ + col2l = 100; col2r = 154; /* Input column (edit boxes and combo boxes) */ + + /* + * Count the controls so we can allocate cfgaux. + */ + for (nctrls = 0, i = fe->cfg; i->type != C_END; i++) + nctrls++; + fe->cfgaux = snewn(nctrls, struct cfg_aux); + + id = 1000; + y = 22; /* Leave some room for the dialog title */ + for (i = fe->cfg, j = fe->cfgaux; i->type != C_END; i++, j++) { + switch (i->type) { + case C_STRING: + /* + * Edit box with a label beside it. + */ + mkctrl(fe, col1l, col1r, y + 1, y + 11, + TEXT("Static"), SS_LEFTNOWORDWRAP, 0, i->name, id++); + mkctrl(fe, col2l, col2r, y, y + 12, + TEXT("EDIT"), WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL, + 0, "", (j->ctlid = id++)); + SetDlgItemTextA(fe->cfgbox, j->ctlid, i->sval); + break; + + case C_BOOLEAN: + /* + * Simple checkbox. + */ + mkctrl(fe, col1l, col2r, y + 1, y + 11, TEXT("BUTTON"), + BS_NOTIFY | BS_AUTOCHECKBOX | WS_TABSTOP, + 0, i->name, (j->ctlid = id++)); + CheckDlgButton(fe->cfgbox, j->ctlid, (i->ival != 0)); + break; + + case C_CHOICES: + /* + * Drop-down list with a label beside it. + */ + mkctrl(fe, col1l, col1r, y + 1, y + 11, + TEXT("STATIC"), SS_LEFTNOWORDWRAP, 0, i->name, id++); + ctl = mkctrl(fe, col2l, col2r, y, y + 48, + TEXT("COMBOBOX"), WS_BORDER | WS_TABSTOP | + CBS_DROPDOWNLIST | CBS_HASSTRINGS, + 0, "", (j->ctlid = id++)); + { + char c, *p, *q, *str; + + p = i->sval; + c = *p++; + while (*p) { + q = p; + while (*q && *q != c) q++; + str = snewn(q-p+1, char); + strncpy(str, p, q-p); + str[q-p] = '\0'; + { + TCHAR ws[50]; + MultiByteToWideChar (CP_ACP, 0, str, -1, ws, 50); + SendMessage(ctl, CB_ADDSTRING, 0, (LPARAM)ws); + } + + sfree(str); + if (*q) q++; + p = q; + } + } + SendMessage(ctl, CB_SETCURSEL, i->ival, 0); + break; + } + + y += 15; + } + +} +#endif + static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -1411,15 +1916,32 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, switch (msg) { case WM_INITDIALOG: - return 0; +#ifdef _WIN32_WCE + { + char *title; + + fe = (frontend *) lParam; + SetWindowLong(hwnd, GWL_USERDATA, lParam); + fe->cfgbox = hwnd; + + fe->cfg = frontend_get_config(fe, fe->cfg_which, &title); + + make_dialog_full_screen(hwnd); + + SetDlgItemTextA(hwnd, IDC_CONFIG_CAPTION, title); + SendDlgItemMessage(hwnd, IDC_CONFIG_CAPTION, WM_SETFONT, + (WPARAM) dialog_title_font(), 0); + + create_config_controls(fe); + } +#endif + return TRUE; case WM_COMMAND: /* * OK and Cancel are special cases. */ - if ((HIWORD(wParam) == BN_CLICKED || - HIWORD(wParam) == BN_DOUBLECLICKED) && - (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) { + if ((LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) { if (LOWORD(wParam) == IDOK) { char *err = frontend_set_config(fe, fe->cfg_which, fe->cfg); @@ -1427,10 +1949,18 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, MessageBox(hwnd, err, "Validation error", MB_ICONERROR | MB_OK); } else { +#ifdef _WIN32_WCE + EndDialog(hwnd, 2); +#else fe->dlg_done = 2; +#endif } } else { +#ifdef _WIN32_WCE + EndDialog(hwnd, 1); +#else fe->dlg_done = 1; +#endif } return 0; } @@ -1447,13 +1977,19 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, if (i->type == C_STRING && HIWORD(wParam) == EN_CHANGE) { char buffer[4096]; +#ifdef _WIN32_WCE + TCHAR wBuffer[4096]; + GetDlgItemText(fe->cfgbox, j->ctlid, wBuffer, 4096); + WideCharToMultiByte(CP_ACP, 0, wBuffer, -1, buffer, 4096, NULL, NULL); +#else GetDlgItemText(fe->cfgbox, j->ctlid, buffer, lenof(buffer)); +#endif buffer[lenof(buffer)-1] = '\0'; sfree(i->sval); i->sval = dupstr(buffer); } else if (i->type == C_BOOLEAN && (HIWORD(wParam) == BN_CLICKED || - HIWORD(wParam) == BN_DOUBLECLICKED)) { + HIWORD(wParam) == BN_DBLCLK)) { i->ival = IsDlgButtonChecked(fe->cfgbox, j->ctlid); } else if (i->type == C_CHOICES && HIWORD(wParam) == CBN_SELCHANGE) { @@ -1471,6 +2007,7 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, return 0; } +#ifndef _WIN32_WCE HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, char *wclass, int wstyle, int exstyle, const char *wtext, int wid) @@ -1482,9 +2019,13 @@ HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, SendMessage(ret, WM_SETFONT, (WPARAM)fe->cfgfont, MAKELPARAM(TRUE, 0)); return ret; } +#endif static void about(frontend *fe) { +#ifdef _WIN32_WCE + DialogBox(fe->inst, MAKEINTRESOURCE(IDD_ABOUT), fe->hwnd, AboutDlgProc); +#else int i; WNDCLASS wc; MSG msg; @@ -1506,7 +2047,7 @@ static void about(frontend *fe) strings[nstrings++] = "from Simon Tatham's Portable Puzzle Collection"; strings[nstrings++] = ver; - wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW; + wc.style = CS_DBLCLKS | CS_SAVEBITS; wc.lpfnWndProc = DefDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = DLGWINDOWEXTRA + 8; @@ -1622,7 +2163,7 @@ static void about(frontend *fe) SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0); EnableWindow(fe->hwnd, FALSE); - ShowWindow(fe->cfgbox, SW_NORMAL); + ShowWindow(fe->cfgbox, SW_SHOWNORMAL); while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { if (!IsDialogMessage(fe->cfgbox, &msg)) DispatchMessage(&msg); @@ -1633,10 +2174,19 @@ static void about(frontend *fe) SetForegroundWindow(fe->hwnd); DestroyWindow(fe->cfgbox); DeleteObject(fe->cfgfont); +#endif } static int get_config(frontend *fe, int which) { +#ifdef _WIN32_WCE + fe->cfg_which = which; + + return DialogBoxParam(fe->inst, + MAKEINTRESOURCE(IDD_CONFIG), + fe->hwnd, ConfigDlgProc, + (LPARAM) fe) == 2; +#else config_item *i; struct cfg_aux *j; char *title; @@ -1651,7 +2201,7 @@ static int get_config(frontend *fe, int which) int winwidth, winheight, col1l, col1r, col2l, col2r, y; int height, width, maxlabel, maxcheckbox; - wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW; + wc.style = CS_DBLCLKS | CS_SAVEBITS; wc.lpfnWndProc = DefDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = DLGWINDOWEXTRA + 8; @@ -1858,7 +2408,7 @@ static int get_config(frontend *fe, int which) SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0); EnableWindow(fe->hwnd, FALSE); - ShowWindow(fe->cfgbox, SW_NORMAL); + ShowWindow(fe->cfgbox, SW_SHOWNORMAL); while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { if (!IsDialogMessage(fe->cfgbox, &msg)) DispatchMessage(&msg); @@ -1874,8 +2424,48 @@ static int get_config(frontend *fe, int which) sfree(fe->cfgaux); return (fe->dlg_done == 2); +#endif } +#ifdef _WIN32_WCE +static void calculate_bitmap_position(frontend *fe, int x, int y) +{ + /* Pocket PC - center the game in the full screen window */ + int yMargin; + RECT rcClient; + + GetClientRect(fe->hwnd, &rcClient); + fe->bitmapPosition.left = (rcClient.right - x) / 2; + yMargin = rcClient.bottom - y; + + if (fe->numpad != NULL) { + RECT rcPad; + GetWindowRect(fe->numpad, &rcPad); + yMargin -= rcPad.bottom - rcPad.top; + } + + if (fe->statusbar != NULL) { + RECT rcStatus; + GetWindowRect(fe->statusbar, &rcStatus); + yMargin -= rcStatus.bottom - rcStatus.top; + } + + fe->bitmapPosition.top = yMargin / 2; + + fe->bitmapPosition.right = fe->bitmapPosition.left + x; + fe->bitmapPosition.bottom = fe->bitmapPosition.top + y; +} +#else +static void calculate_bitmap_position(frontend *fe, int x, int y) +{ + /* Plain Windows - position the game in the upper-left corner */ + fe->bitmapPosition.left = 0; + fe->bitmapPosition.top = 0; + fe->bitmapPosition.right = fe->bitmapPosition.left + x; + fe->bitmapPosition.bottom = fe->bitmapPosition.top + y; +} +#endif + static void new_game_size(frontend *fe) { RECT r, sr; @@ -1895,23 +2485,31 @@ static void new_game_size(frontend *fe) } else { sr.left = sr.right = sr.top = sr.bottom = 0; } +#ifndef _WIN32_WCE SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top + sr.bottom - sr.top, SWP_NOMOVE | SWP_NOZORDER); +#endif check_window_size(fe, &x, &y); +#ifndef _WIN32_WCE if (fe->statusbar != NULL) SetWindowPos(fe->statusbar, NULL, 0, y, x, sr.bottom - sr.top, SWP_NOZORDER); +#endif - DeleteObject(fe->bitmap); + 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); +#ifdef _WIN32_WCE + InvalidateRect(fe->hwnd, NULL, TRUE); +#endif midend_redraw(fe->me); } @@ -1960,6 +2558,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, DestroyWindow(hwnd); return 0; case WM_COMMAND: +#ifdef _WIN32_WCE + /* Numeric pad sends WM_COMMAND messages */ + if ((wParam >= IDM_KEYEMUL) && (wParam < IDM_KEYEMUL + 256)) + { + midend_process_key(fe->me, 0, 0, wParam - IDM_KEYEMUL); + } +#endif cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */ switch (cmd) { case IDM_NEW: @@ -2104,21 +2709,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; +#ifndef _WIN32_WCE 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; +#endif default: { int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10; @@ -2132,6 +2730,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case WM_DESTROY: +#ifndef _WIN32_WCE + stop_help(fe); +#endif PostQuitMessage(0); return 0; case WM_PAINT: @@ -2139,16 +2740,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, PAINTSTRUCT p; HDC hdc, hdc2; HBITMAP prevbm; + RECT rcDest; hdc = BeginPaint(hwnd, &p); hdc2 = CreateCompatibleDC(hdc); prevbm = SelectObject(hdc2, fe->bitmap); +#ifdef _WIN32_WCE + FillRect(hdc, &(p.rcPaint), (HBRUSH) GetStockObject(WHITE_BRUSH)); +#endif + IntersectRect(&rcDest, &(fe->bitmapPosition), &(p.rcPaint)); BitBlt(hdc, - p.rcPaint.left, p.rcPaint.top, - p.rcPaint.right - p.rcPaint.left, - p.rcPaint.bottom - p.rcPaint.top, + rcDest.left, rcDest.top, + rcDest.right - rcDest.left, + rcDest.bottom - rcDest.top, hdc2, - p.rcPaint.left, p.rcPaint.top, + rcDest.left - fe->bitmapPosition.left, + rcDest.top - fe->bitmapPosition.top, SRCCOPY); SelectObject(hdc2, prevbm); DeleteDC(hdc2); @@ -2253,10 +2860,32 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, else if (message == WM_RBUTTONDOWN || is_alt_pressed()) button = RIGHT_BUTTON; else +#ifndef _WIN32_WCE button = LEFT_BUTTON; +#else + if ((thegame.flags & REQUIRE_RBUTTON) == 0) + button = LEFT_BUTTON; + else + { + SHRGINFO shrgi; + + shrgi.cbSize = sizeof(SHRGINFO); + shrgi.hwndClient = hwnd; + shrgi.ptDown.x = (signed short)LOWORD(lParam); + shrgi.ptDown.y = (signed short)HIWORD(lParam); + shrgi.dwFlags = SHRG_RETURNCMD; + + if (GN_CONTEXTMENU == SHRecognizeGesture(&shrgi)) + button = RIGHT_BUTTON; + else + button = LEFT_BUTTON; + } +#endif - if (!midend_process_key(fe->me, (signed short)LOWORD(lParam), - (signed short)HIWORD(lParam), button)) + if (!midend_process_key(fe->me, + (signed short)LOWORD(lParam) - fe->bitmapPosition.left, + (signed short)HIWORD(lParam) - fe->bitmapPosition.top, + button)) PostQuitMessage(0); SetCapture(hwnd); @@ -2280,8 +2909,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, else button = LEFT_RELEASE; - if (!midend_process_key(fe->me, (signed short)LOWORD(lParam), - (signed short)HIWORD(lParam), button)) + if (!midend_process_key(fe->me, + (signed short)LOWORD(lParam) - fe->bitmapPosition.left, + (signed short)HIWORD(lParam) - fe->bitmapPosition.top, + button)) PostQuitMessage(0); ReleaseCapture(); @@ -2298,8 +2929,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, else button = LEFT_DRAG; - if (!midend_process_key(fe->me, (signed short)LOWORD(lParam), - (signed short)HIWORD(lParam), button)) + if (!midend_process_key(fe->me, + (signed short)LOWORD(lParam) - fe->bitmapPosition.left, + (signed short)HIWORD(lParam) - fe->bitmapPosition.top, + button)) PostQuitMessage(0); } break; @@ -2320,11 +2953,34 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, return DefWindowProc(hwnd, message, wParam, lParam); } +#ifdef _WIN32_WCE +static int FindPreviousInstance() +{ + /* Check if application is running. If it's running then focus on the window */ + HWND hOtherWnd = NULL; + + hOtherWnd = FindWindow (wGameName, wGameName); + if (hOtherWnd) + { + SetForegroundWindow (hOtherWnd); + return TRUE; + } + + return FALSE; +} +#endif + int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { MSG msg; char *error; +#ifdef _WIN32_WCE + MultiByteToWideChar (CP_ACP, 0, thegame.name, -1, wGameName, 256); + if (FindPreviousInstance ()) + return 0; +#endif + InitCommonControls(); if (!prev) { @@ -2335,11 +2991,19 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = inst; - wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION); + wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200)); +#ifndef _WIN32_WCE + if (!wndclass.hIcon) /* in case resource file is absent */ + wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION); +#endif wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; +#ifdef _WIN32_WCE + wndclass.lpszClassName = wGameName; +#else wndclass.lpszClassName = thegame.name; +#endif RegisterClass(&wndclass); } @@ -2347,6 +3011,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) 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); @@ -2358,5 +3024,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) DispatchMessage(&msg); } + cleanup_help(); + return msg.wParam; }