Added a status bar.
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 29 Apr 2004 19:23:08 +0000 (19:23 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 29 Apr 2004 19:23:08 +0000 (19:23 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/puzzles@4174 cda61777-01e9-0310-a592-d414129be87e

Recipe
cube.c
fifteen.c
gtk.c
midend.c
net.c
nullgame.c
puzzles.h
sixteen.c
windows.c

diff --git a/Recipe b/Recipe
index 19ca3a5..a2a5bfc 100644 (file)
--- a/Recipe
+++ b/Recipe
@@ -12,7 +12,7 @@
 !makefile vc Makefile.vc
 !makefile cygwin Makefile.cyg
 
-WINDOWS  = windows user32.lib gdi32.lib
+WINDOWS  = windows user32.lib gdi32.lib comctl32.lib
 COMMON   = midend misc malloc
 NET      = net random tree234
 
diff --git a/cube.c b/cube.c
index 6fef4d1..5940c8b 100644 (file)
--- a/cube.c
+++ b/cube.c
@@ -788,7 +788,7 @@ game_state *new_game(game_params *params, char *seed)
 
     state->previous = state->current;
     state->angle = 0.0;
-    state->completed = FALSE;
+    state->completed = 0;
     state->movecount = 0;
 
     return state;
@@ -1068,7 +1068,7 @@ game_state *make_move(game_state *from, int x, int y, int button)
             if (ret->facecolours[i])
                 j++;
         if (j == ret->solid->nfaces)
-            ret->completed = TRUE;
+            ret->completed = ret->movecount;
     }
 
     sfree(poly);
@@ -1329,6 +1329,19 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
 
     draw_update(fe, 0, 0, (int)((bb.r-bb.l+2.0F) * GRID_SCALE),
                 (int)((bb.d-bb.u+2.0F) * GRID_SCALE));
+
+    /*
+     * Update the status bar.
+     */
+    {
+       char statusbuf[256];
+
+       sprintf(statusbuf, "%sMoves: %d",
+               (state->completed ? "COMPLETED! " : ""),
+               (state->completed ? state->completed : state->movecount));
+
+       status_bar(fe, statusbuf);
+    }
 }
 
 float game_anim_length(game_state *oldstate, game_state *newstate)
@@ -1340,3 +1353,8 @@ float game_flash_length(game_state *oldstate, game_state *newstate)
 {
     return 0.0F;
 }
+
+int game_wants_statusbar(void)
+{
+    return TRUE;
+}
index 9357d65..b3285e7 100644 (file)
--- a/fifteen.c
+++ b/fifteen.c
@@ -42,6 +42,7 @@ struct game_state {
     int *tiles;
     int gap_pos;
     int completed;
+    int movecount;
 };
 
 game_params *default_params(void)
@@ -224,7 +225,7 @@ game_state *new_game(game_params *params, char *seed)
     assert(!*p);
     assert(state->tiles[state->gap_pos] == 0);
 
-    state->completed = FALSE;
+    state->completed = state->movecount = 0;
 
     return state;
 }
@@ -240,6 +241,7 @@ game_state *dup_game(game_state *state)
     memcpy(ret->tiles, state->tiles, state->w * state->h * sizeof(int));
     ret->gap_pos = state->gap_pos;
     ret->completed = state->completed;
+    ret->movecount = state->movecount;
 
     return ret;
 }
@@ -297,16 +299,17 @@ game_state *make_move(game_state *from, int x, int y, int button)
     for (p = from->gap_pos; p != ret->gap_pos; p += up) {
         assert(p >= 0 && p < from->n);
         ret->tiles[p] = from->tiles[p + up];
+       ret->movecount++;
     }
 
     /*
      * See if the game has been completed.
      */
     if (!ret->completed) {
-        ret->completed = TRUE;
+        ret->completed = ret->movecount;
         for (p = 0; p < ret->n; p++)
             if (ret->tiles[p] != (p < ret->n-1 ? p+1 : 0))
-                ret->completed = FALSE;
+                ret->completed = 0;
     }
 
     return ret;
