StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.
| 1 | use strato_ui::color::ColorU; |
| 2 | use strato_ui::elements::{ |
| 3 | Align, Container, CornerRadius, CrossAxisAlignment, Fill, Flex, ParentElement, Radius, Text, |
| 4 | }; |
| 5 | use strato_ui::fonts::FamilyId; |
| 6 | use strato_ui::presenter::ChildView; |
| 7 | use strato_ui::ui_components::components::{Coords, UiComponentStyles}; |
| 8 | use strato_ui::ui_components::segmented_control::{ |
| 9 | LabelConfig, RenderableOptionConfig, SegmentedControl, SegmentedControlEvent, |
| 10 | }; |
| 11 | use strato_ui::SingletonEntity as _; |
| 12 | use strato_ui::{AppContext, Element, Entity, TypedActionView, View, ViewContext, ViewHandle}; |
| 13 | |
| 14 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 15 | pub enum DisplayMode { |
| 16 | Rendered, |
| 17 | Raw, |
| 18 | } |
| 19 | |
| 20 | pub struct RootView { |
| 21 | font_family: FamilyId, |
| 22 | segmented_control: ViewHandle<SegmentedControl<DisplayMode>>, |
| 23 | selected_mode: DisplayMode, |
| 24 | } |
| 25 | |
| 26 | impl RootView { |
| 27 | pub fn new(ctx: &mut ViewContext<Self>) -> Self { |
| 28 | let font_family = strato_ui::fonts::Cache::handle(ctx) |
| 29 | .update(ctx, |cache, _| cache.load_system_font("Arial").unwrap()); |
| 30 | |
| 31 | let segmented_control = ctx.add_typed_action_view(move |_ctx| { |
| 32 | SegmentedControl::new( |
| 33 | vec![DisplayMode::Rendered, DisplayMode::Raw], |
| 34 | move |mode, is_selected, _app| { |
| 35 | Some(RenderableOptionConfig { |
| 36 | icon_path: "", |
| 37 | icon_color: ColorU::white(), |
| 38 | label: Some(LabelConfig { |
| 39 | label: match mode { |
| 40 | DisplayMode::Rendered => "Rendered".into(), |
| 41 | DisplayMode::Raw => "Raw".into(), |
| 42 | }, |
| 43 | width_override: Some(55.0), |
| 44 | color: if is_selected { |
| 45 | ColorU::new(100, 200, 255, 255) // accent color |
| 46 | } else { |
| 47 | ColorU::white() |
| 48 | }, |
| 49 | }), |
| 50 | tooltip: None, |
| 51 | background: if is_selected { |
| 52 | Fill::Solid(ColorU::new(60, 60, 60, 255)) // surface_3 |
| 53 | } else { |
| 54 | Fill::None |
| 55 | }, |
| 56 | }) |
| 57 | }, |
| 58 | DisplayMode::Rendered, |
| 59 | segmented_control_styles(font_family), |
| 60 | ) |
| 61 | }); |
| 62 | |
| 63 | ctx.subscribe_to_view(&segmented_control, |me, _, event, ctx| { |
| 64 | let SegmentedControlEvent::OptionSelected(mode) = event; |
| 65 | me.selected_mode = *mode; |
| 66 | ctx.notify(); |
| 67 | }); |
| 68 | |
| 69 | Self { |
| 70 | font_family, |
| 71 | segmented_control, |
| 72 | selected_mode: DisplayMode::Rendered, |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | fn segmented_control_styles(font_family: FamilyId) -> UiComponentStyles { |
| 78 | UiComponentStyles { |
| 79 | font_family_id: Some(font_family), |
| 80 | font_size: Some(12.0), |
| 81 | border_radius: Some(CornerRadius::with_all(Radius::Pixels(4.0))), |
| 82 | border_width: Some(1.0), |
| 83 | border_color: Some(Fill::Solid(ColorU::new(60, 60, 60, 255))), // surface_3 |
| 84 | background: Some(Fill::Solid(ColorU::new(30, 30, 30, 255))), // background |
| 85 | height: Some(20.0), |
| 86 | padding: Some(Coords::uniform(2.0)), |
| 87 | margin: Some(Coords { |
| 88 | top: 0.0, |
| 89 | bottom: 0.0, |
| 90 | left: 0.0, |
| 91 | right: 8.0, |
| 92 | }), |
| 93 | ..Default::default() |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | impl Entity for RootView { |
| 98 | type Event = (); |
| 99 | } |
| 100 | |
| 101 | impl View for RootView { |
| 102 | fn ui_name() -> &'static str { |
| 103 | "RootView" |
| 104 | } |
| 105 | |
| 106 | fn render(&self, _app: &AppContext) -> Box<dyn Element> { |
| 107 | let status_text = format!("Selected: {:?}", self.selected_mode); |
| 108 | |
| 109 | let content = Flex::column() |
| 110 | .with_spacing(20.0) |
| 111 | .with_cross_axis_alignment(CrossAxisAlignment::Center) |
| 112 | .with_child( |
| 113 | Text::new_inline("Segmented Control Example", self.font_family, 20.0) |
| 114 | .with_color(ColorU::white()) |
| 115 | .finish(), |
| 116 | ) |
| 117 | .with_child(ChildView::new(&self.segmented_control).finish()) |
| 118 | .with_child( |
| 119 | Text::new_inline(status_text, self.font_family, 14.0) |
| 120 | .with_color(ColorU::new(150, 150, 150, 255)) |
| 121 | .finish(), |
| 122 | ) |
| 123 | .finish(); |
| 124 | |
| 125 | Container::new(Align::new(content).finish()) |
| 126 | .with_background_color(ColorU::new(20, 20, 20, 255)) |
| 127 | .finish() |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | impl TypedActionView for RootView { |
| 132 | type Action = (); |
| 133 | } |
| 134 |