Skip to content

Commit fd1e638

Browse files
authored
feat: use builtin context menu (#38)
* chore: use builtin context menu * feat: use builtin context menu * chore: reuse toast * chore: clean code
1 parent 1fd5684 commit fd1e638

File tree

12 files changed

+97
-123
lines changed

12 files changed

+97
-123
lines changed

crates/egui-term/examples/custom_bindings.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ impl eframe::App for App {
9292
active_tab_id: &mut self.active_id,
9393
};
9494
let terminal = TerminalView::new(ui, term_ctx, term_opt)
95-
.set_focus(true)
9695
.add_bindings(self.custom_terminal_bindings.clone())
9796
.set_size(Vec2::new(ui.available_width(), ui.available_height()));
9897

crates/egui-term/examples/tabs.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,8 @@ impl eframe::App for App {
8181
default_font_size: 14.,
8282
active_tab_id: &mut self.active_tab,
8383
};
84-
let terminal = TerminalView::new(ui, term_ctx, term_opt)
85-
.set_focus(true)
86-
.set_size(ui.available_size());
84+
let terminal =
85+
TerminalView::new(ui, term_ctx, term_opt).set_size(ui.available_size());
8786

8887
ui.add(terminal);
8988
}

crates/egui-term/examples/themes.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ impl eframe::App for App {
107107
active_tab_id: &mut self.active_id,
108108
};
109109
let terminal = TerminalView::new(ui, term_ctx, term_opt)
110-
.set_focus(true)
111110
.set_size(Vec2::new(ui.available_width(), ui.available_height()));
112111

113112
ui.add(terminal);

crates/egui-term/src/display/mod.rs

Lines changed: 1 addition & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@ use alacritty_terminal::grid::GridCell;
88
use alacritty_terminal::term::cell::Flags;
99
use alacritty_terminal::term::TermMode;
1010
use alacritty_terminal::vte::ansi::{Color, NamedColor};
11-
use copypasta::ClipboardProvider;
1211
use egui::epaint::RectShape;
13-
use egui::{
14-
Align2, Area, Button, Color32, CornerRadius, CursorIcon, Id, Key, KeyboardShortcut, Modifiers,
15-
Painter, Pos2, Rect, Response, Vec2, WidgetText,
16-
};
12+
use egui::{Align2, CornerRadius, CursorIcon, Painter, Pos2, Rect, Response, Vec2};
1713
use egui::{Shape, Stroke};
1814

1915
impl TerminalView<'_> {
@@ -146,82 +142,3 @@ impl TerminalView<'_> {
146142
painter.extend(shapes);
147143
}
148144
}
149-
150-
impl TerminalView<'_> {
151-
pub fn context_menu(&mut self, pos: Pos2, layout: &Response, ui: &mut egui::Ui) {
152-
Area::new(Id::new(format!("context_menu_{:?}", self.id())))
153-
.fixed_pos(pos)
154-
.order(egui::Order::Foreground)
155-
.show(ui.ctx(), |ui| {
156-
egui::Frame::popup(ui.style()).show(ui, |ui| {
157-
let width = 200.;
158-
ui.set_width(width);
159-
// copy btn
160-
self.copy_btn(ui, layout, width);
161-
// paste btn
162-
self.paste_btn(ui, width);
163-
164-
ui.separator();
165-
// select all btn
166-
self.select_all_btn(ui, width);
167-
});
168-
});
169-
}
170-
171-
fn copy_btn(&mut self, ui: &mut egui::Ui, layout: &Response, btn_width: f32) {
172-
#[cfg(not(target_os = "macos"))]
173-
let copy_shortcut = KeyboardShortcut::new(Modifiers::CTRL | Modifiers::SHIFT, Key::C);
174-
#[cfg(target_os = "macos")]
175-
let copy_shortcut = KeyboardShortcut::new(Modifiers::MAC_CMD, Key::C);
176-
let copy_shortcut = ui.ctx().format_shortcut(&copy_shortcut);
177-
let copy_btn = context_btn("Copy", btn_width, Some(copy_shortcut));
178-
if ui.add(copy_btn).clicked() {
179-
let data = self.term_ctx.selection_content();
180-
layout.ctx.copy_text(data);
181-
ui.close();
182-
}
183-
}
184-
185-
fn paste_btn(&mut self, ui: &mut egui::Ui, btn_width: f32) {
186-
#[cfg(not(target_os = "macos"))]
187-
let paste_shortcut = KeyboardShortcut::new(Modifiers::CTRL | Modifiers::SHIFT, Key::V);
188-
#[cfg(target_os = "macos")]
189-
let paste_shortcut = KeyboardShortcut::new(Modifiers::MAC_CMD, Key::V);
190-
let paste_shortcut = ui.ctx().format_shortcut(&paste_shortcut);
191-
let paste_btn = context_btn("Paste", btn_width, Some(paste_shortcut));
192-
if ui.add(paste_btn).clicked() {
193-
if let Ok(data) = self.term_ctx.clipboard.get_contents() {
194-
self.term_ctx.write_data(data.into_bytes());
195-
self.term_ctx.terminal.selection = None;
196-
}
197-
ui.close();
198-
}
199-
}
200-
201-
fn select_all_btn(&mut self, ui: &mut egui::Ui, btn_width: f32) {
202-
#[cfg(not(target_os = "macos"))]
203-
let select_all_shortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::A);
204-
#[cfg(target_os = "macos")]
205-
let select_all_shortcut = KeyboardShortcut::new(Modifiers::MAC_CMD, Key::A);
206-
let select_all_shortcut = ui.ctx().format_shortcut(&select_all_shortcut);
207-
let select_all_btn = context_btn("Select All", btn_width, Some(select_all_shortcut));
208-
if ui.add(select_all_btn).clicked() {
209-
self.term_ctx.select_all();
210-
ui.close();
211-
}
212-
}
213-
}
214-
215-
fn context_btn<'a>(
216-
text: impl Into<WidgetText>,
217-
width: f32,
218-
shortcut: Option<String>,
219-
) -> Button<'a> {
220-
let mut btn = Button::new(text)
221-
.fill(Color32::TRANSPARENT)
222-
.min_size((width, 0.).into());
223-
if let Some(shortcut) = shortcut {
224-
btn = btn.shortcut_text(shortcut);
225-
}
226-
btn
227-
}

