Initial Commit

This commit is contained in:
2022-07-29 01:36:18 +02:00
commit e7baf561bd
32 changed files with 4394 additions and 0 deletions

View File

@ -0,0 +1,225 @@
use crate::css::C;
use lighter_lib::BulbColor;
use seed::prelude::*;
use seed::{attrs, div, C};
use std::f32::consts::PI;
use web_sys::MouseEvent;
#[derive(Default)]
pub struct ColorPicker {
hue: f32,
saturation: f32,
brightness: f32,
temperature: f32,
mode: ColorPickerSetting,
dragging: Option<ColorPickerAttr>,
}
#[derive(Default)]
enum ColorPickerSetting {
#[default]
HSB,
Kelvin,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ColorPickerAttr {
HueSat,
Brightness,
Temperature,
}
#[derive(Debug)]
pub enum ColorPickerMsg {
MouseDown(ColorPickerAttr, MouseEvent),
MouseMove(ColorPickerAttr, MouseEvent),
MouseUp(Option<ColorPickerAttr>, MouseEvent),
SetColor(BulbColor),
}
impl ColorPicker {
pub fn update(&mut self, msg: ColorPickerMsg, orders: &mut impl Orders<ColorPickerMsg>) {
match msg {
ColorPickerMsg::MouseDown(target, event) => {
self.dragging = Some(target);
self.handle_mouse_event(target, event);
}
ColorPickerMsg::MouseMove(target, event) => {
self.handle_mouse_event(target, event);
}
ColorPickerMsg::MouseUp(target, event) => {
if let Some(target) = target {
self.handle_mouse_event(target, event);
}
match self.dragging.take() {
Some(ColorPickerAttr::HueSat) => self.mode = ColorPickerSetting::HSB,
Some(ColorPickerAttr::Brightness) => {}
Some(ColorPickerAttr::Temperature) => self.mode = ColorPickerSetting::Kelvin,
None => return,
}
let color = match self.mode {
ColorPickerSetting::HSB => {
BulbColor::hsb(self.hue, self.saturation, self.brightness)
}
ColorPickerSetting::Kelvin => {
BulbColor::kelvin(self.temperature, self.brightness)
}
};
orders.send_msg(ColorPickerMsg::SetColor(color));
}
ColorPickerMsg::SetColor { .. } => {}
}
}
fn handle_mouse_event(&mut self, target: ColorPickerAttr, event: MouseEvent) {
if Some(target) != self.dragging {
return;
}
let handle_bar = || {
let y = event.offset_y() as f32;
let height = 200.0;
1.0 - (y / height).clamp(0.0, 1.0)
};
match target {
ColorPickerAttr::HueSat => {
let (x, y) = (event.offset_x() as f32, event.offset_y() as f32);
let radius = 100.0;
let x = x - radius;
let y = y - radius;
let angle = (x.atan2(y) + PI) / (2.0 * PI);
self.hue = 1.0 - angle;
self.saturation = ((x.powi(2) + y.powi(2)).sqrt() / radius).clamp(0.0, 1.0);
}
ColorPickerAttr::Brightness => self.brightness = handle_bar(),
ColorPickerAttr::Temperature => self.temperature = handle_bar(),
}
}
pub fn view(&self) -> Node<ColorPickerMsg> {
use ColorPickerAttr::{Brightness, HueSat, Temperature};
use ColorPickerMsg::{MouseDown, MouseMove, MouseUp};
let (hs_x, hs_y) = {
let radius = 100.0;
let angle = -self.hue * PI * 2.0;
let x = -self.saturation * radius * angle.sin();
let y = -self.saturation * radius * angle.cos();
(x + radius - 5.0, y + radius - 5.0)
};
let br_y = {
let height = 200.0;
let marker_height = 10.0;
(1.0 - self.brightness) * height - marker_height / 2.0
};
let temp_y = {
let height = 200.0;
let marker_height = 10.0;
(1.0 - self.temperature) * height - marker_height / 2.0
};
let (r, g, b) = hsb_to_rgb(self.hue, 1.0, 1.0);
let saturation_gradient = match self.mode {
ColorPickerSetting::HSB => {
format!("background: linear-gradient(0deg, #000, rgba({r},{g},{b},1));")
}
ColorPickerSetting::Kelvin => format!("background: linear-gradient(0deg, #000, #fff);"),
};
div![
C![C.color_picker],
mouse_ev(Ev::MouseUp, |ev| MouseUp(None, ev)),
div![
C![C.color_wheel],
div![
C![C.color_wheel_marker],
attrs! {
At::Style => format!("margin-left: {hs_x}px; margin-top: {hs_y}px;"),
},
],
mouse_ev(Ev::MouseDown, |ev| MouseDown(HueSat, ev)),
mouse_ev(Ev::MouseMove, |ev| MouseMove(HueSat, ev)),
mouse_ev(Ev::MouseUp, |ev| MouseUp(Some(HueSat), ev)),
//mouse_ev(Ev::MouseLeave, |ev| MouseUp(HueSat, ev)),
],
div![
C![C.brightness_bar],
attrs! { At::Style => saturation_gradient },
div![
C![C.color_bar_marker],
attrs! {
At::Style => format!("margin-top: {br_y}px;"),
},
],
mouse_ev(Ev::MouseDown, |ev| MouseDown(Brightness, ev)),
mouse_ev(Ev::MouseMove, |ev| MouseMove(Brightness, ev)),
mouse_ev(Ev::MouseUp, |ev| MouseUp(Some(Brightness), ev)),
//mouse_ev(Ev::MouseLeave, |ev| MouseUp(Brightness, ev)),
],
div![
C![C.temperature_bar],
div![
C![C.color_bar_marker],
attrs! {
At::Style => format!("margin-top: {temp_y}px;"),
},
],
mouse_ev(Ev::MouseDown, |ev| MouseDown(Temperature, ev)),
mouse_ev(Ev::MouseMove, |ev| MouseMove(Temperature, ev)),
mouse_ev(Ev::MouseUp, |ev| MouseUp(Some(Temperature), ev)),
//mouse_ev(Ev::MouseLeave, |ev| MouseUp(Temperature, ev)),
],
]
}
pub fn set_hsb(&mut self, h: f32, s: f32, b: f32) {
self.hue = h;
self.saturation = s;
self.brightness = b;
self.mode = ColorPickerSetting::HSB;
}
pub fn set_kelvin(&mut self, t: f32, b: f32) {
self.temperature = t;
self.brightness = b;
self.mode = ColorPickerSetting::Kelvin;
}
pub fn set_color(&mut self, color: BulbColor) {
match color {
BulbColor::HSB { h, s, b } => self.set_hsb(h, s, b),
BulbColor::Kelvin { t, b } => self.set_kelvin(t, b),
}
}
}
fn hsb_to_rgb(h: f32, s: f32, b: f32) -> (u8, u8, u8) {
let h = 360.0 * h.clamp(0.0, 1.0);
let c = b * s; // chroma
let x = c * (1. - ((h / 60.) % 2. - 1.).abs());
let m = b - c;
let m = |v| ((v + m) * 255.0) as u8;
let (r, g, b) = match h {
_ if h < 60. => (c, x, 0.0),
_ if h < 120.0 => (x, c, 0.0),
_ if h < 180.0 => (0.0, c, x),
_ if h < 240.0 => (0.0, x, c),
_ if h < 300.0 => (x, 0.0, c),
_ => (c, 0.0, x),
};
(m(r), m(g), m(b))
}

View File

@ -0,0 +1 @@
pub mod color_picker;