cranpose_ui/widgets/
text_selection_menu.rs1#![allow(non_snake_case)]
8
9use std::rc::Rc;
10
11use crate::composable;
12use crate::modifier::{Color, Modifier};
13use crate::text::TextStyle;
14use crate::widgets::box_widget::{Box, BoxSpec};
15use crate::widgets::popup::Popup;
16use crate::widgets::{Row, RowSpec, Text};
17use cranpose_ui_graphics::{Point, Rect};
18
19const MENU_BG: Color = Color(0.18, 0.18, 0.2, 0.96);
21const MENU_FG: Color = Color(0.96, 0.96, 0.98, 1.0);
23const MENU_HEIGHT: f32 = 40.0;
26
27fn menu_text_style() -> TextStyle {
28 let mut style = TextStyle::default();
29 style.span_style.color = Some(MENU_FG);
30 style
31}
32
33fn menu_item(label: &str, action: Rc<dyn Fn()>) {
35 Text(
36 label.to_string(),
37 Modifier::empty()
38 .padding(10.0)
39 .clickable(move |_point| action()),
40 menu_text_style(),
41 );
42}
43
44#[composable]
50pub fn TextSelectionMenu(
51 anchor: Point,
52 can_paste: bool,
53 on_copy: impl Fn() + 'static,
54 on_cut: impl Fn() + 'static,
55 on_paste: impl Fn() + 'static,
56 on_select_all: impl Fn() + 'static,
57) {
58 let popup_anchor = Rect {
60 x: (anchor.x - 8.0).max(0.0),
61 y: (anchor.y - MENU_HEIGHT).max(0.0),
62 width: 0.0,
63 height: 0.0,
64 };
65
66 let on_copy: Rc<dyn Fn()> = Rc::new(on_copy);
67 let on_cut: Rc<dyn Fn()> = Rc::new(on_cut);
68 let on_paste: Rc<dyn Fn()> = Rc::new(on_paste);
69 let on_select_all: Rc<dyn Fn()> = Rc::new(on_select_all);
70
71 Popup(popup_anchor, Point { x: 0.0, y: 0.0 }, move || {
72 let on_copy = Rc::clone(&on_copy);
73 let on_cut = Rc::clone(&on_cut);
74 let on_paste = Rc::clone(&on_paste);
75 let on_select_all = Rc::clone(&on_select_all);
76 Box(
77 Modifier::empty().background(MENU_BG).rounded_corners(6.0),
78 BoxSpec::default(),
79 move || {
80 let on_copy = Rc::clone(&on_copy);
81 let on_cut = Rc::clone(&on_cut);
82 let on_paste = Rc::clone(&on_paste);
83 let on_select_all = Rc::clone(&on_select_all);
84 Row(Modifier::empty(), RowSpec::default(), move || {
85 menu_item("Copy", Rc::clone(&on_copy));
86 menu_item("Cut", Rc::clone(&on_cut));
87 if can_paste {
88 menu_item("Paste", Rc::clone(&on_paste));
89 }
90 menu_item("Select all", Rc::clone(&on_select_all));
91 });
92 },
93 );
94 });
95}