From: Timo Korvola Date: Sat, 17 Feb 2018 21:00:12 +0000 (+0200) Subject: Have resize_screen repaint window 0. X-Git-Url: https://scope-eye.net/git/?a=commitdiff_plain;h=b6d96e615cda223adeca813996990be5b54ffbc7;p=liskon_frotz.git Have resize_screen repaint window 0. 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 --- diff --git a/src/common/frotz.h b/src/common/frotz.h index ca93354..89626a1 100644 --- a/src/common/frotz.h +++ b/src/common/frotz.h @@ -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); diff --git a/src/common/screen.c b/src/common/screen.c index c4bda9c..5d3d19f 100644 --- a/src/common/screen.c +++ b/src/common/screen.c @@ -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 */ diff --git a/src/curses/ux_screen.c b/src/curses/ux_screen.c index 5460cc2..b8ce68a 100644 --- a/src/curses/ux_screen.c +++ b/src/curses/ux_screen.c @@ -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; +} diff --git a/src/dumb/dumb_output.c b/src/dumb/dumb_output.c index f2e2d4d..95252ad 100644 --- a/src/dumb/dumb_output.c +++ b/src/dumb/dumb_output.c @@ -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) {