mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
Plug-ins: a file only an importer reads opens when dropped on the canvas
File › Place reads only built-in formats, so a dropped file that only an importer reads failed with a place error. It now opens as File › Open opens it, with or without a drop position, also when an exporter lists the same extension.
This commit is contained in:
@@ -132,8 +132,8 @@ use formats::{ARTBOARD, ARTBOARDS, RANGE, USE_ARTBOARDS, import_name, writable};
|
||||
pub use formats::{
|
||||
DOC_EXTS, DOCX_EXTS, FORMATS, Format, FormatOption, OPEN_EXTS, PLACE_EXTS, RTF_EXTS, TEXT_EXTS, UNASSOCIATED_EXTS, builtin_open_filters,
|
||||
export_extensions, extension, file_stem, format, format_for_name, has_own_title, importer_formats, library_open_filters, open_extensions,
|
||||
open_filters, opens_as_other, place_filters, plugin_formats, read_extensions, readable_format, readable_format_for_name, titled_for_export,
|
||||
writable_format,
|
||||
open_filters, opens_as_other, opens_with_importer, place_filters, plugin_formats, read_extensions, readable_format, readable_format_for_name,
|
||||
titled_for_export, writable_format,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -669,6 +669,13 @@ fn format_filters() -> impl Iterator<Item = (&'static str, &'static [&'static st
|
||||
FORMATS.iter().filter(|f| f.read).map(|f| (f.label, read_extensions(f)))
|
||||
}
|
||||
|
||||
/// Whether a file named `name` can only be read by an importer plug-in: an installed importer lists
|
||||
/// its extension and File › Place does not read that extension.
|
||||
pub fn opens_with_importer(name: &str) -> bool {
|
||||
let ext = extension(name);
|
||||
!ext.is_empty() && !PLACE_EXTS.contains(&ext.as_str()) && !vectorcraft_plugins::import::for_extension(&ext).is_empty()
|
||||
}
|
||||
|
||||
/// Whether File › Open opens a file of extension `ext` (lower case) as something other than a
|
||||
/// document: a plug-in (installed), a shortcut set, a script (checked), flattener, PDF, print,
|
||||
/// perspective grid or export presets (imported), a Libraries panel library, or a swatch or graphic
|
||||
|
||||
@@ -191,6 +191,32 @@ fn export_as_lists_exporters_and_not_importers() {
|
||||
app.run("plugin.remove", json!({"id": "test.ui.writes"})).unwrap();
|
||||
}
|
||||
|
||||
/// A file only an importer reads opens wherever it is dropped, also when an exporter lists its
|
||||
/// extension; a file File › Place reads is still placed on the canvas.
|
||||
#[test]
|
||||
fn a_dropped_file_only_an_importer_reads_opens() {
|
||||
use crate::place::DropTarget;
|
||||
let mut app = app();
|
||||
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
|
||||
app.sync_views();
|
||||
app.canvas_rect = Some(egui::Rect::from_min_size(egui::pos2(0.0, 0.0), egui::vec2(800.0, 600.0)));
|
||||
let on_canvas = Some(egui::pos2(400.0, 300.0));
|
||||
let placed = |app: &VectorcraftApp, name, pos| matches!(app.drop_target(name, pos, false), DropTarget::Place(_));
|
||||
assert!(placed(&app, "a.tud", on_canvas), "no importer lists the extension yet");
|
||||
|
||||
install(&mut app, &tpl::module(&tpl::importer("test.ui.dropped", r#"["tud","tus","png"]"#, "{}"), tpl::ECHO, "", 1));
|
||||
install(&mut app, &tpl::module(&tpl::exporter("test.ui.dropshare", r#"["tus"]"#, "{}"), tpl::ECHO, "", 1));
|
||||
for name in ["a.tud", "A.TUD", "a.tus"] {
|
||||
assert_eq!(app.drop_target(name, on_canvas, false), DropTarget::Open, "{name} on the canvas");
|
||||
assert_eq!(app.drop_target(name, None, false), DropTarget::Open, "{name} without a position");
|
||||
}
|
||||
assert!(placed(&app, "a.png", on_canvas), "File › Place reads the extension");
|
||||
assert!(placed(&app, "a.png", None));
|
||||
|
||||
app.run("plugin.remove", json!({"id": "test.ui.dropped"})).unwrap();
|
||||
app.run("plugin.remove", json!({"id": "test.ui.dropshare"})).unwrap();
|
||||
}
|
||||
|
||||
/// The extensions File › Open's filters leave out of importers' (`fileio::opens_as_other`) are the
|
||||
/// ones File › Open installs, imports, checks or loads as something other than a document.
|
||||
#[test]
|
||||
|
||||
@@ -444,12 +444,12 @@ impl VectorcraftApp {
|
||||
/// onto the canvas of the open document (Shift embeds it), else opened. Where the platform
|
||||
/// doesn't say (`None`: desktop drags carry no position), a document opens as a tab of its
|
||||
/// own and a picture or text is placed in the middle of the view. A library, a presets file, a
|
||||
/// plug-in, a shortcut set or a script opens wherever it is dropped, as File → Open opens it
|
||||
/// ([`io::opens_as`]).
|
||||
/// plug-in, a shortcut set, a script or a file only an importer plug-in reads opens wherever it
|
||||
/// is dropped, as File → Open opens it ([`io::opens_as`], [`fileio::opens_with_importer`]).
|
||||
pub fn drop_target(&self, name: &str, pos: Option<egui::Pos2>, shift: bool) -> DropTarget {
|
||||
let (Some(rect), Some(st), Some(v)) = (self.canvas_rect, self.session.active(), self.view()) else { return DropTarget::Open };
|
||||
let at = match pos {
|
||||
_ if io::opens_as(name).is_some() => return DropTarget::Open,
|
||||
_ if io::opens_as(name).is_some() || fileio::opens_with_importer(name) => return DropTarget::Open,
|
||||
Some(p) if !rect.contains(p) => return DropTarget::Open,
|
||||
Some(p) => crate::canvas::Xf::new(rect, v).to_doc(p),
|
||||
None if is_document(name) => return DropTarget::Open,
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ one whose id sorts first opens it. `document.open {"importer": "plugin.<id>", "p
|
||||
which must list the file's extension, also one a built-in format reads (an importer that lists `svg` opens an `.svg`
|
||||
only this way). A damaged file of a built-in format reports that format's error, and the file is not handed to an
|
||||
importer. The importer's objects become a new document whose artboard is their bounds (at least 1 pt wide and high,
|
||||
and within ±4,000,000 pt); the document keeps no path, so Save asks for a name. File › Place reads only the built-in formats. These rules are
|
||||
and within ±4,000,000 pt); the document keeps no path, so Save asks for a name. File › Place reads only the built-in formats, and a file only an importer reads opens as a new document when it is dropped on the canvas. These rules are
|
||||
VectorCraft's own.
|
||||
|
||||
In the app, installed filters appear under **Object › Plug-ins**, next to **Install Plug-in…** and **Reload
|
||||
|
||||
Reference in New Issue
Block a user