~ubuntu-branches/ubuntu/saucy/sgt-puzzles/saucy

« back to all changes in this revision

Viewing changes to windows.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings
  • Date: 2008-04-13 17:39:38 UTC
  • mto: (1.1.6 upstream) (3.1.2 lenny)
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20080413173938-nnrvlls98m6ky6eq
ImportĀ upstreamĀ versionĀ 7983

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
 
5
5
#include <windows.h>
6
6
#include <commctrl.h>
 
7
#ifndef NO_HTMLHELP
 
8
#include <htmlhelp.h>
 
9
#endif /* NO_HTMLHELP */
 
10
 
 
11
#ifdef _WIN32_WCE
 
12
#include <commdlg.h>
 
13
#include <aygshell.h>
 
14
#endif
7
15
 
8
16
#include <stdio.h>
9
17
#include <assert.h>
15
23
 
16
24
#include "puzzles.h"
17
25
 
 
26
#ifdef _WIN32_WCE
 
27
#include "resource.h"
 
28
#endif
 
29
 
18
30
#define IDM_NEW       0x0010
19
31
#define IDM_RESTART   0x0020
20
32
#define IDM_UNDO      0x0030
33
45
#define IDM_PRINT     0x0100
34
46
#define IDM_PRESETS   0x0110
35
47
 
 
48
#define IDM_KEYEMUL   0x0400
 
49
 
36
50
#define HELP_FILE_NAME  "puzzles.hlp"
37
51
#define HELP_CNT_NAME   "puzzles.cnt"
 
52
#ifndef NO_HTMLHELP
 
53
#define CHM_FILE_NAME   "puzzles.chm"
 
54
#endif /* NO_HTMLHELP */
 
55
 
 
56
#ifndef NO_HTMLHELP
 
57
typedef HWND (CALLBACK *htmlhelp_t)(HWND, LPCSTR, UINT, DWORD);
 
58
static htmlhelp_t htmlhelp;
 
59
static HINSTANCE hh_dll;
 
60
#endif /* NO_HTMLHELP */
 
61
enum { NONE, HLP, CHM } help_type;
 
62
char *help_path;
 
63
const char *help_topic;
 
64
int help_has_contents;
 
65
 
 
66
#ifndef FILENAME_MAX
 
67
#define FILENAME_MAX    (260)
 
68
#endif
 
69
 
 
70
#ifndef HGDI_ERROR
 
71
#define HGDI_ERROR ((HANDLE)GDI_ERROR)
 
72
#endif
 
73
 
 
74
#ifdef _WIN32_WCE
 
75
 
 
76
/*
 
77
 * Wrapper implementations of functions not supplied by the
 
78
 * PocketPC API.
 
79
 */
 
80
 
 
81
#define SHGetSubMenu(hWndMB,ID_MENU) (HMENU)SendMessage((hWndMB), SHCMBM_GETSUBMENU, (WPARAM)0, (LPARAM)ID_MENU)
 
82
 
 
83
#undef MessageBox
 
84
 
 
85
int MessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
 
86
{
 
87
    TCHAR wText[2048];
 
88
    TCHAR wCaption[2048];
 
89
 
 
90
    MultiByteToWideChar (CP_ACP, 0, lpText,    -1, wText,    2048);
 
91
    MultiByteToWideChar (CP_ACP, 0, lpCaption, -1, wCaption, 2048);
 
92
 
 
93
    return MessageBoxW (hWnd, wText, wCaption, uType);
 
94
}
 
95
 
 
96
BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPCSTR lpString)
 
97
{
 
98
    TCHAR wText[256];
 
99
 
 
100
    MultiByteToWideChar (CP_ACP, 0, lpString, -1, wText, 256);
 
101
    return SetDlgItemTextW(hDlg, nIDDlgItem, wText);
 
102
}
 
103
 
 
104
LPCSTR getenv(LPCSTR buf)
 
105
{
 
106
    return NULL;
 
107
}
 
108
 
 
109
BOOL GetKeyboardState(PBYTE pb)
 
110
{
 
111
  return FALSE;
 
112
}
 
113
 
 
114
static TCHAR wGameName[256];
 
115
 
 
116
#endif
38
117
 
39
118
#ifdef DEBUGGING
40
119
static FILE *debug_fp = NULL;
60
139
    }
61
140
    fputs(buf, debug_fp);
62
141
    fflush(debug_fp);
 
142
    OutputDebugString(buf);
63
143
}
64
144
 
65
145
void debug_printf(char *fmt, ...)
68
148
    va_list ap;
69
149
 
70
150
    va_start(ap, fmt);
71
 
    vsprintf(buf, fmt, ap);
 
151
    _vsnprintf(buf, 4095, fmt, ap);
72
152
    dputs(buf);
73
153
    va_end(ap);
74
154
}
75
155
#endif
76
156
 
 
157
#ifndef _WIN32_WCE
77
158
#define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \
78
 
                      (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED))
 
159
                      (WS_MAXIMIZEBOX | WS_OVERLAPPED))
 
160
#else
 
161
#define WINFLAGS (WS_CAPTION | WS_SYSMENU)
 
162
#endif
79
163
 
80
164
static void new_game_size(frontend *fe);
81
165
 
100
184
struct frontend {
101
185
    midend *me;
102
186
    HWND hwnd, statusbar, cfgbox;
 
187
#ifdef _WIN32_WCE
 
188
    HWND numpad;  /* window handle for the numeric pad */
 
189
#endif
103
190
    HINSTANCE inst;
104
191
    HBITMAP bitmap, prevbm;
 
192
    RECT bitmapPosition;  /* game bitmap position within game window */
105
193
    HDC hdc;
106
194
    COLORREF *colours;
107
195
    HBRUSH *brushes;
108
196
    HPEN *pens;
109
197
    HRGN clip;
 
198
    HMENU typemenu;
110
199
    UINT timer;
111
200
    DWORD timer_last_tickcount;
112
201
    int npresets;
119
208
    HFONT cfgfont;
120
209
    HBRUSH oldbr;
121
210
    HPEN oldpen;
122
 
    char *help_path;
123
 
    int help_has_contents;
 
211
    int help_running;
124
212
    enum { DRAWING, PRINTING, NOTHING } drawstatus;
125
213
    DOCINFO di;
126
214
    int printcount, printw, printh, printsolns, printcurr, printcolour;
130
218
    int fontstart;
131
219
    int linewidth;
132
220
    drawing *dr;
 
221
    int xmin, ymin;
133
222
};
134
223
 
 
224
static void update_type_menu_tick(frontend *fe);
 
225
 
135
226
void fatal(char *fmt, ...)
136
227
{
137
228
    char buf[2048];
170
261
 
171
262
void get_random_seed(void **randseed, int *randseedsize)
172
263
{
173
 
    time_t *tp = snew(time_t);
174
 
    time(tp);
175
 
    *randseed = (void *)tp;
176
 
    *randseedsize = sizeof(time_t);
 
264
    SYSTEMTIME *st = snew(SYSTEMTIME);
 
265
 
 
266
    GetLocalTime(st);
 
267
 
 
268
    *randseed = (void *)st;
 
269
    *randseedsize = sizeof(SYSTEMTIME);
177
270
}
178
271
 
179
272
static void win_status_bar(void *handle, char *text)
180
273
{
 
274
#ifdef _WIN32_WCE
 
275
    TCHAR wText[255];
 
276
#endif
181
277
    frontend *fe = (frontend *)handle;
182
278
 
 
279
#ifdef _WIN32_WCE
 
280
    MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 255);
 
281
    SendMessage(fe->statusbar, SB_SETTEXT,
 
282
                (WPARAM) 255 | SBT_NOBORDERS,
 
283
                (LPARAM) wText);
 
284
#else
183
285
    SetWindowText(fe->statusbar, text);
 
286
#endif
184
287
}
185
288
 
186
289
static blitter *win_blitter_new(void *handle, int w, int h)
298
401
    if (fe->drawstatus == PRINTING) {
299
402
        int hatch;
300
403
        float r, g, b;
301
 
        print_get_colour(fe->dr, colour, &hatch, &r, &g, &b);
302
 
        if (fe->printcolour)
303
 
            SetTextColor(fe->hdc, RGB(r * 255, g * 255, b * 255));
304
 
        else
305
 
            SetTextColor(fe->hdc,
306
 
                         hatch == HATCH_CLEAR ? RGB(255,255,255) : RGB(0,0,0));
 
404
        print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b);
 
405
 
 
406
        /*
 
407
         * Displaying text in hatched colours is not permitted.
 
408
         */
 
409
        assert(hatch < 0);
 
410
 
 
411
        SetTextColor(fe->hdc, RGB(r * 255, g * 255, b * 255));
307
412
    } else {
308
413
        SetTextColor(fe->hdc, fe->colours[colour]);
309
414
    }
317
422
    if (fe->drawstatus == PRINTING) {
318
423
        int hatch;
319
424
        float r, g, b;
320
 
        print_get_colour(fe->dr, colour, &hatch, &r, &g, &b);
 
425
        print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b);
321
426
 
322
 
        if (fe->printcolour)
 
427
        if (hatch < 0) {
323
428
            br = CreateSolidBrush(RGB(r * 255, g * 255, b * 255));
324
 
        else if (hatch == HATCH_SOLID)
325
 
            br = CreateSolidBrush(RGB(0,0,0));
326
 
        else if (hatch == HATCH_CLEAR)
327
 
            br = CreateSolidBrush(RGB(255,255,255));
328
 
        else
 
429
        } else {
 
430
#ifdef _WIN32_WCE
 
431
            /*
 
432
             * This is only ever required during printing, and the
 
433
             * PocketPC port doesn't support printing.
 
434
             */
 
435
            fatal("CreateHatchBrush not supported");
 
436
#else
329
437
            br = CreateHatchBrush(hatch == HATCH_BACKSLASH ? HS_FDIAGONAL :
330
438
                                  hatch == HATCH_SLASH ? HS_BDIAGONAL :
331
439
                                  hatch == HATCH_HORIZ ? HS_HORIZONTAL :
333
441
                                  hatch == HATCH_PLUS ? HS_CROSS :
334
442
                                  /* hatch == HATCH_X ? */ HS_DIAGCROSS,
335
443
                                  RGB(0,0,0));
 
444
#endif
 
445
        }
