From 0ae0bf73b23a86b410e0ca618ec365a93b4d73a6 Mon Sep 17 00:00:00 2001 From: Arthur Roberts Date: Wed, 26 Feb 2025 19:26:17 +0000 Subject: [PATCH] Added deck and the start of the waste I think I'm going to need some mode advanced widget that I make myself though --- card_stuffs/src/lib.rs | 1 + card_stuffs/src/main.rs | 125 +++++++++++++++++++++++++++++++++------- 2 files changed, 105 insertions(+), 21 deletions(-) diff --git a/card_stuffs/src/lib.rs b/card_stuffs/src/lib.rs index 88f65f9..b3090fc 100644 --- a/card_stuffs/src/lib.rs +++ b/card_stuffs/src/lib.rs @@ -97,6 +97,7 @@ impl fmt::Display for Value { } } + #[derive(PartialEq, Debug, Copy, Clone)] pub struct Card { pub suit: Suit, diff --git a/card_stuffs/src/main.rs b/card_stuffs/src/main.rs index b4ce34b..913cfed 100644 --- a/card_stuffs/src/main.rs +++ b/card_stuffs/src/main.rs @@ -1,27 +1,88 @@ use std::io; -use card_stuffs::{self, NUM_PILES_KLONDIKE}; +use card_stuffs::{self}; use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind}; use ratatui::{ - buffer::Buffer, layout::{Constraint, Layout, Rect, Flex}, style::{Style, Stylize, Color}, - symbols::border, - text::{Line, Text}, - widgets::{block::title, Block, BorderType, Borders, Paragraph, Widget, Padding, ListItem, List}, + text::Line, + widgets::{Block, BorderType, Borders, ListItem, List}, DefaultTerminal, Frame, }; #[derive(Debug, Default)] pub struct App { cards: card_stuffs::Klondike, + // There aren't pretty... not sure what else I can do about that though... + highlighted_card: Option, + // I should think about making this a Vec so I can highlight a whole stack which is about to move + selected_card: Option, exit: bool, } const CARD_HEIGHT: u16 = 11; const CARD_WIDTH: u16 = 15; -fn card_widget(card: &card_stuffs::Card, top: bool) -> List { +fn waste_widget(cards_in_waste: &Vec) -> List { + let mut cards_to_display = Vec::new(); + if cards_in_waste.len() >= 3 { + cards_to_display.push(cards_in_waste.windows(3).last()); + } else if cards_in_waste.len() == 2 { + cards_to_display.push(cards_in_waste.windows(2).last()); + } else if cards_in_waste.len() == 1 { + cards_to_display.push(cards_in_waste.windows(1).last()); + } + + // Eeeek - we're no longer a basic "List"... I think maybe I need + // a new widget I've make myself... I probably should do that for all cards + // to be toootaly honest + + let hidden_card = [ + format!("#############"), + format!("#############"), + format!("#############"), + format!("#####TODO####"), + format!("#############"), + format!("#############"), + format!("#############"), + format!("#############"), + format!("#############"), + ]; + + let card_image: Vec = hidden_card.iter().map(|m| { + ListItem::new(m.to_string()) + }) + .collect(); + + List::new(card_image) + .block(Block::new() + .borders(Borders::ALL) + .border_type(BorderType::Rounded)) +} + +fn deck_widget(cards_in_deck: &Vec) -> List<'static> { + let hidden_card = [ + format!("#############"), + format!("#############"), + format!("### Cards ###"), + format!("### Left ###"), + format!("#############"), + format!("#### {:02} #####", cards_in_deck.len()), + format!("#############"), + format!("#############"), + format!("#############"), + ]; + let card_image: Vec = hidden_card.iter().map(|m| { + ListItem::new(m.to_string()) + }) + .collect(); + List::new(card_image) + .block(Block::new() + .borders(Borders::ALL) + .border_type(BorderType::Rounded)) +} + +fn card_widget<'a>(card: &'a card_stuffs::Card, top: bool, highlight: bool, select: bool) -> List<'a> { let five_card = [ format!("{value}{suit} ", value=card.value, suit=card.suit), format!(" "), @@ -37,7 +98,7 @@ fn card_widget(card: &card_stuffs::Card, top: bool) -> List { card_stuffs::Colour::Black => Style::new().black().bg(Color::White), card_stuffs::Colour::Red => Style::new().red().bg(Color::White), }; - let card: Vec = five_card.iter().map(|m| { + let card_image: Vec = five_card.iter().map(|m| { ListItem::new(m.to_string()) .style(card_style) }) @@ -48,12 +109,18 @@ fn card_widget(card: &card_stuffs::Card, top: bool) -> List { borders |= Borders::BOTTOM; } - List::new(card) + let mut border_style = Style::default(); + if highlight { + border_style = border_style.fg(Color::Blue); + } else if select { + border_style = border_style.fg(Color::Green); + } + + List::new(card_image) .block(Block::new() - //.style(Style::new().red().bold().italic()) - // Might use something like this for "active"/"selected" - .borders(borders) - .border_type(BorderType::Rounded)) + .style(border_style) + .borders(borders) + .border_type(BorderType::Rounded)) } fn turned_over_card(top: bool) -> List<'static> { @@ -66,6 +133,7 @@ fn turned_over_card(top: bool) -> List<'static> { format!("#############"), format!("#############"), format!("#############"), + format!("#############"), ]; let card: Vec = hidden_card.iter().map(|m| { ListItem::new(m.to_string()) @@ -84,7 +152,6 @@ fn turned_over_card(top: bool) -> List<'static> { } impl App { - /// runs the application's main loop until the user quits pub fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> { while !self.exit { @@ -100,7 +167,7 @@ impl App { Constraint::Min(0), Constraint::Length(1), ]); - let [title_bar, main_area, status_bar] = vertical.areas(frame.area()); + let [title_bar, main_area, _status_bar] = vertical.areas(frame.area()); frame.render_widget( Block::new() @@ -111,19 +178,32 @@ impl App { ); let vertical = Layout::vertical([ - Constraint::Length(CARD_HEIGHT + 2), // for padding + Constraint::Length(CARD_HEIGHT), Constraint::Min(0) ]); let [dwf_area, piles_area] = vertical.areas(main_area); + let horizontal = Layout::horizontal([ + Constraint::Length(CARD_WIDTH), + Constraint::Length(3 + 3 + CARD_WIDTH), // 3+3 for 2 cards shown underneath + Constraint::Length(CARD_WIDTH), + Constraint::Length(CARD_WIDTH), + Constraint::Length(CARD_WIDTH), + Constraint::Length(CARD_WIDTH), + ]).flex(Flex::SpaceAround); + + let [deck_area, waste_area, fa, fb, fc, fd] = horizontal.areas(dwf_area); + let _foundation_areas = [fa, fb, fc, fd]; + frame.render_widget( - Block::new().borders(Borders::ALL).title("dwf_area"), - dwf_area + deck_widget(&self.cards.deck), + deck_area ); frame.render_widget( - Block::new().borders(Borders::ALL).title("piles_area"), - piles_area + waste_widget(&self.cards.waste), + waste_area ); + let horizontal = Layout::horizontal([ Constraint::Length(CARD_WIDTH), Constraint::Length(CARD_WIDTH), @@ -154,15 +234,18 @@ impl App { } let vertical = Layout::vertical(constraints); let card_display: [Rect; card_stuffs::NUM_PILES_KLONDIKE + 13] = vertical.areas(pileses[pile]); + for (i, card) in card_display.iter().enumerate() { match self.cards.piles[pile].get(i) { None => break, Some(c) => { let is_top_card = i == self.cards.piles[pile].len() - 1; + let highlight = self.highlighted_card.is_some() && *c == self.highlighted_card.unwrap(); + let selected = self.selected_card.is_some() && *c == self.selected_card.unwrap(); let a_card = match c.visible { - true => card_widget(c, is_top_card), + true => card_widget(c, is_top_card, highlight, selected), //false => turned_over_card(is_top_card), - false => card_widget(c, is_top_card), + false => card_widget(c, is_top_card, highlight, selected), }; frame.render_widget( &a_card,