use crate::UiHost;
use crate::elements::{ElementContext, GlobalElementId};
use crate::overlay_placement::{Align, AnchoredPanelLayout, AnchoredPanelOptions, Side};
use fret_core::scene::{BlendMode, CustomEffectPyramidRequestV1, Mask, Paint};
use fret_core::{
AttributedText, CaretAffinity, Color, Corners, Edges, EffectChain, EffectMode, EffectQuality,
ImageId, KeyCode, NodeId, Px, Rect, RenderTargetId, SemanticsLive, SemanticsOrientation,
SemanticsRole, Size, SvgFit, TextAlign, TextOverflow, TextStyle, TextStyleRefinement, TextWrap,
UvRect, ViewportFit,
};
use fret_runtime::{CommandId, Model};
use std::sync::Arc;
use crate::{ResizablePanelGroupStyle, SvgSource, TextAreaStyle, TextInputStyle};
#[derive(Debug)]
pub struct AnyElement {
pub id: GlobalElementId,
pub kind: ElementKind,
pub children: Vec<AnyElement>,
pub inherited_foreground: Option<Color>,
pub inherited_text_style: Option<TextStyleRefinement>,
pub semantics_decoration: Option<SemanticsDecoration>,
pub key_context: Option<Arc<str>>,
}
impl AnyElement {
pub fn new(id: GlobalElementId, kind: ElementKind, children: Vec<AnyElement>) -> Self {
Self {
id,
kind,
children,
inherited_foreground: None,
inherited_text_style: None,
semantics_decoration: None,
key_context: None,
}
}
pub fn inherit_foreground(mut self, foreground: Color) -> Self {
self.inherited_foreground = Some(foreground);
self
}
pub fn inherit_text_style(mut self, refinement: TextStyleRefinement) -> Self {
match self.inherited_text_style.as_mut() {
Some(existing) => existing.merge(&refinement),
None => self.inherited_text_style = Some(refinement),
}
self
}
pub fn attach_semantics(mut self, decoration: SemanticsDecoration) -> Self {
self.semantics_decoration = Some(match self.semantics_decoration.take() {
Some(existing) => existing.merge(decoration),
None => decoration,
});
self
}
pub fn a11y(self, decoration: SemanticsDecoration) -> Self {
self.attach_semantics(decoration)
}
pub fn a11y_role(self, role: SemanticsRole) -> Self {
self.a11y(SemanticsDecoration::default().role(role))
}
pub fn a11y_label(self, label: impl Into<Arc<str>>) -> Self {
self.a11y(SemanticsDecoration::default().label(label))
}
pub fn test_id(self, test_id: impl Into<Arc<str>>) -> Self {
self.a11y(SemanticsDecoration::default().test_id(test_id))
}
pub fn a11y_value(self, value: impl Into<Arc<str>>) -> Self {
self.a11y(SemanticsDecoration::default().value(value))
}
pub fn a11y_disabled(self, disabled: bool) -> Self {
self.a11y(SemanticsDecoration::default().disabled(disabled))
}
pub fn a11y_selected(self, selected: bool) -> Self {
self.a11y(SemanticsDecoration::default().selected(selected))
}
pub fn a11y_expanded(self, expanded: bool) -> Self {
self.a11y(SemanticsDecoration::default().expanded(expanded))
}
pub fn a11y_checked(self, checked: Option<bool>) -> Self {
self.a11y(SemanticsDecoration::default().checked(checked))
}
pub fn key_context(mut self, key_context: impl Into<Arc<str>>) -> Self {
self.key_context = Some(key_context.into());
self
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
pub enum ElementKind {
Container(ContainerProps),
Semantics(SemanticsProps),
SemanticFlex(SemanticFlexProps),
FocusScope(FocusScopeProps),
LayoutQueryRegion(LayoutQueryRegionProps),
InteractivityGate(InteractivityGateProps),
HitTestGate(HitTestGateProps),
FocusTraversalGate(FocusTraversalGateProps),
ForegroundScope(ForegroundScopeProps),
Opacity(OpacityProps),
EffectLayer(EffectLayerProps),
BackdropSourceGroup(BackdropSourceGroupProps),
MaskLayer(MaskLayerProps),
CompositeGroup(CompositeGroupProps),
ViewCache(ViewCacheProps),
VisualTransform(VisualTransformProps),
RenderTransform(RenderTransformProps),
FractionalRenderTransform(FractionalRenderTransformProps),
Anchored(AnchoredProps),
Pressable(PressableProps),
PointerRegion(PointerRegionProps),
TextInputRegion(TextInputRegionProps),
InternalDragRegion(InternalDragRegionProps),
ExternalDragRegion(ExternalDragRegionProps),
RovingFlex(RovingFlexProps),
Stack(StackProps),
Column(ColumnProps),
Row(RowProps),
Spacer(SpacerProps),
Text(TextProps),
StyledText(StyledTextProps),
SelectableText(SelectableTextProps),
TextInput(TextInputProps),
TextArea(TextAreaProps),
ResizablePanelGroup(ResizablePanelGroupProps),
VirtualList(VirtualListProps),
Flex(FlexProps),
Grid(GridProps),
Image(ImageProps),
Canvas(CanvasProps),
#[cfg(feature = "unstable-retained-bridge")]
RetainedSubtree(crate::retained_bridge::RetainedSubtreeProps),
ViewportSurface(ViewportSurfaceProps),
SvgIcon(SvgIconProps),
Spinner(SpinnerProps),
HoverRegion(HoverRegionProps),
WheelRegion(WheelRegionProps),
Scroll(ScrollProps),
Scrollbar(ScrollbarProps),
}
#[derive(Debug, Clone, Copy)]
pub struct SemanticFlexProps {
pub role: SemanticsRole,
pub flex: FlexProps,
}
#[derive(Debug, Default, Clone)]
pub struct PointerRegionState {
pub last_down: Option<crate::action::PointerDownCx>,
}
#[derive(Debug, Clone, Copy)]
pub struct PointerRegionProps {
pub layout: LayoutStyle,
pub enabled: bool,
pub capture_phase_pointer_moves: bool,
}
#[derive(Debug, Clone)]
pub struct TextInputRegionProps {
pub layout: LayoutStyle,
pub enabled: bool,
pub text_boundary_mode_override: Option<fret_runtime::TextBoundaryMode>,
pub ime_cursor_area: Option<fret_core::Rect>,
pub a11y_label: Option<Arc<str>>,
pub a11y_value: Option<Arc<str>>,
pub a11y_required: bool,
pub a11y_invalid: Option<fret_core::SemanticsInvalid>,
pub a11y_text_selection: Option<(u32, u32)>,
pub a11y_text_composition: Option<(u32, u32)>,
pub ime_surrounding_text: Option<fret_runtime::WindowImeSurroundingText>,
}
#[derive(Debug, Clone, Copy)]
pub struct InternalDragRegionProps {
pub layout: LayoutStyle,
pub enabled: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct ExternalDragRegionProps {
pub layout: LayoutStyle,
pub enabled: bool,
}
impl Default for InternalDragRegionProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
enabled: true,
}
}
}
impl Default for ExternalDragRegionProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
enabled: true,
}
}
}
impl Default for PointerRegionProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
enabled: true,
capture_phase_pointer_moves: false,
}
}
}
impl Default for TextInputRegionProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
enabled: true,
text_boundary_mode_override: None,
ime_cursor_area: None,
a11y_label: None,
a11y_value: None,
a11y_required: false,
a11y_invalid: None,
a11y_text_selection: None,
a11y_text_composition: None,
ime_surrounding_text: None,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct LayoutStyle {
pub size: SizeStyle,
pub flex: FlexItemStyle,
pub overflow: Overflow,
pub margin: MarginEdges,
pub position: PositionStyle,
pub inset: InsetStyle,
pub aspect_ratio: Option<f32>,
pub grid: GridItemStyle,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MarginEdge {
Px(Px),
Fill,
Fraction(f32),
Auto,
}
impl Default for MarginEdge {
fn default() -> Self {
Self::Px(Px(0.0))
}
}
impl From<Px> for MarginEdge {
fn from(px: Px) -> Self {
Self::Px(px)
}
}
impl From<Option<Px>> for MarginEdge {
fn from(px: Option<Px>) -> Self {
match px {
Some(px) => Self::Px(px),
None => Self::Auto,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct MarginEdges {
pub top: MarginEdge,
pub right: MarginEdge,
pub bottom: MarginEdge,
pub left: MarginEdge,
}
impl MarginEdges {
pub fn all(edge: MarginEdge) -> Self {
Self {
top: edge,
right: edge,
bottom: edge,
left: edge,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum Overflow {
#[default]
Visible,
Clip,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum PositionStyle {
#[default]
Static,
Relative,
Absolute,
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct InsetStyle {
pub top: InsetEdge,
pub right: InsetEdge,
pub bottom: InsetEdge,
pub left: InsetEdge,
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub enum InsetEdge {
Px(Px),
Fill,
Fraction(f32),
#[default]
Auto,
}
impl From<Px> for InsetEdge {
fn from(px: Px) -> Self {
Self::Px(px)
}
}
impl From<Option<Px>> for InsetEdge {
fn from(px: Option<Px>) -> Self {
match px {
Some(px) => Self::Px(px),
None => Self::Auto,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct GridItemStyle {
pub column: GridLine,
pub row: GridLine,
pub align_self: Option<CrossAlign>,
pub justify_self: Option<CrossAlign>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct GridLine {
pub start: Option<i16>,
pub span: Option<u16>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SizeStyle {
pub width: Length,
pub height: Length,
pub min_width: Option<Length>,
pub min_height: Option<Length>,
pub max_width: Option<Length>,
pub max_height: Option<Length>,
}
impl Default for SizeStyle {
fn default() -> Self {
Self {
width: Length::Auto,
height: Length::Auto,
min_width: None,
min_height: None,
max_width: None,
max_height: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FlexItemStyle {
pub order: i32,
pub grow: f32,
pub shrink: f32,
pub basis: Length,
pub align_self: Option<CrossAlign>,
}
impl Default for FlexItemStyle {
fn default() -> Self {
Self {
order: 0,
grow: 0.0,
shrink: 1.0,
basis: Length::Auto,
align_self: None,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub enum Length {
#[default]
Auto,
Px(Px),
Fraction(f32),
Fill,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SpacingLength {
Px(Px),
Fraction(f32),
Fill,
}
impl Default for SpacingLength {
fn default() -> Self {
Self::Px(Px(0.0))
}
}
impl SpacingLength {
pub const fn px(px: Px) -> Self {
Self::Px(px)
}
pub const fn fraction(fraction: f32) -> Self {
Self::Fraction(fraction)
}
pub const fn fill() -> Self {
Self::Fill
}
}
impl From<Px> for SpacingLength {
fn from(value: Px) -> Self {
Self::Px(value)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SpacingEdges {
pub top: SpacingLength,
pub right: SpacingLength,
pub bottom: SpacingLength,
pub left: SpacingLength,
}
impl Default for SpacingEdges {
fn default() -> Self {
Self::all(SpacingLength::Px(Px(0.0)))
}
}
impl SpacingEdges {
pub const fn all(value: SpacingLength) -> Self {
Self {
top: value,
right: value,
bottom: value,
left: value,
}
}
pub const fn symmetric(horizontal: SpacingLength, vertical: SpacingLength) -> Self {
Self {
top: vertical,
right: horizontal,
bottom: vertical,
left: horizontal,
}
}
}
impl From<Edges> for SpacingEdges {
fn from(value: Edges) -> Self {
Self {
top: SpacingLength::Px(value.top),
right: SpacingLength::Px(value.right),
bottom: SpacingLength::Px(value.bottom),
left: SpacingLength::Px(value.left),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ContainerProps {
pub layout: LayoutStyle,
pub padding: SpacingEdges,
pub background: Option<Color>,
pub background_paint: Option<Paint>,
pub shadow: Option<ShadowStyle>,
pub border: Edges,
pub border_color: Option<Color>,
pub border_paint: Option<Paint>,
pub border_dash: Option<fret_core::scene::DashPatternV1>,
pub focus_ring: Option<RingStyle>,
pub focus_ring_always_paint: bool,
pub focus_border_color: Option<Color>,
pub focus_within: bool,
pub corner_radii: Corners,
pub snap_to_device_pixels: bool,
}
impl Default for ContainerProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
padding: SpacingEdges::all(SpacingLength::Px(Px(0.0))),
background: None,
background_paint: None,
shadow: None,
border: Edges::all(Px(0.0)),
border_color: None,
border_paint: None,
border_dash: None,
focus_ring: None,
focus_ring_always_paint: false,
focus_border_color: None,
focus_within: false,
corner_radii: Corners::all(Px(0.0)),
snap_to_device_pixels: false,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct SemanticsDecoration {
pub role: Option<SemanticsRole>,
pub label: Option<Arc<str>>,
pub role_description: Option<Arc<str>>,
pub test_id: Option<Arc<str>>,
pub value: Option<Arc<str>>,
pub disabled: Option<bool>,
pub read_only: Option<bool>,
pub required: Option<bool>,
pub invalid: Option<fret_core::SemanticsInvalid>,
pub hidden: Option<bool>,
pub visited: Option<bool>,
pub multiselectable: Option<bool>,
pub busy: Option<bool>,
pub live: Option<Option<SemanticsLive>>,
pub live_atomic: Option<bool>,
pub selected: Option<bool>,
pub expanded: Option<bool>,
pub checked: Option<Option<bool>>,
pub placeholder: Option<Arc<str>>,
pub url: Option<Arc<str>>,
pub level: Option<u32>,
pub orientation: Option<SemanticsOrientation>,
pub numeric_value: Option<f64>,
pub min_numeric_value: Option<f64>,
pub max_numeric_value: Option<f64>,
pub numeric_value_step: Option<f64>,
pub numeric_value_jump: Option<f64>,
pub scroll_x: Option<f64>,
pub scroll_x_min: Option<f64>,
pub scroll_x_max: Option<f64>,
pub scroll_y: Option<f64>,
pub scroll_y_min: Option<f64>,
pub scroll_y_max: Option<f64>,
pub active_descendant_element: Option<u64>,
pub labelled_by_element: Option<u64>,
pub described_by_element: Option<u64>,
pub controls_element: Option<u64>,
pub invokable: Option<bool>,
}
impl SemanticsDecoration {
pub fn merge(self, other: Self) -> Self {
Self {
role: other.role.or(self.role),
label: other.label.or(self.label),
role_description: other.role_description.or(self.role_description),
test_id: other.test_id.or(self.test_id),
value: other.value.or(self.value),
disabled: other.disabled.or(self.disabled),
read_only: other.read_only.or(self.read_only),
required: other.required.or(self.required),
invalid: other.invalid.or(self.invalid),
hidden: other.hidden.or(self.hidden),
visited: other.visited.or(self.visited),
multiselectable: other.multiselectable.or(self.multiselectable),
busy: other.busy.or(self.busy),
live: other.live.or(self.live),
live_atomic: other.live_atomic.or(self.live_atomic),
selected: other.selected.or(self.selected),
expanded: other.expanded.or(self.expanded),
checked: other.checked.or(self.checked),
placeholder: other.placeholder.or(self.placeholder),
url: other.url.or(self.url),
level: other.level.or(self.level),
orientation: other.orientation.or(self.orientation),
numeric_value: other.numeric_value.or(self.numeric_value),
min_numeric_value: other.min_numeric_value.or(self.min_numeric_value),
max_numeric_value: other.max_numeric_value.or(self.max_numeric_value),
numeric_value_step: other.numeric_value_step.or(self.numeric_value_step),
numeric_value_jump: other.numeric_value_jump.or(self.numeric_value_jump),
scroll_x: other.scroll_x.or(self.scroll_x),
scroll_x_min: other.scroll_x_min.or(self.scroll_x_min),
scroll_x_max: other.scroll_x_max.or(self.scroll_x_max),
scroll_y: other.scroll_y.or(self.scroll_y),
scroll_y_min: other.scroll_y_min.or(self.scroll_y_min),
scroll_y_max: other.scroll_y_max.or(self.scroll_y_max),
active_descendant_element: other
.active_descendant_element
.or(self.active_descendant_element),
labelled_by_element: other.labelled_by_element.or(self.labelled_by_element),
described_by_element: other.described_by_element.or(self.described_by_element),
controls_element: other.controls_element.or(self.controls_element),
invokable: other.invokable.or(self.invokable),
}
}
pub fn role(mut self, role: SemanticsRole) -> Self {
self.role = Some(role);
self
}
pub fn label(mut self, label: impl Into<Arc<str>>) -> Self {
self.label = Some(label.into());
self
}
pub fn role_description(mut self, role_description: impl Into<Arc<str>>) -> Self {
self.role_description = Some(role_description.into());
self
}
pub fn test_id(mut self, test_id: impl Into<Arc<str>>) -> Self {
self.test_id = Some(test_id.into());
self
}
pub fn value(mut self, value: impl Into<Arc<str>>) -> Self {
self.value = Some(value.into());
self
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = Some(disabled);
self
}
pub fn read_only(mut self, read_only: bool) -> Self {
self.read_only = Some(read_only);
self
}
pub fn required(mut self, required: bool) -> Self {
self.required = Some(required);
self
}
pub fn invalid(mut self, invalid: fret_core::SemanticsInvalid) -> Self {
self.invalid = Some(invalid);
self
}
pub fn hidden(mut self, hidden: bool) -> Self {
self.hidden = Some(hidden);
self
}
pub fn visited(mut self, visited: bool) -> Self {
self.visited = Some(visited);
self
}
pub fn multiselectable(mut self, multiselectable: bool) -> Self {
self.multiselectable = Some(multiselectable);
self
}
pub fn busy(mut self, busy: bool) -> Self {
self.busy = Some(busy);
self
}
pub fn live(mut self, live: Option<SemanticsLive>) -> Self {
self.live = Some(live);
self
}
pub fn live_atomic(mut self, live_atomic: bool) -> Self {
self.live_atomic = Some(live_atomic);
self
}
pub fn selected(mut self, selected: bool) -> Self {
self.selected = Some(selected);
self
}
pub fn expanded(mut self, expanded: bool) -> Self {
self.expanded = Some(expanded);
self
}
pub fn checked(mut self, checked: Option<bool>) -> Self {
self.checked = Some(checked);
self
}
pub fn placeholder(mut self, placeholder: impl Into<Arc<str>>) -> Self {
self.placeholder = Some(placeholder.into());
self
}
pub fn url(mut self, url: impl Into<Arc<str>>) -> Self {
self.url = Some(url.into());
self
}
pub fn level(mut self, level: u32) -> Self {
self.level = Some(level);
self
}
pub fn orientation(mut self, orientation: SemanticsOrientation) -> Self {
self.orientation = Some(orientation);
self
}
pub fn numeric_value(mut self, value: f64) -> Self {
self.numeric_value = Some(value);
self
}
pub fn numeric_range(mut self, min: f64, max: f64) -> Self {
self.min_numeric_value = Some(min);
self.max_numeric_value = Some(max);
self
}
pub fn numeric_step(mut self, step: f64) -> Self {
self.numeric_value_step = Some(step);
self
}
pub fn numeric_jump(mut self, jump: f64) -> Self {
self.numeric_value_jump = Some(jump);
self
}
pub fn scroll_x(mut self, x: f64, min: f64, max: f64) -> Self {
self.scroll_x = Some(x);
self.scroll_x_min = Some(min);
self.scroll_x_max = Some(max);
self
}
pub fn scroll_y(mut self, y: f64, min: f64, max: f64) -> Self {
self.scroll_y = Some(y);
self.scroll_y_min = Some(min);
self.scroll_y_max = Some(max);
self
}
pub fn active_descendant_element(mut self, element: u64) -> Self {
self.active_descendant_element = Some(element);
self
}
pub fn labelled_by_element(mut self, element: u64) -> Self {
self.labelled_by_element = Some(element);
self
}
pub fn described_by_element(mut self, element: u64) -> Self {
self.described_by_element = Some(element);
self
}
pub fn controls_element(mut self, element: u64) -> Self {
self.controls_element = Some(element);
self
}
pub fn invokable(mut self, invokable: bool) -> Self {
self.invokable = Some(invokable);
self
}
}
#[derive(Debug, Clone)]
pub struct SemanticsProps {
pub layout: LayoutStyle,
pub role: SemanticsRole,
pub label: Option<Arc<str>>,
pub test_id: Option<Arc<str>>,
pub value: Option<Arc<str>>,
pub placeholder: Option<Arc<str>>,
pub url: Option<Arc<str>>,
pub level: Option<u32>,
pub orientation: Option<SemanticsOrientation>,
pub numeric_value: Option<f64>,
pub min_numeric_value: Option<f64>,
pub max_numeric_value: Option<f64>,
pub numeric_value_step: Option<f64>,
pub numeric_value_jump: Option<f64>,
pub scroll_x: Option<f64>,
pub scroll_x_min: Option<f64>,
pub scroll_x_max: Option<f64>,
pub scroll_y: Option<f64>,
pub scroll_y_min: Option<f64>,
pub scroll_y_max: Option<f64>,
pub focusable: bool,
pub value_editable: Option<bool>,
pub disabled: bool,
pub read_only: bool,
pub required: bool,
pub invalid: Option<fret_core::SemanticsInvalid>,
pub hidden: bool,
pub visited: bool,
pub multiselectable: bool,
pub busy: bool,
pub live: Option<SemanticsLive>,
pub live_atomic: bool,
pub selected: bool,
pub expanded: Option<bool>,
pub checked: Option<bool>,
pub active_descendant: Option<NodeId>,
pub labelled_by_element: Option<u64>,
pub described_by_element: Option<u64>,
pub controls_element: Option<u64>,
}
impl Default for SemanticsProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
role: SemanticsRole::Generic,
label: None,
test_id: None,
value: None,
placeholder: None,
url: None,
level: None,
orientation: None,
numeric_value: None,
min_numeric_value: None,
max_numeric_value: None,
numeric_value_step: None,
numeric_value_jump: None,
scroll_x: None,
scroll_x_min: None,
scroll_x_max: None,
scroll_y: None,
scroll_y_min: None,
scroll_y_max: None,
focusable: false,
value_editable: None,
disabled: false,
read_only: false,
required: false,
invalid: None,
hidden: false,
visited: false,
multiselectable: false,
busy: false,
live: None,
live_atomic: false,
selected: false,
expanded: None,
checked: None,
active_descendant: None,
labelled_by_element: None,
described_by_element: None,
controls_element: None,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct LayoutQueryRegionProps {
pub layout: LayoutStyle,
pub name: Option<Arc<str>>,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct FocusScopeProps {
pub layout: LayoutStyle,
pub trap_focus: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct InteractivityGateProps {
pub layout: LayoutStyle,
pub present: bool,
pub interactive: bool,
}
impl Default for InteractivityGateProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
present: true,
interactive: true,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct HitTestGateProps {
pub layout: LayoutStyle,
pub hit_test: bool,
}
impl Default for HitTestGateProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
hit_test: true,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct FocusTraversalGateProps {
pub layout: LayoutStyle,
pub traverse: bool,
}
impl Default for FocusTraversalGateProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
traverse: true,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct OpacityProps {
pub layout: LayoutStyle,
pub opacity: f32,
}
impl Default for OpacityProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
opacity: 1.0,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ForegroundScopeProps {
pub layout: LayoutStyle,
pub foreground: Option<Color>,
}
#[derive(Debug, Clone, Copy)]
pub struct EffectLayerProps {
pub layout: LayoutStyle,
pub mode: EffectMode,
pub chain: EffectChain,
pub quality: EffectQuality,
}
impl Default for EffectLayerProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
mode: EffectMode::FilterContent,
chain: EffectChain::EMPTY,
quality: EffectQuality::Auto,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct BackdropSourceGroupProps {
pub layout: LayoutStyle,
pub pyramid: Option<CustomEffectPyramidRequestV1>,
pub quality: EffectQuality,
}
impl Default for BackdropSourceGroupProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
pyramid: None,
quality: EffectQuality::Auto,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MaskLayerProps {
pub layout: LayoutStyle,
pub mask: Mask,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CompositeGroupProps {
pub layout: LayoutStyle,
pub mode: BlendMode,
pub quality: EffectQuality,
}
impl Default for CompositeGroupProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
mode: BlendMode::Over,
quality: EffectQuality::Auto,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ViewCacheProps {
pub layout: LayoutStyle,
pub contained_layout: bool,
pub cache_key: u64,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct VisualTransformProps {
pub layout: LayoutStyle,
pub transform: fret_core::Transform2D,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct RenderTransformProps {
pub layout: LayoutStyle,
pub transform: fret_core::Transform2D,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct FractionalRenderTransformProps {
pub layout: LayoutStyle,
pub translate_x_fraction: f32,
pub translate_y_fraction: f32,
}
#[derive(Debug, Clone)]
pub struct AnchoredProps {
pub layout: LayoutStyle,
pub outer_margin: Edges,
pub anchor: fret_core::Rect,
pub anchor_element: Option<u64>,
pub side: Side,
pub align: Align,
pub side_offset: Px,
pub options: AnchoredPanelOptions,
pub layout_out: Option<Model<AnchoredPanelLayout>>,
}
impl Default for AnchoredProps {
fn default() -> Self {
let mut layout = LayoutStyle::default();
layout.size.width = Length::Fill;
layout.size.height = Length::Fill;
Self {
layout,
outer_margin: Edges::all(Px(0.0)),
anchor: fret_core::Rect::default(),
anchor_element: None,
side: Side::Bottom,
align: Align::Start,
side_offset: Px(0.0),
options: AnchoredPanelOptions::default(),
layout_out: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ShadowLayerStyle {
pub color: Color,
pub offset_x: Px,
pub offset_y: Px,
pub blur: Px,
pub spread: Px,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ShadowStyle {
pub primary: ShadowLayerStyle,
pub secondary: Option<ShadowLayerStyle>,
pub corner_radii: Corners,
}
#[derive(Clone)]
pub struct PressableProps {
pub layout: LayoutStyle,
pub enabled: bool,
pub focusable: bool,
pub focus_ring: Option<RingStyle>,
pub focus_ring_always_paint: bool,
pub focus_ring_bounds: Option<Rect>,
pub key_activation: PressableKeyActivation,
pub a11y: PressableA11y,
}
impl std::fmt::Debug for PressableProps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut out = f.debug_struct("PressableProps");
out.field("layout", &self.layout)
.field("enabled", &self.enabled)
.field("focusable", &self.focusable);
out.field("focus_ring", &self.focus_ring)
.field("focus_ring_always_paint", &self.focus_ring_always_paint)
.field("focus_ring_bounds", &self.focus_ring_bounds)
.field("key_activation", &self.key_activation)
.field("a11y", &self.a11y)
.finish()
}
}
impl Default for PressableProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
enabled: true,
focusable: true,
focus_ring: None,
focus_ring_always_paint: false,
focus_ring_bounds: None,
key_activation: PressableKeyActivation::default(),
a11y: PressableA11y::default(),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum PressableKeyActivation {
#[default]
EnterAndSpace,
EnterOnly,
}
impl PressableKeyActivation {
pub fn allows(self, key: KeyCode) -> bool {
match self {
Self::EnterAndSpace => {
matches!(key, KeyCode::Enter | KeyCode::NumpadEnter | KeyCode::Space)
}
Self::EnterOnly => matches!(key, KeyCode::Enter | KeyCode::NumpadEnter),
}
}
}
#[derive(Clone, Default)]
pub struct RovingFlexProps {
pub flex: FlexProps,
pub roving: RovingFocusProps,
}
impl std::fmt::Debug for RovingFlexProps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RovingFlexProps")
.field("flex", &self.flex)
.field("roving", &self.roving)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct RovingFocusProps {
pub enabled: bool,
pub wrap: bool,
pub disabled: Arc<[bool]>,
}
impl Default for RovingFocusProps {
fn default() -> Self {
Self {
enabled: true,
wrap: true,
disabled: Arc::from([]),
}
}
}
#[derive(Debug, Default, Clone)]
pub struct PressableA11y {
pub role: Option<SemanticsRole>,
pub label: Option<Arc<str>>,
pub level: Option<u32>,
pub test_id: Option<Arc<str>>,
pub hidden: bool,
pub visited: bool,
pub multiselectable: bool,
pub required: bool,
pub invalid: Option<fret_core::SemanticsInvalid>,
pub selected: bool,
pub expanded: Option<bool>,
pub checked: Option<bool>,
pub checked_state: Option<fret_core::SemanticsCheckedState>,
pub pressed_state: Option<fret_core::SemanticsPressedState>,
pub active_descendant: Option<NodeId>,
pub labelled_by_element: Option<u64>,
pub described_by_element: Option<u64>,
pub controls_element: Option<u64>,
pub pos_in_set: Option<u32>,
pub set_size: Option<u32>,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct PressableState {
pub hovered: bool,
pub hovered_raw: bool,
pub hovered_raw_below_barrier: bool,
pub pressed: bool,
pub focused: bool,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum RingPlacement {
Inset,
#[default]
Outset,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RingStyle {
pub placement: RingPlacement,
pub width: Px,
pub offset: Px,
pub color: Color,
pub offset_color: Option<Color>,
pub corner_radii: Corners,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct StackProps {
pub layout: LayoutStyle,
}
#[derive(Debug, Clone, Copy)]
pub struct ColumnProps {
pub layout: LayoutStyle,
pub gap: SpacingLength,
pub padding: SpacingEdges,
pub justify: MainAlign,
pub align: CrossAlign,
}
impl Default for ColumnProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
gap: SpacingLength::Px(Px(0.0)),
padding: SpacingEdges::all(SpacingLength::Px(Px(0.0))),
justify: MainAlign::Start,
align: CrossAlign::Stretch,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct RowProps {
pub layout: LayoutStyle,
pub gap: SpacingLength,
pub padding: SpacingEdges,
pub justify: MainAlign,
pub align: CrossAlign,
}
impl Default for RowProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
gap: SpacingLength::Px(Px(0.0)),
padding: SpacingEdges::all(SpacingLength::Px(Px(0.0))),
justify: MainAlign::Start,
align: CrossAlign::Stretch,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum MainAlign {
#[default]
Start,
Center,
End,
SpaceBetween,
SpaceAround,
SpaceEvenly,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum CrossAlign {
Start,
#[default]
Center,
End,
Stretch,
}
#[derive(Debug, Clone, Copy)]
pub struct SpacerProps {
pub layout: LayoutStyle,
pub min: Px,
}
impl Default for SpacerProps {
fn default() -> Self {
let mut layout = LayoutStyle::default();
layout.flex.grow = 1.0;
layout.flex.shrink = 1.0;
layout.flex.basis = Length::Px(Px(0.0));
Self {
layout,
min: Px(0.0),
}
}
}
#[derive(Debug, Clone)]
pub struct TextProps {
pub layout: LayoutStyle,
pub text: std::sync::Arc<str>,
pub style: Option<TextStyle>,
pub color: Option<Color>,
pub wrap: TextWrap,
pub overflow: TextOverflow,
pub align: TextAlign,
pub ink_overflow: TextInkOverflow,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TextInkOverflow {
#[default]
None,
AutoPad,
}
#[derive(Debug, Clone)]
pub struct StyledTextProps {
pub layout: LayoutStyle,
pub rich: AttributedText,
pub style: Option<TextStyle>,
pub color: Option<Color>,
pub wrap: TextWrap,
pub overflow: TextOverflow,
pub align: TextAlign,
pub ink_overflow: TextInkOverflow,
}
#[derive(Debug, Clone)]
pub struct SelectableTextProps {
pub layout: LayoutStyle,
pub rich: AttributedText,
pub style: Option<TextStyle>,
pub color: Option<Color>,
pub wrap: TextWrap,
pub overflow: TextOverflow,
pub align: TextAlign,
pub ink_overflow: TextInkOverflow,
pub interactive_spans: std::sync::Arc<[SelectableTextInteractiveSpan]>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SelectableTextInteractiveSpan {
pub range: std::ops::Range<usize>,
pub tag: std::sync::Arc<str>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SelectableTextInteractiveSpanBounds {
pub range: std::ops::Range<usize>,
pub tag: std::sync::Arc<str>,
pub bounds_local: fret_core::Rect,
}
#[derive(Debug, Clone)]
pub struct SelectableTextState {
pub selection_anchor: usize,
pub caret: usize,
pub affinity: CaretAffinity,
pub preferred_x: Option<Px>,
pub dragging: bool,
pub last_pointer_pos: Option<fret_core::Point>,
pub pointer_down_pos: Option<fret_core::Point>,
pub pending_span_activation: Option<crate::action::SelectableTextSpanActivation>,
pub pending_span_click_count: u8,
pub interactive_span_bounds: Vec<SelectableTextInteractiveSpanBounds>,
}
impl Default for SelectableTextState {
fn default() -> Self {
Self {
selection_anchor: 0,
caret: 0,
affinity: CaretAffinity::Downstream,
preferred_x: None,
dragging: false,
last_pointer_pos: None,
pointer_down_pos: None,
pending_span_activation: None,
pending_span_click_count: 0,
interactive_span_bounds: Vec::new(),
}
}
}
#[derive(Clone)]
pub struct TextInputProps {
pub layout: LayoutStyle,
pub enabled: bool,
pub focusable: bool,
pub model: Model<String>,
pub a11y_label: Option<std::sync::Arc<str>>,
pub a11y_role: Option<SemanticsRole>,
pub test_id: Option<std::sync::Arc<str>>,
pub placeholder: Option<std::sync::Arc<str>>,
pub obscure_text: bool,
pub a11y_required: bool,
pub a11y_invalid: Option<fret_core::SemanticsInvalid>,
pub active_descendant: Option<NodeId>,
pub active_descendant_element: Option<u64>,
pub controls_element: Option<u64>,
pub expanded: Option<bool>,
pub chrome: TextInputStyle,
pub focus_ring_always_paint: bool,
pub text_style: TextStyle,
pub submit_command: Option<CommandId>,
pub cancel_command: Option<CommandId>,
}
impl TextInputProps {
pub fn new(model: Model<String>) -> Self {
Self {
layout: LayoutStyle::default(),
enabled: true,
focusable: true,
model,
a11y_label: None,
a11y_role: None,
test_id: None,
placeholder: None,
obscure_text: false,
a11y_required: false,
a11y_invalid: None,
active_descendant: None,
active_descendant_element: None,
controls_element: None,
expanded: None,
chrome: TextInputStyle::default(),
focus_ring_always_paint: false,
text_style: TextStyle::default(),
submit_command: None,
cancel_command: None,
}
}
}
impl std::fmt::Debug for TextInputProps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TextInputProps")
.field("layout", &self.layout)
.field("enabled", &self.enabled)
.field("focusable", &self.focusable)
.field("model", &"<model>")
.field("a11y_label", &self.a11y_label.as_ref().map(|s| s.as_ref()))
.field("a11y_role", &self.a11y_role)
.field("test_id", &self.test_id.as_ref().map(|s| s.as_ref()))
.field(
"placeholder",
&self.placeholder.as_ref().map(|s| s.as_ref()),
)
.field("obscure_text", &self.obscure_text)
.field("active_descendant_element", &self.active_descendant_element)
.field("controls_element", &self.controls_element)
.field("expanded", &self.expanded)
.field("chrome", &self.chrome)
.field("focus_ring_always_paint", &self.focus_ring_always_paint)
.field("text_style", &self.text_style)
.field("submit_command", &self.submit_command)
.field("cancel_command", &self.cancel_command)
.finish()
}
}
#[derive(Clone)]
pub struct TextAreaProps {
pub layout: LayoutStyle,
pub enabled: bool,
pub focusable: bool,
pub model: Model<String>,
pub placeholder: Option<std::sync::Arc<str>>,
pub a11y_required: bool,
pub a11y_invalid: Option<fret_core::SemanticsInvalid>,
pub a11y_label: Option<std::sync::Arc<str>>,
pub test_id: Option<std::sync::Arc<str>>,
pub chrome: TextAreaStyle,
pub focus_ring_always_paint: bool,
pub text_style: TextStyle,
pub min_height: Px,
}
impl TextAreaProps {
pub fn new(model: Model<String>) -> Self {
Self {
layout: LayoutStyle::default(),
enabled: true,
focusable: true,
model,
placeholder: None,
a11y_required: false,
a11y_invalid: None,
a11y_label: None,
test_id: None,
chrome: TextAreaStyle::default(),
focus_ring_always_paint: false,
text_style: TextStyle::default(),
min_height: Px(80.0),
}
}
}
impl std::fmt::Debug for TextAreaProps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TextAreaProps")
.field("layout", &self.layout)
.field("enabled", &self.enabled)
.field("focusable", &self.focusable)
.field("model", &"<model>")
.field(
"placeholder",
&self.placeholder.as_ref().map(|s| s.as_ref()),
)
.field("a11y_label", &self.a11y_label.as_ref().map(|s| s.as_ref()))
.field("test_id", &self.test_id.as_ref().map(|s| s.as_ref()))
.field("chrome", &self.chrome)
.field("focus_ring_always_paint", &self.focus_ring_always_paint)
.field("text_style", &self.text_style)
.field("min_height", &self.min_height)
.finish()
}
}
#[derive(Clone)]
pub struct ResizablePanelGroupProps {
pub layout: LayoutStyle,
pub axis: fret_core::Axis,
pub model: Model<Vec<f32>>,
pub min_px: Vec<Px>,
pub enabled: bool,
pub chrome: ResizablePanelGroupStyle,
}
impl ResizablePanelGroupProps {
pub fn new(axis: fret_core::Axis, model: Model<Vec<f32>>) -> Self {
let mut layout = LayoutStyle::default();
layout.size.width = Length::Fill;
layout.size.height = Length::Fill;
Self {
layout,
axis,
model,
min_px: Vec::new(),
enabled: true,
chrome: ResizablePanelGroupStyle::default(),
}
}
}
impl std::fmt::Debug for ResizablePanelGroupProps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ResizablePanelGroupProps")
.field("layout", &self.layout)
.field("axis", &self.axis)
.field("model", &"<model>")
.field("min_px_len", &self.min_px.len())
.field("enabled", &self.enabled)
.field("chrome", &self.chrome)
.finish()
}
}
#[derive(Debug, Clone, Copy)]
pub struct ImageProps {
pub layout: LayoutStyle,
pub image: ImageId,
pub fit: ViewportFit,
pub sampling: fret_core::scene::ImageSamplingHint,
pub opacity: f32,
pub uv: Option<UvRect>,
}
impl ImageProps {
pub fn new(image: ImageId) -> Self {
Self {
layout: LayoutStyle::default(),
image,
fit: ViewportFit::Stretch,
sampling: fret_core::scene::ImageSamplingHint::Default,
opacity: 1.0,
uv: None,
}
}
pub fn sampling(mut self, sampling: fret_core::scene::ImageSamplingHint) -> Self {
self.sampling = sampling;
self
}
}
#[derive(Debug, Clone, Copy)]
pub struct ViewportSurfaceProps {
pub layout: LayoutStyle,
pub target: RenderTargetId,
pub target_px_size: (u32, u32),
pub fit: ViewportFit,
pub opacity: f32,
}
impl ViewportSurfaceProps {
pub fn new(target: RenderTargetId) -> Self {
Self {
layout: LayoutStyle::default(),
target,
target_px_size: (1, 1),
fit: ViewportFit::Stretch,
opacity: 1.0,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct CanvasProps {
pub layout: LayoutStyle,
pub cache_policy: CanvasCachePolicy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CanvasCacheTuning {
pub keep_frames: u64,
pub max_entries: usize,
}
impl CanvasCacheTuning {
pub const fn transient() -> Self {
Self {
keep_frames: 0,
max_entries: 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CanvasCachePolicy {
pub text: CanvasCacheTuning,
pub shared_text: CanvasCacheTuning,
pub path: CanvasCacheTuning,
pub svg: CanvasCacheTuning,
}
impl CanvasCachePolicy {
pub const fn smooth_default() -> Self {
Self {
text: CanvasCacheTuning {
keep_frames: 60,
max_entries: 4096,
},
shared_text: CanvasCacheTuning {
keep_frames: 120,
max_entries: 4096,
},
path: CanvasCacheTuning {
keep_frames: 60,
max_entries: 2048,
},
svg: CanvasCacheTuning {
keep_frames: 60,
max_entries: 256,
},
}
}
}
impl Default for CanvasCachePolicy {
fn default() -> Self {
Self::smooth_default()
}
}
impl Default for CanvasProps {
fn default() -> Self {
let mut layout = LayoutStyle::default();
layout.size.width = Length::Fill;
layout.size.height = Length::Fill;
Self {
layout,
cache_policy: CanvasCachePolicy::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct SvgIconProps {
pub layout: LayoutStyle,
pub svg: SvgSource,
pub fit: SvgFit,
pub color: Color,
pub inherit_color: bool,
pub opacity: f32,
}
impl SvgIconProps {
pub fn new(svg: SvgSource) -> Self {
Self {
layout: LayoutStyle::default(),
svg,
fit: SvgFit::Contain,
color: Color {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
},
inherit_color: false,
opacity: 1.0,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct SpinnerProps {
pub layout: LayoutStyle,
pub color: Option<Color>,
pub dot_count: u8,
pub speed: f32,
}
impl Default for SpinnerProps {
fn default() -> Self {
let mut layout = LayoutStyle::default();
layout.size.width = Length::Px(Px(16.0));
layout.size.height = Length::Px(Px(16.0));
Self {
layout,
color: None,
dot_count: 12,
speed: 0.2,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct HoverRegionProps {
pub layout: LayoutStyle,
}
#[derive(Debug, Clone)]
pub struct WheelRegionProps {
pub layout: LayoutStyle,
pub axis: ScrollAxis,
pub scroll_target: Option<GlobalElementId>,
pub scroll_handle: crate::scroll::ScrollHandle,
}
impl Default for WheelRegionProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
axis: ScrollAxis::Y,
scroll_target: None,
scroll_handle: crate::scroll::ScrollHandle::default(),
}
}
}
impl TextProps {
pub fn new(text: impl Into<std::sync::Arc<str>>) -> Self {
Self {
layout: LayoutStyle::default(),
text: text.into(),
style: None,
color: None,
wrap: TextWrap::Word,
overflow: TextOverflow::Clip,
align: TextAlign::Start,
ink_overflow: TextInkOverflow::None,
}
}
pub(crate) fn resolved_text_style_with_inherited(
&self,
theme: crate::ThemeSnapshot,
inherited: Option<&fret_core::TextStyleRefinement>,
) -> TextStyle {
crate::text_props::resolve_text_style(theme, self.style.clone(), inherited)
}
pub(crate) fn build_text_input_with_style(&self, style: TextStyle) -> fret_core::TextInput {
crate::text_props::build_text_input_plain(self.text.clone(), style)
}
}
impl StyledTextProps {
pub fn new(rich: AttributedText) -> Self {
Self {
layout: LayoutStyle::default(),
rich,
style: None,
color: None,
wrap: TextWrap::Word,
overflow: TextOverflow::Clip,
align: TextAlign::Start,
ink_overflow: TextInkOverflow::None,
}
}
pub(crate) fn resolved_text_style_with_inherited(
&self,
theme: crate::ThemeSnapshot,
inherited: Option<&fret_core::TextStyleRefinement>,
) -> TextStyle {
crate::text_props::resolve_text_style(theme, self.style.clone(), inherited)
}
pub(crate) fn build_text_input_with_style(&self, style: TextStyle) -> fret_core::TextInput {
crate::text_props::build_text_input_attributed(&self.rich, style)
}
}
impl SelectableTextProps {
pub fn new(rich: AttributedText) -> Self {
Self {
layout: LayoutStyle::default(),
rich,
style: None,
color: None,
wrap: TextWrap::Word,
overflow: TextOverflow::Clip,
align: TextAlign::Start,
ink_overflow: TextInkOverflow::None,
interactive_spans: std::sync::Arc::from([]),
}
}
pub(crate) fn resolved_text_style_with_inherited(
&self,
theme: crate::ThemeSnapshot,
inherited: Option<&fret_core::TextStyleRefinement>,
) -> TextStyle {
crate::text_props::resolve_text_style(theme, self.style.clone(), inherited)
}
pub(crate) fn build_text_input_with_style(&self, style: TextStyle) -> fret_core::TextInput {
crate::text_props::build_text_input_attributed(&self.rich, style)
}
}
#[derive(Debug, Clone, Copy)]
pub struct FlexProps {
pub layout: LayoutStyle,
pub direction: fret_core::Axis,
pub gap: SpacingLength,
pub padding: SpacingEdges,
pub justify: MainAlign,
pub align: CrossAlign,
pub wrap: bool,
}
impl Default for FlexProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
direction: fret_core::Axis::Horizontal,
gap: SpacingLength::Px(Px(0.0)),
padding: SpacingEdges::all(SpacingLength::Px(Px(0.0))),
justify: MainAlign::Start,
align: CrossAlign::Stretch,
wrap: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GridTrackSizing {
Auto,
MinContent,
MaxContent,
Px(Px),
Fr(f32),
Flex(f32),
}
#[derive(Debug, Clone, PartialEq)]
pub struct GridProps {
pub layout: LayoutStyle,
pub cols: u16,
pub rows: Option<u16>,
pub template_columns: Option<Vec<GridTrackSizing>>,
pub template_rows: Option<Vec<GridTrackSizing>>,
pub gap: SpacingLength,
pub column_gap: Option<SpacingLength>,
pub row_gap: Option<SpacingLength>,
pub padding: SpacingEdges,
pub justify: MainAlign,
pub align: CrossAlign,
pub justify_items: Option<CrossAlign>,
}
impl Default for GridProps {
fn default() -> Self {
Self {
layout: LayoutStyle::default(),
cols: 1,
rows: None,
template_columns: None,
template_rows: None,
gap: SpacingLength::Px(Px(0.0)),
column_gap: None,
row_gap: None,
padding: SpacingEdges::all(SpacingLength::Px(Px(0.0))),
justify: MainAlign::Start,
align: CrossAlign::Stretch,
justify_items: None,
}
}
}
impl GridProps {
pub fn resolved_column_gap(&self) -> SpacingLength {
self.column_gap.unwrap_or(self.gap)
}
pub fn resolved_row_gap(&self) -> SpacingLength {
self.row_gap.unwrap_or(self.gap)
}
}
#[derive(Debug, Clone)]
pub struct VirtualListProps {
pub layout: LayoutStyle,
pub axis: fret_core::Axis,
pub len: usize,
pub items_revision: u64,
pub estimate_row_height: Px,
pub measure_mode: VirtualListMeasureMode,
pub key_cache: VirtualListKeyCacheMode,
pub overscan: usize,
pub keep_alive: usize,
pub scroll_margin: Px,
pub gap: Px,
pub scroll_handle: crate::scroll::VirtualListScrollHandle,
pub visible_items: Vec<crate::virtual_list::VirtualItem>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VirtualListMeasureMode {
Measured,
Fixed,
Known,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum VirtualListKeyCacheMode {
#[default]
AllKeys,
VisibleOnly,
}
#[derive(Clone)]
pub struct VirtualListOptions {
pub axis: fret_core::Axis,
pub items_revision: u64,
pub estimate_row_height: Px,
pub measure_mode: VirtualListMeasureMode,
pub key_cache: VirtualListKeyCacheMode,
pub overscan: usize,
pub keep_alive: usize,
pub scroll_margin: Px,
pub gap: Px,
pub known_row_height_at: Option<Arc<dyn Fn(usize) -> Px + Send + Sync>>,
}
impl VirtualListOptions {
pub fn new(estimate_row_height: Px, overscan: usize) -> Self {
Self {
axis: fret_core::Axis::Vertical,
items_revision: 0,
estimate_row_height,
measure_mode: VirtualListMeasureMode::Measured,
key_cache: VirtualListKeyCacheMode::AllKeys,
overscan,
keep_alive: 0,
scroll_margin: Px(0.0),
gap: Px(0.0),
known_row_height_at: None,
}
}
pub fn keep_alive(mut self, keep_alive: usize) -> Self {
self.keep_alive = keep_alive;
self
}
pub fn fixed(estimate_row_height: Px, overscan: usize) -> Self {
Self {
measure_mode: VirtualListMeasureMode::Fixed,
..Self::new(estimate_row_height, overscan)
}
}
pub fn known(
estimate_row_height: Px,
overscan: usize,
height_at: impl Fn(usize) -> Px + Send + Sync + 'static,
) -> Self {
let mut options = Self::new(estimate_row_height, overscan);
options.measure_mode = VirtualListMeasureMode::Known;
options.known_row_height_at = Some(Arc::new(height_at));
options
}
}
impl std::fmt::Debug for VirtualListOptions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VirtualListOptions")
.field("axis", &self.axis)
.field("items_revision", &self.items_revision)
.field("estimate_row_height", &self.estimate_row_height)
.field("measure_mode", &self.measure_mode)
.field("key_cache", &self.key_cache)
.field("overscan", &self.overscan)
.field("keep_alive", &self.keep_alive)
.field("scroll_margin", &self.scroll_margin)
.field("gap", &self.gap)
.field("known_row_height_at", &self.known_row_height_at.is_some())
.finish()
}
}
#[derive(Debug, Default, Clone)]
pub struct VirtualListState {
pub offset_x: Px,
pub offset_y: Px,
pub viewport_w: Px,
pub viewport_h: Px,
pub(crate) window_range: Option<crate::virtual_list::VirtualRange>,
pub(crate) render_window_range: Option<crate::virtual_list::VirtualRange>,
pub(crate) last_scroll_direction_forward: Option<bool>,
pub(crate) has_final_viewport: bool,
pub(crate) deferred_scroll_offset_hint: Option<Px>,
pub(crate) metrics: crate::virtual_list::VirtualListMetrics,
pub(crate) items_revision: u64,
pub(crate) items_len: usize,
pub(crate) key_cache: VirtualListKeyCacheMode,
pub(crate) keys: Vec<crate::ItemKey>,
pub(crate) layout_scratch: VirtualListLayoutScratch,
}
#[derive(Debug, Default, Clone)]
pub(crate) struct VirtualListLayoutScratch {
pub(crate) measured_updates: Vec<(NodeId, usize, Px)>,
pub(crate) barrier_roots: Vec<(NodeId, Rect)>,
}
#[derive(Debug, Clone)]
pub struct ScrollProps {
pub layout: LayoutStyle,
pub axis: ScrollAxis,
pub scroll_handle: Option<crate::scroll::ScrollHandle>,
pub intrinsic_measure_mode: ScrollIntrinsicMeasureMode,
pub windowed_paint: bool,
pub probe_unbounded: bool,
}
impl Default for ScrollProps {
fn default() -> Self {
let layout = LayoutStyle {
overflow: Overflow::Clip,
..Default::default()
};
Self {
layout,
axis: ScrollAxis::Y,
scroll_handle: None,
intrinsic_measure_mode: ScrollIntrinsicMeasureMode::Content,
windowed_paint: false,
probe_unbounded: true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScrollIntrinsicMeasureMode {
Content,
Viewport,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScrollAxis {
X,
Y,
Both,
}
impl ScrollAxis {
pub fn scroll_x(self) -> bool {
matches!(self, Self::X | Self::Both)
}
pub fn scroll_y(self) -> bool {
matches!(self, Self::Y | Self::Both)
}
}
#[derive(Debug, Default, Clone)]
pub struct ScrollState {
pub scroll_handle: crate::scroll::ScrollHandle,
pub(crate) intrinsic_measure_cache: Option<ScrollIntrinsicMeasureCache>,
pub(crate) pending_extent_probe: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ScrollIntrinsicMeasureCacheKey {
pub avail_w: u64,
pub avail_h: u64,
pub axis: u8,
pub probe_unbounded: bool,
pub scale_bits: u32,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ScrollIntrinsicMeasureCache {
pub key: ScrollIntrinsicMeasureCacheKey,
pub max_child: Size,
}
#[derive(Debug, Clone, Copy)]
pub struct ScrollbarStyle {
pub thumb: Color,
pub thumb_hover: Color,
pub thumb_idle_alpha: f32,
pub track_padding: Px,
}
impl Default for ScrollbarStyle {
fn default() -> Self {
Self {
thumb: Color {
r: 0.35,
g: 0.38,
b: 0.45,
a: 1.0,
},
thumb_hover: Color {
r: 0.45,
g: 0.50,
b: 0.60,
a: 1.0,
},
thumb_idle_alpha: 0.65,
track_padding: Px(1.0),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ScrollbarAxis {
#[default]
Vertical,
Horizontal,
}
#[derive(Debug, Clone, Default)]
pub struct ScrollbarProps {
pub layout: LayoutStyle,
pub axis: ScrollbarAxis,
pub scroll_target: Option<GlobalElementId>,
pub scroll_handle: crate::scroll::ScrollHandle,
pub style: ScrollbarStyle,
}
#[derive(Debug, Default, Clone)]
pub struct ScrollbarState {
pub dragging_thumb: bool,
pub drag_start_pointer: Px,
pub drag_start_offset: Px,
pub drag_baseline_viewport: Option<Px>,
pub drag_baseline_content: Option<Px>,
pub hovered: bool,
}
pub trait IntoElement {
fn into_element(self, id: GlobalElementId) -> AnyElement;
}
#[derive(Debug, Default)]
pub struct Elements(pub Vec<AnyElement>);
impl Elements {
pub fn new(children: impl IntoIterator<Item = AnyElement>) -> Self {
Self(children.into_iter().collect())
}
pub fn into_vec(self) -> Vec<AnyElement> {
self.0
}
}
impl From<Vec<AnyElement>> for Elements {
fn from(value: Vec<AnyElement>) -> Self {
Self(value)
}
}
impl From<AnyElement> for Elements {
fn from(value: AnyElement) -> Self {
Self::new([value])
}
}
impl<const N: usize> From<[AnyElement; N]> for Elements {
fn from(value: [AnyElement; N]) -> Self {
Self::new(value)
}
}
impl std::iter::FromIterator<AnyElement> for Elements {
fn from_iter<T: IntoIterator<Item = AnyElement>>(iter: T) -> Self {
Self::new(iter)
}
}
impl std::ops::Deref for Elements {
type Target = Vec<AnyElement>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for Elements {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl IntoIterator for Elements {
type Item = AnyElement;
type IntoIter = std::vec::IntoIter<AnyElement>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a Elements {
type Item = &'a AnyElement;
type IntoIter = std::slice::Iter<'a, AnyElement>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut Elements {
type Item = &'a mut AnyElement;
type IntoIter = std::slice::IterMut<'a, AnyElement>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
pub trait AnyElementIterExt: Iterator<Item = AnyElement> + Sized {
fn elements(self) -> Vec<AnyElement> {
self.collect()
}
fn elements_owned(self) -> Elements {
self.collect::<Elements>()
}
}
impl<T> AnyElementIterExt for T where T: Iterator<Item = AnyElement> + Sized {}
impl IntoElement for AnyElement {
fn into_element(self, _id: GlobalElementId) -> AnyElement {
self
}
}
impl IntoElement for TextProps {
fn into_element(self, id: GlobalElementId) -> AnyElement {
AnyElement::new(id, ElementKind::Text(self), Vec::new())
}
}
impl IntoElement for StyledTextProps {
fn into_element(self, id: GlobalElementId) -> AnyElement {
AnyElement::new(id, ElementKind::StyledText(self), Vec::new())
}
}
impl IntoElement for SelectableTextProps {
fn into_element(self, id: GlobalElementId) -> AnyElement {
AnyElement::new(id, ElementKind::SelectableText(self), Vec::new())
}
}
impl IntoElement for ImageProps {
fn into_element(self, id: GlobalElementId) -> AnyElement {
AnyElement::new(id, ElementKind::Image(self), Vec::new())
}
}
impl IntoElement for ViewportSurfaceProps {
fn into_element(self, id: GlobalElementId) -> AnyElement {
AnyElement::new(id, ElementKind::ViewportSurface(self), Vec::new())
}
}
impl IntoElement for SvgIconProps {
fn into_element(self, id: GlobalElementId) -> AnyElement {
AnyElement::new(id, ElementKind::SvgIcon(self), Vec::new())
}
}
impl IntoElement for ScrollProps {
fn into_element(self, id: GlobalElementId) -> AnyElement {
AnyElement::new(id, ElementKind::Scroll(self), Vec::new())
}
}
impl IntoElement for std::sync::Arc<str> {
fn into_element(self, id: GlobalElementId) -> AnyElement {
TextProps::new(self).into_element(id)
}
}
impl IntoElement for &'static str {
fn into_element(self, id: GlobalElementId) -> AnyElement {
TextProps::new(self).into_element(id)
}
}
pub trait Render {
fn render<H: UiHost>(&mut self, cx: &mut ElementContext<'_, H>) -> AnyElement;
}
pub trait RenderOnce {
fn render_once<H: UiHost>(self, cx: &mut ElementContext<'_, H>) -> AnyElement;
}
#[cfg(test)]
mod default_semantics_tests {
use super::*;
#[test]
fn flex_props_default_width_is_auto() {
assert_eq!(FlexProps::default().layout.size.width, Length::Auto);
}
#[test]
fn length_default_is_auto() {
assert_eq!(Length::default(), Length::Auto);
}
#[test]
fn scroll_props_default_probe_unbounded_is_true() {
assert!(ScrollProps::default().probe_unbounded);
}
}