]> git.draconx.ca Git - rrace.git/commitdiff
curses: Add timer display.
authorNick Bowler <nbowler@draconx.ca>
Sat, 11 Jun 2022 22:55:39 +0000 (18:55 -0400)
committerNick Bowler <nbowler@draconx.ca>
Sun, 12 Jun 2022 15:56:25 +0000 (11:56 -0400)
It seems timeouts interact very weirdly with mouse support in ncurses,
but enabling all the button events appears to avoid serious problems.

src/curses.c

index d5b1cc4be149681d9a383183adb3493c97f4bd79..6d86101c41f354236ce6f82fe3a694916613ae84 100644 (file)
@@ -49,6 +49,7 @@ static struct app_state {
        struct board board;
 
        WINDOW *gamewin[WINDOW_MAX], *goalwin[WINDOW_MAX];
+       WINDOW *timer;
        int cursor;
 } state;
 
@@ -288,6 +289,10 @@ static void setup_mainwin(struct app_state *state)
        w = MIN(scr_w-split, 3+6*goalsz);
        h = MIN(scr_h-GAME_YPOS, 2+3*goalsz);
        realloc_area(&state->goalwin[WINDOW_AREA], h, w, GAME_YPOS, split);
+
+       /* Status area */
+       w = MAX(0, scr_w-split-1);
+       realloc_area(&state->timer, 1, w, GAME_YPOS+h, split+1);
 }
 
 static void app_initialize(int argc, char **argv)
@@ -319,7 +324,7 @@ static void app_initialize(int argc, char **argv)
        }
 
        game_reset(&state.board);
-       state.cursor = 5*state.board.y + state.board.x;
+       state.cursor = -1;
 
        initscr();
        start_color();
@@ -328,14 +333,36 @@ static void app_initialize(int argc, char **argv)
        cbreak();
        keypad(stdscr, TRUE);
        if (enable_mouse) {
+               /*
+                * While we only care about a subset of these events, for
+                * some reason with ncurses failing to enable all of them
+                * causes timeout to stop working when disabled buttons are
+                * pressed (or released).
+                *
+                * It is not known if other curses have this problem; at least
+                * pdcurses does not, but the extra events should be harmless
+                * in any case.
+                */
+#if HAVE_CURSES_MOUSE_SUPPORT
+               unsigned long mask = BUTTON1_PRESSED | BUTTON1_RELEASED
+                                   | BUTTON2_PRESSED | BUTTON2_RELEASED
+                                   | BUTTON3_PRESSED | BUTTON3_RELEASED
+#ifdef BUTTON4_PRESSED
+                                   | BUTTON4_PRESSED | BUTTON4_RELEASED
+#endif
+#ifdef BUTTON5_PRESSED
+                                   | BUTTON5_PRESSED | BUTTON5_RELEASED
+#endif
+                                   ;
 #if HAVE_CURSES_MOUSE_SET
-               mouse_set(BUTTON1_PRESSED);
+               mouse_set(mask);
 #elif HAVE_CURSES_MOUSEMASK
-               mousemask(BUTTON1_PRESSED, NULL);
+               mousemask(mask, NULL);
 #endif
 #if HAVE_CURSES_MOUSEINTERVAL
                mouseinterval(0);
 #endif
+#endif /* HAVE_CURSES_MOUSE_SUPPORT */
        }
 
        noecho();
@@ -358,12 +385,43 @@ static uint_fast32_t do_move(struct app_state *state, int x, int y)
 
        if ((mask = game_do_move(&state->board, x, y)) != 0) {
                curs_redraw_game(state, mask);
-               refresh();
+               doupdate();
        }
 
        return mask;
 }
 
+static void do_reset_cursor(struct app_state *state)
+{
+       state->cursor = 5*state->board.y + state->board.x;
+}
+
+static void update_timer(struct app_state *state, uint_fast32_t ms)
+{
+       unsigned sec, min;
+
+       sec = ms / 1000; ms %= 1000;
+       min = sec / 60; sec %= 60;
+       mvwprintw(state->timer, 0, 0, "Time: %u:%.2u.%.3u",
+                 min, sec, (unsigned)ms);
+       wclrtoeol(state->timer);
+       wrefresh(state->timer);
+}
+
+static void do_new_game(struct app_state *state)
+{
+       game_reset(&state->board);
+
+       do_reset_cursor(state);
+       curs_redraw_game(state, -1);
+       curs_redraw_goal(state, -1);
+       update_timer(state, 0);
+       doupdate();
+
+       timeout(33);
+       game_begin(&state->board);
+}
+
 #if HAVE_CURSES_MOUSE_SUPPORT
 static void do_mouse(struct app_state *state)
 {
@@ -384,12 +442,16 @@ static void do_mouse(struct app_state *state)
        y = MOUSE_Y_POS;
 
        bstate = 0;
-       if (BUTTON_CHANGED(1)) {
-               switch (BUTTON_STATUS(1)) {
-               case BUTTON_RELEASED: bstate |= BUTTON1_RELEASED;
-               case BUTTON_PRESSED:  bstate |= BUTTON1_PRESSED;
-               }
-       }
+
+#define set_bstate_helper(button) do { if (BUTTON_CHANGED(button)) \
+       switch (BUTTON_STATUS(button)) { \
+       case BUTTON_RELEASED: bstate |= BUTTON ## button ##  _RELEASED; break; \
+       case BUTTON_PRESSED:  bstate |= BUTTON ## button ##  _PRESSED; break; \
+       } \
+} while (0);
+
+       set_bstate_helper(1);
+       set_bstate_helper(3);
 #endif
        if (bstate == BUTTON1_PRESSED) {
                uint_fast32_t cursor_mask, move_mask;
@@ -409,7 +471,7 @@ static void do_mouse(struct app_state *state)
                move_mask = do_move(state, x/w, y/h);
                if ((cursor_mask & move_mask) == 0) {
                        curs_redraw_game(state, cursor_mask);
-                       refresh();
+                       doupdate();
                }
        }
 }
@@ -420,8 +482,8 @@ static void do_move_cursor(struct app_state *state, int c)
        uint_fast32_t mask = 1ul << state->cursor;
 
        if (state->cursor < 0) {
-               /* Reset keyboard cursor to the empty position */
-               state->cursor = 5*state->board.y + state->board.x;
+               /* Cursor was hidden; reset it */
+               do_reset_cursor(state);
        }
 
        switch (c) {
@@ -465,9 +527,7 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, "");
        app_initialize(argc, argv);
 
-       curs_redraw_game(&state, -1);
-       curs_redraw_goal(&state, -1);
-       refresh();
+       do_new_game(&state);
 
        while (1) {
                int c = getch();
@@ -490,6 +550,9 @@ int main(int argc, char **argv)
 #endif
                default:
                        do_keystroke(&state, c);
+               case ERR:;
                }
+
+               update_timer(&state, game_elapsed(&state.board));
        }
 }