1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![expect(clippy::type_complexity)]
11#![warn(unused_extern_crates)]
12#![warn(missing_docs)]
13
14zng_wgt::enable_widget_macros!();
15
16use zng_wgt::prelude::*;
17
18#[macro_use]
19extern crate bitflags;
20
21pub mod cmd;
22pub mod node;
23mod text_properties;
24pub use text_properties::*;
25
26#[doc(hidden)]
27pub use zng_wgt::prelude::formatx as __formatx;
28
29pub mod icon;
30
31#[widget($crate::Text {
95 ($txt:literal) => {
96 txt = $crate::__formatx!($txt);
97 };
98 ($txt:expr) => {
99 txt = $txt;
100 };
101 ($txt:tt, $($format:tt)*) => {
102 txt = $crate::__formatx!($txt, $($format)*);
103 };
104})]
105#[rustfmt::skip]
106pub struct Text(
107 FontMix<
108 TextFillMix<
109 TextAlignMix<
110 TextWrapMix<
111 TextDecorationMix<
112 TextSpacingMix<
113 TextTransformMix<
114 LangMix<
115 FontFeaturesMix<
116 ParagraphMix<
117 TextEditMix<
118 SelectionToolbarMix<
119 TextInspectMix<
120 WidgetBase
121 >>>>>>>>>>>>>
122);
123
124impl Text {
125 pub fn context_vars_set(set: &mut ContextValueSet) {
127 FontMix::<()>::context_vars_set(set);
128 TextFillMix::<()>::context_vars_set(set);
129 TextAlignMix::<()>::context_vars_set(set);
130 TextWrapMix::<()>::context_vars_set(set);
131 TextDecorationMix::<()>::context_vars_set(set);
132 TextSpacingMix::<()>::context_vars_set(set);
133 TextTransformMix::<()>::context_vars_set(set);
134 FontFeaturesMix::<()>::context_vars_set(set);
135 TextEditMix::<()>::context_vars_set(set);
136 SelectionToolbarMix::<()>::context_vars_set(set);
137 TextInspectMix::<()>::context_vars_set(set);
138
139 LangMix::<()>::context_vars_set(set);
140 }
141}
142
143#[property(CHILD, default(""), widget_impl(Text))]
147pub fn txt(wgt: &mut WidgetBuilding, txt: impl IntoVar<Txt>) {
148 let _ = txt;
149 wgt.expect_property_capture();
150}
151
152#[property(CHILD, widget_impl(Text))]
171pub fn txt_parse<T>(child: impl IntoUiNode, value: impl IntoVar<T>) -> UiNode
172where
173 T: TxtParseValue,
174{
175 node::parse_text(child, value)
176}
177
178#[diagnostic::on_unimplemented(note = "`TxtParseValue` is implemented for all `T: VarValue + Display + FromStr<Error: Display>")]
185pub trait TxtParseValue: VarValue {
186 fn from_txt(txt: &Txt) -> Result<Self, Txt>;
190 fn to_txt(&self) -> Txt;
194}
195impl<T> TxtParseValue for T
196where
197 T: VarValue + std::str::FromStr + std::fmt::Display,
198 <Self as std::str::FromStr>::Err: std::fmt::Display,
199{
200 fn from_txt(txt: &Txt) -> Result<Self, Txt> {
201 T::from_str(txt).map_err(|e| e.to_txt())
202 }
203
204 fn to_txt(&self) -> Txt {
205 ToTxt::to_txt(self)
206 }
207}
208
209impl Text {
210 fn widget_intrinsic(&mut self) {
211 self.widget_builder().push_build_action(|wgt| {
212 let child = node::render_text();
213 let child = node::non_interactive_caret(child);
214 let child = node::interactive_carets(child);
215 let child = node::render_overlines(child);
216 let child = node::render_strikethroughs(child);
217 let child = node::render_underlines(child);
218 let child = node::render_ime_preview_underlines(child);
219 let child = node::render_selection(child);
220 wgt.set_child(child);
221
222 wgt.push_intrinsic(NestGroup::CHILD_LAYOUT + 100, "layout_text", |child| {
223 let child = node::selection_toolbar_node(child);
224 node::layout_text(child)
225 });
226
227 let text = if wgt.property(property_id!(Self::txt_parse)).is_some() {
228 wgt.capture_var(property_id!(Self::txt)).unwrap_or_else(|| var(Txt::from_str("")))
229 } else {
230 wgt.capture_var_or_default(property_id!(Self::txt))
231 };
232 wgt.push_intrinsic(NestGroup::EVENT, "resolve_text", |child| {
233 let child = node::rich_text_component(child, "text");
234 node::resolve_text(child, text)
235 });
236 });
237 }
238}
239
240#[doc(hidden)]
241pub use zng_ext_font::{FontStyle as __FontStyle, FontWeight as __FontWeight};
242
243#[macro_export]
253macro_rules! Strong {
254 ($txt:expr) => {
255 $crate::Text! {
256 txt = $txt;
257 font_weight = $crate::__FontWeight::BOLD;
258 }
259 };
260 ($txt:tt, $($format:tt)*) => {
261 $crate::Text! {
262 txt = $crate::__formatx!($txt, $($format)*);
263 font_weight = $crate::__FontWeight::BOLD;
264 }
265 };
266}
267
268#[macro_export]
278macro_rules! Em {
279 ($txt:expr) => {
280 $crate::Text! {
281 txt = $txt;
282 font_style = $crate::__FontStyle::Italic;
283 }
284 };
285 ($txt:tt, $($format:tt)*) => {
286 $crate::Text! {
287 txt = $crate::__formatx!($txt, $($format)*);
288 font_style = $crate::__FontStyle::Italic;
289 }
290 };
291}