Skip to content

Commit

Permalink
Add callbacks to SelectState
Browse files Browse the repository at this point in the history
Also merge FixedSelectState into SelectState
  • Loading branch information
LucasPickering committed Nov 25, 2023
1 parent 362d49e commit 1a49302
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 196 deletions.
14 changes: 9 additions & 5 deletions src/tui/view/common/list.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
use crate::tui::view::{
common::Block, draw::Generate, state::select::SelectState, theme::Theme,
common::Block,
draw::Generate,
state::select::{SelectState, SelectStateKind},
theme::Theme,
};
use ratatui::{
text::Span,
widgets::{ListItem, ListState},
};

/// A list with a border and title. Each item has to be convertible to text
pub struct List<'a, T> {
pub struct List<'a, Kind: SelectStateKind, Item> {
pub block: Block<'a>,
pub list: &'a SelectState<T, ListState>,
pub list: &'a SelectState<Kind, Item, ListState>,
}

impl<'a, T> Generate for List<'a, T>
impl<'a, Kind, Item> Generate for List<'a, Kind, Item>
where
&'a T: Generate<Output<'a> = Span<'a>>,
Kind: SelectStateKind,
&'a Item: Generate<Output<'a> = Span<'a>>,
{
type Output<'this> = ratatui::widgets::List<'this> where Self: 'this;

Expand Down
10 changes: 5 additions & 5 deletions src/tui/view/common/tabs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::tui::{
view::{
draw::{Draw, DrawContext},
event::{Event, EventHandler, Update, UpdateContext},
state::select::{FixedSelect, FixedSelectState},
state::select::{Fixed, FixedSelect, SelectState},
theme::Theme,
},
};
Expand All @@ -13,7 +13,7 @@ use std::fmt::Debug;
/// Multi-tab display. Generic parameter defines the available tabs.
#[derive(Debug, Default)]
pub struct Tabs<T: FixedSelect> {
tabs: FixedSelectState<T, usize>,
tabs: SelectState<Fixed, T, usize>,
}

impl<T: FixedSelect> Tabs<T> {
Expand All @@ -23,18 +23,18 @@ impl<T: FixedSelect> Tabs<T> {
}

impl<T: FixedSelect> EventHandler for Tabs<T> {
fn update(&mut self, _context: &mut UpdateContext, event: Event) -> Update {
fn update(&mut self, context: &mut UpdateContext, event: Event) -> Update {
match event {
Event::Input {
action: Some(action),
..
} => match action {
Action::Left => {
self.tabs.previous();
self.tabs.previous(context);
Update::Consumed
}
Action::Right => {
self.tabs.next();
self.tabs.next(context);
Update::Consumed
}

Expand Down
75 changes: 30 additions & 45 deletions src/tui/view/component/primary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
draw::{Draw, DrawContext, Generate},
event::{Event, EventHandler, Update, UpdateContext},
state::{
select::{FixedSelectState, SelectState},
select::{Dynamic, Fixed, SelectState},
RequestState,
},
util::layout,
Expand All @@ -25,14 +25,17 @@ use crate::{
},
};
use derive_more::Display;
use ratatui::prelude::{Constraint, Direction, Rect};
use ratatui::{
prelude::{Constraint, Direction, Rect},
widgets::ListState,
};
use strum::EnumIter;

/// Primary TUI view, which shows request/response panes
#[derive(Debug)]
pub struct PrimaryView {
// Own state
selected_pane: FixedSelectState<PrimaryPane>,
selected_pane: SelectState<Fixed, PrimaryPane, ListState>,

// Children
profile_list_pane: ProfileListPane,
Expand Down Expand Up @@ -126,11 +129,11 @@ impl EventHandler for PrimaryView {
// Input messages
Event::Input { action, .. } => match action {
Some(Action::PreviousPane) => {
self.selected_pane.previous();
self.selected_pane.previous(context);
Update::Consumed
}
Some(Action::NextPane) => {
self.selected_pane.next();
self.selected_pane.next(context);
Update::Consumed
}
Some(Action::SendRequest) => {
Expand Down Expand Up @@ -246,7 +249,7 @@ impl<'a> Draw<PrimaryViewProps<'a>> for PrimaryView {

#[derive(Debug)]
struct ProfileListPane {
profiles: SelectState<Profile>,
profiles: SelectState<Dynamic, Profile>,
}

struct ListPaneProps {
Expand Down Expand Up @@ -291,55 +294,37 @@ impl Draw<ListPaneProps> for ProfileListPane {

#[derive(Debug)]
struct RecipeListPane {
recipes: SelectState<RequestRecipe>,
recipes: SelectState<Dynamic, RequestRecipe>,
}

impl RecipeListPane {
pub fn new(recipes: Vec<RequestRecipe>) -> Self {
// When highlighting a new recipe, load it from the repo
let on_select = |context: &mut UpdateContext,
recipe: &RequestRecipe| {
context.send_message(Message::RepositoryStartLoad {
recipe_id: recipe.id.clone(),
});
};

// Trigger a request on submit
let on_submit = |context: &mut UpdateContext, _: &RequestRecipe| {
// Parent has to be responsible for actually sending the request
// because it also needs access to the profile list state
context.queue_event(Event::HttpSendRequest);
};

Self {
recipes: SelectState::new(recipes),
recipes: SelectState::new(recipes)
.on_select(on_select)
.on_submit(on_submit),
}
}
}

impl EventHandler for RecipeListPane {
fn update(&mut self, context: &mut UpdateContext, event: Event) -> Update {
let mut load_from_repo = |pane: &RecipeListPane| -> Update {
if let Some(recipe) = pane.recipes.selected() {
context.send_message(Message::RepositoryStartLoad {
recipe_id: recipe.id.clone(),
});
}
Update::Consumed
};

match event {
Event::Input {
action: Some(Action::Submit),
..
} => {
// Parent has to be responsible for sending the request because
// it also needs access to the profile list state
context.queue_event(Event::HttpSendRequest);
Update::Consumed
}
// TODO use input handling from StatefulList
Event::Input {
action: Some(Action::Up),
..
} => {
self.recipes.previous();
load_from_repo(self)
}
Event::Input {
action: Some(Action::Down),
..
} => {
self.recipes.next();
load_from_repo(self)
}
_ => Update::Propagate(event),
}
fn children(&mut self) -> Vec<&mut dyn EventHandler> {
vec![&mut self.recipes]
}
}

Expand Down
48 changes: 19 additions & 29 deletions src/tui/view/component/settings.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::tui::{
input::Action,
message::Message,
view::{
common::{modal::Modal, table::Table, Checkbox},
draw::{Draw, DrawContext, Generate},
event::{Event, EventHandler, Update, UpdateContext},
state::select::FixedSelectState,
event::{EventHandler, UpdateContext},
state::select::{Fixed, SelectState},
ViewConfig,
},
};
Expand All @@ -20,13 +19,28 @@ use strum::{EnumCount, EnumIter, IntoEnumIterator};
/// Modal to view and modify user/view configuration
#[derive(Debug)]
pub struct SettingsModal {
table: FixedSelectState<Setting, TableState>,
table: SelectState<Fixed, Setting, TableState>,
}

impl Default for SettingsModal {
fn default() -> Self {
// Toggle the selected setting on Enter
let on_submit =
|context: &mut UpdateContext, setting: &Setting| match setting {
Setting::PreviewTemplates => {
context.config().preview_templates ^= true;
}
Setting::CaptureMouse => {
context.config().capture_mouse ^= true;
// Tell the terminal to actually do the switch
let capture = context.config().capture_mouse;
context
.send_message(Message::ToggleMouseCapture { capture });
}
};

Self {
table: FixedSelectState::new(),
table: SelectState::fixed().on_submit(on_submit),
}
}
}
Expand All @@ -49,30 +63,6 @@ impl Modal for SettingsModal {
}

impl EventHandler for SettingsModal {
fn update(&mut self, context: &mut UpdateContext, event: Event) -> Update {
match event {
Event::Input {
action: Some(Action::Submit),
..
} => {
match self.table.selected() {
Setting::PreviewTemplates => {
context.config().preview_templates ^= true;
}
Setting::CaptureMouse => {
context.config().capture_mouse ^= true;
let capture = context.config().capture_mouse;
context.send_message(Message::ToggleMouseCapture {
capture,
});
}
}
Update::Consumed
}
_ => Update::Propagate(event),
}
}

fn children(&mut self) -> Vec<&mut dyn EventHandler> {
vec![&mut self.table]
}
Expand Down
Loading

0 comments on commit 1a49302

Please sign in to comment.