@@ -544,6 +547,19 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
         }
     }
     ds->bgcolour = bgcolour;
+
+    /*
+     * Update the status bar.
+     */
+    {
+       char statusbuf[256];
+
+       sprintf(statusbuf, "%sMoves: %d",
+               (state->completed ? "COMPLETED! " : ""),
+               (state->completed ? state->completed : state->movecount));
+
+       status_bar(fe, statusbuf);
+    }
 }
 
 float game_anim_length(game_state *oldstate, game_state *newstate)
@@ -558,3 +574,8 @@ float game_flash_length(game_state *oldstate, game_state *newstate)
     else
         return 0.0F;
 }
+
+int game_wants_statusbar(void)
+{
+    return TRUE;
+}
diff --git a/gtk.c b/gtk.c
index 778868a..9ffc96a 100644 (file)
--- a/gtk.c
+++ b/gtk.c
@@ -3,6 +3,7 @@
  */
 
 #include <stdio.h>
+#include <assert.h>
 #include <stdlib.h>
 #include <time.h>
 #include <stdarg.h>
@@ -50,6 +51,8 @@ struct font {
 struct frontend {
     GtkWidget *window;
     GtkWidget *area;
+    GtkWidget *statusbar;
+    guint statusctx;
     GdkPixmap *pixmap;
     GdkColor *colours;
     int ncolours;
@@ -71,6 +74,14 @@ void frontend_default_colour(frontend *fe, float *output)
     output[2] = col.blue / 65535.0;
 }
 
+void status_bar(frontend *fe, char *text)
+{
+    assert(fe->statusbar);
+
+    gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx);
+    gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, text);
+}
+
 void start_draw(frontend *fe)
 {
     fe->gc = gdk_gc_new(fe->area->window);
@@ -299,6 +310,21 @@ static gint expose_area(GtkWidget *widget, GdkEventExpose *event,
     return TRUE;
 }
 
+static gint map_window(GtkWidget *widget, GdkEvent *event,
+                      gpointer data)
+{
+    frontend *fe = (frontend *)data;
+
+    /*
+     * Apparently we need to do this because otherwise the status
+     * bar will fail to update immediately. Annoying, but there we
+     * go.
+     */
+    gtk_widget_queue_draw(fe->window);
+
+    return TRUE;
+}
+
 static gint configure_area(GtkWidget *widget,
                            GdkEventConfigure *event, gpointer data)
 {
@@ -483,6 +509,17 @@ static frontend *new_window(void)
         }
     }
 
+    if (midend_wants_statusbar(fe->me)) {
+       fe->statusbar = gtk_statusbar_new();
+       gtk_box_pack_end(vbox, fe->statusbar, FALSE, FALSE, 0);
+       gtk_widget_show(fe->statusbar);
+       fe->statusctx = gtk_statusbar_get_context_id
+           (GTK_STATUSBAR(fe->statusbar), "game");
+       gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx,
+                          "");
+    } else
+       fe->statusbar = NULL;
+
     fe->area = gtk_drawing_area_new();
     midend_size(fe->me, &x, &y);
     gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
@@ -505,6 +542,8 @@ static frontend *new_window(void)
                       GTK_SIGNAL_FUNC(button_event), fe);
     gtk_signal_connect(GTK_OBJECT(fe->area), "expose_event",
                       GTK_SIGNAL_FUNC(expose_area), fe);
+    gtk_signal_connect(GTK_OBJECT(fe->window), "map_event",
+                      GTK_SIGNAL_FUNC(map_window), fe);
     gtk_signal_connect(GTK_OBJECT(fe->area), "configure_event",
                       GTK_SIGNAL_FUNC(configure_area), fe);
 
index 3b1a0e4..79e6d7d 100644 (file)
--- a/midend.c
+++ b/midend.c
@@ -294,3 +294,8 @@ void midend_fetch_preset(midend_data *me, int n,
     *name = me->preset_names[n];
     *params = me->presets[n];
 }
