Move application implementation in color_palette

This commit is contained in:
Héctor Ramón Jiménez 2020-05-01 22:27:14 +02:00
parent 4d724a88e6
commit 555371f77e

View File

@ -13,6 +13,82 @@ pub fn main() {
}) })
} }
#[derive(Default)]
pub struct ColorPalette {
theme: Theme,
rgb: ColorPicker<Color>,
hsl: ColorPicker<palette::Hsl>,
hsv: ColorPicker<palette::Hsv>,
hwb: ColorPicker<palette::Hwb>,
lab: ColorPicker<palette::Lab>,
lch: ColorPicker<palette::Lch>,
canvas_layer: canvas::layer::Cache<Theme>,
}
#[derive(Debug, Clone, Copy)]
pub enum Message {
RgbColorChanged(Color),
HslColorChanged(palette::Hsl),
HsvColorChanged(palette::Hsv),
HwbColorChanged(palette::Hwb),
LabColorChanged(palette::Lab),
LchColorChanged(palette::Lch),
}
impl Sandbox for ColorPalette {
type Message = Message;
fn new() -> Self {
Self::default()
}
fn title(&self) -> String {
String::from("Color palette - Iced")
}
fn update(&mut self, message: Message) {
let srgb = match message {
Message::RgbColorChanged(rgb) => palette::Srgb::from(rgb),
Message::HslColorChanged(hsl) => palette::Srgb::from(hsl),
Message::HsvColorChanged(hsv) => palette::Srgb::from(hsv),
Message::HwbColorChanged(hwb) => palette::Srgb::from(hwb),
Message::LabColorChanged(lab) => palette::Srgb::from(lab),
Message::LchColorChanged(lch) => palette::Srgb::from(lch),
};
self.theme = Theme::new(srgb.clamp());
self.canvas_layer.clear();
}
fn view(&mut self) -> Element<Message> {
let base = self.theme.base;
let srgb = palette::Srgb::from(base);
let hsl = palette::Hsl::from(srgb);
let hsv = palette::Hsv::from(srgb);
let hwb = palette::Hwb::from(srgb);
let lab = palette::Lab::from(srgb);
let lch = palette::Lch::from(srgb);
Column::new()
.padding(10)
.spacing(10)
.push(self.rgb.view(base).map(Message::RgbColorChanged))
.push(self.hsl.view(hsl).map(Message::HslColorChanged))
.push(self.hsv.view(hsv).map(Message::HsvColorChanged))
.push(self.hwb.view(hwb).map(Message::HwbColorChanged))
.push(self.lab.view(lab).map(Message::LabColorChanged))
.push(self.lch.view(lch).map(Message::LchColorChanged))
.push(
Canvas::new()
.width(Length::Fill)
.height(Length::Fill)
.push(self.canvas_layer.with(&self.theme)),
)
.into()
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Theme { pub struct Theme {
lower: Vec<Color>, lower: Vec<Color>,
@ -20,12 +96,6 @@ pub struct Theme {
higher: Vec<Color>, higher: Vec<Color>,
} }
impl Default for Theme {
fn default() -> Self {
Theme::new(Color::from_rgb8(75, 128, 190))
}
}
impl Theme { impl Theme {
pub fn new(base: impl Into<Color>) -> Theme { pub fn new(base: impl Into<Color>) -> Theme {
use palette::{Hsl, Hue, Shade, Srgb}; use palette::{Hsl, Hue, Shade, Srgb};
@ -74,6 +144,136 @@ impl Theme {
} }
} }
impl canvas::Drawable for Theme {
fn draw(&self, frame: &mut canvas::Frame) {
use canvas::{Fill, Path};
use iced::{HorizontalAlignment, VerticalAlignment};
use iced_native::{Point, Size};
use palette::{Hsl, Srgb};
let pad = 20.0;
let box_size = Size {
width: frame.width() / self.len() as f32,
height: frame.height() / 2.0 - pad,
};
let mut text = canvas::Text {
horizontal_alignment: HorizontalAlignment::Center,
vertical_alignment: VerticalAlignment::Top,
size: 15.0,
..canvas::Text::default()
};
for (i, &color) in self.colors().enumerate() {
let anchor = Point {
x: (i as f32) * box_size.width,
y: 0.0,
};
let rect = Path::new(|path| {
path.rectangle(anchor, box_size);
});
frame.fill(&rect, Fill::Color(color));
if self.base == color {
let cx = anchor.x + box_size.width / 2.0;
let tri_w = 10.0;
let tri = Path::new(|path| {
path.move_to(Point {
x: cx - tri_w,
y: 0.0,
});
path.line_to(Point {
x: cx + tri_w,
y: 0.0,
});
path.line_to(Point { x: cx, y: tri_w });
path.line_to(Point {
x: cx - tri_w,
y: 0.0,
});
});
frame.fill(&tri, Fill::Color(Color::WHITE));
let tri = Path::new(|path| {
path.move_to(Point {
x: cx - tri_w,
y: box_size.height,
});
path.line_to(Point {
x: cx + tri_w,
y: box_size.height,
});
path.line_to(Point {
x: cx,
y: box_size.height - tri_w,
});
path.line_to(Point {
x: cx - tri_w,
y: box_size.height,
});
});
frame.fill(&tri, Fill::Color(Color::WHITE));
}
frame.fill_text(canvas::Text {
content: color_hex_string(&color),
position: Point {
x: anchor.x + box_size.width / 2.0,
y: box_size.height,
},
..text
});
}
text.vertical_alignment = VerticalAlignment::Bottom;
let hsl = Hsl::from(Srgb::from(self.base));
for i in 0..self.len() {
let pct = (i as f32 + 1.0) / (self.len() as f32 + 1.0);
let graded = Hsl {
lightness: 1.0 - pct,
..hsl
};
let color: Color = Srgb::from(graded.clamp()).into();
let anchor = Point {
x: (i as f32) * box_size.width,
y: box_size.height + 2.0 * pad,
};
let rect = Path::new(|path| {
path.rectangle(anchor, box_size);
});
frame.fill(&rect, Fill::Color(color));
frame.fill_text(canvas::Text {
content: color_hex_string(&color),
position: Point {
x: anchor.x + box_size.width / 2.0,
y: box_size.height + 2.0 * pad,
},
..text
});
}
}
}
impl Default for Theme {
fn default() -> Self {
Theme::new(Color::from_rgb8(75, 128, 190))
}
}
fn color_hex_string(color: &Color) -> String {
format!(
"#{:x}{:x}{:x}",
(255.0 * color.r).round() as u8,
(255.0 * color.g).round() as u8,
(255.0 * color.b).round() as u8
)
}
#[derive(Default)] #[derive(Default)]
struct ColorPicker<C: ColorSpace> { struct ColorPicker<C: ColorSpace> {
sliders: [slider::State; 3], sliders: [slider::State; 3],
@ -261,203 +461,3 @@ impl ColorSpace for palette::Lch {
) )
} }
} }
#[derive(Default)]
pub struct ColorPalette {
theme: Theme,
rgb: ColorPicker<Color>,
hsl: ColorPicker<palette::Hsl>,
hsv: ColorPicker<palette::Hsv>,
hwb: ColorPicker<palette::Hwb>,
lab: ColorPicker<palette::Lab>,
lch: ColorPicker<palette::Lch>,
canvas_layer: canvas::layer::Cache<Theme>,
}
#[derive(Debug, Clone, Copy)]
pub enum Message {
RgbColorChanged(Color),
HslColorChanged(palette::Hsl),
HsvColorChanged(palette::Hsv),
HwbColorChanged(palette::Hwb),
LabColorChanged(palette::Lab),
LchColorChanged(palette::Lch),
}
impl Sandbox for ColorPalette {
type Message = Message;
fn new() -> Self {
Self::default()
}
fn title(&self) -> String {
String::from("Color Palette")
}
fn update(&mut self, message: Message) {
let srgb = match message {
Message::RgbColorChanged(rgb) => palette::Srgb::from(rgb),
Message::HslColorChanged(hsl) => palette::Srgb::from(hsl),
Message::HsvColorChanged(hsv) => palette::Srgb::from(hsv),
Message::HwbColorChanged(hwb) => palette::Srgb::from(hwb),
Message::LabColorChanged(lab) => palette::Srgb::from(lab),
Message::LchColorChanged(lch) => palette::Srgb::from(lch),
};
self.theme = Theme::new(srgb.clamp());
self.canvas_layer.clear();
}
fn view(&mut self) -> Element<Message> {
let base = self.theme.base;
let srgb = palette::Srgb::from(base);
let hsl = palette::Hsl::from(srgb);
let hsv = palette::Hsv::from(srgb);
let hwb = palette::Hwb::from(srgb);
let lab = palette::Lab::from(srgb);
let lch = palette::Lch::from(srgb);
Column::new()
.padding(10)
.spacing(10)
.push(self.rgb.view(base).map(Message::RgbColorChanged))
.push(self.hsl.view(hsl).map(Message::HslColorChanged))
.push(self.hsv.view(hsv).map(Message::HsvColorChanged))
.push(self.hwb.view(hwb).map(Message::HwbColorChanged))
.push(self.lab.view(lab).map(Message::LabColorChanged))
.push(self.lch.view(lch).map(Message::LchColorChanged))
.push(
Canvas::new()
.width(Length::Fill)
.height(Length::Fill)
.push(self.canvas_layer.with(&self.theme)),
)
.into()
}
}
impl canvas::Drawable for Theme {
fn draw(&self, frame: &mut canvas::Frame) {
use canvas::{Fill, Path};
use iced::{HorizontalAlignment, VerticalAlignment};
use iced_native::{Point, Size};
use palette::{Hsl, Srgb};
let pad = 20.0;
let box_size = Size {
width: frame.width() / self.len() as f32,
height: frame.height() / 2.0 - pad,
};
let mut text = canvas::Text {
horizontal_alignment: HorizontalAlignment::Center,
vertical_alignment: VerticalAlignment::Top,
size: 15.0,
..canvas::Text::default()
};
for (i, &color) in self.colors().enumerate() {
let anchor = Point {
x: (i as f32) * box_size.width,
y: 0.0,
};
let rect = Path::new(|path| {
path.rectangle(anchor, box_size);
});
frame.fill(&rect, Fill::Color(color));
if self.base == color {
let cx = anchor.x + box_size.width / 2.0;
let tri_w = 10.0;
let tri = Path::new(|path| {
path.move_to(Point {
x: cx - tri_w,
y: 0.0,
});
path.line_to(Point {
x: cx + tri_w,
y: 0.0,
});
path.line_to(Point { x: cx, y: tri_w });
path.line_to(Point {
x: cx - tri_w,
y: 0.0,
});
});
frame.fill(&tri, Fill::Color(Color::WHITE));
let tri = Path::new(|path| {
path.move_to(Point {
x: cx - tri_w,
y: box_size.height,
});
path.line_to(Point {
x: cx + tri_w,
y: box_size.height,
});
path.line_to(Point {
x: cx,
y: box_size.height - tri_w,
});
path.line_to(Point {
x: cx - tri_w,
y: box_size.height,
});
});
frame.fill(&tri, Fill::Color(Color::WHITE));
}
frame.fill_text(canvas::Text {
content: color_hex_str(&color),
position: Point {
x: anchor.x + box_size.width / 2.0,
y: box_size.height,
},
..text
});
}
text.vertical_alignment = VerticalAlignment::Bottom;
let hsl = Hsl::from(Srgb::from(self.base));
for i in 0..self.len() {
let pct = (i as f32 + 1.0) / (self.len() as f32 + 1.0);
let graded = Hsl {
lightness: 1.0 - pct,
..hsl
};
let color: Color = Srgb::from(graded.clamp()).into();
let anchor = Point {
x: (i as f32) * box_size.width,
y: box_size.height + 2.0 * pad,
};
let rect = Path::new(|path| {
path.rectangle(anchor, box_size);
});
frame.fill(&rect, Fill::Color(color));
frame.fill_text(canvas::Text {
content: color_hex_str(&color),
position: Point {
x: anchor.x + box_size.width / 2.0,
y: box_size.height + 2.0 * pad,
},
..text
});
}
}
}
fn color_hex_str(color: &Color) -> String {
format!(
"#{:x}{:x}{:x}",
(255.0 * color.r).round() as u8,
(255.0 * color.g).round() as u8,
(255.0 * color.b).round() as u8
)
}