make contextmenu aware of commands

e.g. to process vim-like keybindings for navigation

fixes #108, fixes #157, fixes #178, fixes #199, fixes #250
This commit is contained in:
Henrik Friedrichsen
2020-08-23 15:40:44 +02:00
parent d2b9dffb54
commit 1edf28a165
5 changed files with 112 additions and 18 deletions

View File

@@ -1,17 +1,20 @@
use std::sync::Arc;
use cursive::view::{Margins, ViewWrapper};
use cursive::views::{Dialog, ScrollView, SelectView};
use cursive::views::{Dialog, NamedView, ScrollView, SelectView};
use cursive::Cursive;
use crate::command::{Command, MoveAmount, MoveMode};
use crate::commands::CommandResult;
use crate::library::Library;
use crate::queue::Queue;
use crate::track::Track;
use crate::traits::ListItem;
use crate::traits::{ListItem, ViewExt};
use crate::ui::layout::Layout;
use crate::ui::modal::Modal;
#[cfg(feature = "share_clipboard")]
use clipboard::{ClipboardContext, ClipboardProvider};
use cursive::traits::{Finder, Nameable};
pub struct ContextMenu {
dialog: Modal<Dialog>,
@@ -44,7 +47,7 @@ impl ContextMenu {
Modal::new(dialog)
}
pub fn new(item: &dyn ListItem, queue: Arc<Queue>, library: Arc<Library>) -> Self {
pub fn new(item: &dyn ListItem, queue: Arc<Queue>, library: Arc<Library>) -> NamedView<Self> {
let mut content: SelectView<ContextMenuAction> = SelectView::new().autojump();
if let Some(a) = item.artist() {
content.add_item("Show artist", ContextMenuAction::ShowItem(Box::new(a)));
@@ -92,9 +95,52 @@ impl ContextMenu {
.title(item.display_left())
.dismiss_button("Cancel")
.padding(Margins::lrtb(1, 1, 1, 0))
.content(content);
.content(content.with_name("contextmenu_select"));
Self {
dialog: Modal::new(dialog),
dialog: Modal::new_ext(dialog),
}
.with_name("contextmenu")
}
}
impl ViewExt for ContextMenu {
fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
match cmd {
Command::Back => {
s.pop_layer();
Ok(CommandResult::Consumed(None))
}
Command::Move(mode, amount) => self
.dialog
.call_on_name(
"contextmenu_select",
|select: &mut SelectView<ContextMenuAction>| {
let items = select.len();
match mode {
MoveMode::Up => {
match amount {
MoveAmount::Extreme => select.set_selection(0),
MoveAmount::Integer(amount) => {
select.select_up(*amount as usize)
}
};
Ok(CommandResult::Consumed(None))
}
MoveMode::Down => {
match amount {
MoveAmount::Extreme => select.set_selection(items),
MoveAmount::Integer(amount) => {
select.select_down(*amount as usize)
}
};
Ok(CommandResult::Consumed(None))
}
_ => Ok(CommandResult::Consumed(None)),
}
},
)
.unwrap_or(Ok(CommandResult::Consumed(None))),
_ => Ok(CommandResult::Consumed(None)),
}
}
}

View File

@@ -6,10 +6,11 @@ use cursive::view::ViewWrapper;
use cursive::views::{ScrollView, TextView};
use cursive::Cursive;
use crate::command::Command;
use crate::command::{Command, MoveAmount, MoveMode};
use crate::commands::CommandResult;
use crate::config::config_path;
use crate::traits::ViewExt;
use cursive::view::scroll::Scroller;
pub struct HelpView {
view: ScrollView<TextView>,
@@ -50,10 +51,36 @@ impl ViewExt for HelpView {
}
fn on_command(&mut self, _s: &mut Cursive, cmd: &Command) -> Result<CommandResult, String> {
if let Command::Help = cmd {
Ok(CommandResult::Consumed(None))
} else {
Ok(CommandResult::Ignored)
match cmd {
Command::Help => Ok(CommandResult::Consumed(None)),
Command::Move(mode, amount) => {
let scroller = self.view.get_scroller_mut();
let viewport = scroller.content_viewport();
match mode {
MoveMode::Up => {
match amount {
MoveAmount::Extreme => {
self.view.scroll_to_top();
}
MoveAmount::Integer(amount) => scroller
.scroll_to_y(viewport.top().saturating_sub(*amount as usize)),
};
Ok(CommandResult::Consumed(None))
}
MoveMode::Down => {
match amount {
MoveAmount::Extreme => {
self.view.scroll_to_bottom();
}
MoveAmount::Integer(amount) => scroller
.scroll_to_y(viewport.bottom().saturating_add(*amount as usize)),
};
Ok(CommandResult::Consumed(None))
}
_ => Ok(CommandResult::Consumed(None)),
}
}
_ => Ok(CommandResult::Ignored),
}
}
}

View File

@@ -2,12 +2,22 @@ use cursive::event::{Event, EventResult};
use cursive::view::{View, ViewWrapper};
pub struct Modal<T: View> {
block_events: bool,
inner: T,
}
impl<T: View> Modal<T> {
pub fn new(inner: T) -> Self {
Modal { inner }
Modal {
block_events: true,
inner,
}
}
pub fn new_ext(inner: T) -> Self {
Modal {
block_events: false,
inner,
}
}
}
@@ -16,7 +26,10 @@ impl<T: View> ViewWrapper for Modal<T> {
fn wrap_on_event(&mut self, ch: Event) -> EventResult {
match self.inner.on_event(ch) {
EventResult::Consumed(cb) => EventResult::Consumed(cb),
_ => EventResult::Consumed(None),
_ => match self.block_events {
true => EventResult::Consumed(None),
false => EventResult::Ignored,
},
}
}
}