+
+int midend_wants_statusbar(midend_data *me)
+{
+    return game_wants_statusbar();
+}
diff --git a/net.c b/net.c
index 268fbca..c345ecb 100644 (file)
--- a/net.c
+++ b/net.c
@@ -1189,6 +1189,24 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
             }
         }
 
+    /*
+     * Update the status bar.
+     */
+    {
+       char statusbuf[256];
+       int i, n, a;
+
+       n = state->width * state->height;
+       for (i = a = 0; i < n; i++)
+           if (active[i])
+               a++;
+
+       sprintf(statusbuf, "%sActive: %d/%d",
+               (state->completed ? "COMPLETED! " : ""), a, n);
+
+       status_bar(fe, statusbuf);
+    }
+
     sfree(active);
 }
 
@@ -1231,3 +1249,8 @@ float game_flash_length(game_state *oldstate, game_state *newstate)
 
     return 0.0F;
 }
+
+int game_wants_statusbar(void)
+{
+    return TRUE;
+}
index 5ce6f07..3d278ad 100644 (file)
@@ -144,3 +144,8 @@ float game_flash_length(game_state *oldstate, game_state *newstate)
 {
     return 0.0F;
 }
+
+int game_wants_statusbar(void)
+{
+    return FALSE;
+}
index cb276e2..0c5dec4 100644 (file)
--- a/puzzles.h
+++ b/puzzles.h
@@ -65,6 +65,7 @@ void draw_update(frontend *fe, int x, int y, int w, int h);
 void end_draw(frontend *fe);
 void deactivate_timer(frontend *fe);
 void activate_timer(frontend *fe);
+void status_bar(frontend *fe, char *text);
 
 /*
  * midend.c
@@ -82,6 +83,7 @@ void midend_timer(midend_data *me, float tplus);
 int midend_num_presets(midend_data *me);
 void midend_fetch_preset(midend_data *me, int n,
                          char **name, game_params **params);
+int midend_wants_statusbar(midend_data *me);
 
 /*
  * malloc.c
@@ -130,5 +132,6 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
                  game_state *newstate, float anim_time, float flash_time);
 float game_anim_length(game_state *oldstate, game_state *newstate);
 float game_flash_length(game_state *oldstate, game_state *newstate);
+int game_wants_statusbar(void);
 
 #endif /* PUZZLES_PUZZLES_H */
index bc21964..89eef4f 100644 (file)
--- a/sixteen.c
+++ b/sixteen.c
@@ -43,6 +43,7 @@ struct game_state {
     int w, h, n;
     int *tiles;
     int completed;
+    int movecount;
 };
 
 game_params *default_params(void)
@@ -231,7 +232,7 @@ game_state *new_game(game_params *params, char *seed)
     }
     assert(!*p);
 
-    state->completed = FALSE;
+    state->completed = state->movecount = 0;
 
     return state;
 }
@@ -246,6 +247,7 @@ game_state *dup_game(game_state *state)
     ret->tiles = snewn(state->w * state->h, int);
     memcpy(ret->tiles, state->tiles, state->w * state->h * sizeof(int));
     ret->completed = state->completed;
+    ret->movecount = state->movecount;
 
     return ret;
 }
@@ -287,11 +289,13 @@ game_state *make_move(game_state *from, int x, int y, int button)
         ret->tiles[C(ret, cx, cy)] = from->tiles[C(from, tx, ty)];
     } while (--n > 0);
 
+    ret->movecount++;
+
     /*
      * See if the game has been completed.
      */
     if (!ret->completed) {
-        ret->completed = TRUE;
+        ret->completed = ret->movecount;
         for (n = 0; n < ret->n; n++)
             if (ret->tiles[n] != n+1)
                 ret->completed = FALSE;
@@ -588,6 +592,19 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
     unclip(fe);
 
     ds->bgcolour = bgcolour;
+
+    /*
+     * Update the status bar.
+     */
+    {
+       char statusbuf[256];
+
+       sprintf(statusbuf, "%sMoves: %d",
+               (state->completed ? "COMPLETED! " : ""),
+               (state->completed ? state->completed : state->movecount));
+
+       status_bar(fe, statusbuf);
+    }
 }
 
 float game_anim_length(game_state *oldstate, game_state *newstate)