336
446
    } else {
337
447
        br = fe->brushes[colour];
338
448
    }
360
470
        float r, g, b;
361
471
        int width = thin ? 0 : fe->linewidth;
362
472
 
363
 
        print_get_colour(fe->dr, colour, &hatch, &r, &g, &b);
364
 
        if (fe->printcolour)
365
 
            pen = CreatePen(PS_SOLID, width,
366
 
                            RGB(r * 255, g * 255, b * 255));
367
 
        else if (hatch == HATCH_SOLID)
368
 
            pen = CreatePen(PS_SOLID, width, RGB(0, 0, 0));
369
 
        else if (hatch == HATCH_CLEAR)
370
 
            pen = CreatePen(PS_SOLID, width, RGB(255,255,255));
371
 
        else {
372
 
            assert(!"This shouldn't happen");
373
 
            pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
374
 
        }
 
473
        print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b);
 
474
        /*
 
475
         * Stroking in hatched colours is not permitted.
 
476
         */
 
477
        assert(hatch < 0);
 
478
        pen = CreatePen(PS_SOLID, width, RGB(r * 255, g * 255, b * 255));
375
479
    } else {
376
480
        pen = fe->pens[colour];
377
481
    }
418
522
    frontend *fe = (frontend *)handle;
419
523
    POINT xy;
420
524
    int i;
 
525
    LOGFONT lf;
421
526
 
422
527
    if (fe->drawstatus == NOTHING)
423
528
        return;
445
550
        fe->fonts[i].type = fonttype;
446
551
        fe->fonts[i].size = fontsize;
447
552
 
448
 
        fe->fonts[i].font = CreateFont(-fontsize, 0, 0, 0,
449
 
                                       fe->drawstatus == PRINTING ? 0 : FW_BOLD,
450
 
                                       FALSE, FALSE, FALSE, DEFAULT_CHARSET,
451
 
                                       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
452
 
                                       DEFAULT_QUALITY,
453
 
                                       (fonttype == FONT_FIXED ?
454
 
                                        FIXED_PITCH | FF_DONTCARE :
455
 
                                        VARIABLE_PITCH | FF_SWISS),
456
 
                                       NULL);
 
553
        memset (&lf, 0, sizeof(LOGFONT));
 
554
        lf.lfHeight = -fontsize;
 
555
        lf.lfWeight = (fe->drawstatus == PRINTING ? 0 : FW_BOLD);
 
556
        lf.lfCharSet = DEFAULT_CHARSET;
 
557
        lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
 
558
        lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
 
559
        lf.lfQuality = DEFAULT_QUALITY;
 
560
        lf.lfPitchAndFamily = (fonttype == FONT_FIXED ?
 
561
                               FIXED_PITCH | FF_DONTCARE :
 
562
                               VARIABLE_PITCH | FF_SWISS);
 
563
#ifdef _WIN32_WCE
 
564
        wcscpy(lf.lfFaceName, TEXT("Tahoma"));
 
565
#endif
 
566
 
 
567
        fe->fonts[i].font = CreateFontIndirect(&lf);
457
568
    }
458
569
 
459
570
    /*
463
574
        HFONT oldfont;
464
575
        TEXTMETRIC tm;
465
576
        SIZE size;
 
577
#ifdef _WIN32_WCE
 
578
        TCHAR wText[256];
 
579
        MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 256);
 
580
#endif
466
581
 
467
582
        oldfont = SelectObject(fe->hdc, fe->fonts[i].font);
468
583
        if (GetTextMetrics(fe->hdc, &tm)) {
471
586
            else
472
587
                xy.y -= tm.tmAscent;
473
588
        }
474
 
        if (GetTextExtentPoint32(fe->hdc, text, strlen(text), &size)) {
 
589
#ifndef _WIN32_WCE
 
590
        if (GetTextExtentPoint32(fe->hdc, text, strlen(text), &size))
 
591
#else
 
592
        if (GetTextExtentPoint32(fe->hdc, wText, wcslen(wText), &size))
 
593
#endif
 
594
        {
475
595
            if (align & ALIGN_HCENTRE)
476
596
                xy.x -= size.cx / 2;
477
597
            else if (align & ALIGN_HRIGHT)
479
599
        }
480
600
        SetBkMode(fe->hdc, TRANSPARENT);
481
601
        win_text_colour(fe, colour);
 
602
#ifndef _WIN32_WCE
482
603
        TextOut(fe->hdc, xy.x, xy.y, text, strlen(text));
 
604
#else
 
605
        ExtTextOut(fe->hdc, xy.x, xy.y, 0, NULL, wText, wcslen(wText), NULL);
 
606
#endif
483
607
        SelectObject(fe->hdc, oldfont);
484
608
    }
485
609
}
514
638
static void win_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour)
515
639
{
516
640
    frontend *fe = (frontend *)handle;
517
 
    POINT p, q;
 
641
    POINT pp[2];
518
642
 
519
643
    if (fe->drawstatus == NOTHING)
520
644
        return;
521
645
 
522
646
    win_set_pen(fe, colour, FALSE);
523
 
    p = win_transform_point(fe, x1, y1);
524
 
    q = win_transform_point(fe, x2, y2);
525
 
    MoveToEx(fe->hdc, p.x, p.y, NULL);
526
 
    LineTo(fe->hdc, q.x, q.y);
 
647
    pp[0] = win_transform_point(fe, x1, y1);
 
648
    pp[1] = win_transform_point(fe, x2, y2);
 
649
    Polyline(fe->hdc, pp, 2);
527
650
    if (fe->drawstatus == DRAWING)
528
 
        SetPixel(fe->hdc, q.x, q.y, fe->colours[colour]);
 
651
        SetPixel(fe->hdc, pp[1].x, pp[1].y, fe->colours[colour]);
529
652
    win_reset_pen(fe);
530
653
}
531
654
 
533
656
                            int fillcolour, int outlinecolour)
534
657
{
535
658
    frontend *fe = (frontend *)handle;
536
 
    POINT p, q, r;
 
659
    POINT p, q;
537
660
 
538
661
    assert(outlinecolour >= 0);
539
662
 
540
663
    if (fe->drawstatus == NOTHING)
541
664
        return;
542
665
 
543
 
    if (fillcolour >= 0) {
 
666
    if (fillcolour >= 0)
544
667
        win_set_brush(fe, fillcolour);
545
 
        win_set_pen(fe, outlinecolour, FALSE);
546
 
        p = win_transform_point(fe, cx - radius, cy - radius);
547
 
        q = win_transform_point(fe, cx + radius, cy + radius);
548
 
        Ellipse(fe->hdc, p.x, p.y, q.x+1, q.y+1);
549
 
        win_reset_brush(fe);
550
 
        win_reset_pen(fe);
551
 
    } else {
552
 
        win_set_pen(fe, outlinecolour, FALSE);
553
 
        p = win_transform_point(fe, cx - radius, cy - radius);
554
 
        q = win_transform_point(fe, cx + radius, cy + radius);
555
 
        r = win_transform_point(fe, cx - radius, cy);
556
 
        Arc(fe->hdc, p.x, p.y, q.x+1, q.y+1, r.x, r.y, r.x, r.y);
557
 
        win_reset_pen(fe);
558
 
    }
 
668
    else
 
669
        fe->oldbr = SelectObject(fe->hdc, GetStockObject(NULL_BRUSH));
 
670
 
 
671
    win_set_pen(fe, outlinecolour, FALSE);
 
672
    p = win_transform_point(fe, cx - radius, cy - radius);
 
673
    q = win_transform_point(fe, cx + radius, cy + radius);
 
674
    Ellipse(fe->hdc, p.x, p.y, q.x+1, q.y+1);
 
675
    win_reset_brush(fe);
 
676
    win_reset_pen(fe);
559
677
}
560
678
 
561
679
static void win_draw_polygon(void *handle, int *coords, int npoints,
604
722
    fe->prevbm = SelectObject(fe->hdc, fe->bitmap);
605
723
    ReleaseDC(fe->hwnd, hdc_win);
606
724
    fe->clip = NULL;
 
725
#ifndef _WIN32_WCE
607
726
    SetMapMode(fe->hdc, MM_TEXT);
 
727
#endif
608
728
    fe->drawstatus = DRAWING;
609
729
}
610
730
 
621
741
    r.right = x + w;
622
742
    r.bottom = y + h;
623
743
 
 
744
    OffsetRect(&r, fe->bitmapPosition.left, fe->bitmapPosition.top);
624
745
    InvalidateRect(fe->hwnd, &r, FALSE);
625
746
}
626
747
 
823
944
 
824
945
void print(frontend *fe)
825
946
{
 
947
#ifndef _WIN32_WCE
826
948
    PRINTDLG pd;
827
949
    char doctitle[256];
828
950
    document *doc;
913
1035
 
914
1036
    DeleteDC(pd.hDC);
915
1037
    document_free(doc);
 
1038
#endif
916
1039
}
917
1040
 
918
1041
void deactivate_timer(frontend *fe)
928
1051
    if (!fe)
929
1052
        return;                        /* for non-interactive midend */
930
1053
    if (!fe->timer) {
931
 
        fe->timer = SetTimer(fe->hwnd, fe->timer, 20, NULL);
 
1054
        fe->timer = SetTimer(fe->hwnd, 1, 20, NULL);
932
1055
        fe->timer_last_tickcount = GetTickCount();
933
1056
    }
934
1057
}
981
1104
}
982
1105
 
983
1106
/*
984
 
 * See if we can find a help file.
 
1107
 * Set up Help and see if we can find a help file.
985
1108
 */
986
 
static void find_help_file(frontend *fe)
 
1109
static void init_help(void)
987
1110
{
 
1111
#ifndef _WIN32_WCE
988
1112
    char b[2048], *p, *q, *r;
989
1113
    FILE *fp;
990
 
    if (!fe->help_path) {
991
 
        GetModuleFileName(NULL, b, sizeof(b) - 1);
992
 
        r = b;
993
 
        p = strrchr(b, '\\');
994
 
        if (p && p >= r) r = p+1;
995
 
        q = strrchr(b, ':');
996
 
        if (q && q >= r) r = q+1;
997
 
        strcpy(r, HELP_FILE_NAME);
998
 
        if ( (fp = fopen(b, "r")) != NULL) {
999
 
            fe->help_path = dupstr(b);
1000
 
            fclose(fp);
1001
 
        } else
1002
 
            fe->help_path = NULL;
1003
 
        strcpy(r, HELP_CNT_NAME);
1004
 
        if ( (fp = fopen(b, "r")) != NULL) {
1005
 
            fe->help_has_contents = TRUE;
1006
 
            fclose(fp);
1007
 
        } else
1008
 
            fe->help_has_contents = FALSE;
1009
 
    }
1010
 
}
1011
 
 
1012
 
