mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Find Objects: document.find filters by bounds, size and anchor count and can select the matches
document.find took only name, kind and text, so removing hairline slivers or every object in one region needed the whole inspect tree and a filter written outside the app. It now also takes within and intersects ([x, y, width, height] in document points), min and max width, height, thickness (the smaller side) and area of the geometric bounds, and min and max anchor count (a compound path counts its members together). Each given filter must match, and limits are inclusive. select: true also selects the matches, leaving out hidden and locked objects, matches inside another match, and compound path members unless the compound path is isolated; the reply adds selected. Select > Reselect repeats the find, and an action being recorded records a find that selects. The count that select.color, the Select > Same commands and the Select > Object commands report is now the number of objects selected, after Lock Guides leaves out guide paths.
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