diff --git a/crates/egui-term/src/display/mod.rs b/crates/egui-term/src/display/mod.rs index 799a115..188bf9b 100644 --- a/crates/egui-term/src/display/mod.rs +++ b/crates/egui-term/src/display/mod.rs @@ -46,10 +46,11 @@ impl TerminalView<'_> { .term_ctx .to_range() .is_some_and(|r| r.contains(indexed.point)); - let is_hovered_hyperlink = - self.term_ctx.hovered_hyperlink.as_ref().is_some_and(|r| { - r.contains(&indexed.point) && r.contains(&state.mouse_position) - }); + let is_hovered_hyperlink = self + .term_ctx + .hovered_hyperlink + .as_ref() + .is_some_and(|r| r.contains(&indexed.point) && r.contains(&state.mouse_point)); let is_text_cell = indexed.c != ' ' && indexed.c != '\t'; let x = layout_min.x + indexed.point.column.saturating_mul(cell_width as usize) as f32; @@ -112,6 +113,7 @@ impl TerminalView<'_> { cell_width / 2. }; + state.cursor_position = Some(Pos2::new(x, y)); shapes.push(Shape::Rect(RectShape::filled( Rect::from_min_size(Pos2::new(x, y), Vec2::new(cursor_width, cell_height)), CornerRadius::default(), diff --git a/crates/egui-term/src/input/mod.rs b/crates/egui-term/src/input/mod.rs index e4f5bd3..dba8a30 100644 --- a/crates/egui-term/src/input/mod.rs +++ b/crates/egui-term/src/input/mod.rs @@ -4,7 +4,7 @@ use crate::{BindingAction, InputKind, TerminalView}; use alacritty_terminal::grid::Dimensions; use alacritty_terminal::selection::SelectionType; use alacritty_terminal::term::TermMode; -use egui::{Key, Modifiers, MouseWheelUnit, PointerButton, Pos2, Response, Vec2}; +use egui::{Key, Modifiers, MouseWheelUnit, PointerButton, Pos2, Rect, Response, Vec2}; use std::cmp::min; /// Minimum number of pixels at the bottom/top where selection scrolling is performed. @@ -134,7 +134,7 @@ impl TerminalView<'_> { self.left_button_click(state, layout, position, modifiers, pressed) } PointerButton::Secondary => { - state.cursor_position = Some(position); + state.context_menu_position = Some(position); None } _ => None, @@ -149,7 +149,7 @@ impl TerminalView<'_> { modifiers: &Modifiers, pressed: bool, ) -> Option { - if state.cursor_position.is_some() { + if state.context_menu_position.is_some() { return None; } let terminal_mode = self.term_ctx.terminal.mode(); @@ -157,10 +157,10 @@ impl TerminalView<'_> { Some(InputAction::BackendCall(BackendCommand::MouseReport( MouseButton::LeftButton, *modifiers, - state.mouse_position, + state.mouse_point, pressed, ))) - } else if pressed { + } else if pressed && is_in_terminal(position, layout.rect) { state.is_dragged = true; Some(InputAction::BackendCall(start_select_command( layout, position, @@ -189,7 +189,7 @@ impl TerminalView<'_> { *self.term_ctx.terminal.mode(), ) { Some(BindingAction::LinkOpen) => Some(InputAction::BackendCall( - BackendCommand::ProcessLink(LinkAction::Open, state.mouse_position), + BackendCommand::ProcessLink(LinkAction::Open, state.mouse_point), )), _ => None, } @@ -203,21 +203,22 @@ impl TerminalView<'_> { position: Pos2, modifiers: &Modifiers, ) -> Vec { - let cursor_x = position.x - layout.rect.min.x; - let cursor_y = position.y - layout.rect.min.y; + let mouse_x = position.x - layout.rect.min.x; + let mouse_y = position.y - layout.rect.min.y; - state.mouse_position = selection_point( - cursor_x, - cursor_y, + state.mouse_point = selection_point( + mouse_x, + mouse_y, self.term_ctx.size, self.term_ctx.terminal.grid().display_offset(), ); + state.mouse_position = Some(position); let mut actions = vec![]; // Handle command or selection update based on terminal mode and modifiers if state.is_dragged { if !self.term_ctx.selection_is_empty() { - if let Some(action) = self.update_selection_scrolling(cursor_y as i32) { + if let Some(action) = self.update_selection_scrolling(mouse_y as i32) { actions.push(action); } } @@ -232,11 +233,11 @@ impl TerminalView<'_> { InputAction::BackendCall(BackendCommand::MouseReport( MouseButton::LeftMove, *modifiers, - state.mouse_position, + state.mouse_point, true, )) } else { - InputAction::BackendCall(BackendCommand::SelectUpdate(cursor_x, cursor_y)) + InputAction::BackendCall(BackendCommand::SelectUpdate(mouse_x, mouse_y)) }; actions.push(cmd); @@ -245,7 +246,7 @@ impl TerminalView<'_> { // Handle link hover if applicable actions.push(InputAction::BackendCall(BackendCommand::ProcessLink( LinkAction::Hover, - state.mouse_position, + state.mouse_point, ))); actions @@ -293,3 +294,7 @@ fn start_select_command(layout: &Response, cursor_position: Pos2) -> BackendComm cursor_position.y - layout.rect.min.y, ) } + +pub fn is_in_terminal(pos: Pos2, rect: Rect) -> bool { + pos.x > rect.min.x && pos.x < rect.max.x && pos.y > rect.min.y && pos.y < rect.max.y +} diff --git a/crates/egui-term/src/view.rs b/crates/egui-term/src/view.rs index 5cb3637..d1f6553 100644 --- a/crates/egui-term/src/view.rs +++ b/crates/egui-term/src/view.rs @@ -2,18 +2,19 @@ use crate::alacritty::{BackendCommand, TerminalContext}; use crate::bindings::Binding; use crate::bindings::{BindingAction, Bindings, InputKind}; use crate::font::TerminalFont; -use crate::input::InputAction; +use crate::input::{is_in_terminal, InputAction}; use crate::scroll_bar::{InteractiveScrollbar, ScrollbarState}; use crate::theme::TerminalTheme; use crate::types::Size; use alacritty_terminal::grid::{Dimensions, Scroll}; use alacritty_terminal::index::Point; use alacritty_terminal::vte::ansi::{Color, NamedColor}; -use egui::ImeEvent; +use egui::output::IMEOutput; use egui::Widget; use egui::{Context, Event}; use egui::{CursorIcon, Key}; use egui::{Id, Pos2}; +use egui::{ImeEvent, Rect}; use egui::{Response, Vec2}; #[derive(Clone, Default)] @@ -21,10 +22,10 @@ pub struct TerminalViewState { pub is_dragged: bool, pub scroll_pixels: f32, // for terminal - pub mouse_position: Point, + pub mouse_point: Point, + pub mouse_position: Option, + pub context_menu_position: Option, pub cursor_position: Option, - // ime_enabled: bool, - // ime_cursor_range: CursorRange, pub scrollbar_state: ScrollbarState, } @@ -80,13 +81,14 @@ impl Widget for TerminalView<'_> { } // context menu - if let Some(pos) = state.cursor_position { - if !out_of_terminal(pos, &layout) { + if let Some(pos) = state.context_menu_position { + if is_in_terminal(pos, layout.rect) { self.context_menu(pos, &layout, ui); } } + if ui.input(|input_state| input_state.pointer.primary_clicked()) { - state.cursor_position = None; + state.context_menu_position = None; ui.close(); } @@ -97,6 +99,20 @@ impl Widget for TerminalView<'_> { .resize(&layout) .process_input(&mut state, &layout); + if let Some(pos) = state.mouse_position { + if is_in_terminal(pos, layout.rect) { + if let Some(cur_pos) = state.cursor_position { + ui.ctx().output_mut(|output| { + let vec = Vec2::new(15., 15.); + output.ime = Some(IMEOutput { + rect: Rect::from_min_size(cur_pos, vec), + cursor_rect: Rect::from_min_size(cur_pos, vec), + }) + }); + } + } + } + let grid = term.term_ctx.terminal.grid_mut(); let total_lines = grid.total_lines() as f32; let display_offset = grid.display_offset() as f32; @@ -241,10 +257,10 @@ impl<'a> TerminalView<'a> { modifiers, pos, } => { - let new_pos = if out_of_terminal(pos, layout) { - pos.clamp(layout.rect.min, layout.rect.max) - } else { + let new_pos = if is_in_terminal(pos, layout.rect) { pos + } else { + pos.clamp(layout.rect.min, layout.rect.max) }; if let Some(action) = @@ -257,15 +273,17 @@ impl<'a> TerminalView<'a> { input_actions = self.mouse_move(state, layout, pos, &modifiers) } Event::Ime(event) => match event { - ImeEvent::Disabled => { - // state.ime_enabled = false; + ImeEvent::Preedit(text_mark) => { + if text_mark != "\n" && text_mark != "\r" { + // TODO: handle preedit + } } - ImeEvent::Enabled | ImeEvent::Preedit(_) => { - // state.ime_enabled = true; - } - ImeEvent::Commit(text) => { - input_actions.push(self.text_input(&text)); + ImeEvent::Commit(prediction) => { + if prediction != "\n" && prediction != "\r" { + input_actions.push(self.text_input(&prediction)); + } } + _ => {} }, _ => {} }; @@ -285,10 +303,3 @@ impl<'a> TerminalView<'a> { self } } - -fn out_of_terminal(pos: Pos2, layout: &Response) -> bool { - !(pos.x > layout.rect.min.x - && pos.x < layout.rect.max.x - && pos.y > layout.rect.min.y - && pos.y < layout.rect.max.y) -} diff --git a/nxshell/src/app.rs b/nxshell/src/app.rs index 1f5e5f5..9476328 100644 --- a/nxshell/src/app.rs +++ b/nxshell/src/app.rs @@ -126,11 +126,6 @@ impl eframe::App for NxShell { ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { ui.label("Sessions"); }); - - // TODO: add close menu - // ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| { - // ui.label("Sessions"); - // }); }); self.search_sessions(ui);