static void check_window_size(frontend *fe, int *px, int *py)
1013
 
{
1014
 
    RECT r;
1015
 
    int x, y, sy;
1016
 
 
 
1114
 
 
1115
    /*
 
1116
     * Find the executable file path, so we can look alongside
 
1117
     * it for help files. Trim the filename off the end.
 
1118
     */
 
1119
    GetModuleFileName(NULL, b, sizeof(b) - 1);
 
1120
    r = b;
 
1121
    p = strrchr(b, '\\');
 
1122
    if (p && p >= r) r = p+1;
 
1123
    q = strrchr(b, ':');
 
1124
    if (q && q >= r) r = q+1;
 
1125
 
 
1126
#ifndef NO_HTMLHELP
 
1127
    /*
 
1128
     * Try HTML Help first.
 
1129
     */
 
1130
    strcpy(r, CHM_FILE_NAME);
 
1131
    if ( (fp = fopen(b, "r")) != NULL) {
 
1132
        fclose(fp);
 
1133
 
 
1134
        /*
 
1135
         * We have a .CHM. See if we can use it.
 
1136
         */
 
1137
        hh_dll = LoadLibrary("hhctrl.ocx");
 
1138
        if (hh_dll) {
 
1139
            htmlhelp = (htmlhelp_t)GetProcAddress(hh_dll, "HtmlHelpA");
 
1140
            if (!htmlhelp)
 
1141
                FreeLibrary(hh_dll);
 
1142
        }
 
1143
        if (htmlhelp) {
 
1144
            help_path = dupstr(b);
 
1145
            help_type = CHM;
 
1146
            help_topic = thegame.htmlhelp_topic;
 
1147
            return;
 
1148
        }
 
1149
    }
 
1150
#endif /* NO_HTMLHELP */
 
1151
 
 
1152
    /*
 
1153
     * Now try old-style .HLP.
 
1154
     */
 
1155
    strcpy(r, HELP_FILE_NAME);
 
1156
    if ( (fp = fopen(b, "r")) != NULL) {
 
1157
        fclose(fp);
 
1158
 
 
1159
        help_path = dupstr(b);
 
1160
        help_type = HLP;
 
1161
 
 
1162
        help_topic = thegame.winhelp_topic;
 
1163
 
 
1164
        /*
 
1165
         * See if there's a .CNT file alongside it.
 
1166
         */
 
1167
        strcpy(r, HELP_CNT_NAME);
 
1168
        if ( (fp = fopen(b, "r")) != NULL) {
 
1169
            fclose(fp);
 
1170
            help_has_contents = TRUE;
 
1171
        } else
 
1172
            help_has_contents = FALSE;
 
1173
 
 
1174
        return;
 
1175
    }
 
1176
 
 
1177
    help_type = NONE;          /* didn't find any */
 
1178
#endif
 
1179
}
 
1180
 
 
1181
#ifndef _WIN32_WCE
 
1182
 
 
1183
/*
 
1184
 * Start Help.
 
1185
 */
 
1186
static void start_help(frontend *fe, const char *topic)
 
1187
{
 
1188
    char *str = NULL;
 
1189
    int cmd;
 
1190
 
 
1191
    switch (help_type) {
 
1192
      case HLP:
 
1193
        assert(help_path);
 
1194
        if (topic) {
 
1195
            str = snewn(10+strlen(topic), char);
 
1196
            sprintf(str, "JI(`',`%s')", topic);
 
1197
            cmd = HELP_COMMAND;
 
1198
        } else if (help_has_contents) {
 
1199
            cmd = HELP_FINDER;
 
1200
        } else {
 
1201
            cmd = HELP_CONTENTS;
 
1202
        }
 
1203
        WinHelp(fe->hwnd, help_path, cmd, (DWORD)str);
 
1204
        fe->help_running = TRUE;
 
1205
        break;
 
1206
      case CHM:
 
1207
#ifndef NO_HTMLHELP
 
1208
        assert(help_path);
 
1209
        assert(htmlhelp);
 
1210
        if (topic) {
 
1211
            str = snewn(20 + strlen(topic) + strlen(help_path), char);
 
1212
            sprintf(str, "%s::/%s.html>main", help_path, topic);
 
1213
        } else {
 
1214
            str = dupstr(help_path);
 
1215
        }
 
1216
        htmlhelp(fe->hwnd, str, HH_DISPLAY_TOPIC, 0);
 
1217
        fe->help_running = TRUE;
 
1218
        break;
 
1219
#endif /* NO_HTMLHELP */
 
1220
      case NONE:
 
1221
        assert(!"This shouldn't happen");
 
1222
        break;
 
1223
    }
 
1224
 
 
1225
    sfree(str);
 
1226
}
 
1227
 
 
1228
/*
 
1229
 * Stop Help on window cleanup.
 
1230
 */
 
1231
static void stop_help(frontend *fe)
 
1232
{
 
1233
    if (fe->help_running) {
 
1234
        switch (help_type) {
 
1235
          case HLP:
 
1236
            WinHelp(fe->hwnd, help_path, HELP_QUIT, 0);
 
1237
            break;
 
1238
          case CHM:
 
1239
#ifndef NO_HTMLHELP
 
1240
            assert(htmlhelp);
 
1241
            htmlhelp(NULL, NULL, HH_CLOSE_ALL, 0);
 
1242
            break;
 
1243
#endif /* NO_HTMLHELP */
 
1244
          case NONE:
 
1245
            assert(!"This shouldn't happen");
 
1246
            break;
 
1247
        }
 
1248
        fe->help_running = FALSE;
 
1249
    }
 
1250
}
 
1251
 
 
1252
#endif
 
1253
 
 
1254
/*
 
1255
 * Terminate Help on process exit.
 
1256
 */
 
1257
static void cleanup_help(void)
 
1258
{
 
1259
    /* Nothing to do currently.
 
1260
     * (If we were running HTML Help single-threaded, this is where we'd
 
1261
     * call HH_UNINITIALIZE.) */
 
1262
}
 
1263
 
 
1264
static int get_statusbar_height(frontend *fe)
 
1265
{
 
1266
    int sy;
1017
1267
    if (fe->statusbar) {
1018
1268
        RECT sr;
1019
1269
        GetWindowRect(fe->statusbar, &sr);
1021
1271
    } else {
1022
1272
        sy = 0;
1023
1273
    }
 
1274
    return sy;
 
1275
}
 
1276
 
 
1277
static void adjust_statusbar(frontend *fe, RECT *r)
 
1278
{
 
1279
    int sy;
 
1280
 
 
1281
    if (!fe->statusbar) return;
 
1282
 
 
1283
    sy = get_statusbar_height(fe);
 
1284
#ifndef _WIN32_WCE
 
1285
    SetWindowPos(fe->statusbar, NULL, 0, r->bottom-r->top-sy, r->right-r->left,
 
1286
                 sy, SWP_NOZORDER);
 
1287
#endif
 
1288
}
 
1289
 
 
1290
static void get_menu_size(HWND wh, RECT *r)
 
1291
{
 
1292
    HMENU bar = GetMenu(wh);
 
1293
    RECT rect;
 
1294
    int i;
 
1295
 
 
1296
    SetRect(r, 0, 0, 0, 0);
 
1297
    for (i = 0; i < GetMenuItemCount(bar); i++) {
 
1298
        GetMenuItemRect(wh, bar, i, &rect);
 
1299
        UnionRect(r, r, &rect);
 
1300
    }
 
1301
}
 
1302
 
 
1303
/*
 
1304
 * Given a proposed new puzzle size (cx,cy), work out the actual
 
1305
 * puzzle size that would be (px,py) and the window size including
 
1306
 * furniture (wx,wy).
 
1307
 */
 
1308
 
 
1309
static int check_window_resize(frontend *fe, int cx, int cy,
 
1310
                               int *px, int *py,
 
1311
                               int *wx, int *wy, int resize)
 
1312
{
 
1313
    RECT r;
 
1314
    int x, y, sy = get_statusbar_height(fe), changed = 0;
 
1315
 
 
1316
    /* disallow making window thinner than menu bar */
 
1317
    x = max(cx, fe->xmin);
 
1318
    y = max(cy - sy, fe->ymin);
1024
1319
 
1025
1320
    /*
1026
1321
     * See if we actually got the window size we wanted, and adjust
1027
1322
     * the puzzle size if not.
1028
1323
     */
1029
 
    GetClientRect(fe->hwnd, &r);
1030
 
    x = r.right - r.left;
1031
 
    y = r.bottom - r.top - sy;
1032
 
    midend_size(fe->me, &x, &y, FALSE);
1033
 
    if (x != r.right - r.left || y != r.bottom - r.top) {
1034
 
        /*
1035
 
         * Resize the window, now we know what size we _really_
1036
 
         * want it to be.
1037
 
         */
1038
 
        r.left = r.top = 0;
1039
 
        r.right = x;
1040
 
        r.bottom = y + sy;
1041
 
        AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
1042
 
        SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top,
1043
 
                     SWP_NOMOVE | SWP_NOZORDER);
1044
 
    }
1045
 
 
1046
 
    if (fe->statusbar) {
1047
 
        GetClientRect(fe->hwnd, &r);
1048
 
        SetWindowPos(fe->statusbar, NULL, 0, r.bottom-r.top-sy, r.right-r.left,
1049
 
                     sy, SWP_NOZORDER);
 
1324
    midend_size(fe->me, &x, &y, resize);
 
1325
    if (x != cx || y != cy) {
 
1326
        /*
 
1327
         * Resize the window, now we know what size we _really_
 
1328
         * want it to be.
 
1329
         */
 
1330
        r.left = r.top = 0;
 
1331
        r.right = x;
 
1332
        r.bottom = y + sy;
 
1333
        AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
 
1334
        *wx = r.right - r.left;
 
1335
        *wy = r.bottom - r.top;
 
1336
        changed = 1;
1050
1337
    }
1051
1338
 
1052
1339
    *px = x;
1053
1340
    *py = y;
 
1341
 
 
1342
    return changed;
 
1343
}
 
