use crate::state::app_state::HomeOrAway;
use crate::state::boxscore::BoxscoreState;
use crate::ui::scroll::{ScrollParams, adjust_area_for_scroll, render_scrollbar};
use crate::ui::styling::{header_style, text_style};
use tui::prelude::*;
use tui::widgets::{Block, Borders, Cell, Row, Table};
const BATTER_WIDTHS: [Constraint; 9] = [
Constraint::Length(25), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(5), ];
const BATTING_HEADER: &[&str] = &["player", "ab", "r", "h", "rbi", "bb", "k", "lob", "avg"];
const PITCHER_WIDTHS: [Constraint; 9] = [
Constraint::Length(25), Constraint::Length(5), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(4), Constraint::Length(5), ];
const PITCHING_HEADER: &[&str] = &["pitcher", "ip", "h", "r", "er", "bb", "k", "hr", "era"];
pub struct TeamBatterBoxscoreWidget<'a> {
pub active: HomeOrAway,
pub state: &'a mut BoxscoreState,
}
impl Widget for TeamBatterBoxscoreWidget<'_> {
fn render(mut self, area: Rect, buf: &mut Buffer) {
self.state.sync_scrollbar(area.height, area.width);
if self.state.get_total_content_height() > area.height {
self.render_scrollable(area, buf);
} else {
self.render_static(area, buf);
}
}
}
impl TeamBatterBoxscoreWidget<'_> {
fn render_scrollable(&mut self, area: Rect, buf: &mut Buffer) {
let (batting_height, notes_height, pitching_height, _, total_content_height) =
self.state.get_content_heights(self.active);
let virtual_area = Rect {
x: area.x,
y: 0,
width: area.width,
height: total_content_height,
};
let [boxscore_area, notes_area, pitchers_area, game_notes_area] =
self.get_layout_areas(virtual_area);
let scroll_offset = self.state.scroll as u16;
let params = ScrollParams {
scroll_offset: scroll_offset as i32,
visible_top: area.y as i32,
visible_bottom: (area.y + area.height) as i32,
};
if let Some((visible_boxscore, _)) = adjust_area_for_scroll(boxscore_area, params) {
Widget::render(
create_table(
self.state.get_batting_rows(self.active),
&BATTER_WIDTHS,
BATTING_HEADER,
scroll_offset as usize,
),
visible_boxscore,
buf,
);
}
if let Some((visible_note, _)) = adjust_area_for_scroll(notes_area, params)
&& let Some(paragraph) = self.state.get_batting_notes_paragraph(self.active)
{
let offset = scroll_offset.saturating_sub(batting_height + 1); render_paragraph_with_scroll(paragraph, offset, visible_note, buf);
}
if let Some((visible_pitchers, _)) = adjust_area_for_scroll(pitchers_area, params) {
let offset = scroll_offset
.saturating_sub(batting_height + 1)
.saturating_sub(notes_height + 1); Widget::render(
create_table(
self.state.get_pitching_rows(self.active),
&PITCHER_WIDTHS,
PITCHING_HEADER,
offset as usize,
),
visible_pitchers,
buf,
);
}
if let Some((visible_game_notes, _)) = adjust_area_for_scroll(game_notes_area, params)
&& let Some(paragraph) = self.state.get_game_notes_paragraph()
{
let offset = scroll_offset
.saturating_sub(batting_height + 1)
.saturating_sub(notes_height + 1)
.saturating_sub(pitching_height + 1); render_paragraph_with_scroll(paragraph, offset, visible_game_notes, buf);
}
render_scrollbar(area, &mut self.state.scroll_state, buf);
}
fn render_static(&mut self, area: Rect, buf: &mut Buffer) {
let [boxscore, note, pitchers, game_notes_area] = self.get_layout_areas(area);
Widget::render(
create_table(
self.state.get_batting_rows(self.active),
&BATTER_WIDTHS,
BATTING_HEADER,
0,
),
boxscore,
buf,
);
if let Some(paragraph) = self.state.get_batting_notes_paragraph(self.active) {
Widget::render(paragraph, note, buf);
}
Widget::render(
create_table(
self.state.get_pitching_rows(self.active),
&PITCHER_WIDTHS,
PITCHING_HEADER,
0,
),
pitchers,
buf,
);
if let Some(paragraph) = self.state.get_game_notes_paragraph() {
Widget::render(paragraph, game_notes_area, buf);
}
}
fn get_layout_areas(&mut self, area: Rect) -> [Rect; 4] {
let (batting_height, notes_height, pitching_height, game_notes_height, _) =
self.state.get_content_heights(self.active);
Layout::vertical([
Constraint::Length(batting_height),
Constraint::Length(notes_height),
Constraint::Length(pitching_height),
Constraint::Length(game_notes_height),
])
.spacing(1)
.areas(area)
}
}
fn create_table<'a, I, R>(
rows: I,
widths: &[Constraint],
header: &'static [&'static str],
skip_rows: usize,
) -> Table<'a>
where
I: IntoIterator<Item = R>,
R: IntoIterator<Item = Cell<'a>>,
{
Table::new(rows.into_iter().skip(skip_rows).map(Row::new), widths)
.column_spacing(0)
.style(text_style())
.header(Row::new(header.iter().copied()).style(header_style()))
.block(Block::default().borders(Borders::NONE))
}
fn render_paragraph_with_scroll(
paragraph: &tui::widgets::Paragraph<'static>,
scroll_offset: u16,
area: Rect,
buf: &mut Buffer,
) {
if scroll_offset > 0 {
let scrolled = paragraph.clone().scroll((scroll_offset, 0));
Widget::render(scrolled, area, buf);
} else {
Widget::render(paragraph, area, buf);
};
}