mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-11-22 13:22:28 +00:00
Compare commits
8 Commits
f2b1edf2eb
...
b4f29edb57
Author | SHA1 | Date | |
---|---|---|---|
|
b4f29edb57 | ||
|
3a0717d267 | ||
|
5e4e336eff | ||
|
bb974b2701 | ||
|
654cd615cf | ||
|
a6e948f1c9 | ||
|
e2f87e38b1 | ||
|
ee090dd31f |
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||
|
||||
use crate::{float::FloatContent, hint::Shortcut};
|
||||
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use crossterm::event::{KeyCode, KeyEvent, MouseEvent, MouseEventKind};
|
||||
use ratatui::{
|
||||
layout::Alignment,
|
||||
prelude::*,
|
||||
|
@ -84,6 +84,19 @@ impl FloatContent for ConfirmPrompt {
|
|||
frame.render_widget(List::new(paths_text), inner_area);
|
||||
}
|
||||
|
||||
fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
||||
match event.kind {
|
||||
MouseEventKind::ScrollDown => {
|
||||
self.scroll_down();
|
||||
}
|
||||
MouseEventKind::ScrollUp => {
|
||||
self.scroll_up();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn handle_key_event(&mut self, key: &KeyEvent) -> bool {
|
||||
use KeyCode::*;
|
||||
self.status = match key.code {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use crossterm::event::{KeyCode, KeyEvent, MouseEvent};
|
||||
use ratatui::{
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
Frame,
|
||||
|
@ -9,6 +9,7 @@ use crate::hint::Shortcut;
|
|||
pub trait FloatContent {
|
||||
fn draw(&mut self, frame: &mut Frame, area: Rect);
|
||||
fn handle_key_event(&mut self, key: &KeyEvent) -> bool;
|
||||
fn handle_mouse_event(&mut self, key: &MouseEvent) -> bool;
|
||||
fn is_finished(&self) -> bool;
|
||||
fn get_shortcut_list(&self) -> (&str, Box<[Shortcut]>);
|
||||
}
|
||||
|
@ -53,6 +54,10 @@ impl<Content: FloatContent + ?Sized> Float<Content> {
|
|||
self.content.draw(frame, popup_area);
|
||||
}
|
||||
|
||||
pub fn handle_mouse_event(&mut self, event: &MouseEvent) {
|
||||
self.content.handle_mouse_event(event);
|
||||
}
|
||||
|
||||
// Returns true if the floating window is finished.
|
||||
pub fn handle_key_event(&mut self, key: &KeyEvent) -> bool {
|
||||
match key.code {
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{float::FloatContent, hint::Shortcut};
|
|||
|
||||
use linutil_core::Command;
|
||||
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use crossterm::event::{KeyCode, KeyEvent, MouseEvent, MouseEventKind};
|
||||
|
||||
use ratatui::{
|
||||
layout::Rect,
|
||||
|
@ -283,6 +283,17 @@ impl FloatContent for FloatingText {
|
|||
frame.render_widget(list, inner_area);
|
||||
}
|
||||
|
||||
fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
||||
match event.kind {
|
||||
MouseEventKind::ScrollDown => self.scroll_down(),
|
||||
MouseEventKind::ScrollUp => self.scroll_up(),
|
||||
MouseEventKind::ScrollLeft => self.scroll_left(),
|
||||
MouseEventKind::ScrollRight => self.scroll_right(),
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn handle_key_event(&mut self, key: &KeyEvent) -> bool {
|
||||
use KeyCode::*;
|
||||
match key.code {
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::{
|
|||
use crate::theme::Theme;
|
||||
use clap::Parser;
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, Event, KeyEventKind},
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyEventKind},
|
||||
style::ResetColor,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
ExecutableCommand,
|
||||
|
@ -44,6 +44,8 @@ fn main() -> io::Result<()> {
|
|||
let mut state = AppState::new(args.theme, args.override_validation, args.size_bypass);
|
||||
|
||||
stdout().execute(EnterAlternateScreen)?;
|
||||
stdout().execute(EnableMouseCapture)?;
|
||||
|
||||
enable_raw_mode()?;
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
|
||||
terminal.clear()?;
|
||||
|
@ -73,15 +75,22 @@ fn run(
|
|||
|
||||
// It's guaranteed that the `read()` won't block when the `poll()`
|
||||
// function returns `true`
|
||||
if let Event::Key(key) = event::read()? {
|
||||
// We are only interested in Press and Repeat events
|
||||
if key.kind != KeyEventKind::Press && key.kind != KeyEventKind::Repeat {
|
||||
continue;
|
||||
}
|
||||
match event::read()? {
|
||||
Event::Key(key) => {
|
||||
if key.kind != KeyEventKind::Press && key.kind != KeyEventKind::Repeat {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !state.handle_key(&key) {
|
||||
return Ok(());
|
||||
if !state.handle_key(&key) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Event::Mouse(mouse_event) => {
|
||||
if !state.handle_mouse(&mouse_event) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{float::FloatContent, hint::Shortcut};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind};
|
||||
use linutil_core::Command;
|
||||
use oneshot::{channel, Receiver};
|
||||
use portable_pty::{
|
||||
|
@ -91,6 +91,18 @@ impl FloatContent for RunningCommand {
|
|||
frame.render_widget(pseudo_term, area);
|
||||
}
|
||||
|
||||
fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
||||
match event.kind {
|
||||
MouseEventKind::ScrollUp => {
|
||||
self.scroll_offset = self.scroll_offset.saturating_add(1);
|
||||
}
|
||||
MouseEventKind::ScrollDown => {
|
||||
self.scroll_offset = self.scroll_offset.saturating_sub(1);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
}
|
||||
/// Handle key events of the running command "window". Returns true when the "window" should be
|
||||
/// closed
|
||||
fn handle_key_event(&mut self, key: &KeyEvent) -> bool {
|
||||
|
|
|
@ -7,13 +7,13 @@ use crate::{
|
|||
running_command::RunningCommand,
|
||||
theme::Theme,
|
||||
};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind};
|
||||
use ego_tree::NodeId;
|
||||
use linutil_core::{ListNode, Tab};
|
||||
#[cfg(feature = "tips")]
|
||||
use rand::Rng;
|
||||
use ratatui::{
|
||||
layout::{Alignment, Constraint, Direction, Flex, Layout},
|
||||
layout::{Alignment, Constraint, Direction, Flex, Layout, Position, Rect},
|
||||
style::{Style, Stylize},
|
||||
text::{Line, Span, Text},
|
||||
widgets::{Block, Borders, List, ListState, Paragraph},
|
||||
|
@ -40,6 +40,7 @@ P* - privileged *
|
|||
";
|
||||
|
||||
pub struct AppState {
|
||||
areas: Option<Areas>,
|
||||
/// This must be passed to retain the temp dir until the end of the program
|
||||
_temp_dir: TempDir,
|
||||
/// Selected theme
|
||||
|
@ -79,6 +80,11 @@ pub struct ListEntry {
|
|||
pub has_children: bool,
|
||||
}
|
||||
|
||||
pub struct Areas {
|
||||
tab_list: Rect,
|
||||
list: Rect,
|
||||
}
|
||||
|
||||
enum SelectedItem {
|
||||
UpDir,
|
||||
Directory,
|
||||
|
@ -92,6 +98,7 @@ impl AppState {
|
|||
let root_id = tabs[0].tree.root().id();
|
||||
|
||||
let mut state = Self {
|
||||
areas: None,
|
||||
_temp_dir: temp_dir,
|
||||
theme,
|
||||
focus: Focus::List,
|
||||
|
@ -284,6 +291,11 @@ impl AppState {
|
|||
.split(horizontal[0]);
|
||||
frame.render_widget(label, left_chunks[0]);
|
||||
|
||||
self.areas = Some(Areas {
|
||||
tab_list: left_chunks[1],
|
||||
list: horizontal[1],
|
||||
});
|
||||
|
||||
let tabs = self
|
||||
.tabs
|
||||
.iter()
|
||||
|
@ -432,6 +444,59 @@ impl AppState {
|
|||
frame.render_widget(keybind_para, vertical[1]);
|
||||
}
|
||||
|
||||
pub fn handle_mouse(&mut self, event: &MouseEvent) -> bool {
|
||||
if !self.drawable {
|
||||
return true;
|
||||
}
|
||||
|
||||
if matches!(self.focus, Focus::TabList | Focus::List) {
|
||||
let position = Position::new(event.column, event.row);
|
||||
let mouse_in_tab_list = self.areas.as_ref().unwrap().tab_list.contains(position);
|
||||
let mouse_in_list = self.areas.as_ref().unwrap().list.contains(position);
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Moved => {
|
||||
if mouse_in_list {
|
||||
self.focus = Focus::List
|
||||
} else if mouse_in_tab_list {
|
||||
self.focus = Focus::TabList
|
||||
}
|
||||
}
|
||||
MouseEventKind::ScrollDown => {
|
||||
if mouse_in_tab_list {
|
||||
if self.current_tab.selected().unwrap() != self.tabs.len() - 1 {
|
||||
self.current_tab.select_next();
|
||||
}
|
||||
self.refresh_tab();
|
||||
} else if mouse_in_list {
|
||||
self.selection.select_next()
|
||||
}
|
||||
}
|
||||
MouseEventKind::ScrollUp => {
|
||||
if mouse_in_tab_list {
|
||||
if self.current_tab.selected().unwrap() != 0 {
|
||||
self.current_tab.select_previous();
|
||||
}
|
||||
self.refresh_tab();
|
||||
} else if mouse_in_list {
|
||||
self.selection.select_previous()
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
match &mut self.focus {
|
||||
Focus::FloatingWindow(float) => {
|
||||
float.content.handle_mouse_event(event);
|
||||
}
|
||||
Focus::ConfirmationPrompt(confirm) => {
|
||||
confirm.content.handle_mouse_event(event);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn handle_key(&mut self, key: &KeyEvent) -> bool {
|
||||
// This should be defined first to allow closing
|
||||
// the application even when not drawable ( If terminal is small )
|
||||
|
|
Loading…
Reference in New Issue
Block a user