1344
 
 
1345
/*
 
1346
 * Given the current window size, make sure it's sane for the
 
1347
 * current puzzle and resize if necessary.
 
1348
 */
 
1349
 
 
1350
static void check_window_size(frontend *fe, int *px, int *py)
 
1351
{
 
1352
    RECT r;
 
1353
    int wx, wy, cx, cy;
 
1354
 
 
1355
    GetClientRect(fe->hwnd, &r);
 
1356
    cx = r.right - r.left;
 
1357
    cy = r.bottom - r.top;
 
1358
 
 
1359
    if (check_window_resize(fe, cx, cy, px, py, &wx, &wy, FALSE)) {
 
1360
#ifdef _WIN32_WCE
 
1361
        SetWindowPos(fe->hwnd, NULL, 0, 0, wx, wy,
 
1362
                     SWP_NOMOVE | SWP_NOZORDER);
 
1363
#endif
 
1364
        ;
 
1365
    }
 
1366
 
 
1367
    GetClientRect(fe->hwnd, &r);
 
1368
    adjust_statusbar(fe, &r);
1054
1369
}
1055
1370
 
1056
1371
static void get_max_puzzle_size(frontend *fe, int *x, int *y)
1077
1392
    }
1078
1393
}
1079
1394
 
 
1395
#ifdef _WIN32_WCE
 
1396
/* Toolbar buttons on the numeric pad */
 
1397
static TBBUTTON tbNumpadButtons[] =
 
1398
{
 
1399
    {0, IDM_KEYEMUL + '1', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1400
    {1, IDM_KEYEMUL + '2', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1401
    {2, IDM_KEYEMUL + '3', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1402
    {3, IDM_KEYEMUL + '4', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1403
    {4, IDM_KEYEMUL + '5', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1404
    {5, IDM_KEYEMUL + '6', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1405
    {6, IDM_KEYEMUL + '7', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1406
    {7, IDM_KEYEMUL + '8', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1407
    {8, IDM_KEYEMUL + '9', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
 
1408
    {9, IDM_KEYEMUL + ' ', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1}
 
1409
};
 
1410
#endif
 
1411
 
1080
1412
static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
1081
1413
{
1082
1414
    frontend *fe;
1096
1428
        }
1097
1429
    }
1098
1430
 
1099
 
    fe->help_path = NULL;
1100
 
    find_help_file(fe);
1101
 
 
1102
1431
    fe->inst = inst;
1103
1432
 
1104
1433
    fe->timer = 0;
1105
1434
    fe->hwnd = NULL;
1106
1435
 
 
1436
    fe->help_running = FALSE;
 
1437
 
1107
1438
    fe->drawstatus = NOTHING;
1108
1439
    fe->dr = NULL;
1109
1440
    fe->fontstart = 0;
1134
1465
    }
1135
1466
 
1136
1467
    if (midend_wants_statusbar(fe->me)) {
1137
 
        fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
 
1468
        fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("ooh"),
1138
1469
                                       WS_CHILD | WS_VISIBLE,
1139
1470
                                       0, 0, 0, 0, /* status bar does these */
1140
1471
                                       NULL, NULL, inst, NULL);
1149
1480
    r.bottom = y;
1150
1481
    AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
1151
1482
 
 
1483
#ifdef _WIN32_WCE
 
1484
    fe->hwnd = CreateWindowEx(0, wGameName, wGameName,
 
1485
                              WS_VISIBLE,
 
1486
                              CW_USEDEFAULT, CW_USEDEFAULT,
 
1487
                              CW_USEDEFAULT, CW_USEDEFAULT,
 
1488
                              NULL, NULL, inst, NULL);
 
1489
 
 
1490
    {
 
1491
        SHMENUBARINFO mbi;
 
1492
        RECT rc, rcBar, rcTB, rcClient;
 
1493
 
 
1494
        memset (&mbi, 0, sizeof(SHMENUBARINFO));
 
1495
        mbi.cbSize     = sizeof(SHMENUBARINFO);
 
1496
        mbi.hwndParent = fe->hwnd;
 
1497
        mbi.nToolBarId = IDR_MENUBAR1;
 
1498
        mbi.hInstRes   = inst;
 
1499
 
 
1500
        SHCreateMenuBar(&mbi);
 
1501
 
 
1502
        GetWindowRect(fe->hwnd, &rc);
 
1503
        GetWindowRect(mbi.hwndMB, &rcBar);
 
1504
        rc.bottom -= rcBar.bottom - rcBar.top;
 
1505
        MoveWindow(fe->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
 
1506
 
 
1507
        if (thegame.flags & REQUIRE_NUMPAD)
 
1508
        {
 
1509
            fe->numpad = CreateToolbarEx (fe->hwnd,
 
1510
                                          WS_VISIBLE | WS_CHILD | CCS_NOPARENTALIGN | TBSTYLE_FLAT,
 
1511
                                          0, 10, inst, IDR_PADTOOLBAR,
 
1512
                                          tbNumpadButtons, sizeof (tbNumpadButtons) / sizeof (TBBUTTON),
 
1513
                                          0, 0, 14, 15, sizeof (TBBUTTON));
 
1514
            GetWindowRect(fe->numpad, &rcTB);
 
1515
            GetClientRect(fe->hwnd, &rcClient);
 
1516
            MoveWindow(fe->numpad, 
 
1517
                       0, 
 
1518
                       rcClient.bottom - (rcTB.bottom - rcTB.top) - 1,
 
1519
                       rcClient.right,
 
1520
                       rcTB.bottom - rcTB.top,
 
1521
                       FALSE);
 
1522
            SendMessage(fe->numpad, TB_SETINDENT, (rcClient.right - (10 * 21)) / 2, 0);
 
1523
        }
 
1524
        else
 
1525
            fe->numpad = NULL;
 
1526
    }
 
1527
#else
1152
1528
    fe->hwnd = CreateWindowEx(0, thegame.name, thegame.name,
1153
1529
                              WS_OVERLAPPEDWINDOW &~
1154
 
                              (WS_THICKFRAME | WS_MAXIMIZEBOX),
 
1530
                              (WS_MAXIMIZEBOX),
1155
1531
                              CW_USEDEFAULT, CW_USEDEFAULT,
1156
1532
                              r.right - r.left, r.bottom - r.top,
1157
1533
                              NULL, NULL, inst, NULL);
 
1534
#endif
1158
1535
 
1159
1536
    if (midend_wants_statusbar(fe->me)) {
1160
1537
        RECT sr;
1161
1538
        DestroyWindow(fe->statusbar);
1162
 
        fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
 
1539
        fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("ooh"),
1163
1540
                                       WS_CHILD | WS_VISIBLE,
1164
1541
                                       0, 0, 0, 0, /* status bar does these */
1165
1542
                                       fe->hwnd, NULL, inst, NULL);
 
1543
#ifdef _WIN32_WCE
 
1544
        /* Flat status bar looks better on the Pocket PC */
 
1545
        SendMessage(fe->statusbar, SB_SIMPLE, (WPARAM) TRUE, 0);
 
1546
        SendMessage(fe->statusbar, SB_SETTEXT,
 
1547
                                (WPARAM) 255 | SBT_NOBORDERS,
 
1548
                                (LPARAM) L"");
 
1549
#endif
 
1550
 
1166
1551
        /*
1167
1552
         * Now resize the window to take account of the status bar.
1168
1553
         */
1169
1554
        GetWindowRect(fe->statusbar, &sr);
1170
1555
        GetWindowRect(fe->hwnd, &r);
 
1556
#ifndef _WIN32_WCE
1171
1557
        SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left,
1172
1558
                     r.bottom - r.top + sr.bottom - sr.top,
1173
1559
                     SWP_NOMOVE | SWP_NOZORDER);
 
1560
#endif
1174
1561
    } else {
1175
1562
        fe->statusbar = NULL;
1176
1563
    }
1177
1564
 
1178
1565
    {
 
1566
#ifndef _WIN32_WCE
1179
1567
        HMENU bar = CreateMenu();
1180
1568
        HMENU menu = CreateMenu();
 
1569
        RECT menusize;
1181
1570
 
1182
 
        AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Game");
1183
 
        AppendMenu(menu, MF_ENABLED, IDM_NEW, "New");
1184
 
        AppendMenu(menu, MF_ENABLED, IDM_RESTART, "Restart");
1185
 
        AppendMenu(menu, MF_ENABLED, IDM_DESC, "Specific...");
1186
 
        AppendMenu(menu, MF_ENABLED, IDM_SEED, "Random Seed...");
 
1571
        AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "&Game");
 
1572
#else
 
1573
        HMENU menu = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_GAME);
 
1574
        DeleteMenu(menu, 0, MF_BYPOSITION);
 
1575
#endif
 
1576
        AppendMenu(menu, MF_ENABLED, IDM_NEW, TEXT("&New"));
 
1577
        AppendMenu(menu, MF_ENABLED, IDM_RESTART, TEXT("&Restart"));
 
1578
#ifndef _WIN32_WCE
 
1579
        /* ...here I run out of sensible accelerator characters. */
 
1580
        AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Speci&fic..."));
 
1581
        AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Rando&m Seed..."));
 
1582
#endif
1187
1583
 
1188
1584
        if ((fe->npresets = midend_num_presets(fe->me)) > 0 ||
1189
1585
            thegame.can_configure) {
 
1586
            int i;
 
1587
#ifndef _WIN32_WCE
1190
1588
            HMENU sub = CreateMenu();
1191
 
            int i;
1192
 
 
1193
 
            AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "Type");
1194
 
 
 
1589
 
 
1590
            AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "&Type");
 
1591
#else
 
1592
            HMENU sub = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_TYPE);
 
1593
            DeleteMenu(sub, 0, MF_BYPOSITION);
 
1594
#endif
1195
1595
            fe->presets = snewn(fe->npresets, game_params *);
1196
1596
 
1197
1597
            for (i = 0; i < fe->npresets; i++) {
1198
1598
                char *name;
 
1599
#ifdef _WIN32_WCE
 
1600
                TCHAR wName[255];
 
1601
#endif
1199
1602
 
1200
1603
                midend_fetch_preset(fe->me, i, &name, &fe->presets[i]);
1201
1604
 
1204
1607
                 * with ampersands here.
1205
1608
                 */
1206
1609
 
 
1610
#ifndef _WIN32_WCE
1207
1611
                AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, name);
 
1612
#else
 
1613
                MultiByteToWideChar (CP_ACP, 0, name, -1, wName, 255);
 
1614
                AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, wName);
 
1615
#endif
1208
1616
            }
1209
 
 
1210
1617
            if (thegame.can_configure) {
1211
 
                AppendMenu(sub, MF_ENABLED, IDM_CONFIG, "Custom...");
 
1618
                AppendMenu(sub, MF_ENABLED, IDM_CONFIG, TEXT("&Custom..."));
1212
1619
            }
1213
 
        }
 
