Give Image Statistics a source-file dialog and stack mode selector (#4778)
* Give Image Statistics a source-file dialog and stack mode selector * Keep stack sources in vertical rows and translate the mode label * Place the new label alongside stack-mode translations --------- Co-authored-by: jonathnwxh <258340642+jonathanwxh-cell@users.noreply.github.com>
This commit is contained in:
parent
d3d86da130
commit
907752daf2
|
|
@ -101,10 +101,7 @@ pub fn invoke(app: &mut PhotocraftApp, ctx: &egui::Context, id: &str, params: &V
|
|||
json!({"format": ["same", "png", "jpg", "psd", "tiff"]}),
|
||||
)
|
||||
}
|
||||
"file.scripts.statistics" => {
|
||||
let modes: Vec<&str> = photocraft_doc::StackMode::ALL.iter().map(|m| m.id()).collect();
|
||||
form(app, id, "Image Statistics", json!({"mode": "median", "input": dir, "align": false}), json!({"mode": modes}))
|
||||
}
|
||||
"file.scripts.statistics" => json!({"dialog": crate::stack_dialog::open_statistics(app)}),
|
||||
"file.scripts.browse" => {
|
||||
return Some(app.pick_file_bytes_filtered(SCRIPT_EXTENSIONS, |app, name, bytes| {
|
||||
let r = app.run("file.scripts.browse", json!({"script": String::from_utf8_lossy(&bytes)}));
|
||||
|
|
|
|||
|
|
@ -387,6 +387,7 @@
|
|||
Update Modified Content Aktualizovat změněný obsah
|
||||
Update All Modified Content Aktualizovat veškerý změněný obsah
|
||||
Stack Mode Režim zásobníku
|
||||
Choose Stack Mode: Vyberte režim zásobníku:
|
||||
Entropy Entropie
|
||||
Kurtosis Špičatost
|
||||
Maximum Maximum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -386,6 +386,7 @@
|
|||
Update Modified Content Geänderten Inhalt aktualisieren
|
||||
Update All Modified Content Alle geänderten Inhalte aktualisieren
|
||||
Stack Mode Stapelmodus
|
||||
Choose Stack Mode: Stapelmodus auswählen:
|
||||
Entropy Entropie
|
||||
Kurtosis Kurtosis
|
||||
Maximum Maximum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1847,6 +1847,7 @@
|
|||
Update Modified Content Ενημέρωση τροποποιημένου περιεχομένου
|
||||
Update All Modified Content Ενημέρωση όλων των τροποποιημένων περιεχομένων
|
||||
Stack Mode Λειτουργία στοίβας
|
||||
Choose Stack Mode: Επιλογή λειτουργίας στοίβας:
|
||||
Entropy Εντροπία
|
||||
Kurtosis Κύρτωση
|
||||
Maximum Μέγιστο
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 7.
|
|
|
@ -383,6 +383,7 @@
|
|||
Update Modified Content Actualizar contenido modificado
|
||||
Update All Modified Content Actualizar todo el contenido modificado
|
||||
Stack Mode Modo de apilamiento
|
||||
Choose Stack Mode: Elegir modo de apilamiento:
|
||||
Entropy Entropía
|
||||
Kurtosis Curtosis
|
||||
Maximum Máximo
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
|
|
@ -377,6 +377,7 @@
|
|||
Update Modified Content Mettre à jour le contenu modifié
|
||||
Update All Modified Content Mettre à jour tout le contenu modifié
|
||||
Stack Mode Mode de pile
|
||||
Choose Stack Mode: Choisir le mode de pile :
|
||||
Entropy Entropie
|
||||
Kurtosis Kurtosis
|
||||
Maximum Maximum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -400,6 +400,7 @@
|
|||
Smooth… Simítás…
|
||||
Solid Color… Egyszínű kitöltés…
|
||||
Stack Mode Halommód
|
||||
Choose Stack Mode: Halommód kiválasztása:
|
||||
Standard Deviation Szórás
|
||||
Subject Fő téma
|
||||
Subtract Front Shape Elülső alakzat kivonása
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -370,6 +370,7 @@
|
|||
Update Modified Content Perbarui Isi yang Diubah
|
||||
Update All Modified Content Perbarui Semua Isi yang Diubah
|
||||
Stack Mode Mode Stack
|
||||
Choose Stack Mode: Pilih Mode Stack:
|
||||
Entropy Entropi
|
||||
Kurtosis Kurtosis
|
||||
Maximum Maksimum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
|
|
@ -379,6 +379,7 @@
|
|||
Update Modified Content Aggiorna contenuto modificato
|
||||
Update All Modified Content Aggiorna tutto il contenuto modificato
|
||||
Stack Mode Modalità pila
|
||||
Choose Stack Mode: Scegli modalità pila:
|
||||
Entropy Entropia
|
||||
Kurtosis Curtosi
|
||||
Maximum Massimo
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 16.
|
|
|
@ -381,6 +381,7 @@
|
|||
Update Modified Content 変更されたコンテンツを更新
|
||||
Update All Modified Content 変更されたコンテンツをすべて更新
|
||||
Stack Mode スタックモード
|
||||
Choose Stack Mode: スタックモードを選択:
|
||||
Entropy エントロピー
|
||||
Kurtosis 尖度
|
||||
Maximum 最大値
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -368,6 +368,7 @@
|
|||
Update Modified Content 수정된 내용 업데이트
|
||||
Update All Modified Content 수정된 모든 내용 업데이트
|
||||
Stack Mode 스택 모드
|
||||
Choose Stack Mode: 스택 모드 선택:
|
||||
Entropy 엔트로피
|
||||
Kurtosis 첨도
|
||||
Maximum 최대값
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 11.
|
|
|
@ -372,6 +372,7 @@
|
|||
Update Modified Content Gewijzigde inhoud bijwerken
|
||||
Update All Modified Content Alle gewijzigde inhoud bijwerken
|
||||
Stack Mode Stapelmodus
|
||||
Choose Stack Mode: Stapelmodus kiezen:
|
||||
Entropy Entropie
|
||||
Kurtosis Kurtosis
|
||||
Maximum Maximum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 8 and column 34.
|
|
|
@ -379,6 +379,7 @@
|
|||
Update Modified Content Aktualizuj zmodyfikowaną zawartość
|
||||
Update All Modified Content Aktualizuj całą zmodyfikowaną zawartość
|
||||
Stack Mode Tryb stosu
|
||||
Choose Stack Mode: Wybierz tryb stosu:
|
||||
Entropy Entropia
|
||||
Kurtosis Kurtoza
|
||||
Maximum Maksimum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -372,6 +372,7 @@
|
|||
Update Modified Content Atualizar conteúdo modificado
|
||||
Update All Modified Content Atualizar todo o conteúdo modificado
|
||||
Stack Mode Modo de pilha
|
||||
Choose Stack Mode: Escolher modo de pilha:
|
||||
Entropy Entropia
|
||||
Kurtosis Curtose
|
||||
Maximum Máximo
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1996,6 +1996,7 @@
|
|||
Solid Color… Однотонный цвет…
|
||||
Square Квадрат
|
||||
Stack Mode Режим стопки
|
||||
Choose Stack Mode: Выберите режим стопки:
|
||||
Standard Deviation Стандартное отклонение
|
||||
Statistics… Статистика…
|
||||
Stylistic Alternates Стилистические варианты
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -367,6 +367,7 @@
|
|||
Update Modified Content Ažuriraj izmenjeni sadržaj
|
||||
Update All Modified Content Ažuriraj sav izmenjeni sadržaj
|
||||
Stack Mode Režim steka
|
||||
Choose Stack Mode: Izaberite režim steka:
|
||||
Entropy Entropija
|
||||
Kurtosis Kurtozis
|
||||
Maximum Maksimum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -363,6 +363,7 @@
|
|||
Update Modified Content Değiştirilen İçeriği Güncelle
|
||||
Update All Modified Content Değiştirilen Tüm İçeriği Güncelle
|
||||
Stack Mode Yığın Modu
|
||||
Choose Stack Mode: Yığın Modunu Seçin:
|
||||
Entropy Entropi
|
||||
Kurtosis Basıklık
|
||||
Maximum Maksimum
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 8 and column 34.
|
|
|
@ -1975,6 +1975,7 @@
|
|||
Solid Color… Суцільний колір…
|
||||
Square Квадрат
|
||||
Stack Mode Режим стосу
|
||||
Choose Stack Mode: Виберіть режим стосу:
|
||||
Standard Deviation Стандартне відхилення
|
||||
Statistics… Статистика…
|
||||
Stylistic Alternates Стилістичні альтернативи
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 12.
|
|
|
@ -385,6 +385,7 @@
|
|||
Smart Objects Đối tượng thông minh
|
||||
Solid Color… Màu đặc…
|
||||
Stack Mode Chế độ chồng
|
||||
Choose Stack Mode: Chọn chế độ chồng:
|
||||
Standard Deviation Độ lệch chuẩn
|
||||
Subtract Front Shape Trừ hình phía trước
|
||||
Summation Tổng
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -386,6 +386,7 @@
|
|||
Update Modified Content 更新已修改的内容
|
||||
Update All Modified Content 更新所有已修改的内容
|
||||
Stack Mode 堆栈模式
|
||||
Choose Stack Mode: 选择堆栈模式:
|
||||
Entropy 熵
|
||||
Kurtosis 峰度
|
||||
Maximum 最大值
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 15.
|
|
|
@ -391,6 +391,7 @@
|
|||
Update Modified Content 更新修改過的內容
|
||||
Update All Modified Content 更新所有修改過的內容
|
||||
Stack Mode 堆疊模式
|
||||
Choose Stack Mode: 選擇堆疊模式:
|
||||
Entropy 熵
|
||||
Kurtosis 峰度
|
||||
Maximum 最大
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1,7 +1,8 @@
|
|||
//! File › Scripts › Load Files into Stack… (#4671, #4696), laid out as Photoshop's: Source Files
|
||||
//! File › Scripts › Load Files into Stack… and Statistics: shared Source Files controls
|
||||
//! with Use (Files or Folder), the list of what will be loaded, Browse…, Remove, Add Open Files and
|
||||
//! Sort By Name, then Attempt to Automatically Align Source Images and Create Smart Object after
|
||||
//! Loading Layers. OK runs `file.scripts.loadFilesIntoStack` with the list or the folder.
|
||||
//! Loading Layers. Statistics adds Stack Mode and always creates a smart object. OK runs the
|
||||
//! corresponding engine command with the list or the folder.
|
||||
use egui::{RichText, vec2};
|
||||
use serde_json::{Map, Value, json};
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ use crate::{PhotocraftApp, state::DialogKind, theme::Tokens, widgets};
|
|||
|
||||
const MARK: &str = "__loadStack";
|
||||
pub const COMMAND: &str = "file.scripts.loadFilesIntoStack";
|
||||
const STATISTICS: &str = "file.scripts.statistics";
|
||||
|
||||
pub fn owns(fields: &Map<String, Value>) -> bool {
|
||||
fields.contains_key(MARK)
|
||||
|
|
@ -17,15 +19,30 @@ pub fn owns(fields: &Map<String, Value>) -> bool {
|
|||
|
||||
/// Open the dialog with an empty Files list. Returns its id.
|
||||
pub fn open(app: &mut PhotocraftApp) -> u64 {
|
||||
open_for(app, COMMAND, "Load Files into Stack…")
|
||||
}
|
||||
|
||||
pub fn open_statistics(app: &mut PhotocraftApp) -> u64 {
|
||||
open_for(app, STATISTICS, "Image Statistics")
|
||||
}
|
||||
|
||||
fn statistics(f: &Map<String, Value>) -> bool {
|
||||
f.get("__command").and_then(Value::as_str) == Some(STATISTICS)
|
||||
}
|
||||
|
||||
fn open_for(app: &mut PhotocraftApp, command: &str, label: &str) -> u64 {
|
||||
let mut f = Map::new();
|
||||
f.insert(MARK.into(), json!(true));
|
||||
f.insert("__command".into(), json!(COMMAND));
|
||||
f.insert("__label".into(), json!("Load Files into Stack…"));
|
||||
f.insert("__command".into(), json!(command));
|
||||
f.insert("__label".into(), json!(label));
|
||||
f.insert("use".into(), json!("files"));
|
||||
f.insert("files".into(), json!([]));
|
||||
f.insert("folder".into(), json!(""));
|
||||
f.insert("align".into(), json!(false));
|
||||
f.insert("smartObject".into(), json!(false));
|
||||
if command == STATISTICS {
|
||||
f.insert("mode".into(), json!("median"));
|
||||
}
|
||||
app.ui.open_dialog(DialogKind::Command, f)
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +113,17 @@ fn browse(app: &mut PhotocraftApp, id: u64, folder: bool) {
|
|||
/// The dialog's body (dialog `id`); OK and Cancel are the standard ones below it.
|
||||
pub fn body(app: &mut PhotocraftApp, ui: &mut egui::Ui, f: &mut Map<String, Value>, id: u64) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
if statistics(f) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(tl!("Choose Stack Mode:"));
|
||||
let mut mode = f.get("mode").and_then(Value::as_str).unwrap_or("median").to_string();
|
||||
let options: Vec<_> = photocraft_doc::StackMode::ALL.iter().map(|m| (m.id().to_string(), m.label())).collect();
|
||||
if widgets::dropdown(ui, "statistics-stack-mode", &mut mode, &options, 180.0) {
|
||||
f.insert("mode".into(), json!(mode));
|
||||
}
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
}
|
||||
ui.label(RichText::new(tl!("Source Files")).font(crate::theme::semibold(13.0)));
|
||||
ui.add_space(4.0);
|
||||
ui.horizontal(|ui| {
|
||||
|
|
@ -122,15 +150,17 @@ pub fn body(app: &mut PhotocraftApp, ui: &mut egui::Ui, f: &mut Map<String, Valu
|
|||
ui.set_min_size(vec2(300.0, 160.0));
|
||||
ui.set_max_width(300.0);
|
||||
egui::ScrollArea::vertical().id_salt("load-stack-files").max_height(160.0).auto_shrink([false, false]).show(ui, |ui| {
|
||||
if folder_mode && !folder(f).is_empty() {
|
||||
ui.label(RichText::new(folder(f)).color(t.text_dim));
|
||||
}
|
||||
for (i, p) in shown.iter().enumerate() {
|
||||
let row = ui.add(egui::Button::selectable(!folder_mode && sel == Some(i), file_name(p))).on_hover_text(p.as_str());
|
||||
if row.clicked() && !folder_mode {
|
||||
f.insert("selected".into(), json!(i));
|
||||
ui.with_layout(egui::Layout::top_down(egui::Align::Min), |ui| {
|
||||
if folder_mode && !folder(f).is_empty() {
|
||||
ui.label(RichText::new(folder(f)).color(t.text_dim));
|
||||
}
|
||||
}
|
||||
for (i, p) in shown.iter().enumerate() {
|
||||
let row = ui.add(egui::Button::selectable(!folder_mode && sel == Some(i), file_name(p))).on_hover_text(p.as_str());
|
||||
if row.clicked() && !folder_mode {
|
||||
f.insert("selected".into(), json!(i));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
|
|
@ -162,6 +192,9 @@ pub fn body(app: &mut PhotocraftApp, ui: &mut egui::Ui, f: &mut Map<String, Valu
|
|||
});
|
||||
ui.add_space(8.0);
|
||||
for (key, label) in [("align", tl!("Attempt to Automatically Align Source Images")), ("smartObject", tl!("Create Smart Object after Loading Layers"))] {
|
||||
if statistics(f) && key == "smartObject" {
|
||||
continue;
|
||||
}
|
||||
let mut on = f.get(key).and_then(Value::as_bool).unwrap_or(false);
|
||||
if widgets::checkbox(ui, &mut on, label).changed() {
|
||||
f.insert(key.into(), json!(on));
|
||||
|
|
@ -193,7 +226,12 @@ pub fn confirm(app: &mut PhotocraftApp, f: &Map<String, Value>) -> Result<Value,
|
|||
};
|
||||
let align = f.get("align").and_then(Value::as_bool).unwrap_or(false);
|
||||
let smart = f.get("smartObject").and_then(Value::as_bool).unwrap_or(false);
|
||||
let r = app.run(COMMAND, json!({"paths": paths, "align": align, "createSmartObject": smart}));
|
||||
let r = if statistics(f) {
|
||||
let mode = f.get("mode").and_then(Value::as_str).unwrap_or("median");
|
||||
app.run(STATISTICS, json!({"paths": paths, "align": align, "mode": mode}))
|
||||
} else {
|
||||
app.run(COMMAND, json!({"paths": paths, "align": align, "createSmartObject": smart}))
|
||||
};
|
||||
if r.is_ok() {
|
||||
app.sync_views();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,107 @@ fn listed(h: &Harness<'_, PhotocraftApp>) -> Vec<String> {
|
|||
dialog(h).map(|(_, f)| files(&f).iter().map(|p| file_name(p).to_string()).collect()).unwrap_or_default()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statistics_menu_opens_a_source_file_list_with_stack_mode() {
|
||||
let (mut h, _) = harness(vec![]);
|
||||
let ctx = h.ctx.clone();
|
||||
crate::menus::invoke(h.state_mut(), &ctx, "file.scripts.statistics", json!({})).unwrap();
|
||||
h.run_steps(4);
|
||||
for label in ["Choose Stack Mode:", "Source Files", "Browse…", "Remove", "Add Open Files", "Sort By Name", "Attempt to Automatically Align Source Images"]
|
||||
{
|
||||
assert!(h.query_by_label(label).is_some(), "Statistics is missing {label}");
|
||||
}
|
||||
assert!(h.get_by_label("OK").accesskit_node().is_disabled(), "choose source files before running statistics");
|
||||
assert!(h.query_by_label("Create Smart Object after Loading Layers").is_none(), "Statistics always creates its stack smart object");
|
||||
assert!(!dialog(&h).unwrap().1.contains_key("input"), "no generic Input field");
|
||||
h.get_by_label("Cancel").click();
|
||||
h.run_steps(2);
|
||||
assert!(dialog(&h).is_none());
|
||||
assert!(h.state().session.documents().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statistics_browse_and_mode_selection_compute_the_chosen_statistic() {
|
||||
let (_, paths) = pngs("statistics-mean", &["first.png", "second.png"]);
|
||||
let mut source = photocraft_engine::Session::new();
|
||||
source.execute("file.new", json!({"width": 8, "height": 6, "background": "#80a0c0"})).unwrap();
|
||||
source.execute("file.saveACopy", json!({"path": paths[1]})).unwrap();
|
||||
let (mut h, _) = harness(vec![Some(FileDialogAnswer::Paths(paths))]);
|
||||
let ctx = h.ctx.clone();
|
||||
crate::menus::invoke(h.state_mut(), &ctx, STATISTICS, json!({})).unwrap();
|
||||
h.run_steps(3);
|
||||
h.get_by_label("Browse…").click();
|
||||
h.run_steps(4);
|
||||
assert_eq!(listed(&h), ["first.png", "second.png"]);
|
||||
assert!(h.get_by_label("first.png").rect().bottom() <= h.get_by_label("second.png").rect().top(), "source files must be vertical rows");
|
||||
h.get_by_value("Median").click();
|
||||
h.run_steps(2);
|
||||
for mode in photocraft_doc::StackMode::ALL {
|
||||
assert!(h.query_by_label(mode.label()).is_some(), "missing {}", mode.label());
|
||||
}
|
||||
h.get_by_label("Mean").click();
|
||||
h.run_steps(2);
|
||||
h.get_by_label("OK").click();
|
||||
h.run_steps(4);
|
||||
assert!(dialog(&h).is_none());
|
||||
assert_eq!(h.state().session.documents().len(), 1);
|
||||
let doc = &h.state().session.active().unwrap().doc;
|
||||
assert_eq!(doc.layers.len(), 1);
|
||||
let photocraft_doc::LayerContent::Smart(smart) = &doc.layers[0].content else { panic!("expected a stack smart object") };
|
||||
assert_eq!(smart.stack_mode, Some(photocraft_doc::StackMode::Mean));
|
||||
let pixel = photocraft_compose::flatten(doc).px[0];
|
||||
for (actual, expected) in pixel.iter().zip([96.0, 128.0, 160.0, 255.0]) {
|
||||
assert!((actual * 255.0 - expected).abs() < 1.5, "{pixel:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statistics_explicit_parameters_bypass_the_dialog() {
|
||||
let (_, paths) = pngs("statistics-script", &["one.png", "two.png"]);
|
||||
let (mut h, _) = harness(vec![]);
|
||||
let ctx = h.ctx.clone();
|
||||
let result = crate::menus::invoke(h.state_mut(), &ctx, STATISTICS, json!({"input": paths, "mode": "maximum"})).unwrap();
|
||||
assert_eq!(result["images"], 2);
|
||||
assert_eq!(result["mode"], "maximum");
|
||||
assert!(dialog(&h).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statistics_folder_and_alignment_reach_the_engine() {
|
||||
let (dir, paths) = pngs("statistics-folder", &["one.png", "two.png"]);
|
||||
// Auto-Align needs identifiable detail, not a uniform tiny colour swatch.
|
||||
let mut source = photocraft_engine::Session::new();
|
||||
source.execute("file.new", json!({"width": 96, "height": 72, "background": "#606060"})).unwrap();
|
||||
source
|
||||
.edit("texture", |doc, active| {
|
||||
let surface = doc.layer_mut(active.unwrap()).unwrap().surface_mut().unwrap();
|
||||
for k in 0..40 {
|
||||
let (x, y, v) = ((k * 37) % 88, (k * 23) % 66, (k % 7) as f32 / 6.0);
|
||||
surface.fill_rect(photocraft_geom::Rect::new(x, y, x + 3 + k % 5, y + 2 + k % 4), &[v, 1.0 - v, 0.5, 1.0]);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
for path in paths {
|
||||
source.execute("file.saveACopy", json!({"path": path})).unwrap();
|
||||
}
|
||||
let (mut h, _) = harness(vec![Some(FileDialogAnswer::FolderTo(dir))]);
|
||||
let id = open_statistics(h.state_mut());
|
||||
h.state_mut().ui.dialog_mut(id).unwrap().fields.insert("use".into(), json!("folder"));
|
||||
h.run_steps(3);
|
||||
h.get_by_label("Browse…").click();
|
||||
h.run_steps(4);
|
||||
h.get_by_label("Attempt to Automatically Align Source Images").click();
|
||||
h.run_steps(2);
|
||||
assert_eq!(dialog(&h).unwrap().1["align"], true);
|
||||
let result = crate::dialogs::confirm(h.state_mut(), id).unwrap();
|
||||
assert_eq!(result["images"], 2);
|
||||
assert_eq!(result["mode"], "median");
|
||||
let doc = &h.state().session.active().unwrap().doc;
|
||||
let photocraft_doc::LayerContent::Smart(smart) = &doc.layers[0].content else { panic!("expected a stack smart object") };
|
||||
assert_eq!(smart.stack_mode, Some(photocraft_doc::StackMode::Median));
|
||||
}
|
||||
|
||||
/// #4671 / #4696: the menu opens Photoshop's dialog, Browse… adds files (once each), Remove,
|
||||
/// Sort By Name and Add Open Files edit the list, and OK loads it.
|
||||
#[test]
|
||||
|
|
@ -71,6 +172,7 @@ fn source_files_list_is_built_with_browse_remove_sort_and_open_files() {
|
|||
h.run_steps(4);
|
||||
assert!(matches!(asked.borrow()[0], FileDialogRequest::Open { multiple: true, .. }), "{:?}", asked.borrow());
|
||||
assert_eq!(listed(&h), ["b.png", "c.png"]);
|
||||
assert!(h.get_by_label("b.png").rect().bottom() <= h.get_by_label("c.png").rect().top(), "source files must be vertical rows");
|
||||
h.get_by_label("Browse…").click();
|
||||
h.run_steps(4);
|
||||
assert_eq!(listed(&h), ["b.png", "c.png", "a.png"], "b.png only once");
|
||||
|
|
|
|||
Loading…
Reference in New Issue