crates/egui-term/src/input/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,6 @@ impl TerminalView<'_> {
133133
PointerButton::Primary => {
134134
self.left_button_click(state, layout, position, modifiers, pressed)
135135
}
136-
PointerButton::Secondary => {
137-
state.context_menu_position = Some(position);
138-
None
139-
}
140136
_ => None,
141137
}
142138
}
@@ -149,7 +145,7 @@ impl TerminalView<'_> {
149145
modifiers: &Modifiers,
150146
pressed: bool,
151147
) -> Option<InputAction> {
152-
if state.context_menu_position.is_some() {
148+
if layout.context_menu_opened() {
153149
return None;
154150
}
155151
let terminal_mode = self.term_ctx.terminal.mode();

crates/egui-term/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod scroll_bar;
88
mod ssh;
99
mod theme;
1010
mod types;
11+
mod ui;
1112
mod view;
1213

1314
pub use alacritty::{PtyEvent, TermType, Terminal, TerminalContext};

crates/egui-term/src/ui/menu.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::TerminalView;
2+
use copypasta::ClipboardProvider;
3+
use egui::{Button, Key, KeyboardShortcut, Modifiers, Response, WidgetText};
4+
5+
impl TerminalView<'_> {
6+
pub fn context_menu(&mut self, layout: &Response) {
7+
layout.context_menu(|ui| {
8+
let width = 200.;
9+
ui.set_width(width);
10+
// copy btn
11+
self.copy_btn(ui, layout, width);
12+
// paste btn
13+
self.paste_btn(ui, width);
14+
15+
ui.separator();
16+
// select all btn
17+
self.select_all_btn(ui, width);
18+
});
19+
}
20+
21+
fn copy_btn(&mut self, ui: &mut egui::Ui, layout: &Response, btn_width: f32) {
22+
#[cfg(not(target_os = "macos"))]
23+
let copy_shortcut = KeyboardShortcut::new(Modifiers::CTRL | Modifiers::SHIFT, Key::C);
24+
#[cfg(target_os = "macos")]
25+
let copy_shortcut = KeyboardShortcut::new(Modifiers::MAC_CMD, Key::C);
26+
let copy_shortcut = ui.ctx().format_shortcut(&copy_shortcut);
27+
let copy_btn = context_btn("Copy", btn_width, Some(copy_shortcut));
28+
if ui.add(copy_btn).clicked() {
29+
let data = self.term_ctx.selection_content();
30+
layout.ctx.copy_text(data);
31+
ui.close();
32+
}
33+
}
34+
35+
fn paste_btn(&mut self, ui: &mut egui::Ui, btn_width: f32) {
36+
#[cfg(not(target_os = "macos"))]
37+
let paste_shortcut = KeyboardShortcut::new(Modifiers::CTRL | Modifiers::SHIFT, Key::V);
38+
#[cfg(target_os = "macos")]
39+
let paste_shortcut = KeyboardShortcut::new(Modifiers::MAC_CMD, Key::V);
40+
let paste_shortcut = ui.ctx().format_shortcut(&paste_shortcut);
41+
let paste_btn = context_btn("Paste", btn_width, Some(paste_shortcut));
42+
if ui.add(paste_btn).clicked() {
43+
if let Ok(data) = self.term_ctx.clipboard.get_contents() {
44+
self.term_ctx.write_data(data.into_bytes());
45+
self.term_ctx.terminal.selection = None;
46+
}
47+
ui.close();
48+
}
49+
}
50+
51+
fn select_all_btn(&mut self, ui: &mut egui::Ui, btn_width: f32) {
52+
#[cfg(not(target_os = "macos"))]
53+
let select_all_shortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::A);
54+
#[cfg(target_os = "macos")]
55+
let select_all_shortcut = KeyboardShortcut::new(Modifiers::MAC_CMD, Key::A);
56+
let select_all_shortcut = ui.ctx().format_shortcut(&select_all_shortcut);
57+
let select_all_btn = context_btn("Select All", btn_width, Some(select_all_shortcut));
58+
if ui.add(select_all_btn).clicked() {
59+
self.term_ctx.select_all();
60+
ui.close();
61+
}
62+
}
63+
}
64+
65+
fn context_btn<'a>(
66+
text: impl Into<WidgetText>,
67+
width: f32,
68+
shortcut: Option<String>,
69+
) -> Button<'a> {
70+
let mut btn = Button::new(text).min_size((width, 0.).into());
71+
if let Some(shortcut) = shortcut {
72+
btn = btn.shortcut_text(shortcut);
73+
}
74+
btn
75+
}

