floem plattle 调色板 - jiemo2187/rust-crates GitHub Wiki

代码来源:floem color_pallete

代码来源:floem webgpu

字体:fonts

本地运行:cargo run 网页运行: trunk serve

格式化配置rustfmt.toml

# https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=
# cargo +nightly fmt
imports_granularity = 'Item'
reorder_imports = true
group_imports = 'StdExternalCrate'

依赖Cargo.toml

[package]
name = "floem-palette"
version = "0.1.0"
edition = "2021"

[dependencies]
floem = "0.2.0"
im = "15.1.0"
palette = "0.7.6"

[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.7"
console_log = "1.0.0"
wasm-bindgen = "0.2.95"
wasm-bindgen-futures = "0.4.45"
web-sys = { version = "0.3.72", features = ["Element", "Window", "Document"] }
wgpu = "23.0.0"

main.rs文件

use floem::peniko::Color;
use floem::prelude::Decorators;
use floem::prelude::RwSignal;
use floem::reactive::SignalGet;
use floem::reactive::SignalUpdate;
use floem::style::Position;
use floem::text::FONT_SYSTEM;
use floem::views::dyn_view;
use floem::views::empty;
use floem::views::label;
use floem::views::slider::Slider;
use floem::window::WindowConfig;
use floem::Application;
use floem::IntoView;
use palette::Hsl;
use palette::Hsv;
use palette::IntoColor;
use palette::Lch;
use palette::Srgb;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

const FIRA_MONO: &[u8] = include_bytes!("../fonts/FiraMono-Medium.ttf");
const FIRA_SANS: &[u8] = include_bytes!("../fonts/FiraSans-Medium.ttf");
const DEJAVU_SERIF: &[u8] = include_bytes!("../fonts/DejaVuSerif.ttf");

fn create_color_sliders(
    label_text: &str,
    signal: RwSignal<f32>,
    update_fn: impl Fn(f32) + 'static,
) -> impl IntoView {
    let text_label = label_text.to_string();
    (
        label(move || text_label.clone()).style(|s| s.size(65, 30)),
        Slider::new(move || signal.get())
            .on_change_px(move |new_value| update_fn(new_value as f32))
            .style(|s| s.width(250)),
    )
        .style(|s| s.flex_row().gap(3).width_full())
}

fn create_color_display(
    red: RwSignal<f32>,
    green: RwSignal<f32>,
    blue: RwSignal<f32>,
) -> impl IntoView {
    (
        dyn_view(move || {
            format!(
                "rgb: ({}, {}, {})",
                (red.get() * 255.0) as i32,
                (green.get() * 255.0) as i32,
                (blue.get() * 255.0) as i32,
            )
        })
        .style(|s| s.width(50).font_size(18)),
        empty().style(move |s| {
            s.background(Color::rgb(
                red.get() as f64,
                green.get() as f64,
                blue.get() as f64,
            ))
            .size(310, 75)
        }),
    )
        .style(|s| s.flex_col().gap(10))
}

fn lch_view() -> impl IntoView {
    let l = RwSignal::new(40.0);
    let c = RwSignal::new(40.0);
    let h = RwSignal::new(40.0);

    let red = RwSignal::new(0.4);
    let green = RwSignal::new(0.4);
    let blue = RwSignal::new(0.4);

    let update_rgb = move |get_values: Box<dyn Fn() -> (f32, f32, f32)>| {
        let (l_val, c_val, h_val) = get_values();
        let rgb: Srgb = Lch::new(l_val, c_val, h_val).into_color();
        red.set(rgb.red);
        green.set(rgb.green);
        blue.set(rgb.blue);
    };

    (
        (
            create_color_sliders("Lightness", l, move |new_l| {
                l.set(new_l);
                update_rgb(Box::new(move || (new_l, c.get(), h.get())))
            }),
            create_color_sliders("Chroma", c, move |new_c| {
                c.set(new_c);
                update_rgb(Box::new(move || (l.get(), new_c, h.get())))
            }),
            create_color_sliders("Hue", h, move |new_h| {
                h.set(new_h);
                update_rgb(Box::new(move || (l.get(), c.get(), new_h)))
            }),
        )
            .style(|s| s.flex_col().gap(3)),
        create_color_display(red, green, blue),
    )
        .style(|s| s.flex_col().items_start().margin_right(10))
}
fn hsl_view() -> impl IntoView {
    let h = RwSignal::new(40.0);
    let s = RwSignal::new(40.0);
    let l = RwSignal::new(40.0);

    let red = RwSignal::new(0.2);
    let green = RwSignal::new(0.2);
    let blue = RwSignal::new(0.2);

    let update_rgb = move |get_values: Box<dyn Fn() -> (f32, f32, f32)>| {
        let (h_val, s_val, l_val) = get_values();
        let rgb: Srgb = Hsl::new(h_val, s_val, l_val).into_color();
        red.set(rgb.red);
        green.set(rgb.green);
        blue.set(rgb.blue);
    };

    (
        (
            create_color_sliders("Hue", h, move |new_h| {
                h.set(new_h);
                update_rgb(Box::new(move || {
                    (new_h * 3.6, s.get() / 100.0, l.get() / 100.0)
                }))
            }),
            create_color_sliders("Saturation", s, move |new_s| {
                s.set(new_s);
                update_rgb(Box::new(move || {
                    (h.get() * 3.6, new_s / 100.0, l.get() / 100.0)
                }))
            }),
            create_color_sliders("Lightness", l, move |new_l| {
                l.set(new_l);
                update_rgb(Box::new(move || {
                    (h.get() * 3.6, s.get() / 100.0, new_l / 100.0)
                }))
            }),
        )
            .style(|s| s.flex_col().gap(3)),
        create_color_display(red, green, blue),
    )
        .style(|s| s.flex_col().items_start().margin_right(10))
}

fn hsv_view() -> impl IntoView {
    let h = RwSignal::new(40.0);
    let s = RwSignal::new(40.0);
    let v = RwSignal::new(40.0);

    let red = RwSignal::new(0.2);
    let green = RwSignal::new(0.2);
    let blue = RwSignal::new(0.2);

    let update_rgb = move |get_values: Box<dyn Fn() -> (f32, f32, f32)>| {
        let (h_val, s_val, v_val) = get_values();
        let rgb: Srgb = Hsv::new(h_val, s_val, v_val).into_color();
        red.set(rgb.red);
        green.set(rgb.green);
        blue.set(rgb.blue);
    };

    (
        (
            create_color_sliders("Hue", h, move |new_h| {
                h.set(new_h);
                update_rgb(Box::new(move || {
                    (new_h * 3.6, s.get() / 100.0, v.get() / 100.0)
                }));
            }),
            create_color_sliders("Saturation", s, move |new_s| {
                s.set(new_s);
                update_rgb(Box::new(move || {
                    (h.get() * 3.6, new_s / 100.0, v.get() / 100.0)
                }))
            }),
            create_color_sliders("Value", v, move |new_v| {
                v.set(new_v);
                update_rgb(Box::new(move || {
                    (h.get() * 3.6, s.get() / 100.0, new_v / 100.0)
                }))
            }),
        )
            .style(|s| s.flex_col().gap(3)),
        create_color_display(red, green, blue),
    )
        .style(|s| s.flex_col().items_start().margin_right(10))
}

fn rgb_view() -> impl IntoView {
    let r = RwSignal::new(40);
    let g = RwSignal::new(40);
    let b = RwSignal::new(40);

    (
        (
            create_color_sliders("Red", RwSignal::new(r.get() as f32), move |new_r| {
                r.set(new_r as i32)
            }),
            create_color_sliders("Green", RwSignal::new(g.get() as f32), move |new_g| {
                g.set(new_g as i32)
            }),
            create_color_sliders("Blue", RwSignal::new(b.get() as f32), move |new_b| {
                b.set(new_b as i32)
            }),
        )
            .style(|s| s.flex_col().gap(3)),
        (
            dyn_view(move || format!("rgb: ({}, {}, {})", r.get(), g.get(), b.get(),))
                .style(|s| s.width(50).font_size(18)),
            empty().style(move |s| {
                s.background(Color::rgb8(r.get() as u8, g.get() as u8, b.get() as u8))
                    .size(310, 75)
            }),
        )
            .style(|s| s.flex_col().gap(10)),
    )
        .style(|s| s.flex_col().items_start().margin_right(10))
}

fn palette() -> impl IntoView {
    (
        (
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(194, 255, 199))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#C2FFC7".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(158, 223, 156))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#9EDF9C".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(98, 130, 93))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#62825D".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(82, 110, 72))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#526E48".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(223, 242, 235))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#DFF2EB".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(185, 229, 232))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#B9E5E8".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(122, 178, 211))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#7AB2D3".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(74, 98, 138))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#4A628A".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(116, 9, 56))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#740938".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(175, 23, 64))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#AF1740".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(204, 43, 82))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#CC2B52".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(222, 124, 125))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#DE7C7D".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(255, 245, 228))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FFF5E4".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(255, 227, 225))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FFE3E1".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(255, 209, 209))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FFD1D1".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(255, 148, 148))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FF9494".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
        )
            .style(|s| s.flex_col().gap(10)),
        (
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(203, 157, 240))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#CB9DF0".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(240, 193, 225))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#F0C1E1".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(253, 219, 187))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FDDBBB".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(255, 249, 191))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FFF9BF".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(46, 7, 63))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#2E073F".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(122, 28, 172))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#7A1CAC".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(173, 73, 225))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#AD49E1".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(235, 211, 248))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#EBD3F8".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(111, 78, 55))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#6F4E37".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(166, 123, 91))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#A67B5B".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(236, 177, 118))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#ECB176".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(254, 216, 177))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FED8B1".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
            (
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(204, 213, 174))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#CCD5AE".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(224, 229, 182))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#E0E5B6".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(250, 237, 206))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FAEDCE".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
                (
                    empty().style(|s| {
                        s.background(Color::rgb8(254, 250, 224))
                            .size(235, 185)
                            .position(Position::Relative)
                    }),
                    label(move || "#FEFAE0".to_string())
                        .style(|s| s.position(Position::Absolute).padding(10).font_size(18)),
                )
                    .style(|s| s.flex_col().items_center().gap(2)),
            )
                .style(|s| s.flex_row()),
        )
            .style(|s| s.flex_col().gap(10)),
    )
        .style(|s| s.flex_row().gap(20))
}

