Skip to main content

AnimatedValues

Struct AnimatedValues 

Source
pub struct AnimatedValues {
    pub opacity: f32,
    pub translate: UiPoint,
    pub scale: f32,
    pub morph: f32,
}

Fields§

§opacity: f32§translate: UiPoint§scale: f32§morph: f32

Implementations§

Source§

impl AnimatedValues

Source

pub const fn new(opacity: f32, translate: UiPoint, scale: f32) -> Self

Examples found in repository?
examples/showcase.rs (line 5028)
5020fn animation_blend_machine(
5021    input: &'static str,
5022    value: f32,
5023    translate: UiPoint,
5024    start_scale: f32,
5025    end_scale: f32,
5026    end_opacity: f32,
5027) -> AnimationMachine {
5028    let start_values = AnimatedValues::new(0.45, UiPoint::new(0.0, 0.0), start_scale);
5029    let end_values = AnimatedValues::new(end_opacity, translate, end_scale).with_morph(1.0);
5030    AnimationMachine::new(
5031        vec![
5032            AnimationState::new("start", start_values),
5033            AnimationState::new("end", end_values),
5034        ],
5035        Vec::new(),
5036        "start",
5037    )
5038    .unwrap_or_else(|_| AnimationMachine::single_state("start", start_values))
5039    .with_number_input(input, value)
5040    .with_blend_binding(AnimationBlendBinding::new(input, "start", "end"))
5041}
5042
5043fn animation_open_machine(open: bool) -> AnimationMachine {
5044    let closed_values = AnimatedValues::new(0.35, UiPoint::new(0.0, 0.0), 1.0);
5045    let open_values = AnimatedValues::new(1.0, UiPoint::new(0.0, 0.0), 1.0);
5046    let fallback_values = if open { open_values } else { closed_values };
5047    AnimationMachine::new(
5048        vec![
5049            AnimationState::new("closed", closed_values),
5050            AnimationState::new("open", open_values),
5051        ],
5052        vec![
5053            AnimationTransition::when(
5054                "closed",
5055                "open",
5056                AnimationCondition::bool(ANIMATION_INPUT_OPEN, true),
5057                0.18,
5058            ),
5059            AnimationTransition::when(
5060                "open",
5061                "closed",
5062                AnimationCondition::bool(ANIMATION_INPUT_OPEN, false),
5063                0.14,
5064            ),
5065        ],
5066        "closed",
5067    )
5068    .unwrap_or_else(|_| AnimationMachine::single_state("closed", fallback_values))
5069    .with_bool_input(ANIMATION_INPUT_OPEN, open)
5070}
5071
5072fn animation_interaction_machine() -> AnimationMachine {
5073    let rest_values = AnimatedValues::new(0.72, UiPoint::new(0.0, 0.0), 1.0);
5074    let right_values = AnimatedValues::new(1.0, UiPoint::new(0.0, 0.0), 1.0).with_morph(1.0);
5075    AnimationMachine::new(
5076        vec![
5077            AnimationState::new("rest", rest_values),
5078            AnimationState::new("right", right_values),
5079        ],
5080        Vec::new(),
5081        "rest",
5082    )
5083    .unwrap_or_else(|_| AnimationMachine::single_state("rest", rest_values))
5084    .with_number_input(ANIMATION_INPUT_POINTER_NORM_X, 0.0)
5085    .with_blend_binding(AnimationBlendBinding::new(
5086        ANIMATION_INPUT_POINTER_NORM_X,
5087        "rest",
5088        "right",
5089    ))
5090}
5091
5092fn animation_interaction_primitives(
5093    fill: ColorRgba,
5094    size: f32,
5095    offset: UiPoint,
5096) -> Vec<ScenePrimitive> {
5097    vec![
5098        ScenePrimitive::MorphPolygon {
5099            from_points: animation_square_points(size, offset),
5100            to_points: animation_pentagon_points(size, offset),
5101            amount: 0.0,
5102            fill,
5103            stroke: Some(StrokeStyle::new(color(236, 244, 255), 1.0)),
5104        },
5105        ScenePrimitive::Circle {
5106            center: UiPoint::new(offset.x + size * 0.34, offset.y + size * 0.30),
5107            radius: size * 0.10,
5108            fill: color(244, 248, 255),
5109            stroke: None,
5110        },
5111    ]
5112}
5113
5114fn animation_orb_primitives(fill: ColorRgba, size: f32, offset: UiPoint) -> Vec<ScenePrimitive> {
5115    let center = size * 0.5;
5116    let radius = size * 0.44;
5117    vec![
5118        ScenePrimitive::Circle {
5119            center: UiPoint::new(offset.x + center, offset.y + center),
5120            radius,
5121            fill,
5122            stroke: Some(StrokeStyle::new(color(236, 244, 255), 1.0)),
5123        },
5124        ScenePrimitive::Circle {
5125            center: UiPoint::new(offset.x + size * 0.34, offset.y + size * 0.30),
5126            radius: size * 0.12,
5127            fill: color(244, 248, 255),
5128            stroke: None,
5129        },
5130    ]
5131}
5132
5133fn animation_morph_shape_primitives(
5134    fill: ColorRgba,
5135    size: f32,
5136    offset: UiPoint,
5137    amount: f32,
5138) -> Vec<ScenePrimitive> {
5139    vec![ScenePrimitive::MorphPolygon {
5140        from_points: animation_square_points(size, offset),
5141        to_points: animation_pentagon_points(size, offset),
5142        amount,
5143        fill,
5144        stroke: Some(StrokeStyle::new(color(226, 246, 236), 1.0)),
5145    }]
5146}
5147
5148fn animation_square_points(size: f32, offset: UiPoint) -> Vec<UiPoint> {
5149    let inset = size * 0.08;
5150    let left = offset.x + inset;
5151    let top = offset.y + inset;
5152    let right = offset.x + size - inset;
5153    let bottom = offset.y + size - inset;
5154    let center_x = offset.x + size * 0.5;
5155    vec![
5156        UiPoint::new(center_x, top),
5157        UiPoint::new(right, top),
5158        UiPoint::new(right, bottom),
5159        UiPoint::new(left, bottom),
5160        UiPoint::new(left, top),
5161    ]
5162}
5163
5164fn animation_pentagon_points(size: f32, offset: UiPoint) -> Vec<UiPoint> {
5165    let center = size * 0.5;
5166    let radius = size * 0.46;
5167    (0..5)
5168        .map(|index| {
5169            let angle = -std::f32::consts::FRAC_PI_2 + index as f32 * std::f32::consts::TAU / 5.0;
5170            UiPoint::new(
5171                offset.x + center + angle.cos() * radius,
5172                offset.y + center + angle.sin() * radius,
5173            )
5174        })
5175        .collect()
5176}
5177
5178fn animation_panel_primitives(offset: UiPoint) -> Vec<ScenePrimitive> {
5179    vec![ScenePrimitive::Rect(
5180        PaintRect::solid(
5181            UiRect::new(
5182                offset.x,
5183                offset.y,
5184                ANIMATION_PANEL_WIDTH,
5185                ANIMATION_PANEL_HEIGHT,
5186            ),
5187            color(232, 186, 88),
5188        )
5189        .stroke(AlignedStroke::inside(StrokeStyle::new(
5190            color(255, 226, 154),
5191            1.0,
5192        )))
5193        .corner_radii(CornerRadii::uniform(6.0)),
5194    )]
5195}
5196
5197fn list_and_table_widgets(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
5198    let body = section(ui, parent, "lists_tables", "Lists and tables");
5199
5200    let scroll_shell = row(ui, body, "lists_tables.scroll_area.shell", 8.0);
5201    let nested_scroll = widgets::scroll_area(
5202        ui,
5203        scroll_shell,
5204        "lists_tables.scroll_area",
5205        ScrollAxes::VERTICAL,
5206        LayoutStyle::column()
5207            .with_width(0.0)
5208            .with_flex_grow(1.0)
5209            .with_height(92.0),
5210    );
5211    ui.node_mut(nested_scroll)
5212        .set_action("lists_tables.scroll_area.scroll");
5213    if let Some(scroll) = ui.node_mut(nested_scroll).scroll_mut() {
5214        scroll.set_offset(UiPoint::new(0.0, state.list_scroll));
5215    }
5216    for index in 0..6 {
5217        widgets::label(
5218            ui,
5219            nested_scroll,
5220            format!("lists_tables.scroll_area.row.{index}"),
5221            format!("Scroll row {}", index + 1),
5222            text(12.0, color(200, 212, 228)),
5223            LayoutStyle::new()
5224                .with_width_percent(1.0)
5225                .with_height(26.0)
5226                .with_flex_shrink(0.0),
5227        );
5228    }
5229    scrollbar_widgets::scrollbar(
5230        ui,
5231        scroll_shell,
5232        "lists_tables.scroll_area.scrollbar",
5233        scroll_state(state.list_scroll, 92.0, 6.0 * 26.0),
5234        scrollbar_widgets::ScrollAxis::Vertical,
5235        scrollbar_widgets::ScrollbarOptions::default()
5236            .with_layout(LayoutStyle::size(8.0, 92.0))
5237            .with_track_size(UiSize::new(8.0, 92.0))
5238            .with_action("lists_tables.scroll_area.scrollbar"),
5239    );
5240
5241    widgets::table_header(ui, body, "lists_tables.table_header", &table_columns());
5242
5243    let virtual_shell = row(ui, body, "lists_tables.virtual_list.shell", 8.0);
5244    let virtual_list = widgets::virtual_list(
5245        ui,
5246        virtual_shell,
5247        "lists_tables.virtual_list",
5248        widgets::VirtualListSpec {
5249            row_count: 24,
5250            row_height: 28.0,
5251            viewport_height: 112.0,
5252            scroll_offset: state.virtual_scroll,
5253            overscan: 1,
5254        },
5255        |ui, row_parent, row| {
5256            widgets::label(
5257                ui,
5258                row_parent,
5259                format!("lists_tables.virtual_list.row.{row}"),
5260                format!("Virtual row {}", row + 1),
5261                text(12.0, color(214, 224, 238)),
5262                LayoutStyle::new()
5263                    .with_width_percent(1.0)
5264                    .with_height(28.0)
5265                    .with_flex_shrink(0.0),
5266            );
5267        },
5268    );
5269    ui.node_mut(virtual_list)
5270        .set_action("lists_tables.virtual_list.scroll");
5271    scrollbar_widgets::scrollbar(
5272        ui,
5273        virtual_shell,
5274        "lists_tables.virtual_list.scrollbar",
5275        scroll_state(state.virtual_scroll, 112.0, 24.0 * 28.0),
5276        scrollbar_widgets::ScrollAxis::Vertical,
5277        scrollbar_widgets::ScrollbarOptions::default()
5278            .with_layout(LayoutStyle::size(8.0, 112.0))
5279            .with_track_size(UiSize::new(8.0, 112.0))
5280            .with_action("lists_tables.virtual_list.scrollbar"),
5281    );
5282
5283    let table_shell = row(ui, body, "lists_tables.data_table.shell", 8.0);
5284    let table_scroll = widgets::scroll_area(
5285        ui,
5286        table_shell,
5287        "lists_tables.data_table",
5288        ScrollAxes::VERTICAL,
5289        LayoutStyle::column()
5290            .with_width(0.0)
5291            .with_flex_grow(1.0)
5292            .with_height(128.0),
5293    );
5294    ui.node_mut(table_scroll)
5295        .set_action("lists_tables.data_table.scroll");
5296    if let Some(scroll) = ui.node_mut(table_scroll).scroll_mut() {
5297        scroll.set_offset(UiPoint::new(0.0, state.table_scroll));
5298    }
5299    for row_index in 0..16 {
5300        data_table_row(ui, table_scroll, row_index, state);
5301    }
5302    scrollbar_widgets::scrollbar(
5303        ui,
5304        table_shell,
5305        "lists_tables.data_table.scrollbar",
5306        scroll_state(state.table_scroll, 128.0, 16.0 * 28.0),
5307        scrollbar_widgets::ScrollAxis::Vertical,
5308        scrollbar_widgets::ScrollbarOptions::default()
5309            .with_layout(LayoutStyle::size(8.0, 128.0))
5310            .with_track_size(UiSize::new(8.0, 128.0))
5311            .with_action("lists_tables.data_table.scrollbar"),
5312    );
5313
5314    let virtual_controls = wrapping_row(ui, body, "lists_tables.virtualized_table.controls", 8.0);
5315    button(
5316        ui,
5317        virtual_controls,
5318        "lists_tables.virtualized_table.sort.name",
5319        if state.virtual_table_descending {
5320            "Name desc"
5321        } else {
5322            "Name asc"
5323        },
5324        "lists_tables.virtualized_table.sort.name",
5325        button_visual(38, 52, 70),
5326    );
5327    button(
5328        ui,
5329        virtual_controls,
5330        "lists_tables.virtualized_table.filter.status",
5331        if state.virtual_table_ready_only {
5332            "Ready only"
5333        } else {
5334            "All status"
5335        },
5336        "lists_tables.virtualized_table.filter.status",
5337        button_visual(38, 52, 70),
5338    );
5339    button(
5340        ui,
5341        virtual_controls,
5342        "lists_tables.virtualized_table.resize.reset",
5343        "Reset width",
5344        "lists_tables.virtualized_table.resize.reset",
5345        button_visual(38, 52, 70),
5346    );
5347
5348    let columns = virtual_table_columns(state);
5349    let visible_rows = virtual_table_visible_rows(state);
5350    let mut table_options = ext_widgets::DataTableOptions::default()
5351        .with_row_action_prefix("lists_tables.virtualized_table")
5352        .with_cell_action_prefix("lists_tables.virtualized_table")
5353        .with_scroll_action("lists_tables.virtualized_table.scroll");
5354    table_options.layout = LayoutStyle::column()
5355        .with_width(0.0)
5356        .with_flex_grow(1.0)
5357        .with_flex_shrink(1.0);
5358    table_options.selection = state.table_selection.clone();
5359    let virtual_shell = row(ui, body, "lists_tables.virtualized_table.shell", 8.0);
5360    ext_widgets::virtualized_data_table(
5361        ui,
5362        virtual_shell,
5363        "lists_tables.virtualized_table",
5364        &columns,
5365        ext_widgets::VirtualDataTableSpec {
5366            row_count: visible_rows.len(),
5367            row_height: 28.0,
5368            viewport_width: 420.0,
5369            viewport_height: 128.0,
5370            scroll_offset: UiPoint::new(0.0, state.virtual_table_scroll),
5371            overscan_rows: 1,
5372        },
5373        table_options,
5374        |ui, cell_parent, cell| {
5375            let source_row = visible_rows.get(cell.row).copied().unwrap_or(cell.row);
5376            let value = virtual_table_cell_value(source_row, cell.column);
5377            widgets::label(
5378                ui,
5379                cell_parent,
5380                format!(
5381                    "lists_tables.virtualized_table.cell.{}.{}.label",
5382                    cell.row, cell.column
5383                ),
5384                value,
5385                text(12.0, color(220, 228, 238)),
5386                LayoutStyle::new().with_width_percent(1.0),
5387            );
5388        },
5389    );
5390    scrollbar_widgets::scrollbar(
5391        ui,
5392        virtual_shell,
5393        "lists_tables.virtualized_table.scrollbar",
5394        scroll_state(
5395            state.virtual_table_scroll,
5396            128.0,
5397            visible_rows.len() as f32 * 28.0,
5398        ),
5399        scrollbar_widgets::ScrollAxis::Vertical,
5400        scrollbar_widgets::ScrollbarOptions::default()
5401            .with_layout(LayoutStyle::size(8.0, 158.0))
5402            .with_track_size(UiSize::new(8.0, 158.0))
5403            .with_action("lists_tables.virtualized_table.scrollbar"),
5404    );
5405}
5406
5407fn data_table_row(ui: &mut UiDocument, parent: UiNodeId, row_index: usize, state: &ShowcaseState) {
5408    let selected = state.table_selection.contains_row(row_index);
5409    let row = ui.add_child(
5410        parent,
5411        UiNode::container(
5412            format!("lists_tables.data_table.row.{row_index}"),
5413            LayoutStyle::row()
5414                .with_width_percent(1.0)
5415                .with_height(28.0)
5416                .with_flex_shrink(0.0),
5417        )
5418        .with_input(operad::InputBehavior::BUTTON)
5419        .with_action(format!("lists_tables.data_table.row.{row_index}"))
5420        .with_visual(if selected {
5421            UiVisual::panel(color(45, 73, 109), None, 0.0)
5422        } else {
5423            UiVisual::TRANSPARENT
5424        }),
5425    );
5426    let values = [
5427        format!("Item {}", row_index + 1),
5428        if row_index % 2 == 0 {
5429            "Ready".to_string()
5430        } else {
5431            "Pending".to_string()
5432        },
5433        format!("{}%", 40 + row_index * 3),
5434    ];
5435    let widths = [0.42, 0.33, 0.25];
5436    for (column, value) in values.into_iter().enumerate() {
5437        let cell = ui.add_child(
5438            row,
5439            UiNode::container(
5440                format!("lists_tables.data_table.cell.{row_index}.{column}"),
5441                LayoutStyle::new()
5442                    .with_width_percent(widths[column])
5443                    .with_height_percent(1.0)
5444                    .padding(6.0),
5445            )
5446            .with_input(operad::InputBehavior::BUTTON)
5447            .with_action(format!("lists_tables.data_table.cell.{row_index}.{column}")),
5448        );
5449        widgets::label(
5450            ui,
5451            cell,
5452            format!("lists_tables.data_table.cell.{row_index}.{column}.label"),
5453            value,
5454            text(12.0, color(222, 230, 240)),
5455            LayoutStyle::new().with_width_percent(1.0),
5456        );
5457    }
5458}
5459
5460#[allow(clippy::field_reassign_with_default)]
5461fn property_inspector(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
5462    let body = section(ui, parent, "property_inspector", "Property inspector");
5463    widgets::label(
5464        ui,
5465        body,
5466        "property_inspector.target",
5467        "Inspecting: Styling preview",
5468        text(12.0, color(196, 210, 230)),
5469        LayoutStyle::new().with_width_percent(1.0),
5470    );
5471    let mut options = ext_widgets::PropertyInspectorOptions::default();
5472    options.selected_index = Some(0);
5473    options.label_width = 120.0;
5474    options.row_height = 30.0;
5475    ext_widgets::property_inspector_grid(
5476        ui,
5477        body,
5478        "property_inspector.grid",
5479        &[
5480            ext_widgets::PropertyGridRow::new("target", "Widget", "Button preview").read_only(),
5481            ext_widgets::PropertyGridRow::new(
5482                "inner",
5483                "Inner margin",
5484                format!("{:.0}px", state.styling.inner_margin),
5485            )
5486            .with_kind(ext_widgets::PropertyValueKind::Number),
5487            ext_widgets::PropertyGridRow::new(
5488                "outer",
5489                "Outer margin",
5490                format!("{:.0}px", state.styling.outer_margin),
5491            )
5492            .with_kind(ext_widgets::PropertyValueKind::Number),
5493            ext_widgets::PropertyGridRow::new(
5494                "radius",
5495                "Corner radius",
5496                format!("{:.0}px", state.styling.corner_radius),
5497            )
5498            .with_kind(ext_widgets::PropertyValueKind::Number),
5499            ext_widgets::PropertyGridRow::new(
5500                "stroke",
5501                "Stroke",
5502                format!("{:.1}px", state.styling.stroke_width),
5503            )
5504            .with_kind(ext_widgets::PropertyValueKind::Number)
5505            .changed(),
5506            ext_widgets::PropertyGridRow::new("state", "Source", "Styling widget").read_only(),
5507        ],
5508        options,
5509    );
5510}
5511
5512fn diagnostics_widgets(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
5513    let body = section(ui, parent, "diagnostics", "Diagnostics");
5514
5515    widgets::label(
5516        ui,
5517        body,
5518        "diagnostics.layout.title",
5519        "Layout and animation inspector",
5520        text(14.0, color(222, 230, 240)),
5521        LayoutStyle::new().with_width_percent(1.0),
5522    );
5523    let debug_snapshot = &state.diagnostics_snapshot;
5524    ext_widgets::debug_inspector_panel(
5525        ui,
5526        body,
5527        "diagnostics.inspector",
5528        debug_snapshot,
5529        ext_widgets::DebugInspectorPanelOptions {
5530            selected_node: Some("diagnostics.sample.preview".to_owned()),
5531            label_width: 104.0,
5532            max_layout_rows: 5,
5533            max_animation_rows: 1,
5534            show_animation: false,
5535            ..Default::default()
5536        },
5537    );
5538    ext_widgets::animation_state_graph_panel(
5539        ui,
5540        body,
5541        "diagnostics.animation.graph",
5542        debug_snapshot.animation("diagnostics.sample.preview"),
5543        ext_widgets::AnimationStateGraphPanelOptions {
5544            state_width: 72.0,
5545            state_height: 28.0,
5546            edge_row_height: 22.0,
5547            max_edges: 2,
5548            action_prefix: Some("diagnostics.animation.graph".to_owned()),
5549            ..Default::default()
5550        },
5551    );
5552    ext_widgets::animation_inspector_controls_panel(
5553        ui,
5554        body,
5555        "diagnostics.animation.controls",
5556        debug_snapshot.animation("diagnostics.sample.preview"),
5557        ext_widgets::AnimationInspectorControlsOptions {
5558            max_inputs: 3,
5559            paused: state.diagnostics_animation_paused,
5560            scrub_progress: Some(state.diagnostics_animation_scrub),
5561            action_prefix: Some("diagnostics.animation.controls".to_owned()),
5562            ..Default::default()
5563        },
5564    );
5565    widgets::label(
5566        ui,
5567        body,
5568        "diagnostics.animation.controls.status",
5569        format!(
5570            "scrub {:.0}%  hover {:.0}%  pulses {}",
5571            state.diagnostics_animation_scrub * 100.0,
5572            state.diagnostics_animation_hover * 100.0,
5573            state.diagnostics_animation_pulse_count
5574        ),
5575        text(12.0, color(166, 180, 198)),
5576        LayoutStyle::new().with_width_percent(1.0),
5577    );
5578
5579    widgets::label(
5580        ui,
5581        body,
5582        "diagnostics.a11y.title",
5583        "Accessibility overlay",
5584        text(14.0, color(222, 230, 240)),
5585        LayoutStyle::new().with_width_percent(1.0),
5586    );
5587    let mut overlay_preview_style = UiNodeStyle::from(
5588        LayoutStyle::new()
5589            .with_width(320.0)
5590            .with_height(140.0)
5591            .with_flex_shrink(0.0),
5592    );
5593    overlay_preview_style.set_clip(ClipBehavior::Clip);
5594    let overlay_preview = ui.add_child(
5595        body,
5596        UiNode::container("diagnostics.a11y.preview", overlay_preview_style).with_visual(
5597            UiVisual::panel(
5598                color(12, 17, 24),
5599                Some(StrokeStyle::new(color(47, 62, 82), 1.0)),
5600                4.0,
5601            ),
5602        ),
5603    );
5604    let mut overlay_options = ext_widgets::AccessibilityDebugOverlayOptions {
5605        action_prefix: Some("diagnostics.a11y.visual".to_owned()),
5606        ..Default::default()
5607    };
5608    overlay_options.show_labels = false;
5609    ext_widgets::accessibility_debug_overlay(
5610        ui,
5611        overlay_preview,
5612        "diagnostics.a11y.visual",
5613        &debug_snapshot,
5614        overlay_options,
5615    );
5616    ext_widgets::accessibility_overlay_panel(
5617        ui,
5618        body,
5619        "diagnostics.a11y",
5620        &debug_snapshot,
5621        ext_widgets::AccessibilityOverlayPanelOptions {
5622            label_width: 118.0,
5623            max_rows: 1,
5624            action_prefix: Some("diagnostics.a11y".to_owned()),
5625            ..Default::default()
5626        },
5627    );
5628
5629    let diagnostic_columns = ui.add_child(
5630        body,
5631        UiNode::container(
5632            "diagnostics.columns",
5633            LayoutStyle::column()
5634                .with_width_percent(1.0)
5635                .with_flex_shrink(0.0)
5636                .gap(10.0),
5637        ),
5638    );
5639    let command_column = ui.add_child(
5640        diagnostic_columns,
5641        UiNode::container(
5642            "diagnostics.commands.column",
5643            LayoutStyle::column()
5644                .with_width_percent(1.0)
5645                .with_flex_shrink(0.0)
5646                .gap(8.0),
5647        ),
5648    );
5649    let theme_column = ui.add_child(
5650        diagnostic_columns,
5651        UiNode::container(
5652            "diagnostics.theme.column",
5653            LayoutStyle::column()
5654                .with_width_percent(1.0)
5655                .with_flex_shrink(0.0)
5656                .gap(8.0),
5657        ),
5658    );
5659
5660    widgets::label(
5661        ui,
5662        command_column,
5663        "diagnostics.commands.title",
5664        "Command registry",
5665        text(14.0, color(222, 230, 240)),
5666        LayoutStyle::new().with_width_percent(1.0),
5667    );
5668    let registry = diagnostics_command_registry();
5669    ext_widgets::command_diagnostics_panel(
5670        ui,
5671        command_column,
5672        "diagnostics.commands",
5673        &registry,
5674        &[CommandScope::Global, CommandScope::Panel],
5675        &ShortcutFormatter::default(),
5676        ext_widgets::CommandDiagnosticsPanelOptions {
5677            label_width: 92.0,
5678            max_command_rows: 3,
5679            max_conflict_rows: 1,
5680            action_prefix: Some("diagnostics.commands".to_owned()),
5681            ..Default::default()
5682        },
5683    );
5684
5685    widgets::label(
5686        ui,
5687        theme_column,
5688        "diagnostics.theme.title",
5689        "Theme editor",
5690        text(14.0, color(222, 230, 240)),
5691        LayoutStyle::new().with_width_percent(1.0),
5692    );
5693    let theme_snapshot = DebugThemeSnapshot::from_theme(&Theme::dark());
5694    ext_widgets::theme_editor_panel(
5695        ui,
5696        theme_column,
5697        "diagnostics.theme",
5698        &theme_snapshot,
5699        ext_widgets::ThemeEditorPanelOptions {
5700            label_width: 92.0,
5701            max_token_rows: 1,
5702            max_component_rows: 1,
5703            action_prefix: Some("diagnostics.theme".to_owned()),
5704            ..Default::default()
5705        },
5706    );
5707}
5708
5709fn diagnostics_sample_snapshot(state: &ShowcaseState) -> DebugInspectorSnapshot {
5710    diagnostics_sample_snapshot_for(
5711        state.diagnostics_animation_hover,
5712        state.diagnostics_animation_active,
5713    )
5714}
5715
5716fn diagnostics_sample_snapshot_for(hover: f32, active: bool) -> DebugInspectorSnapshot {
5717    let mut sample = UiDocument::new(root_style(320.0, 180.0));
5718    let card = sample.add_child(
5719        sample.root(),
5720        UiNode::container(
5721            "diagnostics.sample.card",
5722            LayoutStyle::column()
5723                .with_width_percent(1.0)
5724                .with_height(120.0)
5725                .padding(12.0)
5726                .gap(8.0),
5727        )
5728        .with_visual(UiVisual::panel(
5729            color(16, 22, 30),
5730            Some(StrokeStyle::new(color(62, 77, 98), 1.0)),
5731            6.0,
5732        ))
5733        .with_accessibility(
5734            AccessibilityMeta::new(AccessibilityRole::Group).label("Diagnostics sample"),
5735        ),
5736    );
5737    sample.add_child(
5738        card,
5739        UiNode::container(
5740            "diagnostics.sample.preview",
5741            LayoutStyle::new().with_width(160.0).with_height(38.0),
5742        )
5743        .with_input(InputBehavior::BUTTON)
5744        .with_visual(UiVisual::panel(
5745            color(52, 112, 180),
5746            Some(StrokeStyle::new(color(116, 183, 255), 1.0)),
5747            5.0,
5748        ))
5749        .with_accessibility(
5750            AccessibilityMeta::new(AccessibilityRole::Button)
5751                .label("Preview action")
5752                .focusable(),
5753        )
5754        .with_animation(
5755            AnimationMachine::new(
5756                vec![
5757                    AnimationState::new(
5758                        "idle",
5759                        AnimatedValues::new(1.0, UiPoint::new(0.0, 0.0), 1.0),
5760                    ),
5761                    AnimationState::new(
5762                        "hot",
5763                        AnimatedValues::new(0.92, UiPoint::new(18.0, 0.0), 1.08),
5764                    ),
5765                ],
5766                vec![AnimationTransition::when(
5767                    "idle",
5768                    "hot",
5769                    AnimationCondition::bool("active", true),
5770                    0.18,
5771                )],
5772                "idle",
5773            )
5774            .expect("sample animation")
5775            .with_number_input("hover", hover)
5776            .with_blend_binding(AnimationBlendBinding::new("hover", "idle", "hot"))
5777            .with_bool_input("active", active)
5778            .with_trigger_input("pulse"),
5779        ),
5780    );
5781    widgets::label(
5782        &mut sample,
5783        card,
5784        "diagnostics.sample.label",
5785        "Sample node",
5786        text(12.0, color(198, 210, 226)),
5787        LayoutStyle::new().with_width_percent(1.0),
5788    );
5789    sample
5790        .compute_layout(UiSize::new(320.0, 180.0), &mut ApproxTextMeasurer)
5791        .expect("sample layout");
5792    DebugInspectorSnapshot::from_document(&sample, &mut ApproxTextMeasurer)
5793}
More examples
Hide additional examples
examples/animation_state_machine.rs (line 129)
128fn shape_machine(open: bool) -> AnimationMachine {
129    let closed = AnimatedValues::new(0.82, UiPoint::new(0.0, 0.0), 1.0).with_morph(0.0);
130    let open_values = AnimatedValues::new(1.0, UiPoint::new(160.0, 0.0), 1.08).with_morph(1.0);
131    AnimationMachine::new(
132        vec![
133            AnimationState::new("closed", closed),
134            AnimationState::new("open", open_values),
135        ],
136        vec![
137            AnimationTransition::when(
138                "closed",
139                "open",
140                AnimationCondition::bool(INPUT_OPEN, true),
141                0.24,
142            ),
143            AnimationTransition::when(
144                "open",
145                "closed",
146                AnimationCondition::bool(INPUT_OPEN, false),
147                0.18,
148            ),
149        ],
150        "closed",
151    )
152    .unwrap_or_else(|_| AnimationMachine::single_state("closed", closed))
153    .with_bool_input(INPUT_OPEN, open)
154    .with_number_input(INPUT_MORPH, if open { 1.0 } else { 0.0 })
155    .with_blend_binding(AnimationBlendBinding::new(INPUT_MORPH, "closed", "open"))
156}
Source

