mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3976 from dotCooCoo/feat/find-by-bounds-and-select
Find Objects: document.find filters by bounds, size and anchor count and can select the matches
This commit is contained in:
@@ -269,11 +269,11 @@ fn candidates(s: &Session, f: impl Fn(&Node) -> bool) -> Result<Vec<NodeId>> {
|
||||
}
|
||||
|
||||
fn finish_same(s: &mut Session, cmd: &str, ids: Vec<NodeId>) -> Result<Value> {
|
||||
let n = ids.len();
|
||||
let from = s.doc()?.selection.objects.clone();
|
||||
s.select(|_, sel| sel.set(ids))?;
|
||||
s.doc_mut()?.last_selection_cmd = Some((cmd.to_string(), json!({}), from));
|
||||
Ok(json!({ "count": n }))
|
||||
let st = s.doc_mut()?;
|
||||
st.last_selection_cmd = Some((cmd.to_string(), json!({}), from));
|
||||
Ok(json!({ "count": st.selection.objects.len() }))
|
||||
}
|
||||
|
||||
fn same(s: &mut Session, cmd: &str, eq: fn(&Node, &Node) -> bool) -> Result<Value> {
|
||||
@@ -312,9 +312,9 @@ fn same_text(s: &mut Session, cmd: &str, eq: fn(&CharStyle, &CharStyle) -> bool)
|
||||
|
||||
fn by_kind(s: &mut Session, f: impl Fn(&Node) -> bool) -> Result<Value> {
|
||||
let ids = candidates(s, f)?;
|
||||
let n = ids.len();
|
||||
s.select(|_, sel| sel.set(ids))?;
|
||||
Ok(json!({ "count": n }))
|
||||
// The objects selected, after Lock Guides has left out guide paths.
|
||||
Ok(json!({ "count": s.doc()?.selection.objects.len() }))
|
||||
}
|
||||
|
||||
fn direction_handles(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
|
||||
@@ -27,7 +27,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
cmd!("document.activate", "Activate Document", [], None, "{index}", always, doc_activate),
|
||||
cmd!(query "document.inspect", "Inspect Document", [], None, "{depth?, childLimit?, ids?: [id…] (list just these nodes, of any level, in this order, under `nodes` in place of `layers`; an unknown id is an error; at most 10000), kind?: panel label such as Layer; Group; Path; Type or Image (exact, ignoring case; list every such node under `nodes`, each with `path`, its ancestor ids with the layer first, searching the subtrees of `ids` when given), limit?: at most this many entries of the list, offset?: entries skipped first (default 0; with `ids`, `kind`, `limit` or `offset` the reply adds `total`, the entries before paging)} → layer tree (each node: id, name, kind, visible, locked, bounds, opacity when below 1, blend when not Normal, fill, stroke and strokeWidth of objects and compound paths; a compound path's members have compoundMember: true instead of paint, which is the compound's), artboards, selection, history (a sliced tree reports childCount); without the scope options the reply is the whole layer tree", has_doc, doc_inspect),
|
||||
cmd!(query "document.node", "Inspect Object", [], None, "{id, summary?: compact summary, depth?: child levels in the summary (default all), childLimit?: children shown per node (default all; a level that shows fewer reports childCount)} → one object", has_doc, doc_node),
|
||||
cmd!(query "document.find", "Find Objects", [], None, "{name?: substring of the Layers panel name, kind?: panel label such as Group; Path; Type or Image (exact), text?: substring of type content, limit?: max matches (default 100, 0 counts only)} → {matches: [{id, name, kind, path}], total}", has_doc, doc_find),
|
||||
cmd!(query "document.find", "Find Objects", [], None, "{name?: substring of the Layers panel name, kind?: panel label such as Group; Path; Type or Image (exact), text?: substring of type content, within?: [x, y, width, height] (an object's geometric bounds inside this rectangle, edges included; document points as document.inspect's bounds; layers never match this or the size filters), intersects?: [x, y, width, height] (bounds touching or overlapping it), minWidth?, maxWidth?, minHeight?, maxHeight?: pt (the bounds' size), minThickness?, maxThickness?: pt (the smaller of the bounds' width and height), minArea?, maxArea?: pt² (the bounds' width × height), minAnchors?, maxAnchors?: anchor points of a path (a compound path's members together; other objects never match), select?: bool (also select the matches, leaving out hidden and locked ones, those inside another match, and a compound path's members unless the compound path is isolated; Select > Reselect repeats it), limit?: max matches listed (default 100, 0 counts only)} → {matches: [{id, name, kind, path}], total, selected (with select: the count selected)}; at least one filter, all of them matching", has_doc, doc_find),
|
||||
cmd!(query "document.json", "Document JSON", [], None, "{} → complete document model", has_doc, |s, _| Ok(serde_json::to_value(&*s.doc()?.doc).unwrap_or(Value::Null))),
|
||||
cmd!(
|
||||
"document.setUnits",
|
||||
@@ -243,19 +243,82 @@ fn opt_u64(p: &Value, cmd: &str, key: &str) -> Result<Option<u64>> {
|
||||
}
|
||||
|
||||
fn doc_find(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "document.find";
|
||||
// A filter of the wrong type is an error, not dropped: dropping it would widen the search.
|
||||
let needle = |key: &str| match p.get(key) {
|
||||
None | Some(Value::Null) => Ok(None),
|
||||
Some(Value::String(v)) => Ok(Some(v.to_lowercase()).filter(|v| !v.is_empty())),
|
||||
Some(_) => Err(bad("document.find", format!("`{key}` must be a string"))),
|
||||
Some(_) => Err(bad(C, format!("`{key}` must be a string"))),
|
||||
};
|
||||
let filter = inspect::FindFilter { name: needle("name")?, kind: needle("kind")?, text: needle("text")? };
|
||||
if filter.is_empty() {
|
||||
return Err(bad("document.find", "give at least one of `name`, `kind`, `text`"));
|
||||
let rect = |key: &str| match p.get(key) {
|
||||
None | Some(Value::Null) => Ok(None),
|
||||
Some(v) => match finite_numbers::<4>(v) {
|
||||
Some([x, y, w, h]) if w >= 0.0 && h >= 0.0 => Ok(Some(vectorcraft_geom::Rect::new(x, y, x + w, y + h))),
|
||||
_ => Err(bad(C, format!("`{key}` must be [x, y, width, height]: four finite numbers, width and height not negative"))),
|
||||
},
|
||||
};
|
||||
let bound = |key: &str| match p.get(key) {
|
||||
None | Some(Value::Null) => Ok(None),
|
||||
Some(v) => v.as_f64().filter(|n| n.is_finite() && *n >= 0.0).map(Some).ok_or_else(|| bad(C, format!("`{key}` must be a number not below 0"))),
|
||||
};
|
||||
let range = |name: &str| -> Result<inspect::FindRange> {
|
||||
let (min_key, max_key) = (format!("min{name}"), format!("max{name}"));
|
||||
let r = inspect::FindRange { min: bound(&min_key)?, max: bound(&max_key)? };
|
||||
if let (Some(min), Some(max)) = (r.min, r.max)
|
||||
&& min > max
|
||||
{
|
||||
return Err(bad(C, format!("`{min_key}` is greater than `{max_key}`")));
|
||||
}
|
||||
Ok(r)
|
||||
};
|
||||
let anchors = range("Anchors")?;
|
||||
if [anchors.min, anchors.max].iter().flatten().any(|n| n.fract() != 0.0) {
|
||||
return Err(bad(C, "`minAnchors` and `maxAnchors` must be whole numbers"));
|
||||
}
|
||||
let limit = opt_u64(p, "document.find", "limit")?.unwrap_or(100);
|
||||
let (matches, total) = inspect::find_nodes(&s.doc()?.doc, &filter, limit);
|
||||
Ok(json!({"matches": matches, "total": total}))
|
||||
let filter = inspect::FindFilter {
|
||||
name: needle("name")?,
|
||||
kind: needle("kind")?,
|
||||
text: needle("text")?,
|
||||
within: rect("within")?,
|
||||
intersects: rect("intersects")?,
|
||||
width: range("Width")?,
|
||||
height: range("Height")?,
|
||||
thickness: range("Thickness")?,
|
||||
area: range("Area")?,
|
||||
anchors,
|
||||
};
|
||||
if filter.is_empty() {
|
||||
return Err(bad(
|
||||
C,
|
||||
"give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`",
|
||||
));
|
||||
}
|
||||
let select = match p.get("select") {
|
||||
None | Some(Value::Null) => false,
|
||||
Some(v) => v.as_bool().ok_or_else(|| bad(C, "`select` must be true or false"))?,
|
||||
};
|
||||
let limit = opt_u64(p, C, "limit")?.unwrap_or(100);
|
||||
let (matches, ids) = inspect::find_nodes(&s.doc()?.doc, &filter, limit);
|
||||
let mut reply = json!({"matches": matches, "total": ids.len()});
|
||||
if select {
|
||||
reply["selected"] = select_found(s, p, &ids)?["count"].clone();
|
||||
s.journal_query();
|
||||
}
|
||||
Ok(reply)
|
||||
}
|
||||
|
||||
/// Select the objects among `ids` that Select All and the objects inside them take (none hidden or
|
||||
/// locked, nor inside a hidden or locked one), leaving out those inside another of them and the
|
||||
/// members of compound paths, unless a compound path is isolated. Select > Reselect repeats
|
||||
/// `document.find` with `p`.
|
||||
fn select_found(s: &mut Session, p: &Value, ids: &[NodeId]) -> Result<Value> {
|
||||
let st = s.doc()?;
|
||||
let compound = |n: &Node| matches!(n.kind, vectorcraft_doc::NodeKind::Compound { .. });
|
||||
let members = st.isolation.and_then(|i| st.doc.ancestry(i)).is_some_and(|a| a.iter().any(|i| st.doc.node(*i).is_some_and(compound)));
|
||||
let found: BTreeSet<NodeId> = ids.iter().copied().collect();
|
||||
super::select::select_where(s, "document.find", p, |d, n| {
|
||||
found.contains(&n.id) && (members || !d.parent_of(n.id).and_then(|p| d.node(p)).is_some_and(compound))
|
||||
})
|
||||
}
|
||||
|
||||
/// Document Setup's units (also `document.setup {units}`).
|
||||
|
||||
@@ -689,7 +689,7 @@ fn same(s: &mut Session, cmd: &str, eq: impl Fn(&Node, &Node) -> bool) -> Result
|
||||
|
||||
/// Select the objects [`walk_selectable`] visits that `f` accepts (not looking inside accepted
|
||||
/// ones); Select > Reselect repeats `cmd` with `p`.
|
||||
fn select_where(s: &mut Session, cmd: &str, p: &Value, f: impl Fn(&Document, &Node) -> bool) -> Result<Value> {
|
||||
pub(crate) fn select_where(s: &mut Session, cmd: &str, p: &Value, f: impl Fn(&Document, &Node) -> bool) -> Result<Value> {
|
||||
let st = s.doc()?;
|
||||
let mut ids = vec![];
|
||||
walk_selectable(&st.doc, st.isolation, |n| {
|
||||
@@ -701,8 +701,10 @@ fn select_where(s: &mut Session, cmd: &str, p: &Value, f: impl Fn(&Document, &No
|
||||
});
|
||||
let from = st.selection.objects.clone();
|
||||
s.select(|_, sel| sel.set(ids.iter().copied()))?;
|
||||
s.doc_mut()?.last_selection_cmd = Some((cmd.to_string(), p.clone(), from));
|
||||
Ok(json!({ "count": ids.len() }))
|
||||
let st = s.doc_mut()?;
|
||||
st.last_selection_cmd = Some((cmd.to_string(), p.clone(), from));
|
||||
// The objects selected, after Lock Guides has left out guide paths.
|
||||
Ok(json!({ "count": st.selection.objects.len() }))
|
||||
}
|
||||
|
||||
fn same_graphic_style(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
@@ -763,6 +765,7 @@ fn by_kind(s: &mut Session, f: fn(&Node) -> bool) -> Result<Value> {
|
||||
}
|
||||
true
|
||||
});
|
||||
s.select(|_, sel| sel.set(ids.iter().copied()))?;
|
||||
Ok(json!({ "count": ids.len() }))
|
||||
s.select(|_, sel| sel.set(ids))?;
|
||||
// The objects selected, after Lock Guides has left out guide paths.
|
||||
Ok(json!({ "count": s.doc()?.selection.objects.len() }))
|
||||
}
|
||||
|
||||
+102
-18
@@ -2,7 +2,8 @@
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::BlendMode;
|
||||
use vectorcraft_doc::{ArrowAlign, Document, LineCap, LineJoin, Node, NodeKind, StrokeAlign, StrokeLayer, SymbolBoxes, WidthProfile};
|
||||
use vectorcraft_doc::{ArrowAlign, Document, LineCap, LineJoin, Node, NodeId, NodeKind, StrokeAlign, StrokeLayer, SymbolBoxes, WidthProfile};
|
||||
use vectorcraft_geom::Rect;
|
||||
|
||||
use crate::Session;
|
||||
|
||||
@@ -298,20 +299,87 @@ fn document_base(s: &Session) -> Value {
|
||||
|
||||
/// What `document.find` matches: every given filter must hit (AND). All matching is
|
||||
/// case-insensitive; `name` and `text` are substrings, `kind` is the exact panel label
|
||||
/// (`Layer`, `Group`, `Path`, `Type`, `Image`, ...).
|
||||
/// (`Layer`, `Group`, `Path`, `Type`, `Image`, ...). The geometric filters read an object's
|
||||
/// geometric bounds as `document.inspect` reports them; layers and sublayers fail them, and so
|
||||
/// does a node without bounds (an empty group); `anchors` counts a path's anchor points, summed
|
||||
/// over a compound path's members, and a node that is neither fails it.
|
||||
#[derive(Default)]
|
||||
pub struct FindFilter {
|
||||
pub name: Option<String>,
|
||||
pub kind: Option<String>,
|
||||
pub text: Option<String>,
|
||||
/// The bounds lie inside this rectangle, edges included.
|
||||
pub within: Option<Rect>,
|
||||
/// The bounds touch or overlap this rectangle.
|
||||
pub intersects: Option<Rect>,
|
||||
/// The bounds' width.
|
||||
pub width: FindRange,
|
||||
/// The bounds' height.
|
||||
pub height: FindRange,
|
||||
/// The smaller of the bounds' width and height.
|
||||
pub thickness: FindRange,
|
||||
/// The bounds' width times their height.
|
||||
pub area: FindRange,
|
||||
/// The anchor points of a path, or of a compound path's members together.
|
||||
pub anchors: FindRange,
|
||||
}
|
||||
|
||||
/// Inclusive limits on one measure of a [`FindFilter`]; neither given matches everything.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct FindRange {
|
||||
pub min: Option<f64>,
|
||||
pub max: Option<f64>,
|
||||
}
|
||||
|
||||
impl FindRange {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.min.is_none() && self.max.is_none()
|
||||
}
|
||||
|
||||
fn hits(&self, v: f64) -> bool {
|
||||
self.min.is_none_or(|m| v >= m) && self.max.is_none_or(|m| v <= m)
|
||||
}
|
||||
}
|
||||
|
||||
impl FindFilter {
|
||||
/// True when no effective filter was given (empty strings count as absent).
|
||||
pub fn is_empty(&self) -> bool {
|
||||
[self.name.as_ref(), self.kind.as_ref(), self.text.as_ref()].iter().all(|f| f.is_none())
|
||||
&& self.within.is_none()
|
||||
&& self.intersects.is_none()
|
||||
&& self.ranges().iter().all(|r| r.is_empty())
|
||||
&& self.anchors.is_empty()
|
||||
}
|
||||
|
||||
fn hits(&self, n: &Node) -> bool {
|
||||
/// The limits read from the bounds.
|
||||
fn ranges(&self) -> [FindRange; 4] {
|
||||
[self.width, self.height, self.thickness, self.area]
|
||||
}
|
||||
|
||||
fn hits(&self, n: &Node, symbols: &SymbolBoxes) -> bool {
|
||||
if self.within.is_some() || self.intersects.is_some() || self.ranges().iter().any(|r| !r.is_empty()) {
|
||||
if matches!(n.kind, NodeKind::Layer { .. }) {
|
||||
return false;
|
||||
}
|
||||
let Some(b) = n.geometric_bounds_with(symbols) else { return false };
|
||||
if self.within.is_some_and(|r| b.x0 < r.x0 || b.y0 < r.y0 || b.x1 > r.x1 || b.y1 > r.y1) {
|
||||
return false;
|
||||
}
|
||||
if self.intersects.is_some_and(|r| b.x0 > r.x1 || b.x1 < r.x0 || b.y0 > r.y1 || b.y1 < r.y0) {
|
||||
return false;
|
||||
}
|
||||
let (w, h) = (b.width(), b.height());
|
||||
if !(self.width.hits(w) && self.height.hits(h) && self.thickness.hits(w.min(h)) && self.area.hits(w * h)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if !self.anchors.is_empty() && !anchor_count(n).is_some_and(|c| self.anchors.hits(c as f64)) {
|
||||
return false;
|
||||
}
|
||||
self.hits_text(n)
|
||||
}
|
||||
|
||||
fn hits_text(&self, n: &Node) -> bool {
|
||||
if let Some(needle) = &self.name
|
||||
&& !n.display_name().to_lowercase().contains(needle)
|
||||
{
|
||||
@@ -332,31 +400,47 @@ impl FindFilter {
|
||||
}
|
||||
}
|
||||
|
||||
/// The anchor points of a path, or of a compound path's members together; `None` for any other
|
||||
/// node.
|
||||
fn anchor_count(n: &Node) -> Option<usize> {
|
||||
match &n.kind {
|
||||
NodeKind::Path { path, .. } => Some(path.anchor_count()),
|
||||
NodeKind::Compound { children, .. } => Some(children.iter().filter_map(|c| anchor_count(c)).sum()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Search the whole layer tree, top of the stack first like the Layers panel.
|
||||
/// Returns at most `limit` hits as `{id, name, kind, path}` (`path` is the ancestor
|
||||
/// chain, layer first) plus the total hit count, so a capped reply stays explicit.
|
||||
pub fn find_nodes(doc: &Document, filter: &FindFilter, limit: u64) -> (Vec<Value>, u64) {
|
||||
/// chain, layer first) plus the ids of every hit, so a capped reply stays explicit.
|
||||
pub fn find_nodes(doc: &Document, filter: &FindFilter, limit: u64) -> (Vec<Value>, Vec<NodeId>) {
|
||||
use std::sync::Arc;
|
||||
let mut out = Vec::new();
|
||||
let mut total = 0u64;
|
||||
let mut ancestors: Vec<u64> = Vec::new();
|
||||
fn walk(nodes: &[Arc<Node>], ancestors: &mut Vec<u64>, filter: &FindFilter, limit: u64, out: &mut Vec<Value>, total: &mut u64) {
|
||||
struct Walk<'a> {
|
||||
filter: &'a FindFilter,
|
||||
symbols: SymbolBoxes<'a>,
|
||||
limit: u64,
|
||||
ancestors: Vec<u64>,
|
||||
out: Vec<Value>,
|
||||
ids: Vec<NodeId>,
|
||||
}
|
||||
fn walk(nodes: &[Arc<Node>], w: &mut Walk) {
|
||||
for n in nodes.iter().rev() {
|
||||
if filter.hits(n) {
|
||||
*total += 1;
|
||||
if (out.len() as u64) < limit {
|
||||
out.push(json!({"id": n.id.0, "name": n.display_name(), "kind": n.kind_label(), "path": ancestors}));
|
||||
if w.filter.hits(n, &w.symbols) {
|
||||
w.ids.push(n.id);
|
||||
if (w.out.len() as u64) < w.limit {
|
||||
w.out.push(json!({"id": n.id.0, "name": n.display_name(), "kind": n.kind_label(), "path": w.ancestors}));
|
||||
}
|
||||
}
|
||||
if let Some(ch) = n.children() {
|
||||
ancestors.push(n.id.0);
|
||||
walk(ch, ancestors, filter, limit, out, total);
|
||||
ancestors.pop();
|
||||
w.ancestors.push(n.id.0);
|
||||
walk(ch, w);
|
||||
w.ancestors.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(&doc.layers, &mut ancestors, filter, limit, &mut out, &mut total);
|
||||
(out, total)
|
||||
let mut w = Walk { filter, symbols: doc.symbol_boxes(), limit, ancestors: Vec::new(), out: Vec::new(), ids: Vec::new() };
|
||||
walk(&doc.layers, &mut w);
|
||||
(w.out, w.ids)
|
||||
}
|
||||
|
||||
/// Cap names as `stroke.set` takes them.
|
||||
|
||||
@@ -1415,6 +1415,9 @@ pub struct Session {
|
||||
/// The depth of the command whose values [`Session::note_journal`] keeps: 1 (the top-level
|
||||
/// command), or a step's while a batch runs it ([`Session::execute_step`]).
|
||||
note_depth: u32,
|
||||
/// The running top-level query command changed the selection and is journaled like any other
|
||||
/// command ([`Session::journal_query`]).
|
||||
journal_query: bool,
|
||||
/// While `command.batch` runs: the documents its steps closed or replaced (Revert), which an
|
||||
/// error brings back; `None` otherwise.
|
||||
pub(crate) batch_stash: Option<Vec<DocState>>,
|
||||
@@ -1546,6 +1549,7 @@ impl Session {
|
||||
ui_language: None,
|
||||
journal_note: Default::default(),
|
||||
note_depth: 1,
|
||||
journal_query: false,
|
||||
batch_stash: None,
|
||||
place_hand_off: None,
|
||||
queue_hand_off: None,
|
||||
@@ -1762,6 +1766,7 @@ impl Session {
|
||||
if self.depth == 0 {
|
||||
self.journal_note.clear();
|
||||
self.note_depth = 1;
|
||||
self.journal_query = false;
|
||||
self.batch_stash = None;
|
||||
}
|
||||
// A selection-only command given `ids` selects them first, in the same undo step (#2130);
|
||||
@@ -1792,7 +1797,8 @@ impl Session {
|
||||
if self.depth == 0 {
|
||||
self.inherit_new_art();
|
||||
}
|
||||
if spec.journal && self.depth == 0 && self.active().is_none_or(|d| d.interaction.is_none()) {
|
||||
let journaled = spec.journal || (self.depth == 0 && std::mem::take(&mut self.journal_query));
|
||||
if journaled && self.depth == 0 && self.active().is_none_or(|d| d.interaction.is_none()) {
|
||||
let p = self.noted(params);
|
||||
self.journal.push((id.to_string(), p));
|
||||
}
|
||||
@@ -1818,6 +1824,14 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
/// Journal the running query command when it is the top-level command: it changed the
|
||||
/// selection (`document.find {select: true}`), so an action recorded around it repeats that.
|
||||
pub(crate) fn journal_query(&mut self) {
|
||||
if self.depth == 1 {
|
||||
self.journal_query = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Run `id` as a step of the running command, which journals its steps (`command.batch`):
|
||||
/// → the step's result and its params with what it noted ([`Session::note_journal`]), for the
|
||||
/// step in the running command's journal entry.
|
||||
|
||||
@@ -2616,6 +2616,156 @@ fn document_find_searches_names_kinds_and_text() {
|
||||
assert_eq!(s.execute("document.find", &json!({"kind": "nope"})).unwrap()["total"], 0);
|
||||
}
|
||||
|
||||
/// `document.find` filters by geometric bounds (inside or touching a rectangle, width, height,
|
||||
/// thickness and area) and by anchor count, and `select: true` selects the matches that can be
|
||||
/// selected.
|
||||
#[test]
|
||||
fn document_find_filters_by_geometry_and_selects() {
|
||||
let mut s = session();
|
||||
let big = rect(&mut s, 0.0, 0.0, 100.0, 100.0).0;
|
||||
let sliver = rect(&mut s, 200.0, 0.0, 95.0, 0.9).0;
|
||||
let star = s.execute("shape.star", &json!({"cx": 400, "cy": 50, "radius1": 40, "radius2": 20, "points": 5})).unwrap()["id"].as_u64().unwrap();
|
||||
let left = rect(&mut s, 600.0, 0.0, 10.0, 10.0).0;
|
||||
let right = rect(&mut s, 620.0, 0.0, 10.0, 10.0).0;
|
||||
let compound = s.execute("object.compoundPath.make", &json!({"ids": [left, right]})).unwrap()["id"].as_u64().unwrap();
|
||||
let hidden = rect(&mut s, 0.0, 300.0, 5.0, 5.0).0;
|
||||
s.execute("object.hide", &json!({"ids": [hidden]})).unwrap();
|
||||
let locked = rect(&mut s, 20.0, 300.0, 5.0, 5.0).0;
|
||||
s.execute("object.lock", &json!({"ids": [locked]})).unwrap();
|
||||
let dot = rect(&mut s, 40.0, 300.0, 5.0, 5.0).0;
|
||||
let found = |s: &mut Session, p: Value| {
|
||||
let v = s.execute("document.find", &p).unwrap();
|
||||
let mut ids: Vec<u64> = v["matches"].as_array().unwrap().iter().map(|m| m["id"].as_u64().unwrap()).collect();
|
||||
ids.sort_unstable();
|
||||
assert_eq!(v["total"], ids.len(), "{p}");
|
||||
ids
|
||||
};
|
||||
let sorted = |mut v: Vec<u64>| {
|
||||
v.sort_unstable();
|
||||
v
|
||||
};
|
||||
|
||||
// Edges count as inside; a rectangle touching the bounds intersects them.
|
||||
assert_eq!(found(&mut s, json!({"within": [0, 0, 100, 100]})), [big]);
|
||||
assert_eq!(found(&mut s, json!({"within": [0, 0, 99, 100]})), Vec::<u64>::new());
|
||||
assert_eq!(found(&mut s, json!({"intersects": [100, 0, 100, 0.5], "kind": "rectangle"})), sorted(vec![big, sliver]));
|
||||
// Size: a thin sliver of either orientation, and the bounds' area.
|
||||
assert_eq!(found(&mut s, json!({"maxThickness": 1})), [sliver]);
|
||||
assert_eq!(found(&mut s, json!({"maxHeight": 1})), [sliver]);
|
||||
assert_eq!(found(&mut s, json!({"minWidth": 90, "maxWidth": 96})), [sliver]);
|
||||
assert_eq!(found(&mut s, json!({"minArea": 9000, "maxArea": 10000})), [big]);
|
||||
assert_eq!(found(&mut s, json!({"maxArea": 30})), sorted(vec![hidden, locked, dot]));
|
||||
// Anchors: a compound path counts its members' together; the layer never matches.
|
||||
assert_eq!(found(&mut s, json!({"minAnchors": 10, "maxAnchors": 10})), [star]);
|
||||
assert_eq!(found(&mut s, json!({"minAnchors": 8, "maxAnchors": 8})), [compound]);
|
||||
let four = sorted(vec![big, sliver, left, right, hidden, locked, dot]);
|
||||
assert_eq!(found(&mut s, json!({"maxAnchors": 4})), four);
|
||||
|
||||
// A find that only reads is not journaled; one that selects is, so an action replays it.
|
||||
let journaled = s.journal.len();
|
||||
s.execute("document.find", &json!({"maxAnchors": 4})).unwrap();
|
||||
assert_eq!(s.journal.len(), journaled);
|
||||
// select: every match except hidden, locked and compound members; the reply counts them.
|
||||
let v = s.execute("document.find", &json!({"maxAnchors": 4, "select": true, "limit": 0})).unwrap();
|
||||
assert_eq!(s.journal_for_action(journaled), [("document.find".to_string(), json!({"maxAnchors": 4, "select": true, "limit": 0}))]);
|
||||
assert_eq!((v["total"].clone(), v["selected"].clone()), (json!(7), json!(3)));
|
||||
let selection = |s: &Session| sorted(s.doc().unwrap().selection.objects.iter().map(|i| i.0).collect());
|
||||
assert_eq!(selection(&s), sorted(vec![big, sliver, dot]));
|
||||
// Without select the selection stays, and the reply has no `selected`.
|
||||
let v = s.execute("document.find", &json!({"maxThickness": 1})).unwrap();
|
||||
assert!(v.get("selected").is_none(), "{v}");
|
||||
assert_eq!(selection(&s), sorted(vec![big, sliver, dot]));
|
||||
// Select > Reselect repeats the find.
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
s.execute("select.reselect", &json!({})).unwrap();
|
||||
assert_eq!(selection(&s), sorted(vec![big, sliver, dot]));
|
||||
// A compound path matched selects as itself.
|
||||
s.execute("document.find", &json!({"minAnchors": 8, "maxAnchors": 8, "select": true})).unwrap();
|
||||
assert_eq!(selection(&s), [compound]);
|
||||
// Inside an isolated compound path its members are what selects.
|
||||
s.execute("object.isolate", &json!({"id": compound})).unwrap();
|
||||
let v = s.execute("document.find", &json!({"maxAnchors": 4, "select": true})).unwrap();
|
||||
assert_eq!(v["selected"], 2);
|
||||
assert_eq!(selection(&s), sorted(vec![left, right]));
|
||||
|
||||
for bad in [
|
||||
json!({"within": [0, 0, -1, 5]}),
|
||||
json!({"within": [0, 0, 1]}),
|
||||
json!({"intersects": "everywhere"}),
|
||||
json!({"minArea": -1}),
|
||||
json!({"maxWidth": "5 pt"}),
|
||||
json!({"minWidth": 5, "maxWidth": 1}),
|
||||
json!({"minAnchors": 1.5}),
|
||||
json!({"maxThickness": 1, "select": "yes"}),
|
||||
json!({"select": true}),
|
||||
] {
|
||||
assert!(s.execute("document.find", &bad).is_err(), "{bad}");
|
||||
}
|
||||
}
|
||||
|
||||
/// `document.find {select: true}` counts the objects it selected: a guide path that Lock Guides
|
||||
/// leaves out of the selection is a match, not a selected object.
|
||||
#[test]
|
||||
fn document_find_counts_the_objects_it_selected() {
|
||||
let mut s = session();
|
||||
let guide = rect(&mut s, 0.0, 0.0, 5.0, 5.0);
|
||||
s.execute("select.set", &json!({"ids": [guide.0]})).unwrap();
|
||||
s.execute("view.guides.make", &json!({})).unwrap();
|
||||
rect(&mut s, 20.0, 0.0, 5.0, 5.0);
|
||||
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
|
||||
let v = s.execute("document.find", &json!({"maxArea": 30, "select": true})).unwrap();
|
||||
assert_eq!((v["total"].clone(), v["selected"].clone()), (json!(2), json!(1)));
|
||||
assert_eq!(s.doc().unwrap().selection.objects.len(), 1);
|
||||
}
|
||||
|
||||
/// Select > Object reports the number of objects it selected: a guide path that Lock Guides
|
||||
/// leaves out is not counted.
|
||||
#[test]
|
||||
fn select_object_counts_the_objects_it_selected() {
|
||||
let mut s = session();
|
||||
let line = |s: &mut Session, x: f64| {
|
||||
let id = s.execute("path.create", &json!({"anchors": [{"x": x, "y": 0}, {"x": x + 10.0, "y": 10}]})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("brush.apply", &json!({"name": "Charcoal", "ids": [id]})).unwrap();
|
||||
id
|
||||
};
|
||||
let guide = line(&mut s, 0.0);
|
||||
s.execute("select.set", &json!({"ids": [guide]})).unwrap();
|
||||
s.execute("view.guides.make", &json!({})).unwrap();
|
||||
line(&mut s, 20.0);
|
||||
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
|
||||
for cmd in ["select.object.openPaths", "select.object.brushStrokes"] {
|
||||
let v = s.execute(cmd, &json!({})).unwrap();
|
||||
assert_eq!((v["count"].clone(), s.doc().unwrap().selection.objects.len()), (json!(1), 1), "{cmd}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The geometric filters of `document.find` match objects only: a layer or sublayer whose bounds
|
||||
/// fit is not a match, so `total` counts what `select: true` can select. The text filters still
|
||||
/// find layers.
|
||||
#[test]
|
||||
fn document_find_geometric_filters_leave_out_layers() {
|
||||
let mut s = session();
|
||||
let a = rect(&mut s, 0.0, 0.0, 5.0, 5.0).0;
|
||||
let sub = s.execute("layer.newSublayer", &json!({})).unwrap()["id"].as_u64().unwrap();
|
||||
let b = rect(&mut s, 10.0, 0.0, 5.0, 5.0).0;
|
||||
assert_eq!(s.doc().unwrap().doc.parent_of(NodeId(b)), Some(NodeId(sub)));
|
||||
let found = |s: &mut Session, p: Value| {
|
||||
let v = s.execute("document.find", &p).unwrap();
|
||||
let mut ids: Vec<u64> = v["matches"].as_array().unwrap().iter().map(|m| m["id"].as_u64().unwrap()).collect();
|
||||
ids.sort_unstable();
|
||||
assert_eq!(v["total"], ids.len(), "{p}");
|
||||
ids
|
||||
};
|
||||
assert_eq!(found(&mut s, json!({"within": [0, 0, 15, 5]})), [a, b]);
|
||||
assert_eq!(found(&mut s, json!({"intersects": [0, 0, 1, 1]})), [a]);
|
||||
assert_eq!(found(&mut s, json!({"maxArea": 30})), [a, b]);
|
||||
assert_eq!(found(&mut s, json!({"minWidth": 15})), Vec::<u64>::new());
|
||||
assert_eq!(found(&mut s, json!({"kind": "layer", "within": [0, 0, 15, 5]})), Vec::<u64>::new());
|
||||
assert_eq!(found(&mut s, json!({"kind": "layer"})).len(), 2);
|
||||
let v = s.execute("document.find", &json!({"within": [0, 0, 15, 5], "select": true})).unwrap();
|
||||
assert_eq!((v["total"].clone(), v["selected"].clone()), (json!(2), json!(2)));
|
||||
}
|
||||
|
||||
/// Type reports the paint its characters show, and its own object-level paint apart from it.
|
||||
#[test]
|
||||
fn inspect_reports_the_paint_of_types_characters() {
|
||||
|
||||
@@ -4204,6 +4204,12 @@ imageTrace Outline Obrys
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` musí být mezi {min} a {max} (zadáno {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` musí být jedno z {_1}
|
||||
@msg `{key}` must be true or false `{key}` musí být true nebo false
|
||||
@msg `select` must be true or false `select` musí být true nebo false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` a `maxAnchors` musí být celá čísla
|
||||
@msg `{key}` must be a number not below 0 `{key}` musí být číslo nejméně 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` musí být [x, y, width, height]: čtyři konečná čísla, šířka a výška nesmí být záporné
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` je větší než `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` zadejte alespoň jeden z parametrů `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` musí být grayscale, rgb, hsb, cmyk nebo websafe
|
||||
@msg `{k}` must be [x, y] `{k}` musí být [x, y]
|
||||
@msg `{name}` has no options `{name}` nemá žádné možnosti
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3825,6 +3825,12 @@ theme Appearance Erscheinungsbild
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` muss zwischen {min} und {max} liegen (erhalten: {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` muss einer der folgenden Werte sein: {_1}
|
||||
@msg `{key}` must be true or false `{key}` muss true oder false sein
|
||||
@msg `select` must be true or false `select` muss true oder false sein
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` und `maxAnchors` müssen ganze Zahlen sein
|
||||
@msg `{key}` must be a number not below 0 `{key}` muss eine Zahl nicht kleiner als 0 sein
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` muss [x, y, width, height] sein: vier endliche Zahlen, Breite und Höhe nicht negativ
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` ist größer als `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` geben Sie mindestens einen der Parameter `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` an
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` muss grayscale, rgb, hsb, cmyk oder websafe sein
|
||||
@msg `{k}` must be [x, y] `{k}` muss [x, y] sein
|
||||
@msg `{name}` has no options `{name}` hat keine Optionen
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2167,6 +2167,12 @@ axis Both Και τα δύο
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) Το `{key}` πρέπει να είναι μεταξύ {min} και {max} (δόθηκε {x})
|
||||
@msg `{key}` must be one of {_1} Το `{key}` πρέπει να είναι ένα από τα {_1}
|
||||
@msg `{key}` must be true or false Το `{key}` πρέπει να είναι true ή false
|
||||
@msg `select` must be true or false Το `select` πρέπει να είναι true ή false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers Τα `minAnchors` και `maxAnchors` πρέπει να είναι ακέραιοι αριθμοί
|
||||
@msg `{key}` must be a number not below 0 Το `{key}` πρέπει να είναι αριθμός όχι μικρότερος από 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative Το `{key}` πρέπει να είναι [x, y, width, height]: τέσσερις πεπερασμένοι αριθμοί, με πλάτος και ύψος όχι αρνητικά
|
||||
@msg `{min_key}` is greater than `{max_key}` Το `{min_key}` είναι μεγαλύτερο από το `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` δώστε τουλάχιστον ένα από τα `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `{k}` must be [x, y] Το `{k}` πρέπει να είναι [x, y]
|
||||
@msg `{name}` has no options Το `{name}` δεν έχει επιλογές
|
||||
@msg `{name}` is a built-in workspace; choose another name Το `{name}` είναι ενσωματωμένος χώρος εργασίας· επιλέξτε άλλο όνομα
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2066 and column 19.
|
@@ -3901,6 +3901,12 @@ axis Both Ambos
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` debe estar entre {min} y {max} (se recibió {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` debe ser uno de estos: {_1}
|
||||
@msg `{key}` must be true or false `{key}` debe ser true o false
|
||||
@msg `select` must be true or false `select` debe ser true o false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` y `maxAnchors` deben ser números enteros
|
||||
@msg `{key}` must be a number not below 0 `{key}` debe ser un número no inferior a 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` debe ser [x, y, width, height]: cuatro números finitos, con anchura y altura no negativas
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` es mayor que `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` indica al menos uno de `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` debe ser grayscale, rgb, hsb, cmyk o websafe
|
||||
@msg `{k}` must be [x, y] `{k}` debe ser [x, y]
|
||||
@msg `{name}` has no options `{name}` no tiene opciones
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4122,6 +4122,12 @@ imageTrace Outline Ääriviiva
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` on oltava väliltä {min}–{max} (saatiin {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` on oltava jokin seuraavista: {_1}
|
||||
@msg `{key}` must be true or false `{key}` on oltava true tai false
|
||||
@msg `select` must be true or false `select` on oltava true tai false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` ja `maxAnchors` on oltava kokonaislukuja
|
||||
@msg `{key}` must be a number not below 0 `{key}` on oltava luku, joka on vähintään 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` on oltava [x, y, width, height]: neljä äärellistä lukua, joista leveys ja korkeus eivät ole negatiivisia
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` on suurempi kuin `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` anna vähintään yksi parametreista `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `{k}` must be [x, y] `{k}` on oltava [x, y]
|
||||
@msg `{name}` has no options `{name}`: ei asetuksia
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` on sisäänrakennettu työtila; valitse toinen nimi
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3898,6 +3898,12 @@ axis Both Les deux
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` doit être compris entre {min} et {max} (reçu : {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` doit valoir l’une de ces valeurs : {_1}
|
||||
@msg `{key}` must be true or false `{key}` doit valoir true ou false
|
||||
@msg `select` must be true or false `select` doit valoir true ou false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` et `maxAnchors` doivent être des nombres entiers
|
||||
@msg `{key}` must be a number not below 0 `{key}` doit être un nombre supérieur ou égal à 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` doit être [x, y, width, height] : quatre nombres finis, largeur et hauteur non négatives
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` est supérieur à `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` indiquez au moins l’un des paramètres `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` doit valoir grayscale, rgb, hsb, cmyk ou websafe
|
||||
@msg `{k}` must be [x, y] `{k}` doit être [x, y]
|
||||
@msg `{name}` has no options `{name}` n’a pas d’options
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4434,6 +4434,12 @@ imageTrace Outline Körvonal
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}`: {min} és {max} közötti érték kell (kapott érték: {x})
|
||||
@msg `{key}` must be one of {_1} `{key}`: ezek egyike kell: {_1}
|
||||
@msg `{key}` must be true or false `{key}`: true vagy false kell
|
||||
@msg `select` must be true or false `select`: true vagy false kell
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` és `maxAnchors`: egész szám kell
|
||||
@msg `{key}` must be a number not below 0 `{key}`: legalább 0 értékű szám kell
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}`: [x, y, width, height] kell, négy véges szám, a szélesség és a magasság nem negatív
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` nagyobb, mint `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` adj meg legalább egyet ezek közül: `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode`: grayscale, rgb, hsb, cmyk vagy websafe kell
|
||||
@msg `{k}` must be [x, y] `{k}`: [x, y] kell
|
||||
@msg `{name}` has no options ennek nincsenek beállításai: `{name}`
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3941,6 +3941,12 @@ axis Both Entrambi
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` deve essere compreso tra {min} e {max} (ricevuto {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` deve essere uno dei seguenti: {_1}
|
||||
@msg `{key}` must be true or false `{key}` deve essere true o false
|
||||
@msg `select` must be true or false `select` deve essere true o false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` e `maxAnchors` devono essere numeri interi
|
||||
@msg `{key}` must be a number not below 0 `{key}` deve essere un numero non inferiore a 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` deve essere [x, y, width, height]: quattro numeri finiti, con larghezza e altezza non negative
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` è maggiore di `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` indica almeno uno tra `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` deve essere grayscale, rgb, hsb, cmyk o websafe
|
||||
@msg `{k}` must be [x, y] `{k}` deve essere [x, y]
|
||||
@msg `{name}` has no options `{name}` non ha opzioni
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4437,6 +4437,12 @@ swatch Bright Violet ビビッドバイオレット
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` には、メニュー項目がダイアログを開くコマンドを指定してください (ui.menuDialog を参照)
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` には grayscale、rgb、hsb、cmyk、websafe のいずれかを指定してください
|
||||
@msg `{key}` must be true or false `{key}` には true または false を指定してください
|
||||
@msg `select` must be true or false `select` には true または false を指定してください
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` と `maxAnchors` は整数にしてください
|
||||
@msg `{key}` must be a number not below 0 `{key}` には 0 以上の数値を指定してください
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` は [x, y, width, height] の形式で指定してください: 有限の数値 4 つで、幅と高さは負の値にできません
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` が `{max_key}` より大きくなっています
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` 次のうち少なくとも 1 つを指定してください: `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg brightness must be dark|mediumDark|mediumLight|light brightness には dark|mediumDark|mediumLight|light のいずれかを指定してください
|
||||
@msg index must be a number or first, previous, next or last index には数値、または first、previous、next、last のいずれかを指定してください
|
||||
@msg index must be a number or first, previous, next or last, not `{other}` index には数値、または first、previous、next、last のいずれかを指定してください (`{other}` は指定できません)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3695,6 +3695,12 @@ font-technology Variable ცვლადი
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` უნდა იყოს {min}-სა და {max}-ს შორის (მიღებულია {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` უნდა იყოს ერთ-ერთი: {_1}
|
||||
@msg `{key}` must be true or false `{key}` უნდა იყოს true ან false
|
||||
@msg `select` must be true or false `select` უნდა იყოს true ან false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` და `maxAnchors` უნდა იყოს მთელი რიცხვები
|
||||
@msg `{key}` must be a number not below 0 `{key}` უნდა იყოს რიცხვი, არანაკლებ 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` უნდა იყოს [x, y, width, height]: ოთხი სასრული რიცხვი, სიგანე და სიმაღლე არ უნდა იყოს უარყოფითი
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` მეტია, ვიდრე `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` მიუთითეთ ერთი მაინც: `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `{k}` must be [x, y] `{k}` უნდა იყოს [x, y]
|
||||
@msg `{name}` has no options `{name}`-ს პარამეტრები არ აქვს
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` ჩაშენებული სამუშაო სივრცეა; აირჩიეთ სხვა სახელი
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4369,6 +4369,12 @@ theme Appearance 외관
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command`는 메뉴 항목이 대화상자를 여는 명령이어야 합니다(ui.menuDialog 참조)
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode`은(는) grayscale, rgb, hsb, cmyk, websafe 중 하나여야 합니다
|
||||
@msg `{key}` must be true or false `{key}`은(는) true 또는 false여야 합니다
|
||||
@msg `select` must be true or false `select`은(는) true 또는 false여야 합니다
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors`와 `maxAnchors`는 정수여야 합니다
|
||||
@msg `{key}` must be a number not below 0 `{key}`은(는) 0 이상의 숫자여야 합니다
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}`은(는) [x, y, width, height]여야 합니다: 유한한 숫자 네 개이며 너비와 높이는 음수가 아니어야 합니다
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}`이(가) `{max_key}`보다 큽니다
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` 다음 중 하나 이상을 지정하세요: `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg brightness must be dark|mediumDark|mediumLight|light brightness는 dark|mediumDark|mediumLight|light 중 하나여야 합니다
|
||||
@msg index must be a number or first, previous, next or last index는 숫자이거나 first, previous, next, last 중 하나여야 합니다
|
||||
@msg index must be a number or first, previous, next or last, not `{other}` index는 숫자이거나 first, previous, next, last 중 하나여야 하며 `{other}`은(는) 안 됩니다
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4026,6 +4026,12 @@ imageTrace Outline Kontur
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` musi mieścić się w zakresie od {min} do {max} (podano {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` musi mieć jedną z wartości: {_1}
|
||||
@msg `{key}` must be true or false `{key}` musi mieć wartość true lub false
|
||||
@msg `select` must be true or false `select` musi mieć wartość true lub false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` i `maxAnchors` muszą być liczbami całkowitymi
|
||||
@msg `{key}` must be a number not below 0 `{key}` musi być liczbą nie mniejszą niż 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` musi mieć postać [x, y, width, height]: cztery skończone liczby, szerokość i wysokość nieujemne
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` jest większe niż `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` podaj co najmniej jeden z parametrów `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` musi mieć wartość grayscale, rgb, hsb, cmyk lub websafe
|
||||
@msg `{k}` must be [x, y] `{k}` musi mieć postać [x, y]
|
||||
@msg `{name}` has no options `{name}` nie ma opcji
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3483,6 +3483,12 @@ axis Both Ambos
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` deve estar entre {min} e {max} (recebido {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` deve ser um de {_1}
|
||||
@msg `{key}` must be true or false `{key}` deve ser true ou false
|
||||
@msg `select` must be true or false `select` deve ser true ou false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` e `maxAnchors` devem ser números inteiros
|
||||
@msg `{key}` must be a number not below 0 `{key}` deve ser um número não inferior a 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` deve ser [x, y, width, height]: quatro números finitos, com largura e altura não negativas
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` é maior que `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` informe pelo menos um de `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `{k}` must be [x, y] `{k}` deve ser [x, y]
|
||||
@msg `{name}` has no options `{name}` não tem opções
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` é um espaço de trabalho integrado; escolha outro nome
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3937,6 +3937,12 @@ axis Both Оба
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` должно быть от {min} до {max} (получено {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` должно быть одним из: {_1}
|
||||
@msg `{key}` must be true or false `{key}` должно быть true или false
|
||||
@msg `select` must be true or false `select` должно быть true или false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` и `maxAnchors` должны быть целыми числами
|
||||
@msg `{key}` must be a number not below 0 `{key}` должно быть числом не меньше 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` должно быть [x, y, width, height]: четыре конечных числа, ширина и высота не отрицательные
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` больше, чем `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` укажите хотя бы один из параметров `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` должно быть grayscale, rgb, hsb, cmyk или websafe
|
||||
@msg `{k}` must be [x, y] `{k}` должно быть [x, y]
|
||||
@msg `{name}` has no options `{name}` не имеет параметров
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3821,6 +3821,12 @@ axis Both Båda
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` måste vara mellan {min} och {max} (fick {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` måste vara något av {_1}
|
||||
@msg `{key}` must be true or false `{key}` måste vara true eller false
|
||||
@msg `select` must be true or false `select` måste vara true eller false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` och `maxAnchors` måste vara heltal
|
||||
@msg `{key}` must be a number not below 0 `{key}` måste vara ett tal som inte är under 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` måste vara [x, y, width, height]: fyra ändliga tal, där bredd och höjd inte är negativa
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` är större än `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` ange minst en av `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `{k}` must be [x, y] `{k}` måste vara [x, y]
|
||||
@msg `{name}` has no options `{name}` har inga alternativ
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` är en inbyggd arbetsyta; välj ett annat namn
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3705,6 +3705,12 @@ axis Both Her İkisi
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}`, {min} ile {max} arasında olmalıdır ({x}'yi aldı)
|
||||
@msg `{key}` must be one of {_1} `{key}`, {_1}'den biri olmalıdır
|
||||
@msg `{key}` must be true or false "{key}" doğru veya yanlış olmalıdır
|
||||
@msg `select` must be true or false `select` true veya false olmalıdır
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` ve `maxAnchors` tam sayı olmalıdır
|
||||
@msg `{key}` must be a number not below 0 `{key}` 0'dan küçük olmayan bir sayı olmalıdır
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` [x, y, width, height] olmalıdır: dört sonlu sayı, genişlik ve yükseklik negatif olmamalı
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}`, `{max_key}` değerinden büyük
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` şunlardan en az birini verin: `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe "mod" gri tonlamalı, rgb, hsb, cmyk veya web uyumlu olmalıdır
|
||||
@msg `{k}` must be [x, y] "{k}" [x, y] olmalıdır
|
||||
@msg `{name}` has no options `{name}`nin seçeneği yok
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3925,6 +3925,12 @@ axis Both Обидві
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` має бути від {min} до {max} (отримано {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` має бути одним з: {_1}
|
||||
@msg `{key}` must be true or false `{key}` має бути true або false
|
||||
@msg `select` must be true or false `select` має бути true або false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` і `maxAnchors` мають бути цілими числами
|
||||
@msg `{key}` must be a number not below 0 `{key}` має бути числом, не меншим за 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` має бути [x, y, width, height]: чотири скінченні числа, ширина й висота невід’ємні
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` більше за `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` укажіть принаймні один із параметрів `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` має бути grayscale, rgb, hsb, cmyk або websafe
|
||||
@msg `{k}` must be [x, y] `{k}` має бути [x, y]
|
||||
@msg `{name}` has no options `{name}` не має параметрів
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 747 and column 40.
|
@@ -4082,6 +4082,12 @@ theme Appearance Giao diện
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` phải nằm trong khoảng {min} đến {max} (nhận được {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` phải là một trong {_1}
|
||||
@msg `{key}` must be true or false `{key}` phải là true hoặc false
|
||||
@msg `select` must be true or false `select` phải là true hoặc false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` và `maxAnchors` phải là số nguyên
|
||||
@msg `{key}` must be a number not below 0 `{key}` phải là một số không nhỏ hơn 0
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` phải là [x, y, width, height]: bốn số hữu hạn, chiều rộng và chiều cao không âm
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` lớn hơn `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` hãy cung cấp ít nhất một trong `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` phải là grayscale, rgb, hsb, cmyk hoặc websafe
|
||||
@msg `{k}` must be [x, y] `{k}` phải là [x, y]
|
||||
@msg `{name}` has no options `{name}` không có tùy chọn
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 4051 and column 10.
|
@@ -4162,6 +4162,12 @@ imageTrace Outline 轮廓
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` 必须是其菜单项会打开对话框的命令 (请参阅 ui.menuDialog)
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` 必须是 grayscale、rgb、hsb、cmyk 或 websafe
|
||||
@msg `{key}` must be true or false `{key}` 必须是 true 或 false
|
||||
@msg `select` must be true or false `select` 必须是 true 或 false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` 和 `maxAnchors` 必须是整数
|
||||
@msg `{key}` must be a number not below 0 `{key}` 必须是不小于 0 的数字
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` 必须是 [x, y, width, height]:四个有限数字,宽度和高度不能为负
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` 大于 `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` 请至少提供以下其中之一:`name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg brightness must be dark|mediumDark|mediumLight|light brightness 必须是 dark|mediumDark|mediumLight|light
|
||||
@msg index must be a number or first, previous, next or last index 必须是数字,或 first、previous、next 或 last
|
||||
@msg index must be a number or first, previous, next or last, not `{other}` index 必须是数字,或 first、previous、next 或 last,而不是 `{other}`
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2143,6 +2143,12 @@ file-filter Templates 範本
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` 必須是選單項目會開啟對話框的指令 (請參閱 ui.menuDialog)
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` 必須是 grayscale、rgb、hsb、cmyk 或 websafe
|
||||
@msg `{key}` must be true or false `{key}` 必須是 true 或 false
|
||||
@msg `select` must be true or false `select` 必須是 true 或 false
|
||||
@msg `minAnchors` and `maxAnchors` must be whole numbers `minAnchors` 和 `maxAnchors` 必須是整數
|
||||
@msg `{key}` must be a number not below 0 `{key}` 必須是不小於 0 的數字
|
||||
@msg `{key}` must be [x, y, width, height]: four finite numbers, width and height not negative `{key}` 必須是 [x, y, width, height]:四個有限數字,寬度和高度不能為負
|
||||
@msg `{min_key}` is greater than `{max_key}` `{min_key}` 大於 `{max_key}`
|
||||
@msg give at least one of `name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors` 請至少提供下列其中之一:`name`, `kind`, `text`, `within`, `intersects`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minThickness`, `maxThickness`, `minArea`, `maxArea`, `minAnchors`, `maxAnchors`
|
||||
@msg brightness must be dark|mediumDark|mediumLight|light brightness 必須是 dark|mediumDark|mediumLight|light
|
||||
@msg index must be a number or first, previous, next or last index 必須是數字,或 first、previous、next 或 last
|
||||
@msg index must be a number or first, previous, next or last, not `{other}` index 必須是數字,或 first、previous、next 或 last,而非 `{other}`
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
+16
-3
@@ -219,7 +219,8 @@ node (layers and groups too) reports `opacity` when it is below 1 and `blend` wh
|
||||
|
||||
On a large document, drill instead of dumping: `inspect_document {depth: 0}` (or `run_command document.inspect
|
||||
{depth?, childLimit?}`, same rules) is the skeleton (artboards with top layers and counts), `run_command
|
||||
document.find {name?, kind?, text?, limit?}` locates nodes across the whole tree, and `document.node` reads the
|
||||
document.find {name?, kind?, text?, within?, intersects?, minArea?, …, select?, limit?}` locates nodes across the
|
||||
whole tree, and `document.node` reads the
|
||||
interesting ones sliced. `document.inspect` and the `doc_inspect` / `inspect_document` tools also scope the
|
||||
reply themselves: `ids: [id…]` lists just those nodes (any level, in the order given, an unknown id is an error,
|
||||
at most 10000), `kind` lists every node of one panel label (ignoring case; within the subtrees of `ids` when both
|
||||
@@ -230,9 +231,21 @@ top layers (`layers` and `total`). Without these options the reply is the whole
|
||||
`document.find` needs at least one filter and all given filters must match; matching
|
||||
ignores case, `name` is a substring of the Layers panel name, `text` a substring of type content and `kind` the
|
||||
exact panel label (`Layer`, `Group`, `Clip Group`, `Path`, `Compound Path`, `Type`, `Image`, `Rectangle`, ...).
|
||||
The geometric filters read each object's geometric bounds, in the document points `document.inspect` reports
|
||||
(groups included; layers, sublayers and a node without bounds do not match): `within: [x, y, width, height]` keeps
|
||||
objects inside that rectangle (edges included), `intersects: [x, y, width, height]` objects touching or overlapping it,
|
||||
`minWidth` / `maxWidth` and `minHeight` / `maxHeight` limit the bounds' size, `minThickness` / `maxThickness`
|
||||
the smaller of width and height (thin slivers of either orientation), and `minArea` / `maxArea` width × height.
|
||||
`minAnchors` / `maxAnchors` count a path's anchor points, a compound path's members together; other nodes do not
|
||||
match them. Limits are inclusive, not negative, and a minimum above its maximum is an error. `select: true`
|
||||
also selects the matches, leaving out hidden and locked ones, those inside another match, and a compound path's
|
||||
members unless the compound path is isolated; Select › Reselect repeats the find, and an action being recorded
|
||||
records it as a step (a find without `select` is not recorded). For example,
|
||||
`document.find {maxThickness: 1, kind: "path", select: true}` followed by `edit.clear` deletes hairline slivers.
|
||||
It answers `{matches: [{id, name, kind, path}], total}` top of the stack first, where `path` is the ancestor
|
||||
chain (layer first) and `limit` caps `matches` (default 100; `0` only counts). `document.json` stays whole: it is
|
||||
the fidelity path, not the way to look around.
|
||||
chain (layer first) and `limit` caps `matches` (default 100; `0` only counts); with `select` the reply adds
|
||||
`selected`, the number of objects selected. `document.json` stays whole: it is the fidelity path, not the way to
|
||||
look around.
|
||||
|
||||
### Completions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user