Add HACKING to main doc build.
[sgt/puzzles] / osx.m
diff --git a/osx.m b/osx.m
index 74bd1b2..c3f6d1b 100644 (file)
--- a/osx.m
+++ b/osx.m
@@ -138,6 +138,21 @@ void get_random_seed(void **randseed, int *randseedsize)
     *randseedsize = sizeof(time_t);
 }
 
+static void savefile_write(void *wctx, void *buf, int len)
+{
+    FILE *fp = (FILE *)wctx;
+    fwrite(buf, 1, len, fp);
+}
+
+static int savefile_read(void *wctx, void *buf, int len)
+{
+    FILE *fp = (FILE *)wctx;
+    int ret;
+
+    ret = fread(buf, 1, len, fp);
+    return (ret == len);
+}
+
 /* ----------------------------------------------------------------------
  * Tiny extension to NSMenuItem which carries a payload of a `void
  * *', allowing several menu items to invoke the same message but
@@ -384,6 +399,7 @@ struct frontend {
 - (void)activateTimer;
 - (void)deactivateTimer;
 - (void)setStatusLine:(char *)text;
+- (void)resizeForNewGameParams;
 @end
 
 @implementation MyImageView
@@ -659,6 +675,17 @@ struct frontend {
     last_time = now;
 }
 
+- (void)showError:(char *)message
+{
+    NSAlert *alert;
+
+    alert = [[[NSAlert alloc] init] autorelease];
+    [alert addButtonWithTitle:@"Bah"];
+    [alert setInformativeText:[NSString stringWithCString:message]];
+    [alert beginSheetModalForWindow:self modalDelegate:nil
+     didEndSelector:nil contextInfo:nil];
+}
+
 - (void)newGame:(id)sender
 {
     [self processButton:'n' x:-1 y:-1];
@@ -667,6 +694,54 @@ struct frontend {
 {
     midend_restart_game(me);
 }
+- (void)saveGame:(id)sender
+{
+    NSSavePanel *sp = [NSSavePanel savePanel];
+
+    if ([sp runModal] == NSFileHandlingPanelOKButton) {
+       const char *name = [[sp filename] cString];
+
+        FILE *fp = fopen(name, "w");
+
+        if (!fp) {
+            [self showError:"Unable to open save file"];
+            return;
+        }
+
+        midend_serialise(me, savefile_write, fp);
+
+        fclose(fp);
+    }
+}
+- (void)loadSavedGame:(id)sender
+{
+    NSOpenPanel *op = [NSOpenPanel openPanel];
+
+    [op setAllowsMultipleSelection:NO];
+
+    if ([op runModalForTypes:nil] == NSOKButton) {
+       const char *name = [[[op filenames] objectAtIndex:0] cString];
+       char *err;
+
+        FILE *fp = fopen(name, "r");
+
+        if (!fp) {
+            [self showError:"Unable to open saved game file"];
+            return;
+        }
+
+        err = midend_deserialise(me, savefile_read, fp);
+
+        fclose(fp);
+
+        if (err) {
+            [self showError:err];
+            return;
+        }
+
+       [self resizeForNewGameParams];
+    }
+}
 - (void)undoMove:(id)sender
 {
     [self processButton:'u' x:-1 y:-1];
@@ -693,17 +768,11 @@ struct frontend {
 - (void)solveGame:(id)sender
 {
     char *msg;
-    NSAlert *alert;
 
     msg = midend_solve(me);
 
-    if (msg) {
-       alert = [[[NSAlert alloc] init] autorelease];
-       [alert addButtonWithTitle:@"Bah"];
-       [alert setInformativeText:[NSString stringWithCString:msg]];
-       [alert beginSheetModalForWindow:self modalDelegate:nil
-        didEndSelector:nil contextInfo:nil];
-    }
+    if (msg)
+       [self showError:msg];
 }
 
 - (BOOL)validateMenuItem:(NSMenuItem *)item
@@ -1147,16 +1216,13 @@ struct frontend {
  * Drawing routines called by the midend.
  */
 void draw_polygon(frontend *fe, int *coords, int npoints,
-                  int fill, int colour)
+                  int fillcolour, int outlinecolour)
 {
     NSBezierPath *path = [NSBezierPath bezierPath];
     int i;
 
     [[NSGraphicsContext currentContext] setShouldAntialias:YES];
 
-    assert(colour >= 0 && colour < fe->ncolours);
-    [fe->colours[colour] set];
-
     for (i = 0; i < npoints; i++) {
        NSPoint p = { coords[i*2] + 0.5, coords[i*2+1] + 0.5 };
        if (i == 0)
@@ -1167,10 +1233,37 @@ void draw_polygon(frontend *fe, int *coords, int npoints,
 
     [path closePath];
 
-    if (fill)
+    if (fillcolour >= 0) {
+       assert(fillcolour >= 0 && fillcolour < fe->ncolours);
+       [fe->colours[fillcolour] set];
        [path fill];
-    else
-       [path stroke];
+    }
+
+    assert(outlinecolour >= 0 && outlinecolour < fe->ncolours);
+    [fe->colours[outlinecolour] set];
+    [path stroke];
+}
+void draw_circle(frontend *fe, int cx, int cy, int radius,
+                 int fillcolour, int outlinecolour)
+{
+    NSBezierPath *path = [NSBezierPath bezierPath];
+
+    [[NSGraphicsContext currentContext] setShouldAntialias:YES];
+
+    [path appendBezierPathWithArcWithCenter:NSMakePoint(cx + 0.5, cy + 0.5)
+        radius:radius startAngle:0.0 endAngle:360.0];
+
+    [path closePath];
+
+    if (fillcolour >= 0) {
+       assert(fillcolour >= 0 && fillcolour < fe->ncolours);
+       [fe->colours[fillcolour] set];
+       [path fill];
+    }
+
+    assert(outlinecolour >= 0 && outlinecolour < fe->ncolours);
+    [fe->colours[outlinecolour] set];
+    [path stroke];
 }
 void draw_line(frontend *fe, int x1, int y1, int x2, int y2, int colour)
 {
@@ -1401,6 +1494,8 @@ int main(int argc, char **argv)
     [NSApp setAppleMenu: menu];
 
     menu = newsubmenu([NSApp mainMenu], "File");
+    item = newitem(menu, "Open", "o", NULL, @selector(loadSavedGame:));
+    item = newitem(menu, "Save As", "s", NULL, @selector(saveGame:));
     item = newitem(menu, "New Game", "n", NULL, @selector(newGame:));
     item = newitem(menu, "Restart Game", "r", NULL, @selector(restartGame:));
     item = newitem(menu, "Specific Game", "", NULL, @selector(specificGame:));