Have resize_screen repaint window 0.
authorTimo Korvola <tkorvola@iki.fi>
Sat, 17 Feb 2018 21:00:12 +0000 (23:00 +0200)
committerTimo Korvola <tkorvola@iki.fi>
Sat, 17 Feb 2018 21:05:50 +0000 (23:05 +0200)
resize_screen decides which part of the window it wants to keep,
adjusts the window properties and calls a new front end function
os_repaint_window to repaint the required part.  Only window 0 currently
has this special handling - for the others it seems to suffice that
curses repaints the screen from the top left.  Resizing now
works pretty well in Beyond Zork as long as the width is not resized
and the height is enough for the upper window.

Also have resize_screen ask V6 games to redraw.  This used to be in
the front end but I can't see how any front end could do anything else
because the interpreter does not know what kind of window layout the
game wants.  So it may as well be in the common code.

#42: Handle terminal resizing

src/common/frotz.h
src/common/screen.c
src/curses/ux_screen.c
src/dumb/dumb_output.c

index ca9335440b3e55c9320dcfb14b40a6f32883c1aa..89626a1f6aef8ba1b39666a9f216abe3b9f54b72 100644 (file)
@@ -788,3 +788,7 @@ void        os_stop_sample ();
 int    os_string_width (const zchar *);
 void   os_init_setup (void);
 void   os_warn (const char *, ...);
+
+/* This is callable only from resize_screen. */
+bool    os_repaint_window (int win, int ypos_old, int ypos_new, int xpos,
+                           int ysize, int xsize);
index c4bda9c77e54c217401f18a80cf1e77d12245984..5d3d19f8ebd2c17f6e33173da4b7ced3e009e350 100644 (file)
@@ -682,8 +682,13 @@ static void erase_screen (zword win)
  */
 void resize_screen (void)
 {
+    /* V6 games are asked to redraw.  Other versions have no means for that
+       so we do what we can. */
+    if (h_version == V6)
+        h_flags |= REFRESH_FLAG;
+    else {
+        int scroll;
 
-    if (h_version != V6) {
        wp[0].x_size = h_screen_width;
        if (wp[0].x_cursor > h_screen_width)
            wp[0].x_cursor = h_screen_width;
@@ -694,10 +699,14 @@ void resize_screen (void)
         if (wp[7].x_cursor > h_screen_width)
             wp[7].x_cursor = h_screen_width;
 
-        /*XXX This needs to be in sync with unix_resize_display. */
+        /*TODO What if this becomes negative? */
        wp[0].y_size = h_screen_height - wp[1].y_size - wp[7].y_size;
-        if (wp[0].y_cursor > wp[0].y_size)
+       scroll = wp[0].y_cursor - wp[0].y_size;
+        if (scroll > 0) {
             wp[0].y_cursor = wp[0].y_size;
+            os_repaint_window(0, wp[0].y_pos + scroll, wp[0].y_pos,
+                              wp[0].x_pos, wp[0].y_size, wp[0].x_size);
+        }
     }
 
 }/* resize_screen */
index 5460cc278ec484c66ccee556cdf889801e07b1ed..b8ce68a7656d25c19e348f01ae155e6973541954 100644 (file)
@@ -138,51 +138,29 @@ void os_scroll_area (int top, int left, int bottom, int right, int units)
 }/* os_scroll_area */
 
 
-/*
- * unix_resize_display
- *
- * Resize the display and redraw.
- *
+/**
+ * Resize the display and redraw.  Retain the old screen starting from the
+ * top left.  Call resize_screen, which may repaint more accurately.
  */
 void unix_resize_display(void)
 {
-    int x, y, start = 0,
-        lines = h_screen_rows, cols = h_screen_cols;
-
-    if ((saved_screen = newpad(lines, cols))
+    if ((saved_screen = newpad(h_screen_rows, h_screen_cols))
         && overwrite(stdscr, saved_screen) == ERR) {
         delwin(saved_screen);
         saved_screen = NULL;
     }
-    getyx(stdscr, y, x);
+    if (saved_screen) {
+        int y, x;
+        getyx(stdscr, y, x);
+        wmove(saved_screen, y, x);
+    }
 
     endwin();
     refresh();
     unix_get_terminal_size();
-    if (lines > h_screen_rows) {
-        lines = h_screen_rows;
-        if (y >= h_screen_rows) {
-            /* Lose some topmost lines to keep the cursor on screen. */
-            start = y + 1 - h_screen_rows;
-            y = h_screen_rows - 1;
-        }
-    }
-    if (cols > h_screen_cols)
-        cols = h_screen_cols;
-    if (x >= h_screen_cols)
-        x = h_screen_cols - 1;
-    if (saved_screen)
-        copywin(saved_screen, stdscr, start, 0, 0, 0,
-                lines - 1, cols - 1, FALSE);
-    move(y, x);
-    refresh();
-
-    /* Notify the game that the display needs refreshing */
-    if (h_version == V6)
-       h_flags |= REFRESH_FLAG;
 
+    resize_screen();
     if (zmp != NULL) {
-       resize_screen();
        restart_header();
     }
     if (saved_screen) {
@@ -190,3 +168,46 @@ void unix_resize_display(void)
         saved_screen = NULL;
     }
 }/* unix_redraw_display */
+
+
+/**
+ * Repaint a window.
+ *
+ * This can only be called from resize_screen.  It copies part of the screen
+ * as it was before the resize onto the current screen.  The source and
+ * destination rectangles may start at different rows but the columns
+ * are the same.  Positions are 1-based.  win should be the index
+ * of the window that is being repainted.  If it equals the current window,
+ * the saved cursor position adjusted by ypos_new - ypos_old is also restored.
+ *
+ * The copied rectangle is clipped to the saved window size.  Returns true
+ * on success, false if anything went wrong.
+ */
+bool os_repaint_window(int win, int ypos_old, int ypos_new, int xpos,
+                       int ysize, int xsize)
+{
+    int lines, cols;
+    if (!saved_screen)
+        return false;
+    getmaxyx(saved_screen, lines, cols);
+    ypos_old--, ypos_new--, xpos--;
+    if (xpos + xsize > cols)
+        xsize = cols - xpos;
+    if (ypos_old + ysize > lines)
+        ysize = lines - ypos_old;
+    /* Most of the time we are in os_read_line, where the cursor position
+       is different from that in the window properties.  So use the real cursor
+       position. */
+    if (win == cwin) {
+        int y, x;
+        getyx(saved_screen, y, x);
+        y += ypos_new - ypos_old;
+        if (y >= ypos_new && y< ypos_new + ysize
+            && x >= xpos && x < xpos + xsize)
+            move(y, x);
+    }
+    if (xsize <= 0 || ysize <= 0)
+        return false;
+    return copywin(saved_screen, stdscr, ypos_old, xpos, ypos_new, xpos,
+                   ypos_new + ysize - 1, xpos + xsize - 1, FALSE) != ERR;
+}
index f2e2d4d836a4d53a7204bd6584ff45a16f4e4cb7..95252ad6b5f5de4e1c3a7a9b41ffdd65d5747fb1 100644 (file)
@@ -116,6 +116,10 @@ void os_set_cursor(int row, int col)
        cursor_row = h_screen_rows - 1;
 }
 
+void os_repaint_window(int win, int ypos_old, int ypos_new, int xpos,
+                       int ysize, int xsize)
+{}
+
 /* Set a cell and update screen_changes.  */
 static void dumb_set_cell(int row, int col, cell c)
 {