diff --git a/examples/color_pallete/Cargo.toml b/examples/color_pallete/Cargo.toml
new file mode 100644
index 00000000..8b01bb34
--- /dev/null
+++ b/examples/color_pallete/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "color_pallete"
+edition = "2021"
+license.workspace = true
+version.workspace = true
+
+[dependencies]
+im.workspace = true
+floem = { path = "../.." }
+palette = "0.7.6"
diff --git a/examples/color_pallete/README.md b/examples/color_pallete/README.md
new file mode 100644
index 00000000..01c91bc1
--- /dev/null
+++ b/examples/color_pallete/README.md
@@ -0,0 +1,7 @@
+## Color palette
+
+A color palette generator
+
+
+
+
diff --git a/examples/color_pallete/color_palette.png b/examples/color_pallete/color_palette.png
new file mode 100644
index 00000000..5e64c730
Binary files /dev/null and b/examples/color_pallete/color_palette.png differ
diff --git a/examples/color_pallete/src/main.rs b/examples/color_pallete/src/main.rs
new file mode 100644
index 00000000..bf815bd9
--- /dev/null
+++ b/examples/color_pallete/src/main.rs
@@ -0,0 +1,583 @@
+use floem::kurbo::Size;
+use floem::peniko::Color;
+use floem::prelude::{Decorators, RwSignal};
+use floem::reactive::{SignalGet, SignalUpdate};
+use floem::style::Position;
+use floem::views::slider::Slider;
+use floem::views::{dyn_view, empty, label};
+use floem::window::WindowConfig;
+use floem::Application;
+use floem::IntoView;
+use palette::{Hsl, Hsv, IntoColor, Lch, Srgb};
+
+fn create_color_sliders(
+ label_text: &str,
+ signal: RwSignal,
+ 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,
+ green: RwSignal,
+ blue: RwSignal,
+) -> 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 (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 (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 (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))
+}
+
+fn main() {
+ Application::new()
+ .window(
+ |_| app_view(),
+ Some(
+ WindowConfig::default()
+ .size(Size::new(1800.0, 1000.0))
+ .title("Color Palette"),
+ ),
+ )
+ .run();
+}