Skip to content

Commit

Permalink
Add mouse event handling for request and response
Browse files Browse the repository at this point in the history
  • Loading branch information
Philipp Reiter committed Aug 10, 2024
1 parent 99811fe commit 89661ee
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 21 deletions.
5 changes: 2 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 23 additions & 5 deletions tui-key-event-handler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod key_event;
use std::collections::HashMap;
use std::fmt::Display;

use ::crossterm::event::MouseEvent;
pub use key_event::KeyCode;
pub use key_event::KeyEvent;
pub use key_event::{KeyModifier, KeyModifiers};
Expand All @@ -29,6 +30,12 @@ pub trait EventHandler {
/// registering any specific handling logic.
fn pass_through_key_events(_: &KeyEvent, _: &mut Self::Context) {}

/// Passes through key events without any specific handling.
///
/// This method is optional and can be used to simply pass through character events without
/// registering any specific handling logic.
fn pass_through_mouse_events(_: &MouseEvent, _: &mut Self::Context) {}

/// Retrieves the key event mappings to their corresponding application events.
///
/// Returns a map of key events to application events.
Expand All @@ -39,17 +46,28 @@ pub trait EventHandler {
/// # Arguments
///
/// * `ctx` - The context in which the key event is handled.
/// * `key_event` - The key event to handle.
fn handle_key_event<T: Into<KeyEvent>>(ctx: &mut Self::Context, key_event: T) {
/// * `event` - The key event to handle.
fn handle_key_event<T: Into<KeyEvent>>(ctx: &mut Self::Context, event: T) {
let mappings = Self::key_event_mappings(ctx);
let key_event = key_event.into();
if let Some(item) = mappings.iter().find(|item| item.0 == key_event) {
let event = event.into();
if let Some(item) = mappings.iter().find(|item| item.0 == event) {
Self::handle_event(&item.1, ctx);
} else {
Self::pass_through_key_events(&key_event, ctx);
Self::pass_through_key_events(&event, ctx);
}
}

/// Handles a mouse event by dispatching it to the corresponding application event handler.
///
/// # Arguments
///
/// * `ctx` - The context in which the key event is handled.
/// * `event` - The mouse event to handle.
fn handle_mouse_event<T: Into<MouseEvent>>(ctx: &mut Self::Context, event: T) {
let event = event.into();
Self::pass_through_mouse_events(&event, ctx);
}

/// Converts the key event mappings into a vector of string representations, i.e.
/// (app event as string, key event as string).
///
Expand Down
5 changes: 3 additions & 2 deletions wireman/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ tui-widget-list = { version = "0.11.0" }
# tui-widget-list = { git = "https://github.com/preiter93/tui-widget-list.git", branch = "v0.9" }
# tui-widget-list = { path = "../../tui-widget-list", version = "0.9.0"}
tui-key-event-handler = { package = "tui-key-event-handler", path = "../tui-key-event-handler", version = "0.1.0" }
edtui = "0.5"
# edtui = { version = "0.3.3", path = "../../edtui" }
# edtui = "0.5"
# edtui = { version = "0.6", path = "../../edtui" }
edtui = { package = "edtui", version = "0.6", git = "https://github.com/preiter93/edtui.git" }
crossterm = { version = "0.27", features = ["events", "event-stream"] }
ratatui = "0.27"
serde = { version = "1.0", features = ["derive"] }
Expand Down
8 changes: 6 additions & 2 deletions wireman/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,12 @@ impl App {
async fn handle_events(&mut self) -> Result<()> {
select! {
crossterm_event = self.crossterm_stream.next() => {
if let Some(Ok(Event::Key(event))) = crossterm_event {
self.handle_crossterm_event(event);
if let Some(Ok(event)) = crossterm_event {
match event {
Event::Key(event) => self.handle_crossterm_key_event(event),
Event::Mouse(event) => self.handle_crossterm_mouse_event(event),
_ => (),
}
}
},
internal_event = self.internal_stream.rx.recv() =>{
Expand Down
18 changes: 16 additions & 2 deletions wireman/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::fmt::Display;
use crate::app::App;
use crate::context::{AppContext, HelpContext, MessagesTab, SelectionTab, Tab};
use crate::model::messages::{do_request, RequestResult};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent};
pub(crate) use selection::methods::MethodsSelectionEventsHandler;
pub(crate) use selection::methods_search::MethodsSearchEventsHandler;
pub(crate) use selection::services::ServicesSelectionEventsHandler;
Expand Down Expand Up @@ -34,7 +34,7 @@ impl InternalStream {
}

impl App {
pub(crate) fn handle_crossterm_event(&mut self, event: KeyEvent) {
pub(crate) fn handle_crossterm_key_event(&mut self, event: KeyEvent) {
let sx = self.internal_stream.sx.clone();
match event.code {
KeyCode::Char('c') if event.modifiers == KeyModifiers::CONTROL => {
Expand Down Expand Up @@ -96,6 +96,7 @@ impl App {
}
}
}

// Dispatch the grpc request in a seperate thread.
if self.ctx.messages.borrow().dispatch {
let mut messages_model = self.ctx.messages.borrow_mut();
Expand All @@ -116,6 +117,19 @@ impl App {
}
}

pub(crate) fn handle_crossterm_mouse_event(&mut self, event: MouseEvent) {
if self.ctx.tab == Tab::Messages {
match self.ctx.messages_tab {
MessagesTab::Request => {
RequestEventHandler::handle_mouse_event(&mut self.ctx, event)
}
MessagesTab::Response => {
ResponseEventHandler::handle_mouse_event(&mut self.ctx, event)
}
};
}
}

pub(crate) fn handle_internal_event(&mut self, result: &RequestResult) {
result.set(&mut self.ctx.messages.borrow_mut().response.editor);
self.ctx.messages.borrow_mut().handler.take();
Expand Down
10 changes: 8 additions & 2 deletions wireman/src/events/messages/request.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::context::{AppContext, MessagesTab};
use crossterm::event::MouseEvent;
use std::fmt;
use tui_key_event_handler::{EventHandler, KeyCode, KeyEvent};

Expand Down Expand Up @@ -168,9 +169,14 @@ impl EventHandler for RequestEventHandler {
map
}

fn pass_through_key_events(key_event: &KeyEvent, ctx: &mut Self::Context) {
fn pass_through_key_events(event: &KeyEvent, ctx: &mut Self::Context) {
let request = &mut ctx.messages.borrow_mut().request.editor;
request.on_key(key_event.clone().into());
request.on_key(event.clone().into());
ctx.disable_root_events = !request.normal_mode();
}

fn pass_through_mouse_events(event: &MouseEvent, ctx: &mut Self::Context) {
let editor = &mut ctx.messages.borrow_mut().request.editor;
editor.on_mouse(event.clone().into());
}
}
6 changes: 6 additions & 0 deletions wireman/src/events/messages/response.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::context::{AppContext, MessagesTab};
use crossterm::event::MouseEvent;
use std::fmt;
use tui_key_event_handler::{EventHandler, KeyCode, KeyEvent};

Expand Down Expand Up @@ -81,4 +82,9 @@ impl EventHandler for ResponseEventHandler {
response.on_key(key_event.clone().into());
ctx.disable_root_events = !response.normal_mode();
}

fn pass_through_mouse_events(event: &MouseEvent, ctx: &mut Self::Context) {
let editor = &mut ctx.messages.borrow_mut().response.editor;
editor.on_mouse(event.clone().into());
}
}
5 changes: 3 additions & 2 deletions wireman/src/term.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
Expand All @@ -18,7 +19,7 @@ impl Term {
pub fn new() -> Result<Self> {
let terminal = Terminal::new(CrosstermBackend::new(stderr()))?;

crossterm::execute!(stdout(), EnterAlternateScreen)?;
crossterm::execute!(stdout(), EnterAlternateScreen, EnableMouseCapture)?;
enable_raw_mode()?;

// Shutdown gracefully
Expand All @@ -34,7 +35,7 @@ impl Term {

pub fn stop() -> Result<()> {
disable_raw_mode()?;
crossterm::execute!(stdout(), LeaveAlternateScreen)?;
crossterm::execute!(stdout(), LeaveAlternateScreen, DisableMouseCapture)?;
Ok(())
}
}
Expand Down
13 changes: 10 additions & 3 deletions wireman/src/widgets/editor.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use arboard::Clipboard;
use crossterm::event::MouseEvent;
use crossterm::event::{KeyCode, KeyEvent};
use edtui::{
actions::{Execute, SwitchMode},
clipboard::ClipboardTrait,
EditorInput, EditorMode, EditorState, EditorTheme, EditorView, Index2, Lines, RowIndex,
EditorInput, EditorMode, EditorMouse, EditorState, EditorTheme, EditorView, Index2, Lines,
RowIndex,
};
use once_cell::sync::Lazy;
use ratatui::{
Expand Down Expand Up @@ -182,21 +184,26 @@ impl TextEditor {
}
}

/// Key bindings in normal mode
/// Handle key events.
pub fn on_key(&mut self, key: KeyEvent) {
match key.code {
KeyCode::Tab | KeyCode::BackTab if self.single_line && self.insert_mode() => {
SwitchMode(EditorMode::Normal).execute(&mut self.state);
}
_ => {
self.input.on_key(key, &mut self.state);
self.input.on_event(key, &mut self.state);
}
}

if self.single_line {
self.truncate_first_line();
}
}
/// Handle mouse events.
pub fn on_mouse(&mut self, event: MouseEvent) {
let mouse = EditorMouse::default();
mouse.on_event(event, &mut self.state)
}
}

static CLIPBOARD: Lazy<GlobalClipboard> = Lazy::new(GlobalClipboard::new);
Expand Down

0 comments on commit 89661ee

Please sign in to comment.