fn app_view() -> impl IntoView {
    ((rgb_view(), lch_view(), hsl_view(), hsv_view()), palette())
        .style(|s| s.flex_col().padding(6).gap(10))
}


#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
pub fn run() {
    #[cfg(target_family = "wasm")]
    console_error_panic_hook::set_once();

    {
        let mut font_system = FONT_SYSTEM.lock();
        let font_db = font_system.db_mut();
        font_db.load_font_data(Vec::from(FIRA_MONO));
        font_db.load_font_data(Vec::from(FIRA_SANS));
        font_db.load_font_data(Vec::from(DEJAVU_SERIF));
    }

    let window_config = WindowConfig::default().with_web_config(|w| w.canvas_id("the-canvas"));

    Application::new()
        .window(move |_| app_view(), Some(window_config))
        .run()
}

fn main() {
    run();
}

index.html文件:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>floem plattle</title>
    <style>
        html,
        body {
            padding: 0;
            margin: 0;
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
            background-color: rgb(255, 255, 255)
        }

        #the-canvas {
            /* Margin around the canvas */
            margin: 16px;
            background-color: black;
            /* Account for 16px margin on each side */
            width: calc(100% - 32px);
            height: calc(100% - 32px);
            /* Maintains aspect ratio, scales to fill space */
            object-fit: contain;
        }

        /* Remove focus outline (e.g. on Firefox) */
        #the-canvas:focus-visible {
            outline: none;
        }
    </style>
</head>

<body>
    <canvas id="the-canvas"></canvas>
</body>

</html>
⚠️ **GitHub.com Fallback** ⚠️