feat: update editor UI to use CompositeIcon

This commit is contained in:
2026-08-03 21:07:10 -04:00
parent d0233b544d
commit 6a9995cc49
+62 -34
View File
@@ -1,19 +1,18 @@
use crate::color_scheme::ColorScheme; use crate::composite_icon::CompositeIcon;
use anyhow::Result;
use gtk::glib; use gtk::glib;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{ use gtk::{
Box as GtkBox, ColorDialog, ColorDialogButton, InfoBar, Label, MessageType, Orientation, Box as GtkBox, ColorDialog, ColorDialogButton, Label, Orientation, Picture, ScrolledWindow,
Picture, ScrolledWindow,
}; };
use std::cell::RefCell; use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Result<gtk::Widget> { pub fn build_editor_page(
let scheme = ColorScheme::load(icon_path)?; composite: Rc<RefCell<CompositeIcon>>,
let scheme = Rc::new(RefCell::new(scheme)); on_back: impl Fn() + 'static,
on_add_emblem: impl Fn() + 'static,
on_save_as: impl Fn() + 'static,
) -> gtk::Widget {
let root = GtkBox::new(Orientation::Vertical, 8); let root = GtkBox::new(Orientation::Vertical, 8);
root.set_margin_top(8); root.set_margin_top(8);
root.set_margin_bottom(8); root.set_margin_bottom(8);
@@ -25,29 +24,36 @@ pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Resu
back_button.connect_clicked(move |_| on_back()); back_button.connect_clicked(move |_| on_back());
toolbar.append(&back_button); toolbar.append(&back_button);
let add_emblem_button = gtk::Button::with_label("Add Emblem");
add_emblem_button.connect_clicked(move |_| on_add_emblem());
toolbar.append(&add_emblem_button);
let save_as_button = gtk::Button::with_label("Save As...");
save_as_button.connect_clicked(move |_| on_save_as());
toolbar.append(&save_as_button);
let undo_button = gtk::Button::with_label("Undo"); let undo_button = gtk::Button::with_label("Undo");
let redo_button = gtk::Button::with_label("Redo"); let redo_button = gtk::Button::with_label("Redo");
toolbar.append(&undo_button); toolbar.append(&undo_button);
toolbar.append(&redo_button); toolbar.append(&redo_button);
root.append(&toolbar); root.append(&toolbar);
if scheme.borrow().colors.is_empty() {
let info = InfoBar::new();
info.set_message_type(MessageType::Warning);
info.add_child(&Label::new(Some(
"No ColorScheme tags were found in this SVG.",
)));
root.append(&info);
}
let content = GtkBox::new(Orientation::Horizontal, 8); let content = GtkBox::new(Orientation::Horizontal, 8);
content.set_vexpand(true); content.set_vexpand(true);
let side_panel = GtkBox::new(Orientation::Vertical, 8);
let swatches_scroller = ScrolledWindow::new(); let swatches_scroller = ScrolledWindow::new();
swatches_scroller.set_min_content_width(300); swatches_scroller.set_min_content_width(300);
swatches_scroller.set_vexpand(true);
let swatches_box = GtkBox::new(Orientation::Vertical, 4); let swatches_box = GtkBox::new(Orientation::Vertical, 4);
swatches_scroller.set_child(Some(&swatches_box)); swatches_scroller.set_child(Some(&swatches_box));
content.append(&swatches_scroller); side_panel.append(&swatches_scroller);
// Geometry sliders will go here in Task 4
let geometry_box = GtkBox::new(Orientation::Vertical, 4);
side_panel.append(&geometry_box);
content.append(&side_panel);
let preview = Picture::new(); let preview = Picture::new();
preview.set_hexpand(true); preview.set_hexpand(true);
@@ -56,10 +62,10 @@ pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Resu
root.append(&content); root.append(&content);
let refresh_preview = { let refresh_preview = {
let scheme = Rc::clone(&scheme); let composite = Rc::clone(&composite);
let preview = preview.clone(); let preview = preview.clone();
move || { move || {
let bytes = glib::Bytes::from_owned(scheme.borrow().content.clone().into_bytes()); let bytes = glib::Bytes::from_owned(composite.borrow().render().into_bytes());
match gtk::gdk::Texture::from_bytes(&bytes) { match gtk::gdk::Texture::from_bytes(&bytes) {
Ok(texture) => preview.set_paintable(Some(&texture)), Ok(texture) => preview.set_paintable(Some(&texture)),
Err(_) => preview.set_paintable(gtk::gdk::Paintable::NONE), Err(_) => preview.set_paintable(gtk::gdk::Paintable::NONE),
@@ -70,7 +76,7 @@ pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Resu
let rebuild_swatches: Rc<RefCell<Box<dyn Fn()>>> = Rc::new(RefCell::new(Box::new(|| {}))); let rebuild_swatches: Rc<RefCell<Box<dyn Fn()>>> = Rc::new(RefCell::new(Box::new(|| {})));
{ {
let scheme = Rc::clone(&scheme); let composite = Rc::clone(&composite);
let swatches_box = swatches_box.clone(); let swatches_box = swatches_box.clone();
let refresh_preview = refresh_preview.clone(); let refresh_preview = refresh_preview.clone();
let rebuild_swatches_for_closure = Rc::clone(&rebuild_swatches); let rebuild_swatches_for_closure = Rc::clone(&rebuild_swatches);
@@ -80,8 +86,18 @@ pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Resu
swatches_box.remove(&child); swatches_box.remove(&child);
} }
let tags: Vec<(String, String)> = scheme.borrow().colors.clone(); let comp = composite.borrow();
for (tag, hex) in tags { let mut all_colors = Vec::new();
for c in &comp.bg.colors {
all_colors.push((c.0.clone(), c.1.clone(), false));
}
if let Some(emblem) = &comp.emblem {
for c in &emblem.colors {
all_colors.push((c.0.clone(), c.1.clone(), true));
}
}
for (tag, hex, is_emblem) in all_colors {
let row = GtkBox::new(Orientation::Horizontal, 8); let row = GtkBox::new(Orientation::Horizontal, 8);
let label = Label::new(Some(&tag)); let label = Label::new(Some(&tag));
label.set_hexpand(true); label.set_hexpand(true);
@@ -93,7 +109,7 @@ pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Resu
button.set_rgba(&rgba); button.set_rgba(&rgba);
{ {
let scheme = Rc::clone(&scheme); let composite = Rc::clone(&composite);
let tag = tag.clone(); let tag = tag.clone();
let refresh_preview = refresh_preview.clone(); let refresh_preview = refresh_preview.clone();
let rebuild_swatches_for_closure = Rc::clone(&rebuild_swatches_for_closure); let rebuild_swatches_for_closure = Rc::clone(&rebuild_swatches_for_closure);
@@ -105,10 +121,12 @@ pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Resu
(new_rgba.green() * 255.0).round() as u8, (new_rgba.green() * 255.0).round() as u8,
(new_rgba.blue() * 255.0).round() as u8, (new_rgba.blue() * 255.0).round() as u8,
); );
let changed = scheme let mut comp = composite.borrow_mut();
.borrow_mut() let changed = if is_emblem {
.update_color(&tag, &new_hex) comp.emblem.as_mut().unwrap().update_color(&tag, &new_hex).unwrap_or(false)
.unwrap_or(false); } else {
comp.bg.update_color(&tag, &new_hex).unwrap_or(false)
};
if changed { if changed {
refresh_preview(); refresh_preview();
(rebuild_swatches_for_closure.borrow())(); (rebuild_swatches_for_closure.borrow())();
@@ -127,27 +145,37 @@ pub fn build_editor_page(icon_path: &Path, on_back: impl Fn() + 'static) -> Resu
(rebuild_swatches.borrow())(); (rebuild_swatches.borrow())();
{ {
let scheme = Rc::clone(&scheme); let composite = Rc::clone(&composite);
let refresh_preview = refresh_preview.clone(); let refresh_preview = refresh_preview.clone();
let rebuild_swatches = Rc::clone(&rebuild_swatches); let rebuild_swatches = Rc::clone(&rebuild_swatches);
undo_button.connect_clicked(move |_| { undo_button.connect_clicked(move |_| {
if scheme.borrow_mut().undo().unwrap_or(false) { let mut comp = composite.borrow_mut();
let mut changed = comp.bg.undo().unwrap_or(false);
if let Some(emblem) = &mut comp.emblem {
changed |= emblem.undo().unwrap_or(false);
}
if changed {
refresh_preview(); refresh_preview();
(rebuild_swatches.borrow())(); (rebuild_swatches.borrow())();
} }
}); });
} }
{ {
let scheme = Rc::clone(&scheme); let composite = Rc::clone(&composite);
let refresh_preview = refresh_preview.clone(); let refresh_preview = refresh_preview.clone();
let rebuild_swatches = Rc::clone(&rebuild_swatches); let rebuild_swatches = Rc::clone(&rebuild_swatches);
redo_button.connect_clicked(move |_| { redo_button.connect_clicked(move |_| {
if scheme.borrow_mut().redo().unwrap_or(false) { let mut comp = composite.borrow_mut();
let mut changed = comp.bg.redo().unwrap_or(false);
if let Some(emblem) = &mut comp.emblem {
changed |= emblem.redo().unwrap_or(false);
}
if changed {
refresh_preview(); refresh_preview();
(rebuild_swatches.borrow())(); (rebuild_swatches.borrow())();
} }
}); });
} }
Ok(root.upcast()) root.upcast()
} }