context_menu.rs (3282B)
1 /// Context menu helpers (paste, etc) 2 use egui_winit::clipboard::Clipboard; 3 4 #[derive(Copy, Clone, Eq, PartialEq)] 5 pub enum PasteBehavior { 6 Clear, 7 Append, 8 } 9 10 fn handle_paste(clipboard: &mut Clipboard, input: &mut String, paste_behavior: PasteBehavior) { 11 if let Some(text) = clipboard.get() { 12 // if called with clearing_input_context, then we clear before 13 // we paste. Useful for certain fields like passwords, etc 14 match paste_behavior { 15 PasteBehavior::Clear => input.clear(), 16 PasteBehavior::Append => {} 17 } 18 input.push_str(&text); 19 } 20 } 21 22 pub fn input_context( 23 ui: &mut egui::Ui, 24 response: &egui::Response, 25 clipboard: &mut Clipboard, 26 input: &mut String, 27 paste_behavior: PasteBehavior, 28 ) { 29 response.context_menu(|ui| { 30 if ui.button("Paste").clicked() { 31 handle_paste(clipboard, input, paste_behavior); 32 ui.close_menu(); 33 } 34 35 if ui.button("Copy").clicked() { 36 clipboard.set_text(input.to_owned()); 37 ui.close_menu(); 38 } 39 40 if ui.button("Cut").clicked() { 41 clipboard.set_text(input.to_owned()); 42 input.clear(); 43 ui.close_menu(); 44 } 45 }); 46 47 if response.middle_clicked() { 48 handle_paste(clipboard, input, paste_behavior) 49 } 50 51 // for keyboard visibility 52 crate::include_input(ui, response) 53 } 54 55 pub fn stationary_arbitrary_menu_button<R>( 56 ui: &mut egui::Ui, 57 button_response: egui::Response, 58 add_contents: impl FnOnce(&mut egui::Ui) -> R, 59 ) -> egui::InnerResponse<Option<R>> { 60 let bar_id = ui.id(); 61 let mut bar_state = egui::menu::BarState::load(ui.ctx(), bar_id); 62 63 let inner = bar_state.bar_menu(&button_response, add_contents); 64 65 bar_state.store(ui.ctx(), bar_id); 66 egui::InnerResponse::new(inner.map(|r| r.inner), button_response) 67 } 68 69 pub fn context_button(ui: &mut egui::Ui, id: egui::Id, put_at: egui::Rect) -> egui::Response { 70 let min_radius = 2.0; 71 let anim_speed = 0.05; 72 let response = ui.interact(put_at, id, egui::Sense::click()); 73 74 let hovered = response.hovered(); 75 let animation_progress = ui.ctx().animate_bool_with_time(id, hovered, anim_speed); 76 77 if hovered { 78 ui.ctx().set_cursor_icon(egui::CursorIcon::PointingHand); 79 } 80 81 let max_distance = 2.0; 82 let expansion_mult = 2.0; 83 let min_distance = max_distance / expansion_mult; 84 let cur_distance = min_distance + (max_distance - min_distance) * animation_progress; 85 86 let max_radius = 4.0; 87 let cur_radius = min_radius + (max_radius - min_radius) * animation_progress; 88 89 let center = put_at.center(); 90 let left_circle_center = center - egui::vec2(cur_distance + cur_radius, 0.0); 91 let right_circle_center = center + egui::vec2(cur_distance + cur_radius, 0.0); 92 93 let translated_radius = (cur_radius - 1.0) / 2.0; 94 95 // This works in both themes 96 let color = ui.style().visuals.noninteractive().fg_stroke.color; 97 98 // Draw circles 99 let painter = ui.painter_at(put_at); 100 painter.circle_filled(left_circle_center, translated_radius, color); 101 painter.circle_filled(center, translated_radius, color); 102 painter.circle_filled(right_circle_center, translated_radius, color); 103 104 response 105 }