1#![allow(non_snake_case)]
2pub mod adaptive;
106pub mod anim;
107pub mod anim_ext;
108pub mod gestures;
109pub mod layout;
110pub use layout::IntrinsicSizeMode;
111pub mod lazy;
112pub mod selection;
113pub mod subcompose;
114pub use lazy::{LazyColumn, LazyColumnState, LazyGridState, LazyRow, LazyRowState, LazyVerticalGrid, SimpleList};
115pub use subcompose::{
116 BoxWithConstraints, SubcomposeLayout, box_with_constraints_with_key, subcompose_hash_key,
117 subcompose_layout_with_slots, subcompose_with_key, subcompose_with_key_slots,
118};
119pub mod navigation;
120pub mod overlay;
121pub mod pager;
122pub mod scroll;
123pub mod windowing;
124
125use rustc_hash::{FxHashMap, FxHashSet};
126use std::collections::{HashMap, HashSet};
127use std::rc::Rc;
128use std::{cell::RefCell, cmp::Ordering};
129
130use repose_core::*;
131use taffy::style::FlexDirection;
132use taffy::{Overflow, Point};
133
134pub mod textfield;
135use crate::textfield::{TF_FONT_DP, TF_PADDING_X_DP, byte_to_char_index, measure_text};
136use repose_core::locals;
137pub use selection::SelectableText;
138pub use textfield::{TextArea, TextField, TextFieldState};
139
140thread_local! {
141 static LAYOUT_ENGINE: RefCell<layout::LayoutEngine> =
142 RefCell::new(layout::LayoutEngine::new());
143}
144
145#[derive(Default)]
146pub struct Interactions {
147 pub hover: Option<u64>,
148 pub pressed: HashSet<u64>,
149}
150
151pub fn Surface(modifier: Modifier, child: View) -> View {
152 let mut v = View::new(0, ViewKind::Surface).modifier(modifier);
153 v.children = vec![child];
154 v
155}
156
157pub fn Box(modifier: Modifier) -> View {
158 View::new(0, ViewKind::Box).modifier(modifier)
159}
160
161pub fn Row(modifier: Modifier) -> View {
162 View::new(0, ViewKind::Row).modifier(modifier)
163}
164
165pub fn Column(modifier: Modifier) -> View {
166 View::new(0, ViewKind::Column).modifier(modifier)
167}
168
169pub fn FlowRow(modifier: Modifier) -> View {
172 Row(modifier.flex_wrap(FlexWrap::Wrap))
173}
174
175pub fn FlowColumn(modifier: Modifier) -> View {
178 Column(modifier.flex_wrap(FlexWrap::Wrap))
179}
180
181pub fn Center(modifier: Modifier) -> View {
183 Box(modifier.align_self(AlignSelf::Center))
184}
185
186pub fn Stack(modifier: Modifier) -> View {
187 View::new(0, ViewKind::Stack).modifier(modifier)
188}
189
190pub fn ZStack(modifier: Modifier) -> View {
191 View::new(0, ViewKind::ZStack).modifier(modifier)
192}
193
194pub fn OverlayHost(modifier: Modifier) -> View {
195 View::new(0, ViewKind::OverlayHost).modifier(modifier)
196}
197
198#[deprecated = "Use ScollArea instead"]
199pub fn Scroll(modifier: Modifier) -> View {
200 View::new(
201 0,
202 ViewKind::ScrollV {
203 on_scroll: None,
204 set_viewport_height: None,
205 set_content_height: None,
206 get_scroll_offset: None,
207 set_scroll_offset: None,
208 show_scrollbar: true,
209 },
210 )
211 .modifier(modifier)
212}
213
214pub fn Text(text: impl Into<String>) -> View {
215 View::new(
216 0,
217 ViewKind::Text {
218 text: text.into(),
219 color: locals::content_color(),
220 font_size: 16.0, soft_wrap: true,
222 max_lines: None,
223 overflow: TextOverflow::Visible,
224 font_family: None,
225 annotations: None,
226 },
227 )
228}
229
230pub fn AnnotatedText(annotated: AnnotatedString) -> View {
234 let annotations: Option<std::sync::Arc<[TextSpan]>> = if annotated.spans.is_empty() {
235 None
236 } else {
237 Some(annotated.spans.clone())
238 };
239 View::new(
240 0,
241 ViewKind::Text {
242 text: annotated.text,
243 color: locals::content_color(),
244 font_size: 16.0,
245 soft_wrap: true,
246 max_lines: None,
247 overflow: TextOverflow::Visible,
248 font_family: None,
249 annotations,
250 },
251 )
252}
253
254pub fn Spacer() -> View {
255 Box(Modifier::new().flex_grow(1.0))
256}
257
258pub fn Space(modifier: Modifier) -> View {
259 Box(modifier)
260}
261
262pub fn Grid(
263 columns: usize,
264 modifier: Modifier,
265 children: Vec<View>,
266 row_gap: f32,
267 column_gap: f32,
268) -> View {
269 Column(modifier.grid(columns, row_gap, column_gap)).with_children(children)
270}
271
272pub fn Button(content: impl IntoChildren, on_click: impl Fn() + 'static) -> View {
273 View::new(
274 0,
275 ViewKind::Button {
276 on_click: Some(Rc::new(on_click)),
277 },
278 )
279 .with_children(content.into_children())
280 .semantics(Semantics {
281 role: Role::Button,
282 label: None, focused: false,
284 enabled: true,
285 })
286}
287
288pub fn Slider(
289 value: f32,
290 range: (f32, f32),
291 step: Option<f32>,
292 on_change: impl Fn(f32) + 'static,
293) -> View {
294 View::new(
295 0,
296 ViewKind::Slider {
297 value,
298 min: range.0,
299 max: range.1,
300 step,
301 on_change: Some(Rc::new(on_change)),
302 },
303 )
304 .semantics(Semantics {
305 role: Role::Slider,
306 label: None,
307 focused: false,
308 enabled: true,
309 })
310}
311
312pub fn RangeSlider(
313 start: f32,
314 end: f32,
315 range: (f32, f32),
316 step: Option<f32>,
317 on_change: impl Fn(f32, f32) + 'static,
318) -> View {
319 View::new(
320 0,
321 ViewKind::RangeSlider {
322 start,
323 end,
324 min: range.0,
325 max: range.1,
326 step,
327 on_change: Some(Rc::new(on_change)),
328 },
329 )
330 .semantics(Semantics {
331 role: Role::Slider,
332 label: None,
333 focused: false,
334 enabled: true,
335 })
336}
337
338pub fn LinearProgress(value: Option<f32>) -> View {
339 View::new(
340 0,
341 ViewKind::ProgressBar {
342 value: value.unwrap_or(0.0),
343 min: 0.0,
344 max: 1.0,
345 circular: false,
346 },
347 )
348 .semantics(Semantics {
349 role: Role::ProgressBar,
350 label: None,
351 focused: false,
352 enabled: true,
353 })
354}
355
356pub fn ProgressBar(value: f32, range: (f32, f32)) -> View {
357 View::new(
358 0,
359 ViewKind::ProgressBar {
360 value,
361 min: range.0,
362 max: range.1,
363 circular: false,
364 },
365 )
366 .semantics(Semantics {
367 role: Role::ProgressBar,
368 label: None,
369 focused: false,
370 enabled: true,
371 })
372}
373
374pub fn CircularProgress(value: Option<f32>) -> View {
380 View::new(
381 0,
382 ViewKind::ProgressBar {
383 value: value.unwrap_or(0.0),
384 min: 0.0,
385 max: 1.0,
386 circular: true,
387 },
388 )
389 .modifier(Modifier::new().width(48.0).height(48.0))
390}
391
392pub fn Image(modifier: Modifier, handle: ImageHandle) -> View {
393 View::new(
394 0,
395 ViewKind::Image {
396 handle,
397 tint: Color::WHITE,
398 fit: ImageFit::Contain,
399 },
400 )
401 .modifier(modifier)
402}
403
404pub trait ImageExt {
405 fn image_tint(self, c: Color) -> View;
406 fn image_fit(self, fit: ImageFit) -> View;
407}
408impl ImageExt for View {
409 fn image_tint(mut self, c: Color) -> View {
410 if let ViewKind::Image { tint, .. } = &mut self.kind {
411 *tint = c;
412 }
413 self
414 }
415 fn image_fit(mut self, fit: ImageFit) -> View {
416 if let ViewKind::Image { fit: f, .. } = &mut self.kind {
417 *f = fit;
418 }
419 self
420 }
421}
422
423fn flex_dir_for(kind: &ViewKind) -> Option<FlexDirection> {
424 match kind {
425 ViewKind::Row => {
426 if repose_core::locals::text_direction() == repose_core::locals::TextDirection::Rtl {
427 Some(FlexDirection::RowReverse)
428 } else {
429 Some(FlexDirection::Row)
430 }
431 }
432 ViewKind::Column | ViewKind::Surface | ViewKind::ScrollV { .. } => {
433 Some(FlexDirection::Column)
434 }
435 _ => None,
436 }
437}
438
439pub trait ViewExt: Sized {
441 fn child(self, children: impl IntoChildren) -> Self;
442}
443
444impl ViewExt for View {
445 fn child(self, children: impl IntoChildren) -> Self {
446 self.with_children(children.into_children())
447 }
448}
449
450pub trait IntoChildren {
451 fn into_children(self) -> Vec<View>;
452}
453
454impl IntoChildren for View {
455 fn into_children(self) -> Vec<View> {
456 vec![self]
457 }
458}
459
460impl IntoChildren for Vec<View> {
461 fn into_children(self) -> Vec<View> {
462 self
463 }
464}
465
466impl<const N: usize> IntoChildren for [View; N] {
467 fn into_children(self) -> Vec<View> {
468 self.into()
469 }
470}
471
472macro_rules! impl_into_children_tuple {
474 ($($idx:tt $t:ident),+) => {
475 impl<$($t: IntoChildren),+> IntoChildren for ($($t,)+) {
476 fn into_children(self) -> Vec<View> {
477 let mut v = Vec::new();
478 $(v.extend(self.$idx.into_children());)+
479 v
480 }
481 }
482 };
483}
484
485impl_into_children_tuple!(0 A);
486impl_into_children_tuple!(0 A, 1 B);
487impl_into_children_tuple!(0 A, 1 B, 2 C);
488impl_into_children_tuple!(0 A, 1 B, 2 C, 3 D);
489impl_into_children_tuple!(0 A, 1 B, 2 C, 3 D, 4 E);
490impl_into_children_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F);
491impl_into_children_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G);
492impl_into_children_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H);
493
494pub fn layout_and_paint(
496 root: &View,
497 size_px_u32: (u32, u32),
498 textfield_states: &HashMap<u64, Rc<RefCell<TextFieldState>>>,
499 interactions: &Interactions,
500 focused: Option<u64>,
501) -> (Scene, Vec<HitRegion>, Vec<SemNode>) {
502 LAYOUT_ENGINE.with(|engine| {
503 engine
504 .borrow_mut()
505 .layout_frame(root, size_px_u32, textfield_states, interactions, focused)
506 })
507}
508
509pub trait TextStyle {
511 fn color(self, c: Color) -> View;
512 fn size(self, px: f32) -> View;
513 fn max_lines(self, n: usize) -> View;
514 fn single_line(self) -> View;
515 fn overflow_ellipsize(self) -> View;
516 fn overflow_clip(self) -> View;
517 fn overflow_visible(self) -> View;
518 fn font_family(self, family: &'static str) -> View;
519}
520impl TextStyle for View {
521 fn color(mut self, c: Color) -> View {
522 if let ViewKind::Text {
523 color: text_color, ..
524 } = &mut self.kind
525 {
526 *text_color = c;
527 }
528 self
529 }
530 fn size(mut self, dp_font: f32) -> View {
531 if let ViewKind::Text {
532 font_size: text_size_dp,
533 ..
534 } = &mut self.kind
535 {
536 *text_size_dp = dp_font;
537 }
538 self
539 }
540 fn max_lines(mut self, n: usize) -> View {
541 if let ViewKind::Text {
542 max_lines,
543 soft_wrap,
544 ..
545 } = &mut self.kind
546 {
547 *max_lines = Some(n);
548 *soft_wrap = true;
549 }
550 self
551 }
552 fn single_line(mut self) -> View {
553 if let ViewKind::Text {
554 soft_wrap,
555 max_lines,
556 ..
557 } = &mut self.kind
558 {
559 *soft_wrap = false;
560 *max_lines = Some(1);
561 }
562 self
563 }
564 fn overflow_ellipsize(mut self) -> View {
565 if let ViewKind::Text { overflow, .. } = &mut self.kind {
566 *overflow = TextOverflow::Ellipsis;
567 }
568 self
569 }
570 fn overflow_clip(mut self) -> View {
571 if let ViewKind::Text { overflow, .. } = &mut self.kind {
572 *overflow = TextOverflow::Clip;
573 }
574 self
575 }
576 fn overflow_visible(mut self) -> View {
577 if let ViewKind::Text { overflow, .. } = &mut self.kind {
578 *overflow = TextOverflow::Visible;
579 }
580 self
581 }
582 fn font_family(mut self, family: &'static str) -> View {
583 if let ViewKind::Text {
584 font_family: ff, ..
585 } = &mut self.kind
586 {
587 *ff = Some(family);
588 }
589 self
590 }
591}