1620
 
 
1621
            fe->typemenu = sub;
 
1622
        } else
 
1623
            fe->typemenu = INVALID_HANDLE_VALUE;
1214
1624
 
1215
1625
        AppendMenu(menu, MF_SEPARATOR, 0, 0);
1216
 
        AppendMenu(menu, MF_ENABLED, IDM_LOAD, "Load");
1217
 
        AppendMenu(menu, MF_ENABLED, IDM_SAVE, "Save");
 
1626
#ifndef _WIN32_WCE
 
1627
        AppendMenu(menu, MF_ENABLED, IDM_LOAD, TEXT("&Load..."));
 
1628
        AppendMenu(menu, MF_ENABLED, IDM_SAVE, TEXT("&Save..."));
1218
1629
        AppendMenu(menu, MF_SEPARATOR, 0, 0);
1219
1630
        if (thegame.can_print) {
1220
 
            AppendMenu(menu, MF_ENABLED, IDM_PRINT, "Print");
 
1631
            AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("&Print..."));
1221
1632
            AppendMenu(menu, MF_SEPARATOR, 0, 0);
1222
1633
        }
1223
 
        AppendMenu(menu, MF_ENABLED, IDM_UNDO, "Undo");
1224
 
        AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo");
 
1634
#endif
 
1635
        AppendMenu(menu, MF_ENABLED, IDM_UNDO, TEXT("Undo"));
 
1636
        AppendMenu(menu, MF_ENABLED, IDM_REDO, TEXT("Redo"));
 
1637
#ifndef _WIN32_WCE
1225
1638
        if (thegame.can_format_as_text) {
1226
1639
            AppendMenu(menu, MF_SEPARATOR, 0, 0);
1227
 
            AppendMenu(menu, MF_ENABLED, IDM_COPY, "Copy");
 
1640
            AppendMenu(menu, MF_ENABLED, IDM_COPY, TEXT("&Copy"));
1228
1641
        }
 
1642
#endif
1229
1643
        if (thegame.can_solve) {
1230
1644
            AppendMenu(menu, MF_SEPARATOR, 0, 0);
1231
 
            AppendMenu(menu, MF_ENABLED, IDM_SOLVE, "Solve");
 
1645
            AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Sol&ve"));
1232
1646
        }
1233
1647
        AppendMenu(menu, MF_SEPARATOR, 0, 0);
1234
 
        AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit");
 
1648
#ifndef _WIN32_WCE
 
1649
        AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("E&xit"));
1235
1650
        menu = CreateMenu();
1236
 
        AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Help");
1237
 
        AppendMenu(menu, MF_ENABLED, IDM_ABOUT, "About");
1238
 
        if (fe->help_path) {
 
1651
        AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, TEXT("&Help"));
 
1652
#endif
 
1653
        AppendMenu(menu, MF_ENABLED, IDM_ABOUT, TEXT("&About"));
 
1654
#ifndef _WIN32_WCE
 
1655
        if (help_type != NONE) {
1239
1656
            AppendMenu(menu, MF_SEPARATOR, 0, 0);
1240
 
            AppendMenu(menu, MF_ENABLED, IDM_HELPC, "Contents");
1241
 
            if (thegame.winhelp_topic) {
 
1657
            AppendMenu(menu, MF_ENABLED, IDM_HELPC, TEXT("&Contents"));
 
1658
            if (help_topic) {
1242
1659
                char *item;
1243
1660
                assert(thegame.name);
1244
 
                item = snewn(9+strlen(thegame.name), char); /*ick*/
1245
 
                sprintf(item, "Help on %s", thegame.name);
 
1661
                item = snewn(10+strlen(thegame.name), char); /*ick*/
 
1662
                sprintf(item, "&Help on %s", thegame.name);
1246
1663
                AppendMenu(menu, MF_ENABLED, IDM_GAMEHELP, item);
1247
1664
                sfree(item);
1248
1665
            }
1249
1666
        }
1250
1667
        SetMenu(fe->hwnd, bar);
 
1668
        get_menu_size(fe->hwnd, &menusize);
 
1669
        fe->xmin = (menusize.right - menusize.left) + 25;
 
1670
#endif
1251
1671
    }
1252
1672
 
1253
1673
    fe->bitmap = NULL;
1256
1676
 
1257
1677
    SetWindowLong(fe->hwnd, GWL_USERDATA, (LONG)fe);
1258
1678
 
1259
 
    ShowWindow(fe->hwnd, SW_NORMAL);
 
1679
    ShowWindow(fe->hwnd, SW_SHOWNORMAL);
1260
1680
    SetForegroundWindow(fe->hwnd);
1261
1681
 
 
1682
    update_type_menu_tick(fe);
 
1683
 
1262
1684
    midend_redraw(fe->me);
1263
1685
 
1264
1686
    return fe;
1265
1687
}
1266
1688
 
 
1689
#ifdef _WIN32_WCE
 
1690
static HFONT dialog_title_font()
 
1691
{
 
1692
    static HFONT hf = NULL;
 
1693
    LOGFONT lf;
 
1694
 
 
1695
    if (hf)
 
1696
        return hf;
 
1697
 
 
1698
    memset (&lf, 0, sizeof(LOGFONT));
 
1699
    lf.lfHeight = -11; /* - ((8 * GetDeviceCaps(hdc, LOGPIXELSY)) / 72) */
 
1700
    lf.lfWeight = FW_BOLD;
 
1701
    wcscpy(lf.lfFaceName, TEXT("Tahoma"));
 
1702
 
 
1703
    return hf = CreateFontIndirect(&lf);
 
1704
}
 
1705
 
 
1706
static void make_dialog_full_screen(HWND hwnd)
 
1707
{
 
1708
    SHINITDLGINFO shidi;
 
1709
 
 
1710
    /* Make dialog full screen */
 
1711
    shidi.dwMask = SHIDIM_FLAGS;
 
1712
    shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN |
 
1713
                    SHIDIF_EMPTYMENU;
 
1714
    shidi.hDlg = hwnd;
 
1715
    SHInitDialog(&shidi);
 
1716
}
 
1717
#endif
 
1718
 
1267
1719
static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg,
1268
1720
                                 WPARAM wParam, LPARAM lParam)
1269
1721
{
1271
1723
 
1272
1724
    switch (msg) {
1273
1725
      case WM_INITDIALOG:
1274
 
        return 0;
 
1726
#ifdef _WIN32_WCE
 
1727
        {
 
1728
            char title[256];
 
1729
 
 
1730
            make_dialog_full_screen(hwnd);
 
1731
 
 
1732
            sprintf(title, "About %.250s", thegame.name);
 
1733
            SetDlgItemTextA(hwnd, IDC_ABOUT_CAPTION, title);
 
1734
 
 
1735
            SendDlgItemMessage(hwnd, IDC_ABOUT_CAPTION, WM_SETFONT,
 
1736
                               (WPARAM) dialog_title_font(), 0);
 
1737
 
 
1738
            SetDlgItemTextA(hwnd, IDC_ABOUT_GAME, thegame.name);
 
1739
            SetDlgItemTextA(hwnd, IDC_ABOUT_VERSION, ver);
 
1740
        }
 
1741
#endif
 
1742
        return TRUE;
1275
1743
 
1276
1744
      case WM_COMMAND:
1277
 
        if ((HIWORD(wParam) == BN_CLICKED ||
1278
 
             HIWORD(wParam) == BN_DOUBLECLICKED) &&
1279
 
            LOWORD(wParam) == IDOK)
 
1745
        if (LOWORD(wParam) == IDOK)
 
1746
#ifdef _WIN32_WCE
 
1747
            EndDialog(hwnd, 1);
 
1748
#else
1280
1749
            fe->dlg_done = 1;
 
1750
#endif
1281
1751
        return 0;
1282
1752
 
1283
1753
      case WM_CLOSE:
 
1754
#ifdef _WIN32_WCE
 
1755
        EndDialog(hwnd, 1);
 
1756
#else
1284
1757
        fe->dlg_done = 1;
 
1758
#endif
1285
1759
        return 0;
1286
1760
    }
1287
1761
 
1388
1862
    }
1389
1863
}
1390
1864
 
 
1865
#ifdef _WIN32_WCE
 
1866
/* Separate version of mkctrl function for the Pocket PC. */
 
1867
/* Control coordinates should be specified in dialog units. */
 
1868
HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
 
1869
            LPCTSTR wclass, int wstyle,
 
1870
            int exstyle, const char *wtext, int wid)
 
1871
{
 
1872
    RECT rc;
 
1873
    TCHAR wwtext[256];
 
1874
 
 
1875
    /* Convert dialog units into pixels */
 
1876
    rc.left = x1;  rc.right  = x2;
 
1877
    rc.top  = y1;  rc.bottom = y2;
 
1878
    MapDialogRect(fe->cfgbox, &rc);
 
1879
 
 
1880
    MultiByteToWideChar (CP_ACP, 0, wtext, -1, wwtext, 256);
 
1881
 
 
1882
    return CreateWindowEx(exstyle, wclass, wwtext,
 
1883
                          wstyle | WS_CHILD | WS_VISIBLE,
 
1884
                          rc.left, rc.top,
 
1885
                          rc.right - rc.left, rc.bottom - rc.top,
 
1886
                          fe->cfgbox, (HMENU) wid, fe->inst, NULL);
 
1887
}
 
1888
 
 
1889
static void create_config_controls(frontend * fe)
 
