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-core/src/elements/min_size.rs
1use pathfinder_geometry::rect::RectF;
2use pathfinder_geometry::vector::Vector2F;
3 
4use crate::{
5 event::DispatchedEvent,
6 text::{word_boundaries::WordBoundariesPolicy, IsRect, SelectionDirection, SelectionType},
7};
8 
9use super::{
10 AfterLayoutContext, AppContext, Element, EventContext, LayoutContext, PaintContext, Point,
11 SelectableElement, Selection, SelectionFragment, SizeConstraint,
12};
13 
14/// `MinSize` ensures that it takes up *at least* the minimum size constraint specified by its
15/// parent. It's similar to [`super::Align`] but will not grow to fill the maximum space available.
16pub struct MinSize {
17 child: Box<dyn Element>,
18 size: Option<Vector2F>,
19}
20 
21impl MinSize {
22 pub fn new(child: Box<dyn Element>) -> Self {
23 Self { child, size: None }
24 }
25}
26 
27impl Element for MinSize {
28 fn layout(
29 &mut self,
30 constraint: SizeConstraint,
31 ctx: &mut LayoutContext,
32 app: &AppContext,
33 ) -> Vector2F {
34 let child_constraint = SizeConstraint::new(Vector2F::zero(), constraint.max);
35 let mut size = self.child.layout(child_constraint, ctx, app);
36 size.set_x(size.x().max(constraint.min.x()));
37 size.set_y(size.y().max(constraint.min.y()));
38 self.size = Some(size);
39 size
40 }
41 
42 fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &AppContext) {
43 self.child.after_layout(ctx, app);
44 }
45 
46 fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) {
47 let self_center = self.size.expect("Size must be set during paint") / 2.0;
48 let child_center = self
49 .child
50 .size()
51 .expect("Child size must be set during paint")
52 / 2.0;
53 
54 let child_origin = origin - (child_center - self_center);
55 self.child.paint(child_origin, ctx, app);
56 }
57 
58 fn dispatch_event(
59 &mut self,
60 event: &DispatchedEvent,
61 ctx: &mut EventContext,
62 app: &AppContext,
63 ) -> bool {
64 self.child.dispatch_event(event, ctx, app)
65 }
66 
67 fn size(&self) -> Option<Vector2F> {
68 self.size
69 }
70 
71 fn origin(&self) -> Option<Point> {
72 self.child.origin()
73 }
74 
75 fn as_selectable_element(&self) -> Option<&dyn SelectableElement> {
76 Some(self as &dyn SelectableElement)
77 }
78}
79 
80impl SelectableElement for MinSize {
81 fn get_selection(
82 &self,
83 selection_start: Vector2F,
84 selection_end: Vector2F,
85 is_rect: IsRect,
86 ) -> Option<Vec<SelectionFragment>> {
87 self.child
88 .as_selectable_element()
89 .and_then(|selectable_child| {
90 selectable_child.get_selection(selection_start, selection_end, is_rect)
91 })
92 }
93 
94 fn expand_selection(
95 &self,
96 point: Vector2F,
97 direction: SelectionDirection,
98 unit: SelectionType,
99 word_boundaries_policy: &WordBoundariesPolicy,
100 ) -> Option<Vector2F> {
101 self.child
102 .as_selectable_element()
103 .and_then(|selectable_child| {
104 selectable_child.expand_selection(point, direction, unit, word_boundaries_policy)
105 })
106 }
107 
108 fn is_point_semantically_before(
109 &self,
110 absolute_point: Vector2F,
111 absolute_point_other: Vector2F,
112 ) -> Option<bool> {
113 self.child
114 .as_selectable_element()
115 .and_then(|selectable_child| {
116 selectable_child.is_point_semantically_before(absolute_point, absolute_point_other)
117 })
118 }
119 
120 fn smart_select(
121 &self,
122 absolute_point: Vector2F,
123 smart_select_fn: crate::elements::SmartSelectFn,
124 ) -> Option<(Vector2F, Vector2F)> {
125 self.child
126 .as_selectable_element()
127 .and_then(|selectable_child| {
128 selectable_child.smart_select(absolute_point, smart_select_fn)
129 })
130 }
131 
132 fn calculate_clickable_bounds(&self, current_selection: Option<Selection>) -> Vec<RectF> {
133 self.child
134 .as_selectable_element()
135 .map(|selectable_child| selectable_child.calculate_clickable_bounds(current_selection))
136 .unwrap_or_default()
137 }
138}
139