Add grotty casts to prevent negative -> large positive conversion of cursor
[sgt/puzzles] / windows.c
index 6fb651c..494caae 100644 (file)
--- a/windows.c
+++ b/windows.c
@@ -7,6 +7,7 @@
 
 #include <stdio.h>
 #include <assert.h>
+#include <ctype.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <time.h>
 #define IDM_QUIT      0x0050
 #define IDM_CONFIG    0x0060
 #define IDM_SEED      0x0070
+#define IDM_HELPC     0x0080
+#define IDM_GAMEHELP  0x0090
 #define IDM_PRESETS   0x0100
 
+#define HELP_FILE_NAME  "puzzles.hlp"
+#define HELP_CNT_NAME   "puzzles.cnt"
+
 #ifdef DEBUG
 static FILE *debug_fp = NULL;
 static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
@@ -97,6 +103,8 @@ struct frontend {
     struct cfg_aux *cfgaux;
     int cfg_which, cfg_done;
     HFONT cfgfont;
+    char *help_path;
+    int help_has_contents;
 };
 
 void fatal(char *fmt, ...)
@@ -309,7 +317,36 @@ void activate_timer(frontend *fe)
     }
 }
 
-static frontend *new_window(HINSTANCE inst)
+/*
+ * See if we can find a help file.
+ */
+static void find_help_file(frontend *fe)
+{
+    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;
+    }
+}
+
+static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
 {
     frontend *fe;
     int x, y;
@@ -322,12 +359,27 @@ static frontend *new_window(HINSTANCE inst)
     time(&t);
     fe->me = midend_new(fe, &t, sizeof(t));
 
+    if (game_id) {
+        *error = midend_game_id(fe->me, game_id, FALSE);
+        if (*error) {
+            midend_free(fe->me);
+            sfree(fe);
+            return NULL;
+        }
+    }
+
+    fe->help_path = NULL;
+    find_help_file(fe);
+
     fe->inst = inst;
     midend_new_game(fe->me);
     midend_size(fe->me, &x, &y);
 
     fe->timer = 0;
 
+    fe->fonts = NULL;
+    fe->nfonts = fe->fontsize = 0;
+
     {
        int i, ncolours;
         float *colours;
@@ -402,6 +454,19 @@ static frontend *new_window(HINSTANCE inst)
        AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo");
        AppendMenu(menu, MF_SEPARATOR, 0, 0);
        AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit");
+        if (fe->help_path) {
+            HMENU hmenu = CreateMenu();
+            AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)hmenu, "Help");
+            AppendMenu(hmenu, MF_ENABLED, IDM_HELPC, "Contents");
+            if (game_winhelp_topic) {
+                char *item;
+                assert(game_name);
+                item = snewn(9+strlen(game_name), char); /*ick*/
+                sprintf(item, "Help on %s", game_name);
+                AppendMenu(hmenu, MF_ENABLED, IDM_GAMEHELP, item);
+                sfree(item);
+            }
+        }
        SetMenu(fe->hwnd, bar);
     }
 
@@ -833,6 +898,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if (get_config(fe, CFG_SEED))
                new_game_type(fe);
            break;
+          case IDM_HELPC:
+            assert(fe->help_path);
+            WinHelp(hwnd, fe->help_path,
+                    fe->help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0);
+            break;
+          case IDM_GAMEHELP:
+            assert(fe->help_path);
+            assert(game_winhelp_topic);
+            {
+                char *cmd = snewn(10+strlen(game_winhelp_topic), char); /*ick*/
+                sprintf(cmd, "JI(`',`%s')", game_winhelp_topic);
+                WinHelp(hwnd, fe->help_path, HELP_COMMAND, (DWORD)cmd);
+                sfree(cmd);
+            }
+            break;
          default:
            {
                int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10;
@@ -936,9 +1016,52 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                button = LEFT_BUTTON;
            else
                button = RIGHT_BUTTON;
-               
-           if (!midend_process_key(fe->me, LOWORD(lParam),
-                                   HIWORD(lParam), button))
+
+           if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
+                                   (signed short)HIWORD(lParam), button))
+               PostQuitMessage(0);
+
+           SetCapture(hwnd);
+       }
+       break;
+      case WM_LBUTTONUP:
+      case WM_RBUTTONUP:
+      case WM_MBUTTONUP:
+       {
+           int button;
+
+           /*
+            * Shift-clicks count as middle-clicks, since otherwise
+            * two-button Windows users won't have any kind of
+            * middle click to use.
+            */
+           if (message == WM_MBUTTONUP || (wParam & MK_SHIFT))
+               button = MIDDLE_RELEASE;
+           else if (message == WM_LBUTTONUP)
+               button = LEFT_RELEASE;
+           else
+               button = RIGHT_RELEASE;
+
+           if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
+                                   (signed short)HIWORD(lParam), button))
+               PostQuitMessage(0);
+
+           ReleaseCapture();
+       }
+       break;
+      case WM_MOUSEMOVE:
+       {
+           int button;
+
+           if (wParam & (MK_MBUTTON | MK_SHIFT))
+               button = MIDDLE_DRAG;
+           else if (wParam & MK_LBUTTON)
+               button = LEFT_DRAG;
+           else
+               button = RIGHT_DRAG;
+           
+           if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
+                                   (signed short)HIWORD(lParam), button))
                PostQuitMessage(0);
        }
        break;
@@ -962,6 +1085,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 {
     MSG msg;
+    char *error;
 
     InitCommonControls();
 
@@ -982,7 +1106,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        RegisterClass(&wndclass);
     }
 
-    new_window(inst);
+    while (*cmdline && isspace(*cmdline))
+       cmdline++;
+
+    if (!new_window(inst, *cmdline ? cmdline : NULL, &error)) {
+       char buf[128];
+       sprintf(buf, "%.100s Error", game_name);
+       MessageBox(NULL, error, buf, MB_OK|MB_ICONERROR);
+       return 1;
+    }
 
     while (GetMessage(&msg, NULL, 0, 0)) {
        DispatchMessage(&msg);