cushy 0.4.0

A wgpu-powered graphical user interface (GUI) library with a reactive data model
Documentation
use std::process::exit;

use cushy::figures::units::Lp;
use cushy::value::{Dynamic, Source, Validations};
use cushy::widget::MakeWidget;
use cushy::widgets::input::{InputValue, MaskedString};
use cushy::widgets::layers::OverlayLayer;
use cushy::widgets::Expand;
use cushy::Run;

fn main() -> cushy::Result {
    let tooltips = OverlayLayer::default();
    let username = Dynamic::default();
    let password = Dynamic::default();
    let validations = Validations::default();

    let username_field = "Username"
        .align_left()
        .and(
            username
                .to_input()
                .placeholder("Username")
                .validation(validations.validate(&username, |u: &String| {
                    if u.is_empty() {
                        Err("usernames must contain at least one character")
                    } else {
                        Ok(())
                    }
                }))
                .hint("* required")
                .tooltip(
                    &tooltips,
                    "If you can't remember your username, that's because this is a demo.",
                ),
        )
        .into_rows();

    let password_field = "Password"
        .align_left()
        .and(
            password
                .to_input()
                .placeholder("Password")
                .validation(
                    validations.validate(&password, |u: &MaskedString| match u.len() {
                        0..=7 => Err("passwords must be at least 8 characters long"),
                        _ => Ok(()),
                    }),
                )
                .hint("* required, 8 characters min")
                .tooltip(&tooltips, "Passwords are always at least 8 bytes long."),
        )
        .into_rows();

    let buttons = "Cancel"
        .into_button()
        .on_click(|_| {
            eprintln!("Login cancelled");
            exit(0)
        })
        .into_escape()
        .tooltip(&tooltips, "This button quits the program")
        .and(Expand::empty())
        .and(
            "Log In"
                .into_button()
                .on_click(validations.when_valid(move |_| {
                    println!("Welcome, {}", username.get());
                    exit(0);
                }))
                .into_default(),
        )
        .into_columns();

    let ui = username_field
        .and(password_field)
        .and(buttons)
        .into_rows()
        .contain()
        .width(Lp::inches(3)..Lp::inches(6))
        .pad()
        .scroll()
        .centered();

    ui.and(tooltips).into_layers().run()
}