Skip to content

Commit

Permalink
Add contextual help text
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasPickering committed Nov 2, 2023
1 parent 96d81c3 commit 88c2cd4
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/tui/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl InputEngine {
InputBinding::new(KeyCode::Down, Action::Down),
InputBinding::new(KeyCode::Left, Action::Left),
InputBinding::new(KeyCode::Right, Action::Right),
InputBinding::new(KeyCode::Enter, Action::Interact),
InputBinding::new(KeyCode::Enter, Action::Submit),
InputBinding::new(KeyCode::Esc, Action::Cancel),
]
.into_iter()
Expand Down Expand Up @@ -105,7 +105,7 @@ pub enum Action {
Left,
Right,
/// Do a thing. E.g. select an item in a list
Interact,
Submit,
/// Embiggen a pane
Fullscreen,
/// Close the current modal/dialog/etc.
Expand Down
52 changes: 38 additions & 14 deletions src/tui/view/component/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use crate::{
input::Action,
view::{
component::{
modal::IntoModal, Component, Draw, Event, Modal, UpdateContext,
UpdateOutcome,
modal::IntoModal, primary::PrimaryPane, root::FullscreenMode,
Component, Draw, Event, Modal, UpdateContext, UpdateOutcome,
},
state::Notification,
util::{layout, ButtonBrick, ToTui},
Expand Down Expand Up @@ -48,7 +48,7 @@ impl Component for ErrorModal {
match event {
// Extra close action
Event::Input {
action: Some(Action::Interact),
action: Some(Action::Submit),
..
} => UpdateOutcome::Propagate(Event::CloseModal),

Expand Down Expand Up @@ -154,7 +154,7 @@ impl Component for PromptModal {
match event {
// Submit
Event::Input {
action: Some(Action::Interact),
action: Some(Action::Submit),
..
} => {
// Submission is handled in on_close. The control flow here is
Expand Down Expand Up @@ -200,25 +200,49 @@ impl IntoModal for Prompt {
}
}

/// Tell the user about keybindings
#[derive(Debug)]
pub struct HelpText;

impl Draw for HelpText {
pub struct HelpTextProps {
pub has_modal: bool,
pub fullscreen_mode: Option<FullscreenMode>,
pub selected_pane: PrimaryPane,
}

impl Draw<HelpTextProps> for HelpText {
fn draw(
&self,
context: &RenderContext,
_: (),
props: HelpTextProps,
frame: &mut Frame,
chunk: Rect,
) {
let actions = [
Action::Quit,
Action::ReloadCollection,
Action::FocusNext,
Action::FocusPrevious,
Action::Fullscreen,
Action::Cancel,
];
// Decide which actions to show based on context. This is definitely
// spaghetti and easy to get out of sync, but it's the easiest way to
// get granular control
let mut actions = vec![Action::Quit, Action::ReloadCollection];

match props.fullscreen_mode {
None => {
actions.extend([Action::FocusNext, Action::FocusPrevious]);
// Pane-specific actions
actions.extend(match props.selected_pane {
PrimaryPane::ProfileList => [].as_slice(),
PrimaryPane::RecipeList => &[Action::Submit],
PrimaryPane::Request => &[Action::Fullscreen],
PrimaryPane::Response => &[Action::Fullscreen],
});
}
Some(FullscreenMode::Request | FullscreenMode::Response) => {
actions.extend([Action::Fullscreen])
}
}

if props.has_modal {
actions.push(Action::Cancel);
}

let text = actions
.into_iter()
.map(|action| {
Expand Down
4 changes: 4 additions & 0 deletions src/tui/view/component/modal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ impl ModalQueue {
}
}

/// Is there a modal open right now?
pub fn is_open(&self) -> bool {
!self.queue.is_empty()
}
/// Add a new modal, to either the beginning or end of the queue, depending
/// on priority
pub fn open(&mut self, modal: Box<dyn Modal>, priority: ModalPriority) {
Expand Down
7 changes: 6 additions & 1 deletion src/tui/view/component/primary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ impl PrimaryView {
self.profile_list_pane.profiles.selected()
}

/// Which pane is selected?
pub fn selected_pane(&self) -> PrimaryPane {
*self.selected_pane.selected()
}

/// Expose request pane, for fullscreening
pub fn request_pane(&self) -> &RequestPane {
&self.request_pane
Expand Down Expand Up @@ -322,7 +327,7 @@ impl Component for RecipeListPane {

match event {
Event::Input {
action: Some(Action::Interact),
action: Some(Action::Submit),
..
} => {
// Parent has to be responsible for sending the request because
Expand Down
13 changes: 11 additions & 2 deletions src/tui/view/component/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
message::Message,
view::{
component::{
misc::{HelpText, NotificationText},
misc::{HelpText, HelpTextProps, NotificationText},
modal::ModalQueue,
primary::{PrimaryView, PrimaryViewProps},
request::RequestPaneProps,
Expand Down Expand Up @@ -226,7 +226,16 @@ impl Draw for Root {
Some(notification_text) => {
notification_text.draw(context, (), frame, footer_chunk)
}
None => HelpText.draw(context, (), frame, footer_chunk),
None => HelpText.draw(
context,
HelpTextProps {
has_modal: self.modal_queue.is_open(),
fullscreen_mode: self.fullscreen_mode,
selected_pane: self.primary_view.selected_pane(),
},
frame,
footer_chunk,
),
}

// Render modals last so they go on top
Expand Down

0 comments on commit 88c2cd4

Please sign in to comment.