mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Symbols: Window › Symbol Libraries opens symbol libraries whose symbols click into the document's Symbols
Window › Symbol Libraries and the Symbols panel's Symbol Libraries Menu open each symbol library in a library panel of its own, on the shared library panel code the swatch and graphic style libraries use (https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/create-or-import-symbol-libraries.html, .../symbols-panel-options.html, .../create-and-place-symbols.html). - Basic Shapes: one original library generated in code (circle, squares, triangle, diamond, hexagon, star, burst, arrow); no other app's libraries. - A click adds a library symbol to the document's Symbols as one undo step, with its Symbol Options and the resources it uses (nested symbols, patterns, swatches, brushes, graphic styles, images), and makes it the current symbol; one already there isn't added again, a clash of names numbers the library's. Shift/Cmd-clicks select for Add to Symbols. Dragging a library symbol onto the canvas adds it and places an instance there, in the same step. - Save Symbols… (library menu, Window menu) and Save Symbol Library… (Symbols panel menu) write the document's symbols as a .vectorcraft document holding only them, into the user library folder (User Defined, window.userSymbolLibrary1-10) or a file; Other Library… reads the symbols of any document VectorCraft opens, and a file it can't read is an error. Commands: symbol.libraries, symbol.library, symbol.addFromLibrary (place, x, y), symbol.saveLibrary, symbol.loadLibrary; UI: window.symbolLibrary (.other), ui.saveSymbolLibrary (dialog saveSymbolLibrary). i18n rows in every complete catalog; docs updated.
This commit is contained in:
committed by
bflatastic
parent
f247772042
commit
7da5e3062d
@@ -1024,11 +1024,13 @@ fn main() -> std::process::ExitCode {
|
||||
}
|
||||
// Linux may not map the window before the first frames, so a saved maximize is retried then (#3635).
|
||||
let pending_maximize = cfg!(target_os = "linux") && app.ui.window.as_ref().is_some_and(|g| g.maximized);
|
||||
// User Defined swatch and graphic style libraries live next to the preferences.
|
||||
// User Defined swatch, graphic style and symbol libraries live next to the preferences.
|
||||
let swatches = prefs_path().and_then(|p| Some(p.parent()?.join("Swatches").to_string_lossy().to_string()));
|
||||
app.session.swatch_libraries.set_user_dir(swatches);
|
||||
let styles = prefs_path().and_then(|p| Some(p.parent()?.join("Graphic Styles").to_string_lossy().to_string()));
|
||||
app.session.style_libraries.set_user_dir(styles);
|
||||
let symbols = prefs_path().and_then(|p| Some(p.parent()?.join("Symbols").to_string_lossy().to_string()));
|
||||
app.session.symbol_libraries.set_user_dir(symbols);
|
||||
// With the User Defined libraries listed, the persistent library panels reopen.
|
||||
vectorcraft_ui_egui::panels::library_panel::restore(&mut app);
|
||||
// So do the Libraries panel's libraries; runs without preferences (agents' test
|
||||
|
||||
@@ -22,7 +22,7 @@ use super::*;
|
||||
use crate::EngineError;
|
||||
|
||||
const SIZES_KEY: &str = vectorcraft_doc::SYMBOL_SIZES;
|
||||
const CURRENT_SYMBOL: &str = "currentSymbol";
|
||||
pub(crate) const CURRENT_SYMBOL: &str = "currentSymbol";
|
||||
/// Half the instance box `Node::geometric_bounds` uses for symbol instances.
|
||||
const HALF: f64 = vectorcraft_doc::SYMBOL_HALF;
|
||||
|
||||
@@ -727,7 +727,7 @@ fn brush_freehand(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
// ---------- symbols ----------
|
||||
|
||||
fn natural_size(d: &Document, name: &str) -> (f64, f64) {
|
||||
pub(crate) fn natural_size(d: &Document, name: &str) -> (f64, f64) {
|
||||
d.unknown
|
||||
.get(SIZES_KEY)
|
||||
.and_then(|m| m.get(name))
|
||||
@@ -735,7 +735,7 @@ fn natural_size(d: &Document, name: &str) -> (f64, f64) {
|
||||
.unwrap_or((2.0 * HALF, 2.0 * HALF))
|
||||
}
|
||||
|
||||
fn set_natural_size(d: &mut Document, name: &str, size: Option<(f64, f64)>) {
|
||||
pub(crate) fn set_natural_size(d: &mut Document, name: &str, size: Option<(f64, f64)>) {
|
||||
let m = d.unknown.entry(SIZES_KEY.to_string()).or_insert_with(|| json!({}));
|
||||
if let Some(o) = m.as_object_mut() {
|
||||
match size {
|
||||
@@ -746,7 +746,7 @@ fn set_natural_size(d: &mut Document, name: &str, size: Option<(f64, f64)>) {
|
||||
}
|
||||
|
||||
/// Instance transform for a symbol of natural size `(w, h)` whose registration point is at `at`.
|
||||
fn place_xf(at: Point, (w, h): (f64, f64), reg: SymbolRegistration) -> Affine {
|
||||
pub(crate) fn place_xf(at: Point, (w, h): (f64, f64), reg: SymbolRegistration) -> Affine {
|
||||
let c = at - reg.offset_from_center(w, h);
|
||||
Affine::translate(c.to_vec2()) * Affine::scale_non_uniform(w / (2.0 * HALF), h / (2.0 * HALF))
|
||||
}
|
||||
@@ -806,7 +806,7 @@ fn rename_natural_size(d: &mut Document, from: &str, to: &str) {
|
||||
}
|
||||
|
||||
/// Normalise art for a symbol definition: returns (art, natural size, centre in the document).
|
||||
fn normalize(mut art: Node) -> Result<(Node, (f64, f64), Point)> {
|
||||
pub(crate) fn normalize(mut art: Node) -> Result<(Node, (f64, f64), Point)> {
|
||||
let b = art.geometric_bounds().ok_or_else(|| EngineError::Other("the art has no bounds".into()))?;
|
||||
let (w, h) = (b.width().max(1.0), b.height().max(1.0));
|
||||
let c = b.center();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//! text besides it (see `flavours`).
|
||||
|
||||
mod flavours;
|
||||
mod resources;
|
||||
pub(crate) mod resources;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -500,7 +500,7 @@ impl Imported {
|
||||
|
||||
impl Clipboard {
|
||||
/// `nodes` (from `src`) and the resources of `src` they use.
|
||||
pub(super) fn gather(src: &Document, nodes: Vec<Node>) -> Self {
|
||||
pub(crate) fn gather(src: &Document, nodes: Vec<Node>) -> Self {
|
||||
let used = Used::of(&Defs::of(src), &nodes);
|
||||
let pick = |r: Res, list: &[TextStyleDef]| list.iter().filter(|s| used.has(r, &s.name)).cloned().collect::<Vec<_>>();
|
||||
let brushes = match used.names.get(&Res::Brush) {
|
||||
|
||||
@@ -79,6 +79,7 @@ mod style;
|
||||
pub mod stylelib;
|
||||
mod swatch;
|
||||
pub mod swatchlib;
|
||||
pub mod symbollib;
|
||||
pub(crate) mod tabs;
|
||||
mod textedit;
|
||||
pub mod textstyles;
|
||||
@@ -267,6 +268,7 @@ pub fn command_specs() -> &'static [CommandSpec] {
|
||||
v.extend(freeform::specs());
|
||||
v.extend(flatten::specs());
|
||||
v.extend(stylelib::specs());
|
||||
v.extend(symbollib::specs());
|
||||
v.extend(library::specs());
|
||||
v.extend(expand::specs());
|
||||
v.extend(attributes::specs());
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
//! Symbol libraries (Window → Symbol Libraries, the Symbols panel's library button): read-only sets
|
||||
//! of symbols the library panel shows. A library is a document holding the symbols with the
|
||||
//! resources they use (nested symbols, patterns, swatches, brushes, graphic styles, images) and
|
||||
//! their Symbol Options; saved, it is a native `.vectorcraft` file, which File › Open also opens.
|
||||
//! The built-in library is generated here ([`BUILTIN`]); User Defined ones are the `.vectorcraft`
|
||||
//! files in the user library folder ([`Libraries`]), and Other Library… loads the symbols of any
|
||||
//! document VectorCraft opens. `symbol.addFromLibrary` copies symbols into the document;
|
||||
//! `symbol.saveLibrary` writes the document's.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::{Color, Paint};
|
||||
use vectorcraft_doc::{Appearance, Document, Node, NodeId, NodeKind, Symbol};
|
||||
use vectorcraft_geom::{Affine, Point, Rect, shapes};
|
||||
|
||||
use super::brushsym::{CURRENT_SYMBOL, natural_size, normalize, place_xf, set_natural_size};
|
||||
use super::clipboard::Clipboard;
|
||||
use super::clipboard::resources::SwatchChoices;
|
||||
use super::swatch::str_list;
|
||||
use super::swatchlib::{FileData, LibraryFile, LibraryInfo, stem};
|
||||
use super::*;
|
||||
|
||||
/// The extension of saved symbol libraries: native documents.
|
||||
pub const SYMBOLS_EXT: &str = vectorcraft_format::EXTENSION;
|
||||
|
||||
pub fn specs() -> Vec<CommandSpec> {
|
||||
vec![
|
||||
cmd!(
|
||||
query "symbol.libraries",
|
||||
"Symbol Libraries",
|
||||
[],
|
||||
None,
|
||||
"{} → {libraries: [{id, name, category: \"builtIn\"|\"user\" (User Defined: the .vectorcraft files in the user library folder, rescanned now)|\"loaded\" (symbol.loadLibrary), count, path?}], userFolder} every symbol library the library panel opens, in menu order",
|
||||
always,
|
||||
list
|
||||
),
|
||||
cmd!(
|
||||
query "symbol.library",
|
||||
"Symbol Library",
|
||||
[],
|
||||
None,
|
||||
"{library: id or name} → {id, name, category, symbols: [{name, size: [w, h], registration: 0..8, exportType}] (as symbol.list)}",
|
||||
always,
|
||||
get
|
||||
),
|
||||
cmd!(
|
||||
"symbol.addFromLibrary",
|
||||
"Add to Symbols",
|
||||
["Window", "Symbol Libraries"],
|
||||
None,
|
||||
"{library: id or name, name? | names?: [symbol names in the library] (default: all of it), place?: false (also place an instance of the first one, its registration point at x, y: default the first artboard's centre), x?, y?, swatchConflict? (as edit.paste)} copy library symbols into the document's Symbols as one undo step (with the place), with their Symbol Options and the resources they use (the symbols they nest, patterns, swatches, brushes, graphic styles, images). A symbol the document already has (same name and art) isn't added again; a name another symbol has gets a number (\"Star 2\"). The first one becomes the current symbol → {library, names: [each symbol's name in the document], added: [names added], existing: [names already there], placed?: id}",
|
||||
has_doc,
|
||||
add
|
||||
),
|
||||
cmd!(
|
||||
"symbol.saveLibrary",
|
||||
"Save Symbol Library…",
|
||||
["Window", "Symbols"],
|
||||
None,
|
||||
"{path?, names?: [symbol names] (default: all), name?: library name (default: the document's), user?: false (save into the user library folder, listed under User Defined)} save the document's symbols, with their Symbol Options and the resources they use, as a symbol library: a .vectorcraft document holding only them → {path, count, library?: id when saved to the user folder}; without path or user → {dataBase64: the file's bytes, count}",
|
||||
has_doc,
|
||||
save
|
||||
),
|
||||
cmd!(
|
||||
"symbol.loadLibrary",
|
||||
"Other Library…",
|
||||
["Window", "Symbol Libraries"],
|
||||
None,
|
||||
"{path? | data?: file text | dataBase64?, name?: file name (default: the path's)} load the symbols of any document VectorCraft opens (see document.formats), a saved symbol library included, for the library panel (Window → Symbol Libraries lists it until the app quits; a file of the user library folder, or a file with the same bytes as one there, opens as that User Defined library) → {library: id, name, count}",
|
||||
always,
|
||||
load
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// A symbol library: its name and a document holding its symbols (in panel order) with the
|
||||
/// resources they use and their Symbol Options; the document has no art of its own.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SymbolLibrary {
|
||||
pub name: String,
|
||||
pub doc: Document,
|
||||
}
|
||||
|
||||
impl Default for SymbolLibrary {
|
||||
fn default() -> Self {
|
||||
Self { name: String::new(), doc: Document::new(100.0, 100.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolLibrary {
|
||||
pub fn len(&self) -> usize {
|
||||
self.doc.symbols.len()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.doc.symbols.is_empty()
|
||||
}
|
||||
pub fn symbol(&self, name: &str) -> Option<&Symbol> {
|
||||
self.doc.symbols.iter().find(|s| s.name == name)
|
||||
}
|
||||
|
||||
/// Document `src`'s symbols `names` (empty: all of them, in panel order) as a library named
|
||||
/// `name`: the symbols, the symbols they nest and every other resource they use, with their
|
||||
/// Symbol Options.
|
||||
pub fn from_document(src: &Document, names: &[String], name: String) -> std::result::Result<Self, String> {
|
||||
if let Some(n) = names.iter().find(|n| !src.symbols.iter().any(|s| s.name == **n)) {
|
||||
return Err(format!("no symbol `{n}`"));
|
||||
}
|
||||
let picked = src.symbols.iter().filter(|s| names.is_empty() || names.contains(&s.name));
|
||||
let clip = Clipboard::gather(src, picked.map(|s| instance(&s.name)).collect());
|
||||
let mut doc = clip.to_document();
|
||||
for l in &mut doc.layers {
|
||||
if let Some(ch) = Arc::make_mut(l).children_mut() {
|
||||
ch.clear();
|
||||
}
|
||||
}
|
||||
// The panel order of the document they came from.
|
||||
let order = |n: &str| src.symbols.iter().position(|s| s.name == n);
|
||||
doc.symbols.sort_by_key(|s| order(&s.name));
|
||||
for s in &doc.symbols.clone() {
|
||||
copy_options(src, &s.name, &mut doc, &s.name);
|
||||
}
|
||||
doc.title = name.clone();
|
||||
Ok(Self { name, doc })
|
||||
}
|
||||
}
|
||||
|
||||
impl LibraryFile for SymbolLibrary {
|
||||
const EXTS: &'static [&'static str] = &[SYMBOLS_EXT];
|
||||
fn read(bytes: &[u8], stem: &str) -> std::result::Result<Self, String> {
|
||||
let doc = vectorcraft_format::load(bytes).map_err(|e| e.to_string())?;
|
||||
SymbolLibrary::from_document(&doc, &[], stem.to_string())
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
/// User Defined and loaded symbol libraries.
|
||||
pub type Libraries = super::swatchlib::Libraries<SymbolLibrary>;
|
||||
|
||||
/// A library generated in code.
|
||||
pub struct BuiltinSymbolLibrary {
|
||||
pub id: &'static str,
|
||||
pub name: &'static str,
|
||||
make: fn() -> SymbolLibrary,
|
||||
}
|
||||
|
||||
/// The built-in symbol libraries, in menu order: original art generated in code.
|
||||
pub const BUILTIN: &[BuiltinSymbolLibrary] = &[BuiltinSymbolLibrary { id: "basic-shapes", name: "Basic Shapes", make: basic_shapes }];
|
||||
|
||||
/// Built-in library `id`, made once.
|
||||
fn builtin_library(id: &str) -> Option<Arc<SymbolLibrary>> {
|
||||
static MADE: LazyLock<Vec<Arc<SymbolLibrary>>> = LazyLock::new(|| BUILTIN.iter().map(|b| Arc::new((b.make)())).collect());
|
||||
BUILTIN.iter().position(|b| b.id == id).and_then(|i| MADE.get(i).cloned())
|
||||
}
|
||||
|
||||
/// Basic Shapes: plain filled and outlined shapes, 40 pt (the arrow 48 × 32 pt).
|
||||
fn basic_shapes() -> SymbolLibrary {
|
||||
let square = Rect::new(-20.0, -20.0, 20.0, 20.0);
|
||||
let c = Point::ZERO;
|
||||
let arrow = [(-24.0, -6.0), (4.0, -6.0), (4.0, -16.0), (24.0, 0.0), (4.0, 16.0), (4.0, 6.0), (-24.0, 6.0)];
|
||||
let arrow: Vec<Point> = arrow.iter().map(|&(x, y)| Point::new(x, y)).collect();
|
||||
let shapes = [
|
||||
("Circle", shapes::ellipse(square), "#2f80c9"),
|
||||
("Square", shapes::rectangle(square), "#d9534f"),
|
||||
("Rounded Square", shapes::rounded_rectangle(square, 8.0), "#f0ad4e"),
|
||||
("Triangle", shapes::polygon(c, 22.0, 3, 0.0), "#5cb85c"),
|
||||
("Diamond", shapes::polygon(c, 20.0, 4, 0.0), "#8e5bc6"),
|
||||
("Hexagon", shapes::polygon(c, 20.0, 6, 0.0), "#1fa39b"),
|
||||
("Star", shapes::star(c, 21.0, 9.0, 5, 0.0), "#f2c233"),
|
||||
("Burst", shapes::star(c, 21.0, 15.0, 12, 0.0), "#e8743b"),
|
||||
("Arrow", vectorcraft_geom::PathData::single(vectorcraft_geom::SubPath::polyline(&arrow, true)), "#4a5a6a"),
|
||||
];
|
||||
let mut doc = Document::new(100.0, 100.0);
|
||||
for (name, path, hex) in shapes {
|
||||
let fill = Color::from_hex(hex).unwrap_or(Color::BLACK);
|
||||
// The outline: the fill, darkened.
|
||||
let edge = fill.lerp(&Color::BLACK, 0.4);
|
||||
let id = doc.alloc_id();
|
||||
let art = Node::path(id, path, Appearance::basic(Paint::solid(fill), Paint::solid(edge), 1.0));
|
||||
let Ok((art, size, _)) = normalize(art) else { continue };
|
||||
doc.symbols.push(Symbol { name: name.into(), art: Arc::new(art) });
|
||||
set_natural_size(&mut doc, name, Some(size));
|
||||
}
|
||||
doc.title = "Basic Shapes".into();
|
||||
SymbolLibrary { name: "Basic Shapes".into(), doc }
|
||||
}
|
||||
|
||||
/// An instance of symbol `name` (what the resource gathering follows).
|
||||
fn instance(name: &str) -> Node {
|
||||
Node::new(NodeId(0), NodeKind::SymbolInstance { symbol: name.into(), xf: Affine::IDENTITY })
|
||||
}
|
||||
|
||||
/// Symbol `from`'s Symbol Options in `src` (natural size, registration, export type, 9-slice
|
||||
/// guides) given to symbol `to` of `d`.
|
||||
fn copy_options(src: &Document, from: &str, d: &mut Document, to: &str) {
|
||||
set_natural_size(d, to, Some(natural_size(src, from)));
|
||||
d.set_symbol_registration(to, src.symbol_registration(from));
|
||||
d.set_symbol_export_type(to, src.symbol_export_type(from));
|
||||
d.set_symbol_nine_slice(to, src.symbol_nine_slice(from));
|
||||
}
|
||||
|
||||
fn builtin_info(b: &BuiltinSymbolLibrary) -> LibraryInfo {
|
||||
LibraryInfo { id: b.id.into(), name: b.name.into(), category: "builtIn" }
|
||||
}
|
||||
|
||||
/// Every symbol library, in menu order: built-in, User Defined, loaded.
|
||||
pub fn libraries(s: &Session) -> Vec<LibraryInfo> {
|
||||
BUILTIN.iter().map(builtin_info).chain(s.symbol_libraries.infos().cloned()).collect()
|
||||
}
|
||||
|
||||
/// Library `key` (an id, or a name in any case) with its info.
|
||||
pub fn library(s: &Session, key: &str) -> Option<(LibraryInfo, Arc<SymbolLibrary>)> {
|
||||
if let Some(found) = s.symbol_libraries.get(key) {
|
||||
return Some(found);
|
||||
}
|
||||
if let Some(b) = BUILTIN.iter().find(|b| b.id == key) {
|
||||
return Some((builtin_info(b), builtin_library(key)?));
|
||||
}
|
||||
let id = libraries(s).into_iter().find(|l| l.name.eq_ignore_ascii_case(key))?.id;
|
||||
library(s, &id)
|
||||
}
|
||||
|
||||
fn library_param(s: &Session, p: &Value, cmd: &str) -> Result<(LibraryInfo, Arc<SymbolLibrary>)> {
|
||||
let key = str_param(p, "library").ok_or_else(|| bad(cmd, "missing `library` (see symbol.libraries)"))?;
|
||||
library(s, key).ok_or_else(|| bad(cmd, format!("no symbol library `{key}` (see symbol.libraries)")))
|
||||
}
|
||||
|
||||
fn list(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
s.symbol_libraries.rescan();
|
||||
let libs: Vec<Value> = libraries(s)
|
||||
.into_iter()
|
||||
.map(|l| {
|
||||
let count = library(s, &l.id).map_or(0, |(_, lib)| lib.len());
|
||||
json!({"id": l.id, "name": l.name, "category": l.category, "count": count, "path": s.symbol_libraries.path(&l.id)})
|
||||
})
|
||||
.collect();
|
||||
Ok(json!({ "libraries": libs, "userFolder": s.symbol_libraries.user_dir() }))
|
||||
}
|
||||
|
||||
fn get(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let (info, lib) = library_param(s, p, "symbol.library")?;
|
||||
let d = &lib.doc;
|
||||
let symbols: Vec<Value> = d
|
||||
.symbols
|
||||
.iter()
|
||||
.map(|sym| {
|
||||
let (w, h) = natural_size(d, &sym.name);
|
||||
json!({"name": sym.name, "size": [w, h], "registration": d.symbol_registration(&sym.name).0, "exportType": d.symbol_export_type(&sym.name).id()})
|
||||
})
|
||||
.collect();
|
||||
Ok(json!({"id": info.id, "name": info.name, "category": info.category, "symbols": symbols}))
|
||||
}
|
||||
|
||||
fn add(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "symbol.addFromLibrary";
|
||||
let (info, lib) = library_param(s, p, C)?;
|
||||
let mut names = str_list(p, "names");
|
||||
names.extend(str_param(p, "name").map(str::to_string));
|
||||
if let Some(n) = names.iter().find(|n| lib.symbol(n).is_none()) {
|
||||
return Err(bad(C, format!("no symbol `{n}` in `{}`", lib.name)));
|
||||
}
|
||||
let mut picked: Vec<String> = if names.is_empty() { lib.doc.symbols.iter().map(|s| s.name.clone()).collect() } else { names };
|
||||
// Each once, in the order asked for.
|
||||
let mut seen = HashSet::new();
|
||||
picked.retain(|n| seen.insert(n.clone()));
|
||||
let place = bool_or(p, "place", false);
|
||||
if place && picked.is_empty() {
|
||||
return Err(bad(C, format!("`{}` has no symbols to place", lib.name)));
|
||||
}
|
||||
let choices = SwatchChoices::parse(C, p)?;
|
||||
let clip = Clipboard::gather(&lib.doc, picked.iter().map(|n| instance(n)).collect());
|
||||
let st = s.doc()?;
|
||||
let before: HashSet<String> = st.doc.symbols.iter().map(|s| s.name.clone()).collect();
|
||||
// A library symbol's name in the document: its own, or the one the import gave it.
|
||||
let target = |renamed: &[Value], n: &str| -> String {
|
||||
let to = renamed.iter().find(|r| r["kind"] == "symbol" && r["from"] == n).and_then(|r| r["to"].as_str());
|
||||
to.unwrap_or(n).to_string()
|
||||
};
|
||||
// Where the symbols land, worked out on a copy: nothing to add and nothing to place is no edit.
|
||||
let mut probe = (*st.doc).clone();
|
||||
let imported = clip.import_into(&mut probe, &choices, false);
|
||||
let doc_names: Vec<String> = picked.iter().map(|n| target(&imported.renamed, n)).collect();
|
||||
let centre = st.doc.artboards.first().map(|a| a.rect.center()).unwrap_or(Point::ZERO);
|
||||
let at = if place { Some(Point::new(number_or(p, "x", centre.x, C)?, number_or(p, "y", centre.y, C)?)) } else { None };
|
||||
let parent = if place { st.target_parent()? } else { None };
|
||||
let mut out = json!({ "library": info.id });
|
||||
if imported.added > 0 || place {
|
||||
let placed = s.edit("Add to Symbols", |d, sel| {
|
||||
let imported = clip.import_into(d, &choices, false);
|
||||
// Every symbol brought in (nested ones too) takes its Symbol Options along.
|
||||
for sym in &clip.symbols {
|
||||
let to = target(&imported.renamed, &sym.name);
|
||||
if !before.contains(&to) {
|
||||
copy_options(&lib.doc, &sym.name, d, &to);
|
||||
}
|
||||
}
|
||||
let Some(first) = doc_names.first() else { return Ok(None) };
|
||||
d.unknown.insert(CURRENT_SYMBOL.into(), json!(first));
|
||||
let Some(at) = at else { return Ok(None) };
|
||||
let xf = place_xf(at, natural_size(d, first), d.symbol_registration(first));
|
||||
let id = d.alloc_id();
|
||||
d.insert(parent, usize::MAX, Node::new(id, NodeKind::SymbolInstance { symbol: first.clone(), xf }))?;
|
||||
sel.set([id]);
|
||||
Ok(Some(id))
|
||||
})?;
|
||||
if let Some(id) = placed {
|
||||
out["placed"] = json!(id.0);
|
||||
}
|
||||
} else if let Some(first) = doc_names.first() {
|
||||
s.execute("symbol.setCurrent", &json!({ "name": first }))?;
|
||||
}
|
||||
let (added, existing): (Vec<&String>, Vec<&String>) = doc_names.iter().partition(|n| !before.contains(*n));
|
||||
out["names"] = json!(doc_names);
|
||||
out["added"] = json!(added);
|
||||
out["existing"] = json!(existing);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn save(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "symbol.saveLibrary";
|
||||
let st = s.doc()?;
|
||||
let name = str_param(p, "name").map(str::trim).filter(|n| !n.is_empty()).map_or_else(|| stem(&st.title()).to_string(), str::to_string);
|
||||
let lib = SymbolLibrary::from_document(&st.doc, &str_list(p, "names"), name).map_err(|e| bad(C, e))?;
|
||||
if lib.is_empty() {
|
||||
return Err(bad(C, "the document has no symbols to save"));
|
||||
}
|
||||
let mut out = json!({ "count": lib.len() });
|
||||
let bytes = vectorcraft_format::save_file(&lib.doc);
|
||||
s.symbol_libraries.write(p, &lib.name, SYMBOLS_EXT, FileData::Binary(bytes), &mut out, C)?;
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn load(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "symbol.loadLibrary";
|
||||
let (info, lib) = s.symbol_libraries.load(p, C, |bytes, file| {
|
||||
let loaded = super::fileio::load(file, bytes).map_err(|e| bad(C, e.to_string()))?;
|
||||
if loaded.preview_only {
|
||||
return Err(bad(C, "only this Affinity file's embedded preview could be read; use File › Open to see it with its warning"));
|
||||
}
|
||||
SymbolLibrary::from_document(&loaded.doc, &[], stem(file).to_string()).map_err(|e| bad(C, e))
|
||||
})?;
|
||||
Ok(json!({"library": info.id, "name": info.name, "count": lib.len()}))
|
||||
}
|
||||
@@ -1366,6 +1366,8 @@ pub struct Session {
|
||||
pub(crate) freeform_point: Option<(usize, cmd::gradient::StopOwner)>,
|
||||
/// User Defined and loaded graphic style libraries (Window → Graphic Style Libraries); not saved.
|
||||
pub style_libraries: cmd::stylelib::Libraries,
|
||||
/// User Defined and loaded symbol libraries (Window → Symbol Libraries); not saved.
|
||||
pub symbol_libraries: cmd::symbollib::Libraries,
|
||||
/// The Libraries panel's libraries of graphics, colours and text styles (`library.*`).
|
||||
pub libraries: cmd::library::Libraries,
|
||||
/// Where the saved PDF presets are kept, one file each; `None`: only for the session
|
||||
@@ -1504,6 +1506,7 @@ impl Session {
|
||||
swatch_libraries: Default::default(),
|
||||
freeform_point: None,
|
||||
style_libraries: Default::default(),
|
||||
symbol_libraries: Default::default(),
|
||||
libraries: Default::default(),
|
||||
pdf_preset_dir: None,
|
||||
profile_dir: None,
|
||||
@@ -2616,6 +2619,8 @@ mod tests_swatchlib;
|
||||
#[cfg(test)]
|
||||
mod tests_symbolbounds;
|
||||
#[cfg(test)]
|
||||
mod tests_symbollib;
|
||||
#[cfg(test)]
|
||||
mod tests_targeting;
|
||||
#[cfg(test)]
|
||||
mod tests_textcombos;
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
//! Symbol libraries: the built-in library, saving a document's symbols as a library (User
|
||||
//! Defined, or a file), reopening it and adding its symbols to another document (nested symbols,
|
||||
//! patterns and Symbol Options along, one undo step, deduped, renamed on a clash, placed), other
|
||||
//! documents' symbols, and files that can't be read.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_doc::{NodeId, NodeKind, SymbolRegistration};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn session() -> Session {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
|
||||
s
|
||||
}
|
||||
|
||||
fn run(s: &mut Session, id: &str, p: Value) -> Value {
|
||||
s.execute(id, &p).unwrap_or_else(|e| panic!("{id} {p}: {e}"))
|
||||
}
|
||||
|
||||
fn doc(s: &Session) -> &vectorcraft_doc::Document {
|
||||
&s.doc().unwrap().doc
|
||||
}
|
||||
|
||||
fn undo_len(s: &Session) -> usize {
|
||||
s.doc().unwrap().history.undo.len()
|
||||
}
|
||||
|
||||
fn symbols(s: &Session) -> Vec<String> {
|
||||
doc(s).symbols.iter().map(|x| x.name.clone()).collect()
|
||||
}
|
||||
|
||||
fn strs(v: &Value) -> Vec<&str> {
|
||||
v.as_array().unwrap().iter().map(|n| n.as_str().unwrap()).collect()
|
||||
}
|
||||
|
||||
/// A folder of its own under the temp folder, emptied.
|
||||
fn folder(name: &str) -> std::path::PathBuf {
|
||||
let dir = std::env::temp_dir().join(format!("vc-symbollib-{name}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
dir
|
||||
}
|
||||
|
||||
/// A document with "Star" (a red star), "Badge" (a circle with a Star instance in it, registration
|
||||
/// top left) and "Dots" (a square painted with pattern "Dots").
|
||||
fn kit() -> Session {
|
||||
let mut s = session();
|
||||
run(&mut s, "shape.star", json!({"cx": 50, "cy": 50, "radius1": 20, "radius2": 8}));
|
||||
run(&mut s, "paint.setFill", json!({"color": "#ff0000"}));
|
||||
run(&mut s, "symbol.new", json!({"name": "Star"}));
|
||||
let star = s.doc().unwrap().selection.objects.clone();
|
||||
let ring = run(&mut s, "shape.ellipse", json!({"x": 20, "y": 20, "width": 60, "height": 60}))["id"].as_u64().unwrap();
|
||||
let mut ids: Vec<u64> = star.iter().map(|i| i.0).collect();
|
||||
ids.push(ring);
|
||||
run(&mut s, "symbol.new", json!({"name": "Badge", "ids": ids, "registration": 0}));
|
||||
s.edit("Pattern", |d, _| {
|
||||
let dot = vectorcraft_doc::Node::path(
|
||||
d.alloc_id(),
|
||||
vectorcraft_geom::shapes::ellipse(vectorcraft_geom::Rect::new(0.0, 0.0, 4.0, 4.0)),
|
||||
vectorcraft_doc::Appearance::default_art(),
|
||||
);
|
||||
let def = vectorcraft_doc::PatternDef {
|
||||
tile: vectorcraft_geom::Rect::new(0.0, 0.0, 10.0, 10.0),
|
||||
..vectorcraft_doc::PatternDef::new("Dots", vec![std::sync::Arc::new(dot)])
|
||||
};
|
||||
d.patterns.push(def);
|
||||
d.swatches.push(vectorcraft_color::Swatch {
|
||||
name: "Dots".into(),
|
||||
paint: vectorcraft_color::Paint::Pattern { pattern: "Dots".into(), xf: Default::default() },
|
||||
global: false,
|
||||
spot: false,
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
run(&mut s, "shape.rectangle", json!({"x": 120, "y": 120, "width": 40, "height": 30}));
|
||||
run(&mut s, "paint.setFill", json!({"swatch": "Dots"}));
|
||||
run(&mut s, "symbol.new", json!({"name": "Dots"}));
|
||||
s
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_builtin_library_is_original_art_generated_in_code() {
|
||||
let mut s = Session::new();
|
||||
let list = run(&mut s, "symbol.libraries", json!({}));
|
||||
let libs = list["libraries"].as_array().unwrap();
|
||||
assert_eq!(libs.len(), 1, "{libs:?}");
|
||||
assert_eq!((libs[0]["id"].as_str(), libs[0]["category"].as_str()), (Some("basic-shapes"), Some("builtIn")));
|
||||
let lib = run(&mut s, "symbol.library", json!({"library": "basic shapes"}));
|
||||
let names: Vec<&str> = lib["symbols"].as_array().unwrap().iter().map(|x| x["name"].as_str().unwrap()).collect();
|
||||
assert_eq!(names, ["Circle", "Square", "Rounded Square", "Triangle", "Diamond", "Hexagon", "Star", "Burst", "Arrow"]);
|
||||
assert_eq!(libs[0]["count"].as_u64(), Some(names.len() as u64));
|
||||
let arrow = lib["symbols"].as_array().unwrap().iter().find(|x| x["name"] == "Arrow").unwrap();
|
||||
assert_eq!(arrow["size"], json!([48.0, 32.0]));
|
||||
assert!(s.execute("symbol.library", &json!({"library": "nope"})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_saved_library_reopens_and_its_symbols_join_another_document_in_one_step() {
|
||||
let dir = folder("user");
|
||||
let mut s = kit();
|
||||
s.symbol_libraries.set_user_dir(Some(dir.to_string_lossy().to_string()));
|
||||
// Saving the Badge brings the Star it nests, not Dots.
|
||||
let r = run(&mut s, "symbol.saveLibrary", json!({"user": true, "name": "Signs", "names": ["Badge"]}));
|
||||
assert_eq!((r["library"].as_str(), r["count"].as_u64()), (Some("user/Signs.vectorcraft"), Some(2)));
|
||||
let path = r["path"].as_str().unwrap().to_string();
|
||||
let list = run(&mut s, "symbol.libraries", json!({}));
|
||||
let user: Vec<&Value> = list["libraries"].as_array().unwrap().iter().filter(|l| l["category"] == "user").collect();
|
||||
assert_eq!(user.len(), 1);
|
||||
assert_eq!((user[0]["name"].as_str(), user[0]["count"].as_u64()), (Some("Signs"), Some(2)));
|
||||
// The file is a document: its symbols, no art.
|
||||
let bytes = std::fs::read(&path).unwrap();
|
||||
let saved = vectorcraft_format::load(&bytes).unwrap();
|
||||
assert_eq!(saved.symbols.iter().map(|x| x.name.as_str()).collect::<Vec<_>>(), ["Star", "Badge"]);
|
||||
assert!(saved.layers.iter().all(|l| l.children().is_none_or(|c| c.is_empty())));
|
||||
// Loading the file gives that User Defined library.
|
||||
let r = run(&mut s, "symbol.loadLibrary", json!({ "path": path }));
|
||||
assert_eq!((r["library"].as_str(), r["name"].as_str()), (Some("user/Signs.vectorcraft"), Some("Signs")));
|
||||
|
||||
// Into a new document: Badge and the Star in it, with Badge's registration, as one step.
|
||||
run(&mut s, "file.new", json!({"width": 100, "height": 100}));
|
||||
let before = undo_len(&s);
|
||||
let r = run(&mut s, "symbol.addFromLibrary", json!({"library": "Signs", "name": "Badge"}));
|
||||
assert_eq!((strs(&r["names"]), strs(&r["added"]), strs(&r["existing"])), (vec!["Badge"], vec!["Badge"], vec![]));
|
||||
assert_eq!(undo_len(&s), before + 1);
|
||||
assert_eq!(s.doc().unwrap().history.undo.last().unwrap().label, "Add to Symbols");
|
||||
assert_eq!(symbols(&s), ["Star", "Badge"]);
|
||||
assert_eq!(doc(&s).symbol_registration("Badge"), SymbolRegistration(0));
|
||||
let (_, lib) = cmd::symbollib::library(&s, "Signs").unwrap();
|
||||
assert_eq!(doc(&s).symbols, lib.doc.symbols);
|
||||
assert_eq!(doc(&s).unknown.get("symbolSizes").and_then(|m| m.get("Badge")), lib.doc.unknown.get("symbolSizes").and_then(|m| m.get("Badge")));
|
||||
assert_eq!(run(&mut s, "symbol.list", json!({}))["current"], "Badge");
|
||||
// Undo takes it all back.
|
||||
run(&mut s, "edit.undo", json!({}));
|
||||
assert!(symbols(&s).is_empty());
|
||||
run(&mut s, "edit.redo", json!({}));
|
||||
// Again: already there, so no step.
|
||||
let before = undo_len(&s);
|
||||
let r = run(&mut s, "symbol.addFromLibrary", json!({"library": "user/Signs.vectorcraft", "names": ["Badge", "Star", "Badge"]}));
|
||||
assert_eq!((strs(&r["names"]), strs(&r["existing"])), (vec!["Badge", "Star"], vec!["Badge", "Star"]));
|
||||
assert_eq!((undo_len(&s), symbols(&s).len()), (before, 2));
|
||||
assert_eq!(run(&mut s, "symbol.list", json!({}))["current"], "Badge");
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_library_file_brings_patterns_renames_clashes_and_places_an_instance() {
|
||||
let dir = folder("file");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let file = dir.join("Kit.vectorcraft");
|
||||
let mut s = kit();
|
||||
let r = run(&mut s, "symbol.saveLibrary", json!({"path": file.to_string_lossy()}));
|
||||
assert_eq!(r["count"].as_u64(), Some(3));
|
||||
let lib = run(&mut s, "symbol.loadLibrary", json!({"path": file.to_string_lossy()}));
|
||||
assert_eq!((lib["name"].as_str(), lib["count"].as_u64()), (Some("Kit"), Some(3)));
|
||||
let id = lib["library"].as_str().unwrap().to_string();
|
||||
assert!(id.starts_with("loaded/"));
|
||||
|
||||
// A document with another "Star" of its own.
|
||||
run(&mut s, "file.new", json!({"width": 100, "height": 100}));
|
||||
run(&mut s, "shape.rectangle", json!({"x": 0, "y": 0, "width": 10, "height": 10}));
|
||||
run(&mut s, "symbol.new", json!({"name": "Star"}));
|
||||
let mine = doc(&s).symbols[0].clone();
|
||||
let before = undo_len(&s);
|
||||
let r = run(&mut s, "symbol.addFromLibrary", json!({"library": id, "names": ["Star", "Dots"], "place": true, "x": 30, "y": 40}));
|
||||
assert_eq!(undo_len(&s), before + 1, "adding and placing are one step");
|
||||
assert_eq!(strs(&r["names"]), ["Star 2", "Dots"]);
|
||||
assert_eq!(doc(&s).symbols[0], mine, "the document's own Star stays");
|
||||
// The pattern came along, with its swatch; the placed instance is the first one, selected.
|
||||
assert!(doc(&s).pattern("Dots").is_some() && doc(&s).swatch("Dots").is_some());
|
||||
let placed = NodeId(r["placed"].as_u64().unwrap());
|
||||
assert_eq!(s.doc().unwrap().selection.objects, [placed]);
|
||||
let NodeKind::SymbolInstance { symbol, .. } = &doc(&s).node(placed).unwrap().kind else { panic!("not an instance") };
|
||||
assert_eq!(symbol, "Star 2");
|
||||
let b = doc(&s).node(placed).unwrap().geometric_bounds().unwrap();
|
||||
assert!((b.center().x - 30.0).abs() < 0.01 && (b.center().y - 40.0).abs() < 0.01, "{b:?}");
|
||||
run(&mut s, "edit.undo", json!({}));
|
||||
assert_eq!(symbols(&s), ["Star"]);
|
||||
assert!(doc(&s).node(placed).is_none() && doc(&s).pattern("Dots").is_none());
|
||||
// Placing a symbol the document has still places (one step), without adding it again.
|
||||
run(&mut s, "edit.redo", json!({}));
|
||||
let before = undo_len(&s);
|
||||
let r = run(&mut s, "symbol.addFromLibrary", json!({"library": id, "name": "Dots", "place": true}));
|
||||
assert_eq!((undo_len(&s), strs(&r["existing"])), (before + 1, vec!["Dots"]));
|
||||
assert!(r["placed"].is_u64());
|
||||
assert!(s.execute("symbol.addFromLibrary", &json!({"library": id, "name": "Nope"})).is_err());
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn other_documents_symbols_load_and_unreadable_files_are_errors() {
|
||||
let mut s = kit();
|
||||
// Another document's symbols load as a library, without its art.
|
||||
let b64 = run(&mut s, "document.serialize", json!({}))["dataBase64"].as_str().unwrap().to_string();
|
||||
let r = run(&mut s, "symbol.loadLibrary", json!({"dataBase64": b64, "name": "Poster.vectorcraft"}));
|
||||
assert_eq!((r["name"].as_str(), r["count"].as_u64()), (Some("Poster"), Some(3)));
|
||||
let (_, lib) = cmd::symbollib::library(&s, r["library"].as_str().unwrap()).unwrap();
|
||||
assert!(lib.doc.layers.iter().all(|l| l.children().is_none_or(|c| c.is_empty())));
|
||||
// So do an SVG's.
|
||||
let svg = r##"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100"><defs><symbol id="dot" viewBox="0 0 10 10"><circle cx="5" cy="5" r="5"/></symbol></defs><use xlink:href="#dot" width="10" height="10"/></svg>"##;
|
||||
let r = run(&mut s, "symbol.loadLibrary", json!({"data": svg, "name": "Dots.svg"}));
|
||||
assert_eq!(r["count"].as_u64(), Some(1), "{r}");
|
||||
// Files that aren't documents, missing files and damaged native files are errors.
|
||||
assert!(s.execute("symbol.loadLibrary", &json!({"data": "hello", "name": "x.txt"})).is_err());
|
||||
assert!(s.execute("symbol.loadLibrary", &json!({"path": "/no/such/Library.vectorcraft"})).is_err());
|
||||
let dir = folder("bad");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let bad = dir.join("Broken.vectorcraft");
|
||||
std::fs::write(&bad, b"{\"format\": \"vectorcraft\", \"doc\": 7").unwrap();
|
||||
assert!(s.execute("symbol.loadLibrary", &json!({"path": bad.to_string_lossy()})).is_err());
|
||||
// A damaged file in the user folder isn't listed.
|
||||
s.symbol_libraries.set_user_dir(Some(dir.to_string_lossy().to_string()));
|
||||
let list = run(&mut s, "symbol.libraries", json!({}));
|
||||
assert!(list["libraries"].as_array().unwrap().iter().all(|l| l["category"] != "user"));
|
||||
s.symbol_libraries.set_user_dir(None);
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
// Nothing to save, or no such symbol, is an error; a headless session has no user folder.
|
||||
assert!(s.execute("symbol.saveLibrary", &json!({"names": ["Nope"]})).is_err());
|
||||
assert!(s.execute("symbol.saveLibrary", &json!({"user": true})).is_err());
|
||||
run(&mut s, "file.new", json!({"width": 100, "height": 100}));
|
||||
assert!(s.execute("symbol.saveLibrary", &json!({})).is_err());
|
||||
// Without a path the library comes back as the file's bytes.
|
||||
let mut s = kit();
|
||||
let r = run(&mut s, "symbol.saveLibrary", json!({"names": ["Star"]}));
|
||||
let bytes = vectorcraft_format::base64_decode(r["dataBase64"].as_str().unwrap()).unwrap();
|
||||
assert_eq!(vectorcraft_format::load(&bytes).unwrap().symbols.len(), 1);
|
||||
}
|
||||
@@ -2374,6 +2374,14 @@ fn panel_drop(app: &mut VectorcraftApp, ui: &Ui, resp: &egui::Response, xf: &Xf)
|
||||
}
|
||||
return;
|
||||
}
|
||||
// A symbol from a symbol library panel: added to the document's Symbols and placed there.
|
||||
if let widgets::PanelDrag::LibrarySymbol { library, name } = &*d {
|
||||
let at = xf.to_doc(pos);
|
||||
if let Err(e) = app.run("symbol.addFromLibrary", json!({"library": library, "name": name, "place": true, "x": at.x, "y": at.y})) {
|
||||
app.status(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let Some(hit) = hit_at(app, xf.to_doc(pos), xf.zoom) else { return };
|
||||
let Some(st) = app.session.active() else { return };
|
||||
let (cmd, params) = match &*d {
|
||||
@@ -2404,7 +2412,10 @@ fn panel_drop(app: &mut VectorcraftApp, ui: &Ui, resp: &egui::Response, xf: &Xf)
|
||||
}
|
||||
// Art dragged back onto the canvas: its move was already dropped. (A symbol was placed
|
||||
// above.)
|
||||
widgets::PanelDrag::Art(_) | widgets::PanelDrag::Symbol(_) | widgets::PanelDrag::LibraryGraphic { .. } => return,
|
||||
widgets::PanelDrag::Art(_)
|
||||
| widgets::PanelDrag::Symbol(_)
|
||||
| widgets::PanelDrag::LibrarySymbol { .. }
|
||||
| widgets::PanelDrag::LibraryGraphic { .. } => return,
|
||||
// A Libraries panel style or group only moves within that panel.
|
||||
widgets::PanelDrag::LibraryItem { .. } | widgets::PanelDrag::LibraryGroup { .. } => return,
|
||||
};
|
||||
|
||||
@@ -88,6 +88,7 @@ pub(crate) mod save_options;
|
||||
mod save_pdf;
|
||||
pub mod save_style_library;
|
||||
pub mod save_swatch_library;
|
||||
pub mod save_symbol_library;
|
||||
pub mod script_check;
|
||||
pub mod shape_builder_options;
|
||||
pub(crate) mod shapes;
|
||||
@@ -284,6 +285,7 @@ registry! {
|
||||
FlattenTransparency: [flatten::KIND] => flatten::SPEC,
|
||||
FlattenerPresets: [flattener_presets::KIND] => flattener_presets::SPEC,
|
||||
SaveStyleLibrary: [save_style_library::KIND] => save_style_library::SPEC,
|
||||
SaveSymbolLibrary: [save_symbol_library::KIND] => save_symbol_library::SPEC,
|
||||
Expand: [expand::KIND] => expand::SPEC,
|
||||
SpotColors: [spot_colors::KIND] => spot_colors::SPEC,
|
||||
TransformEach: [transform_each::KIND] => transform_each::SPEC,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//! (there is a user library folder).
|
||||
//!
|
||||
//! The name and Save To rows and the saving are shared with Save Graphic Style Library
|
||||
//! ([`super::save_style_library`]).
|
||||
//! ([`super::save_style_library`]) and Save Symbol Library ([`super::save_symbol_library`]).
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::palette_io::PaletteFormat;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
//! Save Symbol Library: a name and where it goes: the user library folder (listed under Window →
|
||||
//! Symbol Libraries → User Defined) or a `.vectorcraft` file picked in a save dialog (a download
|
||||
//! on the web). OK runs `symbol.saveLibrary`.
|
||||
//!
|
||||
//! Fields: `name`, `user` (save to the user library folder), `selectedOnly` and `names` (the
|
||||
//! symbol selected in the Symbols panel), `__user` (there is a user library folder).
|
||||
|
||||
use serde_json::Value;
|
||||
use vectorcraft_engine::cmd::symbollib::SYMBOLS_EXT;
|
||||
|
||||
use super::DialogSpec;
|
||||
use super::save_swatch_library::{destination, fields, name_row, params, save};
|
||||
use super::swatch_options::grid;
|
||||
use crate::VectorcraftApp;
|
||||
use crate::state::Dialog;
|
||||
|
||||
/// The dialog kind of Save Symbol Library.
|
||||
pub const KIND: &str = "saveSymbolLibrary";
|
||||
|
||||
pub(super) const SPEC: DialogSpec =
|
||||
DialogSpec { heading: |_| tl!("Save Symbol Library").into(), body, confirm, min_width: 360.0, ..DialogSpec::FORM };
|
||||
|
||||
/// Open Save Symbol Library for the document's symbols (`names`: the one selected in the panel).
|
||||
pub fn open(app: &mut VectorcraftApp, names: Vec<String>) -> Result<Value, String> {
|
||||
let fields = fields(app, app.session.symbol_libraries.user_dir().is_some(), names)?;
|
||||
app.ui.dialog = Some(Dialog::new(KIND, fields));
|
||||
Ok(Value::Null)
|
||||
}
|
||||
|
||||
fn body(_: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
grid(ui, |ui| {
|
||||
name_row(ui, d);
|
||||
destination(ui, d, tl!("Selected Symbols Only"));
|
||||
});
|
||||
false
|
||||
}
|
||||
|
||||
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
save(app, d, "symbol.saveLibrary", SYMBOLS_EXT, params(d))
|
||||
}
|
||||
@@ -3166,7 +3166,6 @@ font-technology Variable Променливи
|
||||
Show all open documents Показване на всички отворени документи
|
||||
Symbol Instance Екземпляр на символ
|
||||
Symbol Libraries Библиотеки със символи
|
||||
Symbol Libraries (on the roadmap) Библиотеки със символи (в план-графика)
|
||||
Symbol Screener Tool Инструмент „Филтър на символи“
|
||||
Symbol Scruncher Tool Инструмент „Свиване на символи“
|
||||
Symbol Shifter Tool Инструмент „Преместване на символи“
|
||||
@@ -5424,6 +5423,26 @@ axis Y Axis Y ос
|
||||
The plug-in is computing… Приставката изчислява…
|
||||
Inspect Plug-in Проверка на приставка
|
||||
Cancel Plug-in Run Отказ от изпълнението на приставката
|
||||
Add to Symbols Добавяне към символи
|
||||
Basic Shapes Основни фигури
|
||||
Open Symbol Library Отваряне на библиотека със символи
|
||||
Save Symbol Library Запазване на библиотека със символи
|
||||
Save Symbol Library… Запази библиотека със символи…
|
||||
Save Symbols… Запази символи…
|
||||
Selected Symbols Only Само избрани символи
|
||||
Symbol Libraries Menu Меню с библиотеки със символи
|
||||
Symbol Library Библиотека със символи
|
||||
User Symbol Library 1 Потребителска библиотека със символи 1
|
||||
User Symbol Library 2 Потребителска библиотека със символи 2
|
||||
User Symbol Library 3 Потребителска библиотека със символи 3
|
||||
User Symbol Library 4 Потребителска библиотека със символи 4
|
||||
User Symbol Library 5 Потребителска библиотека със символи 5
|
||||
User Symbol Library 6 Потребителска библиотека със символи 6
|
||||
User Symbol Library 7 Потребителска библиотека със символи 7
|
||||
User Symbol Library 8 Потребителска библиотека със символи 8
|
||||
User Symbol Library 9 Потребителска библиотека със символи 9
|
||||
User Symbol Library 10 Потребителска библиотека със символи 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg Trap: select two or more objects filled with solid colours Застъпване: изберете два или повече обекта, запълнени с плътни цветове
|
||||
@msg Trap: no edges of different colours meet among the selected objects Застъпване: сред избраните обекти няма допиращи се ръбове с различни цветове
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness трябва да е от 0,01 до 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1925,7 +1925,6 @@ lighting Light Světlo
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document V tomto dokumentu nejsou žádné symboly
|
||||
Select art and click New Symbol to make one. Vyberte kresbu a symbol vytvořte tlačítkem Nový symbol.
|
||||
Symbol Libraries (on the roadmap) Knihovny symbolů (v plánu)
|
||||
Align On: Zarovnat na:
|
||||
Bottom-Justified Tab Tabulátor zarovnaný dolů
|
||||
Center-Justified Tab Tabulátor zarovnaný na střed
|
||||
@@ -5475,6 +5474,32 @@ axis Y Axis osa Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` živý efekt běží během vykreslování dokumentu, takže nemůže být `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out exportní zásuvný modul dostává vždy rozpočet exportu: klíč `budget` vynechte
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees „{_1}“ žádá o velký výpočetní rozpočet (každé spuštění až {minutes} minut a {times}krát víc instrukcí než obvykle): nainstalujte ho s `allowHeavy: true`, jakmile uživatel souhlasí
|
||||
Add to Symbols Přidat do symbolů
|
||||
Basic Shapes Základní tvary
|
||||
Open Symbol Library Otevřít knihovnu symbolů
|
||||
Save Symbol Library Uložit knihovnu symbolů
|
||||
Save Symbol Library… Uložit knihovnu symbolů…
|
||||
Save Symbols… Uložit symboly…
|
||||
Selected Symbols Only Pouze vybrané symboly
|
||||
Symbol Libraries Menu Nabídka knihoven symbolů
|
||||
Symbol Library Knihovna symbolů
|
||||
User Symbol Library 1 Uživatelská knihovna symbolů 1
|
||||
User Symbol Library 2 Uživatelská knihovna symbolů 2
|
||||
User Symbol Library 3 Uživatelská knihovna symbolů 3
|
||||
User Symbol Library 4 Uživatelská knihovna symbolů 4
|
||||
User Symbol Library 5 Uživatelská knihovna symbolů 5
|
||||
User Symbol Library 6 Uživatelská knihovna symbolů 6
|
||||
User Symbol Library 7 Uživatelská knihovna symbolů 7
|
||||
User Symbol Library 8 Uživatelská knihovna symbolů 8
|
||||
User Symbol Library 9 Uživatelská knihovna symbolů 9
|
||||
User Symbol Library 10 Uživatelská knihovna symbolů 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` nemá žádné symboly k umístění
|
||||
@msg missing `library` (see symbol.libraries) chybí `library` (viz symbol.libraries)
|
||||
@msg no symbol `{n}` žádný symbol `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` žádný symbol `{n}` v `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) žádná knihovna symbolů `{key}` (viz symbol.libraries)
|
||||
@msg the document has no symbols to save dokument nemá žádné symboly k uložení
|
||||
@msg Trap: select two or more objects filled with solid colours Přesah barev: vyberte dva nebo více objektů vyplněných plnými barvami
|
||||
@msg Trap: no edges of different colours meet among the selected objects Přesah barev: mezi vybranými objekty se nestýkají žádné okraje různých barev
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness musí být od 0,01 do 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1742,7 +1742,6 @@ lighting Light Lys
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document Ingen symboler i dette dokument
|
||||
Select art and click New Symbol to make one. Markér grafik, og klik på Nyt symbol for at oprette et.
|
||||
Symbol Libraries (on the roadmap) Symbolbiblioteker (på roadmappen)
|
||||
Align On: Justér på:
|
||||
Bottom-Justified Tab Bundjusteret tabulator
|
||||
Center-Justified Tab Midterjusteret tabulator
|
||||
@@ -5440,6 +5439,26 @@ axis Y Axis Y-akse
|
||||
The plug-in is computing… Plug-in'en regner…
|
||||
Inspect Plug-in Undersøg plug-in
|
||||
Cancel Plug-in Run Annullér plug-in-kørsel
|
||||
Add to Symbols Føj til symboler
|
||||
Basic Shapes Grundlæggende former
|
||||
Open Symbol Library Åbn symbolbibliotek
|
||||
Save Symbol Library Gem symbolbibliotek
|
||||
Save Symbol Library… Gem symbolbibliotek…
|
||||
Save Symbols… Gem symboler…
|
||||
Selected Symbols Only Kun valgte symboler
|
||||
Symbol Libraries Menu Menu med symbolbiblioteker
|
||||
Symbol Library Symbolbibliotek
|
||||
User Symbol Library 1 Brugersymbolbibliotek 1
|
||||
User Symbol Library 2 Brugersymbolbibliotek 2
|
||||
User Symbol Library 3 Brugersymbolbibliotek 3
|
||||
User Symbol Library 4 Brugersymbolbibliotek 4
|
||||
User Symbol Library 5 Brugersymbolbibliotek 5
|
||||
User Symbol Library 6 Brugersymbolbibliotek 6
|
||||
User Symbol Library 7 Brugersymbolbibliotek 7
|
||||
User Symbol Library 8 Brugersymbolbibliotek 8
|
||||
User Symbol Library 9 Brugersymbolbibliotek 9
|
||||
User Symbol Library 10 Brugersymbolbibliotek 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg Trap: select two or more objects filled with solid colours Trap: Vælg to eller flere objekter udfyldt med ensfarvede farver
|
||||
@msg Trap: no edges of different colours meet among the selected objects Trap: Ingen kanter i forskellige farver mødes blandt de valgte objekter
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness skal være fra 0,01 til 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3187,7 +3187,6 @@ effect Points Punkte
|
||||
Show all open documents Alle geöffneten Dokumente anzeigen
|
||||
Symbol Instance Symbolinstanz
|
||||
Symbol Libraries Symbol-Bibliotheken
|
||||
Symbol Libraries (on the roadmap) Symbol-Bibliotheken (geplant)
|
||||
Symbol Screener Tool Symbol-transparent-gestalten-Werkzeug
|
||||
Symbol Scruncher Tool Symbol-stauchen-Werkzeug
|
||||
Symbol Shifter Tool Symbol-verschieben-Werkzeug
|
||||
@@ -5058,6 +5057,32 @@ axis Y Axis Y-Achse
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` ein Live-Effekt läuft, während das Dokument gezeichnet wird, daher kann er nicht `heavy` sein
|
||||
@msg an exporter always gets an export's budget: leave `budget` out ein Export-Plug-in erhält immer das Budget eines Exports: Lassen Sie `budget` weg
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees „{_1}“ verlangt ein großes Rechenbudget (jede Ausführung bis zu {minutes} Minuten und {times}-mal so viele Anweisungen wie üblich): Installieren Sie es mit `allowHeavy: true`, sobald der Benutzer zustimmt
|
||||
Add to Symbols Zu Symbolen hinzufügen
|
||||
Basic Shapes Grundformen
|
||||
Open Symbol Library Symbol-Bibliothek öffnen
|
||||
Save Symbol Library Symbol-Bibliothek speichern
|
||||
Save Symbol Library… Symbol-Bibliothek speichern…
|
||||
Save Symbols… Symbole speichern…
|
||||
Selected Symbols Only Nur ausgewählte Symbole
|
||||
Symbol Libraries Menu Menü „Symbol-Bibliotheken“
|
||||
Symbol Library Symbol-Bibliothek
|
||||
User Symbol Library 1 Benutzer-Symbol-Bibliothek 1
|
||||
User Symbol Library 2 Benutzer-Symbol-Bibliothek 2
|
||||
User Symbol Library 3 Benutzer-Symbol-Bibliothek 3
|
||||
User Symbol Library 4 Benutzer-Symbol-Bibliothek 4
|
||||
User Symbol Library 5 Benutzer-Symbol-Bibliothek 5
|
||||
User Symbol Library 6 Benutzer-Symbol-Bibliothek 6
|
||||
User Symbol Library 7 Benutzer-Symbol-Bibliothek 7
|
||||
User Symbol Library 8 Benutzer-Symbol-Bibliothek 8
|
||||
User Symbol Library 9 Benutzer-Symbol-Bibliothek 9
|
||||
User Symbol Library 10 Benutzer-Symbol-Bibliothek 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` hat keine Symbole zum Platzieren
|
||||
@msg missing `library` (see symbol.libraries) `library` fehlt (siehe symbol.libraries)
|
||||
@msg no symbol `{n}` kein Symbol `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` kein Symbol `{n}` in `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) keine Symbol-Bibliothek `{key}` (siehe symbol.libraries)
|
||||
@msg the document has no symbols to save das Dokument hat keine Symbole zum Speichern
|
||||
@msg Trap: select two or more objects filled with solid colours Überfüllen: Wählen Sie zwei oder mehr Objekte mit Volltonflächen aus
|
||||
@msg Trap: no edges of different colours meet among the selected objects Überfüllen: Unter den ausgewählten Objekten treffen keine Kanten verschiedener Farben aufeinander
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness muss zwischen 0,01 und 5000 pt liegen
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3582,7 +3582,6 @@ theme Appearance Εμφάνιση
|
||||
Show all open documents Εμφάνιση όλων των ανοιχτών εγγράφων
|
||||
Symbol Instance Στιγμιότυπο συμβόλου
|
||||
Symbol Libraries Βιβλιοθήκες συμβόλων
|
||||
Symbol Libraries (on the roadmap) Βιβλιοθήκες συμβόλων (προγραμματισμένη λειτουργία)
|
||||
Symbol Screener Tool Αραίωση συμβόλων (Symbol Screener Tool)
|
||||
Symbol Scruncher Tool Σύμπτυξη συμβόλων (Symbol Scruncher Tool)
|
||||
Symbol Shifter Tool Μετατόπιση συμβόλων (Symbol Shifter Tool)
|
||||
@@ -5427,6 +5426,32 @@ axis Y Axis Άξονας Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` ένα δυναμικό εφέ εκτελείται κατά τη σχεδίαση του εγγράφου, οπότε δεν μπορεί να είναι `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out ένα πρόσθετο εξαγωγής παίρνει πάντα τον προϋπολογισμό μιας εξαγωγής: παραλείψτε το `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees το «{_1}» ζητά μεγάλο υπολογιστικό προϋπολογισμό (κάθε εκτέλεση έως {minutes} λεπτά και {times} φορές τις συνήθεις εντολές): εγκαταστήστε το με `allowHeavy: true` μόλις συμφωνήσει ο χρήστης
|
||||
Add to Symbols Προσθήκη στα σύμβολα
|
||||
Basic Shapes Βασικά σχήματα
|
||||
Open Symbol Library Άνοιγμα βιβλιοθήκης συμβόλων
|
||||
Save Symbol Library Αποθήκευση βιβλιοθήκης συμβόλων
|
||||
Save Symbol Library… Αποθήκευση βιβλιοθήκης συμβόλων…
|
||||
Save Symbols… Αποθήκευση συμβόλων…
|
||||
Selected Symbols Only Μόνο επιλεγμένα σύμβολα
|
||||
Symbol Libraries Menu Μενού βιβλιοθηκών συμβόλων
|
||||
Symbol Library Βιβλιοθήκη συμβόλων
|
||||
User Symbol Library 1 Βιβλιοθήκη συμβόλων χρήστη 1
|
||||
User Symbol Library 2 Βιβλιοθήκη συμβόλων χρήστη 2
|
||||
User Symbol Library 3 Βιβλιοθήκη συμβόλων χρήστη 3
|
||||
User Symbol Library 4 Βιβλιοθήκη συμβόλων χρήστη 4
|
||||
User Symbol Library 5 Βιβλιοθήκη συμβόλων χρήστη 5
|
||||
User Symbol Library 6 Βιβλιοθήκη συμβόλων χρήστη 6
|
||||
User Symbol Library 7 Βιβλιοθήκη συμβόλων χρήστη 7
|
||||
User Symbol Library 8 Βιβλιοθήκη συμβόλων χρήστη 8
|
||||
User Symbol Library 9 Βιβλιοθήκη συμβόλων χρήστη 9
|
||||
User Symbol Library 10 Βιβλιοθήκη συμβόλων χρήστη 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place Η `{_1}` δεν έχει σύμβολα για τοποθέτηση
|
||||
@msg missing `library` (see symbol.libraries) λείπει το `library` (δείτε symbol.libraries)
|
||||
@msg no symbol `{n}` δεν υπάρχει σύμβολο `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` δεν υπάρχει σύμβολο `{n}` στη `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) δεν υπάρχει βιβλιοθήκη συμβόλων `{key}` (δείτε symbol.libraries)
|
||||
@msg the document has no symbols to save το έγγραφο δεν έχει σύμβολα για αποθήκευση
|
||||
@msg Trap: select two or more objects filled with solid colours Παγίδευση χρωμάτων: επιλέξτε δύο ή περισσότερα αντικείμενα με συμπαγές χρώμα γεμίσματος
|
||||
@msg Trap: no edges of different colours meet among the selected objects Παγίδευση χρωμάτων: δεν συναντώνται άκρες διαφορετικών χρωμάτων στα επιλεγμένα αντικείμενα
|
||||
@msg thickness must be from 0.01 to 5000 pt το thickness πρέπει να είναι από 0,01 έως 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2059 and column 19.
|
@@ -3234,7 +3234,6 @@ font-technology Variable Variables
|
||||
Show all open documents Mostrar todos los documentos abiertos
|
||||
Symbol Instance Instancia de símbolo
|
||||
Symbol Libraries Bibliotecas de símbolos
|
||||
Symbol Libraries (on the roadmap) Bibliotecas de símbolos (en la hoja de ruta)
|
||||
Symbol Screener Tool Herramienta Transparencia de símbolos
|
||||
Symbol Scruncher Tool Herramienta Concentración de símbolos
|
||||
Symbol Shifter Tool Herramienta Desplazamiento de símbolos
|
||||
@@ -5417,6 +5416,32 @@ axis Y Axis Eje Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` un efecto interactivo se ejecuta mientras se dibuja el documento, así que no puede ser `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out un plugin de exportación siempre recibe el presupuesto de una exportación: omite `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees “{_1}” pide un presupuesto de cálculo grande (cada ejecución hasta {minutes} minutos y {times} veces las instrucciones habituales): instálalo con `allowHeavy: true` cuando el usuario lo acepte
|
||||
Add to Symbols Agregar a símbolos
|
||||
Basic Shapes Formas básicas
|
||||
Open Symbol Library Abrir biblioteca de símbolos
|
||||
Save Symbol Library Guardar biblioteca de símbolos
|
||||
Save Symbol Library… Guardar biblioteca de símbolos…
|
||||
Save Symbols… Guardar símbolos…
|
||||
Selected Symbols Only Solo símbolos seleccionados
|
||||
Symbol Libraries Menu Menú Bibliotecas de símbolos
|
||||
Symbol Library Biblioteca de símbolos
|
||||
User Symbol Library 1 Biblioteca de símbolos del usuario 1
|
||||
User Symbol Library 2 Biblioteca de símbolos del usuario 2
|
||||
User Symbol Library 3 Biblioteca de símbolos del usuario 3
|
||||
User Symbol Library 4 Biblioteca de símbolos del usuario 4
|
||||
User Symbol Library 5 Biblioteca de símbolos del usuario 5
|
||||
User Symbol Library 6 Biblioteca de símbolos del usuario 6
|
||||
User Symbol Library 7 Biblioteca de símbolos del usuario 7
|
||||
User Symbol Library 8 Biblioteca de símbolos del usuario 8
|
||||
User Symbol Library 9 Biblioteca de símbolos del usuario 9
|
||||
User Symbol Library 10 Biblioteca de símbolos del usuario 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` no tiene símbolos para colocar
|
||||
@msg missing `library` (see symbol.libraries) falta `library` (consulte symbol.libraries)
|
||||
@msg no symbol `{n}` no hay ningún símbolo `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` no hay ningún símbolo `{n}` en `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) no hay ninguna biblioteca de símbolos `{key}` (consulte symbol.libraries)
|
||||
@msg the document has no symbols to save el documento no tiene símbolos para guardar
|
||||
@msg Trap: select two or more objects filled with solid colours Reventar: seleccione dos o más objetos rellenos con colores sólidos
|
||||
@msg Trap: no edges of different colours meet among the selected objects Reventar: entre los objetos seleccionados no se tocan bordes de colores distintos
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness debe estar entre 0,01 y 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1888,7 +1888,6 @@ lighting Light Valo
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document Tässä asiakirjassa ei ole symboleja
|
||||
Select art and click New Symbol to make one. Luo symboli valitsemalla kuvitus ja napsauttamalla Uusi symboli.
|
||||
Symbol Libraries (on the roadmap) Symbolikirjastot (suunnitteilla)
|
||||
Align On: Tasaa kohteeseen:
|
||||
Bottom-Justified Tab Alas tasattu sarkain
|
||||
Center-Justified Tab Keskitetty sarkain
|
||||
@@ -5506,6 +5505,32 @@ axis Y Axis Y-akseli
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` live-tehoste suoritetaan asiakirjaa piirrettäessä, joten se ei voi olla `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out vientilaajennus saa aina viennin budjetin: jätä `budget` pois
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees ”{_1}” pyytää suurta laskentabudjettia (jokainen ajo enintään {minutes} minuuttia ja {times} kertaa tavallinen määrä käskyjä): asenna se asetuksella `allowHeavy: true`, kun käyttäjä hyväksyy
|
||||
Add to Symbols Lisää symboleihin
|
||||
Basic Shapes Perusmuodot
|
||||
Open Symbol Library Avaa symbolikirjasto
|
||||
Save Symbol Library Tallenna symbolikirjasto
|
||||
Save Symbol Library… Tallenna symbolikirjasto…
|
||||
Save Symbols… Tallenna symbolit…
|
||||
Selected Symbols Only Vain valitut symbolit
|
||||
Symbol Libraries Menu Symbolikirjastojen valikko
|
||||
Symbol Library Symbolikirjasto
|
||||
User Symbol Library 1 Käyttäjän symbolikirjasto 1
|
||||
User Symbol Library 2 Käyttäjän symbolikirjasto 2
|
||||
User Symbol Library 3 Käyttäjän symbolikirjasto 3
|
||||
User Symbol Library 4 Käyttäjän symbolikirjasto 4
|
||||
User Symbol Library 5 Käyttäjän symbolikirjasto 5
|
||||
User Symbol Library 6 Käyttäjän symbolikirjasto 6
|
||||
User Symbol Library 7 Käyttäjän symbolikirjasto 7
|
||||
User Symbol Library 8 Käyttäjän symbolikirjasto 8
|
||||
User Symbol Library 9 Käyttäjän symbolikirjasto 9
|
||||
User Symbol Library 10 Käyttäjän symbolikirjasto 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place Kohteessa `{_1}` ei ole sijoitettavia symboleja
|
||||
@msg missing `library` (see symbol.libraries) `library` puuttuu (katso symbol.libraries)
|
||||
@msg no symbol `{n}` ei symbolia `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` ei symbolia `{n}` kohteessa `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) ei symbolikirjastoa `{key}` (katso symbol.libraries)
|
||||
@msg the document has no symbols to save dokumentissa ei ole tallennettavia symboleja
|
||||
@msg Trap: select two or more objects filled with solid colours Ylitäyttö: valitse vähintään kaksi tasaisella värillä täytettyä objektia
|
||||
@msg Trap: no edges of different colours meet among the selected objects Ylitäyttö: valituissa objekteissa eriväriset reunat eivät kohtaa
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness-arvon on oltava 0,01–5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3231,7 +3231,6 @@ font-technology Variable Variables
|
||||
Show all open documents Afficher tous les documents ouverts
|
||||
Symbol Instance Instance de symbole
|
||||
Symbol Libraries Bibliothèques de symboles
|
||||
Symbol Libraries (on the roadmap) Bibliothèques de symboles (prévu dans la feuille de route)
|
||||
Symbol Screener Tool Outil Transparence de symboles
|
||||
Symbol Scruncher Tool Outil Espacement de symboles
|
||||
Symbol Shifter Tool Outil Glissement de symboles
|
||||
@@ -5474,6 +5473,32 @@ axis Y Axis Axe Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` un effet dynamique s’exécute pendant le tracé du document, il ne peut donc pas être `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out un module externe d’exportation reçoit toujours le budget d’une exportation : omettez `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees « {_1} » demande un budget de calcul important (chaque exécution jusqu’à {minutes} minutes et {times} fois les instructions habituelles) : installez-le avec `allowHeavy: true` une fois que l’utilisateur l’accepte
|
||||
Add to Symbols Ajouter aux symboles
|
||||
Basic Shapes Formes de base
|
||||
Open Symbol Library Ouvrir une bibliothèque de symboles
|
||||
Save Symbol Library Enregistrer la bibliothèque de symboles
|
||||
Save Symbol Library… Enregistrer la bibliothèque de symboles…
|
||||
Save Symbols… Enregistrer les symboles…
|
||||
Selected Symbols Only Symboles sélectionnés uniquement
|
||||
Symbol Libraries Menu Menu Bibliothèques de symboles
|
||||
Symbol Library Bibliothèque de symboles
|
||||
User Symbol Library 1 Bibliothèque de symboles utilisateur 1
|
||||
User Symbol Library 2 Bibliothèque de symboles utilisateur 2
|
||||
User Symbol Library 3 Bibliothèque de symboles utilisateur 3
|
||||
User Symbol Library 4 Bibliothèque de symboles utilisateur 4
|
||||
User Symbol Library 5 Bibliothèque de symboles utilisateur 5
|
||||
User Symbol Library 6 Bibliothèque de symboles utilisateur 6
|
||||
User Symbol Library 7 Bibliothèque de symboles utilisateur 7
|
||||
User Symbol Library 8 Bibliothèque de symboles utilisateur 8
|
||||
User Symbol Library 9 Bibliothèque de symboles utilisateur 9
|
||||
User Symbol Library 10 Bibliothèque de symboles utilisateur 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` n'a aucun symbole à placer
|
||||
@msg missing `library` (see symbol.libraries) `library` manquant (voir symbol.libraries)
|
||||
@msg no symbol `{n}` aucun symbole `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` aucun symbole `{n}` dans `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) aucune bibliothèque de symboles `{key}` (voir symbol.libraries)
|
||||
@msg the document has no symbols to save le document n'a aucun symbole à enregistrer
|
||||
@msg Trap: select two or more objects filled with solid colours Recouvrement : sélectionnez au moins deux objets remplis de couleurs unies
|
||||
@msg Trap: no edges of different colours meet among the selected objects Recouvrement : aucun bord de couleurs différentes ne se touche parmi les objets sélectionnés
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness doit être compris entre 0,01 et 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3874,7 +3874,6 @@ mark-style Japanese Japán
|
||||
Symbol Szimbólum
|
||||
Symbol Instance Szimbólumpéldány
|
||||
Symbol Libraries Szimbólumkönyvtárak
|
||||
Symbol Libraries (on the roadmap) Szimbólumkönyvtárak (tervezett funkció)
|
||||
Symbol Screener Tool Szimbólumhalványító
|
||||
Symbol Scruncher Tool Szimbólumtömörítő
|
||||
Symbol Set Density: Szimbólumkészlet sűrűsége:
|
||||
@@ -5461,6 +5460,32 @@ axis Y Axis Y tengely
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` az élő effektus a dokumentum rajzolása közben fut, ezért nem lehet `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out az exportáló bővítmény mindig az exportálás keretét kapja: hagyd ki a `budget` kulcsot
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees a(z) „{_1}” nagy számítási keretet kér (futásonként legfeljebb {minutes} perc és a szokásos utasításszám {times}-szorosa): telepítsd az `allowHeavy: true` megadásával, miután a felhasználó beleegyezett
|
||||
Add to Symbols Hozzáadás a szimbólumokhoz
|
||||
Basic Shapes Alapalakzatok
|
||||
Open Symbol Library Szimbólumkönyvtár megnyitása
|
||||
Save Symbol Library Szimbólumkönyvtár mentése
|
||||
Save Symbol Library… Szimbólumkönyvtár mentése…
|
||||
Save Symbols… Szimbólumok mentése…
|
||||
Selected Symbols Only Csak a kijelölt szimbólumok
|
||||
Symbol Libraries Menu Szimbólumkönyvtárak menü
|
||||
Symbol Library Szimbólumkönyvtár
|
||||
User Symbol Library 1 Felhasználói szimbólumkönyvtár 1
|
||||
User Symbol Library 2 Felhasználói szimbólumkönyvtár 2
|
||||
User Symbol Library 3 Felhasználói szimbólumkönyvtár 3
|
||||
User Symbol Library 4 Felhasználói szimbólumkönyvtár 4
|
||||
User Symbol Library 5 Felhasználói szimbólumkönyvtár 5
|
||||
User Symbol Library 6 Felhasználói szimbólumkönyvtár 6
|
||||
User Symbol Library 7 Felhasználói szimbólumkönyvtár 7
|
||||
User Symbol Library 8 Felhasználói szimbólumkönyvtár 8
|
||||
User Symbol Library 9 Felhasználói szimbólumkönyvtár 9
|
||||
User Symbol Library 10 Felhasználói szimbólumkönyvtár 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place A(z) `{_1}` nem tartalmaz elhelyezhető szimbólumot
|
||||
@msg missing `library` (see symbol.libraries) hiányzik a `library` (lásd: symbol.libraries)
|
||||
@msg no symbol `{n}` nincs `{n}` szimbólum
|
||||
@msg no symbol `{n}` in `{_1}` nincs `{n}` szimbólum itt: `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) nincs `{key}` szimbólumkönyvtár (lásd: symbol.libraries)
|
||||
@msg the document has no symbols to save a dokumentumban nincs menthető szimbólum
|
||||
@msg Trap: select two or more objects filled with solid colours Csapdázás: jelöljön ki legalább két, egyszínű kitöltésű objektumot
|
||||
@msg Trap: no edges of different colours meet among the selected objects Csapdázás: a kijelölt objektumok között nem érintkeznek különböző színű élek
|
||||
@msg thickness must be from 0.01 to 5000 pt a thickness értéke 0,01 és 5000 pt között lehet
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1742,7 +1742,6 @@ lighting Light Cahaya
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document Tidak ada simbol dalam dokumen ini
|
||||
Select art and click New Symbol to make one. Pilih karya seni dan klik Simbol Baru untuk membuatnya.
|
||||
Symbol Libraries (on the roadmap) Pustaka simbol (ada di peta jalan)
|
||||
Align On: Ratakan pada:
|
||||
Bottom-Justified Tab Tab rata bawah
|
||||
Center-Justified Tab Tab rata tengah
|
||||
@@ -5440,6 +5439,26 @@ axis Y Axis Sumbu Y
|
||||
The plug-in is computing… Plug-in sedang menghitung…
|
||||
Inspect Plug-in Periksa plug-in
|
||||
Cancel Plug-in Run Batalkan jalannya plug-in
|
||||
Add to Symbols Tambahkan ke simbol
|
||||
Basic Shapes Bentuk dasar
|
||||
Open Symbol Library Buka pustaka simbol
|
||||
Save Symbol Library Simpan pustaka simbol
|
||||
Save Symbol Library… Simpan pustaka simbol…
|
||||
Save Symbols… Simpan simbol…
|
||||
Selected Symbols Only Hanya simbol terpilih
|
||||
Symbol Libraries Menu Menu pustaka simbol
|
||||
Symbol Library Pustaka simbol
|
||||
User Symbol Library 1 Pustaka simbol pengguna 1
|
||||
User Symbol Library 2 Pustaka simbol pengguna 2
|
||||
User Symbol Library 3 Pustaka simbol pengguna 3
|
||||
User Symbol Library 4 Pustaka simbol pengguna 4
|
||||
User Symbol Library 5 Pustaka simbol pengguna 5
|
||||
User Symbol Library 6 Pustaka simbol pengguna 6
|
||||
User Symbol Library 7 Pustaka simbol pengguna 7
|
||||
User Symbol Library 8 Pustaka simbol pengguna 8
|
||||
User Symbol Library 9 Pustaka simbol pengguna 9
|
||||
User Symbol Library 10 Pustaka simbol pengguna 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg Trap: select two or more objects filled with solid colours Trap: pilih dua objek atau lebih yang diisi warna solid
|
||||
@msg Trap: no edges of different colours meet among the selected objects Trap: tidak ada tepi berwarna berbeda yang bertemu di antara objek yang dipilih
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness harus dari 0,01 sampai 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3830 and column 19.
|
@@ -3268,7 +3268,6 @@ mark-style Japanese Giapponese
|
||||
Show all open documents Mostra tutti i documenti aperti
|
||||
Symbol Instance Istanza di simbolo
|
||||
Symbol Libraries Librerie simboli
|
||||
Symbol Libraries (on the roadmap) Librerie simboli (in programma)
|
||||
Symbol Screener Tool Strumento Trasparenza simboli
|
||||
Symbol Scruncher Tool Strumento Addensamento simboli
|
||||
Symbol Shifter Tool Strumento Spostamento simboli
|
||||
@@ -5092,6 +5091,32 @@ axis Y Axis Asse Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` un effetto dinamico viene eseguito mentre il documento viene disegnato, quindi non può essere `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out un plug-in di esportazione riceve sempre il budget di un’esportazione: ometti `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees “{_1}” chiede un budget di calcolo elevato (ogni esecuzione fino a {minutes} minuti e {times} volte le istruzioni consuete): installalo con `allowHeavy: true` quando l’utente acconsente
|
||||
Add to Symbols Aggiungi ai simboli
|
||||
Basic Shapes Forme di base
|
||||
Open Symbol Library Apri libreria simboli
|
||||
Save Symbol Library Salva libreria simboli
|
||||
Save Symbol Library… Salva libreria simboli…
|
||||
Save Symbols… Salva simboli…
|
||||
Selected Symbols Only Solo simboli selezionati
|
||||
Symbol Libraries Menu Menu Librerie simboli
|
||||
Symbol Library Libreria simboli
|
||||
User Symbol Library 1 Libreria simboli utente 1
|
||||
User Symbol Library 2 Libreria simboli utente 2
|
||||
User Symbol Library 3 Libreria simboli utente 3
|
||||
User Symbol Library 4 Libreria simboli utente 4
|
||||
User Symbol Library 5 Libreria simboli utente 5
|
||||
User Symbol Library 6 Libreria simboli utente 6
|
||||
User Symbol Library 7 Libreria simboli utente 7
|
||||
User Symbol Library 8 Libreria simboli utente 8
|
||||
User Symbol Library 9 Libreria simboli utente 9
|
||||
User Symbol Library 10 Libreria simboli utente 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` non ha simboli da inserire
|
||||
@msg missing `library` (see symbol.libraries) manca `library` (vedi symbol.libraries)
|
||||
@msg no symbol `{n}` nessun simbolo `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` nessun simbolo `{n}` in `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) nessuna libreria simboli `{key}` (vedi symbol.libraries)
|
||||
@msg the document has no symbols to save il documento non ha simboli da salvare
|
||||
@msg Trap: select two or more objects filled with solid colours Trapping: selezionate due o più oggetti con riempimento in tinta unita
|
||||
@msg Trap: no edges of different colours meet among the selected objects Trapping: tra gli oggetti selezionati non si incontrano bordi di colori diversi
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness deve essere compreso tra 0,01 e 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2990,7 +2990,6 @@ mark-style Japanese 日本式
|
||||
Use Library Item ライブラリ項目を使用
|
||||
Graphic グラフィック
|
||||
Show all open documents 開いているすべてのドキュメントを表示
|
||||
Symbol Libraries (on the roadmap) シンボルライブラリ (今後対応予定)
|
||||
Symbol Screener Tool シンボルスクリーナーツール
|
||||
Symbol Scruncher Tool シンボルスクランチャーツール
|
||||
Symbol Shifter Tool シンボルシフターツール
|
||||
@@ -5154,6 +5153,32 @@ axis Y Axis Y 軸
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` ライブ効果はドキュメントの描画中に実行されるため、`heavy` にはできません
|
||||
@msg an exporter always gets an export's budget: leave `budget` out 書き出しプラグインには常に書き出しの予算が割り当てられます。`budget` は省略してください
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees 「{_1}」は大きな計算予算を求めています (1 回の実行につき最大 {minutes} 分、通常の {times} 倍の命令)。ユーザーが同意したら `allowHeavy: true` を指定してインストールしてください
|
||||
Add to Symbols シンボルに追加
|
||||
Basic Shapes 基本シェイプ
|
||||
Open Symbol Library シンボルライブラリを開く
|
||||
Save Symbol Library シンボルライブラリを保存
|
||||
Save Symbol Library… シンボルライブラリを保存…
|
||||
Save Symbols… シンボルを保存…
|
||||
Selected Symbols Only 選択したシンボルのみ
|
||||
Symbol Libraries Menu シンボルライブラリメニュー
|
||||
Symbol Library シンボルライブラリ
|
||||
User Symbol Library 1 ユーザーシンボルライブラリ 1
|
||||
User Symbol Library 2 ユーザーシンボルライブラリ 2
|
||||
User Symbol Library 3 ユーザーシンボルライブラリ 3
|
||||
User Symbol Library 4 ユーザーシンボルライブラリ 4
|
||||
User Symbol Library 5 ユーザーシンボルライブラリ 5
|
||||
User Symbol Library 6 ユーザーシンボルライブラリ 6
|
||||
User Symbol Library 7 ユーザーシンボルライブラリ 7
|
||||
User Symbol Library 8 ユーザーシンボルライブラリ 8
|
||||
User Symbol Library 9 ユーザーシンボルライブラリ 9
|
||||
User Symbol Library 10 ユーザーシンボルライブラリ 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` に配置できるシンボルがありません
|
||||
@msg missing `library` (see symbol.libraries) `library` がありません (symbol.libraries を参照)
|
||||
@msg no symbol `{n}` シンボル `{n}` がありません
|
||||
@msg no symbol `{n}` in `{_1}` `{_1}` にシンボル `{n}` がありません
|
||||
@msg no symbol library `{key}` (see symbol.libraries) シンボルライブラリ `{key}` がありません (symbol.libraries を参照)
|
||||
@msg the document has no symbols to save ドキュメントに保存するシンボルがありません
|
||||
@msg Trap: select two or more objects filled with solid colours トラップ: 単色で塗りつぶした 2 つ以上のオブジェクトを選択してください
|
||||
@msg Trap: no edges of different colours meet among the selected objects トラップ: 選択したオブジェクトに異なる色が接する辺がありません
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness は 0.01~5000 pt にしてください
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1642,7 +1642,6 @@ lighting Light სინათლე
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document ამ დოკუმენტში სიმბოლოები არ არის
|
||||
Select art and click New Symbol to make one. მონიშნეთ ნახატი და შესაქმნელად დაწკაპეთ „ახალ სიმბოლოზე“.
|
||||
Symbol Libraries (on the roadmap) სიმბოლოების ბიბლიოთეკები (სამომავლო გეგმაშია)
|
||||
Align On: სწორება მიმართ:
|
||||
Bottom-Justified Tab ქვემოთ სწორებული ტაბულაცია
|
||||
Center-Justified Tab ცენტრით სწორებული ტაბულაცია
|
||||
@@ -5391,6 +5390,32 @@ axis Y Axis Y ღერძი
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` ცოცხალი ეფექტი დოკუმენტის დახატვისას ეშვება, ამიტომ ის ვერ იქნება `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out ექსპორტის პლაგინი ყოველთვის ექსპორტის ბიუჯეტს იღებს: გამოტოვეთ `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees „{_1}“ დიდ გამოთვლით ბიუჯეტს ითხოვს (თითო გაშვება {minutes} წუთამდე და ჩვეულებრივზე {times}-ჯერ მეტი ინსტრუქცია): მომხმარებლის თანხმობის შემდეგ დააყენეთ ის `allowHeavy: true` პარამეტრით
|
||||
Add to Symbols სიმბოლოებში დამატება
|
||||
Basic Shapes ძირითადი ფიგურები
|
||||
Open Symbol Library სიმბოლოების ბიბლიოთეკის გახსნა
|
||||
Save Symbol Library სიმბოლოების ბიბლიოთეკის შენახვა
|
||||
Save Symbol Library… სიმბოლოების ბიბლიოთეკის შენახვა…
|
||||
Save Symbols… სიმბოლოების შენახვა…
|
||||
Selected Symbols Only მხოლოდ მონიშნული სიმბოლოები
|
||||
Symbol Libraries Menu სიმბოლოების ბიბლიოთეკების მენიუ
|
||||
Symbol Library სიმბოლოების ბიბლიოთეკა
|
||||
User Symbol Library 1 მომხმარებლის სიმბოლოების ბიბლიოთეკა 1
|
||||
User Symbol Library 2 მომხმარებლის სიმბოლოების ბიბლიოთეკა 2
|
||||
User Symbol Library 3 მომხმარებლის სიმბოლოების ბიბლიოთეკა 3
|
||||
User Symbol Library 4 მომხმარებლის სიმბოლოების ბიბლიოთეკა 4
|
||||
User Symbol Library 5 მომხმარებლის სიმბოლოების ბიბლიოთეკა 5
|
||||
User Symbol Library 6 მომხმარებლის სიმბოლოების ბიბლიოთეკა 6
|
||||
User Symbol Library 7 მომხმარებლის სიმბოლოების ბიბლიოთეკა 7
|
||||
User Symbol Library 8 მომხმარებლის სიმბოლოების ბიბლიოთეკა 8
|
||||
User Symbol Library 9 მომხმარებლის სიმბოლოების ბიბლიოთეკა 9
|
||||
User Symbol Library 10 მომხმარებლის სიმბოლოების ბიბლიოთეკა 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}`-ში განსათავსებელი სიმბოლოები არ არის
|
||||
@msg missing `library` (see symbol.libraries) `library` აკლია (იხ. symbol.libraries)
|
||||
@msg no symbol `{n}` სიმბოლო `{n}` არ არის
|
||||
@msg no symbol `{n}` in `{_1}` `{_1}`-ში სიმბოლო `{n}` არ არის
|
||||
@msg no symbol library `{key}` (see symbol.libraries) სიმბოლოების ბიბლიოთეკა `{key}` არ არის (იხ. symbol.libraries)
|
||||
@msg the document has no symbols to save დოკუმენტში შესანახი სიმბოლოები არ არის
|
||||
@msg Trap: select two or more objects filled with solid colours ტრეპინგი: აირჩიეთ ორი ან მეტი ობიექტი, შევსებული ერთგვაროვანი ფერით
|
||||
@msg Trap: no edges of different colours meet among the selected objects ტრეპინგი: არჩეულ ობიექტებს შორის განსხვავებული ფერის კიდეები არ ეხება ერთმანეთს
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness უნდა იყოს 0,01-დან 5000 pt-მდე
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2984,7 +2984,6 @@ mark-style Japanese 일본식
|
||||
Use Library Item 라이브러리 항목 사용
|
||||
Graphic 그래픽
|
||||
Show all open documents 열린 문서 모두 표시
|
||||
Symbol Libraries (on the roadmap) 심볼 라이브러리(예정)
|
||||
Symbol Screener Tool 심볼 스크리너 도구
|
||||
Symbol Scruncher Tool 심볼 스크런처 도구
|
||||
Symbol Shifter Tool 심볼 시프터 도구
|
||||
@@ -5055,6 +5054,32 @@ axis Y Axis Y축
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` 라이브 효과는 문서를 그리는 동안 실행되므로 `heavy`일 수 없습니다
|
||||
@msg an exporter always gets an export's budget: leave `budget` out 내보내기 플러그인은 항상 내보내기 예산을 받습니다. `budget`은 생략하세요
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees “{_1}”은(는) 큰 계산 예산을 요청합니다(실행당 최대 {minutes}분, 평소의 {times}배 명령어). 사용자가 동의하면 `allowHeavy: true`로 설치하세요
|
||||
Add to Symbols 심볼에 추가
|
||||
Basic Shapes 기본 모양
|
||||
Open Symbol Library 심볼 라이브러리 열기
|
||||
Save Symbol Library 심볼 라이브러리 저장
|
||||
Save Symbol Library… 심볼 라이브러리 저장…
|
||||
Save Symbols… 심볼 저장…
|
||||
Selected Symbols Only 선택한 심볼만
|
||||
Symbol Libraries Menu 심볼 라이브러리 메뉴
|
||||
Symbol Library 심볼 라이브러리
|
||||
User Symbol Library 1 사용자 심볼 라이브러리 1
|
||||
User Symbol Library 2 사용자 심볼 라이브러리 2
|
||||
User Symbol Library 3 사용자 심볼 라이브러리 3
|
||||
User Symbol Library 4 사용자 심볼 라이브러리 4
|
||||
User Symbol Library 5 사용자 심볼 라이브러리 5
|
||||
User Symbol Library 6 사용자 심볼 라이브러리 6
|
||||
User Symbol Library 7 사용자 심볼 라이브러리 7
|
||||
User Symbol Library 8 사용자 심볼 라이브러리 8
|
||||
User Symbol Library 9 사용자 심볼 라이브러리 9
|
||||
User Symbol Library 10 사용자 심볼 라이브러리 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}`에 배치할 심볼이 없습니다
|
||||
@msg missing `library` (see symbol.libraries) `library`가 없습니다(symbol.libraries 참조)
|
||||
@msg no symbol `{n}` 심볼 `{n}`이(가) 없습니다
|
||||
@msg no symbol `{n}` in `{_1}` `{_1}`에 심볼 `{n}`이(가) 없습니다
|
||||
@msg no symbol library `{key}` (see symbol.libraries) 심볼 라이브러리 `{key}`이(가) 없습니다(symbol.libraries 참조)
|
||||
@msg the document has no symbols to save 문서에 저장할 심볼이 없습니다
|
||||
@msg Trap: select two or more objects filled with solid colours 트랩: 단색으로 칠한 개체를 두 개 이상 선택하십시오
|
||||
@msg Trap: no edges of different colours meet among the selected objects 트랩: 선택한 개체 사이에 서로 다른 색상이 맞닿는 가장자리가 없습니다
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness는 0.01~5000pt여야 합니다
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1756,7 +1756,6 @@ lighting Light Licht
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document Geen symbolen in dit document
|
||||
Select art and click New Symbol to make one. Selecteer artwork en klik op Nieuw symbool om er een te maken.
|
||||
Symbol Libraries (on the roadmap) Symboolbibliotheken (op de roadmap)
|
||||
Align On: Uitlijnen op:
|
||||
Bottom-Justified Tab Onder uitgelijnde tabstop
|
||||
Center-Justified Tab Midden uitgelijnde tabstop
|
||||
@@ -5483,6 +5482,26 @@ axis Y Axis Y-as
|
||||
The plug-in is computing… De plug-in is aan het rekenen…
|
||||
Inspect Plug-in Plug-in inspecteren
|
||||
Cancel Plug-in Run Plug-in-run annuleren
|
||||
Add to Symbols Aan symbolen toevoegen
|
||||
Basic Shapes Basisvormen
|
||||
Open Symbol Library Symboolbibliotheek openen
|
||||
Save Symbol Library Symboolbibliotheek opslaan
|
||||
Save Symbol Library… Symboolbibliotheek opslaan…
|
||||
Save Symbols… Symbolen opslaan…
|
||||
Selected Symbols Only Alleen geselecteerde symbolen
|
||||
Symbol Libraries Menu Menu symboolbibliotheken
|
||||
Symbol Library Symboolbibliotheek
|
||||
User Symbol Library 1 Symboolbibliotheek van gebruiker 1
|
||||
User Symbol Library 2 Symboolbibliotheek van gebruiker 2
|
||||
User Symbol Library 3 Symboolbibliotheek van gebruiker 3
|
||||
User Symbol Library 4 Symboolbibliotheek van gebruiker 4
|
||||
User Symbol Library 5 Symboolbibliotheek van gebruiker 5
|
||||
User Symbol Library 6 Symboolbibliotheek van gebruiker 6
|
||||
User Symbol Library 7 Symboolbibliotheek van gebruiker 7
|
||||
User Symbol Library 8 Symboolbibliotheek van gebruiker 8
|
||||
User Symbol Library 9 Symboolbibliotheek van gebruiker 9
|
||||
User Symbol Library 10 Symboolbibliotheek van gebruiker 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg Trap: select two or more objects filled with solid colours Overbrugging: selecteer twee of meer objecten met een egale vulkleur
|
||||
@msg Trap: no edges of different colours meet among the selected objects Overbrugging: tussen de geselecteerde objecten raken geen randen van verschillende kleuren elkaar
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness moet tussen 0,01 en 5000 pt liggen
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1844,7 +1844,6 @@ lighting Light Światło
|
||||
{kind}, {model} {kind}, {model}
|
||||
No symbols in this document Brak symboli w tym dokumencie
|
||||
Select art and click New Symbol to make one. Zaznacz kompozycję i kliknij Nowy symbol, aby go utworzyć.
|
||||
Symbol Libraries (on the roadmap) Biblioteki symboli (w planach)
|
||||
Align On: Wyrównaj do:
|
||||
Bottom-Justified Tab Tabulator dolny
|
||||
Center-Justified Tab Tabulator środkowy
|
||||
@@ -5327,6 +5326,32 @@ axis Y Axis Oś Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` efekt na żywo działa podczas rysowania dokumentu, więc nie może być `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out wtyczka eksportu zawsze dostaje budżet eksportu: pomiń `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees „{_1}” prosi o duży budżet obliczeń (każde uruchomienie do {minutes} minut i {times} razy więcej instrukcji niż zwykle): zainstaluj wtyczkę z `allowHeavy: true`, gdy użytkownik się zgodzi
|
||||
Add to Symbols Dodaj do symboli
|
||||
Basic Shapes Kształty podstawowe
|
||||
Open Symbol Library Otwórz bibliotekę symboli
|
||||
Save Symbol Library Zapisz bibliotekę symboli
|
||||
Save Symbol Library… Zapisz bibliotekę symboli…
|
||||
Save Symbols… Zapisz symbole…
|
||||
Selected Symbols Only Tylko zaznaczone symbole
|
||||
Symbol Libraries Menu Menu bibliotek symboli
|
||||
Symbol Library Biblioteka symboli
|
||||
User Symbol Library 1 Biblioteka symboli użytkownika 1
|
||||
User Symbol Library 2 Biblioteka symboli użytkownika 2
|
||||
User Symbol Library 3 Biblioteka symboli użytkownika 3
|
||||
User Symbol Library 4 Biblioteka symboli użytkownika 4
|
||||
User Symbol Library 5 Biblioteka symboli użytkownika 5
|
||||
User Symbol Library 6 Biblioteka symboli użytkownika 6
|
||||
User Symbol Library 7 Biblioteka symboli użytkownika 7
|
||||
User Symbol Library 8 Biblioteka symboli użytkownika 8
|
||||
User Symbol Library 9 Biblioteka symboli użytkownika 9
|
||||
User Symbol Library 10 Biblioteka symboli użytkownika 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` nie ma symboli do umieszczenia
|
||||
@msg missing `library` (see symbol.libraries) brak `library` (zobacz symbol.libraries)
|
||||
@msg no symbol `{n}` brak symbolu `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` brak symbolu `{n}` w `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) brak biblioteki symboli `{key}` (zobacz symbol.libraries)
|
||||
@msg the document has no symbols to save dokument nie ma symboli do zapisania
|
||||
@msg Trap: select two or more objects filled with solid colours Zalewka: zaznacz co najmniej dwa obiekty wypełnione kolorem jednolitym
|
||||
@msg Trap: no edges of different colours meet among the selected objects Zalewka: wśród zaznaczonych obiektów nie stykają się krawędzie różnych kolorów
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness musi wynosić od 0,01 do 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2636,7 +2636,6 @@
|
||||
Switch workspace Trocar espaço de trabalho
|
||||
Symbol Instance Instância de Símbolo
|
||||
Symbol Libraries Bibliotecas de Símbolos
|
||||
Symbol Libraries (on the roadmap) Bibliotecas de Símbolos (no roadmap)
|
||||
Symbol Screener Tool Ferramenta Peneira de Símbolos
|
||||
Symbol Scruncher Tool Ferramenta Amontoar Símbolos
|
||||
Symbol Shifter Tool Ferramenta Deslocador de Símbolos
|
||||
@@ -5392,6 +5391,32 @@ axis Y Axis Eixo Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` um efeito dinâmico é executado enquanto o documento é desenhado, então não pode ser `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out um plug-in de exportação sempre recebe o orçamento de uma exportação: omita `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees “{_1}” pede um orçamento de processamento grande (cada execução até {minutes} minutos e {times} vezes as instruções habituais): instale-o com `allowHeavy: true` depois que o usuário concordar
|
||||
Add to Symbols Adicionar aos Símbolos
|
||||
Basic Shapes Formas Básicas
|
||||
Open Symbol Library Abrir Biblioteca de Símbolos
|
||||
Save Symbol Library Salvar Biblioteca de Símbolos
|
||||
Save Symbol Library… Salvar Biblioteca de Símbolos…
|
||||
Save Symbols… Salvar Símbolos…
|
||||
Selected Symbols Only Somente Símbolos Selecionados
|
||||
Symbol Libraries Menu Menu de Bibliotecas de Símbolos
|
||||
Symbol Library Biblioteca de Símbolos
|
||||
User Symbol Library 1 Biblioteca de Símbolos do Usuário 1
|
||||
User Symbol Library 2 Biblioteca de Símbolos do Usuário 2
|
||||
User Symbol Library 3 Biblioteca de Símbolos do Usuário 3
|
||||
User Symbol Library 4 Biblioteca de Símbolos do Usuário 4
|
||||
User Symbol Library 5 Biblioteca de Símbolos do Usuário 5
|
||||
User Symbol Library 6 Biblioteca de Símbolos do Usuário 6
|
||||
User Symbol Library 7 Biblioteca de Símbolos do Usuário 7
|
||||
User Symbol Library 8 Biblioteca de Símbolos do Usuário 8
|
||||
User Symbol Library 9 Biblioteca de Símbolos do Usuário 9
|
||||
User Symbol Library 10 Biblioteca de Símbolos do Usuário 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` não tem símbolos para inserir
|
||||
@msg missing `library` (see symbol.libraries) falta `library` (consulte symbol.libraries)
|
||||
@msg no symbol `{n}` nenhum símbolo `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` nenhum símbolo `{n}` em `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) nenhuma biblioteca de símbolos `{key}` (consulte symbol.libraries)
|
||||
@msg the document has no symbols to save o documento não tem símbolos para salvar
|
||||
@msg Trap: select two or more objects filled with solid colours Armadilha: selecione dois ou mais objetos preenchidos com cores sólidas
|
||||
@msg Trap: no edges of different colours meet among the selected objects Armadilha: nenhuma borda de cores diferentes se encontra entre os objetos selecionados
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness deve estar entre 0,01 e 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3264,7 +3264,6 @@ mark-style Japanese Японский
|
||||
Show all open documents Показать все открытые документы
|
||||
Symbol Instance Экземпляр символа
|
||||
Symbol Libraries Библиотеки символов
|
||||
Symbol Libraries (on the roadmap) Библиотеки символов (в плане развития)
|
||||
Symbol Screener Tool Инструмент «Прозрачность символов»
|
||||
Symbol Scruncher Tool Инструмент «Сжатие символов»
|
||||
Symbol Shifter Tool Инструмент «Сдвиг символов»
|
||||
@@ -5088,6 +5087,32 @@ axis Y Axis Ось Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` динамический эффект выполняется во время отрисовки документа, поэтому он не может быть `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out модуль экспорта всегда получает бюджет экспорта: не указывайте `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees «{_1}» запрашивает большой вычислительный бюджет (каждый запуск до {minutes} минут и в {times} раз больше инструкций, чем обычно): установите его с `allowHeavy: true`, когда пользователь согласится
|
||||
Add to Symbols Добавить в символы
|
||||
Basic Shapes Базовые фигуры
|
||||
Open Symbol Library Открыть библиотеку символов
|
||||
Save Symbol Library Сохранить библиотеку символов
|
||||
Save Symbol Library… Сохранить библиотеку символов…
|
||||
Save Symbols… Сохранить символы…
|
||||
Selected Symbols Only Только выбранные символы
|
||||
Symbol Libraries Menu Меню «Библиотеки символов»
|
||||
Symbol Library Библиотека символов
|
||||
User Symbol Library 1 Пользовательская библиотека символов 1
|
||||
User Symbol Library 2 Пользовательская библиотека символов 2
|
||||
User Symbol Library 3 Пользовательская библиотека символов 3
|
||||
User Symbol Library 4 Пользовательская библиотека символов 4
|
||||
User Symbol Library 5 Пользовательская библиотека символов 5
|
||||
User Symbol Library 6 Пользовательская библиотека символов 6
|
||||
User Symbol Library 7 Пользовательская библиотека символов 7
|
||||
User Symbol Library 8 Пользовательская библиотека символов 8
|
||||
User Symbol Library 9 Пользовательская библиотека символов 9
|
||||
User Symbol Library 10 Пользовательская библиотека символов 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place В `{_1}` нет символов для размещения
|
||||
@msg missing `library` (see symbol.libraries) не указан `library` (см. symbol.libraries)
|
||||
@msg no symbol `{n}` нет символа `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` нет символа `{n}` в `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) нет библиотеки символов `{key}` (см. symbol.libraries)
|
||||
@msg the document has no symbols to save в документе нет символов для сохранения
|
||||
@msg Trap: select two or more objects filled with solid colours Треппинг: выберите два или более объекта со сплошной заливкой
|
||||
@msg Trap: no edges of different colours meet among the selected objects Треппинг: среди выбранных объектов нет соприкасающихся краёв разных цветов
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness должно быть от 0,01 до 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3166,7 +3166,6 @@ font-technology Variable Variabla
|
||||
Show all open documents Visa alla öppna dokument
|
||||
Symbol Instance Symbolinstans
|
||||
Symbol Libraries Symbolbibliotek
|
||||
Symbol Libraries (on the roadmap) Symbolbibliotek (planeras)
|
||||
Symbol Screener Tool Verktyg för symbolopacitet
|
||||
Symbol Scruncher Tool Verktyg för att dra ihop symboler
|
||||
Symbol Shifter Tool Verktyg för att flytta symboler
|
||||
@@ -5431,6 +5430,32 @@ axis Y Axis Y-axel
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` en live-effekt körs medan dokumentet ritas, så den kan inte vara `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out ett exportinsticksprogram får alltid en exports budget: utelämna `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees ”{_1}” begär en stor beräkningsbudget (varje körning upp till {minutes} minuter och {times} gånger de vanliga instruktionerna): installera det med `allowHeavy: true` när användaren har godkänt
|
||||
Add to Symbols Lägg till i symboler
|
||||
Basic Shapes Grundformer
|
||||
Open Symbol Library Öppna symbolbibliotek
|
||||
Save Symbol Library Spara symbolbibliotek
|
||||
Save Symbol Library… Spara symbolbibliotek…
|
||||
Save Symbols… Spara symboler…
|
||||
Selected Symbols Only Endast markerade symboler
|
||||
Symbol Libraries Menu Meny för symbolbibliotek
|
||||
Symbol Library Symbolbibliotek
|
||||
User Symbol Library 1 Användarbibliotek för symboler 1
|
||||
User Symbol Library 2 Användarbibliotek för symboler 2
|
||||
User Symbol Library 3 Användarbibliotek för symboler 3
|
||||
User Symbol Library 4 Användarbibliotek för symboler 4
|
||||
User Symbol Library 5 Användarbibliotek för symboler 5
|
||||
User Symbol Library 6 Användarbibliotek för symboler 6
|
||||
User Symbol Library 7 Användarbibliotek för symboler 7
|
||||
User Symbol Library 8 Användarbibliotek för symboler 8
|
||||
User Symbol Library 9 Användarbibliotek för symboler 9
|
||||
User Symbol Library 10 Användarbibliotek för symboler 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` har inga symboler att placera
|
||||
@msg missing `library` (see symbol.libraries) `library` saknas (se symbol.libraries)
|
||||
@msg no symbol `{n}` ingen symbol `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` ingen symbol `{n}` i `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) inget symbolbibliotek `{key}` (se symbol.libraries)
|
||||
@msg the document has no symbols to save dokumentet har inga symboler att spara
|
||||
@msg Trap: select two or more objects filled with solid colours Överfyllning: markera två eller fler objekt fyllda med enfärgade färger
|
||||
@msg Trap: no edges of different colours meet among the selected objects Överfyllning: inga kanter i olika färger möts bland de markerade objekten
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness måste vara från 0,01 till 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3062,7 +3062,6 @@ font-technology Variable Değişken
|
||||
Show all open documents Tüm açık belgeleri göster
|
||||
Symbol Instance Sembol Örneği
|
||||
Symbol Libraries Sembol Kitaplıkları
|
||||
Symbol Libraries (on the roadmap) Sembol Kitaplıkları (yol haritasında)
|
||||
Symbol Screener Tool Sembol Perdeleyici Aracı
|
||||
Symbol Scruncher Tool Sembol Ezici Aracı
|
||||
Symbol Shifter Tool Sembol Yer Değiştirme Aracı
|
||||
@@ -5438,6 +5437,32 @@ axis Y Axis Y ekseni
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` canlı efekt belge çizilirken çalışır, bu yüzden `heavy` olamaz
|
||||
@msg an exporter always gets an export's budget: leave `budget` out dışa aktarma eklentisi her zaman bir dışa aktarmanın bütçesini alır: `budget` anahtarını çıkarın
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees “{_1}” büyük bir hesaplama bütçesi istiyor (her çalıştırma en fazla {minutes} dakika ve olağan komutların {times} katı): kullanıcı onayladıktan sonra `allowHeavy: true` ile yükleyin
|
||||
Add to Symbols Sembollere Ekle
|
||||
Basic Shapes Temel Şekiller
|
||||
Open Symbol Library Sembol Kitaplığını Aç
|
||||
Save Symbol Library Sembol Kitaplığını Kaydet
|
||||
Save Symbol Library… Sembol Kitaplığını Kaydet…
|
||||
Save Symbols… Sembolleri Kaydet…
|
||||
Selected Symbols Only Yalnızca Seçilen Semboller
|
||||
Symbol Libraries Menu Sembol Kitaplıkları Menüsü
|
||||
Symbol Library Sembol Kitaplığı
|
||||
User Symbol Library 1 Kullanıcı Sembol Kitaplığı 1
|
||||
User Symbol Library 2 Kullanıcı Sembol Kitaplığı 2
|
||||
User Symbol Library 3 Kullanıcı Sembol Kitaplığı 3
|
||||
User Symbol Library 4 Kullanıcı Sembol Kitaplığı 4
|
||||
User Symbol Library 5 Kullanıcı Sembol Kitaplığı 5
|
||||
User Symbol Library 6 Kullanıcı Sembol Kitaplığı 6
|
||||
User Symbol Library 7 Kullanıcı Sembol Kitaplığı 7
|
||||
User Symbol Library 8 Kullanıcı Sembol Kitaplığı 8
|
||||
User Symbol Library 9 Kullanıcı Sembol Kitaplığı 9
|
||||
User Symbol Library 10 Kullanıcı Sembol Kitaplığı 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` içinde yerleştirilecek sembol yok
|
||||
@msg missing `library` (see symbol.libraries) `library` eksik (bkz. symbol.libraries)
|
||||
@msg no symbol `{n}` `{n}` sembolü yok
|
||||
@msg no symbol `{n}` in `{_1}` `{_1}` içinde `{n}` sembolü yok
|
||||
@msg no symbol library `{key}` (see symbol.libraries) `{key}` sembol kitaplığı yok (bkz. symbol.libraries)
|
||||
@msg the document has no symbols to save belgede kaydedilecek sembol yok
|
||||
@msg Trap: select two or more objects filled with solid colours Tuzak: düz renkle doldurulmuş iki veya daha fazla nesne seçin
|
||||
@msg Trap: no edges of different colours meet among the selected objects Tuzak: seçili nesneler arasında farklı renkli kenarlar birleşmiyor
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness 0,01 ile 5000 pt arasında olmalıdır
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3261,7 +3261,6 @@ effect Points Точки
|
||||
Show all open documents Показати всі відкриті документи
|
||||
Symbol Instance Екземпляр символу
|
||||
Symbol Libraries Бібліотеки символів
|
||||
Symbol Libraries (on the roadmap) Бібліотеки символів (у плані розвитку)
|
||||
Symbol Screener Tool Інструмент «Прозорість символів»
|
||||
Symbol Scruncher Tool Інструмент «Стиск символів»
|
||||
Symbol Shifter Tool Інструмент «Зсув символів»
|
||||
@@ -5072,6 +5071,32 @@ axis Y Axis Вісь Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` динамічний ефект виконується під час відмальовування документа, тому він не може бути `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out модуль експорту завжди отримує бюджет експорту: не вказуйте `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees «{_1}» запитує великий обчислювальний бюджет (кожен запуск до {minutes} хвилин і в {times} разів більше інструкцій, ніж зазвичай): встановіть його з `allowHeavy: true`, коли користувач погодиться
|
||||
Add to Symbols Додати до символів
|
||||
Basic Shapes Базові фігури
|
||||
Open Symbol Library Відкрити бібліотеку символів
|
||||
Save Symbol Library Зберегти бібліотеку символів
|
||||
Save Symbol Library… Зберегти бібліотеку символів…
|
||||
Save Symbols… Зберегти символи…
|
||||
Selected Symbols Only Тільки вибрані символи
|
||||
Symbol Libraries Menu Меню "Бібліотеки символів"
|
||||
Symbol Library Бібліотека символів
|
||||
User Symbol Library 1 Користувацька бібліотека символів 1
|
||||
User Symbol Library 2 Користувацька бібліотека символів 2
|
||||
User Symbol Library 3 Користувацька бібліотека символів 3
|
||||
User Symbol Library 4 Користувацька бібліотека символів 4
|
||||
User Symbol Library 5 Користувацька бібліотека символів 5
|
||||
User Symbol Library 6 Користувацька бібліотека символів 6
|
||||
User Symbol Library 7 Користувацька бібліотека символів 7
|
||||
User Symbol Library 8 Користувацька бібліотека символів 8
|
||||
User Symbol Library 9 Користувацька бібліотека символів 9
|
||||
User Symbol Library 10 Користувацька бібліотека символів 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place У `{_1}` немає символів для розміщення
|
||||
@msg missing `library` (see symbol.libraries) не вказано `library` (див. symbol.libraries)
|
||||
@msg no symbol `{n}` немає символу `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` немає символу `{n}` у `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) немає бібліотеки символів `{key}` (див. symbol.libraries)
|
||||
@msg the document has no symbols to save у документі немає символів для збереження
|
||||
@msg Trap: select two or more objects filled with solid colours Трепінг: виберіть два або більше об’єктів із суцільною заливкою
|
||||
@msg Trap: no edges of different colours meet among the selected objects Трепінг: серед вибраних об’єктів немає дотичних країв різних кольорів
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness має бути від 0,01 до 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 740 and column 40.
|
@@ -3591,7 +3591,6 @@ mark-style Japanese Kiểu Nhật
|
||||
Switch x/y Đổi x/y
|
||||
Symbol Instance Thực thể ký hiệu
|
||||
Symbol Libraries Thư viện ký hiệu
|
||||
Symbol Libraries (on the roadmap) Thư viện ký hiệu (trong lộ trình)
|
||||
Symbol Screener Tool Công cụ Lọc ký hiệu
|
||||
Symbol Scruncher Tool Công cụ Thu gọn ký hiệu
|
||||
Symbol Set Density: Mật độ bộ ký hiệu:
|
||||
@@ -5072,6 +5071,32 @@ axis Y Axis Trục Y
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` hiệu ứng trực tiếp chạy trong lúc tài liệu được vẽ nên không thể là `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out plug-in xuất luôn nhận ngân sách của một lần xuất: hãy bỏ `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees “{_1}” yêu cầu ngân sách tính toán lớn (mỗi lần chạy tới {minutes} phút và gấp {times} lần số lệnh thông thường): hãy cài đặt với `allowHeavy: true` khi người dùng đồng ý
|
||||
Add to Symbols Thêm vào ký hiệu
|
||||
Basic Shapes Hình cơ bản
|
||||
Open Symbol Library Mở thư viện ký hiệu
|
||||
Save Symbol Library Lưu thư viện ký hiệu
|
||||
Save Symbol Library… Lưu thư viện ký hiệu…
|
||||
Save Symbols… Lưu ký hiệu…
|
||||
Selected Symbols Only Chỉ ký hiệu đã chọn
|
||||
Symbol Libraries Menu Menu thư viện ký hiệu
|
||||
Symbol Library Thư viện ký hiệu
|
||||
User Symbol Library 1 Thư viện ký hiệu người dùng 1
|
||||
User Symbol Library 2 Thư viện ký hiệu người dùng 2
|
||||
User Symbol Library 3 Thư viện ký hiệu người dùng 3
|
||||
User Symbol Library 4 Thư viện ký hiệu người dùng 4
|
||||
User Symbol Library 5 Thư viện ký hiệu người dùng 5
|
||||
User Symbol Library 6 Thư viện ký hiệu người dùng 6
|
||||
User Symbol Library 7 Thư viện ký hiệu người dùng 7
|
||||
User Symbol Library 8 Thư viện ký hiệu người dùng 8
|
||||
User Symbol Library 9 Thư viện ký hiệu người dùng 9
|
||||
User Symbol Library 10 Thư viện ký hiệu người dùng 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` không có ký hiệu nào để đặt
|
||||
@msg missing `library` (see symbol.libraries) thiếu `library` (xem symbol.libraries)
|
||||
@msg no symbol `{n}` không có ký hiệu `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` không có ký hiệu `{n}` trong `{_1}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) không có thư viện ký hiệu `{key}` (xem symbol.libraries)
|
||||
@msg the document has no symbols to save tài liệu không có ký hiệu nào để lưu
|
||||
@msg Trap: select two or more objects filled with solid colours Chồng màu: hãy chọn hai đối tượng trở lên được tô màu đặc
|
||||
@msg Trap: no edges of different colours meet among the selected objects Chồng màu: không có cạnh khác màu nào tiếp giáp giữa các đối tượng đã chọn
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness phải từ 0,01 đến 5000 pt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 4044 and column 10.
|
@@ -3100,7 +3100,6 @@ font-script Japanese 汉字
|
||||
Show all open documents 显示所有打开的文档
|
||||
Symbol Instance 符号实例
|
||||
Symbol Libraries 符号库
|
||||
Symbol Libraries (on the roadmap) 符号库 (已列入路线图)
|
||||
Symbol Screener Tool 符号透明度工具
|
||||
Symbol Scruncher Tool 符号紧缩工具
|
||||
Symbol Shifter Tool 符号移位工具
|
||||
@@ -5315,6 +5314,32 @@ axis Y Axis Y 轴
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` 实时效果在绘制文档时运行,因此不能为 `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out 导出增效工具始终使用导出的预算:请省略 `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees “{_1}”需要大量计算预算(每次运行最多 {minutes} 分钟,指令数为通常的 {times} 倍):请在用户同意后使用 `allowHeavy: true` 安装
|
||||
Add to Symbols 添加到符号
|
||||
Basic Shapes 基本形状
|
||||
Open Symbol Library 打开符号库
|
||||
Save Symbol Library 保存符号库
|
||||
Save Symbol Library… 保存符号库…
|
||||
Save Symbols… 保存符号…
|
||||
Selected Symbols Only 仅限选择的符号
|
||||
Symbol Libraries Menu 符号库菜单
|
||||
Symbol Library 符号库
|
||||
User Symbol Library 1 用户符号库 1
|
||||
User Symbol Library 2 用户符号库 2
|
||||
User Symbol Library 3 用户符号库 3
|
||||
User Symbol Library 4 用户符号库 4
|
||||
User Symbol Library 5 用户符号库 5
|
||||
User Symbol Library 6 用户符号库 6
|
||||
User Symbol Library 7 用户符号库 7
|
||||
User Symbol Library 8 用户符号库 8
|
||||
User Symbol Library 9 用户符号库 9
|
||||
User Symbol Library 10 用户符号库 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` 中没有可置入的符号
|
||||
@msg missing `library` (see symbol.libraries) 缺少 `library`(请参阅 symbol.libraries)
|
||||
@msg no symbol `{n}` 没有符号 `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` `{_1}` 中没有符号 `{n}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) 没有符号库 `{key}`(请参阅 symbol.libraries)
|
||||
@msg the document has no symbols to save 文档中没有可保存的符号
|
||||
@msg Trap: select two or more objects filled with solid colours 陷印:请选择两个或更多用实色填充的对象
|
||||
@msg Trap: no edges of different colours meet among the selected objects 陷印:所选对象中没有不同颜色相接的边缘
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness 必须介于 0.01 到 5000 pt 之间
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4025,7 +4025,6 @@ font-script Japanese 漢字
|
||||
Show all open documents 顯示所有開啟的文件
|
||||
Symbol Instance 符號範例
|
||||
Symbol Libraries 符號資料庫
|
||||
Symbol Libraries (on the roadmap) 符號資料庫 (已列入路線圖)
|
||||
Symbol Screener Tool 符號濾色器工具
|
||||
Symbol Scruncher Tool 符號緊縮器工具
|
||||
Symbol Shifter Tool 符號移位器工具
|
||||
@@ -5111,6 +5110,32 @@ axis Y Axis Y 軸
|
||||
@msg a live effect runs while the document is drawn, so it can't be `heavy` 即時效果會在繪製文件時執行,因此不能是 `heavy`
|
||||
@msg an exporter always gets an export's budget: leave `budget` out 匯出增效模組一律使用匯出的預算:請移除 `budget`
|
||||
@msg “{_1}” asks for a heavy budget (each run up to {minutes} minutes and {times} times the usual instructions): install it with `allowHeavy: true` once the user agrees 「{_1}」需要大量運算預算(每次執行最多 {minutes} 分鐘,指令數為一般的 {times} 倍):請在使用者同意後以 `allowHeavy: true` 安裝
|
||||
Add to Symbols 新增至符號
|
||||
Basic Shapes 基本形狀
|
||||
Open Symbol Library 開啟符號資料庫
|
||||
Save Symbol Library 儲存符號資料庫
|
||||
Save Symbol Library… 儲存符號資料庫…
|
||||
Save Symbols… 儲存符號…
|
||||
Selected Symbols Only 僅限選取的符號
|
||||
Symbol Libraries Menu 符號資料庫選單
|
||||
Symbol Library 符號資料庫
|
||||
User Symbol Library 1 使用者符號資料庫 1
|
||||
User Symbol Library 2 使用者符號資料庫 2
|
||||
User Symbol Library 3 使用者符號資料庫 3
|
||||
User Symbol Library 4 使用者符號資料庫 4
|
||||
User Symbol Library 5 使用者符號資料庫 5
|
||||
User Symbol Library 6 使用者符號資料庫 6
|
||||
User Symbol Library 7 使用者符號資料庫 7
|
||||
User Symbol Library 8 使用者符號資料庫 8
|
||||
User Symbol Library 9 使用者符號資料庫 9
|
||||
User Symbol Library 10 使用者符號資料庫 10
|
||||
{w} × {h} pt {w} × {h} pt
|
||||
@msg `{_1}` has no symbols to place `{_1}` 中沒有可置入的符號
|
||||
@msg missing `library` (see symbol.libraries) 未提供 `library`(請參閱 symbol.libraries)
|
||||
@msg no symbol `{n}` 沒有符號 `{n}`
|
||||
@msg no symbol `{n}` in `{_1}` `{_1}` 中沒有符號 `{n}`
|
||||
@msg no symbol library `{key}` (see symbol.libraries) 沒有符號資料庫 `{key}`(請參閱 symbol.libraries)
|
||||
@msg the document has no symbols to save 文件中沒有可儲存的符號
|
||||
@msg Trap: select two or more objects filled with solid colours 補漏白:請選取兩個或更多以實色填色的物件
|
||||
@msg Trap: no edges of different colours meet among the selected objects 補漏白:所選物件中沒有不同顏色相接的邊緣
|
||||
@msg thickness must be from 0.01 to 5000 pt thickness 必須介於 0.01 到 5000 pt 之間
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -761,6 +761,34 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
|
||||
("window.userGraphicStyleLibrary8", "User Graphic Style Library 8", "", "{} open the 8. User Defined graphic style library"),
|
||||
("window.userGraphicStyleLibrary9", "User Graphic Style Library 9", "", "{} open the 9. User Defined graphic style library"),
|
||||
("window.userGraphicStyleLibrary10", "User Graphic Style Library 10", "", "{} open the 10. User Defined graphic style library"),
|
||||
(
|
||||
"window.symbolLibrary",
|
||||
"Symbol Library",
|
||||
"",
|
||||
"{library: id or name (see symbol.libraries) | null (close)} open a symbol library in a library panel of its own (UI state `library_panels`, kind symbols); clicking a symbol there runs symbol.addFromLibrary, dragging one onto the canvas runs it with place → {open, panel, name, count}",
|
||||
),
|
||||
(
|
||||
"window.symbolLibrary.other",
|
||||
"Other Library…",
|
||||
"",
|
||||
"{path?} (default: pick a file) load the symbols of another document or a saved symbol library (engine: symbol.loadLibrary), and open them in a library panel",
|
||||
),
|
||||
(
|
||||
"ui.saveSymbolLibrary",
|
||||
"Save Symbols…",
|
||||
"",
|
||||
"{names?: [the symbol selected in the Symbols panel]} open Save Symbol Library (dialog `saveSymbolLibrary`: name, user: save to the user library folder, selectedOnly); OK runs symbol.saveLibrary",
|
||||
),
|
||||
("window.userSymbolLibrary1", "User Symbol Library 1", "", "{} open the 1. User Defined symbol library (symbol.libraries, category user)"),
|
||||
("window.userSymbolLibrary2", "User Symbol Library 2", "", "{} open the 2. User Defined symbol library"),
|
||||
("window.userSymbolLibrary3", "User Symbol Library 3", "", "{} open the 3. User Defined symbol library"),
|
||||
("window.userSymbolLibrary4", "User Symbol Library 4", "", "{} open the 4. User Defined symbol library"),
|
||||
("window.userSymbolLibrary5", "User Symbol Library 5", "", "{} open the 5. User Defined symbol library"),
|
||||
("window.userSymbolLibrary6", "User Symbol Library 6", "", "{} open the 6. User Defined symbol library"),
|
||||
("window.userSymbolLibrary7", "User Symbol Library 7", "", "{} open the 7. User Defined symbol library"),
|
||||
("window.userSymbolLibrary8", "User Symbol Library 8", "", "{} open the 8. User Defined symbol library"),
|
||||
("window.userSymbolLibrary9", "User Symbol Library 9", "", "{} open the 9. User Defined symbol library"),
|
||||
("window.userSymbolLibrary10", "User Symbol Library 10", "", "{} open the 10. User Defined symbol library"),
|
||||
(
|
||||
"ui.expandDialog",
|
||||
"Expand…",
|
||||
@@ -1774,6 +1802,16 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
|
||||
Some(l) => crate::panels::graphic_styles::open_library(app, &json!({ "library": l.id })),
|
||||
None => Err("no such user library".into()),
|
||||
},
|
||||
"window.symbolLibrary" => crate::panels::symbols::open_library(app, p),
|
||||
"window.symbolLibrary.other" => crate::panels::symbols::other_library(app, s("path")),
|
||||
"ui.saveSymbolLibrary" => {
|
||||
let names = p.get("names").and_then(Value::as_array).map(|a| a.iter().filter_map(Value::as_str).map(str::to_string).collect());
|
||||
crate::dialogs::save_symbol_library::open(app, names.unwrap_or_default())
|
||||
}
|
||||
id if id.starts_with(crate::panels::symbols::USER_SLOT) => match crate::panels::symbols::user_library(app, id) {
|
||||
Some(l) => crate::panels::symbols::open_library(app, &json!({ "library": l.id })),
|
||||
None => Err("no such user library".into()),
|
||||
},
|
||||
"ui.expandDialog" => crate::dialogs::expand::open(app),
|
||||
"ui.simplifyAuto" => crate::dialogs::simplify_slider::auto(app),
|
||||
"ui.simplifyMoreOptions" => crate::dialogs::simplify_slider::more_options(app),
|
||||
@@ -2091,6 +2129,9 @@ pub fn dynamic_label(app: &VectorcraftApp, id: &str, label: &str) -> String {
|
||||
id if id.starts_with(crate::panels::graphic_styles::USER_SLOT) => {
|
||||
crate::panels::graphic_styles::user_library(app, id).map_or_else(|| "—".into(), |l| l.name)
|
||||
}
|
||||
id if id.starts_with(crate::panels::symbols::USER_SLOT) => {
|
||||
crate::panels::symbols::user_library(app, id).map_or_else(|| "—".into(), |l| l.name)
|
||||
}
|
||||
id if id.starts_with(crate::dialogs::perspective_presets::SLOT) => {
|
||||
crate::dialogs::perspective_presets::slot_preset(app, id).unwrap_or_else(|| "—".into())
|
||||
}
|
||||
@@ -2106,12 +2147,13 @@ pub fn dynamic_label(app: &VectorcraftApp, id: &str, label: &str) -> String {
|
||||
/// plug-in? Such names are shown as they are, never translated (a workspace the user calls
|
||||
/// "Layers" stays "Layers").
|
||||
fn shows_a_name(id: &str, label: &str) -> bool {
|
||||
const SLOTS: [&str; 6] = [
|
||||
const SLOTS: [&str; 7] = [
|
||||
"file.openRecent",
|
||||
"view.goto",
|
||||
"type.recentFont",
|
||||
crate::panels::swatches::USER_SLOT,
|
||||
crate::panels::graphic_styles::USER_SLOT,
|
||||
crate::panels::symbols::USER_SLOT,
|
||||
crate::dialogs::perspective_presets::SLOT,
|
||||
];
|
||||
SLOTS.iter().any(|s| id.starts_with(s))
|
||||
@@ -2197,6 +2239,7 @@ fn hidden_when_disabled(id: &str) -> bool {
|
||||
|| id.starts_with("file.openRecent")
|
||||
|| id.starts_with(crate::panels::swatches::USER_SLOT)
|
||||
|| id.starts_with(crate::panels::graphic_styles::USER_SLOT)
|
||||
|| id.starts_with(crate::panels::symbols::USER_SLOT)
|
||||
|| id.starts_with(crate::dialogs::perspective_presets::SLOT)
|
||||
}
|
||||
|
||||
@@ -2497,6 +2540,8 @@ pub fn enabled(app: &VectorcraftApp, id: &str) -> bool {
|
||||
"ui.flattenTransparencyDialog" => app.session.active().is_some_and(|d| !d.selection.is_empty()),
|
||||
"ui.saveGraphicStyleLibrary" => app.session.active().is_some(),
|
||||
id if id.starts_with(crate::panels::graphic_styles::USER_SLOT) => crate::panels::graphic_styles::user_library(app, id).is_some(),
|
||||
"ui.saveSymbolLibrary" => app.session.active().is_some_and(|d| !d.doc.symbols.is_empty()),
|
||||
id if id.starts_with(crate::panels::symbols::USER_SLOT) => crate::panels::symbols::user_library(app, id).is_some(),
|
||||
"ui.expandDialog" => app.session.active().is_some_and(|d| !d.selection.is_empty()),
|
||||
"ui.spotColors" => app.session.active().is_some(),
|
||||
"ui.menuDialog" => app.session.active().is_some_and(|d| !d.selection.is_empty()),
|
||||
@@ -3195,7 +3240,7 @@ pub fn menu_tree_named(english_names: bool) -> Vec<(&'static str, Vec<Item>)> {
|
||||
sub("Brush Libraries", library_placeholders()),
|
||||
sub("Graphic Style Libraries", crate::panels::graphic_styles::window_menu()),
|
||||
sub("Swatch Libraries", crate::panels::swatches::window_menu()),
|
||||
sub("Symbol Libraries", library_placeholders()),
|
||||
sub("Symbol Libraries", crate::panels::symbols::window_menu()),
|
||||
],
|
||||
),
|
||||
(
|
||||
|
||||
@@ -213,7 +213,7 @@ fn paint_thumb(app: &VectorcraftApp, ui: &Ui, r: Rect, paints: Paints, g: &Graph
|
||||
}
|
||||
|
||||
/// Outline thumbnail `r`: in the accent colour when selected (`on`), brighter when hovered.
|
||||
fn outline(ui: &Ui, r: Rect, on: bool, hovered: bool) {
|
||||
pub(super) fn outline(ui: &Ui, r: Rect, on: bool, hovered: bool) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let color = if on {
|
||||
t.accent
|
||||
@@ -353,6 +353,7 @@ fn zone_input(ui: &Ui, zone: &Response, d: &Document, ev: &mut Events) {
|
||||
PanelDrag::Appearance(id) => (None, Some(*id)),
|
||||
PanelDrag::Paint { .. }
|
||||
| PanelDrag::Symbol(_)
|
||||
| PanelDrag::LibrarySymbol { .. }
|
||||
| PanelDrag::Brush { .. }
|
||||
| PanelDrag::LibraryGraphic { .. }
|
||||
| PanelDrag::LibraryItem { .. }
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
//! Library panels: read-only views of one library each (swatch and graphic style libraries; any
|
||||
//! kind of library implementing [`LibraryKind`]) with thumbnail and list views, a find field, the
|
||||
//! libraries menu and previous / next arrows. A plain click on an item adds it to the document and
|
||||
//! applies it; Shift and Cmd/Ctrl-clicks select items (and folders) for Add to ….
|
||||
//! Library panels: read-only views of one library each (swatch, graphic style and symbol
|
||||
//! libraries; any kind of library implementing [`LibraryKind`]) with thumbnail and list views, a
|
||||
//! find field, the libraries menu and previous / next arrows. A plain click on an item adds it to
|
||||
//! the document and applies it; Shift and Cmd/Ctrl-clicks select items (and folders) for Add to ….
|
||||
//! A kind whose items drag ([`LibraryKind::drag`]) lets them be dragged out of the panel.
|
||||
//!
|
||||
//! As in Illustrator (<https://helpx.adobe.com/illustrator/using/using-creating-swatches.html>,
|
||||
//! "Swatch libraries"), each open library is a panel of its own, `library:<kind>:<library id>`
|
||||
//! ([`panel_id`]), that floats, tabs, docks and closes as any panel of the shared docking system:
|
||||
//! `window.swatchLibrary` and `window.graphicStyleLibrary` open one, or bring it forward when it is
|
||||
//! `window.swatchLibrary`, `window.graphicStyleLibrary` and `window.symbolLibrary` open one, or bring it forward when it is
|
||||
//! open. `UiState::library_panels` keeps each one's view, Show Find Field and Persistent
|
||||
//! (`ui.libraryPanel`); a persistent panel reopens when the app starts ([`restore`]). A persistent
|
||||
//! panel whose library can't be found shows the library as missing, with its file and Locate
|
||||
@@ -25,7 +26,7 @@ use super::swatches::{View, click_selection, folder_tile, list_row, list_row_nam
|
||||
use super::{pstate, set_pstate};
|
||||
use crate::VectorcraftApp;
|
||||
use crate::state::UiState;
|
||||
use crate::widgets::{self, menu_item};
|
||||
use crate::widgets::{self, PanelDrag, menu_item};
|
||||
|
||||
/// What every library panel's id starts with.
|
||||
pub const PREFIX: &str = "library:";
|
||||
@@ -115,6 +116,10 @@ pub(crate) trait LibraryKind {
|
||||
fn click(app: &mut VectorcraftApp, ui: &Ui, id: &str, name: &str);
|
||||
/// Add the items and folders `names` of library `id` to the document.
|
||||
fn add(app: &mut VectorcraftApp, id: &str, names: Vec<String>);
|
||||
/// What dragging item `name` of library `id` out of the panel carries, if it drags.
|
||||
fn drag(_id: &str, _name: &str) -> Option<PanelDrag> {
|
||||
None
|
||||
}
|
||||
/// Items heading the libraries menu.
|
||||
fn menu_head(_app: &mut VectorcraftApp, _ui: &mut Ui) {}
|
||||
/// Items closing the libraries menu.
|
||||
@@ -154,7 +159,13 @@ fn kind_of<K: LibraryKind>() -> Kind {
|
||||
|
||||
/// The kind of library `kind` names.
|
||||
fn kind(kind: &str) -> Option<Kind> {
|
||||
[kind_of::<super::swatches::SwatchLibraries>(), kind_of::<super::graphic_styles::GraphicStyleLibraries>()].into_iter().find(|k| k.kind == kind)
|
||||
[
|
||||
kind_of::<super::swatches::SwatchLibraries>(),
|
||||
kind_of::<super::graphic_styles::GraphicStyleLibraries>(),
|
||||
kind_of::<super::symbols::SymbolLibraries>(),
|
||||
]
|
||||
.into_iter()
|
||||
.find(|k| k.kind == kind)
|
||||
}
|
||||
|
||||
/// The id of the panel of library `id` of `kind` (`library:swatches:pastels`).
|
||||
@@ -541,7 +552,8 @@ fn set(app: &mut VectorcraftApp, panel: &str, mut params: Value) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Open-dialog filters for Other Library… / Locate Library… of library panels of kind `kind`.
|
||||
/// Open-dialog filters for Other Library… / Locate Library… of library panels of kind `kind`
|
||||
/// (symbol libraries: any document).
|
||||
pub(crate) fn library_pick_filters(kind: &str) -> Vec<(&'static str, &'static [&'static str])> {
|
||||
match kind {
|
||||
super::swatches::SwatchLibraries::KIND => fileio::library_open_filters("Swatch libraries", swatchlib::LIBRARY_EXTS).collect(),
|
||||
@@ -628,16 +640,18 @@ fn body<K: LibraryKind>(app: &mut VectorcraftApp, ui: &mut Ui, id: &str) {
|
||||
None => super::swatches::draw_folder(ui, chip),
|
||||
}
|
||||
list_row_name(ui, r, chip, row.name);
|
||||
drag_out::<K>(ui, &resp, id, row);
|
||||
let tip = || row.item.map_or_else(|| row.name.to_string(), |i| format!("{} ({})", row.name, K::describe(i)));
|
||||
click(ui, resp, row, &tip);
|
||||
}
|
||||
} else {
|
||||
for (row, cell) in tile_grid(ui, &rows, view, |r| r.item.is_none()) {
|
||||
let resp = ui.interact(cell, tile_id(&panel, row.name), Sense::click());
|
||||
let resp = ui.interact(cell, tile_id(&panel, row.name), Sense::click_and_drag());
|
||||
match row.item {
|
||||
Some(item) => K::draw(app, ui, cell, item, is_sel(row.name), resp.hovered()),
|
||||
None => folder_tile(ui, cell, is_sel(row.name)),
|
||||
}
|
||||
drag_out::<K>(ui, &resp, id, row);
|
||||
click(ui, resp, row, &|| row.name.to_string());
|
||||
}
|
||||
}
|
||||
@@ -656,6 +670,16 @@ fn body<K: LibraryKind>(app: &mut VectorcraftApp, ui: &mut Ui, id: &str) {
|
||||
bottom::<K>(app, ui, id);
|
||||
}
|
||||
|
||||
/// An item of library `id` dragged out of its tile or row `resp` carries what `K` says it does.
|
||||
fn drag_out<K: LibraryKind>(ui: &Ui, resp: &egui::Response, id: &str, row: &Row<K::Item>) {
|
||||
if row.item.is_some()
|
||||
&& resp.drag_started()
|
||||
&& let Some(drag) = K::drag(id, row.name)
|
||||
{
|
||||
egui::DragAndDrop::set_payload(ui.ctx(), drag);
|
||||
}
|
||||
}
|
||||
|
||||
/// The body of the panel of library `id` when the library is missing ([`missing_file`]): its file,
|
||||
/// and Locate Library… where the app has an open dialog.
|
||||
fn missing<K: LibraryKind>(app: &mut VectorcraftApp, ui: &mut Ui, id: &str) {
|
||||
|
||||
@@ -625,4 +625,6 @@ mod tests_strokeux;
|
||||
#[cfg(test)]
|
||||
mod tests_style_libraries;
|
||||
#[cfg(test)]
|
||||
mod tests_symbol_libraries;
|
||||
#[cfg(test)]
|
||||
mod tests_units;
|
||||
|
||||
@@ -612,6 +612,10 @@ pub(crate) fn drag_preview(app: &VectorcraftApp, ctx: &egui::Context) {
|
||||
Some(st) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &st.doc, r, name)),
|
||||
None => return,
|
||||
},
|
||||
PanelDrag::LibrarySymbol { library, name } => match vectorcraft_engine::cmd::symbollib::library(&app.session, library) {
|
||||
Some((_, lib)) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &lib.doc, r, name)),
|
||||
None => return,
|
||||
},
|
||||
PanelDrag::Brush { def, .. } => return pointer_chip(ctx, |ui, r| super::brushes::chip(ui, r, def)),
|
||||
PanelDrag::LibraryGraphic { library, item } => return pointer_chip(ctx, |ui, r| super::libraries::chip(app, ui, r, library, item)),
|
||||
PanelDrag::LibraryItem { .. } | PanelDrag::LibraryGroup { .. } => return,
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
//! Symbols panel: the document's symbols as rendered thumbnails or a list. Click selects a symbol
|
||||
//! (it becomes the Symbol Sprayer's current symbol); double-click places an instance.
|
||||
//! (it becomes the Symbol Sprayer's current symbol); double-click places an instance. Symbol
|
||||
//! libraries open in library panels ([`SymbolLibraries`]).
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use egui::{Sense, Stroke, StrokeKind, Ui, vec2};
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_doc::{Document, Node, NodeKind};
|
||||
use vectorcraft_engine::cmd::swatchlib::LibraryInfo;
|
||||
use vectorcraft_engine::cmd::symbollib::{self, SymbolLibrary};
|
||||
|
||||
use super::library_panel::{self, LibraryKind, LibraryRef, Row};
|
||||
use super::{pstate, set_pstate};
|
||||
use crate::VectorcraftApp;
|
||||
use crate::menus::Item;
|
||||
use crate::theme::Tokens;
|
||||
use crate::widgets::{self, PanelDrag, menu_item};
|
||||
|
||||
@@ -146,7 +152,12 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
let has_sel = app.session.active().is_some_and(|d| !d.selection.is_empty());
|
||||
let inst = has_instances_selected(app);
|
||||
widgets::bottom_bar(ui, |ui| {
|
||||
widgets::icon_button_enabled(ui, "library", tl!("Symbol Libraries (on the roadmap)"), false, false, 24.0);
|
||||
let open = library_panel::any_open::<SymbolLibraries>(&app.ui);
|
||||
let lr = widgets::icon_button(ui, "library", SymbolLibraries::MENU, open, 24.0);
|
||||
egui::Popup::menu(&lr).show(|ui| {
|
||||
ui.set_min_width(200.0);
|
||||
library_panel::library_menu::<SymbolLibraries>(app, ui);
|
||||
});
|
||||
if widgets::icon_button_enabled(ui, "dc-place-symbol", tl!("Place Symbol Instance"), false, sel.is_some(), 24.0).clicked() {
|
||||
app.run("symbol.place", json!({})).ok();
|
||||
}
|
||||
@@ -197,6 +208,176 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
if menu_item(ui, tl!("List View"), true, list) {
|
||||
set_pstate(ui.ctx(), "sym-list", true);
|
||||
}
|
||||
ui.separator();
|
||||
ui.menu_button(tl!("Open Symbol Library"), |ui| library_panel::library_menu::<SymbolLibraries>(app, ui));
|
||||
let has_symbols = app.session.active().is_some_and(|d| !d.doc.symbols.is_empty());
|
||||
if menu_item(ui, tl!("Save Symbol Library…"), has_symbols, false) {
|
||||
save_library(app, sel.into_iter().collect());
|
||||
}
|
||||
}
|
||||
|
||||
/// Save Symbol Library… for the document's symbols (`names`: the one selected in the panel).
|
||||
fn save_library(app: &mut VectorcraftApp, names: Vec<String>) {
|
||||
if let Err(e) = app.run("ui.saveSymbolLibrary", json!({ "names": names })) {
|
||||
app.status(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- libraries ----------
|
||||
|
||||
/// A symbol of a library as the library panel shows it.
|
||||
pub(crate) struct LibSymbol {
|
||||
lib: Arc<SymbolLibrary>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl LibSymbol {
|
||||
fn name(&self) -> &str {
|
||||
self.lib.doc.symbols.get(self.index).map_or("", |s| s.name.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// Symbol libraries in library panels (engine: `symbol.libraries`, `symbol.addFromLibrary`…).
|
||||
pub(crate) struct SymbolLibraries;
|
||||
|
||||
impl LibraryKind for SymbolLibraries {
|
||||
const KIND: &'static str = "symbols";
|
||||
const OPEN: &'static str = "window.symbolLibrary";
|
||||
const LIST: &'static str = "symbol.libraries";
|
||||
const LOAD: &'static str = "symbol.loadLibrary";
|
||||
const MENU: &'static str = "Symbol Libraries Menu";
|
||||
const ADD: &'static str = "Add to Symbols";
|
||||
/// Symbols need room to show their art.
|
||||
const VIEW: super::swatches::View = super::swatches::View::LargeThumb;
|
||||
type Lib = Arc<Vec<LibSymbol>>;
|
||||
type Item = LibSymbol;
|
||||
|
||||
fn list(app: &VectorcraftApp) -> Vec<LibraryRef> {
|
||||
let libs = symbollib::libraries(&app.session).into_iter();
|
||||
libs.map(|l| LibraryRef { submenu: library_panel::submenu(l.category), id: l.id, name: l.name }).collect()
|
||||
}
|
||||
fn get(app: &VectorcraftApp, id: &str) -> Option<(String, Self::Lib)> {
|
||||
let (info, lib) = symbollib::library(&app.session, id)?;
|
||||
let shown = (0..lib.len()).map(|index| LibSymbol { lib: lib.clone(), index }).collect();
|
||||
Some((info.name, Arc::new(shown)))
|
||||
}
|
||||
fn find(app: &VectorcraftApp, key: &str) -> library_panel::Found {
|
||||
symbollib::library(&app.session, key).map(|(info, lib)| (info.id, info.name, lib.len()))
|
||||
}
|
||||
fn path(app: &VectorcraftApp, id: &str) -> Option<String> {
|
||||
app.session.symbol_libraries.path(id).map(str::to_string)
|
||||
}
|
||||
fn rows<'a>(lib: &'a Self::Lib, query: &str) -> Vec<Row<'a, LibSymbol>> {
|
||||
let found = |n: &str| query.is_empty() || n.to_lowercase().contains(query);
|
||||
lib.iter().filter(|s| found(s.name())).map(|s| Row { name: s.name(), item: Some(s) }).collect()
|
||||
}
|
||||
/// The symbol's art on white, as the Symbols panel shows it.
|
||||
fn draw(_: &VectorcraftApp, ui: &Ui, r: egui::Rect, s: &LibSymbol, selected: bool, hovered: bool) {
|
||||
chip(ui, &s.lib.doc, r, s.name());
|
||||
super::graphic_styles::outline(ui, r, selected, hovered);
|
||||
}
|
||||
fn row_icons(_: &Ui, _: egui::Rect, _: &LibSymbol) {}
|
||||
/// Its natural size.
|
||||
fn describe(s: &LibSymbol) -> String {
|
||||
let (w, h) = symbol_size(&s.lib.doc, s.name());
|
||||
let num = |v: f64| format!("{}", (v * 100.0).round() / 100.0);
|
||||
crate::i18n::fmt(tl!("{w} × {h} pt"), &[("w", &num(w)), ("h", &num(h))])
|
||||
}
|
||||
/// Adds the symbol to the document's Symbols, as the current symbol.
|
||||
fn click(app: &mut VectorcraftApp, _: &Ui, id: &str, name: &str) {
|
||||
add(app, json!({"library": id, "name": name}));
|
||||
}
|
||||
fn add(app: &mut VectorcraftApp, id: &str, names: Vec<String>) {
|
||||
add(app, json!({"library": id, "names": names}));
|
||||
}
|
||||
/// Dragged onto the canvas, the symbol is added and an instance placed where it is dropped.
|
||||
fn drag(id: &str, name: &str) -> Option<PanelDrag> {
|
||||
Some(PanelDrag::LibrarySymbol { library: id.to_string(), name: name.to_string() })
|
||||
}
|
||||
fn menu_tail(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
ui.separator();
|
||||
// As a command, so its file dialog, shown off the UI thread, loads the library when it
|
||||
// answers.
|
||||
if menu_item(ui, tl!("Other Library…"), true, false)
|
||||
&& let Err(e) = app.run("window.symbolLibrary.other", json!({}))
|
||||
{
|
||||
app.status(e);
|
||||
}
|
||||
let has_symbols = app.session.active().is_some_and(|d| !d.doc.symbols.is_empty());
|
||||
if menu_item(ui, tl!("Save Symbols…"), has_symbols, false) {
|
||||
let sel = current(app);
|
||||
save_library(app, sel.into_iter().collect());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Run `symbol.addFromLibrary` with `p`; a failure goes to the status bar.
|
||||
fn add(app: &mut VectorcraftApp, p: Value) {
|
||||
if let Err(e) = app.run("symbol.addFromLibrary", p) {
|
||||
app.status(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Symbol `name`'s natural size in `doc`.
|
||||
fn symbol_size(doc: &Document, name: &str) -> (f64, f64) {
|
||||
let size = doc.unknown.get(vectorcraft_doc::SYMBOL_SIZES).and_then(|m| m.get(name));
|
||||
size.and_then(|v| Some((v.get(0)?.as_f64()?, v.get(1)?.as_f64()?)))
|
||||
.unwrap_or((2.0 * vectorcraft_doc::SYMBOL_HALF, 2.0 * vectorcraft_doc::SYMBOL_HALF))
|
||||
}
|
||||
|
||||
/// `window.symbolLibrary {library}`: open a symbol library in its own panel (`library` null closes
|
||||
/// every symbol library panel).
|
||||
pub(crate) fn open_library(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
|
||||
library_panel::open_command::<SymbolLibraries>(app, p)
|
||||
}
|
||||
|
||||
/// `symbol.loadLibrary` params, then open the library in its panel.
|
||||
pub(crate) fn load_library(app: &mut VectorcraftApp, params: Value) -> Result<Value, String> {
|
||||
let r = app.run("symbol.loadLibrary", params)?;
|
||||
open_library(app, &json!({ "library": r["library"] }))
|
||||
}
|
||||
|
||||
/// Other Library…: load the symbols of the document at `path`, else of one picked in an open
|
||||
/// dialog.
|
||||
pub(crate) fn other_library(app: &mut VectorcraftApp, path: Option<String>) -> Result<Value, String> {
|
||||
match library_panel::pick_library_file(app, path, library_panel::library_pick_filters(SymbolLibraries::KIND))? {
|
||||
Some(path) => load_library(app, json!({ "path": path })),
|
||||
None => Ok(Value::Null),
|
||||
}
|
||||
}
|
||||
|
||||
/// The id prefix of the Window → Symbol Libraries → User Defined slots.
|
||||
pub(crate) const USER_SLOT: &str = "window.userSymbolLibrary";
|
||||
|
||||
/// The User Defined library slot `id` (`window.userSymbolLibrary3`) stands for.
|
||||
pub(crate) fn user_library(app: &VectorcraftApp, id: &str) -> Option<LibraryInfo> {
|
||||
library_panel::user_slot(id, USER_SLOT, symbollib::libraries(&app.session))
|
||||
}
|
||||
|
||||
/// Window → Symbol Libraries.
|
||||
pub(crate) fn window_menu() -> Vec<Item> {
|
||||
const SLOTS: [&str; 10] = [
|
||||
"window.userSymbolLibrary1",
|
||||
"window.userSymbolLibrary2",
|
||||
"window.userSymbolLibrary3",
|
||||
"window.userSymbolLibrary4",
|
||||
"window.userSymbolLibrary5",
|
||||
"window.userSymbolLibrary6",
|
||||
"window.userSymbolLibrary7",
|
||||
"window.userSymbolLibrary8",
|
||||
"window.userSymbolLibrary9",
|
||||
"window.userSymbolLibrary10",
|
||||
];
|
||||
let open = |b: &'static symbollib::BuiltinSymbolLibrary| Item::Cmd(b.name, SymbolLibraries::OPEN, json!({ "library": b.id }));
|
||||
let mut items: Vec<Item> = symbollib::BUILTIN.iter().map(open).collect();
|
||||
items.extend([
|
||||
Item::Sep,
|
||||
Item::Sub("User Defined", SLOTS.iter().map(|id| Item::Cmd("User Library", id, Value::Null)).collect()),
|
||||
Item::Sep,
|
||||
Item::Cmd("Other Library…", "window.symbolLibrary.other", Value::Null),
|
||||
Item::Cmd("Save Symbols…", "ui.saveSymbolLibrary", Value::Null),
|
||||
]);
|
||||
items
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
//! Headless frames of symbol libraries in library panels: clicking a symbol adds it to the
|
||||
//! document's Symbols, dragging one carries it to the canvas, the Window menu and the Symbols panel
|
||||
//! open libraries, Save Symbols writes User Defined libraries that reopen, and Other Library… turns
|
||||
//! down files it can't read.
|
||||
|
||||
use egui::{Event, Modifiers, PointerButton, Pos2, Rect, vec2};
|
||||
use serde_json::json;
|
||||
use vectorcraft_engine::Session;
|
||||
|
||||
use super::library_panel::{self, LibraryKind, LibraryPanel, last_open};
|
||||
use super::symbols::SymbolLibraries;
|
||||
use crate::VectorcraftApp;
|
||||
use crate::widgets::PanelDrag;
|
||||
|
||||
fn app() -> VectorcraftApp {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
|
||||
app
|
||||
}
|
||||
|
||||
fn context() -> egui::Context {
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
ctx
|
||||
}
|
||||
|
||||
/// One frame of `draw` with `events`; the texts it painted.
|
||||
fn frame(ctx: &egui::Context, events: Vec<Event>, time: f64, mut draw: impl FnMut(&mut egui::Ui)) -> Vec<String> {
|
||||
fn texts(s: &egui::Shape, out: &mut Vec<String>) {
|
||||
match s {
|
||||
egui::Shape::Text(t) => out.push(t.galley.text().to_string()),
|
||||
egui::Shape::Vec(v) => v.iter().for_each(|s| texts(s, out)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let screen_rect = Some(Rect::from_min_size(Pos2::ZERO, vec2(1200.0, 800.0)));
|
||||
let input = egui::RawInput { events, time: Some(time), screen_rect, ..Default::default() };
|
||||
let mut out = ctx.run_ui(input, &mut draw);
|
||||
out.textures_delta.clear();
|
||||
let mut v = vec![];
|
||||
out.shapes.iter().for_each(|c| texts(&c.shape, &mut v));
|
||||
v
|
||||
}
|
||||
|
||||
/// The centre of the open library panel's tile of symbol `name` (a new window takes a sizing
|
||||
/// frame first).
|
||||
fn tile(app: &mut VectorcraftApp, ctx: &egui::Context, name: &str, time: f64) -> Pos2 {
|
||||
for t in [time, time + 0.25] {
|
||||
frame(ctx, vec![], t, |ui| library_panel::show_window(app, ui.ctx()));
|
||||
}
|
||||
let id = library_panel::tile_id(&last_open(&app.ui).map(LibraryPanel::panel).unwrap_or_default(), name);
|
||||
ctx.read_response(id).unwrap_or_else(|| panic!("no tile for {name}")).rect.center()
|
||||
}
|
||||
|
||||
fn click(app: &mut VectorcraftApp, ctx: &egui::Context, name: &str, modifiers: Modifiers, time: f64) {
|
||||
let at = tile(app, ctx, name, time);
|
||||
let button = |pressed| Event::PointerButton { pos: at, button: PointerButton::Primary, pressed, modifiers };
|
||||
let events = vec![Event::ModifiersChanged(modifiers), Event::PointerMoved(at), button(true), button(false)];
|
||||
frame(ctx, events, time + 0.5, |ui| library_panel::show_window(app, ui.ctx()));
|
||||
}
|
||||
|
||||
fn undo_len(app: &VectorcraftApp) -> usize {
|
||||
app.session.doc().unwrap().history.undo.len()
|
||||
}
|
||||
|
||||
fn symbols(app: &VectorcraftApp) -> Vec<String> {
|
||||
app.session.doc().unwrap().doc.symbols.iter().map(|s| s.name.clone()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clicking_a_library_symbol_adds_it_to_the_documents_symbols_in_one_step() {
|
||||
let mut app = app();
|
||||
let ctx = context();
|
||||
let r = app.run("window.symbolLibrary", json!({"library": "Basic Shapes"})).unwrap();
|
||||
assert_eq!((r["open"].as_str(), r["count"].as_u64()), (Some("basic-shapes"), Some(9)));
|
||||
assert_eq!(last_open(&app.ui).map(|p| (p.kind.as_str(), p.id.as_str())), Some(("symbols", "basic-shapes")));
|
||||
let undo = undo_len(&app);
|
||||
click(&mut app, &ctx, "Star", Modifiers::NONE, 0.0);
|
||||
assert_eq!(symbols(&app), ["Star"]);
|
||||
assert_eq!(undo_len(&app), undo + 1, "one undo step");
|
||||
assert_eq!(app.run("symbol.list", json!({})).unwrap()["current"], "Star", "the Symbol Sprayer's symbol");
|
||||
// Clicking it again adds nothing.
|
||||
click(&mut app, &ctx, "Star", Modifiers::NONE, 2.0);
|
||||
assert_eq!((symbols(&app).len(), undo_len(&app)), (1, undo + 1));
|
||||
// Modifier clicks only select; Add to Symbols adds the selection.
|
||||
click(&mut app, &ctx, "Hexagon", Modifiers::COMMAND, 4.0);
|
||||
assert_eq!(symbols(&app), ["Star"]);
|
||||
SymbolLibraries::add(&mut app, "basic-shapes", vec!["Hexagon".into(), "Arrow".into()]);
|
||||
assert_eq!(symbols(&app), ["Star", "Hexagon", "Arrow"]);
|
||||
// Find filters by name; list rows give the natural size.
|
||||
let lib = SymbolLibraries::get(&app, "basic-shapes").unwrap().1;
|
||||
let rows = SymbolLibraries::rows(&lib, "arr");
|
||||
assert_eq!(rows.iter().map(|r| r.name).collect::<Vec<_>>(), ["Arrow"]);
|
||||
assert_eq!(SymbolLibraries::describe(rows[0].item.unwrap()), "48 × 32 pt");
|
||||
// Dragging a symbol out of the panel carries it to the canvas.
|
||||
let at = tile(&mut app, &ctx, "Burst", 6.0);
|
||||
let press = Event::PointerButton { pos: at, button: PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE };
|
||||
frame(&ctx, vec![Event::PointerMoved(at), press], 6.5, |ui| library_panel::show_window(&mut app, ui.ctx()));
|
||||
for (i, d) in [20.0, 60.0].into_iter().enumerate() {
|
||||
frame(&ctx, vec![Event::PointerMoved(at + vec2(d, d))], 6.6 + 0.1 * i as f64, |ui| library_panel::show_window(&mut app, ui.ctx()));
|
||||
}
|
||||
let carried = egui::DragAndDrop::payload::<PanelDrag>(&ctx);
|
||||
assert_eq!(carried.as_deref(), Some(&PanelDrag::LibrarySymbol { library: "basic-shapes".into(), name: "Burst".into() }));
|
||||
assert!(app.run("window.symbolLibrary", json!({"library": "nope"})).is_err());
|
||||
app.run("window.symbolLibrary", json!({"library": null})).unwrap();
|
||||
assert!(last_open(&app.ui).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_window_menu_and_the_symbols_panel_open_symbol_libraries() {
|
||||
let mut app = app();
|
||||
let entries = crate::menus::menu_entries(&app);
|
||||
let under = |e: &crate::menus::MenuEntry| e.path == ["Window", "Symbol Libraries"];
|
||||
let opened: Vec<_> =
|
||||
entries.iter().filter(|e| under(e) && e.command.as_deref() == Some("window.symbolLibrary")).map(|e| e.params["library"].clone()).collect();
|
||||
assert_eq!(opened, [json!("basic-shapes")]);
|
||||
let has = |cmd: &str| entries.iter().find(|e| under(e) && e.command.as_deref() == Some(cmd)).map(|e| e.enabled);
|
||||
assert_eq!(has("window.symbolLibrary.other"), Some(true));
|
||||
assert_eq!(has("ui.saveSymbolLibrary"), Some(false), "no symbols to save yet");
|
||||
assert!(!entries.iter().any(|e| e.path == ["Window", "Symbol Libraries", "User Defined"]), "empty slots are hidden");
|
||||
// The Symbols panel's library button and menu.
|
||||
let ctx = context();
|
||||
let texts = frame(&ctx, vec![], 0.0, |ui| {
|
||||
super::symbols::show(&mut app, ui);
|
||||
super::symbols::menu(&mut app, ui);
|
||||
});
|
||||
for t in ["Open Symbol Library", "Save Symbol Library…"] {
|
||||
assert!(texts.iter().any(|x| x.ends_with(t)), "{t}: {texts:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_symbols_writes_a_user_library_that_reopens_and_adds_to_another_document() {
|
||||
let dir = std::env::temp_dir().join(format!("vc-symbol-libraries-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let mut app = app();
|
||||
app.session.symbol_libraries.set_user_dir(Some(dir.to_string_lossy().to_string()));
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 30, "height": 20})).unwrap();
|
||||
app.run("symbol.new", json!({"name": "Brick"})).unwrap();
|
||||
app.run("shape.ellipse", json!({"x": 60, "y": 60, "width": 20, "height": 20})).unwrap();
|
||||
app.run("symbol.new", json!({"name": "Pebble"})).unwrap();
|
||||
app.run("ui.saveSymbolLibrary", json!({"names": ["Brick"]})).unwrap();
|
||||
let d = app.ui.dialog.as_mut().expect("Save Symbol Library opens");
|
||||
assert_eq!((d.kind.as_str(), d.bool("user")), (crate::dialogs::save_symbol_library::KIND, true));
|
||||
d.fields.insert("name".into(), json!("Masonry"));
|
||||
d.fields.insert("selectedOnly".into(), json!(true));
|
||||
let ctx = context();
|
||||
frame(&ctx, vec![], 0.0, |ui| crate::dialogs::show(&mut app, ui.ctx()));
|
||||
let texts = frame(&ctx, vec![], 0.5, |ui| crate::dialogs::show(&mut app, ui.ctx()));
|
||||
assert!(texts.iter().any(|t| t == "Selected Symbols Only (1)"), "{texts:?}");
|
||||
crate::dialogs::confirm(&mut app).unwrap();
|
||||
assert!(app.ui.dialog.is_none());
|
||||
let user: Vec<(String, String)> = crate::menus::menu_entries(&app)
|
||||
.into_iter()
|
||||
.filter(|e| e.path == ["Window", "Symbol Libraries", "User Defined"])
|
||||
.map(|e| (e.label, e.command.unwrap_or_default()))
|
||||
.collect();
|
||||
assert_eq!(user, [("Masonry".to_string(), "window.userSymbolLibrary1".to_string())]);
|
||||
// Reopened in a library panel, its symbol goes into another document.
|
||||
app.run("file.new", json!({"width": 100, "height": 100})).unwrap();
|
||||
app.run("window.userSymbolLibrary1", json!({})).unwrap();
|
||||
assert_eq!(last_open(&app.ui).map(|p| p.id.as_str()), Some("user/Masonry.vectorcraft"));
|
||||
let (name, lib) = SymbolLibraries::get(&app, "user/Masonry.vectorcraft").unwrap();
|
||||
assert_eq!((name.as_str(), lib.len()), ("Masonry", 1), "only the selected symbol");
|
||||
let undo = undo_len(&app);
|
||||
click(&mut app, &ctx, "Brick", Modifiers::NONE, 1.0);
|
||||
assert_eq!((symbols(&app), undo_len(&app)), (vec!["Brick".to_string()], undo + 1));
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn other_library_opens_a_documents_symbols_and_reports_unreadable_files() {
|
||||
let dir = std::env::temp_dir().join(format!("vc-symbol-other-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let mut app = app();
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 30, "height": 20})).unwrap();
|
||||
app.run("symbol.new", json!({"name": "Tile"})).unwrap();
|
||||
let doc = dir.join("Floor.vectorcraft");
|
||||
let b64 = app.run("document.serialize", json!({})).unwrap()["dataBase64"].as_str().unwrap().to_string();
|
||||
std::fs::write(&doc, vectorcraft_format::base64_decode(&b64).unwrap()).unwrap();
|
||||
app.run("file.new", json!({"width": 100, "height": 100})).unwrap();
|
||||
let r = app.run("window.symbolLibrary.other", json!({"path": doc.to_string_lossy()})).unwrap();
|
||||
assert_eq!((r["name"].as_str(), r["count"].as_u64()), (Some("Floor"), Some(1)));
|
||||
let open = last_open(&app.ui).cloned().unwrap();
|
||||
assert_eq!(open.kind, SymbolLibraries::KIND);
|
||||
let other = SymbolLibraries::list(&app).into_iter().find(|l| l.id == open.id).unwrap();
|
||||
assert_eq!(other.submenu, Some("Other Libraries"));
|
||||
// A file that isn't a document is an error, and opens no panel.
|
||||
let bad = dir.join("Broken.vectorcraft");
|
||||
std::fs::write(&bad, b"not a document").unwrap();
|
||||
app.run("window.symbolLibrary", json!({"library": null})).unwrap();
|
||||
assert!(app.run("window.symbolLibrary.other", json!({"path": bad.to_string_lossy()})).is_err());
|
||||
assert!(last_open(&app.ui).is_none());
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
@@ -292,15 +292,13 @@ fn effect_menu_keeps_glowing_edges_out_of_the_vector_stylize() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn library_submenus_are_disabled_placeholders() {
|
||||
fn brush_libraries_submenu_is_a_disabled_placeholder() {
|
||||
let app = app();
|
||||
let entries = menus::menu_entries(&app);
|
||||
for lib in ["Brush Libraries", "Symbol Libraries"] {
|
||||
let items: Vec<_> = entries.iter().filter(|e| e.path == ["Window", lib]).collect();
|
||||
let labels: Vec<&str> = items.iter().map(|e| e.label.as_str()).collect();
|
||||
assert_eq!(labels, ["Built-in Libraries", "User Defined", "Other Library…"], "{lib}");
|
||||
assert!(items.iter().all(|e| !e.enabled && e.command.is_none()), "{lib}");
|
||||
}
|
||||
let items: Vec<_> = entries.iter().filter(|e| e.path == ["Window", "Brush Libraries"]).collect();
|
||||
let labels: Vec<&str> = items.iter().map(|e| e.label.as_str()).collect();
|
||||
assert_eq!(labels, ["Built-in Libraries", "User Defined", "Other Library…"]);
|
||||
assert!(items.iter().all(|e| !e.enabled && e.command.is_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -2266,6 +2266,10 @@ pub enum PanelDrag {
|
||||
/// A Symbols panel symbol: the canvas places an instance of it centred where it is dropped
|
||||
/// (`symbol.place`).
|
||||
Symbol(String),
|
||||
/// A symbol of a symbol library panel (`name`: its name in `library`): the canvas adds it to the
|
||||
/// document's Symbols and places an instance where it is dropped (`symbol.addFromLibrary` with
|
||||
/// `place`).
|
||||
LibrarySymbol { library: String, name: String },
|
||||
/// A Brushes panel brush (`def`: its definition, for the chip at the pointer): the path it is
|
||||
/// dropped on takes it (`brush.apply`).
|
||||
Brush { name: String, def: serde_json::Value },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Control protocol
|
||||
|
||||
> **Last updated:** 2026-10-13 · **Change:** synthetic input budgets (#1709); bounded transport waits (#1726).
|
||||
> **Last updated:** 2026-10-23 · **Change:** symbol library panels (`window.symbolLibrary`, `window.symbolLibrary.other`, `ui.saveSymbolLibrary`); previously: synthetic input budgets (#1709); bounded transport waits (#1726).
|
||||
|
||||
`vectorcraft --control <port>` listens on `127.0.0.1:<port>` (loopback only). The port must be a number
|
||||
from 1 to 65535 (`--control=<port>` works too), given once; otherwise the app prints an error and exits
|
||||
@@ -274,6 +274,16 @@ Defined libraries are `window.userGraphicStyleLibrary1`…`10` in Window → Gra
|
||||
user library folder, `selectedOnly` with `names`); `ui.dialog.confirm` runs `graphicStyle.saveLibrary` (to a file it
|
||||
asks for a path and suggests `name` with `.vcstyles` as the file name; the web downloads the file under that name).
|
||||
|
||||
Symbol libraries open in the same panels: `window.symbolLibrary {library}` (`library_panels` kind `symbols`; `library:
|
||||
null` closes them). Clicking a symbol there runs `symbol.addFromLibrary {library, name}`, adding it to the document's
|
||||
Symbols in one undo step; Shift/Cmd-clicks select symbols for Add to Symbols, and a symbol dragged onto the canvas runs
|
||||
it with `place: true` and the drop point as `x`, `y`. `window.symbolLibrary.other {path?}` loads the symbols of any
|
||||
document VectorCraft opens (a saved symbol library is a `.vectorcraft` document) and opens them there. The User
|
||||
Defined libraries are `window.userSymbolLibrary1`…`10` in Window → Symbol Libraries. `ui.saveSymbolLibrary {names?}`
|
||||
(Save Symbols…, the Symbols panel's Save Symbol Library…) opens the `saveSymbolLibrary` dialog (fields `name`, `user`:
|
||||
save to the user library folder, `selectedOnly` with `names`); `ui.dialog.confirm` runs `symbol.saveLibrary` (to a
|
||||
file it asks for a path and suggests `name` with `.vectorcraft`).
|
||||
|
||||
Tile Edge Color: Object → Pattern → Tile Edge Color… (`ui.tileEdgeColor`) opens the `tileEdgeColor` dialog (field
|
||||
`color`: `#rrggbb` or a preset name such as "Light Blue"); `ui.dialog.confirm` sets the preference
|
||||
`patternTileEdgeColor` (`prefs.set`), the colour pattern editing mode draws the tile edge and the swatch bounds in.
|
||||
@@ -915,6 +925,7 @@ hidden tab (whose frames the browser pauses) answers when it is shown again.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-23 | minor | Documented the symbol library panel commands (`window.symbolLibrary`, `.other`, `ui.saveSymbolLibrary`, `window.userSymbolLibrary1`…`10`). |
|
||||
| 2026-10-13 | minor | Documented count, pending-event and per-frame request budgets (#1709). |
|
||||
| 2026-10-13 | minor | Documented transport deadlines and connection-slot recovery (#1726). |
|
||||
| 2026-10-18 | minor | Documented `window.vectorcraft`, the web build's control channel. |
|
||||
|
||||
+11
-4
File diff suppressed because one or more lines are too long
+26
-3
@@ -86,7 +86,7 @@ The two flags (PhotoCraft and the other Craft apps take the same ones, so one cl
|
||||
the suite) keep the agent to the folders you give it:
|
||||
|
||||
- Every file a command reads must lie inside a **read root**: `open_file`, `file.place`, relinking and
|
||||
updating links, the images an SVG links to, swatch library, graphic style library and colour-profile loads, plug-ins,
|
||||
updating links, the images an SVG links to, swatch library, graphic style library, symbol library and colour-profile loads, plug-ins,
|
||||
`file.newFromTemplate`, preset imports, shortcut sets (`shortcutSet.read`), the folders `text.findFontFiles` and `links.findFiles` search, the
|
||||
scripts `script.check` reads and the files they include.
|
||||
- Every file a command writes must lie inside a **write root**: `save_file`, `export`, the save and
|
||||
@@ -1750,10 +1750,33 @@ with); without `path` it returns `{data}`, and `user: true` saves into the user
|
||||
file, or another document's graphic styles, as a library to add from; a file in the user library folder, or a file
|
||||
with the same extension and bytes as one there, loads as that User Defined library.
|
||||
|
||||
## Symbol libraries
|
||||
|
||||
Symbol libraries are read-only sets of symbols: one generated in code (Basic Shapes), the `.vectorcraft` files in
|
||||
the user library folder of the desktop app (User Defined) and the symbols of any document loaded with
|
||||
`symbol.loadLibrary`. `symbol.libraries` lists them (`id`, `name`, `category`: `builtIn`, `user` or `loaded`, `count`)
|
||||
and `symbol.library {library}` returns one's symbols (`name`, `size`, `registration`, `exportType`; `library` is an
|
||||
id or a name). `symbol.addFromLibrary {library, name? | names?}` copies symbols into the document's Symbols as one
|
||||
undo step (no names: the whole library), with their Symbol Options and the resources they use: the symbols they nest,
|
||||
patterns, swatches (`swatchConflict` as for `edit.paste`), brushes, graphic styles and images. Symbols the document
|
||||
already has (same name and art) are reported under `existing`; a name another symbol has gets a number, and `names`
|
||||
gives each one's name in the document. The first one becomes the current symbol. `place: true` also places an
|
||||
instance of it with its registration point at `x`, `y` (default: the first artboard's centre) in the same step:
|
||||
what dragging a symbol out of the library panel onto the canvas does.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"symbol.addFromLibrary","params":{"library":"basic-shapes","name":"Star","place":true,"x":120,"y":80}}}
|
||||
```
|
||||
`symbol.saveLibrary {path?, names?, name?, user?}` writes the document's symbols as a symbol library: a `.vectorcraft`
|
||||
document holding only them and what they use; without `path` it returns `{dataBase64}`, and `user: true` saves into
|
||||
the user library folder (category `user`, User Defined). `symbol.loadLibrary {path? | data? | dataBase64?, name?}`
|
||||
loads the symbols of any document VectorCraft opens as a library to add from; a file it can't read is an error.
|
||||
|
||||
## Library panels
|
||||
|
||||
Each swatch or graphic style library opens in a read-only panel of its own (#2603), as in Illustrator, and
|
||||
several can be open at once. `window.swatchLibrary {library}` and `window.graphicStyleLibrary {library}`
|
||||
Each swatch, graphic style or symbol library opens in a read-only panel of its own (#2603), as in Illustrator, and
|
||||
several can be open at once. `window.swatchLibrary {library}`, `window.graphicStyleLibrary {library}` and
|
||||
`window.symbolLibrary {library}`
|
||||
(remote mode, `invoke_menu`) open one floating, or bring its panel forward when it is already open, and answer
|
||||
`{open, panel, name, count}`; `library: null` closes every panel of that kind. The panel id is
|
||||
`library:<kind>:<library id>` (`library:swatches:pastels`, `library:graphicStyles:hand-drawn`,
|
||||
|
||||
+4
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+4
-2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user