1890
{
 
1891
    int id, nctrls;
 
1892
    int col1l, col1r, col2l, col2r, y;
 
1893
    config_item *i;
 
1894
    struct cfg_aux *j;
 
1895
    HWND ctl;
 
1896
 
 
1897
    /* Control placement done in dialog units */
 
1898
    col1l = 4;   col1r = 96;   /* Label column */
 
1899
    col2l = 100; col2r = 154;  /* Input column (edit boxes and combo boxes) */
 
1900
 
 
1901
    /*
 
1902
     * Count the controls so we can allocate cfgaux.
 
1903
     */
 
1904
    for (nctrls = 0, i = fe->cfg; i->type != C_END; i++)
 
1905
        nctrls++;
 
1906
    fe->cfgaux = snewn(nctrls, struct cfg_aux);
 
1907
 
 
1908
    id = 1000;
 
1909
    y = 22; /* Leave some room for the dialog title */
 
1910
    for (i = fe->cfg, j = fe->cfgaux; i->type != C_END; i++, j++) {
 
1911
        switch (i->type) {
 
1912
          case C_STRING:
 
1913
            /*
 
1914
             * Edit box with a label beside it.
 
1915
             */
 
1916
            mkctrl(fe, col1l, col1r, y + 1, y + 11,
 
1917
                   TEXT("Static"), SS_LEFTNOWORDWRAP, 0, i->name, id++);
 
1918
            mkctrl(fe, col2l, col2r, y, y + 12,
 
1919
                   TEXT("EDIT"), WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,
 
1920
                   0, "", (j->ctlid = id++));
 
1921
            SetDlgItemTextA(fe->cfgbox, j->ctlid, i->sval);
 
1922
            break;
 
1923
 
 
1924
          case C_BOOLEAN:
 
1925
            /*
 
1926
             * Simple checkbox.
 
1927
             */
 
1928
            mkctrl(fe, col1l, col2r, y + 1, y + 11, TEXT("BUTTON"),
 
1929
                   BS_NOTIFY | BS_AUTOCHECKBOX | WS_TABSTOP,
 
1930
                   0, i->name, (j->ctlid = id++));
 
1931
            CheckDlgButton(fe->cfgbox, j->ctlid, (i->ival != 0));
 
1932
            break;
 
1933
 
 
1934
          case C_CHOICES:
 
1935
            /*
 
1936
             * Drop-down list with a label beside it.
 
1937
             */
 
1938
            mkctrl(fe, col1l, col1r, y + 1, y + 11,
 
1939
                   TEXT("STATIC"), SS_LEFTNOWORDWRAP, 0, i->name, id++);
 
1940
            ctl = mkctrl(fe, col2l, col2r, y, y + 48,
 
1941
                         TEXT("COMBOBOX"), WS_BORDER | WS_TABSTOP |
 
1942
                         CBS_DROPDOWNLIST | CBS_HASSTRINGS,
 
1943
                         0, "", (j->ctlid = id++));
 
1944
            {
 
1945
                char c, *p, *q, *str;
 
1946
 
 
1947
                p = i->sval;
 
1948
                c = *p++;
 
1949
                while (*p) {
 
1950
                    q = p;
 
1951
                    while (*q && *q != c) q++;
 
1952
                    str = snewn(q-p+1, char);
 
1953
                    strncpy(str, p, q-p);
 
1954
                    str[q-p] = '\0';
 
1955
                    {
 
1956
                        TCHAR ws[50];
 
1957
                        MultiByteToWideChar (CP_ACP, 0, str, -1, ws, 50);
 
1958
                        SendMessage(ctl, CB_ADDSTRING, 0, (LPARAM)ws);
 
1959
                    }
 
1960
                    
 
1961
                    sfree(str);
 
1962
                    if (*q) q++;
 
1963
                    p = q;
 
1964
                }
 
1965
            }
 
1966
            SendMessage(ctl, CB_SETCURSEL, i->ival, 0);
 
1967
            break;
 
1968
        }
 
1969
 
 
1970
        y += 15;
 
1971
    }
 
1972
 
 
1973
}
 
1974
#endif
 
1975
 
1391
1976
static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
1392
1977
                                  WPARAM wParam, LPARAM lParam)
1393
1978
{
1397
1982
 
1398
1983
    switch (msg) {
1399
1984
      case WM_INITDIALOG:
1400
 
        return 0;
 
1985
#ifdef _WIN32_WCE
 
1986
        {
 
1987
            char *title;
 
1988
 
 
1989
            fe = (frontend *) lParam;
 
1990
            SetWindowLong(hwnd, GWL_USERDATA, lParam);
 
1991
            fe->cfgbox = hwnd;
 
1992
 
 
1993
            fe->cfg = frontend_get_config(fe, fe->cfg_which, &title);
 
1994
 
 
1995
            make_dialog_full_screen(hwnd);
 
1996
 
 
1997
            SetDlgItemTextA(hwnd, IDC_CONFIG_CAPTION, title);
 
1998
            SendDlgItemMessage(hwnd, IDC_CONFIG_CAPTION, WM_SETFONT,
 
1999
                               (WPARAM) dialog_title_font(), 0);
 
2000
 
 
2001
            create_config_controls(fe);
 
2002
        }
 
2003
#endif
 
2004
        return TRUE;
1401
2005
 
1402
2006
      case WM_COMMAND:
1403
2007
        /*
1404
2008
         * OK and Cancel are special cases.
1405
2009
         */
1406
 
        if ((HIWORD(wParam) == BN_CLICKED ||
1407
 
             HIWORD(wParam) == BN_DOUBLECLICKED) &&
1408
 
            (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) {
 
2010
        if ((LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) {
1409
2011
            if (LOWORD(wParam) == IDOK) {
1410
2012
                char *err = frontend_set_config(fe, fe->cfg_which, fe->cfg);
1411
2013
 
1413
2015
                    MessageBox(hwnd, err, "Validation error",
1414
2016
                               MB_ICONERROR | MB_OK);
1415
2017
                } else {
 
2018
#ifdef _WIN32_WCE
 
2019
                    EndDialog(hwnd, 2);
 
2020
#else
1416
2021
                    fe->dlg_done = 2;
 
2022
#endif
1417
2023
                }
1418
2024
            } else {
 
2025
#ifdef _WIN32_WCE
 
2026
                EndDialog(hwnd, 1);
 
2027
#else
1419
2028
                fe->dlg_done = 1;
 
2029
#endif
1420
2030
            }
1421
2031
            return 0;
1422
2032
        }
1433
2043
 
1434
2044
        if (i->type == C_STRING && HIWORD(wParam) == EN_CHANGE) {
1435
2045
            char buffer[4096];
 
2046
#ifdef _WIN32_WCE
 
2047
            TCHAR wBuffer[4096];
 
2048
            GetDlgItemText(fe->cfgbox, j->ctlid, wBuffer, 4096);
 
2049
            WideCharToMultiByte(CP_ACP, 0, wBuffer, -1, buffer, 4096, NULL, NULL);
 
2050
#else
1436
2051
            GetDlgItemText(fe->cfgbox, j->ctlid, buffer, lenof(buffer));
 
2052
#endif
1437
2053
            buffer[lenof(buffer)-1] = '\0';
1438
2054
            sfree(i->sval);
1439
2055
            i->sval = dupstr(buffer);
1440
2056
        } else if (i->type == C_BOOLEAN && 
1441
2057
                   (HIWORD(wParam) == BN_CLICKED ||
1442
 
                    HIWORD(wParam) == BN_DOUBLECLICKED)) {
 
2058
                    HIWORD(wParam) == BN_DBLCLK)) {
1443
2059
            i->ival = IsDlgButtonChecked(fe->cfgbox, j->ctlid);
1444
2060
        } else if (i->type == C_CHOICES &&
1445
2061
                   HIWORD(wParam) == CBN_SELCHANGE) {
1457
2073
    return 0;
1458
2074
}
1459
2075
 
 
2076
#ifndef _WIN32_WCE
1460
2077
HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
1461
2078
            char *wclass, int wstyle,
1462
2079
            int exstyle, const char *wtext, int wid)
1468
2085
    SendMessage(ret, WM_SETFONT, (WPARAM)fe->cfgfont, MAKELPARAM(TRUE, 0));
1469
2086
    return ret;
1470
2087
}
 
2088
#endif
1471
2089
 
1472
2090
static void about(frontend *fe)
1473
2091
{
 
2092
#ifdef _WIN32_WCE
 
2093
    DialogBox(fe->inst, MAKEINTRESOURCE(IDD_ABOUT), fe->hwnd, AboutDlgProc);
 
2094
#else
1474
2095
    int i;
1475
2096
    WNDCLASS wc;
1476
2097
    MSG msg;
1492
2113
    strings[nstrings++] = "from Simon Tatham's Portable Puzzle Collection";
1493
2114
    strings[nstrings++] = ver;
1494
2115
 
1495
 
    wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
 
2116
    wc.style = CS_DBLCLKS | CS_SAVEBITS;
1496
2117
    wc.lpfnWndProc = DefDlgProc;
1497
2118
    wc.cbClsExtra = 0;
1498
2119
    wc.cbWndExtra = DLGWINDOWEXTRA + 8;
1602
2223
 
1603
2224
    y += height/2;                     /* extra space before OK */
1604
2225
    mkctrl(fe, width*2, maxwid+width*2, y, y+height*7/4, "BUTTON",
1605
 
           BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
 
2226
           BS_PUSHBUTTON | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
1606
2227
           "OK", IDOK);
1607
2228
 
1608
2229
    SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0);
1609
2230
 
1610
2231
    EnableWindow(fe->hwnd, FALSE);
1611
 
    ShowWindow(fe->cfgbox, SW_NORMAL);
 
2232
    ShowWindow(fe->cfgbox, SW_SHOWNORMAL);
1612
2233
    while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
1613
2234
        if (!IsDialogMessage(fe->cfgbox, &msg))
1614
2235
            DispatchMessage(&msg);
1619
2240
    SetForegroundWindow(fe->hwnd);
1620
2241
    DestroyWindow(fe->cfgbox);
1621
2242
    DeleteObject(fe->cfgfont);
 
2243
#endif
1622
2244
}
1623
2245
 