crates/egui-term/src/ui/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mod menu;

crates/egui-term/src/view.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ pub struct TerminalViewState {
2323
// for terminal
2424
pub mouse_point: Point,
2525
pub mouse_position: Option<Pos2>,
26-
pub context_menu_position: Option<Pos2>,
2726
pub cursor_position: Option<Pos2>,
2827
pub scrollbar_state: ScrollbarState,
2928
}
@@ -79,17 +78,7 @@ impl Widget for TerminalView<'_> {
7978
self.has_focus = false;
8079
}
8180

82-
// context menu
83-
if let Some(pos) = state.context_menu_position {
84-
if is_in_terminal(pos, layout.rect) {
85-
self.context_menu(pos, &layout, ui);
86-
}
87-
}
88-
89-
if ui.input(|input_state| input_state.pointer.primary_clicked()) {
90-
state.context_menu_position = None;
91-
ui.close();
92-
}
81+
self.context_menu(&layout);
9382

9483
let background = self.theme().get_color(Color::Named(NamedColor::Background));
9584

@@ -150,7 +139,7 @@ impl<'a> TerminalView<'a> {
150139

151140
Self {
152141
widget_id,
153-
has_focus: false,
142+
has_focus: true,
154143
size: ui.available_size(),
155144
term_ctx,
156145
options,

nxshell/src/app.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub struct NxShell {
6666
pub clipboard: ClipboardContext,
6767
pub db: DbConn,
6868
pub opts: NxShellOptions,
69+
pub toasts: Toasts,
6970
}
7071

7172
impl NxShell {
@@ -89,6 +90,9 @@ impl NxShell {
8990
..Default::default()
9091
},
9192
state_manager,
93+
toasts: Toasts::new()
94+
.anchor(Align2::CENTER_CENTER, (10.0, 10.0))
95+
.direction(egui::Direction::TopDown),
9296
})
9397
}
9498

@@ -112,10 +116,6 @@ impl eframe::App for NxShell {
112116
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
113117
self.recv_event();
114118

115-
let mut toasts = Toasts::new()
116-
.anchor(Align2::CENTER_CENTER, (10.0, 10.0))
117-
.direction(egui::Direction::TopDown);
118-
119119
egui::TopBottomPanel::top("main_top_panel").show(ctx, |ui| {
120120
self.menubar(ui);
121121
});
@@ -131,7 +131,7 @@ impl eframe::App for NxShell {
131131

132132
self.search_sessions(ui);
133133
ui.separator();
134-
self.list_sessions(ctx, ui, &mut toasts);
134+
self.list_sessions(ctx, ui);
135135
});
136136
egui::TopBottomPanel::bottom("main_bottom_panel").show(ctx, |ui| {
137137
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
@@ -141,14 +141,14 @@ impl eframe::App for NxShell {
141141

142142
if *self.opts.show_add_session_modal.borrow() {
143143
self.opts.surrender_focus();
144-
self.show_add_session_window(ctx, &mut toasts);
144+
self.show_add_session_window(ctx);
145145
}
146146

147147
egui::CentralPanel::default().show(ctx, |_ui| {
148148
self.tab_view(ctx);
149149
});
150150

151-
toasts.show(ctx);
151+
self.toasts.show(ctx);
152152
}
153153
}
154154

@@ -165,7 +165,7 @@ impl NxShell {
165165
}
166166
}
167167

168-
fn list_sessions(&mut self, ctx: &egui::Context, ui: &mut egui::Ui, toasts: &mut Toasts) {
168+
fn list_sessions(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) {
169169
if let Some(sessions) = self.state_manager.sessions.take() {
170170
for (group, sessions) in sessions.iter() {
171171
CollapsingHeader::new(group)
@@ -183,12 +183,12 @@ impl NxShell {
183183
if let Err(err) =
184184
self.add_shell_tab_with_secret(ctx, session)
185185
{
186-
toasts.add(error_toast(err.to_string()));
186+
self.toasts.add(error_toast(err.to_string()));
187187
}
188188
}
189189
Ok(None) => {}
190190
Err(err) => {
191-
toasts.add(error_toast(err.to_string()));
191+
self.toasts.add(error_toast(err.to_string()));
192192
}
193193
}
194194
} else if response.secondary_clicked() {

0 commit comments

Comments
 (0)