Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-renderer/examples/formatted-text/root_view.rs
1//! A UI sample demonstrating how the SelectableArea element can be used.
2 
3use strato_ui::fonts::FamilyId;
4use strato_ui::formatted_text::{parse_markdown, FormattedTextFragment, FormattedTextLine};
5use strato_ui::SingletonEntity as _;
6use strato_ui::{
7 elements::{
8 ChildView, ConstrainedBox, Flex, FormattedTextElement, HeadingFontSizeMultipliers,
9 ParentElement, Rect, SelectableArea, SelectionHandle, Stack, Text,
10 },
11 AppContext, Element, Entity, TypedActionView, View, ViewContext, ViewHandle,
12};
13 
14use strato_ui::color::ColorU;
15use strato_ui::elements::{Align, HighlightedHyperlink, HyperlinkLens};
16 
17pub struct RootView {
18 sub_view: ViewHandle<FormattedTextView>,
19}
20 
21impl RootView {
22 pub fn new(ctx: &mut ViewContext<Self>) -> Self {
23 let sub_view = ctx.add_view(|ctx| {
24 let font_family = strato_ui::fonts::Cache::handle(ctx).update(ctx, |cache, _| {
25 cache.load_system_font("Menlo").expect("Should load Menlo")
26 });
27 let view = FormattedTextView {
28 font_family,
29 highlighted_link: Default::default(),
30 selectable_area_state_handle: Default::default(),
31 };
32 ctx.focus_self();
33 view
34 });
35 Self { sub_view }
36 }
37}
38 
39impl Entity for RootView {
40 type Event = ();
41}
42 
43impl View for RootView {
44 fn ui_name() -> &'static str {
45 "RootView"
46 }
47 
48 fn render(&self, _ctx: &AppContext) -> Box<dyn Element> {
49 ChildView::new(&self.sub_view).finish()
50 }
51}
52 
53pub struct FormattedTextView {
54 font_family: FamilyId,
55 highlighted_link: HighlightedHyperlink,
56 selectable_area_state_handle: SelectionHandle,
57}
58 
59impl Entity for FormattedTextView {
60 type Event = ();
61}
62 
63impl View for FormattedTextView {
64 fn ui_name() -> &'static str {
65 "SelectableExampleView"
66 }
67 
68 fn render(&self, _: &AppContext) -> Box<dyn Element> {
69 Stack::new()
70 .with_child(Rect::new().with_background_color(ColorU::black()).finish())
71 .with_child(
72 SelectableArea::new(
73 self.selectable_area_state_handle.clone(),
74 |selection_args, _, _| {
75 println!("Selected text: {:?}", selection_args.selection);
76 },
77 Align::new(
78 ConstrainedBox::new(
79 Flex::column()
80 .with_children([
81 FormattedTextElement::new(
82 parse_markdown(concat!(
83 "## This is a markdown header\n",
84 "### This is a subheader\n",
85 "This is a ~~strikethrough~~ text.\n",
86 "* list item 1\n",
87 "* list item 2\n",
88 "* list item 3\n",
89 "* list item 4\n",
90 "```rust\n",
91 "fn main() {\n",
92 " println!(\"Hello, world!\");\n",
93 "}\n",
94 "```\n",
95 "fi\n",
96 "cd\n",
97 "this is a [link](https://www.google.com)\n",
98 ))
99 .unwrap()
100 .append_line(
101 FormattedTextLine::Line(vec![
102 FormattedTextFragment::plain_text(
103 "\nThis is a link that dispatches an action: ",
104 ),
105 FormattedTextFragment::hyperlink_action(
106 "press enter",
107 RootViewAction::LinkClicked,
108 ),
109 ]),
110 ),
111 13.,
112 self.font_family,
113 self.font_family,
114 ColorU::white(),
115 self.highlighted_link.clone(),
116 )
117 .with_line_height_ratio(1.2)
118 .with_heading_to_font_size_multipliers(
119 HeadingFontSizeMultipliers {
120 h1: 1.8,
121 h2: 1.5,
122 h3: 1.2,
123 ..Default::default()
124 },
125 )
126 .register_default_click_handlers_with_action_support(
127 |hyperlink_lens, evt, ctx| match hyperlink_lens {
128 HyperlinkLens::Url(url) => {
129 ctx.open_url(url);
130 }
131 HyperlinkLens::Action(action_ref) => {
132 if let Some(root_action) = action_ref
133 .as_any()
134 .downcast_ref::<RootViewAction>(
135 ) {
136 evt.dispatch_typed_action(root_action.clone());
137 }
138 }
139 },
140 )
141 .set_selectable(true)
142 .finish(),
143 Text::new(
144 "This is normal Text (large font, not a header)",
145 self.font_family,
146 13. * 1.5,
147 )
148 .finish(),
149 ])
150 .finish(),
151 )
152 .with_max_width(700.)
153 .finish(),
154 )
155 .finish(),
156 )
157 .finish(),
158 )
159 .finish()
160 }
161}
162 
163#[derive(Debug, Clone)]
164pub enum RootViewAction {
165 LinkClicked,
166}
167 
168impl TypedActionView for RootView {
169 type Action = RootViewAction;
170 
171 fn handle_action(&mut self, action: &Self::Action, _ctx: &mut ViewContext<Self>) {
172 match action {
173 RootViewAction::LinkClicked => {
174 println!("Link clicked");
175 }
176 }
177 }
178}
179