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 := { property selected: 0; callback format-rgb-hex(color) -> string; } Colors := Rectangle { width : 100%; border-width : 2px; background: @linear-gradient(90deg, #002b36 0%, #073642 100%); property <[color]> colors: [ rgb( 0, 0, 0), ]; property base: 0; squares := HorizontalBox { width : 100%; height : 20px; for col[i] in colors : psquare := Rectangle { property current-color : col; width : (squares.width / 8) - 12px; height : (squares.width / 8) - 12px; border-color : i == (Aux.selected - base) ? #cb4b16 : #839496; border-width : 3px; forward-focus: pval; ptouch := TouchArea { clicked => { Aux.selected = base + i; } } prect := Rectangle { y : 3px; x : 3px; width : psquare.width - 6px; height : psquare.height - 6px; background : current-color; VerticalBox { pdesc := Text { /* Text will be set through callback from Rust. */ text : i; } Rectangle { background : ptouch.has-hover ? #ffffff77 : #cccccc33; pval := TextInput { text : Aux.format-rgb-hex(current-color); font-size : 9pt; } } Rectangle { } } } } } } GuiEdit := Window { property scheme-name <=> name.text; callback set-primary ([color]); callback set-secondary ([color]); set-primary (colors) => { primary-colors .colors = colors; } set-secondary (colors) => { secondary-colors.colors = colors; } callback user-quit(); key-inputs := FocusScope { key-pressed(event) => { debug("input: got", event.text, "shift?", event.modifiers.shift); if (event.text == "q") { user-quit(); } if (event.text == "h") { debug("select prev"); master.select-prev(); } else if (event.text == "l") { debug("select next"); master.select-next(); } else if (event.text == " ") { if (event.modifiers.shift) { debug("select prev"); master.select-prev(); } else { debug("select next"); master.select-next(); } } else if (event.text == "j" || event.text == "k") { debug("select other row"); master.select-other-row(); } if (event.modifiers.control) { //debug("control was pressed during this event"); } accept } } color-vbox := VerticalBox { alignment: start; callback select-prev(); callback select-next(); callback select-other-row(); select-prev () => { Aux.selected = Aux.selected == 0 ? 15 : Aux.selected - 1; debug ("selected previous, now", Aux.selected); } select-next () => { Aux.selected = mod (Aux.selected + 1, 16); debug ("selected next, now", Aux.selected); } select-other-row () => { Aux.selected = mod (Aux.selected + 8, 16); debug ("selected row above/below, now", Aux.selected); } status := HorizontalBox { width : 100%; name := Text { text : ""; color : #a0a0a0; font-weight : 700; } } primary-colors := Colors { base : 0; } secondary-colors := Colors { base : 8; } } } } 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.on_user_quit (move || { std::process::exit(0); }); 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.invoke_set_primary(primary.into()); gui.invoke_set_secondary(secondary.into()); gui.run(); Ok(()) } }