pub const fn with_morph(self, morph: f32) -> Self

Examples found in repository?
examples/showcase.rs (line 5029)
5020fn animation_blend_machine(
5021    input: &'static str,
5022    value: f32,
5023    translate: UiPoint,
5024    start_scale: f32,
5025    end_scale: f32,
5026    end_opacity: f32,
5027) -> AnimationMachine {
5028    let start_values = AnimatedValues::new(0.45, UiPoint::new(0.0, 0.0), start_scale);
5029    let end_values = AnimatedValues::new(end_opacity, translate, end_scale).with_morph(1.0);
5030    AnimationMachine::new(
5031        vec![
5032            AnimationState::new("start", start_values),
5033            AnimationState::new("end", end_values),
5034        ],
5035        Vec::new(),
5036        "start",
5037    )
5038    .unwrap_or_else(|_| AnimationMachine::single_state("start", start_values))
5039    .with_number_input(input, value)
5040    .with_blend_binding(AnimationBlendBinding::new(input, "start", "end"))
5041}
5042
5043fn animation_open_machine(open: bool) -> AnimationMachine {
5044    let closed_values = AnimatedValues::new(0.35, UiPoint::new(0.0, 0.0), 1.0);
5045    let open_values = AnimatedValues::new(1.0, UiPoint::new(0.0, 0.0), 1.0);
5046    let fallback_values = if open { open_values } else { closed_values };
5047    AnimationMachine::new(
5048        vec![
5049            AnimationState::new("closed", closed_values),
5050            AnimationState::new("open", open_values),
5051        ],
5052        vec![
5053            AnimationTransition::when(
5054                "closed",
5055                "open",
5056                AnimationCondition::bool(ANIMATION_INPUT_OPEN, true),
5057                0.18,
5058            ),
5059            AnimationTransition::when(
5060                "open",
5061                "closed",
5062                AnimationCondition::bool(ANIMATION_INPUT_OPEN, false),
5063                0.14,
5064            ),
5065        ],
5066        "closed",
5067    )
5068    .unwrap_or_else(|_| AnimationMachine::single_state("closed", fallback_values))
5069    .with_bool_input(ANIMATION_INPUT_OPEN, open)
5070}
5071
5072fn animation_interaction_machine() -> AnimationMachine {
5073    let rest_values = AnimatedValues::new(0.72, UiPoint::new(0.0, 0.0), 1.0);
5074    let right_values = AnimatedValues::new(1.0, UiPoint::new(0.0, 0.0), 1.0).with_morph(1.0);
5075    AnimationMachine::new(
5076        vec![
5077            AnimationState::new("rest", rest_values),
5078            AnimationState::new("right", right_values),
5079        ],
5080        Vec::new(),
5081        "rest",
5082    )
5083    .unwrap_or_else(|_| AnimationMachine::single_state("rest", rest_values))
5084    .with_number_input(ANIMATION_INPUT_POINTER_NORM_X, 0.0)
5085    .with_blend_binding(AnimationBlendBinding::new(
5086        ANIMATION_INPUT_POINTER_NORM_X,
5087        "rest",
5088        "right",
5089    ))
5090}
More examples
Hide additional examples
examples/animation_state_machine.rs (line 129)
128fn shape_machine(open: bool) -> AnimationMachine {
129    let closed = AnimatedValues::new(0.82, UiPoint::new(0.0, 0.0), 1.0).with_morph(0.0);
130    let open_values = AnimatedValues::new(1.0, UiPoint::new(160.0, 0.0), 1.08).with_morph(1.0);
131    AnimationMachine::new(
132        vec![
133            AnimationState::new("closed", closed),
134            AnimationState::new("open", open_values),
135        ],
136        vec![
137            AnimationTransition::when(
138                "closed",
139                "open",
140                AnimationCondition::bool(INPUT_OPEN, true),
141                0.24,
142            ),
143            AnimationTransition::when(
144                "open",
145                "closed",
146                AnimationCondition::bool(INPUT_OPEN, false),
147                0.18,
148            ),
149        ],
150        "closed",
151    )
152    .unwrap_or_else(|_| AnimationMachine::single_state("closed", closed))
153    .with_bool_input(INPUT_OPEN, open)
154    .with_number_input(INPUT_MORPH, if open { 1.0 } else { 0.0 })
155    .with_blend_binding(AnimationBlendBinding::new(INPUT_MORPH, "closed", "open"))
156}

Trait Implementations§

Source§

impl Clone for AnimatedValues

Source§

fn clone(&self) -> AnimatedValues

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AnimatedValues

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for AnimatedValues

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl PartialEq for AnimatedValues

Source§

fn eq(&self, other: &AnimatedValues) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Copy for AnimatedValues

Source§

impl StructuralPartialEq for AnimatedValues

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,