mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
Fix #5236: Edit Original is one checkbox, Use System Defaults for Edit Original
Per review on #5327: Preferences › File Handling › Edit Original With (an app path and Choose…) becomes the checkbox Use System Defaults for Edit Original, on by default. Off, Edit Original opens a raster image in the app that made it, PhotoCraft, looked for only where it installs; any other file, or no PhotoCraft, goes to the system's default app. The preference is a boolean, so prefs.set over control or MCP can no longer name an executable. The label has a row in all 26 catalogs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Opus 5.5
parent
79c8d1a7e0
commit
d7aa1c561f
@@ -300,8 +300,8 @@ pub(crate) fn services(parent: Parent, ui: egui::Context) -> Services {
|
||||
reveal: Some(Box::new(reveal)),
|
||||
// Links panel: Edit Original; Package: Show Package. Relink to Folder and Package pick folders.
|
||||
open_file: Some(Box::new(open_file)),
|
||||
// Edit Original with Preferences › File Handling › Edit Original With set (#5236).
|
||||
open_file_with: Some(Box::new(open_file_with)),
|
||||
// Edit Original of a raster image with Use System Defaults for Edit Original off (#5236).
|
||||
open_in_photocraft: Some(Box::new(open_in_photocraft)),
|
||||
pick_folder: Some(Box::new(move || pick_now(PickRequest::Folder, &p4).into_iter().next())),
|
||||
// Sample Color from Screen: the system's color sampler.
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -337,14 +337,14 @@ fn open_file(path: &str) -> Result<(), String> {
|
||||
c.spawn().map(|_| ()).map_err(|e| format!("can't open {path}: {e}"))
|
||||
}
|
||||
|
||||
/// Edit Original with Preferences › File Handling › Edit Original With set (#5236): open `path` in
|
||||
/// `app` (`photocraft`, or an application's path). The app must be an application ([`check_app`]);
|
||||
/// it gets the path as its only argument and is never started through a shell.
|
||||
fn open_file_with(app: &str, path: &str) -> Result<(), String> {
|
||||
/// Edit Original with Preferences › File Handling › Use System Defaults for Edit Original off
|
||||
/// (#5236): open the raster image `path` in PhotoCraft, found only where it installs
|
||||
/// ([`find_photocraft`]); `Ok(false)` when it isn't installed. PhotoCraft gets the path as its only
|
||||
/// argument and is never started through a shell.
|
||||
fn open_in_photocraft(path: &str) -> Result<bool, String> {
|
||||
explorer_safe(path)?;
|
||||
let home = std::env::var_os(if cfg!(windows) { "USERPROFILE" } else { "HOME" }).map(std::path::PathBuf::from);
|
||||
let app = resolve_app(app, home.as_deref(), std::env::var_os("PATH").as_deref())?;
|
||||
check_app(&app)?;
|
||||
let Some(app) = find_photocraft(home.as_deref(), std::env::var_os("PATH").as_deref()) else { return Ok(false) };
|
||||
#[cfg(target_os = "macos")]
|
||||
let mut c = {
|
||||
let mut c = std::process::Command::new("open");
|
||||
@@ -369,7 +369,7 @@ fn open_file_with(app: &str, path: &str) -> Result<(), String> {
|
||||
let started = std::time::Instant::now();
|
||||
loop {
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) if status.success() => return Ok(()),
|
||||
Ok(Some(status)) if status.success() => return Ok(true),
|
||||
Ok(Some(status)) => {
|
||||
let mut why = String::new();
|
||||
if let Some(mut err) = child.stderr.take() {
|
||||
@@ -385,26 +385,19 @@ fn open_file_with(app: &str, path: &str) -> Result<(), String> {
|
||||
std::thread::spawn(move || {
|
||||
let _ = child.wait();
|
||||
});
|
||||
return Ok(());
|
||||
return Ok(true);
|
||||
}
|
||||
Err(e) => return Err(fail(e.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
c.spawn().map(|_| ()).map_err(|e| format!("can't open {path} in {}: {e}", app.display()))
|
||||
c.spawn().map(|_| true).map_err(|e| format!("can't open {path} in {}: {e}", app.display()))
|
||||
}
|
||||
|
||||
/// The application Edit Original With names: PhotoCraft where it is installed for `photocraft`
|
||||
/// ([`photocraft_candidates`]), else the path as given.
|
||||
pub(crate) fn resolve_app(app: &str, home: Option<&std::path::Path>, path_var: Option<&std::ffi::OsStr>) -> Result<std::path::PathBuf, String> {
|
||||
if app.trim().eq_ignore_ascii_case("photocraft") {
|
||||
return photocraft_candidates(home, path_var)
|
||||
.into_iter()
|
||||
.find(|p| check_app(p).is_ok())
|
||||
.ok_or_else(|| "PhotoCraft isn't installed: choose another app in Preferences › File Handling › Edit Original With".to_string());
|
||||
}
|
||||
Ok(std::path::PathBuf::from(app.trim()))
|
||||
/// PhotoCraft where it is installed: the first of [`photocraft_candidates`] that is an application.
|
||||
pub(crate) fn find_photocraft(home: Option<&std::path::Path>, path_var: Option<&std::ffi::OsStr>) -> Option<std::path::PathBuf> {
|
||||
photocraft_candidates(home, path_var).into_iter().find(|p| check_app(p).is_ok())
|
||||
}
|
||||
|
||||
/// Where PhotoCraft may be installed: the Applications folders on macOS, else a `photocraft`
|
||||
@@ -421,7 +414,7 @@ pub(crate) fn photocraft_candidates(home: Option<&std::path::Path>, path_var: Op
|
||||
|
||||
/// Is `app` an application Edit Original may start: an `.app` bundle on macOS, an `.exe` on
|
||||
/// Windows, an executable file elsewhere? Anything else (a document, a folder, a script on
|
||||
/// Windows) is refused, so the preference can only ever open an installed app.
|
||||
/// Windows) found where PhotoCraft installs is not taken for it.
|
||||
pub(crate) fn check_app(app: &std::path::Path) -> Result<(), String> {
|
||||
let ext = app.extension().map(|e| e.to_string_lossy().to_ascii_lowercase()).unwrap_or_default();
|
||||
let ok = if cfg!(target_os = "macos") {
|
||||
@@ -447,7 +440,7 @@ fn executable_file(p: &std::path::Path) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
mod open_with_tests {
|
||||
use super::{check_app, photocraft_candidates, resolve_app};
|
||||
use super::{check_app, find_photocraft, photocraft_candidates};
|
||||
|
||||
/// A fresh, empty folder under the system's temporary folder.
|
||||
fn scratch(name: &str) -> std::path::PathBuf {
|
||||
@@ -457,8 +450,8 @@ mod open_with_tests {
|
||||
d
|
||||
}
|
||||
|
||||
/// #5236: Edit Original With only ever starts an application, never a document, a folder or a
|
||||
/// missing path.
|
||||
/// #5236: only an application counts as PhotoCraft, never a document, a folder or a missing
|
||||
/// path.
|
||||
#[test]
|
||||
fn only_applications_are_started() {
|
||||
let d = scratch("check");
|
||||
@@ -484,22 +477,21 @@ mod open_with_tests {
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
}
|
||||
|
||||
/// `photocraft` is looked for where PhotoCraft installs; any other value is taken as a path.
|
||||
/// PhotoCraft is looked for only where it installs.
|
||||
#[test]
|
||||
fn photocraft_is_found_where_it_installs() {
|
||||
let d = scratch("find");
|
||||
assert_eq!(resolve_app("/Apps/Other.app", None, None).unwrap(), std::path::PathBuf::from("/Apps/Other.app"));
|
||||
if cfg!(target_os = "macos") {
|
||||
let candidates = photocraft_candidates(Some(&d), None);
|
||||
assert_eq!(candidates.first().map(|p| p.to_string_lossy().into_owned()).as_deref(), Some("/Applications/PhotoCraft.app"));
|
||||
assert!(candidates.contains(&d.join("Applications/PhotoCraft.app")), "{candidates:?}");
|
||||
std::fs::create_dir_all(d.join("Applications/PhotoCraft.app")).unwrap();
|
||||
assert!(resolve_app("PhotoCraft", Some(&d), None).unwrap().ends_with("PhotoCraft.app"));
|
||||
assert!(find_photocraft(Some(&d), None).unwrap().ends_with("PhotoCraft.app"));
|
||||
} else {
|
||||
let bin = d.join("bin");
|
||||
std::fs::create_dir_all(&bin).unwrap();
|
||||
let path_var = std::env::join_paths([&bin]).unwrap();
|
||||
assert!(resolve_app("photocraft", None, Some(&path_var)).is_err(), "not installed");
|
||||
assert!(find_photocraft(None, Some(&path_var)).is_none(), "not installed");
|
||||
let exe = bin.join(if cfg!(windows) { "photocraft.exe" } else { "photocraft" });
|
||||
std::fs::write(&exe, "").unwrap();
|
||||
#[cfg(unix)]
|
||||
@@ -507,7 +499,7 @@ mod open_with_tests {
|
||||
use std::os::unix::fs::PermissionsExt as _;
|
||||
std::fs::set_permissions(&exe, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
}
|
||||
assert_eq!(resolve_app("photocraft", None, Some(&path_var)).unwrap(), exe);
|
||||
assert_eq!(find_photocraft(None, Some(&path_var)), Some(exe));
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
}
|
||||
|
||||
@@ -372,8 +372,8 @@ pub const PREF_SPECS: &[PrefSpec] = &[
|
||||
p!("newArtBasic", "General", "Appearance Panel", "New Art Has Basic Appearance", bool),
|
||||
// File Handling (continued)
|
||||
p!("templatesFolder", "File Handling", "Files", "Templates Folder", text),
|
||||
// "" (the system's default app), `photocraft` or an application's path (#5236).
|
||||
p!("editOriginalApp", "File Handling", "Files", "Edit Original With", text),
|
||||
// Off: raster images open in PhotoCraft where it is installed (#5236).
|
||||
p!("editOriginalSystemDefaults", "File Handling", "Files", "Use System Defaults for Edit Original", bool),
|
||||
p!("appendConverted", "File Handling", "Files", "Mark Older Files as [Converted] When Opened", bool),
|
||||
// Native saves (`document.save {compress}`)
|
||||
p!("useCompression", "File Handling", "Files", "Use Compression", bool),
|
||||
|
||||
@@ -253,10 +253,10 @@ pub struct Prefs {
|
||||
// File Handling (continued)
|
||||
/// Where Save as Template and New from Template start ("" = `Documents/VectorCraft Templates`).
|
||||
pub templates_folder: String,
|
||||
/// The app Links panel › Edit Original opens a linked file in (#5236): "" = the system's
|
||||
/// default app for the file, `photocraft` = PhotoCraft wherever it is installed, else the path
|
||||
/// of an application.
|
||||
pub edit_original_app: String,
|
||||
/// File Handling → Use System Defaults for Edit Original (#5236): Links panel › Edit Original
|
||||
/// opens a linked file in the system's default app for it; off, in the app that made it
|
||||
/// (PhotoCraft for a raster image, where it is installed; the system's app otherwise).
|
||||
pub edit_original_system_defaults: bool,
|
||||
/// Open older native files as "<name> [Converted]" so Save asks for a new name.
|
||||
pub append_converted: bool,
|
||||
/// File Handling → Use Compression: native saves are gzip-compressed (`document.save
|
||||
@@ -468,7 +468,7 @@ impl Default for Prefs {
|
||||
pdf_presets: vec![],
|
||||
screen_export_presets: vec![],
|
||||
templates_folder: String::new(),
|
||||
edit_original_app: String::new(),
|
||||
edit_original_system_defaults: true,
|
||||
append_converted: true,
|
||||
use_compression: false,
|
||||
web_export_presets: vec![],
|
||||
|
||||
@@ -1799,6 +1799,7 @@ font-technology Variable Променливи
|
||||
Manually Ръчно
|
||||
Mark as trapped Маркиране като прехванато
|
||||
Mark Older Files as [Converted] When Opened Маркиране на по-стари файлове като [Конвертирани] при отваряне
|
||||
Use System Defaults for Edit Original Системни настройки по подразбиране за „Редактиране на оригинал“
|
||||
Marker… Маркер…
|
||||
Marks Маркери
|
||||
Marks and Bleed Маркери и изтичане
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3560,6 +3560,7 @@ theme Appearance Izgled
|
||||
List Preferences Izlistaj postavke
|
||||
Manually Ručno
|
||||
Mark Older Files as [Converted] When Opened Označi starije datoteke kao [Pretvoreno] pri otvaranju
|
||||
Use System Defaults for Edit Original Koristi sistemske zadane postavke za Uredi original
|
||||
Match User Interface Brightness Uskladi sa svjetlinom korisničkog interfejsa
|
||||
Light Gray Svijetlosiva
|
||||
Medium Gray Srednje siva
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2330,6 +2330,7 @@ digits Malayalam Malaiàlam
|
||||
Manually Manualment
|
||||
Mark as trapped Marca com a reventat
|
||||
Mark Older Files as [Converted] When Opened Marca els fitxers antics com a [Convertit] en obrir-los
|
||||
Use System Defaults for Edit Original Utilitza els valors per defecte del sistema per a Edita l’original
|
||||
Marker… Marcador…
|
||||
Marks Marques
|
||||
Marks and Bleed Marques i sangrat
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3601,6 +3601,7 @@ theme Appearance Motiv
|
||||
List Preferences Vypsat předvolby
|
||||
Manually Ručně
|
||||
Mark Older Files as [Converted] When Opened Při otevření označit starší soubory jako [Converted]
|
||||
Use System Defaults for Edit Original Pro Upravit originál použít výchozí aplikace systému
|
||||
Match User Interface Brightness Odpovídat jasu uživatelského rozhraní
|
||||
Light Gray Světle šedá
|
||||
Medium Gray Středně šedá
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3328,6 +3328,7 @@ theme Appearance Udseende
|
||||
List Preferences Oplist indstillinger
|
||||
Manually Manuelt
|
||||
Mark Older Files as [Converted] When Opened Markér ældre filer som [konverteret] ved åbning
|
||||
Use System Defaults for Edit Original Anvend systemets standarder til Redigér original
|
||||
Match User Interface Brightness Match lysstyrken i brugergrænsefladen
|
||||
Light Gray Lysegrå
|
||||
Medium Gray Mellemgrå
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1861,6 +1861,7 @@ file-filter Templates Vorlagen
|
||||
Manually Manuell
|
||||
Mark as trapped Als überfüllt kennzeichnen
|
||||
Mark Older Files as [Converted] When Opened Ältere Dateien beim Öffnen als [Konvertiert] kennzeichnen
|
||||
Use System Defaults for Edit Original Systemstandards für „Original bearbeiten“ verwenden
|
||||
Marker… Markierung…
|
||||
Marks Marken
|
||||
Marks and Bleed Marken und Anschnitt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2651,6 +2651,7 @@ theme Appearance Εμφάνιση
|
||||
Manually Χειροκίνητα
|
||||
Mark as trapped Σήμανση ως επικαλυπτόμενου
|
||||
Mark Older Files as [Converted] When Opened Σήμανση παλαιότερων αρχείων ως [Μετατράπηκε] κατά το άνοιγμα
|
||||
Use System Defaults for Edit Original Χρήση προεπιλογών συστήματος για την Επεξεργασία πρωτοτύπου
|
||||
Marker… Δείκτης…
|
||||
Marks Σημάδια
|
||||
Marks and Bleed Σημάδια και ξάκρισμα
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 163 and column 5.
|
@@ -1864,6 +1864,7 @@ font-technology Variable Variables
|
||||
Manually Manualmente
|
||||
Mark as trapped Marcar como reventado
|
||||
Mark Older Files as [Converted] When Opened Marcar archivos antiguos como [Convertido] al abrirlos
|
||||
Use System Defaults for Edit Original Usar valores predeterminados del sistema para Editar original
|
||||
Marker… Marcador…
|
||||
Marks Marcas
|
||||
Marks and Bleed Marcas y sangrado
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3525,6 +3525,7 @@ theme Appearance Ulkoasu
|
||||
List Preferences Luettele asetukset
|
||||
Manually Manuaalisesti
|
||||
Mark Older Files as [Converted] When Opened Merkitse vanhemmat tiedostot [Muunnettu] avattaessa
|
||||
Use System Defaults for Edit Original Käytä järjestelmän oletuksia toiminnossa Muokkaa alkuperäistä
|
||||
Match User Interface Brightness Sovita käyttöliittymän kirkkauteen
|
||||
Light Gray Vaaleanharmaa
|
||||
Medium Gray Keskiharmaa
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1858,6 +1858,7 @@ font-technology Variable Variables
|
||||
Manually Manuellement
|
||||
Mark as trapped Marquer comme grossi-maigri
|
||||
Mark Older Files as [Converted] When Opened Marquer les anciens fichiers comme [Converti] à l’ouverture
|
||||
Use System Defaults for Edit Original Utiliser les applications par défaut du système pour Modifier l’original
|
||||
Marker… Marqueur…
|
||||
Marks Repères
|
||||
Marks and Bleed Repères et fond perdu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2351,6 +2351,7 @@ file-filter Templates Sablonok
|
||||
Manually Kézzel
|
||||
Mark as trapped Megjelölés csapdázottként
|
||||
Mark Older Files as [Converted] When Opened Régebbi fájlok megjelölése [Átalakítva] címkével megnyitáskor
|
||||
Use System Defaults for Edit Original Rendszer alapértelmezéseinek használata az Eredeti szerkesztéséhez
|
||||
Marker… Jelölő…
|
||||
Marks Jelek
|
||||
Marks and Bleed Jelek és kifutó
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3328,6 +3328,7 @@ theme Appearance Tampilan
|
||||
List Preferences Daftarkan preferensi
|
||||
Manually Secara manual
|
||||
Mark Older Files as [Converted] When Opened Tandai file lama sebagai [Converted] saat dibuka
|
||||
Use System Defaults for Edit Original Gunakan default sistem untuk Edit asli
|
||||
Match User Interface Brightness Sesuaikan dengan kecerahan antarmuka pengguna
|
||||
Light Gray Abu-abu terang
|
||||
Medium Gray Abu-abu sedang
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2211 and column 5.
|
@@ -1893,6 +1893,7 @@ file-filter Templates Modelli
|
||||
Manually Manualmente
|
||||
Mark as trapped Contrassegna come sottoposto a trapping
|
||||
Mark Older Files as [Converted] When Opened Contrassegna i file meno recenti come [Convertito] all'apertura
|
||||
Use System Defaults for Edit Original Usa le impostazioni predefinite di sistema per Modifica originale
|
||||
Marker… Indicatore…
|
||||
Marks Segni
|
||||
Marks and Bleed Segni e abbondanza
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2094,6 +2094,7 @@ digits Malayalam マラヤーラム数字
|
||||
Manage Workspaces ワークスペースを管理
|
||||
Manually 手動
|
||||
Mark Older Files as [Converted] When Opened 古いファイルを開くときに[変換]と表示
|
||||
Use System Defaults for Edit Original 「オリジナルを編集」にシステムのデフォルトを使用
|
||||
Mark as trapped トラップ済みとしてマーク
|
||||
Marks トンボ
|
||||
Match User Interface Brightness ユーザーインターフェイスの明るさに合わせる
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3138,6 +3138,7 @@ theme Appearance იერსახე
|
||||
List Preferences პარამეტრების სია
|
||||
Manually ხელით
|
||||
Mark Older Files as [Converted] When Opened ძველი ფაილების მარკირება როგორც [გარდაქმნილი] გახსნისას
|
||||
Use System Defaults for Edit Original სისტემის ნაგულისხმევის გამოყენება ორიგინალის რედაქტირებისთვის
|
||||
Match User Interface Brightness ინტერფეისის სიკაშკაშესთან შესაბამისობა
|
||||
Light Gray ღია ნაცრისფერი
|
||||
Medium Gray საშუალო ნაცრისფერი
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -2084,6 +2084,7 @@ digits Malayalam 말라얄람어
|
||||
Manage Workspaces 작업 영역 관리
|
||||
Manually 수동
|
||||
Mark Older Files as [Converted] When Opened 열 때 이전 파일을 [Converted]로 표시
|
||||
Use System Defaults for Edit Original 원본 편집에 시스템 기본값 사용
|
||||
Mark as trapped 트래핑됨으로 표시
|
||||
Marks 표시
|
||||
Match User Interface Brightness 사용자 인터페이스 밝기에 맞춤
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3342,6 +3342,7 @@ theme Appearance Vormgeving
|
||||
List Preferences Voorkeuren weergeven
|
||||
Manually Handmatig
|
||||
Mark Older Files as [Converted] When Opened Oudere bestanden bij het openen markeren als [geconverteerd]
|
||||
Use System Defaults for Edit Original Systeemstandaarden gebruiken voor Origineel bewerken
|
||||
Match User Interface Brightness Aanpassen aan helderheid van gebruikersinterface
|
||||
Light Gray Lichtgrijs
|
||||
Medium Gray Middelgrijs
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3464,6 +3464,7 @@ theme Appearance Wygląd
|
||||
List Preferences Wyświetl preferencje
|
||||
Manually Ręcznie
|
||||
Mark Older Files as [Converted] When Opened Oznaczaj starsze pliki jako [Przekonwertowane] przy otwieraniu
|
||||
Use System Defaults for Edit Original Używaj ustawień domyślnych systemu dla polecenia Edytuj oryginał
|
||||
Match User Interface Brightness Dopasuj do jasności interfejsu
|
||||
Light Gray Jasnoszary
|
||||
Medium Gray Średnio szary
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1585,6 +1585,7 @@
|
||||
Manage Workspaces… Gerenciar Espaços de Trabalho…
|
||||
Manually Manualmente
|
||||
Mark Older Files as [Converted] When Opened Marcar Arquivos Antigos como [Convertido] Ao Abrir
|
||||
Use System Defaults for Edit Original Usar Padrões do Sistema para Editar Original
|
||||
Mark as trapped Marcar como sobreimpresso
|
||||
Marker… Marcador…
|
||||
Marks Marcas
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1890,6 +1890,7 @@ file-filter Templates Шаблоны
|
||||
Manually Вручную
|
||||
Mark as trapped Пометить как треппинг
|
||||
Mark Older Files as [Converted] When Opened Помечать старые файлы как [Преобразованные] при открытии
|
||||
Use System Defaults for Edit Original Использовать системные значения по умолчанию для «Редактировать оригинал»
|
||||
Marker… Маркер…
|
||||
Marks Метки
|
||||
Marks and Bleed Метки и вылет
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1805,6 +1805,7 @@ font-technology Variable Variabla
|
||||
Manually Manuellt
|
||||
Mark as trapped Märk som överfyllt
|
||||
Mark Older Files as [Converted] When Opened Märk äldre filer som [Konverterad] när de öppnas
|
||||
Use System Defaults for Edit Original Använd systemets standardinställningar för Redigera original
|
||||
Marker… Markör…
|
||||
Marks Märken
|
||||
Marks and Bleed Märken och utfall
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -1699,6 +1699,7 @@ font-technology Variable Değişken
|
||||
Manually Manuel olarak
|
||||
Mark as trapped Sıkışmış olarak işaretle
|
||||
Mark Older Files as [Converted] When Opened Eski Dosyaları Açıldığında [Dönüştürülmüş] Olarak İşaretle
|
||||
Use System Defaults for Edit Original Orijinali Düzenle için Sistem Varsayılanlarını Kullan
|
||||
Marker… işaretleyici…
|
||||
Marks İşaretler
|
||||
Marks and Bleed İşaretler ve Taşma Payı
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -1887,6 +1887,7 @@ file-filter Templates Шаблони
|
||||
Manually Вручну
|
||||
Mark as trapped Позначити як трепінг
|
||||
Mark Older Files as [Converted] When Opened Помічати старі файли як [Перетворені] при відкритті
|
||||
Use System Defaults for Edit Original Використовувати системні типові програми для «Редагувати оригінал»
|
||||
Marker… Маркер…
|
||||
Marks Мітки
|
||||
Marks and Bleed Мітки та виліт
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 177 and column 5.
|
@@ -2172,6 +2172,7 @@ digits Hindi Hindi
|
||||
Manually Thủ công
|
||||
Mark as trapped Đánh dấu đã chồng màu
|
||||
Mark Older Files as [Converted] When Opened Đánh dấu tệp cũ là [Đã chuyển đổi] khi mở
|
||||
Use System Defaults for Edit Original Dùng mặc định hệ thống cho Chỉnh sửa bản gốc
|
||||
Marker… Ký hiệu đánh dấu…
|
||||
Marks Dấu in
|
||||
Marks and Bleed Dấu in và chảy tràn
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 199 and column 5.
|
@@ -1774,6 +1774,7 @@ file-filter Templates 模板
|
||||
Manually 手动
|
||||
Mark as trapped 标示为已陷印
|
||||
Mark Older Files as [Converted] When Opened 打开旧文件时标记为 [已转换]
|
||||
Use System Defaults for Edit Original “编辑原稿”使用系统默认设置
|
||||
Marker… 标记…
|
||||
Marks 标记
|
||||
Marks and Bleed 标记和出血
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2728,6 +2728,7 @@ file-filter Templates 範本
|
||||
Manually 手動
|
||||
Mark as trapped 標示為已陷印
|
||||
Mark Older Files as [Converted] When Opened 開啟舊檔時標示為 [已轉換]
|
||||
Use System Defaults for Edit Original 「編輯原稿」使用系統預設值
|
||||
Marker… 標記…
|
||||
Marks 標記
|
||||
Marks and Bleed 標記與出血
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -217,14 +217,20 @@ pub(crate) fn open_in_app(app: &mut VectorcraftApp, path: &str) -> Result<(), St
|
||||
app.services.open_file.as_mut().ok_or("no app to open files here")?(path)
|
||||
}
|
||||
|
||||
/// Edit Original: open `path` in the app Preferences › File Handling › Edit Original With names
|
||||
/// (#5236), or in the system's default app for it when that is System Default ("").
|
||||
/// Edit Original: open `path` in the system's default app for it, or with Preferences › File
|
||||
/// Handling › Use System Defaults for Edit Original off, in the app that made it (#5236): PhotoCraft
|
||||
/// for a raster image where it is installed. Any other file, or no PhotoCraft, uses the system's app.
|
||||
pub(crate) fn open_original(app: &mut VectorcraftApp, path: &str) -> Result<(), String> {
|
||||
let with = app.session.prefs.edit_original_app.trim().to_string();
|
||||
if with.is_empty() {
|
||||
return open_in_app(app, path);
|
||||
let ext = std::path::Path::new(path).extension().map(|e| e.to_string_lossy().into_owned()).unwrap_or_default();
|
||||
let raster = vectorcraft_engine::cmd::fileio::readable_format(&ext).is_some_and(|f| f.raster);
|
||||
if !app.session.prefs.edit_original_system_defaults
|
||||
&& raster
|
||||
&& let Some(open) = app.services.open_in_photocraft.as_mut()
|
||||
&& open(path)?
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
app.services.open_file_with.as_mut().ok_or("no app to open files in here")?(&with, path)
|
||||
open_in_app(app, path)
|
||||
}
|
||||
|
||||
/// File → Export for Screens with `document.exportForScreens` params: the files go into `folder`;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! The Links panel, its flyout, Link Info, Edit Original / Show in Folder, the Placement Options
|
||||
//! dialog and the Properties panel's image section, drawn headless.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
|
||||
use serde_json::json;
|
||||
@@ -168,44 +168,40 @@ fn edit_original_and_show_in_folder_hand_the_file_to_the_system() {
|
||||
assert!(app.run("links.editOriginal", json!({"id": linked})).is_err());
|
||||
}
|
||||
|
||||
/// #5236: Preferences › File Handling › Edit Original With picks the app Edit Original opens the
|
||||
/// file in: System Default ("") hands it to the system's default app as before, PhotoCraft or an
|
||||
/// application's path to that app.
|
||||
/// #5236: with Preferences › File Handling › Use System Defaults for Edit Original off, Edit
|
||||
/// Original opens a raster image in the app that made it, PhotoCraft, and falls back to the
|
||||
/// system's default app when PhotoCraft isn't installed or the file isn't a raster image.
|
||||
#[test]
|
||||
fn edit_original_opens_the_file_in_the_chosen_app() {
|
||||
/// What each open asked for: (the app, `None` for the system's default, and the path).
|
||||
type Opened = Rc<RefCell<Vec<(Option<String>, String)>>>;
|
||||
fn edit_original_opens_raster_images_in_photocraft_without_system_defaults() {
|
||||
/// What each open asked for: (`true` for PhotoCraft, the path).
|
||||
type Opened = Rc<RefCell<Vec<(bool, String)>>>;
|
||||
let dir = Folder::new("with");
|
||||
let (mut app, linked, _) = app(&dir);
|
||||
let opened: Opened = Rc::default();
|
||||
let (o, w) = (opened.clone(), opened.clone());
|
||||
let installed = Rc::new(Cell::new(true));
|
||||
let (o, w, i) = (opened.clone(), opened.clone(), installed.clone());
|
||||
app.services.open_file = Some(Box::new(move |p: &str| {
|
||||
o.borrow_mut().push((None, p.to_string()));
|
||||
o.borrow_mut().push((false, p.to_string()));
|
||||
Ok(())
|
||||
}));
|
||||
app.services.open_file_with = Some(Box::new(move |with: &str, p: &str| {
|
||||
w.borrow_mut().push((Some(with.to_string()), p.to_string()));
|
||||
Ok(())
|
||||
app.services.open_in_photocraft = Some(Box::new(move |p: &str| {
|
||||
if i.get() {
|
||||
w.borrow_mut().push((true, p.to_string()));
|
||||
}
|
||||
Ok(i.get())
|
||||
}));
|
||||
// On (the default): the system's app.
|
||||
let path = app.run("links.editOriginal", json!({"id": linked})).unwrap()["path"].as_str().unwrap().to_string();
|
||||
for value in ["photocraft", "/Applications/Example.app"] {
|
||||
app.run("prefs.set", json!({"key": "editOriginalApp", "value": value})).unwrap();
|
||||
app.run("links.editOriginal", json!({"id": linked})).unwrap();
|
||||
}
|
||||
app.run("prefs.set", json!({"key": "editOriginalApp", "value": ""})).unwrap();
|
||||
app.run("prefs.set", json!({"key": "editOriginalSystemDefaults", "value": false})).unwrap();
|
||||
app.run("links.editOriginal", json!({"id": linked})).unwrap();
|
||||
assert_eq!(
|
||||
*opened.borrow(),
|
||||
[
|
||||
(None, path.clone()),
|
||||
(Some("photocraft".into()), path.clone()),
|
||||
(Some("/Applications/Example.app".into()), path.clone()),
|
||||
(None, path.clone()),
|
||||
]
|
||||
);
|
||||
// An app the host can't open in (the web) is an error, not the default app instead.
|
||||
app.run("prefs.set", json!({"key": "editOriginalApp", "value": "photocraft"})).unwrap();
|
||||
app.services.open_file_with = None;
|
||||
installed.set(false);
|
||||
app.run("links.editOriginal", json!({"id": linked})).unwrap();
|
||||
installed.set(true);
|
||||
// A file that isn't a raster image goes to the system's app.
|
||||
crate::io::open_original(&mut app, "/Art/plan.emf").unwrap();
|
||||
assert_eq!(*opened.borrow(), [(false, path.clone()), (true, path.clone()), (false, path), (false, "/Art/plan.emf".to_string())]);
|
||||
// PhotoCraft failing to open it is said, not hidden behind the system's app.
|
||||
app.services.open_in_photocraft = Some(Box::new(|_: &str| Err("PhotoCraft didn't start".to_string())));
|
||||
assert!(app.run("links.editOriginal", json!({"id": linked})).is_err());
|
||||
assert_eq!(opened.borrow().len(), 4);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,6 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
let Some(mut d) = app.ui.dialog.clone() else { return };
|
||||
let t = Tokens::get(ctx);
|
||||
let (mut ok, mut cancel, mut reset) = (false, false, false);
|
||||
d.fields.insert(CAN_PICK_APP.into(), json!(crate::picks::can(app, &crate::picks::PickRequest::Open(app_pick()))));
|
||||
let cat = d.str("__category");
|
||||
let cat = PREF_CATEGORIES.iter().find(|c| **c == cat).copied().unwrap_or(PREF_CATEGORIES[0]);
|
||||
crate::dialogs::modal::show(ctx, tl!("Preferences"), egui::Id::unique("dialog-preferences"), -20.0, 20, |ui| {
|
||||
@@ -242,10 +241,6 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
for (k, v) in Prefs::default().to_json().as_object().cloned().unwrap_or_default() {
|
||||
d.fields.insert(k, v);
|
||||
}
|
||||
d.fields.remove(CHOSE_OTHER_APP);
|
||||
}
|
||||
if d.fields.remove(CHOOSE_APP).is_some() {
|
||||
choose_app(app, &mut d);
|
||||
}
|
||||
app.ui.dialog = Some(d);
|
||||
if cancel {
|
||||
@@ -385,7 +380,6 @@ fn category_fields(ui: &mut egui::Ui, d: &mut Dialog, cat: &str) {
|
||||
}
|
||||
});
|
||||
}
|
||||
PrefKind::Text if sp.key == "editOriginalApp" => edit_original_row(ui, d, sp.key, sp.label, &v),
|
||||
PrefKind::Text => {
|
||||
labeled(ui, sp.label, |ui| {
|
||||
let mut s = v.as_str().unwrap_or("").to_string();
|
||||
@@ -416,94 +410,6 @@ fn choice_row(ui: &mut egui::Ui, d: &mut Dialog, key: &str, label: &str, opts: &
|
||||
});
|
||||
}
|
||||
|
||||
/// File Handling › Edit Original With (#5236): System Default (""), PhotoCraft (`photocraft`) or
|
||||
/// Other Application, which shows a field for the application's path.
|
||||
fn edit_original_row(ui: &mut egui::Ui, d: &mut Dialog, key: &str, label: &str, v: &Value) {
|
||||
const OPTIONS: [&str; 3] = ["System Default", "PhotoCraft", "Other Application"];
|
||||
// The field shows the value as stored, spaces included (the host trims it when it opens).
|
||||
let raw = v.as_str().unwrap_or("").to_string();
|
||||
let cur = raw.trim().to_string();
|
||||
let photocraft = cur.eq_ignore_ascii_case("photocraft");
|
||||
// Other Application with no path typed yet is still System Default: the dialog remembers the
|
||||
// choice in a field of its own, which a new dialog and Reset Preferences start without.
|
||||
let mut other = !photocraft && (!cur.is_empty() || d.bool(CHOSE_OTHER_APP));
|
||||
// A path (saved or typed) also counts as the choice, so clearing it to type another keeps the
|
||||
// field.
|
||||
if other && !d.bool(CHOSE_OTHER_APP) {
|
||||
d.fields.insert(CHOSE_OTHER_APP.into(), json!(true));
|
||||
}
|
||||
let at = if photocraft {
|
||||
1
|
||||
} else if other {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
};
|
||||
labeled(ui, label, |ui| {
|
||||
if let Some(i) = widgets::dropdown(ui, key, OPTIONS[at], &OPTIONS, 260.0) {
|
||||
other = i == 2;
|
||||
d.fields.insert(CHOSE_OTHER_APP.into(), json!(other));
|
||||
let new = match i {
|
||||
0 => String::new(),
|
||||
1 => "photocraft".to_string(),
|
||||
_ if photocraft => String::new(),
|
||||
_ => raw.clone(),
|
||||
};
|
||||
d.fields.insert(key.into(), json!(new));
|
||||
}
|
||||
});
|
||||
if other {
|
||||
let can_pick = d.bool(CAN_PICK_APP);
|
||||
labeled(ui, "Application Path", |ui| {
|
||||
let mut s = if photocraft { String::new() } else { raw.clone() };
|
||||
let width = if can_pick { 186.0 } else { 260.0 };
|
||||
let field = egui::TextEdit::singleline(&mut s).align(egui::Align2::LEFT_CENTER).desired_width(width);
|
||||
let hint = if cfg!(target_os = "macos") { "/Applications/Example.app" } else { "" };
|
||||
if ui.add(field.hint_text(hint)).changed() {
|
||||
d.fields.insert(key.into(), json!(s));
|
||||
}
|
||||
// The open dialog runs from `show`, which has the app ([`choose_app`]).
|
||||
if can_pick && widgets::flat_button(ui, tl!("Choose…"), 68.0).clicked() {
|
||||
d.fields.insert(CHOOSE_APP.into(), json!(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// UI-only dialog fields for Edit Original With's Choose… button: whether the host shows an open
|
||||
/// dialog, and that the button was clicked this frame.
|
||||
const CAN_PICK_APP: &str = "__canPickApp";
|
||||
const CHOOSE_APP: &str = "__chooseApp";
|
||||
/// UI-only dialog field: Other Application was chosen, though no path is typed yet.
|
||||
const CHOSE_OTHER_APP: &str = "__choseOtherApp";
|
||||
|
||||
/// The open dialog Edit Original With's Choose… shows: applications (`.app` bundles in
|
||||
/// Applications on macOS, `.exe` files on Windows, any file elsewhere).
|
||||
fn app_pick() -> crate::FilePick {
|
||||
let filters: Vec<crate::FileFilter> = if cfg!(target_os = "macos") {
|
||||
vec![("Applications".into(), vec!["app".into()])]
|
||||
} else if cfg!(windows) {
|
||||
vec![("Programs".into(), vec!["exe".into()])]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let folder = cfg!(target_os = "macos").then(|| "/Applications".to_string());
|
||||
crate::FilePick { name: String::new(), folder, filters }
|
||||
}
|
||||
|
||||
/// Edit Original With › Choose…: the picked application into the dialog's `editOriginalApp`. Shown
|
||||
/// off the UI thread, the answer fills the dialog as it is then ([`crate::picks::in_dialog`]).
|
||||
fn choose_app(app: &mut VectorcraftApp, d: &mut Dialog) {
|
||||
let r = crate::picks::in_dialog(app, d, |app, d| {
|
||||
if let Some(path) = crate::picks::open(app, &app_pick()) {
|
||||
d.fields.insert("editOriginalApp".into(), json!(path));
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
// Picking a file doesn't fail.
|
||||
let _ = r;
|
||||
}
|
||||
|
||||
fn bool_row(ui: &mut egui::Ui, d: &mut Dialog, key: &str, label: &str) {
|
||||
// The app's outlined checkbox (it translates `label`): egui's own has no border at rest.
|
||||
let on = d.bool(key);
|
||||
|
||||
@@ -392,56 +392,17 @@ fn hyphenation_exceptions_dialog_ok_reaches_the_hyphenator() {
|
||||
assert_eq!(vectorcraft_text::hyphen::hyphen_points("happen"), vec![3]);
|
||||
}
|
||||
|
||||
/// #5236: File Handling › Edit Original With offers System Default, PhotoCraft and Other
|
||||
/// Application, whose Choose… puts the picked application into the preference.
|
||||
/// #5236: File Handling › Use System Defaults for Edit Original is a checkbox, on by default, and
|
||||
/// OK saves it off.
|
||||
#[test]
|
||||
fn edit_original_with_takes_a_chosen_application() {
|
||||
fn use_system_defaults_for_edit_original_is_a_checkbox() {
|
||||
let mut a = VectorcraftApp::new(Session::new(), Default::default());
|
||||
assert!(a.session.prefs.edit_original_system_defaults, "on by default");
|
||||
open(&mut a, Some("File Handling"));
|
||||
let text = crate::tests_labels::painted_text(&mut a, |a, ui| show(a, ui.ctx()));
|
||||
assert!(text.contains("Edit Original With") && text.contains("System Default"), "{text}");
|
||||
let asked: std::rc::Rc<std::cell::RefCell<Vec<crate::FilePick>>> = Default::default();
|
||||
let seen = asked.clone();
|
||||
a.services.pick_open = Some(Box::new(move |p: &crate::FilePick| {
|
||||
seen.borrow_mut().push(p.clone());
|
||||
Some("/Applications/Editor.app".into())
|
||||
}));
|
||||
let mut d = a.ui.dialog.clone().unwrap();
|
||||
choose_app(&mut a, &mut d);
|
||||
assert_eq!(d.str("editOriginalApp"), "/Applications/Editor.app");
|
||||
let pick = asked.borrow()[0].clone();
|
||||
if cfg!(target_os = "macos") {
|
||||
assert_eq!((pick.folder.as_deref(), pick.filters[0].1.clone()), (Some("/Applications"), vec!["app".to_string()]));
|
||||
}
|
||||
// OK saves it; the dialog's own fields (`__…`) are not preferences.
|
||||
a.ui.dialog = Some(d);
|
||||
assert!(text.contains("Use System Defaults for Edit Original"), "{text}");
|
||||
assert!(a.ui.dialog.as_ref().unwrap().bool("editOriginalSystemDefaults"));
|
||||
a.ui.dialog.as_mut().unwrap().fields.insert("editOriginalSystemDefaults".into(), json!(false));
|
||||
confirm(&mut a).unwrap();
|
||||
assert_eq!(a.session.prefs.edit_original_app, "/Applications/Editor.app");
|
||||
}
|
||||
|
||||
/// #5327 review: choosing Other Application before a path is typed is remembered by the dialog
|
||||
/// itself, so a dialog opened again (or reset) starts at System Default, and a stored path keeps
|
||||
/// its spaces.
|
||||
#[test]
|
||||
fn edit_original_with_other_is_the_dialogs_own_choice() {
|
||||
let mut a = VectorcraftApp::new(Session::new(), Default::default());
|
||||
open(&mut a, Some("File Handling"));
|
||||
assert!(!a.ui.dialog.as_ref().unwrap().bool(CHOSE_OTHER_APP), "a new dialog starts without the choice");
|
||||
let shown = |a: &mut VectorcraftApp| crate::tests_labels::painted_text(a, |a, ui| show(a, ui.ctx())).contains("Application Path");
|
||||
assert!(!shown(&mut a), "System Default shows no path field");
|
||||
a.ui.dialog.as_mut().unwrap().fields.insert(CHOSE_OTHER_APP.into(), json!(true));
|
||||
assert!(shown(&mut a), "Other Application with no path yet shows the field");
|
||||
a.ui.dialog = None;
|
||||
open(&mut a, Some("File Handling"));
|
||||
assert!(!shown(&mut a), "opened again: System Default");
|
||||
// A saved path counts as the choice: clearing it to type another keeps the field.
|
||||
a.ui.dialog.as_mut().unwrap().fields.insert("editOriginalApp".into(), json!("/Applications/Old.app"));
|
||||
assert!(shown(&mut a));
|
||||
a.ui.dialog.as_mut().unwrap().fields.insert("editOriginalApp".into(), json!(""));
|
||||
assert!(shown(&mut a), "the path cleared: still Other Application");
|
||||
// A path with spaces is kept as typed.
|
||||
let path = "/Applications/Visual Studio Code.app";
|
||||
a.ui.dialog.as_mut().unwrap().fields.insert("editOriginalApp".into(), json!(path));
|
||||
confirm(&mut a).unwrap();
|
||||
assert_eq!(a.session.prefs.edit_original_app, path);
|
||||
assert!(!a.session.prefs.edit_original_system_defaults);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ pub(crate) fn browsable_url(url: &str) -> Result<(), String> {
|
||||
/// Shows a file in the system file manager, or opens it in its app.
|
||||
pub type RevealFn = Box<dyn FnMut(&str) -> Result<(), String>>;
|
||||
|
||||
/// Opens a file in a chosen app: `(app, path)`.
|
||||
pub type OpenWithFn = Box<dyn FnMut(&str, &str) -> Result<(), String>>;
|
||||
/// Opens a file in a fixed app; `Ok(false)` when that app isn't installed.
|
||||
pub type OpenInFn = Box<dyn FnMut(&str) -> Result<bool, String>>;
|
||||
|
||||
/// Platform services injected by the host app (desktop or web).
|
||||
#[derive(Default)]
|
||||
@@ -119,10 +119,10 @@ pub struct Services {
|
||||
/// Open a file (or a folder) in the system's default app for it (desktop: Edit Original, Show
|
||||
/// Package). Without it (the web) those answer with an error.
|
||||
pub open_file: Option<RevealFn>,
|
||||
/// Open a file in a chosen app (desktop: Edit Original with Preferences › File Handling › Edit
|
||||
/// Original With set): `(app, path)`, where `app` is `photocraft` or an application's path.
|
||||
/// Without it (the web) Edit Original with an app set answers with an error.
|
||||
pub open_file_with: Option<OpenWithFn>,
|
||||
/// Open a file in PhotoCraft where it is installed (desktop: Edit Original of a raster image
|
||||
/// with Preferences › File Handling › Use System Defaults for Edit Original off); `Ok(false)`
|
||||
/// when it isn't. Without it Edit Original uses `open_file`.
|
||||
pub open_in_photocraft: Option<OpenInFn>,
|
||||
/// Show a folder picker; returns its path (desktop: Relink to Folder, Package).
|
||||
pub pick_folder: Option<Box<dyn FnMut() -> Option<String>>>,
|
||||
/// Show the system's color sampler, which picks a color anywhere on the screen (macOS, and
|
||||
|
||||
@@ -668,10 +668,10 @@ one undo step. The Links panel (`window.panel {panel: "links"}`) shows `links.li
|
||||
`links.info`; `links.editOriginal` and `links.reveal` (Edit › Edit Original, Show in Folder) hand the linked file to
|
||||
the system and return `{path}`. Edit Original opens only a regular file whose extension is a format `document.open`
|
||||
reads, and answers a control request with an error unless the file is a placed document (which opens in a tab).
|
||||
The preference `editOriginalApp` (Preferences › File Handling › Edit Original With, #5236) picks the app: `""` (System
|
||||
Default, the system's default app for the file), `"photocraft"` (PhotoCraft where it is installed) or an application's
|
||||
path. The app must be an application (an `.app` bundle on macOS, an `.exe` on Windows, an executable file elsewhere),
|
||||
and gets the file's path as its only argument.
|
||||
The preference `editOriginalSystemDefaults` (Preferences › File Handling › Use System Defaults for Edit Original, on
|
||||
by default, #5236) opens the file in the system's default app for it; off, in the app that made it: a raster image in
|
||||
PhotoCraft, looked for only where it installs (the Applications folders on macOS, the `PATH` elsewhere), and any other
|
||||
file, or a raster image without PhotoCraft installed, in the system's default app.
|
||||
|
||||
Package: File → Package… (`ui.packageDialog`) opens the `package` dialog for a saved document (a document never saved
|
||||
gets a `confirm` dialog whose OK runs `file.saveAs`). Fields: `folder` (the location), `name` (the package folder),
|
||||
|
||||
+3
-3
@@ -4216,9 +4216,9 @@ file is missing stays linked: relink it first); `links.unembed {id, path}` write
|
||||
clip?}` decides how a relinked or updated file takes an image's place (default `bounds`: stretched into the old
|
||||
bounds; `clip` puts it in a clip group of the old bounds when it is larger). The UI commands `links.editOriginal` and
|
||||
`links.reveal` open the linked file in its app or show it in its folder (desktop). Edit Original runs only from the app's window,
|
||||
except for a placed document, which opens in a tab. The preference `editOriginalApp` (Preferences › File Handling ›
|
||||
Edit Original With) picks the app Edit Original opens the file in: `""` (the system's default app), `"photocraft"` or an
|
||||
application's path (#5236).
|
||||
except for a placed document, which opens in a tab. With the preference `editOriginalSystemDefaults` (Preferences ›
|
||||
File Handling › Use System Defaults for Edit Original, on by default) off, Edit Original opens a raster image in the app
|
||||
that made it, PhotoCraft, where it is installed, and anything else in the system's default app (#5236).
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"links.list","params":{"show":"missing"}}}
|
||||
|
||||
Reference in New Issue
Block a user