1624
2246
static int get_config(frontend *fe, int which)
1625
2247
{
 
2248
#ifdef _WIN32_WCE
 
2249
    fe->cfg_which = which;
 
2250
 
 
2251
    return DialogBoxParam(fe->inst,
 
2252
                          MAKEINTRESOURCE(IDD_CONFIG),
 
2253
                          fe->hwnd, ConfigDlgProc,
 
2254
                          (LPARAM) fe) == 2;
 
2255
#else
1626
2256
    config_item *i;
1627
2257
    struct cfg_aux *j;
1628
2258
    char *title;
1637
2267
    int winwidth, winheight, col1l, col1r, col2l, col2r, y;
1638
2268
    int height, width, maxlabel, maxcheckbox;
1639
2269
 
1640
 
    wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
 
2270
    wc.style = CS_DBLCLKS | CS_SAVEBITS;
1641
2271
    wc.lpfnWndProc = DefDlgProc;
1642
2272
    wc.cbClsExtra = 0;
1643
2273
    wc.cbWndExtra = DLGWINDOWEXTRA + 8;
1836
2466
 
1837
2467
    y += height/2;                     /* extra space before OK and Cancel */
1838
2468
    mkctrl(fe, col1l, (col1l+col2r)/2-width, y, y+height*7/4, "BUTTON",
1839
 
           BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
 
2469
           BS_PUSHBUTTON | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
1840
2470
           "OK", IDOK);
1841
2471
    mkctrl(fe, (col1l+col2r)/2+width, col2r, y, y+height*7/4, "BUTTON",
1842
 
           BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP, 0, "Cancel", IDCANCEL);
 
2472
           BS_PUSHBUTTON | WS_TABSTOP, 0, "Cancel", IDCANCEL);
1843
2473
 
1844
2474
    SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0);
1845
2475
 
1846
2476
    EnableWindow(fe->hwnd, FALSE);
1847
 
    ShowWindow(fe->cfgbox, SW_NORMAL);
 
2477
    ShowWindow(fe->cfgbox, SW_SHOWNORMAL);
1848
2478
    while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
1849
2479
        if (!IsDialogMessage(fe->cfgbox, &msg))
1850
2480
            DispatchMessage(&msg);
1860
2490
    sfree(fe->cfgaux);
1861
2491
 
1862
2492
    return (fe->dlg_done == 2);
 
2493
#endif
 
2494
}
 
2495
 
 
2496
#ifdef _WIN32_WCE
 
2497
static void calculate_bitmap_position(frontend *fe, int x, int y)
 
2498
{
 
2499
    /* Pocket PC - center the game in the full screen window */
 
2500
    int yMargin;
 
2501
    RECT rcClient;
 
2502
 
 
2503
    GetClientRect(fe->hwnd, &rcClient);
 
2504
    fe->bitmapPosition.left = (rcClient.right  - x) / 2;
 
2505
    yMargin = rcClient.bottom - y;
 
2506
 
 
2507
    if (fe->numpad != NULL) {
 
2508
        RECT rcPad;
 
2509
        GetWindowRect(fe->numpad, &rcPad);
 
2510
        yMargin -= rcPad.bottom - rcPad.top;
 
2511
    }
 
2512
 
 
2513
    if (fe->statusbar != NULL) {
 
2514
        RECT rcStatus;
 
2515
        GetWindowRect(fe->statusbar, &rcStatus);
 
2516
        yMargin -= rcStatus.bottom - rcStatus.top;
 
2517
    }
 
2518
 
 
2519
    fe->bitmapPosition.top = yMargin / 2;
 
2520
 
 
2521
    fe->bitmapPosition.right  = fe->bitmapPosition.left + x;
 
2522
    fe->bitmapPosition.bottom = fe->bitmapPosition.top  + y;
 
2523
}
 
2524
#else
 
2525
static void calculate_bitmap_position(frontend *fe, int x, int y)
 
2526
{
 
2527
    /* Plain Windows - position the game in the upper-left corner */
 
2528
    fe->bitmapPosition.left = 0;
 
2529
    fe->bitmapPosition.top = 0;
 
2530
    fe->bitmapPosition.right  = fe->bitmapPosition.left + x;
 
2531
    fe->bitmapPosition.bottom = fe->bitmapPosition.top  + y;
 
2532
}
 
2533
#endif
 
2534
 
 
2535
static void new_bitmap(frontend *fe, int x, int y)
 
2536
{
 
2537
    HDC hdc;
 
2538
 
 
2539
    if (fe->bitmap) DeleteObject(fe->bitmap);
 
2540
 
 
2541
    hdc = GetDC(fe->hwnd);
 
2542
    fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
 
2543
    calculate_bitmap_position(fe, x, y);
 
2544
    ReleaseDC(fe->hwnd, hdc);
1863
2545
}
1864
2546
 
1865
2547
static void new_game_size(frontend *fe)
1866
2548
{
1867
2549
    RECT r, sr;
1868
 
    HDC hdc;
1869
2550
    int x, y;
1870
2551
 
1871
2552
    get_max_puzzle_size(fe, &x, &y);
1872
2553
    midend_size(fe->me, &x, &y, FALSE);
 
2554
    fe->ymin = (fe->xmin * y) / x;
1873
2555
 
1874
2556
    r.left = r.top = 0;
1875
2557
    r.right = x;
1881
2563
    } else {
1882
2564
        sr.left = sr.right = sr.top = sr.bottom = 0;
1883
2565
    }
 
2566
#ifndef _WIN32_WCE
1884
2567
    SetWindowPos(fe->hwnd, NULL, 0, 0,
1885
2568
                 r.right - r.left,
1886
2569
                 r.bottom - r.top + sr.bottom - sr.top,
1887
2570
                 SWP_NOMOVE | SWP_NOZORDER);
 
2571
#endif
1888
2572
 
1889
2573
    check_window_size(fe, &x, &y);
1890
2574
 
 
2575
#ifndef _WIN32_WCE
1891
2576
    if (fe->statusbar != NULL)
1892
2577
        SetWindowPos(fe->statusbar, NULL, 0, y, x,
1893
2578
                     sr.bottom - sr.top, SWP_NOZORDER);
1894
 
 
1895
 
    if (fe->bitmap) DeleteObject(fe->bitmap);
1896
 
 
1897
 
    hdc = GetDC(fe->hwnd);
1898
 
    fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
1899
 
    ReleaseDC(fe->hwnd, hdc);
1900
 
 
 
2579
#endif
 
2580
 
 
2581
    new_bitmap(fe, x, y);
 
2582
 
 
2583
#ifdef _WIN32_WCE
 
2584
    InvalidateRect(fe->hwnd, NULL, TRUE);
 
2585
#endif
1901
2586
    midend_redraw(fe->me);
1902
2587
}
1903
2588
 
 
2589
/*
 
2590
 * Given a proposed new window rect, work out the resulting
 
2591
 * difference in client size (from current), and use to try
 
2592
 * and resize the puzzle, returning (wx,wy) as the actual
 
2593
 * new window size.
 
2594
 */
 
2595
 
 
2596
static void adjust_game_size(frontend *fe, RECT *proposed, int isedge,
 
2597
                             int *wx_r, int *wy_r)
 
2598
{
 
2599
    RECT cr, wr;
 
2600
    int nx, ny, xdiff, ydiff, wx, wy;
 
2601
 
 
2602
    /* Work out the current window sizing, and thus the
 
2603
     * difference in size we're asking for. */
 
2604
    GetClientRect(fe->hwnd, &cr);
 
2605
    wr = cr;
 
2606
    AdjustWindowRectEx(&wr, WINFLAGS, TRUE, 0);
 
2607
 
 
2608
    xdiff = (proposed->right - proposed->left) - (wr.right - wr.left);
 
2609
    ydiff = (proposed->bottom - proposed->top) - (wr.bottom - wr.top);
 
2610
 
 
2611
    if (isedge) {
 
2612
      /* These next four lines work around the fact that midend_size
 
2613
       * is happy to shrink _but not grow_ if you change one dimension
 
2614
       * but not the other. */
 
2615
      if (xdiff > 0 && ydiff == 0)
 
2616
        ydiff = (xdiff * (wr.right - wr.left)) / (wr.bottom - wr.top);
 
2617
      if (xdiff == 0 && ydiff > 0)
 
2618
        xdiff = (ydiff * (wr.bottom - wr.top)) / (wr.right - wr.left);
 
2619
    }
 
2620
 
 
2621
    if (check_window_resize(fe,
 
2622
                            (cr.right - cr.left) + xdiff,
 
2623
                            (cr.bottom - cr.top) + ydiff,
 
2624
                            &nx, &ny, &wx, &wy, TRUE)) {
 
2625
        new_bitmap(fe, nx, ny);
 
2626
        midend_force_redraw(fe->me);
 
2627
    } else {
 
2628
        /* reset size to current window size */
 
2629
        wx = wr.right - wr.left;
 
2630
        wy = wr.bottom - wr.top;
 
2631
    }
 
2632
    /* Re-fetch rectangle; size limits mean we might not have
 
2633
     * taken it quite to the mouse drag positions. */
 
2634
    GetClientRect(fe->hwnd, &cr);
 
2635
    adjust_statusbar(fe, &cr);
 
2636
 
 
2637
    *wx_r = wx; *wy_r = wy;
 
2638
}
 
2639
 
 
2640
static void update_type_menu_tick(frontend *fe)
 
2641
{
 
2642
    int total, n, i;
 
2643
 
 
2644
    if (fe->typemenu == INVALID_HANDLE_VALUE)
 
2645
        return;
 
2646
 
 
2647
    total = GetMenuItemCount(fe->typemenu);
 
2648
    n = midend_which_preset(fe->me);
 
2649
    if (n < 0)
 
2650
        n = total - 1;                 /* "Custom" item */
 
2651
 
 
2652
    for (i = 0; i < total; i++) {
 
2653
        int flag = (i == n ? MF_CHECKED : MF_UNCHECKED);
 
2654
        CheckMenuItem(fe->typemenu, i, MF_BYPOSITION | flag);
 
2655
    }
 
2656
 
 
2657
    DrawMenuBar(fe->hwnd);
 
2658
}
 
2659
 
1904
2660
static void new_game_type(frontend *fe)
1905
2661
{
1906
2662
    midend_new_game(fe->me);
1907
2663
    new_game_size(fe);
 
2664
    update_type_menu_tick(fe);
1908
2665
}
1909
2666
 
1910
2667
static int is_alt_pressed(void)
1946
2703
        DestroyWindow(hwnd);
