From adc525cf75a08eef7aa96c7ca56eef5617becc06 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 7 Aug 2022 11:55:44 +0200 Subject: edit: present color palette No actual editing functionality yet, just the colors layed out as squares on an 8?2 grid. --- src/edit.rs | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 50 +++++++++++++++- src/vtcol.rs | 4 +- 3 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 src/edit.rs diff --git a/src/edit.rs b/src/edit.rs new file mode 100644 index 0000000..a166ce4 --- /dev/null +++ b/src/edit.rs @@ -0,0 +1,184 @@ +use vtcol::{Palette, Rgb, Scheme}; + +use std::rc::Rc; + +use anyhow::{anyhow, Result}; + +use slint::{Color, VecModel}; + +slint::slint! { + import { HorizontalBox, VerticalBox } from "std-widgets.slint"; + + export global Aux := { + callback format-rgb-hex(color) -> string; + } + + GuiEdit := Window { + property scheme-name <=> name.text; + + property <[color]> primary: [ + rgb( 0, 0, 0), + ]; + + property <[color]> secondary: [ + rgb(255, 255, 255), + ]; + + VerticalBox { + alignment: start; + + status := HorizontalBox { + width : 100%; + + name := Text { + text : ""; + color : #a0a0a0; + font-weight : 700; + } + } + + primary-colors := Rectangle { + width : 100%; + background : #aaaaaa; + border-width : 2px; + + squares-primary := HorizontalBox { + width : 100%; + height : 20px; + + for col[i] in primary : psquare := Rectangle { + property current-color : col; + width : 86px; + height : 86px; + border-color : ptouch.has-hover ? #eeeeee : #333333; + border-width : 3px; + + ptouch := TouchArea { + } + + prect := Rectangle { + y : 3px; + x : 3px; + width : 80px; + height : 80px; + background : current-color; + + VerticalBox { + pdesc := Text { + text : i; + } + Rectangle { + background : ptouch.has-hover ? #ffffff77 : #cccccc33; + pval := Text { + text : Aux.format-rgb-hex(current-color); + font-size : 9pt; + } + } + Rectangle { } + } + } + } + } + } + + secondary-colors := Rectangle { + width : 100%; + background : #bbbbbb; + border-width : 2px; + + squares-secondary := HorizontalBox { + width : 100%; + height : 20px; + + for col[i] in secondary : ssquare := Rectangle { + property current-color : col; + property i2 : i + 8; + width : 86px; + height : 86px; + border-color : stouch.has-hover ? #eeeeee : #333333; + border-width : 3px; + + stouch := TouchArea { + } + + srect := Rectangle { + y : 3px; + x : 3px; + width : 80px; + height : 80px; + background : current-color; + + VerticalBox { + sdesc := Text { + text : i; + } + Rectangle { + background : stouch.has-hover ? #ffffff77 : #cccccc33; + sval := Text { + text : Aux.format-rgb-hex(current-color); + font-size : 9pt; + } + } + Rectangle { } + } + } + } + } + } + } + } +} + +pub struct Edit +{ + name: Option, + scheme: Scheme, +} + +impl Edit +{ + pub fn new(name: Option, scheme: Scheme) -> Self + { + Self { name, scheme } + } + + pub fn run(self) -> Result<()> + { + let Self { name, scheme } = self; + + let pal = Palette::try_from(&scheme)?.iter().collect::>(); + + let primary = pal[0..8] + .iter() + .map(|Rgb(r, g, b)| Color::from_rgb_u8(*r, *g, *b)) + .collect::>(); + + let secondary = pal[8..] + .iter() + .map(|Rgb(r, g, b)| Color::from_rgb_u8(*r, *g, *b)) + .collect::>(); + + let primary = Rc::new(VecModel::from(primary)); + let secondary = Rc::new(VecModel::from(secondary)); + + let gui = GuiEdit::new(); + + gui.global::().on_format_rgb_hex(|col| { + let x = (col.red() as u32) << 2 + | (col.green() as u32) << 1 + | (col.blue() as u32); + format!("#{:06x}", x).into() + }); + + if let Some(name) = name { + gui.set_scheme_name(name.into()); + } + + gui.set_primary(primary.into()); + gui.set_secondary(secondary.into()); + + gui.run(); + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 5032f68..021f25a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -846,14 +846,17 @@ macro_rules! byte_of_hex { }; } -struct Rgb(u8, u8, u8); +pub struct Rgb(pub u8, pub u8, pub u8); impl Rgb { + #[inline] fn r(&self) -> u8 { self.0 } + #[inline] fn g(&self) -> u8 { self.1 } + #[inline] fn b(&self) -> u8 { self.2 } } @@ -871,6 +874,18 @@ impl TryFrom<&[u8; 6]> for Rgb } } +impl From<[u8; 3]> for Rgb +{ + fn from(bytes: [u8; 3]) -> Self + { + let r = bytes[0]; + let g = bytes[1]; + let b = bytes[2]; + + Self(r, g, b) + } +} + impl From for Rgb { fn from(rgb: u32) -> Self @@ -1028,6 +1043,7 @@ impl Palette Ok(res) } + pub fn iter(&self) -> PaletteIterator { PaletteIterator::new(&self) } /* [Palette::from_stdin] */ } /* [impl Palette] */ @@ -1109,6 +1125,38 @@ impl From<&RawPalette> for Palette } } +pub struct PaletteIterator +{ + pal: Palette, + cur: usize, +} + +impl PaletteIterator +{ + fn new(pal: &Palette) -> Self { Self { pal: pal.clone(), cur: 0 } } +} + +impl Iterator for PaletteIterator +{ + type Item = Rgb; + + fn next(&mut self) -> Option + { + if self.cur >= PALETTE_SIZE { + None + } else { + let off = self.cur * 3; + let rgb = Rgb::from([ + self.pal.0[off], + self.pal.0[off + 1], + self.pal.0[off + 2], + ]); + self.cur += 1; + Some(rgb) + } + } +} + const CONSOLE_PATHS: [&str; 6] = [ "/proc/self/fd/0", "/dev/tty", diff --git a/src/vtcol.rs b/src/vtcol.rs index f12af09..feb8f0b 100644 --- a/src/vtcol.rs +++ b/src/vtcol.rs @@ -330,9 +330,9 @@ impl ColorJob fn edit(name: Option, scm: Scheme) -> Result<()> { vrb!("Launching color scheme editor for scheme {}", scm); - let editor = crate::edit::Edit::new(); + let editor = crate::edit::Edit::new(name, scm); - editor.run(name, scm) + editor.run() } #[cfg(not(feature = "gui"))] -- cgit v1.2.3