mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-19 02:10:49 -05:00
fix(ui): show brush tip thumbnails while dragging presets (#5203)
* fix(ui): show brush tip thumbnails while dragging presets * test(app): wait for autosave sidecar revision before recovery assertions
This commit is contained in:
1 parent
11c46b7121
commit
5ae3ee0ae5
3 files changed
+69
-2
No files matched your search
@@ -920,7 +920,28 @@ pub fn preset_list(ui: &mut egui::Ui, presets: &[BrushPreset], current: Option<&
|
||||
egui::Area::new(egui::Id::new(("brush-drag-label", layout.id))).order(egui::Order::Tooltip).fixed_pos(p + vec2(12.0, 8.0)).interactable(false).show(
|
||||
ui.ctx(),
|
||||
|ui| {
|
||||
egui::Frame::popup(ui.style()).show(ui, |ui| ui.label(name));
|
||||
if matches!(&*d, BrushDrag::Preset(_)) {
|
||||
ui.set_opacity(0.8);
|
||||
}
|
||||
egui::Frame::popup(ui.style()).show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if let BrushDrag::Preset(n) = &*d
|
||||
&& let Some(preset) = presets.iter().find(|preset| preset.name == *n)
|
||||
{
|
||||
let brush = &preset.brush;
|
||||
let tip = brush_preview::tip_texture(
|
||||
ui.ctx(),
|
||||
&format!("brushes-drag-tip:{}", preset.name),
|
||||
&brush.tip,
|
||||
(brush.hardness, brush.angle, brush.roundness),
|
||||
36,
|
||||
Tokens::get(ui.ctx()).text,
|
||||
);
|
||||
ui.add(egui::Image::new(&tip).fit_to_exact_size(vec2(36.0, 36.0)).alt_text(&preset.name));
|
||||
}
|
||||
ui.label(name);
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,50 @@ use egui_kittest::kittest::{NodeT, Queryable};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn dragging_a_brush_shows_its_tip_preview() {
|
||||
for theme in crate::theme::ThemeKind::ALL {
|
||||
for mode in 0..3 {
|
||||
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), Default::default());
|
||||
app.run("prefs.set", json!({"path": "interface.theme", "value": theme.id()})).unwrap();
|
||||
app.ui.panels.brush_settings = mode != 2;
|
||||
app.ui.brush_tab = 1;
|
||||
app.ui.brushes_panel.view = if mode == 1 { BrushesView::Grid } else { BrushesView::List };
|
||||
if mode == 2 {
|
||||
app.ui.brush_picker = Some([300.0, 120.0]);
|
||||
}
|
||||
let name = app.session.tools.presets[0].name.clone();
|
||||
let brush = app.session.tools.brush.clone();
|
||||
let presets = app.session.tools.presets.clone();
|
||||
let mut h = Harness::builder().with_size(vec2(1200.0, 900.0)).build_eframe(move |cc| {
|
||||
PhotocraftApp::setup_context(&cc.egui_ctx, theme);
|
||||
app
|
||||
});
|
||||
h.run_steps(4);
|
||||
let start = h.get_by_role_and_label(Role::Button, &name).rect().center();
|
||||
h.hover_at(start);
|
||||
h.run_steps(1);
|
||||
h.event(egui::Event::PointerButton { pos: start, button: egui::PointerButton::Primary, pressed: true, modifiers: egui::Modifiers::NONE });
|
||||
h.run_steps(1);
|
||||
let end = start + vec2(50.0, 10.0);
|
||||
h.event(egui::Event::PointerMoved(end));
|
||||
h.run_steps(4);
|
||||
assert!(matches!(egui::DragAndDrop::payload::<BrushDrag>(&h.ctx).as_deref(), Some(BrushDrag::Preset(n)) if n == &name));
|
||||
assert!(h.query_by_role_and_label(Role::Image, &name).is_some(), "dragged brush needs a real tip thumbnail, not only its name");
|
||||
let renders = brush_preview::render_count(&h.ctx);
|
||||
h.run_steps(2);
|
||||
assert_eq!(brush_preview::render_count(&h.ctx), renders, "unchanged drag preview stays cached");
|
||||
h.event(egui::Event::PointerMoved(start));
|
||||
h.run_steps(1);
|
||||
h.event(egui::Event::PointerButton { pos: start, button: egui::PointerButton::Primary, pressed: false, modifiers: egui::Modifiers::NONE });
|
||||
h.run_steps(4);
|
||||
assert!(h.query_by_role_and_label(Role::Image, &name).is_none(), "preview disappears on release");
|
||||
assert_eq!(h.state().session.tools.brush, brush, "preview does not change brush settings");
|
||||
assert_eq!(h.state().session.tools.presets, presets, "dropping on the source preserves the library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grid_columns_centre_whole_columns_past_the_indent() {
|
||||
// 6 × 44 + 5 × 3 = 279 of the 290 past a 4 pt indent: 5 spare on each side (rounded down).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Brush and painting parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (Hue Jitter amount track; Brush Settings minimum fields follow their Control; checkbox-only rows and non-destructive Smoothing switch; shaped-tip cursor follows the view; Color Replacement is a live toolbar tool; no brush-feel estimate changed) · **Target:** Adobe Photoshop 2026
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (dragged preset tip preview; Hue Jitter amount track; Brush Settings minimum fields follow their Control; checkbox-only rows and non-destructive Smoothing switch; shaped-tip cursor follows the view; Color Replacement is a live toolbar tool; no brush-feel estimate changed) · **Target:** Adobe Photoshop 2026
|
||||
|
||||
Painting is where Photoshop users notice differences first, so it gets its own checklist: the
|
||||
brush engine (`crates/paint/src/brush.rs`), the Brush Settings UI
|
||||
@@ -108,6 +108,7 @@ tablets against Photoshop side by side.
|
||||
|---|---|---|
|
||||
| .abr import (v1/v2/v6) and export, persistent presets, folders | done | `psd/src/abr.rs` |
|
||||
| Brushes panel: drag a folder into a folder | missing | #2014 |
|
||||
| Dragged brush preset preview | done | Cached, translucent tip thumbnail plus name in panel list/grid and the preset picker; `ui-egui/src/brushes_tab.rs`, real pointer-drag test in `brushes_tab_tests.rs` (#4225, partial) |
|
||||
| Tool presets (.tpl) | partial | Tool Presets panel exists; .tpl import not found |
|
||||
| Import 500 brushes without blocking the UI | not run | P24 |
|
||||
|
||||
@@ -122,3 +123,4 @@ tablets against Photoshop side by side.
|
||||
| 2026-10-12 | minor | A shaped tip's cursor outline turns and flips with a rotated or flipped view, and follows pixel aspect correction |
|
||||
| 2026-10-13 | minor | Shape Dynamics and Transfer minimum inputs follow their Control and retain their values while disabled (#3825, partial). No brush-feel estimate changed. |
|
||||
| 2026-10-13 | minor | Hue Jitter uses the same themed amount slider as other jitter controls (#3825, partial). No brush-feel estimate changed. |
|
||||
| 2026-10-13 | minor | Dragging a brush preset shows its cached tip thumbnail and name in the Brushes panel and preset picker (#4225, partial). No brush-feel estimate changed. |
|
||||
Reference in new issue
Block a user