Skip to main content

ValidationMessage

Struct ValidationMessage 

Source
pub struct ValidationMessage {
    pub severity: ValidationSeverity,
    pub message: String,
}

Fields§

§severity: ValidationSeverity§message: String

Implementations§

Source§

impl ValidationMessage

Source

pub fn error(message: impl Into<String>) -> Self

Examples found in repository?
examples/showcase.rs (line 4707)
4652fn form_widgets(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
4653    let body = section(ui, parent, "forms", "Forms");
4654    let section = widgets::form_section(
4655        ui,
4656        body,
4657        "forms.profile",
4658        Some("Profile".to_string()),
4659        widgets::FormSectionOptions::default().with_layout(
4660            LayoutStyle::column()
4661                .with_width_percent(1.0)
4662                .with_padding(12.0)
4663                .with_gap(10.0),
4664        ),
4665    );
4666    let name = widgets::form_row(
4667        ui,
4668        section.root,
4669        "forms.profile.name",
4670        widgets::FormRowOptions::default(),
4671    );
4672    widgets::field_label(
4673        ui,
4674        name,
4675        "forms.profile.name.label",
4676        "Name",
4677        widgets::FieldLabelOptions::default().required(),
4678    );
4679    widgets::field_help_text(
4680        ui,
4681        name,
4682        "forms.profile.name.help",
4683        "Shown in window titles and project lists.",
4684        widgets::FieldHelpOptions::default(),
4685    );
4686    form_text_field(ui, name, "forms.profile.name.input", "Ada Lovelace");
4687
4688    let email = widgets::form_row(
4689        ui,
4690        section.root,
4691        "forms.profile.email",
4692        widgets::FormRowOptions::default()
4693            .required()
4694            .invalid("Use a complete email address"),
4695    );
4696    widgets::field_label(
4697        ui,
4698        email,
4699        "forms.profile.email.label",
4700        "Email",
4701        widgets::FieldLabelOptions::default().required(),
4702    );
4703    widgets::field_validation_message(
4704        ui,
4705        email,
4706        "forms.profile.email.validation",
4707        ValidationMessage::error("Use a complete email address"),
4708        widgets::ValidationMessageOptions::default(),
4709    );
4710    form_text_field(ui, email, "forms.profile.email.input", "ada@");
4711
4712    let role = widgets::form_row(
4713        ui,
4714        section.root,
4715        "forms.profile.role",
4716        widgets::FormRowOptions::default(),
4717    );
4718    widgets::field_label(
4719        ui,
4720        role,
4721        "forms.profile.role.label",
4722        "Role",
4723        widgets::FieldLabelOptions::default(),
4724    );
4725    widgets::field_help_text(
4726        ui,
4727        role,
4728        "forms.profile.role.help",
4729        "Form rows compose labels, controls, help, and validation text.",
4730        widgets::FieldHelpOptions::default(),
4731    );
4732    form_text_field(ui, role, "forms.profile.role.input", "Maintainer");
4733
4734    widgets::form_error_summary(
4735        ui,
4736        section.root,
4737        "forms.profile.errors",
4738        &state.form,
4739        widgets::FormErrorSummaryOptions::default(),
4740    );
4741    widgets::form_action_buttons(
4742        ui,
4743        section.root,
4744        "forms.profile.actions",
4745        &state.form,
4746        widgets::FormActionButtonsOptions::default()
4747            .include_reset(true)
4748            .with_action_prefix("forms.profile"),
4749    );
4750    widgets::label(
4751        ui,
4752        section.root,
4753        "forms.profile.status",
4754        format!("Status: {}", state.form_status),
4755        text(11.0, color(154, 166, 184)),
4756        LayoutStyle::new().with_width_percent(1.0),
4757    );
4758}
4759
4760fn overlay_widgets(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
4761    let body = section(ui, parent, "overlays", "Overlays");
4762    let header = widgets::collapsing_header(
4763        ui,
4764        body,
4765        "overlays.collapsing",
4766        "Collapsing header",
4767        widgets::CollapsingHeaderOptions::default()
4768            .expanded(state.overlay_expanded)
4769            .with_toggle_action("overlays.collapsing.toggle"),
4770    );
4771    if let Some(panel) = header.body {
4772        widgets::label(
4773            ui,
4774            panel,
4775            "overlays.collapsing.body",
4776            "Expanded content lives under the header.",
4777            text(12.0, color(196, 210, 230)),
4778            LayoutStyle::new().with_width_percent(1.0),
4779        );
4780    }
4781
4782    let controls = row(ui, body, "overlays.controls", 8.0);
4783    button(
4784        ui,
4785        controls,
4786        "overlays.popup.toggle",
4787        if state.overlay_popup_open {
4788            "Close popup"
4789        } else {
4790            "Open popup"
4791        },
4792        "overlays.popup.toggle",
4793        button_visual(48, 112, 184),
4794    );
4795    button(
4796        ui,
4797        controls,
4798        "overlays.modal.open",
4799        "Open modal",
4800        "overlays.modal.open",
4801        button_visual(58, 78, 96),
4802    );
4803
4804    let tooltip = TooltipContent::new("Tooltip")
4805        .body("Tooltip boxes are overlay surfaces with title, body, and shortcut text.")
4806        .shortcut_label("Ctrl+K");
4807    let mut tooltip_options = widgets::TooltipBoxOptions::default()
4808        .with_layout(
4809            LayoutStyle::column()
4810                .with_width(280.0)
4811                .with_padding(8.0)
4812                .with_gap(4.0),
4813        )
4814        .with_animation(None);
4815    tooltip_options.layer = UiLayer::AppContent;
4816    tooltip_options.z_index = 0;
4817    widgets::tooltip_box(ui, body, "overlays.tooltip", tooltip, tooltip_options);
4818
4819    if state.overlay_popup_open {
4820        let popup = widgets::popup_panel(
4821            ui,
4822            parent,
4823            "overlays.popup_panel",
4824            UiRect::new(0.0, 20.0, 160.0, 96.0),
4825            widgets::PopupOptions {
4826                z_index: 20,
4827                accessibility: Some(
4828                    AccessibilityMeta::new(AccessibilityRole::Dialog).label("Popup"),
4829                ),
4830                ..Default::default()
4831            },
4832        );
4833        let popup_body = ui.add_child(
4834            popup,
4835            UiNode::container(
4836                "overlays.popup_panel.body",
4837                LayoutStyle::column()
4838                    .with_width_percent(1.0)
4839                    .with_height_percent(1.0)
4840                    .with_padding(10.0)
4841                    .with_gap(6.0),
4842            ),
4843        );
4844        let popup_header = row(ui, popup_body, "overlays.popup_panel.header", 8.0);
4845        widgets::label(
4846            ui,
4847            popup_header,
4848            "overlays.popup_panel.label",
4849            "Popup panel",
4850            text(12.0, color(220, 228, 238)),
4851            LayoutStyle::new().with_width_percent(1.0),
4852        );
4853        let mut close = widgets::ButtonOptions::new(LayoutStyle::size(26.0, 22.0))
4854            .with_action("overlays.popup.close");
4855        close.visual = UiVisual::panel(color(28, 34, 43), None, 3.0);
4856        close.hovered_visual = Some(button_visual(54, 70, 92));
4857        close.text_style = text(12.0, color(220, 228, 238));
4858        widgets::button(ui, popup_header, "overlays.popup_panel.close", "x", close);
4859        widgets::label(
4860            ui,
4861            popup_body,
4862            "overlays.popup_panel.body_text",
4863            "Popup content is conditionally rendered.",
4864            text(11.0, color(196, 210, 230)),
4865            LayoutStyle::new().with_width_percent(1.0),
4866        );
4867    }
4868
4869    if state.overlay_modal_open {
4870        let modal = widgets::modal_dialog(
4871            ui,
4872            body,
4873            "overlays.modal",
4874            "Modal dialog",
4875            widgets::ModalDialogOptions::default()
4876                .with_size(320.0, 180.0)
4877                .with_close_action("overlays.modal.close")
4878                .with_dismissal(widgets::DialogDismissal::STANDARD)
4879                .with_focus_restore(FocusRestoreTarget::Previous)
4880                .modeless(),
4881        );
4882        widgets::label(
4883            ui,
4884            modal.body,
4885            "overlays.modal.body.text",
4886            "Dialog body",
4887            text(12.0, color(220, 228, 238)),
4888            LayoutStyle::new().with_width_percent(1.0),
4889        );
4890    }
4891}
4892
4893fn drag_drop_widgets(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
4894    let body = section(ui, parent, "drag_drop", "Drag and drop");
4895    widgets::dnd_drag_source(
4896        ui,
4897        body,
4898        "drag_drop.text_source",
4899        "Drag text payload",
4900        DragPayload::text("Operad payload"),
4901        widgets::DragSourceOptions::default()
4902            .with_kind(DragDropSurfaceKind::ListRow)
4903            .with_action("drag_drop.text_source")
4904            .with_accessibility_hint("Start a text drag operation"),
4905    );
4906
4907    let accepted_options = widgets::DropZoneOptions::default()
4908        .with_kind(DragDropSurfaceKind::EditorSurface)
4909        .with_accepted_payload(DropPayloadFilter::empty().text())
4910        .with_action("drag_drop.accept_text")
4911        .with_accessibility_hint("Accepts text payloads");
4912    let accepted = widgets::dnd_drop_zone(
4913        ui,
4914        body,
4915        "drag_drop.accept_text",
4916        "Drop text here",
4917        accepted_options.clone(),
4918    );
4919    widgets::dnd_apply_drop_zone_preview(
4920        ui,
4921        accepted.root,
4922        &accepted_options,
4923        widgets::DropZonePreviewState::Accepted,
4924    );
4925
4926    let rejected_options = widgets::DropZoneOptions::default()
4927        .with_layout(
4928            LayoutStyle::column()
4929                .with_width(240.0)
4930                .with_height(82.0)
4931                .with_padding(12.0),
4932        )
4933        .with_kind(DragDropSurfaceKind::Asset)
4934        .with_accepted_payload(DropPayloadFilter::empty().files())
4935        .with_action("drag_drop.files_only");
4936    let rejected = widgets::dnd_drop_zone(
4937        ui,
4938        body,
4939        "drag_drop.files_only",
4940        "Files only",
4941        rejected_options.clone(),
4942    );
4943    widgets::dnd_apply_drop_zone_preview(
4944        ui,
4945        rejected.root,
4946        &rejected_options,
4947        widgets::DropZonePreviewState::Rejected,
4948    );
4949    widgets::label(
4950        ui,
4951        body,
4952        "drag_drop.status",
4953        format!("Status: {}", state.drag_drop_status),
4954        text(11.0, color(154, 166, 184)),
4955        LayoutStyle::new().with_width_percent(1.0),
4956    );
4957}
4958
4959fn media_widgets(ui: &mut UiDocument, parent: UiNodeId) {
4960    let body = section(ui, parent, "media", "Media");
4961    let icons = row(ui, body, "media.icons", 10.0);
4962    widgets::image(
4963        ui,
4964        icons,
4965        "media.image.play",
4966        icon_image(BuiltInIcon::Play),
4967        widgets::ImageOptions::default()
4968            .with_layout(LayoutStyle::size(42.0, 42.0))
4969            .with_accessibility_label("Play icon"),
4970    );
4971    widgets::image(
4972        ui,
4973        icons,
4974        "media.image.warning",
4975        ImageContent::new(BuiltInIcon::Warning.key()).tinted(color(232, 186, 88)),
4976        widgets::ImageOptions::default()
4977            .with_layout(LayoutStyle::size(42.0, 42.0))
4978            .with_accessibility_label("Warning icon"),
4979    );
4980    widgets::image(
4981        ui,
4982        icons,
4983        "media.image.info",
4984        ImageContent::new(BuiltInIcon::Info.key()).tinted(color(118, 183, 255)),
4985        widgets::ImageOptions::default()
4986            .with_layout(LayoutStyle::size(42.0, 42.0))
4987            .with_accessibility_label("Info icon"),
4988    );
4989    widgets::label(
4990        ui,
4991        body,
4992        "media.image.note",
4993        "Image widgets reference stable resource keys; the host resolves them to textures or vector assets.",
4994        text(12.0, color(166, 176, 190)),
4995        LayoutStyle::new().with_width_percent(1.0),
4996    );
4997}
4998
4999fn timeline_ruler(ui: &mut UiDocument, parent: UiNodeId) {
5000    let mut layout = LayoutStyle::column()
5001        .with_width_percent(1.0)
5002        .with_height(40.0)
5003        .with_flex_shrink(0.0);
5004    layout.as_taffy_style_mut().min_size.width = operad::length(0.0);
5005    layout.as_taffy_style_mut().min_size.height = operad::length(0.0);
5006    let body = widgets::scroll_area(ui, parent, "timeline", ScrollAxes::BOTH, layout);
5007    widgets::timeline_ruler(
5008        ui,
5009        body,
5010        "timeline.ruler",
5011        widgets::RulerSpec {
5012            range: widgets::TimelineRange::new(0.0, 12.0),
5013            width: 600.0,
5014            major_step: 2.0,
5015            minor_step: 0.5,
5016            label_every: 1,
5017        },
5018        widgets::TimelineRulerOptions::default(),
5019    );
5020}
5021
5022fn toast_controls(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
5023    let body = section(ui, parent, "toasts", "Toasts");
5024    let controls = row(ui, body, "toasts.controls", 10.0);
5025    button(
5026        ui,
5027        controls,
5028        "toasts.show",
5029        "Show toast",
5030        "toast.show",
5031        button_visual(48, 112, 184),
5032    );
5033    button(
5034        ui,
5035        controls,
5036        "toasts.hide",
5037        "Hide",
5038        "toast.hide",
5039        button_visual(58, 78, 96),
5040    );
5041    widgets::label(
5042        ui,
5043        body,
5044        "toasts.status",
5045        if state.toast_visible {
5046            "Toast overlay is visible."
5047        } else {
5048            "Toast overlay is hidden."
5049        },
5050        text(12.0, color(196, 210, 230)),
5051        LayoutStyle::new().with_width_percent(1.0),
5052    );
5053    widgets::label(
5054        ui,
5055        body,
5056        "toasts.action_status",
5057        format!("Action: {}", state.toast_action_status),
5058        text(12.0, color(154, 166, 184)),
5059        LayoutStyle::new().with_width_percent(1.0),
5060    );
5061}
5062
5063fn popup_controls(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
5064    let body = section(ui, parent, "popup_panel", "Popup panel");
5065    let controls = row(ui, body, "popup_panel.controls", 8.0);
5066    button(
5067        ui,
5068        controls,
5069        "popup_panel.toggle",
5070        if state.popup_open {
5071            "Close popup"
5072        } else {
5073            "Open popup"
5074        },
5075        "popup.toggle",
5076        button_visual(48, 112, 184),
5077    );
5078    if state.popup_open {
5079        let mut close =
5080            widgets::ButtonOptions::new(LayoutStyle::size(30.0, 30.0)).with_action("popup.close");
5081        close.visual = UiVisual::panel(color(28, 34, 43), None, 3.0);
5082        close.hovered_visual = Some(button_visual(54, 70, 92));
5083        close.text_style = text(13.0, color(220, 228, 238));
5084        widgets::button(ui, controls, "popup_panel.inline_close", "x", close);
5085    }
5086    widgets::label(
5087        ui,
5088        body,
5089        "popup_panel.status",
5090        if state.popup_open {
5091            "Popup overlay is open."
5092        } else {
5093            "Popup overlay is closed."
5094        },
5095        text(12.0, color(196, 210, 230)),
5096        LayoutStyle::new().with_width_percent(1.0),
5097    );
5098    if state.popup_open {
5099        let panel = widgets::popup_panel(
5100            ui,
5101            parent,
5102            "popup_panel.inline_preview",
5103            UiRect::new(0.0, 20.0, 160.0, 104.0),
5104            widgets::PopupOptions {
5105                z_index: 4,
5106                accessibility: Some(
5107                    AccessibilityMeta::new(AccessibilityRole::Dialog).label("Popup preview"),
5108                ),
5109                ..Default::default()
5110            },
5111        );
5112        let content = ui.add_child(
5113            panel,
5114            UiNode::container(
5115                "popup_panel.inline_preview.body",
5116                LayoutStyle::column()
5117                    .with_width_percent(1.0)
5118                    .with_height_percent(1.0)
5119                    .with_padding(10.0)
5120                    .with_gap(8.0),
5121            ),
5122        );
5123        let header = row(ui, content, "popup_panel.inline_preview.header", 8.0);
5124        widgets::label(
5125            ui,
5126            header,
5127            "popup_panel.inline_preview.title",
5128            "Popup panel",
5129            text(12.0, color(226, 234, 246)),
5130            LayoutStyle::new().with_width_percent(1.0),
5131        );
5132        let mut close =
5133            widgets::ButtonOptions::new(LayoutStyle::size(26.0, 22.0)).with_action("popup.close");
5134        close.visual = UiVisual::panel(color(28, 34, 43), None, 3.0);
5135        close.hovered_visual = Some(button_visual(54, 70, 92));
5136        close.text_style = text(12.0, color(220, 228, 238));
5137        widgets::button(ui, header, "popup_panel.inline_preview.close", "x", close);
5138        widgets::label(
5139            ui,
5140            content,
5141            "popup_panel.inline_preview.text",
5142            "Overlay content",
5143            text(11.0, color(196, 210, 230)),
5144            LayoutStyle::new().with_width_percent(1.0),
5145        );
5146        widgets::spacer(
5147            ui,
5148            body,
5149            "popup_panel.inline_preview.space",
5150            LayoutStyle::new()
5151                .with_width_percent(1.0)
5152                .with_height(112.0)
5153                .with_flex_shrink(0.0),
5154        );
5155    }
5156}
5157
5158fn styling_widgets(ui: &mut UiDocument, parent: UiNodeId, state: &ShowcaseState) {
5159    let body = section(ui, parent, "styling", "Styling");
5160    let grid = ui.add_child(
5161        body,
5162        UiNode::container(
5163            "styling.grid",
5164            LayoutStyle::row()
5165                .with_width_percent(1.0)
5166                .with_height_percent(1.0)
5167                .gap(16.0),
5168        ),
5169    );
5170    let controls = ui.add_child(
5171        grid,
5172        UiNode::container(
5173            "styling.controls",
5174            LayoutStyle::column()
5175                .with_width(330.0)
5176                .with_height_percent(1.0)
5177                .with_flex_shrink(0.0)
5178                .gap(6.0),
5179        ),
5180    );
5181    style_checkbox(
5182        ui,
5183        controls,
5184        "styling.inner_same",
5185        "Inner margin same",
5186        state.styling.inner_same,
5187    );
5188    style_slider(
5189        ui,
5190        controls,
5191        "styling.inner",
5192        "Inner left",
5193        state.styling.inner_margin,
5194        0.0..32.0,
5195    );
5196    if !state.styling.inner_same {
5197        style_slider(
5198            ui,
5199            controls,
5200            "styling.inner_right",
5201            "Inner right",
5202            state.styling.inner_right,
5203            0.0..32.0,
5204        );
5205        style_slider(
5206            ui,
5207            controls,
5208            "styling.inner_top",
5209            "Inner top",
5210            state.styling.inner_top,
5211            0.0..32.0,
5212        );
5213        style_slider(
5214            ui,
5215            controls,
5216            "styling.inner_bottom",
5217            "Inner bottom",
5218            state.styling.inner_bottom,
5219            0.0..32.0,
5220        );
5221    }
5222    style_checkbox(
5223        ui,
5224        controls,
5225        "styling.outer_same",
5226        "Outer margin same",
5227        state.styling.outer_same,
5228    );
5229    style_slider(
5230        ui,
5231        controls,
5232        "styling.outer",
5233        "Outer left",
5234        state.styling.outer_margin,
5235        0.0..40.0,
5236    );
5237    if !state.styling.outer_same {
5238        style_slider(
5239            ui,
5240            controls,
5241            "styling.outer_right",
5242            "Outer right",
5243            state.styling.outer_right,
5244            0.0..40.0,
5245        );
5246        style_slider(
5247            ui,
5248            controls,
5249            "styling.outer_top",
5250            "Outer top",
5251            state.styling.outer_top,
5252            0.0..40.0,
5253        );
5254        style_slider(
5255            ui,
5256            controls,
5257            "styling.outer_bottom",
5258            "Outer bottom",
5259            state.styling.outer_bottom,
5260            0.0..40.0,
5261        );
5262    }
5263    style_checkbox(
5264        ui,
5265        controls,
5266        "styling.radius_same",
5267        "Corner radius same",
5268        state.styling.radius_same,
5269    );
5270    style_slider(
5271        ui,
5272        controls,
5273        "styling.radius",
5274        "Radius NW",
5275        state.styling.corner_radius,
5276        0.0..28.0,
5277    );
5278    if !state.styling.radius_same {
5279        style_slider(
5280            ui,
5281            controls,
5282            "styling.radius_ne",
5283            "Radius NE",
5284            state.styling.corner_ne,
5285            0.0..28.0,
5286        );
5287        style_slider(
5288            ui,
5289            controls,
5290            "styling.radius_sw",
5291            "Radius SW",
5292            state.styling.corner_sw,
5293            0.0..28.0,
5294        );
5295        style_slider(
5296            ui,
5297            controls,
5298            "styling.radius_se",
5299            "Radius SE",
5300            state.styling.corner_se,
5301            0.0..28.0,
5302        );
5303    }
5304    style_slider(
5305        ui,
5306        controls,
5307        "styling.shadow_x",
5308        "Shadow x",
5309        state.styling.shadow_x,
5310        -24.0..24.0,
5311    );
5312    style_slider(
5313        ui,
5314        controls,
5315        "styling.shadow_y",
5316        "Shadow y",
5317        state.styling.shadow_y,
5318        -24.0..24.0,
5319    );
5320    style_slider(
5321        ui,
5322        controls,
5323        "styling.shadow",
5324        "Shadow blur",
5325        state.styling.shadow_blur,
5326        0.0..32.0,
5327    );
5328    style_slider(
5329        ui,
5330        controls,
5331        "styling.shadow_spread",
5332        "Shadow spread",
5333        state.styling.shadow_spread,
5334        0.0..16.0,
5335    );
5336    style_slider(
5337        ui,
5338        controls,
5339        "styling.shadow_alpha",
5340        "Shadow color",
5341        state.styling.shadow_alpha,
5342        0.0..220.0,
5343    );
5344    style_slider(
5345        ui,
5346        controls,
5347        "styling.fill",
5348        "Fill color",
5349        state.styling.fill_tint,
5350        0.0..1.0,
5351    );
5352    style_slider(
5353        ui,
5354        controls,
5355        "styling.stroke_color",
5356        "Stroke color",
5357        state.styling.stroke_tint,
5358        0.0..1.0,
5359    );
5360    style_slider(
5361        ui,
5362        controls,
5363        "styling.stroke",
5364        "Stroke",
5365        state.styling.stroke_width,
5366        0.0..4.0,
5367    );
5368
5369    let preview = ui.add_child(
5370        grid,
5371        UiNode::container(
5372            "styling.preview",
5373            LayoutStyle::column()
5374                .with_width_percent(1.0)
5375                .with_height_percent(1.0)
5376                .padding(8.0),
5377        )
5378        .with_visual(UiVisual::panel(
5379            color(17, 20, 25),
5380            Some(StrokeStyle::new(color(56, 66, 82), 1.0)),
5381            4.0,
5382        )),
5383    );
5384    style_preview(ui, preview, state.styling);
5385}
5386
5387fn style_slider(
5388    ui: &mut UiDocument,
5389    parent: UiNodeId,
5390    name: &'static str,
5391    label: &'static str,
5392    value: f32,
5393    range: std::ops::Range<f32>,
5394) {
5395    let row = row(ui, parent, format!("{name}.row"), 8.0);
5396    widgets::label(
5397        ui,
5398        row,
5399        format!("{name}.label"),
5400        label,
5401        text(12.0, color(166, 176, 190)),
5402        LayoutStyle::new().with_width(118.0),
5403    );
5404    widgets::label(
5405        ui,
5406        row,
5407        format!("{name}.value"),
5408        if range.end <= 1.0 {
5409            format!("{value:.2}")
5410        } else {
5411            format!("{value:.0}")
5412        },
5413        text(12.0, color(226, 232, 242)),
5414        LayoutStyle::new().with_width(42.0),
5415    );
5416    let mut options = widgets::SliderOptions::default()
5417        .with_layout(
5418            LayoutStyle::new()
5419                .with_width(112.0)
5420                .with_height(20.0)
5421                .with_flex_shrink(0.0),
5422        )
5423        .with_value_edit_action(name);
5424    options.fill_color = color(120, 170, 230);
5425    widgets::slider(
5426        ui,
5427        row,
5428        format!("{name}.slider"),
5429        ((value - range.start) / (range.end - range.start).max(f32::EPSILON)).clamp(0.0, 1.0),
5430        0.0..1.0,
5431        options,
5432    );
5433}
5434
5435fn style_checkbox(
5436    ui: &mut UiDocument,
5437    parent: UiNodeId,
5438    name: &'static str,
5439    label: &'static str,
5440    checked: bool,
5441) {
5442    let mut options = widgets::CheckboxOptions::default().with_action(name);
5443    options.layout = LayoutStyle::new().with_width_percent(1.0).with_height(22.0);
5444    options.text_style = text(12.0, color(220, 228, 238));
5445    widgets::checkbox(ui, parent, name, label, checked, options);
5446}
5447
5448fn style_preview(ui: &mut UiDocument, parent: UiNodeId, styling: StylingState) {
5449    let outer = styling.outer_edges();
5450    let inner = styling.inner_edges();
5451    let frame = UiRect::new(
5452        22.0 + outer[0],
5453        28.0 + outer[2],
5454        108.0 + inner[0] + inner[1],
5455        40.0 + inner[2] + inner[3],
5456    );
5457    let text_rect = UiRect::new(
5458        frame.x + inner[0],
5459        frame.y + inner[2],
5460        (frame.width - inner[0] - inner[1]).max(1.0),
5461        (frame.height - inner[2] - inner[3]).max(1.0),
5462    );
5463    ui.add_child(
5464        parent,
5465        UiNode::scene(
5466            "styling.preview.scene",
5467            vec![
5468                ScenePrimitive::Rect(
5469                    PaintRect::solid(frame, styling.fill_color())
5470                        .stroke(AlignedStroke::inside(StrokeStyle::new(
5471                            styling.stroke_color(),
5472                            styling.stroke_width,
5473                        )))
5474                        .corner_radii(styling.radii())
5475                        .effect(PaintEffect::shadow(
5476                            styling.shadow_color(),
5477                            UiPoint::new(styling.shadow_x, styling.shadow_y),
5478                            styling.shadow_blur,
5479                            styling.shadow_spread,
5480                        )),
5481                ),
5482                ScenePrimitive::Text(
5483                    PaintText::new("Content", text_rect, text(13.0, color(255, 255, 255)))
5484                        .horizontal_align(TextHorizontalAlign::Center)
5485                        .vertical_align(TextVerticalAlign::Center)
5486                        .multiline(false),
5487                ),
5488            ],
5489            LayoutStyle::new()
5490                .with_width_percent(1.0)
5491                .with_height(180.0)
5492                .with_flex_shrink(0.0),
5493        ),
5494    );
5495}
5496
5497fn slider_options(state: &ShowcaseState, width: f32) -> widgets::SliderOptions {
5498    let mut options = widgets::SliderOptions::default().with_layout(
5499        LayoutStyle::new()
5500            .with_width(width)
5501            .with_height(24.0)
5502            .with_flex_shrink(0.0),
5503    );
5504    options.fill_color = if state.slider_trailing_color {
5505        state.slider_trailing_picker.value
5506    } else {
5507        color(42, 49, 58)
5508    };
5509    options.thumb_shape = match state.slider_thumb_shape {
5510        SliderThumbChoice::Circle => widgets::SliderThumbShape::Circle,
5511        SliderThumbChoice::Square => widgets::SliderThumbShape::Square,
5512        SliderThumbChoice::Rectangle => widgets::SliderThumbShape::Rectangle,
5513    };
5514    options
5515}
5516
5517fn slider_number_input(
5518    ui: &mut UiDocument,
5519    parent: UiNodeId,
5520    name: &'static str,
5521    input: &TextInputState,
5522    focused: FocusedTextInput,
5523    state: &ShowcaseState,
5524    width: f32,
5525) {
5526    let mut options = TextInputOptions::default();
5527    options.layout = LayoutStyle::new().with_width(width).with_height(28.0);
5528    options.text_style = text(12.0, color(230, 236, 246));
5529    options.placeholder_style = text(12.0, color(144, 156, 174));
5530    options.edit_action = Some(format!("{name}.edit").into());
5531    options.focused = state.focused_text == Some(focused);
5532    options.caret_visible = caret_visible(state.caret_phase);
5533    widgets::text_input(ui, parent, name, input, options);
5534}
5535
5536fn form_text_field(ui: &mut UiDocument, parent: UiNodeId, name: &'static str, value: &'static str) {
5537    let mut options = TextInputOptions::default();
5538    options.layout = LayoutStyle::new().with_width_percent(1.0).with_height(30.0);
5539    options.text_style = text(12.0, color(230, 236, 246));
5540    options.read_only = true;
5541    widgets::text_input(ui, parent, name, &TextInputState::new(value), options);
5542}
5543
5544fn slider_checkbox(
5545    ui: &mut UiDocument,
5546    parent: UiNodeId,
5547    name: &'static str,
5548    label: &'static str,
5549    checked: bool,
5550) {
5551    slider_checkbox_with_layout(
5552        ui,
5553        parent,
5554        name,
5555        label,
5556        checked,
5557        LayoutStyle::new().with_width_percent(1.0).with_height(30.0),
5558    );
5559}
5560
5561fn slider_checkbox_with_layout(
5562    ui: &mut UiDocument,
5563    parent: UiNodeId,
5564    name: &'static str,
5565    label: &'static str,
5566    checked: bool,
5567    layout: LayoutStyle,
5568) {
5569    let mut options = widgets::CheckboxOptions::default().with_action(name);
5570    options.layout = layout;
5571    options.text_style = text(12.0, color(220, 228, 238));
5572    widgets::checkbox(ui, parent, name, label, checked, options);
5573}
5574
5575fn choice_button(
5576    ui: &mut UiDocument,
5577    parent: UiNodeId,
5578    name: &'static str,
5579    label: &'static str,
5580    selected: bool,
5581) {
5582    let mut options =
5583        widgets::ButtonOptions::new(LayoutStyle::new().with_width(78.0).with_height(28.0))
5584            .with_action(name);
5585    options.visual = if selected {
5586        button_visual(48, 112, 184)
5587    } else {
5588        button_visual(38, 46, 58)
5589    };
5590    options.hovered_visual = Some(button_visual(65, 86, 106));
5591    options.pressed_visual = Some(button_visual(34, 54, 84));
5592    options.text_style = text(12.0, color(238, 244, 252));
5593    widgets::button(ui, parent, name, label, options);
5594}
5595
5596fn divider(ui: &mut UiDocument, parent: UiNodeId, name: &'static str) {
5597    ui.add_child(
5598        parent,
5599        UiNode::container(
5600            name,
5601            LayoutStyle::new()
5602                .with_width_percent(1.0)
5603                .with_height(1.0)
5604                .with_flex_shrink(0.0),
5605        )
5606        .with_visual(UiVisual::panel(color(48, 58, 72), None, 0.0)),
5607    );
5608}
5609
5610fn canvas(ui: &mut UiDocument, parent: UiNodeId) {
5611    let body = section(ui, parent, "canvas", "Canvas");
5612    let mut options = widgets::CanvasOptions::default()
5613        .with_accessibility_label("Shader canvas")
5614        .with_action("canvas.rotate")
5615        .with_aspect_ratio(16.0 / 9.0);
5616    options.layout = LayoutStyle::new()
5617        .with_width_percent(1.0)
5618        .with_height_percent(1.0)
5619        .with_flex_grow(1.0)
5620        .with_flex_shrink(1.0);
5621    options.visual = UiVisual::panel(
5622        color(18, 22, 28),
5623        Some(StrokeStyle::new(color(58, 68, 84), 1.0)),
5624        4.0,
5625    );
5626    widgets::canvas(
5627        ui,
5628        body,
5629        "canvas.shader",
5630        CanvasContent::new("canvas.shader").gpu_context(),
5631        options,
5632    );
5633}
5634
5635fn render_showcase_canvas(
5636    state: &mut ShowcaseState,
5637    context: NativeWgpuCanvasRenderContext<'_>,
5638) -> Result<CanvasRenderOutput, RenderError> {
5639    let size = context.surface_size();
5640    if state.cube.needs_render(size) {
5641        render_showcase_canvas_surface(state.cube, &context.surface)?;
5642        state.cube.mark_rendered(size);
5643    }
5644    Ok(CanvasRenderOutput::new())
5645}
5646
5647fn render_showcase_canvas_surface(
5648    cube: CanvasCubeState,
5649    surface: &WgpuCanvasContext<'_>,
5650) -> Result<(), RenderError> {
5651    let uniforms = canvas_cube_uniform_bytes(cube);
5652    surface.render_pass(
5653        WgpuCanvasRenderPass::wgsl(include_str!("shaders/showcase_canvas.wgsl"))
5654            .label(Some("showcase.canvas"))
5655            .uniform_bytes(&uniforms[..])
5656            .clear_color(Some(color(18, 22, 28))),
5657    )
5658}
5659
5660fn canvas_cube_uniform_bytes(cube: CanvasCubeState) -> [u8; 16] {
5661    let mut bytes = [0_u8; 16];
5662    bytes[0..4].copy_from_slice(&cube.yaw.to_ne_bytes());
5663    bytes[4..8].copy_from_slice(&cube.pitch.to_ne_bytes());
5664    bytes
5665}
5666
5667fn section(
5668    ui: &mut UiDocument,
5669    parent: UiNodeId,
5670    name: impl Into<String>,
5671    _title: impl Into<String>,
5672) -> UiNodeId {
5673    let name = name.into();
5674    let mut layout = LayoutStyle::column()
5675        .with_width_percent(1.0)
5676        .with_height_percent(1.0)
5677        .with_flex_grow(1.0)
5678        .gap(10.0);
5679    layout.as_taffy_style_mut().min_size.width = operad::length(0.0);
5680    layout.as_taffy_style_mut().min_size.height = operad::length(0.0);
5681    widgets::scroll_area(
5682        ui,
5683        parent,
5684        format!("{name}.section_scroll"),
5685        ScrollAxes::VERTICAL,
5686        layout,
5687    )
5688}
5689
5690fn row(ui: &mut UiDocument, parent: UiNodeId, name: impl Into<String>, gap: f32) -> UiNodeId {
5691    ui.add_child(
5692        parent,
5693        UiNode::container(name, LayoutStyle::row().with_width_percent(1.0).gap(gap)),
5694    )
5695}
5696
5697fn wrapping_row(
5698    ui: &mut UiDocument,
5699    parent: UiNodeId,
5700    name: impl Into<String>,
5701    gap: f32,
5702) -> UiNodeId {
5703    let mut layout = LayoutStyle::row().with_width_percent(1.0).gap(gap);
5704    layout.as_taffy_style_mut().flex_wrap = LayoutFlexWrap::Wrap.to_taffy();
5705    ui.add_child(parent, UiNode::container(name, layout))
5706}
5707
5708fn egui_panel_contents(
5709    ui: &mut UiDocument,
5710    parent: UiNodeId,
5711    name: &'static str,
5712    title: &'static str,
5713    offset_y: f32,
5714) {
5715    let header = ui.add_child(
5716        parent,
5717        UiNode::container(
5718            format!("{name}.egui_header"),
5719            LayoutStyle::row()
5720                .with_width_percent(1.0)
5721                .with_height(28.0)
5722                .with_padding(6.0)
5723                .with_flex_shrink(0.0),
5724        )
5725        .with_visual(UiVisual::panel(
5726            color(21, 26, 34),
5727            Some(StrokeStyle::new(color(54, 65, 80), 1.0)),
5728            0.0,
5729        )),
5730    );
5731    widgets::label(
5732        ui,
5733        header,
5734        format!("{name}.egui_title"),
5735        title,
5736        text(12.0, color(226, 234, 246)),
5737        LayoutStyle::new().with_width_percent(1.0),
5738    );
5739    let scroll = widgets::scroll_area(
5740        ui,
5741        parent,
5742        format!("{name}.scroll_area"),
5743        ScrollAxes::VERTICAL,
5744        LayoutStyle::column()
5745            .with_width_percent(1.0)
5746            .with_height(0.0)
5747            .with_flex_grow(1.0)
5748            .with_padding(8.0)
5749            .with_gap(6.0),
5750    );
5751    ui.node_mut(scroll).action = Some(format!("{name}.scroll").into());
5752    if let Some(scroll_state) = ui.node_mut(scroll).scroll.as_mut() {
5753        scroll_state.offset.y = offset_y;
5754    }
5755    for (index, line) in lorem_lines().iter().take(8).enumerate() {
5756        widgets::label(
5757            ui,
5758            scroll,
5759            format!("{name}.egui_line.{index}"),
5760            *line,
5761            TextStyle {
5762                wrap: TextWrap::None,
5763                ..text(11.0, color(190, 202, 218))
5764            },
5765            LayoutStyle::new()
5766                .with_width_percent(1.0)
5767                .with_height(22.0)
5768                .with_flex_shrink(0.0),
5769        );
5770    }
5771}
5772
5773fn button(
5774    ui: &mut UiDocument,
5775    parent: UiNodeId,
5776    name: impl Into<String>,
5777    label: impl Into<String>,
5778    action: impl Into<String>,
5779    visual: UiVisual,
5780) -> UiNodeId {
5781    let mut options = widgets::ButtonOptions::new(LayoutStyle::new().with_height(32.0))
5782        .with_action(action.into());
5783    options.visual = visual;
5784    options.hovered_visual = Some(adjusted_button_visual(visual, 58));
5785    options.pressed_visual = Some(adjusted_button_visual(visual, -62));
5786    options.pressed_hovered_visual = Some(adjusted_button_visual(visual, 8));
5787    options.text_style = text(13.0, color(246, 249, 252));
5788    widgets::button(ui, parent, name, label, options)
5789}
5790
5791fn button_visual(r: u8, g: u8, b: u8) -> UiVisual {
5792    UiVisual::panel(
5793        color(r, g, b),
5794        Some(StrokeStyle::new(color(86, 102, 124), 1.0)),
5795        4.0,
5796    )
5797}
5798
5799fn color_square_button_options(action: &'static str) -> widgets::ColorButtonOptions {
5800    widgets::ColorButtonOptions::default()
5801        .with_layout(LayoutStyle::size(30.0, 30.0).with_flex_shrink(0.0))
5802        .with_swatch_size(UiSize::new(30.0, 30.0))
5803        .with_action(action)
5804        .show_label(false)
5805}
5806
5807fn color_value_button_options(action: &'static str, width: f32) -> widgets::ColorButtonOptions {
5808    widgets::ColorButtonOptions::default()
5809        .with_layout(
5810            LayoutStyle::new()
5811                .with_width(width)
5812                .with_height(30.0)
5813                .with_flex_shrink(0.0),
5814        )
5815        .with_action(action)
5816}
5817
5818fn icon_image(icon: BuiltInIcon) -> ImageContent {
5819    ImageContent::new(icon.key()).tinted(color(220, 228, 238))
5820}
5821
5822fn adjusted_button_visual(visual: UiVisual, delta: i16) -> UiVisual {
5823    UiVisual::panel(
5824        adjust_color(visual.fill, delta),
5825        visual.stroke.map(|stroke| StrokeStyle {
5826            color: adjust_color(stroke.color, delta / 2),
5827            width: stroke.width,
5828        }),
5829        visual.corner_radius,
5830    )
5831}
5832
5833fn adjust_color(color: ColorRgba, delta: i16) -> ColorRgba {
5834    let channel = |value: u8| -> u8 { (i16::from(value) + delta).clamp(0, u8::MAX as i16) as u8 };
5835    ColorRgba::new(
5836        channel(color.r),
5837        channel(color.g),
5838        channel(color.b),
5839        color.a,
5840    )
5841}
5842
5843fn select_options() -> Vec<widgets::SelectOption> {
5844    vec![
5845        widgets::SelectOption::new("compact", "Compact"),
5846        widgets::SelectOption::new("comfortable", "Comfortable"),
5847        widgets::SelectOption::new("spacious", "Spacious"),
5848        widgets::SelectOption::new("disabled", "Disabled").disabled(),
5849    ]
5850}
5851
5852fn label_locale_options() -> Vec<widgets::SelectOption> {
5853    vec![
5854        widgets::SelectOption::new("en-US", "English"),
5855        widgets::SelectOption::new("es-MX", "Español"),
5856        widgets::SelectOption::new("fr-FR", "Français"),
5857        widgets::SelectOption::new("de-DE", "Deutsch"),
5858        widgets::SelectOption::new("it-IT", "Italiano"),
5859        widgets::SelectOption::new("pt-BR", "Português"),
5860        widgets::SelectOption::new("nl-NL", "Nederlands"),
5861    ]
5862}
5863
5864fn localized_label(locale_id: &str) -> &'static str {
5865    match locale_id {
5866        "en-US" => "Interface language: English",
5867        "fr-FR" => "Langue de l'interface : français",
5868        "de-DE" => "Sprache der Oberfläche: Deutsch",
5869        "it-IT" => "Lingua dell'interfaccia: italiano",
5870        "pt-BR" => "Idioma da interface: português",
5871        "nl-NL" => "Interfacetaal: Nederlands",
5872        _ => "Idioma de interfaz: español de México",
5873    }
5874}
5875
5876fn lorem_lines() -> [&'static str; 8] {
5877    [
5878        "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
5879        "Integer vitae arcu at neque feugiat posuere.",
5880        "Suspendisse potenti. Praesent eget sem non mauris luctus.",
5881        "Curabitur blandit, justo non gravida tristique, mi nunc.",
5882        "Donec at nibh vel sapien facilisis feugiat.",
5883        "Aliquam erat volutpat. Nam porttitor sem at ligula.",
5884        "Vivamus dictum eros vitae tortor aliquet, in tempor urna.",
5885        "Sed finibus velit non lectus efficitur, sed tempor orci.",
5886    ]
5887}
5888
5889fn menu_bar_menus(autosave: bool, grid: bool) -> Vec<widgets::MenuBarMenu> {
5890    vec![
5891        widgets::MenuBarMenu::new("file", "File", menu_items(autosave)),
5892        widgets::MenuBarMenu::new(
5893            "edit",
5894            "Edit",
5895            vec![
5896                widgets::MenuItem::command("undo", "Undo").shortcut("Ctrl+Z"),
5897                widgets::MenuItem::command("redo", "Redo").shortcut("Ctrl+Shift+Z"),
5898            ],
5899        ),
5900        widgets::MenuBarMenu::new(
5901            "view",
5902            "View",
5903            vec![widgets::MenuItem::check("grid", "Grid", grid)],
5904        ),
5905    ]
5906}
5907
5908fn menu_items(autosave: bool) -> Vec<widgets::MenuItem> {
5909    vec![
5910        widgets::MenuItem::command("new", "New").shortcut("Ctrl+N"),
5911        widgets::MenuItem::command("open", "Open").shortcut("Ctrl+O"),
5912        widgets::MenuItem::separator(),
5913        widgets::MenuItem::check("autosave", "Autosave", autosave),
5914        widgets::MenuItem::submenu(
5915            "recent",
5916            "Recent",
5917            vec![
5918                widgets::MenuItem::command("recent.one", "demo.rs"),
5919                widgets::MenuItem::command("recent.two", "notes.md"),
5920            ],
5921        ),
5922        widgets::MenuItem::command("delete", "Delete").destructive(),
5923        widgets::MenuItem::command("disabled", "Disabled").disabled(),
5924    ]
5925}
5926
5927fn menu_item_top_offset(items: &[widgets::MenuItem], index: usize) -> f32 {
5928    items
5929        .iter()
5930        .take(index)
5931        .map(|item| menu_item_height(Some(item)))
5932        .sum()
5933}
5934
5935fn menu_item_height(item: Option<&widgets::MenuItem>) -> f32 {
5936    if item.is_some_and(widgets::MenuItem::is_separator) {
5937        8.0
5938    } else {
5939        28.0
5940    }
5941}
5942
5943fn command_palette_items() -> Vec<widgets::CommandPaletteItem> {
5944    vec![
5945        widgets::CommandPaletteItem::new("open", "Open")
5946            .subtitle("Open a document")
5947            .shortcut("Ctrl+O")
5948            .keyword("file"),
5949        widgets::CommandPaletteItem::new("save", "Save")
5950            .subtitle("Write current changes")
5951            .shortcut("Ctrl+S"),
5952        widgets::CommandPaletteItem::new("format", "Format document")
5953            .subtitle("Apply source formatting")
5954            .keyword("code"),
5955        widgets::CommandPaletteItem::new("rename", "Rename symbol")
5956            .subtitle("Change every reference")
5957            .shortcut("F2"),
5958        widgets::CommandPaletteItem::new("toggle_sidebar", "Toggle sidebar")
5959            .subtitle("Show or hide the widget panel")
5960            .shortcut("Ctrl+B"),
5961        widgets::CommandPaletteItem::new("run", "Run current example")
5962            .subtitle("Launch showcase")
5963            .shortcut("Ctrl+R"),
5964        widgets::CommandPaletteItem::new("focus_canvas", "Focus canvas")
5965            .subtitle("Move interaction to the canvas window"),
5966        widgets::CommandPaletteItem::new("reset_layout", "Reset window layout")
5967            .subtitle("Restore the default showcase positions"),
5968        widgets::CommandPaletteItem::new("disabled", "Disabled command").disabled(),
5969    ]
5970}
5971
5972fn table_columns() -> Vec<widgets::TableColumn> {
5973    vec![
5974        widgets::TableColumn {
5975            id: "name".to_string(),
5976            label: "Name".to_string(),
5977            width: 160.0,
5978        },
5979        widgets::TableColumn {
5980            id: "status".to_string(),
5981            label: "Status".to_string(),
5982            width: 140.0,
5983        },
5984        widgets::TableColumn {
5985            id: "value".to_string(),
5986            label: "Value".to_string(),
5987            width: 100.0,
5988        },
5989    ]
5990}
5991
5992fn tree_items() -> Vec<widgets::TreeItem> {
5993    vec![
5994        widgets::TreeItem::new("root", "Project").with_children(vec![
5995            widgets::TreeItem::new("src", "src").with_children(vec![
5996                widgets::TreeItem::new("lib", "lib.rs"),
5997                widgets::TreeItem::new("widgets", "widgets.rs"),
5998            ]),
5999            widgets::TreeItem::new("assets", "assets").with_children(vec![
6000                widgets::TreeItem::new("shader", "shader.wgsl"),
6001                widgets::TreeItem::new("logo", "logo.png"),
6002            ]),
6003            widgets::TreeItem::new("target", "target").disabled(),
6004        ]),
6005    ]
6006}
6007
6008fn parse_calendar_date(value: &str) -> Option<CalendarDate> {
6009    let mut parts = value.split('-');
6010    let year = parts.next()?.parse().ok()?;
6011    let month = parts.next()?.parse().ok()?;
6012    let day = parts.next()?.parse().ok()?;
6013    CalendarDate::new(year, month, day)
6014}
6015
6016fn parse_table_cell(value: &str) -> Option<widgets::DataTableCellIndex> {
6017    let mut parts = value.split('.');
6018    let row = parts.next()?.parse().ok()?;
6019    let column = parts.next()?.parse().ok()?;
6020    if parts.next().is_some() {
6021        return None;
6022    }
6023    Some(widgets::DataTableCellIndex::new(row, column))
6024}
6025
6026fn unit(value: f32) -> f32 {
6027    value.clamp(0.0, 1.0)
6028}
6029
6030fn smooth_loop(phase: f32, offset: f32) -> f32 {
6031    0.5 - ((phase + offset).cos() * 0.5)
6032}
6033
6034fn create_system_clipboard() -> Option<arboard::Clipboard> {
6035    arboard::Clipboard::new().ok()
6036}
6037
6038fn profile_form_state() -> FormState {
6039    let mut form = FormState::new("profile")
6040        .with_field("name", "Operad")
6041        .with_field("email", "invalid@example")
6042        .with_field("role", "Designer");
6043    form.update_field("email", "invalid@example").unwrap();
6044    let request = form.begin_form_validation();
6045    let _ = form.apply_form_validation(
6046        FormValidationResult::new(request.generation)
6047            .with_field_messages(
6048                "email",
6049                vec![ValidationMessage::error("Use a complete email address")],
6050            )
6051            .with_form_message(ValidationMessage::warning("Unsaved profile changes")),
6052    );
6053    form
6054}
Source

pub fn warning(message: impl Into<String>) -> Self

Examples found in repository?
examples/showcase.rs (line 6051)
6038fn profile_form_state() -> FormState {
6039    let mut form = FormState::new("profile")
6040        .with_field("name", "Operad")
6041        .with_field("email", "invalid@example")
6042        .with_field("role", "Designer");
6043    form.update_field("email", "invalid@example").unwrap();
6044    let request = form.begin_form_validation();
6045    let _ = form.apply_form_validation(
6046        FormValidationResult::new(request.generation)
6047            .with_field_messages(
6048                "email",
6049                vec![ValidationMessage::error("Use a complete email address")],
6050            )
6051            .with_form_message(ValidationMessage::warning("Unsaved profile changes")),
6052    );
6053    form
6054}
Source

pub fn info(message: impl Into<String>) -> Self

Trait Implementations§

Source§

impl Clone for ValidationMessage

Source§

fn clone(&self) -> ValidationMessage

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 ValidationMessage

Source§

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

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

impl PartialEq for ValidationMessage

Source§

fn eq(&self, other: &ValidationMessage) -> 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 Eq for ValidationMessage

Source§

impl StructuralPartialEq for ValidationMessage

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 + Sync + Send>

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<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
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,