zng_wgt_text_input/
selectable.rs

1//! Selectable text.
2
3use zng_ext_clipboard::COPY_CMD;
4use zng_wgt::prelude::*;
5use zng_wgt_button::Button;
6use zng_wgt_input::focus::FocusableMix;
7use zng_wgt_menu::{
8    self as menu,
9    context::{ContextMenu, context_menu_fn},
10};
11use zng_wgt_style::{Style, StyleMix, impl_style_fn};
12use zng_wgt_text::{self as text, *};
13
14#[doc(hidden)]
15pub use zng_wgt::prelude::formatx as __formatx;
16
17/// Styleable read-only text widget that can be selected and copied to clipboard.
18///
19/// # Shorthand
20///
21/// The same [`Text!`](struct@zng_wgt_text::Text#shorthand) shorthand can be used in this macro.
22#[widget($crate::selectable::SelectableText {
23    ($txt:literal) => {
24        txt = $crate::selectable::__formatx!($txt);
25    };
26    ($txt:expr) => {
27        txt = $txt;
28    };
29    ($txt:tt, $($format:tt)*) => {
30        txt = $crate::selectable::__formatx!($txt, $($format)*);
31    };
32})]
33pub struct SelectableText(FocusableMix<StyleMix<zng_wgt_text::Text>>);
34impl SelectableText {
35    fn widget_intrinsic(&mut self) {
36        self.style_intrinsic(STYLE_FN_VAR, property_id!(self::style_fn));
37        widget_set! {
38            self;
39            txt_selectable = true;
40        }
41    }
42}
43impl_style_fn!(SelectableText, DefaultStyle);
44
45/// Default selectable text style.
46#[widget($crate::selectable::DefaultStyle)]
47pub struct DefaultStyle(Style);
48impl DefaultStyle {
49    fn widget_intrinsic(&mut self) {
50        use zng_wgt_input::*;
51        use zng_wgt_layer::*;
52
53        widget_set! {
54            self;
55            replace = true;
56            cursor = CursorIcon::Text;
57
58            popup::context_capture = crate::default_popup_context_capture();
59            context_menu_fn = WidgetFn::new(default_context_menu);
60            selection_toolbar_fn = WidgetFn::new(default_selection_toolbar);
61            selection_color = colors::ACCENT_COLOR_VAR.rgba_map(|c| c.with_alpha(30.pct()));
62        }
63    }
64}
65
66/// Context menu set by the [`DefaultStyle!`].
67///
68/// [`DefaultStyle!`]: struct@DefaultStyle
69pub fn default_context_menu(args: menu::context::ContextMenuArgs) -> UiNode {
70    let id = args.anchor_id;
71    ContextMenu!(ui_vec![Button!(COPY_CMD.scoped(id)), Button!(text::cmd::SELECT_ALL_CMD.scoped(id)),])
72}
73
74/// Selection toolbar set by the [`DefaultStyle!`].
75///
76/// [`DefaultStyle!`]: struct@DefaultStyle
77pub fn default_selection_toolbar(args: text::SelectionToolbarArgs) -> UiNode {
78    if args.is_touch {
79        let id = args.anchor_id;
80        ContextMenu! {
81            style_fn = menu::context::TouchStyle!();
82            children = ui_vec![Button!(COPY_CMD.scoped(id)), Button!(text::cmd::SELECT_ALL_CMD.scoped(id))];
83        }
84    } else {
85        UiNode::nil()
86    }
87}