From ddeb59a89092b0bd7e7b77e3c71dc9bace1e23e5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 27 Aug 2022 21:45:19 +0200 Subject: edit: implement the actual save operation We save palettes in the format that can be directly re-parsed by vtcol. --- Cargo.toml | 1 + src/edit.rs | 128 +++++++++++++++++++++++++++++++++++++----------------------- src/lib.rs | 61 +++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6aca9fc..acc3138 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ edition = "2021" [dependencies] libc = "0.2" +indoc = "1.0" clap = { version = "2.33", optional = true } anyhow = { version = "1.0", optional = true } base64 = "0.13" diff --git a/src/edit.rs b/src/edit.rs index a804def..19bb486 100644 --- a/src/edit.rs +++ b/src/edit.rs @@ -1,6 +1,8 @@ use vtcol::{Palette, Rgb, Scheme}; -use std::{fmt, path::PathBuf, rc::Rc}; +use std::{fmt, + path::{Path, PathBuf}, + rc::Rc}; use anyhow::{anyhow, Result}; @@ -161,11 +163,8 @@ slint::slint! { 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; } + property <[color]> primary <=> primary-colors .colors; + property <[color]> secondary <=> secondary-colors.colors; callback get-palette-color(int) -> color; callback set-palette-color(int, color); @@ -476,54 +475,67 @@ impl Edit } }); - gui.global::().on_handle_command_buffer(|ev, text, _pos| { - let text = match KeyInput::from(&ev) { - KeyInput::Printable(s) => { - let mut text = text.to_string(); - text.push_str(&s); - text - }, - KeyInput::Return => { - match Command::try_from(text.as_str()) { - Err(e) => { - eprintln!("bad command [{}]: {}", text, e); - String::new() - }, - Ok(cmd) => { - if let Err(e) = cmd.exec() { - eprintln!( - "error executing command [{}]: {}", - text, e - ); - } - String::new() + { + let guiw = gui.as_weak(); + gui.global::().on_handle_command_buffer(move |ev, text, _pos| { + let text = match KeyInput::from(&ev) { + KeyInput::Printable(s) => { + let mut text = text.to_string(); + text.push_str(&s); + text + }, + KeyInput::Return => { + match Command::try_from(text.as_str()) { + Err(e) => { + eprintln!("bad command [{}]: {}", text, e); + String::new() + }, + Ok(cmd) => { + use slint::Model; + let scheme_name = + guiw.unwrap().get_scheme_name().to_string(); + let prim = guiw.unwrap().get_primary(); + let secn = guiw.unwrap().get_secondary(); + let pal = prim.iter().chain(secn.iter()) + .collect::>(); + let pal = Palette::from(pal.as_slice()); + if let Err(e) = cmd + .exec(scheme_name.as_str(), pal) + { + eprintln!( + "error executing command [{}]: {}", + text, e + ); + } + String::new() + }, + } + /* The empty string signals to leave command mode. */ + }, + KeyInput::Backspace => + match text.char_indices().next_back() { + Some((i, _)) => text[..i].into(), + None => text.to_string(), }, - } - /* The empty string signals to leave command mode. */ - }, - KeyInput::Backspace => - match text.char_indices().next_back() { - Some((i, _)) => text[..i].into(), - None => text.to_string(), + other => { + eprintln!( + "»»» command mode input: “{}”", + other.to_string() + ); + text.to_string() }, - other => { - eprintln!( - "»»» command mode input: “{}”", - other.to_string() - ); - text.to_string() - }, - }; - eprintln!("»»» command buffer: “{}”", text); - text.into() - }); + }; + eprintln!("»»» command buffer: “{}”", text); + text.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.set_primary(primary.into()); + gui.set_secondary(secondary.into()); gui.run(); @@ -568,5 +580,25 @@ impl TryFrom<&str> for Command impl Command { - fn exec(self) -> Result<()> { todo!("got command: {:?}", self) } + fn exec(self, name: &str, pal: Palette) -> Result<()> + { + match self { + Self::Noop => Ok(()), + Self::Save(None) => Self::save(&PathBuf::from(&name), pal), + Self::Save(Some(path)) => Self::save(&path, pal), + } + //todo!("got command: {:?}", self) + } + + fn save(path: &Path, pal: Palette) -> Result<()> + { + use std::io::Write; + + let mut f = + std::fs::OpenOptions::new().create(true).write(true).open(path)?; + let pal: String = pal.into(); + f.write_all(pal.as_bytes()).map_err(|e| { + anyhow!("error saving Palette to file [{}]: {}", path.display(), e) + }) + } } diff --git a/src/lib.rs b/src/lib.rs index 021f25a..8ecc4a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1125,6 +1125,67 @@ impl From<&RawPalette> for Palette } } +#[cfg(feature = "gui")] +impl From<&[slint::Color]> for Palette +{ + fn from(colors: &[slint::Color]) -> Self + { + let mut idx: usize = 0; + let mut pal: [u8; PALETTE_BYTES] = [0; PALETTE_BYTES]; + + for &col in colors.iter() { + pal[idx] = col.red(); + pal[idx + 1] = col.green(); + pal[idx + 2] = col.blue(); + idx += 3; + } + + Self(pal) + } +} + +/** Convert palette to the default text format so it can be parsed as a scheme. */ +impl Into for Palette +{ + fn into(self) -> String + { + let mut acc = String::with_capacity(16 * 10); + for i in 0..PALETTE_SIZE { + let idx = i * 3; + let (r, g, b) = (self.0[idx], self.0[idx + 1], self.0[idx + 2]); + acc.push_str(&format!("{}#{:02.x}{:02.x}{:02.x}\n", i, r, g, b)); + } + acc + } +} + +#[test] +fn palette_dump_as_text() +{ + let pal = Palette::from(&SOLARIZED_COLORS_DARK); + let txt = indoc::indoc! { r#" + 0#002b36 + 1#dc322f + 2#859900 + 3#b58900 + 4#268bd2 + 5#d33682 + 6#2aa198 + 7#eee8d5 + 8#002b36 + 9#cb4b16 + 10#586e75 + 11#657b83 + 12#839496 + 13#6c71c4 + 14#93a1a1 + 15#fdf6e3 + "#}; + + let pal: String = pal.into(); + assert_eq!(pal, txt); +} + pub struct PaletteIterator { pal: Palette, -- cgit v1.2.3