transition
This commit is contained in:
+36
-8
@@ -12,6 +12,7 @@ mod log;
|
||||
mod render;
|
||||
mod scroll_overlay;
|
||||
mod term;
|
||||
mod transition;
|
||||
mod utils;
|
||||
mod speech;
|
||||
mod ui;
|
||||
@@ -25,7 +26,7 @@ use ratatui::crossterm::event::{
|
||||
self, DisableMouseCapture, EnableMouseCapture, Event, KeyEventKind,
|
||||
};
|
||||
use ratatui::crossterm::execute;
|
||||
use ratatui::layout::{Constraint, Layout, Spacing};
|
||||
use ratatui::layout::{Constraint, Layout, Rect, Spacing};
|
||||
use ratatui::symbols::merge::MergeStrategy;
|
||||
use ratatui::widgets::Block;
|
||||
use render::BoardWidget;
|
||||
@@ -37,6 +38,7 @@ use crate::input::{current_input_mode, handle_board_input, handle_scroll_input,
|
||||
use crate::log::{log_preview_line, LogWidget};
|
||||
use crate::scroll_overlay::ScrollOverlayWidget;
|
||||
use crate::speech::SpeechBubblesWidget;
|
||||
use crate::transition::TransitionAnimation;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Entry point: parse the map path, load the board, then run the play loop with
|
||||
@@ -130,12 +132,15 @@ fn run(
|
||||
}
|
||||
let terminal_h = terminal.size()?.height;
|
||||
match current_input_mode(game, ui) {
|
||||
InputMode::Board(log_open) => {
|
||||
if handle_board_input(event, log_open, terminal_h, game, ui) {
|
||||
InputMode::Board | InputMode::Frozen => {
|
||||
if handle_board_input(event, ui.log.open, terminal_h, game, ui) {
|
||||
return Ok(());
|
||||
}
|
||||
ui.post_transition_wait = false;
|
||||
}
|
||||
InputMode::Scroll => handle_scroll_input(event, game, ui),
|
||||
// Wipe is running — discard all events.
|
||||
InputMode::Transition => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +175,7 @@ fn draw(frame: &mut Frame, game: &GameState, ui: &mut Ui) {
|
||||
.merge_borders(MergeStrategy::Exact);
|
||||
let inner = block.inner(board_area);
|
||||
frame.render_widget(block, board_area);
|
||||
frame.render_widget(BoardWidget::new(board), inner);
|
||||
frame.render_widget(SpeechBubblesWidget::new(board, &game.speech_bubbles), inner);
|
||||
draw_board_area(frame, inner, game, ui);
|
||||
frame.render_stateful_widget(LogWidget::new(&game.log), log_area, &mut ui.log);
|
||||
} else {
|
||||
// Panel closed: board fills the screen, latest message in the border.
|
||||
@@ -179,14 +183,38 @@ fn draw(frame: &mut Frame, game: &GameState, ui: &mut Ui) {
|
||||
block = block.title_bottom(log_preview_line(&game.log).left_aligned());
|
||||
let inner = block.inner(frame.area());
|
||||
frame.render_widget(block, frame.area());
|
||||
frame.render_widget(BoardWidget::new(board), inner);
|
||||
frame.render_widget(SpeechBubblesWidget::new(board, &game.speech_bubbles), inner);
|
||||
draw_board_area(frame, inner, game, ui);
|
||||
}
|
||||
|
||||
// Scroll overlay: drawn last so it sits above all other content.
|
||||
if let Some(scroll) = &game.active_scroll {
|
||||
// Suppressed during a wipe — enter_board() already cleared active_scroll.
|
||||
if ui.transition.is_none() && let Some(scroll) = &game.active_scroll {
|
||||
// Capture area before the mutable buffer borrow to satisfy the borrow checker.
|
||||
let area = frame.area();
|
||||
frame.render_stateful_widget(ScrollOverlayWidget::new(scroll), area, &mut ui.overlay);
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders the inner board area: either the active wipe animation or the live board.
|
||||
///
|
||||
/// If `ui.pending_transition` is set, pre-renders both boards into a new
|
||||
/// [`TransitionAnimation`] (now that we know the exact `inner` area) and activates it.
|
||||
fn draw_board_area(frame: &mut Frame, inner: Rect, game: &GameState, ui: &mut Ui) {
|
||||
// Initialize any pending transition now that we know the exact area.
|
||||
if let Some((old_rc, new_rc)) = ui.pending_transition.take() {
|
||||
ui.transition = Some(TransitionAnimation::new(
|
||||
&old_rc.borrow(),
|
||||
&new_rc.borrow(),
|
||||
inner,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(ref tr) = ui.transition {
|
||||
// Wipe in progress: blend old and new board buffers; suppress speech bubbles.
|
||||
frame.render_widget(tr, inner);
|
||||
} else {
|
||||
let board = &game.board();
|
||||
frame.render_widget(BoardWidget::new(board), inner);
|
||||
frame.render_widget(SpeechBubblesWidget::new(board, &game.speech_bubbles), inner);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user