finally working with separate views

This commit is contained in:
Niko Abeler 2023-01-11 21:49:16 +01:00
parent 9e51daf566
commit e1b1621a61
4 changed files with 98 additions and 147 deletions

View File

@ -129,9 +129,11 @@ fn main() -> Result<(), io::Error> {
let mut app = App::new(game); let mut app = App::new(game);
loop { loop {
if !app.do_loop(&mut terminal) { terminal.draw(|f| app.draw(f))?;
if !app.step() {
break; break;
} }
// terminal.draw(|f| app.draw(f))?;
} }
// restore terminal // restore terminal

View File

@ -1,7 +1,7 @@
use crossterm::event::{read, Event, KeyCode}; use crossterm::event::{read, Event, KeyCode};
use tui::{backend::Backend, Frame}; use tui::{backend::Backend, Frame};
use crate::{world::Terrain, game::Game}; use crate::{world::Terrain, game::Game, entity::Location};
use super::{controls::Controls, DefaultLayout, status_line::StatusLine, AppStatus, guest_selection::GuestSelectionView}; use super::{controls::Controls, DefaultLayout, status_line::StatusLine, AppStatus, guest_selection::GuestSelectionView};
@ -11,34 +11,61 @@ enum DebugTab {
Items, Items,
Map, Map,
} }
pub struct DebugView<'a> {
list: Vec<tui::widgets::ListItem<'a>>, struct CreatureItem{
id: u32,
name: String,
profession: String,
loc: Location
}
struct ItemItem{
id: u32,
name: String,
item_type: String,
owner: String,
}
pub struct DebugView {
list: Vec<CreatureItem>, // Vec<tui::widgets::ListItem>,
list_state: tui::widgets::ListState, list_state: tui::widgets::ListState,
item_list: Vec<tui::widgets::ListItem<'a>>, item_list: Vec<ItemItem>, // Vec<tui::widgets::ListItem>,
item_list_state: tui::widgets::ListState, item_list_state: tui::widgets::ListState,
selected: DebugTab, selected: DebugTab,
map_scroll: (u16, u16), map_scroll: (u16, u16),
} }
impl<'a> DebugView<'a> { impl DebugView {
pub fn new(game: &Game) -> DebugView<'a> { pub fn new(game: &Game) -> DebugView {
let mut list = vec![]; let mut list = vec![];
let mut item_list = vec![]; let mut item_list = vec![];
for (id, creature) in game.state.creatures.iter() { for (id, creature) in game.state.creatures.iter() {
list.push(tui::widgets::ListItem::new(format!("{}: {} ({}) at {}", list.push(CreatureItem {
id.1, creature.name, id: id.1,
creature.profession, name: creature.name.clone(),
creature.loc, profession: format!("{}", creature.profession),
))); loc: creature.loc,
});
// list.push(tui::widgets::ListItem::new(format!("{}: {} ({}) at {}",
// id.1, creature.name,
// creature.profession,
// creature.loc,
// )));
} }
for (id, item) in game.state.items.iter() { for (id, item) in game.state.items.iter() {
item_list.push(tui::widgets::ListItem::new(format!("{}: {} ({}) at {}", item_list.push(ItemItem {
id.1, item.name, id: id.1,
item.item_type, name: item.name.clone(),
item.owner, item_type: format!("{}", item.item_type),
))); owner: format!("{}", item.owner),
});
// item_list.push(tui::widgets::ListItem::new(format!("{}: {} ({}) at {}",
// id.1, item.name,
// item.item_type,
// item.owner,
// )));
} }
let mut view = DebugView { let mut view = DebugView {
@ -141,7 +168,13 @@ impl<'a> DebugView<'a> {
match data.selected { match data.selected {
DebugTab::Creatures => { DebugTab::Creatures => {
let main_window = tui::widgets::List::new(data.list.clone()) let main_window = tui::widgets::List::new(data.list.iter().map(|c| {
tui::widgets::ListItem::new(format!("{}: {} ({}) at {}",
c.id, c.name,
c.profession,
c.loc,
))
}).collect::<Vec<_>>())
.block(tui::widgets::Block::default().title("Guests").borders(tui::widgets::Borders::ALL)) .block(tui::widgets::Block::default().title("Guests").borders(tui::widgets::Borders::ALL))
.style(tui::style::Style::default().fg(tui::style::Color::White)) .style(tui::style::Style::default().fg(tui::style::Color::White))
.highlight_style(tui::style::Style::default().add_modifier(tui::style::Modifier::ITALIC)) .highlight_style(tui::style::Style::default().add_modifier(tui::style::Modifier::ITALIC))
@ -149,7 +182,13 @@ impl<'a> DebugView<'a> {
f.render_stateful_widget(main_window, chunks.main, &mut data.list_state); f.render_stateful_widget(main_window, chunks.main, &mut data.list_state);
}, },
DebugTab::Items => { DebugTab::Items => {
let main_window = tui::widgets::List::new(data.item_list.clone()) let main_window = tui::widgets::List::new(data.item_list.iter().map(|i| {
tui::widgets::ListItem::new(format!("{}: {} ({}) at {}",
i.id, i.name,
i.item_type,
i.owner,
))
}).collect::<Vec<_>>())
.block(tui::widgets::Block::default().title("Items").borders(tui::widgets::Borders::ALL)) .block(tui::widgets::Block::default().title("Items").borders(tui::widgets::Borders::ALL))
.style(tui::style::Style::default().fg(tui::style::Color::White)) .style(tui::style::Style::default().fg(tui::style::Color::White))
.highlight_style(tui::style::Style::default().add_modifier(tui::style::Modifier::ITALIC)) .highlight_style(tui::style::Style::default().add_modifier(tui::style::Modifier::ITALIC))

View File

@ -5,20 +5,31 @@ use crate::game::Game;
use super::{AppStatus, DefaultLayout, controls::Controls, status_line::StatusLine, talk_to_guest::TalkToGuestView, debug_view::DebugView}; use super::{AppStatus, DefaultLayout, controls::Controls, status_line::StatusLine, talk_to_guest::TalkToGuestView, debug_view::DebugView};
pub struct GuestSelectionView<'a> { struct Guest {
guest_list: Vec<tui::widgets::ListItem<'a>>, name: String,
profession: String,
inventory_size: usize,
}
pub struct GuestSelectionView {
guest_list: Vec<Guest>, // tui::widgets::ListItem
guest_list_state: tui::widgets::ListState, guest_list_state: tui::widgets::ListState,
} }
impl<'a> GuestSelectionView<'a> { impl GuestSelectionView {
pub fn new(game: &Game) -> GuestSelectionView<'a> { pub fn new(game: &Game) -> GuestSelectionView {
let guest_list = game.state.guests().iter().map(|creature_id| { let guest_list = game.state.guests().iter().map(|creature_id| {
let creature = game.state.get_creature(*creature_id).unwrap(); let creature = game.state.get_creature(*creature_id).unwrap();
tui::widgets::ListItem::new(format!( Guest {
"{} ({}, {} items)", name: creature.name.clone(),
creature.name, profession: format!("{}", creature.profession),
creature.profession, game.state.get_inventory(creature.entity.id).len() inventory_size: game.state.get_inventory(creature.entity.id).len(),
)) }
// tui::widgets::ListItem::new(format!(
// "{} ({}, {} items)",
// creature.name,
// creature.profession, game.state.get_inventory(creature.entity.id).len()
// ))
}).collect(); }).collect();
let mut guest_list_state = tui::widgets::ListState::default(); let mut guest_list_state = tui::widgets::ListState::default();
guest_list_state.select(Some(0)); guest_list_state.select(Some(0));
@ -76,7 +87,13 @@ impl<'a> GuestSelectionView<'a> {
pub fn draw<B: Backend>(&mut self, f: &mut Frame<B>, game: &Game) { pub fn draw<B: Backend>(&mut self, f: &mut Frame<B>, game: &Game) {
let chunks = DefaultLayout::default(f.size()); let chunks = DefaultLayout::default(f.size());
let main_window = tui::widgets::List::new(self.guest_list.clone()) let main_window = tui::widgets::List::new(self.guest_list.iter().map(|guest| {
tui::widgets::ListItem::new(format!(
"{} ({}, {} items)",
guest.name,
guest.profession, guest.inventory_size
))
}).collect::<Vec<_>>())
.block(tui::widgets::Block::default().title("Guests").borders(tui::widgets::Borders::ALL)) .block(tui::widgets::Block::default().title("Guests").borders(tui::widgets::Borders::ALL))
.style(tui::style::Style::default().fg(tui::style::Color::White)) .style(tui::style::Style::default().fg(tui::style::Color::White))
.highlight_style(tui::style::Style::default().add_modifier(tui::style::Modifier::ITALIC)) .highlight_style(tui::style::Style::default().add_modifier(tui::style::Modifier::ITALIC))

View File

@ -22,28 +22,17 @@ use self::{chat::{Chat, ChatLine}, controls::Controls, debug_view::DebugView, gu
* |........................| * |........................|
*/ */
pub enum AppStatus<'a> { pub enum AppStatus {
Initial, Initial,
GuestSelection(GuestSelectionView<'a>), GuestSelection(GuestSelectionView),
TalkToGuest(TalkToGuestView), TalkToGuest(TalkToGuestView),
BuyFromGuest(EntityId), BuyFromGuest(EntityId),
Debug(DebugView<'a>), Debug(DebugView),
} }
pub struct App<'a> { pub struct App {
game: Game, game: Game,
status: AppStatus<'a>, status: AppStatus,
next_status: Option<AppStatus<'a>>,
// Conversation
conversation: Chat,
conversation_scroll: u16,
// // Guest Selection
// guest_selection: Option<GuestSelectionView<'a>>,
// // Debug
// debug_view: Option<DebugView<'a>>,
} }
pub struct DefaultLayout { pub struct DefaultLayout {
@ -73,30 +62,15 @@ impl DefaultLayout {
} }
} }
impl<'a> App<'a> { impl App {
pub fn new(state: Game) -> App<'a> { pub fn new(state: Game) -> App {
App { App {
game: state, game: state,
status: AppStatus::Initial, status: AppStatus::Initial,
conversation: Chat::new(),
conversation_scroll: 0,
next_status: None,
// guest_selection: None,
// debug_view: None,
} }
} }
pub fn do_loop<B: Backend>(&'a mut self, terminal: &mut Terminal<B>) -> bool { pub fn step(&mut self) -> bool {
terminal.draw(|f| self.draw(f)).unwrap();
self.step()
}
pub fn step(&'a mut self) -> bool {
if let Some(next_status) = self.next_status.take() {
self.status = next_status;
self.next_status = None;
}
let mut ret = (true, None); let mut ret = (true, None);
match &mut self.status { match &mut self.status {
AppStatus::Initial => { AppStatus::Initial => {
@ -125,7 +99,9 @@ impl<'a> App<'a> {
ret = debug_view.control(&mut self.game); ret = debug_view.control(&mut self.game);
} }
} }
self.next_status = ret.1; if let Some(next_status) = ret.1 {
self.status = next_status;
}
ret.0 ret.0
} }
@ -181,51 +157,6 @@ impl<'a> App<'a> {
pub fn draw_initial<B: Backend>(&mut self, _f: &mut Frame<B>) {} pub fn draw_initial<B: Backend>(&mut self, _f: &mut Frame<B>) {}
fn draw_talk_to_guest<B: Backend>(&self, f: &mut Frame<B>, guest: Option<EntityId>) {
let chunks = DefaultLayout::default(f.size());
let guest = self.game.state.get_creature(guest.unwrap()).unwrap();
let key_style = tui::style::Style::default()
.add_modifier(tui::style::Modifier::BOLD)
.fg(tui::style::Color::Green)
.bg(tui::style::Color::Black);
let mut full_text = self.conversation.to_spans();
full_text.push(tui::text::Spans::from(vec![
tui::text::Span::styled("(a) ", key_style),
tui::text::Span::raw("What's your business?"),
]));
full_text.push(tui::text::Spans::from(vec![
tui::text::Span::styled("(b) ", key_style),
tui::text::Span::raw("What do you have to sell?"),
]));
full_text.push(tui::text::Spans::from(vec![
tui::text::Span::styled("(c) ", key_style),
tui::text::Span::raw("Heard of anything interesting?"),
]));
let text = tui::text::Text::from(full_text);
let scroll: u16 = ((text.lines.len() as u16) )
.saturating_sub(
(chunks.main.height as u16).saturating_sub(2) // 2 lines for the border
)
.saturating_sub(self.conversation_scroll);
let main_window = tui::widgets::Paragraph::new(text)
.block(tui::widgets::Block::default().title(guest.name.clone()).borders(tui::widgets::Borders::ALL))
.style(tui::style::Style::default().fg(tui::style::Color::White))
.scroll((scroll, 0));
let mut binding = Controls::new();
let controls = binding
.add("a-z".to_owned(), "Talk".to_owned())
.add("Esc".to_owned(), "Back".to_owned())
.render();
self.draw_status(f, chunks.status);
f.render_widget(main_window, chunks.main);
f.render_widget(controls, chunks.controls);
}
fn draw_buy_from_guest<B: Backend>(&self, f: &mut Frame<B>, guest_id: EntityId) { fn draw_buy_from_guest<B: Backend>(&self, f: &mut Frame<B>, guest_id: EntityId) {
let chunks = DefaultLayout::default(f.size()); let chunks = DefaultLayout::default(f.size());
@ -256,42 +187,4 @@ impl<'a> App<'a> {
f.render_widget(controls, chunks.controls); f.render_widget(controls, chunks.controls);
} }
/**
* Conversation
*/
fn greet_guest(&mut self, guest_id: Option<EntityId>) {
let guest = self.game.state.get_creature(guest_id.unwrap()).unwrap();
self.conversation.add_line(ChatLine::new(
(EntityType::Creature, 0),
"You".to_owned(),
"Greetings traveller!".to_owned(),
false
));
self.conversation.add_line(ChatLine::new(
guest_id.unwrap(),
guest.name.clone(),
"Hello, I'm ".to_owned() + &guest.name + ", nice to meet you! "
+ "I'm a " + &guest.profession.to_string() + ".",
false
));
self.conversation_scroll = 0;
}
fn ask_business(&mut self, guest: Option<EntityId>) {
let guest = self.game.state.get_creature(guest.unwrap()).unwrap();
self.conversation.add_line(ChatLine::new(
(EntityType::Creature, 0),
"You".to_owned(),
"What's your business?".to_owned(),
false
));
self.conversation.add_line(ChatLine::new(
guest.entity.id,
guest.name.clone(),
guest.say_agenda(& self.game.state),
false
));
self.conversation_scroll = 0;
}
} }