1947
2704
        return 0;
1948
2705
      case WM_COMMAND:
 
2706
#ifdef _WIN32_WCE
 
2707
        /* Numeric pad sends WM_COMMAND messages */
 
2708
        if ((wParam >= IDM_KEYEMUL) && (wParam < IDM_KEYEMUL + 256))
 
2709
        {
 
2710
            midend_process_key(fe->me, 0, 0, wParam - IDM_KEYEMUL);
 
2711
        }
 
2712
#endif
1949
2713
        cmd = wParam & ~0xF;           /* low 4 bits reserved to Windows */
1950
2714
        switch (cmd) {
1951
2715
          case IDM_NEW:
2090
2854
            }
2091
2855
 
2092
2856
            break;
 
2857
#ifndef _WIN32_WCE
2093
2858
          case IDM_HELPC:
2094
 
            assert(fe->help_path);
2095
 
            WinHelp(hwnd, fe->help_path,
2096
 
                    fe->help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0);
2097
 
            break;
 
2859
            start_help(fe, NULL);
 
2860
            break;
2098
2861
          case IDM_GAMEHELP:
2099
 
            assert(fe->help_path);
2100
 
            assert(thegame.winhelp_topic);
2101
 
            {
2102
 
                char *cmd = snewn(10+strlen(thegame.winhelp_topic), char);
2103
 
                sprintf(cmd, "JI(`',`%s')", thegame.winhelp_topic);
2104
 
                WinHelp(hwnd, fe->help_path, HELP_COMMAND, (DWORD)cmd);
2105
 
                sfree(cmd);
2106
 
            }
 
2862
            start_help(fe, help_topic);
2107
2863
            break;
 
2864
#endif
2108
2865
          default:
2109
2866
            {
2110
2867
                int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10;
2118
2875
        }
2119
2876
        break;
2120
2877
      case WM_DESTROY:
 
2878
#ifndef _WIN32_WCE
 
2879
        stop_help(fe);
 
2880
#endif
2121
2881
        PostQuitMessage(0);
2122
2882
        return 0;
2123
2883
      case WM_PAINT:
2125
2885
            PAINTSTRUCT p;
2126
2886
            HDC hdc, hdc2;
2127
2887
            HBITMAP prevbm;
 
2888
            RECT rcDest;
2128
2889
 
2129
2890
            hdc = BeginPaint(hwnd, &p);
2130
2891
            hdc2 = CreateCompatibleDC(hdc);
2131
2892
            prevbm = SelectObject(hdc2, fe->bitmap);
 
2893
#ifdef _WIN32_WCE
 
2894
            FillRect(hdc, &(p.rcPaint), (HBRUSH) GetStockObject(WHITE_BRUSH));
 
2895
#endif
 
2896
            IntersectRect(&rcDest, &(fe->bitmapPosition), &(p.rcPaint));
2132
2897
            BitBlt(hdc,
2133
 
                   p.rcPaint.left, p.rcPaint.top,
2134
 
                   p.rcPaint.right - p.rcPaint.left,
2135
 
                   p.rcPaint.bottom - p.rcPaint.top,
 
2898
                   rcDest.left, rcDest.top,
 
2899
                   rcDest.right - rcDest.left,
 
2900
                   rcDest.bottom - rcDest.top,
2136
2901
                   hdc2,
2137
 
                   p.rcPaint.left, p.rcPaint.top,
 
2902
                   rcDest.left - fe->bitmapPosition.left,
 
2903
                   rcDest.top - fe->bitmapPosition.top,
2138
2904
                   SRCCOPY);
2139
2905
            SelectObject(hdc2, prevbm);
2140
2906
            DeleteDC(hdc2);
2239
3005
            else if (message == WM_RBUTTONDOWN || is_alt_pressed())
2240
3006
                button = RIGHT_BUTTON;
2241
3007
            else
 
3008
#ifndef _WIN32_WCE
2242
3009
                button = LEFT_BUTTON;
2243
 
 
2244
 
            if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
2245
 
                                    (signed short)HIWORD(lParam), button))
 
3010
#else
 
3011
                if ((thegame.flags & REQUIRE_RBUTTON) == 0)
 
3012
                    button = LEFT_BUTTON;
 
3013
                else
 
3014
                {
 
3015
                    SHRGINFO shrgi;
 
3016
 
 
3017
                    shrgi.cbSize     = sizeof(SHRGINFO);
 
3018
                    shrgi.hwndClient = hwnd;
 
3019
                    shrgi.ptDown.x   = (signed short)LOWORD(lParam);
 
3020
                    shrgi.ptDown.y   = (signed short)HIWORD(lParam);
 
3021
                    shrgi.dwFlags    = SHRG_RETURNCMD;
 
3022
 
 
3023
                    if (GN_CONTEXTMENU == SHRecognizeGesture(&shrgi))
 
3024
                        button = RIGHT_BUTTON;
 
3025
                    else
 
3026
                        button = LEFT_BUTTON;
 
3027
                }
 
3028
#endif
 
3029
 
 
3030
            if (!midend_process_key(fe->me,
 
3031
                                    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
 
3032
                                    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
 
3033
                                    button))
2246
3034
                PostQuitMessage(0);
2247
3035
 
2248
3036
            SetCapture(hwnd);
2266
3054
            else
2267
3055
                button = LEFT_RELEASE;
2268
3056
 
2269
 
            if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
2270
 
                                    (signed short)HIWORD(lParam), button))
 
3057
            if (!midend_process_key(fe->me,
 
3058
                                    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
 
3059
                                    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
 
3060
                                    button))
2271
3061
                PostQuitMessage(0);
2272
3062
 
2273
3063
            ReleaseCapture();
2284
3074
            else
2285
3075
                button = LEFT_DRAG;
2286
3076
            
2287
 
            if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
2288
 
                                    (signed short)HIWORD(lParam), button))
 
3077
            if (!midend_process_key(fe->me,
 
3078
                                    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
 
3079
                                    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
 
3080
                                    button))
2289
3081
                PostQuitMessage(0);
2290
3082
        }
2291
3083
        break;
2301
3093
            fe->timer_last_tickcount = now;
2302
3094
        }
2303
3095
        return 0;
 
3096
#ifndef _WIN32_WCE
 
3097
      case WM_SIZING:
 
3098
        {
 
3099
            RECT *sr = (RECT *)lParam;
 
3100
            int wx, wy, isedge = 0;
 
3101
 
 
3102
            if (wParam == WMSZ_TOP ||
 
3103
                wParam == WMSZ_RIGHT ||
 
3104
                wParam == WMSZ_BOTTOM ||
 
3105
                wParam == WMSZ_LEFT) isedge = 1;
 
3106
            adjust_game_size(fe, sr, isedge, &wx, &wy);
 
3107
 
 
3108
            /* Given the window size the puzzles constrain
 
3109
             * us to, work out which edge we should be moving. */
 
3110
            if (wParam == WMSZ_TOP ||
 
3111
                wParam == WMSZ_TOPLEFT ||
 
3112
                wParam == WMSZ_TOPRIGHT) {
 
3113
                sr->top = sr->bottom - wy;
 
3114
            } else {
 
3115
                sr->bottom = sr->top + wy;
 
3116
            }
 
3117
            if (wParam == WMSZ_LEFT ||
 
3118
                wParam == WMSZ_TOPLEFT ||
 
3119
                wParam == WMSZ_BOTTOMLEFT) {
 
3120
                sr->left = sr->right - wx;
 
3121
            } else {
 
3122
                sr->right = sr->left + wx;
 
3123
            }
 
3124
            return TRUE;
 
3125
        }
 
3126
        break;
 
3127
#endif
2304
3128
    }
2305
3129
 
2306
3130
    return DefWindowProc(hwnd, message, wParam, lParam);
2307
3131
}
2308
3132
 
 
3133
#ifdef _WIN32_WCE
 
3134
static int FindPreviousInstance()
 
3135
{
 
3136
    /* Check if application is running. If it's running then focus on the window */
 
3137
    HWND hOtherWnd = NULL;
 
3138
 
 
3139
    hOtherWnd = FindWindow (wGameName, wGameName);
 
3140
    if (hOtherWnd)
 
3141
    {
 
3142
        SetForegroundWindow (hOtherWnd);
 
3143
        return TRUE;
 
3144
    }
 
3145
 
 
3146
    return FALSE;
 
3147
}
 
3148
#endif
 
3149
 
2309
3150
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
2310
3151
{
2311
3152
    MSG msg;
2312
3153
    char *error;
2313
3154
 
 
3155
#ifdef _WIN32_WCE
 
3156
    MultiByteToWideChar (CP_ACP, 0, thegame.name, -1, wGameName, 256);
 
3157
    if (FindPreviousInstance ())
 
3158
        return 0;
 
3159
#endif
 
3160
 
2314
3161
    InitCommonControls();
2315
3162
 
2316
3163
    if (!prev) {
2321
3168
        wndclass.cbClsExtra = 0;
2322
3169
        wndclass.cbWndExtra = 0;
2323
3170
        wndclass.hInstance = inst;
2324
 
        wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION);
 
3171
        wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200));
 
3172
#ifndef _WIN32_WCE
 
3173
        if (!wndclass.hIcon)           /* in case resource file is absent */
 
3174
            wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION);
 
3175
#endif
2325
3176
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
2326
3177
        wndclass.hbrBackground = NULL;
2327
3178
        wndclass.lpszMenuName = NULL;
 
3179
#ifdef _WIN32_WCE
 
3180
        wndclass.lpszClassName = wGameName;
 
3181
#else
2328
3182
        wndclass.lpszClassName = thegame.name;
 
3183
#endif
2329
3184
 
2330
3185
        RegisterClass(&wndclass);
2331
3186
    }
2333
3188
    while (*cmdline && isspace((unsigned char)*cmdline))
2334
3189
        cmdline++;
2335
3190
 
 
3191
    init_help();
 
3192
 
2336
3193
    if (!new_window(inst, *cmdline ? cmdline : NULL, &error)) {
2337
3194
        char buf[128];
2338
3195
        sprintf(buf, "%.100s Error", thegame.name);
2344
3201
        DispatchMessage(&msg);
2345
3202
    }
2346
3203
 
 
3204
    cleanup_help();
 
3205
 
2347
3206
    return msg.wParam;
2348
3207
}