diff --git a/src/config.rs b/src/config.rs index 3f4370d..f2df8df 100644 --- a/src/config.rs +++ b/src/config.rs @@ -466,6 +466,12 @@ impl<'de> Deserialize<'de> for NotifyVia { } } +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] +pub struct Mouse { + #[serde(default)] + pub enabled: bool, +} + #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] pub struct Notifications { #[serde(default)] @@ -562,6 +568,7 @@ pub struct TunableValues { pub message_user_color: bool, pub default_room: Option, pub open_command: Option>, + pub mouse: Mouse, pub notifications: Notifications, pub image_preview: Option, pub user_gutter_width: usize, @@ -586,6 +593,7 @@ pub struct Tunables { pub message_user_color: Option, pub default_room: Option, pub open_command: Option>, + pub mouse: Option, pub notifications: Option, pub image_preview: Option, pub user_gutter_width: Option, @@ -614,6 +622,7 @@ impl Tunables { message_user_color: self.message_user_color.or(other.message_user_color), default_room: self.default_room.or(other.default_room), open_command: self.open_command.or(other.open_command), + mouse: self.mouse.or(other.mouse), notifications: self.notifications.or(other.notifications), image_preview: self.image_preview.or(other.image_preview), user_gutter_width: self.user_gutter_width.or(other.user_gutter_width), @@ -640,6 +649,7 @@ impl Tunables { message_user_color: self.message_user_color.unwrap_or(false), default_room: self.default_room, open_command: self.open_command, + mouse: self.mouse.unwrap_or_default(), notifications: self.notifications.unwrap_or_default(), image_preview: self.image_preview.map(ImagePreview::values), user_gutter_width: self.user_gutter_width.unwrap_or(30), diff --git a/src/main.rs b/src/main.rs index 82b108a..4ca4f96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,11 +44,14 @@ use modalkit::crossterm::{ read, DisableBracketedPaste, DisableFocusChange, + DisableMouseCapture, EnableBracketedPaste, EnableFocusChange, + EnableMouseCapture, Event, KeyEventKind, KeyboardEnhancementFlags, + MouseEventKind, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags, }, @@ -364,8 +367,30 @@ impl Application { return Ok(ke.into()); }, - Event::Mouse(_) => { - // Do nothing for now. + Event::Mouse(me) => { + let dir = match me.kind { + MouseEventKind::ScrollUp => MoveDir2D::Up, + MouseEventKind::ScrollDown => MoveDir2D::Down, + MouseEventKind::ScrollLeft => MoveDir2D::Left, + MouseEventKind::ScrollRight => MoveDir2D::Right, + _ => continue, + }; + + let size = ScrollSize::Cell; + let style = ScrollStyle::Direction2D(dir, size, 1.into()); + let ctx = ProgramContext::default(); + let mut store = self.store.lock().await; + + match self.screen.scroll(&style, &ctx, store.deref_mut()) { + Ok(None) => {}, + Ok(Some(info)) => { + drop(store); + self.handle_info(info); + }, + Err(e) => { + self.screen.push_error(e); + }, + } }, Event::FocusGained => { let mut store = self.store.lock().await; @@ -932,8 +957,8 @@ async fn login_normal( } /// Set up the terminal for drawing the TUI, and getting additional info. -fn setup_tty(title: &str, enable_enhanced_keys: bool) -> std::io::Result<()> { - let title = format!("iamb ({})", title); +fn setup_tty(settings: &ApplicationSettings, enable_enhanced_keys: bool) -> std::io::Result<()> { + let title = format!("iamb ({})", settings.profile.user_id.as_str()); // Enable raw mode and enter the alternate screen. crossterm::terminal::enable_raw_mode()?; @@ -947,15 +972,23 @@ fn setup_tty(title: &str, enable_enhanced_keys: bool) -> std::io::Result<()> { )?; } + if settings.tunables.mouse.enabled { + crossterm::execute!(stdout(), EnableMouseCapture)?; + } + crossterm::execute!(stdout(), EnableBracketedPaste, EnableFocusChange, SetTitle(title)) } // Do our best to reverse what we did in setup_tty() when we exit or crash. -fn restore_tty(enable_enhanced_keys: bool) { +fn restore_tty(enable_enhanced_keys: bool, enable_mouse: bool) { if enable_enhanced_keys { let _ = crossterm::queue!(stdout(), PopKeyboardEnhancementFlags); } + if enable_mouse { + let _ = crossterm::queue!(stdout(), DisableMouseCapture); + } + let _ = crossterm::execute!( stdout(), DisableBracketedPaste, @@ -1009,11 +1042,12 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> { false }, }; - setup_tty(settings.profile.user_id.as_str(), enable_enhanced_keys)?; + setup_tty(&settings, enable_enhanced_keys)?; let orig_hook = std::panic::take_hook(); + let enable_mouse = settings.tunables.mouse.enabled; std::panic::set_hook(Box::new(move |panic_info| { - restore_tty(enable_enhanced_keys); + restore_tty(enable_enhanced_keys, enable_mouse); orig_hook(panic_info); process::exit(1); })); @@ -1023,7 +1057,7 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> { application.run().await?; // Clean up the terminal on exit. - restore_tty(enable_enhanced_keys); + restore_tty(enable_enhanced_keys, enable_mouse); Ok(()) } diff --git a/src/tests.rs b/src/tests.rs index fa379de..f8a3713 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -189,6 +189,7 @@ pub fn mock_tunables() -> TunableValues { external_edit_file_suffix: String::from(".md"), username_display: UserDisplayStyle::Username, message_user_color: false, + mouse: Default::default(), notifications: Notifications { enabled: false, via: NotifyVia::default(),