@@ -602,3 +619,8 @@ float game_flash_length(game_state *oldstate, game_state *newstate)
     else
         return 0.0F;
 }
+
+int game_wants_statusbar(void)
+{
+    return TRUE;
+}
index ea5d7a2..507203e 100644 (file)
--- a/windows.c
+++ b/windows.c
@@ -3,6 +3,7 @@
  */
 
 #include <windows.h>
+#include <commctrl.h>
 
 #include <stdio.h>
 #include <assert.h>
@@ -72,7 +73,7 @@ struct font {
 
 struct frontend {
     midend_data *me;
-    HWND hwnd;
+    HWND hwnd, statusbar;
     HBITMAP bitmap, prevbm;
     HDC hdc_bm;
     COLORREF *colours;
@@ -100,6 +101,11 @@ void fatal(char *fmt, ...)
     exit(1);
 }
 
+void status_bar(frontend *fe, char *text)
+{
+    SetWindowText(fe->statusbar, text);
+}
+
 void frontend_default_colour(frontend *fe, float *output)
 {
     DWORD c = GetSysColor(COLOR_MENU); /* ick */
@@ -291,7 +297,7 @@ static frontend *new_window(HINSTANCE inst)
 {
     frontend *fe;
     int x, y;
-    RECT r;
+    RECT r, sr;
     HDC hdc;
 
     fe = snew(frontend);
@@ -374,6 +380,21 @@ static frontend *new_window(HINSTANCE inst)
        SetMenu(fe->hwnd, bar);
     }
 
+    if (midend_wants_statusbar(fe->me)) {
+       fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
+                                      WS_CHILD | WS_VISIBLE,
+                                      0, 0, 0, 0, /* status bar does these */
+                                      fe->hwnd, NULL, inst, NULL);
+       GetWindowRect(fe->statusbar, &sr);
+       SetWindowPos(fe->hwnd, NULL, 0, 0,
+                    r.right - r.left, r.bottom - r.top + sr.bottom - sr.top,
+                    SWP_NOMOVE | SWP_NOZORDER);
+       SetWindowPos(fe->statusbar, NULL, 0, y, x, sr.bottom - sr.top,
+                    SWP_NOZORDER);
+    } else {
+       fe->statusbar = NULL;
+    }
+
     hdc = GetDC(fe->hwnd);
     fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
     ReleaseDC(fe->hwnd, hdc);
@@ -424,7 +445,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10;
 
                if (p >= 0 && p < fe->npresets) {
-                   RECT r;
+                   RECT r, sr;
                    HDC hdc;
                    int x, y;
 
@@ -440,9 +461,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                                        WS_OVERLAPPED),
                                       TRUE, 0);
 
+                   if (fe->statusbar != NULL) {
+                       GetWindowRect(fe->statusbar, &sr);
+                   } else {
+                       sr.left = sr.right = sr.top = sr.bottom = 0;
+                   }
                    SetWindowPos(fe->hwnd, NULL, 0, 0,
-                                r.right - r.left, r.bottom - r.top,
+                                r.right - r.left,
+                                r.bottom - r.top + sr.bottom - sr.top,
                                 SWP_NOMOVE | SWP_NOZORDER);
+                   if (fe->statusbar != NULL)
+                       SetWindowPos(fe->statusbar, NULL, 0, y, x,
+                                    sr.bottom - sr.top, SWP_NOZORDER);
 
                    DeleteObject(fe->bitmap);
 
@@ -572,6 +602,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 
     srand(time(NULL));
 
+    InitCommonControls();
+
     if (!prev) {
        WNDCLASS wndclass;