mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-28 04:06:54 -06:00
Swatches panel: a gradient dropped on a colour group row is kept too
The drop zone held the ungrouped swatches only, so releasing the gradient over a colour group's row did nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
aa1a0a73f3
commit
d080a5635a
@@ -18,11 +18,57 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) {
|
||||
// Unnamed colours (mixed in the Color panel) aren't listed until Add to Swatches; swatches in
|
||||
// colour groups are listed under their folder.
|
||||
let grouped: Vec<&str> = doc.color_groups.iter().flat_map(|g| g.swatches.iter().map(String::as_str)).collect();
|
||||
// A gradient dragged from the Gradient panel's thumbnail is dropped on the list.
|
||||
// A gradient dragged from the Gradient panel's thumbnail is dropped on the list, colour
|
||||
// groups included.
|
||||
let (_, dropped) = ui.dnd_drop_zone::<GradientDrag, _>(egui::Frame::NONE, |ui| {
|
||||
for sw in doc.swatches.iter().filter(|w| !w.hidden && !grouped.contains(&w.name.as_str())) {
|
||||
swatch_row(app, ui, &doc, sw, 0.0, fill_cur.as_deref());
|
||||
}
|
||||
for g in &doc.color_groups {
|
||||
let open_id = egui::Id::new(("color_group_open", &g.name));
|
||||
let mut open: bool = ui.data(|d| d.get_temp(open_id)).unwrap_or(true);
|
||||
let (row, resp) = ui.allocate_exact_size(vec2(ui.available_width(), 22.0), Sense::click());
|
||||
resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, &g.name));
|
||||
if resp.hovered() {
|
||||
ui.painter().rect_filled(row, 0.0, t.hover);
|
||||
}
|
||||
icons::paint(
|
||||
ui.painter(),
|
||||
egui::Rect::from_min_size(row.min + vec2(2.0, 3.0), vec2(16.0, 16.0)),
|
||||
if open { "chevron-down" } else { "chevron-right" },
|
||||
t.text_dim,
|
||||
);
|
||||
// A folder.
|
||||
let f = egui::Rect::from_min_size(row.min + vec2(20.0, 5.0), vec2(16.0, 12.0));
|
||||
ui.painter().rect_stroke(f, 1.5, egui::Stroke::new(1.2, t.text_dim), egui::StrokeKind::Inside);
|
||||
ui.painter().line_segment([f.left_top() + vec2(1.0, 3.0), f.right_top() + vec2(-1.0, 3.0)], egui::Stroke::new(1.0, t.text_dim));
|
||||
ui.painter().text(row.min + vec2(42.0, 11.0), egui::Align2::LEFT_CENTER, &g.name, egui::FontId::proportional(12.5), t.text);
|
||||
// A double click's first click folded the group: it stays as it was.
|
||||
if resp.clicked() {
|
||||
open = !open;
|
||||
ui.data_mut(|d| d.insert_temp(open_id, open));
|
||||
}
|
||||
if resp.double_clicked() {
|
||||
let _ = app.run("app.colorGroupOptionsDialog", json!({"name": g.name}));
|
||||
}
|
||||
resp.context_menu(|ui| {
|
||||
if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Color Group Options…"))).clicked() {
|
||||
let _ = app.run("app.colorGroupOptionsDialog", json!({"name": g.name}));
|
||||
ui.close();
|
||||
}
|
||||
if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Ungroup Color Group"))).clicked() {
|
||||
let _ = app.run("swatch.ungroupColorGroup", json!({"name": g.name}));
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
if open {
|
||||
for n in &g.swatches {
|
||||
if let Some(sw) = doc.swatches.iter().find(|w| w.name == *n) {
|
||||
swatch_row(app, ui, &doc, sw, 16.0, fill_cur.as_deref());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// An unnamed gradient becomes "New Gradient Swatch"; one that is a swatch already stays one.
|
||||
if let Some(g) = dropped
|
||||
@@ -30,51 +76,6 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) {
|
||||
{
|
||||
let _ = app.run("swatch.new", json!({"swatch": g.0}));
|
||||
}
|
||||
for g in &doc.color_groups {
|
||||
let open_id = egui::Id::new(("color_group_open", &g.name));
|
||||
let mut open: bool = ui.data(|d| d.get_temp(open_id)).unwrap_or(true);
|
||||
let (row, resp) = ui.allocate_exact_size(vec2(ui.available_width(), 22.0), Sense::click());
|
||||
resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, &g.name));
|
||||
if resp.hovered() {
|
||||
ui.painter().rect_filled(row, 0.0, t.hover);
|
||||
}
|
||||
icons::paint(
|
||||
ui.painter(),
|
||||
egui::Rect::from_min_size(row.min + vec2(2.0, 3.0), vec2(16.0, 16.0)),
|
||||
if open { "chevron-down" } else { "chevron-right" },
|
||||
t.text_dim,
|
||||
);
|
||||
// A folder.
|
||||
let f = egui::Rect::from_min_size(row.min + vec2(20.0, 5.0), vec2(16.0, 12.0));
|
||||
ui.painter().rect_stroke(f, 1.5, egui::Stroke::new(1.2, t.text_dim), egui::StrokeKind::Inside);
|
||||
ui.painter().line_segment([f.left_top() + vec2(1.0, 3.0), f.right_top() + vec2(-1.0, 3.0)], egui::Stroke::new(1.0, t.text_dim));
|
||||
ui.painter().text(row.min + vec2(42.0, 11.0), egui::Align2::LEFT_CENTER, &g.name, egui::FontId::proportional(12.5), t.text);
|
||||
// A double click's first click folded the group: it stays as it was.
|
||||
if resp.clicked() {
|
||||
open = !open;
|
||||
ui.data_mut(|d| d.insert_temp(open_id, open));
|
||||
}
|
||||
if resp.double_clicked() {
|
||||
let _ = app.run("app.colorGroupOptionsDialog", json!({"name": g.name}));
|
||||
}
|
||||
resp.context_menu(|ui| {
|
||||
if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Color Group Options…"))).clicked() {
|
||||
let _ = app.run("app.colorGroupOptionsDialog", json!({"name": g.name}));
|
||||
ui.close();
|
||||
}
|
||||
if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Ungroup Color Group"))).clicked() {
|
||||
let _ = app.run("swatch.ungroupColorGroup", json!({"name": g.name}));
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
if open {
|
||||
for n in &g.swatches {
|
||||
if let Some(sw) = doc.swatches.iter().find(|w| w.name == *n) {
|
||||
swatch_row(app, ui, &doc, sw, 16.0, fill_cur.as_deref());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
// InDesign's bottom row: New Color Group, New Swatch, Delete Swatch (the one last clicked).
|
||||
let picked: Option<String> = ui.data(|d| d.get_temp(egui::Id::new(PICKED))).filter(|n: &String| doc.swatch(n).is_some_and(|w| !w.locked));
|
||||
@@ -1054,7 +1055,6 @@ mod gradient_panel_tests {
|
||||
/// which keeps it as a gradient swatch.
|
||||
#[test]
|
||||
fn a_gradient_dragged_onto_the_swatches_becomes_a_swatch() {
|
||||
use egui::{Event, Modifiers, PointerButton};
|
||||
let mut app = app_with_frame();
|
||||
app.run("object.gradient", json!({})).unwrap();
|
||||
app.run("window.panel.float", json!({"panel": "gradient", "x": 300, "y": 120})).unwrap();
|
||||
@@ -1064,10 +1064,23 @@ mod gradient_panel_tests {
|
||||
let before = named(&app);
|
||||
let mut h = crate::test_window::open(app, vec2(1400.0, 900.0));
|
||||
h.run_steps(6);
|
||||
drag_gradient_to(&mut h, "[Black]");
|
||||
let after = named(&h.state().app);
|
||||
assert_eq!(after.len(), before.len() + 1);
|
||||
assert_eq!(after.last().map(String::as_str), Some("New Gradient Swatch"));
|
||||
let d = &h.state().app.session.doc().unwrap().doc;
|
||||
assert!(matches!(d.swatch("New Gradient Swatch").map(|w| &w.value), Some(SwatchValue::Gradient { .. })));
|
||||
let id = h.state().app.session.doc().unwrap().selection.items[0];
|
||||
assert_eq!(d.item(id).unwrap().fill.swatch, "New Gradient Swatch", "the object keeps it, now by name");
|
||||
}
|
||||
|
||||
/// Drag the Gradient panel's thumbnail onto the Swatches panel row labelled `label`.
|
||||
fn drag_gradient_to(h: &mut egui_kittest::Harness<'static, crate::test_window::Window>, label: &str) {
|
||||
use egui::{Event, Modifiers, PointerButton};
|
||||
// The thumbnail sits left of the Type row.
|
||||
let ty = h.get_by_label("Type:").rect();
|
||||
let from = egui::pos2(ty.min.x - 21.0, ty.min.y + 12.0);
|
||||
let to = h.get_by_label("[Black]").rect().center();
|
||||
let to = h.get_by_label(label).rect().center();
|
||||
h.event(Event::PointerMoved(from));
|
||||
h.step();
|
||||
h.event(Event::PointerButton { pos: from, button: PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE });
|
||||
@@ -1078,13 +1091,22 @@ mod gradient_panel_tests {
|
||||
}
|
||||
h.event(Event::PointerButton { pos: to, button: PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE });
|
||||
h.run_steps(4);
|
||||
let after = named(&h.state().app);
|
||||
assert_eq!(after.len(), before.len() + 1);
|
||||
assert_eq!(after.last().map(String::as_str), Some("New Gradient Swatch"));
|
||||
}
|
||||
|
||||
/// A colour group's row is part of the list too: a gradient dropped on it becomes a swatch.
|
||||
#[test]
|
||||
fn a_gradient_dropped_on_a_colour_group_becomes_a_swatch() {
|
||||
let mut app = app_with_frame();
|
||||
app.run("object.gradient", json!({})).unwrap();
|
||||
let group = app.run("swatch.newColorGroup", json!({})).unwrap()["name"].as_str().unwrap().to_string();
|
||||
app.run("window.panel.float", json!({"panel": "gradient", "x": 300, "y": 120})).unwrap();
|
||||
// Tall enough to show the group's row below the swatches.
|
||||
app.run("window.panel.float", json!({"panel": "swatches", "x": 620, "y": 120, "height": 700})).unwrap();
|
||||
let mut h = crate::test_window::open(app, vec2(1400.0, 900.0));
|
||||
h.run_steps(6);
|
||||
drag_gradient_to(&mut h, &group);
|
||||
let d = &h.state().app.session.doc().unwrap().doc;
|
||||
assert!(matches!(d.swatch("New Gradient Swatch").map(|w| &w.value), Some(SwatchValue::Gradient { .. })));
|
||||
let id = h.state().app.session.doc().unwrap().selection.items[0];
|
||||
assert_eq!(d.item(id).unwrap().fill.swatch, "New Gradient Swatch", "the object keeps it, now by name");
|
||||
assert!(matches!(d.swatch("New Gradient Swatch").map(|w| &w.value), Some(SwatchValue::Gradient { .. })), "dropped on the group's row");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user