commit 9033383a290426747963f5566fcb4eaa5f07c167
parent c6045279ddf8a99fe1ea1e7f76fd8f938361dffd
Author: William Casarin <jb55@jb55.com>
Date: Tue, 10 Jun 2025 07:23:55 -0700
add input context menu helper
We are going to want this in more places
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
9 files changed, 82 insertions(+), 28 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -3300,6 +3300,7 @@ dependencies = [
"bitflags 2.9.0",
"blurhash",
"egui",
+ "egui-winit",
"egui_extras",
"ehttp",
"enostr",
@@ -3309,6 +3310,8 @@ dependencies = [
"notedeck",
"poll-promise",
"profiling",
+ "strum",
+ "strum_macros",
"tokio",
"tracing",
]
diff --git a/crates/notedeck_columns/src/accounts/mod.rs b/crates/notedeck_columns/src/accounts/mod.rs
@@ -15,6 +15,7 @@ use crate::{
accounts::{AccountsView, AccountsViewResponse},
},
};
+use egui_winit::clipboard::Clipboard;
use tracing::info;
mod route;
@@ -31,6 +32,7 @@ pub fn render_accounts_route(
accounts: &mut Accounts,
decks: &mut DecksCache,
login_state: &mut AcquireKeyState,
+ clipboard: &mut Clipboard,
route: AccountsRoute,
) -> AddAccountAction {
let resp = match route {
@@ -39,7 +41,7 @@ pub fn render_accounts_route(
.inner
.map(AccountsRouteResponse::Accounts),
- AccountsRoute::AddAccount => AccountLoginView::new(login_state)
+ AccountsRoute::AddAccount => AccountLoginView::new(login_state, clipboard)
.ui(ui)
.inner
.map(AccountsRouteResponse::AddAccount),
diff --git a/crates/notedeck_columns/src/login_manager.rs b/crates/notedeck_columns/src/login_manager.rs
@@ -28,6 +28,10 @@ impl<'a> AcquireKeyState {
textedit_closure(&mut self.desired_key)
}
+ pub fn input_buffer(&mut self) -> &mut String {
+ &mut self.desired_key
+ }
+
/// User pressed the 'acquire' button
pub fn apply_acquire(&'a mut self) {
let new_promise = match &self.promise_query {
diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs
@@ -423,6 +423,7 @@ fn render_nav_body(
ctx.accounts,
&mut app.decks_cache,
&mut app.view_state.login,
+ ctx.clipboard,
*amr,
);
let txn = Transaction::new(ctx.ndb).expect("txn");
diff --git a/crates/notedeck_columns/src/ui/account_login_view.rs b/crates/notedeck_columns/src/ui/account_login_view.rs
@@ -4,11 +4,14 @@ use egui::{
Align, Button, Color32, Frame, Image, InnerResponse, Margin, RichText, TextBuffer, Vec2,
};
use egui::{Layout, TextEdit};
+use egui_winit::clipboard::Clipboard;
use enostr::Keypair;
use notedeck::{fonts::get_font_size, AppAction, NotedeckTextStyle};
+use notedeck_ui::context_menu::{input_context, PasteBehavior};
pub struct AccountLoginView<'a> {
manager: &'a mut AcquireKeyState,
+ clipboard: &'a mut Clipboard,
}
pub enum AccountLoginResponse {
@@ -17,8 +20,8 @@ pub enum AccountLoginResponse {
}
impl<'a> AccountLoginView<'a> {
- pub fn new(state: &'a mut AcquireKeyState) -> Self {
- AccountLoginView { manager: state }
+ pub fn new(manager: &'a mut AcquireKeyState, clipboard: &'a mut Clipboard) -> Self {
+ AccountLoginView { manager, clipboard }
}
pub fn ui(&mut self, ui: &mut egui::Ui) -> InnerResponse<Option<AccountLoginResponse>> {
@@ -42,7 +45,9 @@ impl<'a> AccountLoginView<'a> {
let button_width = 32.0;
let text_edit_width = available_width - button_width;
- ui.add_sized([text_edit_width, 40.0], login_textedit(self.manager));
+ let textedit_resp = ui.add_sized([text_edit_width, 40.0], login_textedit(self.manager));
+ input_context(&textedit_resp, self.clipboard, self.manager.input_buffer(), PasteBehavior::Clear);
+
if eye_button(ui, self.manager.password_visible()).clicked() {
self.manager.toggle_password_visibility();
}
@@ -154,12 +159,8 @@ mod preview {
}
impl App for AccountLoginPreview {
- fn update(
- &mut self,
- _app_ctx: &mut AppContext<'_>,
- ui: &mut egui::Ui,
- ) -> Option<AppAction> {
- AccountLoginView::new(&mut self.manager).ui(ui);
+ fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> {
+ AccountLoginView::new(&mut self.manager, ctx.clipboard).ui(ui);
None
}
diff --git a/crates/notedeck_columns/src/ui/search/mod.rs b/crates/notedeck_columns/src/ui/search/mod.rs
@@ -6,7 +6,12 @@ use crate::{timeline::TimelineTab, ui::timeline::TimelineTabView};
use egui_winit::clipboard::Clipboard;
use nostrdb::{Filter, Ndb, Transaction};
use notedeck::{MuteFun, NoteAction, NoteContext, NoteRef};
-use notedeck_ui::{icons::search_icon, jobs::JobsCache, padding, NoteOptions};
+use notedeck_ui::{
+ context_menu::{input_context, PasteBehavior},
+ icons::search_icon,
+ jobs::JobsCache,
+ padding, NoteOptions,
+};
use std::time::{Duration, Instant};
use tracing::{error, info, warn};
@@ -296,21 +301,7 @@ fn search_box(
.frame(false),
);
- response.context_menu(|ui| {
- if ui.button("paste").clicked() {
- if let Some(text) = clipboard.get() {
- input.clear();
- input.push_str(&text);
- }
- }
- });
-
- if response.middle_clicked() {
- if let Some(text) = clipboard.get() {
- input.clear();
- input.push_str(&text);
- }
- }
+ input_context(&response, clipboard, input, PasteBehavior::Append);
let mut requested_focus = false;
if focus_state == FocusState::ShouldRequestFocus {
diff --git a/crates/notedeck_ui/Cargo.toml b/crates/notedeck_ui/Cargo.toml
@@ -6,6 +6,9 @@ version.workspace = true
[dependencies]
egui = { workspace = true }
egui_extras = { workspace = true }
+egui-winit = { workspace = true }
+strum_macros = { workspace = true }
+strum = { workspace = true }
ehttp = { workspace = true }
nostrdb = { workspace = true }
tracing = { workspace = true }
@@ -18,4 +21,4 @@ bitflags = { workspace = true }
enostr = { workspace = true }
hashbrown = { workspace = true }
-blurhash = "0.2.3"
-\ No newline at end of file
+blurhash = "0.2.3"
diff --git a/crates/notedeck_ui/src/context_menu.rs b/crates/notedeck_ui/src/context_menu.rs
@@ -0,0 +1,49 @@
+/// Context menu helpers (paste, etc)
+use egui_winit::clipboard::Clipboard;
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub enum PasteBehavior {
+ Clear,
+ Append,
+}
+
+fn handle_paste(clipboard: &mut Clipboard, input: &mut String, paste_behavior: PasteBehavior) {
+ if let Some(text) = clipboard.get() {
+ // if called with clearing_input_context, then we clear before
+ // we paste. Useful for certain fields like passwords, etc
+ match paste_behavior {
+ PasteBehavior::Clear => input.clear(),
+ PasteBehavior::Append => {}
+ }
+ input.push_str(&text);
+ }
+}
+
+pub fn input_context(
+ response: &egui::Response,
+ clipboard: &mut Clipboard,
+ input: &mut String,
+ paste_behavior: PasteBehavior,
+) {
+ response.context_menu(|ui| {
+ if ui.button("Paste").clicked() {
+ handle_paste(clipboard, input, paste_behavior);
+ ui.close_menu();
+ }
+
+ if ui.button("Copy").clicked() {
+ clipboard.set_text(input.to_owned());
+ ui.close_menu();
+ }
+
+ if ui.button("Cut").clicked() {
+ clipboard.set_text(input.to_owned());
+ input.clear();
+ ui.close_menu();
+ }
+ });
+
+ if response.middle_clicked() {
+ handle_paste(clipboard, input, paste_behavior)
+ }
+}
diff --git a/crates/notedeck_ui/src/lib.rs b/crates/notedeck_ui/src/lib.rs
@@ -3,6 +3,7 @@ pub mod blur;
pub mod colors;
pub mod constants;
pub mod contacts;
+pub mod context_menu;
pub mod gif;
pub mod icons;
pub mod images;