Added responsiveness to board layout
This commit is contained in:
parent
d7f7b84905
commit
4b4ab92d04
1 changed files with 90 additions and 11 deletions
|
|
@ -817,6 +817,64 @@ TOP_Y = 1
|
||||||
COL_Y = 6
|
COL_Y = 6
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BoardLayout:
|
||||||
|
"""Computed horizontal positions for the current terminal width."""
|
||||||
|
|
||||||
|
freecell_xs: Tuple[int, ...]
|
||||||
|
foundation_xs: Tuple[int, ...]
|
||||||
|
tableau_xs: Tuple[int, ...]
|
||||||
|
freecells_label_x: int
|
||||||
|
foundations_label_x: int
|
||||||
|
tableau_label_x: int
|
||||||
|
|
||||||
|
|
||||||
|
def spread_positions(count: int, start_x: int, end_x: int) -> Tuple[int, ...]:
|
||||||
|
"""Evenly spread fixed-width slots between two inclusive bounds."""
|
||||||
|
if count <= 1:
|
||||||
|
return (start_x,)
|
||||||
|
|
||||||
|
span = max(0, end_x - start_x)
|
||||||
|
step = span / (count - 1)
|
||||||
|
positions = []
|
||||||
|
for index in range(count):
|
||||||
|
positions.append(int(round(start_x + step * index)))
|
||||||
|
return tuple(positions)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_board_layout(max_x: int) -> BoardLayout:
|
||||||
|
"""Compute a centered, width-aware board layout."""
|
||||||
|
left_margin = 2
|
||||||
|
right_margin = max(left_margin, max_x - CARD_W - 2)
|
||||||
|
|
||||||
|
if max_x < 72:
|
||||||
|
top_start = left_margin
|
||||||
|
top_end = max(top_start, max_x - CARD_W - 2)
|
||||||
|
top_positions = spread_positions(8, top_start, top_end)
|
||||||
|
freecell_xs = top_positions[:4]
|
||||||
|
foundation_xs = top_positions[4:]
|
||||||
|
else:
|
||||||
|
center_gap = max(10, min(20, max_x // 6))
|
||||||
|
left_end = max(left_margin, (max_x // 2) - (center_gap // 2) - CARD_W)
|
||||||
|
right_start = min(right_margin, (max_x // 2) + (center_gap // 2))
|
||||||
|
freecell_xs = spread_positions(4, left_margin, left_end)
|
||||||
|
foundation_xs = spread_positions(4, right_start, right_margin)
|
||||||
|
|
||||||
|
tableau_xs = spread_positions(8, left_margin, right_margin)
|
||||||
|
freecells_label_x = freecell_xs[0]
|
||||||
|
foundations_label_x = foundation_xs[0]
|
||||||
|
tableau_label_x = tableau_xs[0]
|
||||||
|
|
||||||
|
return BoardLayout(
|
||||||
|
freecell_xs=freecell_xs,
|
||||||
|
foundation_xs=foundation_xs,
|
||||||
|
tableau_xs=tableau_xs,
|
||||||
|
freecells_label_x=freecells_label_x,
|
||||||
|
foundations_label_x=foundations_label_x,
|
||||||
|
tableau_label_x=tableau_label_x,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def init_colors() -> None:
|
def init_colors() -> None:
|
||||||
"""Initialize curses color pairs."""
|
"""Initialize curses color pairs."""
|
||||||
curses.start_color()
|
curses.start_color()
|
||||||
|
|
@ -859,14 +917,24 @@ def draw_card_label(card: Optional[Card]) -> str:
|
||||||
return card.short_name()
|
return card.short_name()
|
||||||
|
|
||||||
|
|
||||||
def draw_top_row(stdscr, game: FreeCellGame) -> None:
|
def draw_top_row(stdscr, game: FreeCellGame, layout: BoardLayout) -> None:
|
||||||
"""Draw freecells and foundations."""
|
"""Draw freecells and foundations."""
|
||||||
stdscr.addstr(TOP_Y, 2, "Free Cells", curses.color_pair(1) | curses.A_BOLD)
|
stdscr.addstr(
|
||||||
stdscr.addstr(TOP_Y, 40, "Foundations", curses.color_pair(1) | curses.A_BOLD)
|
TOP_Y,
|
||||||
|
layout.freecells_label_x,
|
||||||
|
"Free Cells",
|
||||||
|
curses.color_pair(1) | curses.A_BOLD,
|
||||||
|
)
|
||||||
|
stdscr.addstr(
|
||||||
|
TOP_Y,
|
||||||
|
layout.foundations_label_x,
|
||||||
|
"Foundations",
|
||||||
|
curses.color_pair(1) | curses.A_BOLD,
|
||||||
|
)
|
||||||
|
|
||||||
# Freecells at indexes 0..3
|
# Freecells at indexes 0..3
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
x = 2 + i * (CARD_W + 1)
|
x = layout.freecell_xs[i]
|
||||||
selected = game.cursor_zone == "top" and game.cursor_index == i
|
selected = game.cursor_zone == "top" and game.cursor_index == i
|
||||||
hinted = game.hinted_freecell(i)
|
hinted = game.hinted_freecell(i)
|
||||||
attr = (
|
attr = (
|
||||||
|
|
@ -891,7 +959,7 @@ def draw_top_row(stdscr, game: FreeCellGame) -> None:
|
||||||
|
|
||||||
# Foundations at indexes 4..7 in cursor space
|
# Foundations at indexes 4..7 in cursor space
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
x = 40 + i * (CARD_W + 1)
|
x = layout.foundation_xs[i]
|
||||||
selected = game.cursor_zone == "top" and game.cursor_index == i + 4
|
selected = game.cursor_zone == "top" and game.cursor_index == i + 4
|
||||||
hinted = game.hinted_foundation(i)
|
hinted = game.hinted_foundation(i)
|
||||||
attr = (
|
attr = (
|
||||||
|
|
@ -923,14 +991,19 @@ def draw_top_row(stdscr, game: FreeCellGame) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def draw_columns(stdscr, game: FreeCellGame) -> None:
|
def draw_columns(stdscr, game: FreeCellGame, layout: BoardLayout) -> None:
|
||||||
"""Draw the tableau columns."""
|
"""Draw the tableau columns."""
|
||||||
stdscr.addstr(COL_Y - 1, 2, "Tableau", curses.color_pair(1) | curses.A_BOLD)
|
stdscr.addstr(
|
||||||
|
COL_Y - 1,
|
||||||
|
layout.tableau_label_x,
|
||||||
|
"Tableau",
|
||||||
|
curses.color_pair(1) | curses.A_BOLD,
|
||||||
|
)
|
||||||
|
|
||||||
max_height = max((len(col) for col in game.columns), default=0)
|
max_height = max((len(col) for col in game.columns), default=0)
|
||||||
|
|
||||||
for col_idx in range(8):
|
for col_idx in range(8):
|
||||||
x = 2 + col_idx * 9
|
x = layout.tableau_xs[col_idx]
|
||||||
selected = game.cursor_zone == "bottom" and game.cursor_index == col_idx
|
selected = game.cursor_zone == "bottom" and game.cursor_index == col_idx
|
||||||
hinted_dest = game.hinted_column_destination(col_idx)
|
hinted_dest = game.hinted_column_destination(col_idx)
|
||||||
header_attr = (
|
header_attr = (
|
||||||
|
|
@ -1042,6 +1115,7 @@ def render(stdscr, game: FreeCellGame) -> None:
|
||||||
"""Redraw the full screen."""
|
"""Redraw the full screen."""
|
||||||
stdscr.erase()
|
stdscr.erase()
|
||||||
max_y, max_x = stdscr.getmaxyx()
|
max_y, max_x = stdscr.getmaxyx()
|
||||||
|
layout = compute_board_layout(max_x)
|
||||||
|
|
||||||
title = "mcfreecell 0.1"
|
title = "mcfreecell 0.1"
|
||||||
if len(title) > max_x - 4:
|
if len(title) > max_x - 4:
|
||||||
|
|
@ -1056,10 +1130,15 @@ def render(stdscr, game: FreeCellGame) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
if game.visual_mode:
|
if game.visual_mode:
|
||||||
stdscr.addstr(0, 30, "-- VISUAL --", curses.color_pair(5) | curses.A_BOLD)
|
visual_text = "-- VISUAL --"
|
||||||
|
visual_x = min(max_x - len(visual_text) - 2, title_x + len(title) + 3)
|
||||||
|
if visual_x > title_x + len(title):
|
||||||
|
stdscr.addstr(
|
||||||
|
0, visual_x, visual_text, curses.color_pair(5) | curses.A_BOLD
|
||||||
|
)
|
||||||
|
|
||||||
draw_top_row(stdscr, game)
|
draw_top_row(stdscr, game, layout)
|
||||||
draw_columns(stdscr, game)
|
draw_columns(stdscr, game, layout)
|
||||||
draw_held(stdscr, game, max_y)
|
draw_held(stdscr, game, max_y)
|
||||||
draw_status(stdscr, game, max_y)
|
draw_status(stdscr, game, max_y)
|
||||||
draw_help(stdscr, max_y)
|
draw_help(stdscr, max_y)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue