M1: merge main and complete Turkish artwork drag translations

Add the three Turkish catalog entries requested by the maintainer on #3479. Preserve upstream catalog additions and place existing tab-drag entries beside stable menu labels to avoid append conflicts. Update feature progress notes for all 24 catalogs.

Simplify an equivalent Effect Gallery selection predicate required by the Rust 1.95 clippy gate. Full cargo xtask ci passed all 10 checks, including tab-drag regressions and wasm.
This commit is contained in:
Don Omondi
2026-10-22 04:16:24 +03:00
49 changed files with 6498 additions and 147 deletions
+1
View File
@@ -154,6 +154,7 @@ pub const LANGUAGES: &[(&str, Quotes)] = &[
("Polish", Quotes { double: ['„', '”'], single: ['‚', '’'] }),
("Czech", Quotes { double: ['„', '“'], single: ['‚', '‘'] }),
("Russian", Quotes { double: ['«', '»'], single: ['„', '“'] }),
("Turkish", Quotes { double: ['“', '”'], single: ['‘', '’'] }),
("Japanese", Quotes { double: ['「', '」'], single: ['『', '』'] }),
("Chinese", Quotes { double: ['“', '”'], single: ['‘', '’'] }),
];
+11 -1
View File
@@ -1713,8 +1713,18 @@ impl TextObject {
/// How far the characters' strokes paint past their glyphs, in document space: they scale
/// with the type.
pub fn char_stroke_outset(&self) -> f64 {
self.char_strokes(CharStyle::stroke_outset)
}
/// How far the characters' strokes can paint past their glyphs, their miter spikes and square
/// caps included ([`StrokeLayer::reach`]), in document space: what a change of the type must
/// redraw. The visual bounds take [`Self::char_stroke_outset`].
pub fn char_stroke_reach(&self) -> f64 {
self.char_strokes(|style| if style.has_stroke() { style.stroke_layer().reach() } else { 0.0 })
}
/// The farthest `outset` of the characters' styles, scaled with the type.
fn char_strokes(&self, outset: impl Fn(&CharStyle) -> f64) -> f64 {
let k = crate::node::Scaling::factor(self.xf).unwrap_or(1.0);
self.runs.iter().map(|r| r.style.stroke_outset()).fold(0.0, f64::max) * k
self.runs.iter().map(|r| outset(&r.style)).fold(0.0, f64::max) * k
}
pub fn transform(&mut self, a: Affine) {
self.xf = a * self.xf;
+11
View File
@@ -793,6 +793,17 @@ pub fn open_filters() -> impl Iterator<Item = (&'static str, &'static [&'static
.chain(std::iter::once(("Plug-ins", super::plugin::EXTS)))
}
/// Open-dialog filters for Swatch Libraries and Graphic Style Libraries Other Library… and Locate
/// Library…. The library formats come first so Linux file portals (which grey out files that don't
/// match the default filter) still list `.ase` and the other library extensions; then the same
/// filters as [`open_filters`] so a document can be picked for its swatches or graphic styles.
pub fn library_open_filters(
library_label: &'static str,
library_exts: &'static [&'static str],
) -> impl Iterator<Item = (&'static str, &'static [&'static str])> {
std::iter::once((library_label, library_exts)).chain(open_filters())
}
/// File → Place dialog filters: "All placeable files", then one per placeable format, then text,
/// RTF and Word.
pub fn place_filters() -> impl Iterator<Item = (&'static str, &'static [&'static str])> {
+8
View File
@@ -384,6 +384,14 @@ fn open_exts_cover_every_readable_format() {
assert_eq!(filters.last(), Some(&("Plug-ins", crate::cmd::plugin::EXTS)), "File › Open installs plug-ins");
}
#[test]
fn library_open_filters_list_library_formats_first() {
let filters: Vec<_> = library_open_filters("Swatch libraries", super::swatchlib::LIBRARY_EXTS).collect();
assert_eq!(filters[0], ("Swatch libraries", super::swatchlib::LIBRARY_EXTS));
assert!(filters[0].1.contains(&"ase"));
assert_eq!(filters[1], ("All readable files", OPEN_EXTS));
}
/// The extensions usage texts list for export: one per writable format, each picking that format
/// (`.png` picks PNG; PNG-8 is asked for by `format`).
#[test]
+5 -3
View File
@@ -159,9 +159,10 @@ fn expanded_art_keeps_the_random_transforms_the_canvas_drew() {
assert_eq!(differ, RANDOM_CASES.map(|case| (case, 0)));
}
/// The reply lists each object whose appearance expanded once, by the id it has in the document.
/// In "group copies" the two copies of the square share an id until Expand Appearance gives them
/// ids of their own, and the reply names the group, then each copy by its new id.
/// The reply lists each object whose appearance expanded once, by the id it has in the document,
/// starting with the selected object. In "group copies" the two copies of the square share an id
/// until Expand Appearance gives them ids of their own, and the reply names the group, then each
/// copy by its new id.
#[test]
fn the_reply_names_each_expanded_copy_by_its_own_id() {
for case in RANDOM_CASES {
@@ -169,6 +170,7 @@ fn the_reply_names_each_expanded_copy_by_its_own_id() {
let id = random_transforms(&mut s, case);
let r = run(&mut s, "effect.expandAppearance", json!({}));
let ids: Vec<u64> = r["ids"].as_array().unwrap().iter().map(|v| v.as_u64().unwrap()).collect();
assert_eq!(ids.first(), Some(&id.0), "{case}: {ids:?}");
let unique: std::collections::HashSet<_> = ids.iter().collect();
assert_eq!(unique.len(), ids.len(), "{case}: {ids:?}");
assert!(ids.iter().all(|&i| s.doc().unwrap().doc.node(NodeId(i)).is_some()), "{case}: {ids:?}");
+4 -3
View File
@@ -489,11 +489,12 @@ fn cull_bounds_in(symbols: &SymbolBoxes, n: &Node, after_reshape: bool) -> Optio
}
/// The box of type `t`'s glyphs as laid out (its layout bounds, else laid out now), grown by its
/// characters' strokes and by `outset`: on a path they stand above it and run past its ends, in an
/// area they can hang past its frame, where its own box ([`Node::visual_bounds_with`]) doesn't.
/// characters' strokes, miter spikes included, and by `outset`: on a path they stand above it and
/// run past its ends, in an area they can hang past its frame, where its own box
/// ([`Node::visual_bounds_with`]) doesn't.
fn glyphs_box(t: &vectorcraft_doc::TextObject, outset: f64) -> Option<Rect> {
let b = t.cached_bounds.unwrap_or_else(|| vectorcraft_text::layout(vectorcraft_text::FontDb::global(), t).bounds);
let o = outset.max(t.char_stroke_outset());
let o = outset.max(t.char_stroke_reach());
(b.width() > 0.0 || b.height() > 0.0).then(|| t.xf.transform_rect_bbox(b).inflate(o, o))
}
+22
View File
@@ -192,6 +192,28 @@ fn reshaping_the_path_of_type_on_a_path_changes_where_its_letters_were_and_are()
redraw(&old, &new);
}
/// Stroked type with sharp corners: the miter spikes of its characters' strokes reach past half
/// the weight, and change where they were and where they are.
#[test]
fn moving_type_with_mitred_strokes_changes_where_its_spikes_reach() {
let mut old = Document::new(110.0, 80.0);
let l = old.layers[0].id;
let style = vectorcraft_doc::text::CharStyle {
size: 30.0,
stroke: Paint::solid(Color::BLACK),
stroke_width: 10.0,
stroke_join: vectorcraft_doc::LineJoin::Miter,
stroke_miter_limit: 10.0,
..Default::default()
};
let mut t = vectorcraft_doc::text::TextObject::point(Point::new(10.0, 50.0), "VAWV", style);
t.cached_bounds = Some(vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t).bounds);
let text = old.insert(Some(l), 0, Node::new(NodeId(0), NodeKind::Text(Box::new(t)))).unwrap();
let mut new = old.clone();
new.node_mut(text).unwrap().transform(Affine::translate((9.0, 7.0)), false);
redraw(&old, &new);
}
#[test]
fn an_unchanged_document_changes_nothing_and_a_new_symbol_everything() {
let (old, _) = document();
+2 -1
View File
@@ -78,6 +78,7 @@ fn unit(d: &Dialog) -> Unit {
Unit::named(&d.str("units")).unwrap_or_default()
}
/// The General tab of Document Setup (units, bleed, artboard editing, options).
fn general(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
let units: Vec<(&str, &str)> = Unit::ALL.iter().map(|u| (u.label(), u.label())).collect();
choice(ui, d, "units", tl!("Units:"), &units);
@@ -88,7 +89,7 @@ fn general(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool
let mut close = false;
widgets::label_row(ui, "", LABEL, |ui| {
// Applies the settings, then edits the artboards with the Artboard tool.
if widgets::flat_button(ui, tl!("Edit Artboards"), 120.0).clicked() && confirm(app, d).is_ok() {
if widgets::flat_button_fit(ui, tl!("Edit Artboards"), 120.0).clicked() && confirm(app, d).is_ok() {
app.select_tool("artboard");
// The shared frame restores its working copy after drawing the body. Tell it to
// close too, otherwise it reopens the dialog that confirm just closed.
@@ -0,0 +1,478 @@
//! Effect → Effect Gallery: browse Photoshop-style raster filters by category, build a stack, and
//! apply it as separate appearance effects in one undo step.
use egui;
use serde_json::{Map, Value, json};
use vectorcraft_effects::{EffectInfo, PIXEL_EFFECTS};
use super::{DialogSpec, effect, form};
use crate::state::Dialog;
use crate::theme::Tokens;
use crate::{VectorcraftApp, widgets};
/// Dialog kind for the Effect Gallery.
pub const KIND: &str = "effectGallery";
/// Raster effect submenus in the gallery (the six Photoshop-style folders it holds).
const CATEGORIES: [(&str, &[&str]); 6] = [
("Artistic", &["Effect", "Artistic"]),
("Brush Strokes", &["Effect", "Brush Strokes"]),
("Distort", &["Effect", "Distort"]),
("Sketch", &["Effect", "Sketch"]),
("Stylize", &["Effect", "Stylize"]),
("Texture", &["Effect", "Texture"]),
];
pub(super) const SPEC: DialogSpec = DialogSpec {
heading: |_| tl!("Effect Gallery").into(),
body,
confirm,
preview: true,
min_width: 720.0,
max_width: Some(820.0),
..DialogSpec::FORM
};
#[derive(Clone)]
struct StackEntry {
effect: String,
visible: bool,
params: Map<String, Value>,
}
/// Open the gallery on the current selection.
pub fn open(app: &mut VectorcraftApp, _p: &Value) -> Result<Value, String> {
if app.session.active().is_none_or(|s| s.selection.is_empty()) {
return Err(tl!("Select artwork to apply effects").into());
}
let selected = effects_in_category(0).first().map(|e| e.id).unwrap_or("");
app.ui.dialog = Some(Dialog::new(
KIND,
json!({ "category": 0, "selected": selected, "stack": [], "stackSelected": 0, "stackFocus": false, "preview": true }),
));
Ok(Value::Null)
}
fn effects_in_category(cat: usize) -> Vec<EffectInfo> {
let path = CATEGORIES.get(cat).map(|(_, p)| *p).unwrap_or(CATEGORIES[0].1);
let mut out: Vec<EffectInfo> =
vectorcraft_effects::effect_catalog().into_iter().filter(|e| e.menu == path && PIXEL_EFFECTS.contains(&e.id)).collect();
out.sort_by(|a, b| a.label.cmp(b.label));
out
}
fn default_params(id: &str) -> Map<String, Value> {
match vectorcraft_effects::effect_info(id).map(|e| e.defaults) {
Some(Value::Object(m)) => m,
_ => Map::new(),
}
}
fn merged_params(id: &str, stored: &Map<String, Value>) -> Map<String, Value> {
match vectorcraft_effects::merged_params(id, &Value::Object(stored.clone())) {
Value::Object(m) => m,
_ => default_params(id),
}
}
fn stack_of(d: &Dialog) -> Vec<StackEntry> {
d.fields
.get("stack")
.and_then(Value::as_array)
.map(|rows| {
rows.iter()
.filter_map(|row| {
let effect = row.get("effect").and_then(Value::as_str)?;
let visible = row.get("visible").and_then(Value::as_bool).unwrap_or(true);
let params = row
.get("params")
.and_then(Value::as_object)
.cloned()
.map(|m| merged_params(effect, &m))
.unwrap_or_else(|| default_params(effect));
Some(StackEntry { effect: effect.to_string(), visible, params })
})
.collect()
})
.unwrap_or_default()
}
fn write_stack(d: &mut Dialog, stack: &[StackEntry]) {
let rows: Vec<Value> = stack.iter().map(|e| json!({ "effect": e.effect, "visible": e.visible, "params": e.params })).collect();
d.fields.insert("stack".into(), Value::Array(rows));
}
fn category_ix(d: &Dialog) -> usize {
d.fields.get("category").and_then(Value::as_u64).unwrap_or(0) as usize
}
fn selected_id(d: &Dialog) -> String {
d.str("selected")
}
fn set_selected(d: &mut Dialog, id: &str) {
d.fields.insert("selected".into(), json!(id));
}
fn stack_focus(d: &Dialog) -> bool {
d.fields.get("stackFocus").and_then(Value::as_bool).unwrap_or(false)
}
fn set_stack_focus(d: &mut Dialog, on: bool) {
d.fields.insert("stackFocus".into(), json!(on));
}
fn browse_params(d: &Dialog) -> Map<String, Value> {
let effect = d.fields.get("browseEffect").and_then(Value::as_str).unwrap_or("");
let stored = d.fields.get("browseParams").and_then(Value::as_object).cloned().unwrap_or_default();
if effect.is_empty() { stored } else { merged_params(effect, &stored) }
}
fn set_browse_params(d: &mut Dialog, effect: &str, params: Map<String, Value>) {
d.fields.insert("browseEffect".into(), json!(effect));
d.fields.insert("browseParams".into(), Value::Object(params));
}
/// The effect whose parameters the panel edits, and its values.
fn param_target(d: &Dialog, stack: &[StackEntry], stack_sel: usize, browse: &str) -> (String, Map<String, Value>) {
if stack_focus(d) {
let entry = stack.get(stack_sel);
if let Some(e) = entry {
return (e.effect.clone(), e.params.clone());
}
}
let id = browse.to_string();
let params = if d.fields.get("browseEffect").and_then(Value::as_str) == Some(browse) { browse_params(d) } else { default_params(browse) };
(id, params)
}
fn write_param_target(d: &mut Dialog, stack: &mut [StackEntry], stack_sel: usize, browse: &str, effect: &str, params: Map<String, Value>) {
if stack_focus(d) {
if let Some(e) = stack.get_mut(stack_sel)
&& e.effect == effect
{
e.params = params;
}
return;
}
if browse == effect {
set_browse_params(d, effect, params);
}
}
/// Reuse the live effect dialog's fields for `effect_id` and `params`.
fn effect_param_fields(app: &mut VectorcraftApp, ui: &mut egui::Ui, effect_id: &str, params: &mut Map<String, Value>) {
if effect_id.is_empty() {
return;
}
let label =
vectorcraft_effects::effect_info(effect_id).map(|e| e.label.trim_end_matches('…').to_string()).unwrap_or_else(|| effect_id.to_string());
let mut fields = params.clone();
fields.insert("__effect".into(), json!(effect_id));
fields.insert("__label".into(), json!(label));
fields.insert("preview".into(), json!(false));
let mut temp = Dialog::new("effect", Value::Object(fields));
(effect::SPEC.body)(app, ui, &mut temp);
if let Value::Object(m) = form::params(&temp) {
*params = m;
}
if let Value::Object(m) = vectorcraft_effects::upgrade_params(effect_id, &Value::Object(params.clone())) {
*params = m;
}
}
fn stack_batch_commands(stack: &[StackEntry]) -> Vec<Value> {
let mut commands = Vec::with_capacity(stack.len() * 2);
for (i, entry) in stack.iter().enumerate() {
let params = Value::Object(entry.params.clone());
commands.push(json!({ "command": "effect.apply", "params": { "effect": entry.effect, "params": params } }));
if !entry.visible {
commands.push(json!({ "command": "effect.setParams", "params": { "index": i, "visible": false } }));
}
}
commands
}
fn stack_batch_params(stack: &[StackEntry]) -> Value {
json!({ "label": "Effect Gallery", "commands": stack_batch_commands(stack) })
}
/// Live canvas preview of the stack (`command.batch` would settle the dialog interaction each frame).
fn preview_stack_on_canvas(app: &mut VectorcraftApp, stack: &[StackEntry]) {
if app.session.in_interaction() {
let _ = app.session.cancel_interaction();
}
let _ = app.session.begin_interaction("Effect Gallery");
for (i, entry) in stack.iter().enumerate() {
let params = Value::Object(entry.params.clone());
if app.run("effect.apply", json!({ "effect": entry.effect, "params": params })).is_err() {
let _ = app.session.cancel_interaction();
return;
}
if !entry.visible && app.run("effect.setParams", json!({ "index": i, "visible": false })).is_err() {
let _ = app.session.cancel_interaction();
return;
}
}
}
fn stack_preview_row(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog, stack: &[StackEntry]) {
const LAST: &str = super::form::PREVIEWED;
ui.add_space(8.0);
let mut on = d.bool("preview");
if widgets::check(ui, tl!("Preview"), on, true) {
on = !on;
d.fields.insert("preview".into(), json!(on));
}
if !on {
if d.fields.remove(LAST).is_some() {
let _ = app.session.cancel_interaction();
}
return;
}
if stack.is_empty() {
if d.fields.remove(LAST).is_some() {
let _ = app.session.cancel_interaction();
}
return;
}
let batch = stack_batch_params(stack);
if d.fields.get(LAST) != Some(&batch) || !app.session.in_interaction() {
preview_stack_on_canvas(app, stack);
d.fields.insert(LAST.into(), batch);
}
}
fn effect_label(id: &str) -> String {
vectorcraft_effects::effect_info(id).map(|e| tl!(e.label).trim_end_matches('…').to_string()).unwrap_or_else(|| id.to_string())
}
fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
let t = Tokens::get(ui.ctx());
let cat = category_ix(d);
let effects = effects_in_category(cat);
let mut sel = selected_id(d);
if !effects.iter().any(|e| e.id == sel) {
sel = effects.first().map(|e| e.id.to_string()).unwrap_or_default();
set_selected(d, &sel);
}
let mut stack = stack_of(d);
let mut stack_sel = d.fields.get("stackSelected").and_then(Value::as_u64).unwrap_or(0) as usize;
if stack_sel >= stack.len() && !stack.is_empty() {
stack_sel = stack.len() - 1;
}
let (param_effect, mut param_values) = param_target(d, &stack, stack_sel, &sel);
if !param_effect.is_empty() {
widgets::subheader(ui, tl!("Settings"));
egui::ScrollArea::vertical().max_height(200.0).show(ui, |ui| {
effect_param_fields(app, ui, &param_effect, &mut param_values);
});
write_param_target(d, &mut stack, stack_sel, &sel, &param_effect, param_values);
}
ui.horizontal_top(|ui| {
ui.vertical(|ui| {
widgets::subheader(ui, tl!("Categories"));
ui.set_width(120.0);
for (i, (name, _)) in CATEGORIES.iter().enumerate() {
let count = effects_in_category(i).len();
if count == 0 {
continue;
}
let label = tl!(name);
if ui.add(egui::Button::selectable(cat == i, label)).clicked() {
d.fields.insert("category".into(), json!(i));
let first = effects_in_category(i).first().map(|e| e.id).unwrap_or("");
set_selected(d, first);
set_stack_focus(d, false);
}
}
});
ui.add_space(8.0);
ui.vertical(|ui| {
widgets::subheader(ui, tl!("Filters"));
ui.set_width(220.0);
egui::ScrollArea::vertical().max_height(220.0).show(ui, |ui| {
for e in &effects {
let picked = e.id == sel;
let name = tl!(e.label).trim_end_matches('…').to_string();
let resp = ui.add(egui::Button::selectable(picked, name));
if resp.clicked() {
set_selected(d, e.id);
set_stack_focus(d, false);
}
if resp.double_clicked() {
set_selected(d, e.id);
set_stack_focus(d, false);
add_selected(d, e.id);
stack = stack_of(d);
}
}
});
if widgets::flat_button(ui, tl!("Add to Stack"), 120.0).clicked() && !sel.is_empty() {
add_selected(d, &sel);
stack = stack_of(d);
}
});
});
ui.add_space(10.0);
widgets::subheader(ui, tl!("Applied Filters"));
let mut stack_sel = d.fields.get("stackSelected").and_then(Value::as_u64).unwrap_or(0) as usize;
if stack_sel >= stack.len() && !stack.is_empty() {
stack_sel = stack.len() - 1;
}
enum StackOp {
Toggle(usize),
Up(usize),
Down(usize),
Remove(usize),
Select(usize),
}
let mut op = None;
let stack_len = stack.len();
egui::ScrollArea::vertical().max_height(120.0).show(ui, |ui| {
if stack.is_empty() {
ui.label(egui::RichText::new(tl!("Add filters from the list above")).color(t.text_dim));
return;
}
for (i, entry) in stack.iter().enumerate().take(stack_len) {
ui.horizontal(|ui| {
let eye = if entry.visible { "eye" } else { "eye-off" };
if widgets::icon_button(ui, eye, tl!("Click to toggle visibility"), false, 22.0).clicked() {
op = Some(StackOp::Toggle(i));
}
let name = effect_label(&entry.effect);
if ui.add(egui::Button::selectable(stack_sel == i, name)).clicked() {
op = Some(StackOp::Select(i));
}
if widgets::icon_button_enabled(ui, "dc-arrow-up", tl!("Move Up"), false, i > 0, 22.0).clicked() {
op = Some(StackOp::Up(i));
}
if widgets::icon_button_enabled(ui, "dc-arrow-down", tl!("Move Down"), false, i + 1 < stack_len, 22.0).clicked() {
op = Some(StackOp::Down(i));
}
if widgets::flat_button(ui, tl!("Remove"), 64.0).clicked() {
op = Some(StackOp::Remove(i));
}
});
}
});
match op {
Some(StackOp::Toggle(i)) if stack.get(i).is_some() => stack[i].visible = !stack[i].visible,
Some(StackOp::Select(i)) => {
stack_sel = i;
set_stack_focus(d, true);
}
Some(StackOp::Up(i)) if i > 0 => {
stack.swap(i, i - 1);
stack_sel = i - 1;
}
Some(StackOp::Down(i)) if i + 1 < stack.len() => {
stack.swap(i, i + 1);
stack_sel = i + 1;
}
Some(StackOp::Remove(i)) if i < stack.len() => {
stack.remove(i);
if stack_sel >= stack.len() && !stack.is_empty() {
stack_sel = stack.len() - 1;
}
}
_ => {}
}
write_stack(d, &stack);
d.fields.insert("stackSelected".into(), json!(stack_sel));
stack_preview_row(app, ui, d, &stack);
false
}
fn add_selected(d: &mut Dialog, id: &str) {
let params =
if !stack_focus(d) && d.fields.get("browseEffect").and_then(Value::as_str) == Some(id) { browse_params(d) } else { default_params(id) };
let mut stack = stack_of(d);
stack.push(StackEntry { effect: id.to_string(), visible: true, params });
write_stack(d, &stack);
d.fields.insert("stackSelected".into(), json!(stack.len().saturating_sub(1)));
set_stack_focus(d, true);
}
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
let stack = stack_of(d);
if stack.is_empty() {
if app.session.in_interaction() {
let _ = app.session.cancel_interaction();
}
app.ui.dialog = None;
return Ok(Value::Null);
}
let batch = stack_batch_params(&stack);
if d.bool("preview") && app.session.in_interaction() {
return super::form::commit_preview(app, "command.batch", batch);
}
let r = app.run("command.batch", batch);
if r.is_ok() {
app.ui.dialog = None;
}
r
}
#[cfg(test)]
mod tests {
use serde_json::json;
use vectorcraft_engine::Session;
use crate::VectorcraftApp;
fn frame(app: &mut VectorcraftApp) {
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
crate::theme::apply(&ctx, Default::default());
let raw = egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1200.0, 900.0))), ..Default::default() };
let mut out = ctx.run_ui(raw, |ui| crate::dialogs::show(app, ui.ctx()));
out.textures_delta.clear();
}
#[test]
fn stack_preview_is_one_interaction() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 40, "height": 40})).unwrap()["id"].as_u64().unwrap();
app.run("ui.effectGalleryDialog", json!({})).unwrap();
let d = app.ui.dialog.as_mut().unwrap();
d.fields.insert("stack".into(), json!([{ "effect": "artistic.cutout", "visible": true, "params": { "levels": 3 } }]));
frame(&mut app);
assert!(app.session.in_interaction(), "the stack previews on the canvas");
crate::dialogs::cancel(&mut app);
assert!(!app.session.in_interaction());
assert!(app.session.active().unwrap().doc.node(vectorcraft_doc::NodeId(id)).unwrap().appearance.effects.is_empty());
}
#[test]
fn stack_ok_is_one_undo_step() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 40, "height": 40})).unwrap()["id"].as_u64().unwrap();
app.run("ui.effectGalleryDialog", json!({})).unwrap();
assert_eq!(app.ui.dialog.as_ref().map(|d| d.kind.as_str()), Some(super::KIND));
let d = app.ui.dialog.as_mut().unwrap();
d.fields.insert(
"stack".into(),
json!([
{ "effect": "artistic.cutout", "visible": true, "params": { "levels": 3 } },
{ "effect": "stylize.glowingEdges", "visible": false, "params": { "edgeWidth": 2 } }
]),
);
frame(&mut app);
let steps = app.session.active().unwrap().history.undo.len();
crate::dialogs::confirm(&mut app).unwrap();
let st = app.session.active().unwrap();
let n = st.doc.node(vectorcraft_doc::NodeId(id)).unwrap();
assert_eq!(n.appearance.effects.len(), 2);
assert_eq!(n.appearance.effects[0].id, "artistic.cutout");
assert_eq!(n.appearance.effects[0].params.get("levels").and_then(|v| v.as_i64()), Some(3));
assert_eq!(n.appearance.effects[1].id, "stylize.glowingEdges");
assert!(!n.appearance.effects[1].visible);
assert_eq!(st.history.undo.len(), steps + 1);
}
}
+2
View File
@@ -24,6 +24,7 @@ pub mod dxf_import;
pub mod dxf_options;
pub mod edit_selection;
mod effect;
pub mod effect_gallery;
pub mod envelope;
pub mod eps_options;
pub mod expand;
@@ -301,6 +302,7 @@ registry! {
SwatchConflict: [swatch_conflict::KIND] => swatch_conflict::SPEC,
FileInfo: [file_info::KIND] => file_info::SPEC,
RasterEffectsSettings: [raster_effects::KIND] => raster_effects::SPEC,
EffectGallery: [effect_gallery::KIND] => effect_gallery::SPEC,
MissingLinks: [missing_links::KIND] => missing_links::SPEC,
MissingFonts: [missing_fonts::KIND] => missing_fonts::SPEC,
FindLinks: [find_links::KIND] => find_links::SPEC,
+15 -5
View File
@@ -1049,6 +1049,11 @@
Fidelity: Точност:
Figure Space Цифрово разстояние
Figure: Фигура:
# Artwork drag between document tabs.
Drop Artwork Поставяне на графика
@msg {key} must be [x, y] with finite coordinates {key} трябва да е [x, y] с крайни координати
@msg ids must contain 1–10000 object ids ids трябва да съдържа от 1 до 10000 идентификатора на обекти
File Файл
File Dimensions Размери на файла
File Format: Файлов формат:
@@ -5310,6 +5315,14 @@ theme Appearance Външен вид
Full Justify Пълно двустранно
Minimum must not exceed Desired, nor Desired Maximum. Минималната стойност не може да надвишава желаната, нито желаната – максималната.
Justification Подравняване
Add filters from the list above Добавете филтри от списъка по-горе
Add to Stack Добавяне към стека
Applied Filters Приложени филтри
Categories Категории
Choose a filter Изберете филтър
Effect Gallery Галерия с ефекти
Filters Филтри
Select artwork to apply effects Изберете графика, за да приложите ефекти
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them променливите и наборите от данни на файла не бяха прочетени (променливи: {variables}, набори от данни: {data_sets}): панелът „Променливи“ не ги показва
# Select by Color (select.color)
Select by Color Избиране по цвят
@@ -5343,8 +5356,5 @@ theme Appearance Външен вид
Shift: Изместване:
Fresco… Фреска…
Fresco Фреска
# Artwork drag between document tabs.
Drop Artwork Поставяне на графика
@msg {key} must be [x, y] with finite coordinates {key} трябва да е [x, y] с крайни координати
@msg ids must contain 1–10000 object ids ids трябва да съдържа от 1 до 10000 идентификатора на обекти
Effect Gallery… Галерия с ефекти…
Effect Gallery Dialog Диалог „Галерия с ефекти“
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -34,6 +34,11 @@
Medium Light Středně světlý
Light Světlý
Quit VectorCraft Ukončit VectorCraft
# Artwork drag between document tabs.
Drop Artwork Umístit grafiku
@msg {key} must be [x, y] with finite coordinates {key} musí být [x, y] s konečnými souřadnicemi
@msg ids must contain 1–10000 object ids ids musí obsahovat 1–10000 identifikátorů objektů
File Soubor
New… Nový…
New Without Dialog Nový bez dialogového okna
@@ -5333,6 +5338,7 @@ mark-style Japanese Japonské
@msg Persistent libraries not found: {files} Trvalé knihovny nebyly nalezeny: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` není panel knihovny (viz window.swatchLibrary)
@msg library panel `{given}` isn't open panel knihovny `{given}` není otevřený
@msg library panel `{given}` isn't missing its library knihovna panelu knihovny `{given}` nechybí
@msg too many library panels were opened in this session v této relaci bylo otevřeno příliš mnoho panelů knihoven
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Obraz má {_1} × {_2} pixelů, na jedné straně více než {LARGE_TRACE_SIDE}: vektorizuje se, ale pomaleji. Rychleji se vektorizuje s předvolbou nižší věrnosti nebo menší kopie obrazu.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Obraz byl vektorizován v rozlišení {_1} × {_2} pixelů, zmenšený z {_3} × {_4} (nejvýše {_5} megapixelů).
@@ -5353,6 +5359,14 @@ mark-style Japanese Japonské
Full Justify Zarovnat do bloku
Minimum must not exceed Desired, nor Desired Maximum. Minimum nesmí překročit požadovanou hodnotu ani požadovaná hodnota maximum.
Justification Zarovnání do bloku
Add filters from the list above Přidejte filtry ze seznamu výše
Add to Stack Přidat na zásobník
Applied Filters Použité filtry
Categories Kategorie
Choose a filter Vyberte filtr
Effect Gallery Galerie efektů
Filters Filtry
Select artwork to apply effects Vyberte grafiku, na kterou chcete použít efekty
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them proměnné a sady dat souboru nebyly načteny (proměnné: {variables}, sady dat: {data_sets}): panel Proměnné je nezobrazuje
# Select by Color (select.color)
Select by Color Vybrat podle barvy
@@ -5386,8 +5400,5 @@ mark-style Japanese Japonské
Shift: Posun:
Fresco… Freska…
Fresco Freska
# Artwork drag between document tabs.
Drop Artwork Umístit grafiku
@msg {key} must be [x, y] with finite coordinates {key} musí být [x, y] s konečnými souřadnicemi
@msg ids must contain 1–10000 object ids ids musí obsahovat 1–10000 identifikátorů objektů
Effect Gallery… Galerie efektů…
Effect Gallery Dialog Dialog Galerie efektů
Can't render this file because it contains an unexpected character in line 2 and column 73.
+15 -5
View File
@@ -20,6 +20,11 @@
Medium Light Mellemlys
Light Lys
Quit VectorCraft Slut VectorCraft
# Artwork drag between document tabs.
Drop Artwork Slip illustration
@msg {key} must be [x, y] with finite coordinates {key} skal være [x, y] med endelige koordinater
@msg ids must contain 1–10000 object ids ids skal indeholde 1–10000 objekt-id’er
File Filer
New… Ny…
New Without Dialog Ny uden dialog
@@ -5306,6 +5311,14 @@ swatch Bright Violet Kraftig violet
Full Justify Lige margener
Minimum must not exceed Desired, nor Desired Maximum. Minimum må ikke overstige Ønsket, og Ønsket ikke Maksimum.
Justification Justering
Add filters from the list above Tilføj filtre fra listen ovenfor
Add to Stack Tilføj til stak
Applied Filters Anvendte filtre
Categories Kategorier
Choose a filter Vælg et filter
Effect Gallery Effektgalleri
Filters Filtre
Select artwork to apply effects Vælg grafik for at anvende effekter
# Select by Color (select.color)
Select by Color Markér efter farve
Smudge Stick… Udtværingsstift…
@@ -5359,8 +5372,5 @@ swatch Bright Violet Kraftig violet
Shift: Forskydning:
Fresco… Fresko…
Fresco Fresko
# Artwork drag between document tabs.
Drop Artwork Slip illustration
@msg {key} must be [x, y] with finite coordinates {key} skal være [x, y] med endelige koordinater
@msg ids must contain 1–10000 object ids ids skal indeholde 1–10000 objekt-id’er
Effect Gallery… Effektgalleri…
Effect Gallery Dialog Dialogboksen Effektgalleri
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -1046,6 +1046,11 @@
Fidelity: Genauigkeit:
Figure Space Ziffernleerzeichen
Figure: Ziffern:
# Artwork drag between document tabs.
Drop Artwork Grafik ablegen
@msg {key} must be [x, y] with finite coordinates {key} muss [x, y] mit endlichen Koordinaten sein
@msg ids must contain 1–10000 object ids ids muss 1–10000 Objekt-IDs enthalten
File Datei
File Dimensions Dateiabmessungen
File Format: Dateiformat:
@@ -4913,6 +4918,7 @@ effect Soft Weich
@msg Persistent libraries not found: {files} Dauerhafte Bibliotheken nicht gefunden: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` ist kein Bibliotheksbedienfeld (siehe window.swatchLibrary)
@msg library panel `{given}` isn't open Bibliotheksbedienfeld `{given}` ist nicht geöffnet
@msg library panel `{given}` isn't missing its library dem Bibliotheksbedienfeld `{given}` fehlt seine Bibliothek nicht
@msg too many library panels were opened in this session in dieser Sitzung wurden zu viele Bibliotheksbedienfelder geöffnet
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Das Bild hat {_1} × {_2} Pixel, mehr als {LARGE_TRACE_SIDE} auf einer Seite: Es wird nachgezeichnet, aber langsamer. Eine Vorgabe mit geringerer Detailtreue oder eine kleinere Kopie des Bildes geht schneller.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Das Bild wurde mit {_1} × {_2} Pixeln nachgezeichnet, verkleinert von {_3} × {_4} (höchstens {_5} Megapixel).
@@ -4934,6 +4940,14 @@ effect Soft Weich
Minimum must not exceed Desired, nor Desired Maximum. Das Minimum darf den optimalen Wert nicht übersteigen, der optimale Wert nicht das Maximum.
Minimum Minimum
Justification Abstände
Add filters from the list above Filter aus der Liste oben hinzufügen
Add to Stack Zum Stapel hinzufügen
Applied Filters Angewendete Filter
Categories Kategorien
Choose a filter Filter wählen
Effect Gallery Effekt-Galerie
Filters Filter
Select artwork to apply effects Wählen Sie Grafik aus, um Effekte anzuwenden
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them die Variablen und Datensätze der Datei wurden nicht gelesen (Variablen: {variables}, Datensätze: {data_sets}): Das Bedienfeld „Variablen“ listet sie nicht auf
# Select by Color (select.color)
Select by Color Nach Farbe auswählen
@@ -4967,8 +4981,5 @@ effect Soft Weich
Shift: Verschiebung:
Fresco… Fresko…
Fresco Fresko
# Artwork drag between document tabs.
Drop Artwork Grafik ablegen
@msg {key} must be [x, y] with finite coordinates {key} muss [x, y] mit endlichen Koordinaten sein
@msg ids must contain 1–10000 object ids ids muss 1–10000 Objekt-IDs enthalten
Effect Gallery… Effekt-Galerie…
Effect Gallery Dialog Dialogfeld „Effekt-Galerie“
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -1015,6 +1015,11 @@
Fidelity: Πιστότητα:
Figure Space Κενό ψηφίου
Figure: Σχήμα:
# Artwork drag between document tabs.
Drop Artwork Απόθεση γραφικών
@msg {key} must be [x, y] with finite coordinates Το {key} πρέπει να είναι [x, y] με πεπερασμένες συντεταγμένες
@msg ids must contain 1–10000 object ids Το ids πρέπει να περιέχει 1–10000 αναγνωριστικά αντικειμένων
File Αρχείο
File Dimensions Διαστάσεις αρχείου
File Format: Μορφή αρχείου:
@@ -5285,6 +5290,7 @@ effect Points Σημεία
@msg Persistent libraries not found: {files} Δεν βρέθηκαν μόνιμες βιβλιοθήκες: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) Το `{given}` δεν είναι πίνακας βιβλιοθήκης (δείτε window.swatchLibrary)
@msg library panel `{given}` isn't open ο πίνακας βιβλιοθήκης `{given}` δεν είναι ανοιχτός
@msg library panel `{given}` isn't missing its library η βιβλιοθήκη του πίνακα βιβλιοθήκης `{given}` δεν λείπει
@msg too many library panels were opened in this session άνοιξαν πάρα πολλοί πίνακες βιβλιοθηκών σε αυτή τη συνεδρία
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Η εικόνα είναι {_1} × {_2} εικονοστοιχεία, πάνω από {LARGE_TRACE_SIDE} σε μία πλευρά: ανιχνεύεται, αλλά πιο αργά. Μια προρύθμιση χαμηλότερης πιστότητας ή ένα μικρότερο αντίγραφο της εικόνας ανιχνεύεται γρηγορότερα.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Η εικόνα ανιχνεύτηκε σε {_1} × {_2} εικονοστοιχεία, σμικρυμένη από {_3} × {_4} (το πολύ {_5} megapixel).
@@ -5305,6 +5311,14 @@ effect Points Σημεία
Full Justify Στοίχιση και στα δύο άκρα
Minimum must not exceed Desired, nor Desired Maximum. Το ελάχιστο δεν πρέπει να υπερβαίνει το επιθυμητό, ούτε το επιθυμητό το μέγιστο.
Justification Πλήρης στοίχιση
Add filters from the list above Προσθέστε φίλτρα από τη λίστα παραπάνω
Add to Stack Προσθήκη στη στοίβα
Applied Filters Εφαρμοσμένα φίλτρα
Categories Κατηγορίες
Choose a filter Επιλέξτε φίλτρο
Effect Gallery Συλλογή εφέ
Filters Φίλτρα
Select artwork to apply effects Επιλέξτε γραφικά για να εφαρμόσετε εφέ
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them οι μεταβλητές και τα σύνολα δεδομένων του αρχείου δεν διαβάστηκαν (μεταβλητές: {variables}, σύνολα δεδομένων: {data_sets}): ο πίνακας Μεταβλητές δεν τα εμφανίζει
# Select by Color (select.color)
Select by Color Επιλογή βάσει χρώματος
@@ -5338,8 +5352,5 @@ effect Points Σημεία
Shift: Μετατόπιση:
Fresco… Νωπογραφία…
Fresco Νωπογραφία
# Artwork drag between document tabs.
Drop Artwork Απόθεση γραφικών
@msg {key} must be [x, y] with finite coordinates Το {key} πρέπει να είναι [x, y] με πεπερασμένες συντεταγμένες
@msg ids must contain 1–10000 object ids Το ids πρέπει να περιέχει 1–10000 αναγνωριστικά αντικειμένων
Effect Gallery… Συλλογή εφέ…
Effect Gallery Dialog Παράθυρο διαλόγου Συλλογή εφέ
Can't render this file because it contains an unexpected character in line 2045 and column 19.
+16 -5
View File
@@ -1069,6 +1069,11 @@
Fidelity: Fidelidad:
Figure Space Espacio de cifra
Figure: Cifras:
# Artwork drag between document tabs.
Drop Artwork Soltar ilustración
@msg {key} must be [x, y] with finite coordinates {key} debe ser [x, y] con coordenadas finitas
@msg ids must contain 1–10000 object ids ids debe contener entre 1 y 10000 identificadores de objetos
File Archivo
File Dimensions Dimensiones del archivo
File Format: Formato de archivo:
@@ -5275,6 +5280,7 @@ mark-style Japanese Japonesas
@msg Persistent libraries not found: {files} No se encontraron bibliotecas persistentes: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` no es un panel de biblioteca (consulte window.swatchLibrary)
@msg library panel `{given}` isn't open el panel de biblioteca `{given}` no está abierto
@msg library panel `{given}` isn't missing its library la biblioteca del panel de biblioteca `{given}` no falta
@msg too many library panels were opened in this session se abrieron demasiados paneles de biblioteca en esta sesión
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. La imagen tiene {_1} × {_2} píxeles, más de {LARGE_TRACE_SIDE} en un lado: se calcará, pero más despacio. Un ajuste preestablecido de menor fidelidad o una copia más pequeña de la imagen se calcan más rápido.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). La imagen se calcó a {_1} × {_2} píxeles, reducida desde {_3} × {_4} ({_5} megapíxeles como máximo).
@@ -5295,6 +5301,14 @@ mark-style Japanese Japonesas
Full Justify Justificar completamente
Minimum must not exceed Desired, nor Desired Maximum. El mínimo no puede superar el deseado, ni el deseado el máximo.
Justification Justificación
Add filters from the list above Añada filtros de la lista de arriba
Add to Stack Añadir a la pila
Applied Filters Filtros aplicados
Categories Categorías
Choose a filter Elija un filtro
Effect Gallery Galería de efectos
Filters Filtros
Select artwork to apply effects Seleccione gráficos para aplicar efectos
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them no se leyeron las variables ni los conjuntos de datos del archivo (variables: {variables}, conjuntos de datos: {data_sets}): el panel Variables no los muestra
# Select by Color (select.color)
Select by Color Seleccionar por color
@@ -5328,8 +5342,5 @@ mark-style Japanese Japonesas
Shift: Desplazamiento:
Fresco… Fresco…
Fresco Fresco
# Artwork drag between document tabs.
Drop Artwork Soltar ilustración
@msg {key} must be [x, y] with finite coordinates {key} debe ser [x, y] con coordenadas finitas
@msg ids must contain 1–10000 object ids ids debe contener entre 1 y 10000 identificadores de objetos
Effect Gallery… Galería de efectos…
Effect Gallery Dialog Cuadro de diálogo Galería de efectos
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -42,6 +42,11 @@
Medium Light Keskivaalea
Light Vaalea
Quit VectorCraft Lopeta VectorCraft
# Artwork drag between document tabs.
Drop Artwork Pudota kuvitus
@msg {key} must be [x, y] with finite coordinates {key} on annettava muodossa [x, y] äärellisillä koordinaateilla
@msg ids must contain 1–10000 object ids ids-arvon on sisällettävä 1–10000 objektitunnusta
File Tiedosto
New… Uusi…
New Without Dialog Uusi ilman valintaikkunaa
@@ -5297,6 +5302,7 @@ mark-style Japanese Japanilainen
@msg Persistent libraries not found: {files} Pysyviä kirjastoja ei löytynyt: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` ei ole kirjastopaneeli (katso window.swatchLibrary)
@msg library panel `{given}` isn't open kirjastopaneeli `{given}` ei ole auki
@msg library panel `{given}` isn't missing its library kirjastopaneelin `{given}` kirjasto ei puutu
@msg too many library panels were opened in this session tässä istunnossa on avattu liian monta kirjastopaneelia
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Kuva on {_1} × {_2} kuvapistettä, yhdeltä sivultaan yli {LARGE_TRACE_SIDE}: se jäljitetään, mutta hitaammin. Pienemmän tarkkuuden esiasetus tai kuvan pienempi kopio jäljittyy nopeammin.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Kuva jäljitettiin kokoon {_1} × {_2} kuvapistettä pienennettynä koosta {_3} × {_4} (enintään {_5} megapikseliä).
@@ -5317,6 +5323,14 @@ mark-style Japanese Japanilainen
Full Justify Täysi tasaus
Minimum must not exceed Desired, nor Desired Maximum. Minimi ei saa ylittää haluttua arvoa eikä haluttu arvo maksimia.
Justification Tasaus
Add filters from the list above Lisää suodattimia yllä olevasta luettelosta
Add to Stack Lisää pinoon
Applied Filters Käytetyt suodattimet
Categories Luokat
Choose a filter Valitse suodatin
Effect Gallery Tehostegalleria
Filters Suodattimet
Select artwork to apply effects Valitse grafiikka, johon tehosteet otetaan
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them tiedoston muuttujia ja tietojoukkoja ei luettu (muuttujia: {variables}, tietojoukkoja: {data_sets}): Muuttujat-paneeli ei näytä niitä
# Select by Color (select.color)
Select by Color Valitse värin mukaan
@@ -5417,8 +5431,5 @@ swatch Bright Violet Kirkas violetti
Shift: Siirtymä:
Fresco… Fresko…
Fresco Fresko
# Artwork drag between document tabs.
Drop Artwork Pudota kuvitus
@msg {key} must be [x, y] with finite coordinates {key} on annettava muodossa [x, y] äärellisillä koordinaateilla
@msg ids must contain 1–10000 object ids ids-arvon on sisällettävä 1–10000 objektitunnusta
Effect Gallery… Tehostegalleria…
Effect Gallery Dialog Tehostegalleria-valintaikkuna
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -1069,6 +1069,11 @@
Fidelity: Fidélité :
Figure Space Espace numérique
Figure: Chiffres :
# Artwork drag between document tabs.
Drop Artwork Déposer l’illustration
@msg {key} must be [x, y] with finite coordinates {key} doit être [x, y] avec des coordonnées finies
@msg ids must contain 1–10000 object ids ids doit contenir de 1 à 10000 identifiants d’objets
File Fichier
File Dimensions Dimensions du fichier
File Format: Format de fichier :
@@ -5332,6 +5337,7 @@ theme Appearance Apparence
@msg Persistent libraries not found: {files} Bibliothèques persistantes introuvables : {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` n’est pas un panneau de bibliothèque (voir window.swatchLibrary)
@msg library panel `{given}` isn't open le panneau de bibliothèque `{given}` n’est pas ouvert
@msg library panel `{given}` isn't missing its library la bibliothèque du panneau de bibliothèque `{given}` ne manque pas
@msg too many library panels were opened in this session trop de panneaux de bibliothèque ont été ouverts dans cette session
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. L’image fait {_1} × {_2} pixels, plus de {LARGE_TRACE_SIDE} sur un côté : elle est vectorisée, mais plus lentement. Un paramètre prédéfini moins fidèle ou une copie plus petite de l’image se vectorise plus vite.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). L’image a été vectorisée à {_1} × {_2} pixels, réduite de {_3} × {_4} ({_5} mégapixels au plus).
@@ -5352,6 +5358,14 @@ theme Appearance Apparence
Full Justify Justification complète
Minimum must not exceed Desired, nor Desired Maximum. Le minimum ne doit pas dépasser la valeur optimale, ni la valeur optimale le maximum.
Justification Justification
Add filters from the list above Ajoutez des filtres à partir de la liste ci-dessus
Add to Stack Ajouter à la pile
Applied Filters Filtres appliqués
Categories Catégories
Choose a filter Choisir un filtre
Effect Gallery Galerie d'effets
Filters Filtres
Select artwork to apply effects Sélectionnez des éléments graphiques pour appliquer des effets
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them les variables et jeux de données du fichier n’ont pas été lus (variables : {variables}, jeux de données : {data_sets}) : le panneau Variables ne les affiche pas
# Select by Color (select.color)
Select by Color Sélectionner par couleur
@@ -5385,8 +5399,5 @@ theme Appearance Apparence
Shift: Décalage :
Fresco… Fresque…
Fresco Fresque
# Artwork drag between document tabs.
Drop Artwork Déposer l’illustration
@msg {key} must be [x, y] with finite coordinates {key} doit être [x, y] avec des coordonnées finies
@msg ids must contain 1–10000 object ids ids doit contenir de 1 à 10000 identifiants d’objets
Effect Gallery… Galerie d'effets…
Effect Gallery Dialog Boîte de dialogue Galerie d'effets
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -1355,6 +1355,11 @@
Fidelity: Pontosság:
Figure Space Számjegyszóköz
Figure: Számjegyek:
# Artwork drag between document tabs.
Drop Artwork Grafika elhelyezése
@msg {key} must be [x, y] with finite coordinates A(z) {key} értékének [x, y] alakúnak kell lennie véges koordinátákkal
@msg ids must contain 1–10000 object ids Az ids értékének 1–10000 objektumazonosítót kell tartalmaznia
File Fájl
File Dimensions Fájl méretei
File Format: Fájlformátum:
@@ -5319,6 +5324,7 @@ imageTrace Outline Körvonal
@msg Persistent libraries not found: {files} Nem találhatók állandó könyvtárak: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) A(z) `{given}` nem könyvtárpanel (lásd: window.swatchLibrary)
@msg library panel `{given}` isn't open a(z) `{given}` könyvtárpanel nincs megnyitva
@msg library panel `{given}` isn't missing its library a(z) `{given}` könyvtárpanel könyvtára nem hiányzik
@msg too many library panels were opened in this session ebben a munkamenetben túl sok könyvtárpanel nyílt meg
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. A kép {_1} × {_2} képpont, egyik oldalán több mint {LARGE_TRACE_SIDE}: a vektorizálás megtörténik, de lassabban. Kisebb hűségű előbeállítással vagy a kép kisebb másolatával gyorsabb.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). A kép vektorizálása {_1} × {_2} képponton történt, {_3} × {_4} méretről kicsinyítve (legfeljebb {_5} megapixel).
@@ -5339,6 +5345,14 @@ imageTrace Outline Körvonal
Full Justify Teljes sorkizárás
Minimum must not exceed Desired, nor Desired Maximum. A minimum nem haladhatja meg a kívánt értéket, sem a kívánt érték a maximumot.
Justification Sorkizárás
Add filters from the list above Adjon hozzá szűrőket a fenti listából
Add to Stack Hozzáadás a veremhez
Applied Filters Alkalmazott szűrők
Categories Kategóriák
Choose a filter Válasszon szűrőt
Effect Gallery Effektusgaléria
Filters Szűrők
Select artwork to apply effects Válasszon ki grafikát az effektusok alkalmazásához
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them a fájl változói és adatkészletei nem lettek beolvasva (változók: {variables}, adatkészletek: {data_sets}): a Változók panel nem listázza őket
# Select by Color (select.color)
Select by Color Kijelölés szín szerint
@@ -5372,8 +5386,5 @@ imageTrace Outline Körvonal
Shift: Eltolás:
Fresco… Freskó…
Fresco Freskó
# Artwork drag between document tabs.
Drop Artwork Grafika elhelyezése
@msg {key} must be [x, y] with finite coordinates A(z) {key} értékének [x, y] alakúnak kell lennie véges koordinátákkal
@msg ids must contain 1–10000 object ids Az ids értékének 1–10000 objektumazonosítót kell tartalmaznia
Effect Gallery… Effektusgaléria…
Effect Gallery Dialog Effektusgaléria párbeszédpanel
Can't render this file because it contains an unexpected character in line 2 and column 73.
+15 -5
View File
@@ -20,6 +20,11 @@
Medium Light Agak terang
Light Terang
Quit VectorCraft Keluar dari VectorCraft
# Artwork drag between document tabs.
Drop Artwork Letakkan karya
@msg {key} must be [x, y] with finite coordinates {key} harus berupa [x, y] dengan koordinat berhingga
@msg ids must contain 1–10000 object ids ids harus berisi 1–10000 ID objek
File Berkas
New… Baru…
New Without Dialog Baru tanpa dialog
@@ -5306,6 +5311,14 @@ swatch Bright Violet Violet cerah
Full Justify Rata Penuh
Minimum must not exceed Desired, nor Desired Maximum. Minimum tidak boleh melebihi Diinginkan, dan Diinginkan tidak boleh melebihi Maksimum.
Justification Justifikasi
Add filters from the list above Tambahkan filter dari daftar di atas
Add to Stack Tambahkan ke Tumpukan
Applied Filters Filter yang Diterapkan
Categories Kategori
Choose a filter Pilih filter
Effect Gallery Galeri Efek
Filters Filter
Select artwork to apply effects Pilih grafis untuk menerapkan efek
# Select by Color (select.color)
Select by Color Pilih berdasarkan warna
Smudge Stick… Tongkat olesan…
@@ -5359,8 +5372,5 @@ swatch Bright Violet Violet cerah
Shift: Pergeseran:
Fresco… Fresko…
Fresco Fresko
# Artwork drag between document tabs.
Drop Artwork Letakkan karya
@msg {key} must be [x, y] with finite coordinates {key} harus berupa [x, y] dengan koordinat berhingga
@msg ids must contain 1–10000 object ids ids harus berisi 1–10000 ID objek
Effect Gallery… Galeri Efek…
Effect Gallery Dialog Dialog Galeri Efek
Can't render this file because it contains an unexpected character in line 3816 and column 19.
+16 -5
View File
@@ -1069,6 +1069,11 @@
Fidelity: Fedeltà:
Figure Space Spazio cifra
Figure: Cifre:
# Artwork drag between document tabs.
Drop Artwork Rilascia illustrazione
@msg {key} must be [x, y] with finite coordinates {key} deve essere [x, y] con coordinate finite
@msg ids must contain 1–10000 object ids ids deve contenere da 1 a 10000 identificatori di oggetti
File File
File Dimensions Dimensioni file
File Format: Formato file:
@@ -4947,6 +4952,7 @@ lighting Light Luce
@msg Persistent libraries not found: {files} Librerie persistenti non trovate: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` non è un pannello libreria (vedi window.swatchLibrary)
@msg library panel `{given}` isn't open il pannello libreria `{given}` non è aperto
@msg library panel `{given}` isn't missing its library la libreria del pannello libreria `{given}` non è mancante
@msg too many library panels were opened in this session in questa sessione sono stati aperti troppi pannelli libreria
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. L’immagine è di {_1} × {_2} pixel, più di {LARGE_TRACE_SIDE} su un lato: viene vettorializzata, ma più lentamente. Un predefinito a fedeltà più bassa o una copia più piccola dell’immagine è più veloce.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). L’immagine è stata vettorializzata a {_1} × {_2} pixel, ridotta da {_3} × {_4} (al massimo {_5} megapixel).
@@ -4968,6 +4974,14 @@ lighting Light Luce
Minimum must not exceed Desired, nor Desired Maximum. Il minimo non può superare il valore desiderato, né il desiderato il massimo.
Minimum Minimo
Justification Giustificazione
Add filters from the list above Aggiungi filtri dall'elenco sopra
Add to Stack Aggiungi alla pila
Applied Filters Filtri applicati
Categories Categorie
Choose a filter Scegli un filtro
Effect Gallery Galleria effetti
Filters Filtri
Select artwork to apply effects Seleziona la grafica a cui applicare gli effetti
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them le variabili e i set di dati del file non sono stati letti (variabili: {variables}, set di dati: {data_sets}): il pannello Variabili non li elenca
# Select by Color (select.color)
Select by Color Seleziona per colore
@@ -5001,8 +5015,5 @@ lighting Light Luce
Shift: Spostamento:
Fresco… Affresco…
Fresco Affresco
# Artwork drag between document tabs.
Drop Artwork Rilascia illustrazione
@msg {key} must be [x, y] with finite coordinates {key} deve essere [x, y] con coordinate finite
@msg ids must contain 1–10000 object ids ids deve contenere da 1 a 10000 identificatori di oggetti
Effect Gallery… Galleria effetti…
Effect Gallery Dialog Finestra di dialogo Galleria effetti
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -75,6 +75,11 @@
Medium Light やや明るい
Light 明るい
Quit VectorCraft VectorCraft を終了
# Artwork drag between document tabs.
Drop Artwork アートワークをドロップ
@msg {key} must be [x, y] with finite coordinates {key} は有限の座標を持つ [x, y] である必要があります
@msg ids must contain 1–10000 object ids ids には 1~10000 個のオブジェクト ID を指定してください
File ファイル
New… 新規…
New Without Dialog ダイアログなしで新規
@@ -4987,6 +4992,7 @@ lighting Light ライト
@msg Persistent libraries not found: {files} 永続ライブラリが見つかりません: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` はライブラリパネルではありません (window.swatchLibrary を参照)
@msg library panel `{given}` isn't open ライブラリパネル `{given}` は開いていません
@msg library panel `{given}` isn't missing its library ライブラリパネル `{given}` のライブラリは欠落していません
@msg too many library panels were opened in this session このセッションで開いたライブラリパネルが多すぎます
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. 画像は {_1} × {_2} ピクセルで、一辺が {LARGE_TRACE_SIDE} を超えています。トレースはできますが、時間がかかります。忠実度の低いプリセットや画像の小さいコピーを使うと速くなります。
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). 画像は {_3} × {_4} から縮小した {_1} × {_2} ピクセルでトレースされました (最大 {_5} メガピクセル)。
@@ -5008,6 +5014,14 @@ lighting Light ライト
Minimum must not exceed Desired, nor Desired Maximum. 最小値は最適値を、最適値は最大値を超えることはできません。
Minimum 最小
Justification 文字組み
Add filters from the list above 上のリストからフィルターを追加
Add to Stack スタックに追加
Applied Filters 適用したフィルター
Categories カテゴリ
Choose a filter フィルターを選択
Effect Gallery 効果ギャラリー
Filters フィルター
Select artwork to apply effects 効果を適用するグラフィックを選択してください
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them ファイルの変数とデータセットは読み込まれませんでした (変数: {variables}、データセット: {data_sets})。変数パネルには表示されません
# Select by Color (select.color)
Select by Color カラーで選択
@@ -5048,8 +5062,5 @@ lighting Light ライト
Shift: シフト:
Fresco… フレスコ…
Fresco フレスコ
# Artwork drag between document tabs.
Drop Artwork アートワークをドロップ
@msg {key} must be [x, y] with finite coordinates {key} は有限の座標を持つ [x, y] である必要があります
@msg ids must contain 1–10000 object ids ids には 1~10000 個のオブジェクト ID を指定してください
Effect Gallery… 効果ギャラリー…
Effect Gallery Dialog 効果ギャラリーダイアログ
Can't render this file because it contains an unexpected character in line 2 and column 73.
+15 -5
View File
@@ -27,6 +27,11 @@
Medium Light საშუალოდ ღია
Light ღია
Quit VectorCraft VectorCraft-იდან გასვლა
# Artwork drag between document tabs.
Drop Artwork ნამუშევრის განთავსება
@msg {key} must be [x, y] with finite coordinates {key} უნდა იყოს [x, y] სასრული კოორდინატებით
@msg ids must contain 1–10000 object ids ids უნდა შეიცავდეს 1–10000 ობიექტის იდენტიფიკატორს
File ფაილი
New… ახალი…
New Without Dialog ახალი დიალოგის გარეშე
@@ -5191,6 +5196,7 @@ imageTrace Outline კონტური
@msg handle must be in or out handle უნდა იყოს in ან out
@msg index must be ≥ 0 index უნდა იყოს ≥ 0
@msg library panel `{given}` isn't open ბიბლიოთეკის პანელი `{given}` გახსნილი არ არის
@msg library panel `{given}` isn't missing its library ბიბლიოთეკის პანელს `{given}` ბიბლიოთეკა არ აკლია
@msg mask art ends outside a mask dictionary ნიღბის ნახატი ნიღბის ლექსიკონის გარეთ მთავრდება
@msg missing number `{key}` აკლია რიცხვი `{key}`
@msg missing integer `{key}` აკლია მთელი რიცხვი `{key}`
@@ -5296,8 +5302,12 @@ imageTrace Outline კონტური
Shift: წანაცვლება:
Fresco… ფრესკა…
Fresco ფრესკა
# Artwork drag between document tabs.
Drop Artwork ნამუშევრის განთავსება
@msg {key} must be [x, y] with finite coordinates {key} უნდა იყოს [x, y] სასრული კოორდინატებით
@msg ids must contain 1–10000 object ids ids უნდა შეიცავდეს 1–10000 ობიექტის იდენტიფიკატორს
Effect Gallery ეფექტების გალერეა
Add filters from the list above დაამატეთ ფილტრები ზემოთ მოცემული სიიდან
Add to Stack დასტაში დამატება
Applied Filters გამოყენებული ფილტრები
Categories კატეგორიები
Filters ფილტრები
Select artwork to apply effects აირჩიეთ ნამუშევარი ეფექტების გამოსაყენებლად
Effect Gallery… ეფექტების გალერეა…
Effect Gallery Dialog ეფექტების გალერეა დიალოგი
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -71,6 +71,11 @@
Medium Light 약간 밝게
Light 밝게
Quit VectorCraft VectorCraft 종료
# Artwork drag between document tabs.
Drop Artwork 아트워크 놓기
@msg {key} must be [x, y] with finite coordinates {key}은(는) 유한한 좌표의 [x, y]여야 합니다
@msg ids must contain 1–10000 object ids ids에는 1~10000개의 오브젝트 ID가 있어야 합니다
File 파일
New… 새로 만들기…
New Without Dialog 대화상자 없이 새로 만들기
@@ -4910,6 +4915,7 @@ lighting Light 광원
@msg Persistent libraries not found: {files} 지속 라이브러리를 찾을 수 없습니다: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}`은(는) 라이브러리 패널이 아닙니다(window.swatchLibrary 참조)
@msg library panel `{given}` isn't open 라이브러리 패널 `{given}`이(가) 열려 있지 않습니다
@msg library panel `{given}` isn't missing its library 라이브러리 패널 `{given}`의 라이브러리가 누락되지 않았습니다
@msg too many library panels were opened in this session 이 세션에서 라이브러리 패널을 너무 많이 열었습니다
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. 이미지가 {_1} × {_2}픽셀로 한 변이 {LARGE_TRACE_SIDE}을 넘습니다. 추적은 되지만 더 느립니다. 충실도가 낮은 사전 설정이나 이미지의 작은 사본을 사용하면 더 빠릅니다.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). 이미지를 {_3} × {_4}에서 축소한 {_1} × {_2}픽셀로 추적했습니다(최대 {_5}메가픽셀).
@@ -4931,6 +4937,14 @@ lighting Light 광원
Minimum must not exceed Desired, nor Desired Maximum. 최소값은 희망값을, 희망값은 최대값을 넘을 수 없습니다.
Minimum 최소
Justification 양끝 맞춤
Add filters from the list above 위 목록에서 필터 추가
Add to Stack 스택에 추가
Applied Filters 적용된 필터
Categories 범주
Choose a filter 필터 선택
Effect Gallery 효과 갤러리
Filters 필터
Select artwork to apply effects 효과를 적용할 그래픽을 선택하세요
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them 파일의 변수와 데이터 세트를 읽지 않았습니다(변수: {variables}, 데이터 세트: {data_sets}). 변수 패널에 표시되지 않습니다
# Select by Color (select.color)
Select by Color 색상별 선택
@@ -4964,8 +4978,5 @@ lighting Light 광원
Shift: 이동:
Fresco… 프레스코…
Fresco 프레스코
# Artwork drag between document tabs.
Drop Artwork 아트워크 놓기
@msg {key} must be [x, y] with finite coordinates {key}은(는) 유한한 좌표의 [x, y]여야 합니다
@msg ids must contain 1–10000 object ids ids에는 1~10000개의 오브젝트 ID가 있어야 합니다
Effect Gallery… 효과 갤러리…
Effect Gallery Dialog 효과 갤러리 대화 상자
Can't render this file because it contains an unexpected character in line 2 and column 73.
+5 -1
View File
@@ -94,7 +94,7 @@ fn plural_polish(n: u64) -> usize {
}
/// The registry. English first: it is the fallback and the source language.
pub static LANGUAGES: [LangInfo; 24] = [
pub static LANGUAGES: [LangInfo; 25] = [
LangInfo { code: "en", name: "English", source: "", plural: plural_one_other, complete_menus: false, catalog: OnceLock::new() },
// Greek: the whole interface and the status and error messages, keeping the same names in
// English as Spanish; every `el-*` locale (including `el-GR` and `el-CY`) resolves here.
@@ -263,6 +263,10 @@ pub static LANGUAGES: [LangInfo; 24] = [
// English as Spanish; one/other plurals with the partitive after any number but 1 ("2 tasoa").
// Every `fi-*` locale resolves here.
LangInfo { code: "fi", name: "Suomi", source: include_str!("fi.tsv"), plural: plural_one_other, complete_menus: true, catalog: OnceLock::new() },
// Turkish: the whole interface and the status and error messages, keeping the same names in
// English as Spanish; a count takes the singular ("3 katman"), so plurals have one form. Every
// `tr-*` locale (including `tr-TR` and `tr-CY`) resolves here.
LangInfo { code: "tr", name: "Türkçe", source: include_str!("tr.tsv"), plural: plural_none, complete_menus: true, catalog: OnceLock::new() },
];
impl LangInfo {
+16 -5
View File
@@ -20,6 +20,11 @@
Medium Light Gemiddeld licht
Light Licht
Quit VectorCraft VectorCraft afsluiten
# Artwork drag between document tabs.
Drop Artwork Illustratie neerzetten
@msg {key} must be [x, y] with finite coordinates {key} moet [x, y] met eindige coördinaten zijn
@msg ids must contain 1–10000 object ids ids moet 1–10000 object-id’s bevatten
File Bestand
New… Nieuw…
New Without Dialog Nieuw zonder dialoogvenster
@@ -5329,6 +5334,7 @@ swatch Bright Violet Felviolet
@msg Persistent libraries not found: {files} Permanente bibliotheken niet gevonden: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` is geen bibliotheekpaneel (zie window.swatchLibrary)
@msg library panel `{given}` isn't open bibliotheekpaneel `{given}` is niet geopend
@msg library panel `{given}` isn't missing its library de bibliotheek van bibliotheekpaneel `{given}` ontbreekt niet
@msg too many library panels were opened in this session er zijn in deze sessie te veel bibliotheekpanelen geopend
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. De afbeelding is {_1} × {_2} pixels, meer dan {LARGE_TRACE_SIDE} aan één zijde: ze wordt getraceerd, maar langzamer. Een voorinstelling met minder detail of een kleinere kopie van de afbeelding traceert sneller.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). De afbeelding is getraceerd op {_1} × {_2} pixels, verkleind van {_3} × {_4} (maximaal {_5} megapixels).
@@ -5348,6 +5354,14 @@ swatch Bright Violet Felviolet
Full Justify Volledig uitvullen
Minimum must not exceed Desired, nor Desired Maximum. Minimum mag niet groter zijn dan Gewenst, en Gewenst niet groter dan Maximum.
Justification Uitvullen
Add filters from the list above Voeg filters toe uit de lijst hierboven
Add to Stack Toevoegen aan stapel
Applied Filters Toegepaste filters
Categories Categorieën
Choose a filter Kies een filter
Effect Gallery Effectgalerij
Filters Filters
Select artwork to apply effects Selecteer grafiek om effecten toe te passen
# Select by Color (select.color)
Select by Color Selecteren op kleur
Smudge Stick… Uitsmeerstift…
@@ -5401,8 +5415,5 @@ swatch Bright Violet Felviolet
Shift: Verschuiving:
Fresco… Fresco…
Fresco Fresco
# Artwork drag between document tabs.
Drop Artwork Illustratie neerzetten
@msg {key} must be [x, y] with finite coordinates {key} moet [x, y] met eindige coördinaten zijn
@msg ids must contain 1–10000 object ids ids moet 1–10000 object-id’s bevatten
Effect Gallery… Effectgalerij…
Effect Gallery Dialog Dialoogvenster Effectgalerij
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -38,6 +38,11 @@
Medium Light Średnio jasny
Light Jasny
Quit VectorCraft Zakończ VectorCraft
# Artwork drag between document tabs.
Drop Artwork Upuść kompozycję
@msg {key} must be [x, y] with finite coordinates {key} musi mieć postać [x, y] ze skończonymi współrzędnymi
@msg ids must contain 1–10000 object ids ids musi zawierać od 1 do 10000 identyfikatorów obiektów
File Plik
New… Nowy…
New Without Dialog Nowy bez okna dialogowego
@@ -5185,6 +5190,7 @@ mark-style Japanese Japońskie
@msg Persistent libraries not found: {files} Nie znaleziono trwałych bibliotek: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` nie jest panelem biblioteki (zobacz window.swatchLibrary)
@msg library panel `{given}` isn't open panel biblioteki `{given}` nie jest otwarty
@msg library panel `{given}` isn't missing its library panelowi biblioteki `{given}` nie brakuje biblioteki
@msg too many library panels were opened in this session w tej sesji otwarto zbyt wiele paneli bibliotek
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Obraz ma {_1} × {_2} pikseli, ponad {LARGE_TRACE_SIDE} na jednym boku: zostanie obrysowany, ale wolniej. Ustawienie wstępne o niższej wierności lub mniejsza kopia obrazu obrysuje się szybciej.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Obraz obrysowano w rozdzielczości {_1} × {_2} pikseli, po zmniejszeniu z {_3} × {_4} (najwyżej {_5} megapikseli).
@@ -5205,6 +5211,14 @@ mark-style Japanese Japońskie
Full Justify Pełne justowanie
Minimum must not exceed Desired, nor Desired Maximum. Minimum nie może przekraczać wartości optymalnej, a wartość optymalna maksimum.
Justification Justowanie
Add filters from the list above Dodaj filtry z listy powyżej
Add to Stack Dodaj do stosu
Applied Filters Zastosowane filtry
Categories Kategorie
Choose a filter Wybierz filtr
Effect Gallery Galeria efektów
Filters Filtry
Select artwork to apply effects Wybierz grafikę, aby zastosować efekty
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them zmienne i zestawy danych pliku nie zostały wczytane (zmienne: {variables}, zestawy danych: {data_sets}): panel Zmienne ich nie wyświetla
# Select by Color (select.color)
Select by Color Zaznacz według koloru
@@ -5238,8 +5252,5 @@ mark-style Japanese Japońskie
Shift: Przesunięcie:
Fresco… Fresk…
Fresco Fresk
# Artwork drag between document tabs.
Drop Artwork Upuść kompozycję
@msg {key} must be [x, y] with finite coordinates {key} musi mieć postać [x, y] ze skończonymi współrzędnymi
@msg ids must contain 1–10000 object ids ids musi zawierać od 1 do 10000 identyfikatorów obiektów
Effect Gallery… Galeria efektów…
Effect Gallery Dialog Okno dialogowe Galeria efektów
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -947,6 +947,11 @@
Fidelity: Fidelidade:
Figure Space Espaço de Figura
Figure: Figura:
# Artwork drag between document tabs.
Drop Artwork Soltar arte
@msg {key} must be [x, y] with finite coordinates {key} deve ser [x, y] com coordenadas finitas
@msg ids must contain 1–10000 object ids ids deve conter de 1 a 10000 IDs de objetos
File Arquivo
File Format: Formato do Arquivo:
File Formats Formatos de Arquivo
@@ -5250,6 +5255,7 @@ mark-style Japanese Japonesas
@msg Persistent libraries not found: {files} Bibliotecas persistentes não encontradas: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` não é um painel de biblioteca (consulte window.swatchLibrary)
@msg library panel `{given}` isn't open o painel de biblioteca `{given}` não está aberto
@msg library panel `{given}` isn't missing its library a biblioteca do painel de biblioteca `{given}` não está faltando
@msg too many library panels were opened in this session foram abertos painéis de biblioteca demais nesta sessão
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. A imagem tem {_1} × {_2} pixels, mais de {LARGE_TRACE_SIDE} em um lado: ela é traçada, mas mais devagar. Uma predefinição de menor fidelidade ou uma cópia menor da imagem traça mais rápido.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). A imagem foi traçada em {_1} × {_2} pixels, reduzida de {_3} × {_4} (no máximo {_5} megapixels).
@@ -5270,6 +5276,14 @@ mark-style Japanese Japonesas
Full Justify Justificação Completa
Minimum must not exceed Desired, nor Desired Maximum. O mínimo não pode passar do desejado, nem o desejado do máximo.
Justification Justificação
Add filters from the list above Adicione filtros da lista acima
Add to Stack Adicionar à Pilha
Applied Filters Filtros Aplicados
Categories Categorias
Choose a filter Escolha um filtro
Effect Gallery Galeria de Efeitos
Filters Filtros
Select artwork to apply effects Selecione a arte para aplicar efeitos
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them as variáveis e os conjuntos de dados do arquivo não foram lidos (variáveis: {variables}, conjuntos de dados: {data_sets}): o painel Variáveis não os lista
# Select by Color (select.color)
Select by Color Selecionar por Cor
@@ -5303,8 +5317,5 @@ mark-style Japanese Japonesas
Shift: Deslocamento:
Fresco… Afresco…
Fresco Afresco
# Artwork drag between document tabs.
Drop Artwork Soltar arte
@msg {key} must be [x, y] with finite coordinates {key} deve ser [x, y] com coordenadas finitas
@msg ids must contain 1–10000 object ids ids deve conter de 1 a 10000 IDs de objetos
Effect Gallery… Galeria de Efeitos…
Effect Gallery Dialog Caixa de diálogo Galeria de Efeitos
Can't render this file because it contains an unexpected character in line 6 and column 47.
+16 -5
View File
@@ -1067,6 +1067,11 @@
Fidelity: Точность:
Figure Space Цифровая шпация
Figure: Цифры:
# Artwork drag between document tabs.
Drop Artwork Поместить графику
@msg {key} must be [x, y] with finite coordinates {key} должен быть [x, y] с конечными координатами
@msg ids must contain 1–10000 object ids ids должен содержать от 1 до 10000 идентификаторов объектов
File Файл
File Dimensions Размеры файла
File Format: Формат файла:
@@ -4943,6 +4948,7 @@ lighting Light Свет
@msg Persistent libraries not found: {files} Постоянные библиотеки не найдены: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` — не панель библиотеки (см. window.swatchLibrary)
@msg library panel `{given}` isn't open панель библиотеки `{given}` не открыта
@msg library panel `{given}` isn't missing its library библиотека панели библиотеки `{given}` не отсутствует
@msg too many library panels were opened in this session в этом сеансе открыто слишком много панелей библиотек
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Изображение {_1} × {_2} пикселей, больше {LARGE_TRACE_SIDE} по одной стороне: трассировка выполняется, но медленнее. Стиль с меньшей точностью или уменьшенная копия изображения трассируются быстрее.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Изображение трассировано в размере {_1} × {_2} пикселей, уменьшенное с {_3} × {_4} (не более {_5} мегапикселей).
@@ -4964,6 +4970,14 @@ lighting Light Свет
Minimum must not exceed Desired, nor Desired Maximum. Минимум не может превышать желательное значение, а желательное — максимум.
Minimum Минимум
Justification Выключка
Add filters from the list above Добавьте фильтры из списка выше
Add to Stack Добавить в стек
Applied Filters Применённые фильтры
Categories Категории
Choose a filter Выберите фильтр
Effect Gallery Галерея эффектов
Filters Фильтры
Select artwork to apply effects Выберите графику, чтобы применить эффекты
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them переменные и наборы данных файла не прочитаны (переменных: {variables}, наборов данных: {data_sets}): панель «Переменные» их не показывает
# Select by Color (select.color)
Select by Color Выделить по цвету
@@ -4997,8 +5011,5 @@ lighting Light Свет
Shift: Сдвиг:
Fresco… Фреска…
Fresco Фреска
# Artwork drag between document tabs.
Drop Artwork Поместить графику
@msg {key} must be [x, y] with finite coordinates {key} должен быть [x, y] с конечными координатами
@msg ids must contain 1–10000 object ids ids должен содержать от 1 до 10000 идентификаторов объектов
Effect Gallery… Галерея эффектов…
Effect Gallery Dialog Диалог «Галерея эффектов»
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -1051,6 +1051,11 @@
Fidelity: Återgivning:
Figure Space Siffermellanrum
Figure: Figur:
# Artwork drag between document tabs.
Drop Artwork Släpp grafik
@msg {key} must be [x, y] with finite coordinates {key} måste vara [x, y] med ändliga koordinater
@msg ids must contain 1–10000 object ids ids måste innehålla 1–10000 objekt-id:n
File Fil
File Dimensions Fildimensioner
File Format: Filformat:
@@ -5289,6 +5294,7 @@ theme Appearance Utseende
@msg Persistent libraries not found: {files} Beständiga bibliotek hittades inte: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` är inte en bibliotekspanel (se window.swatchLibrary)
@msg library panel `{given}` isn't open bibliotekspanelen `{given}` är inte öppen
@msg library panel `{given}` isn't missing its library bibliotekspanelen `{given}` saknar inte sitt bibliotek
@msg too many library panels were opened in this session för många bibliotekspaneler har öppnats i den här sessionen
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Bilden är {_1} × {_2} pixlar, mer än {LARGE_TRACE_SIDE} på en sida: den vektoriseras, men långsammare. En förinställning med lägre återgivning eller en mindre kopia av bilden går snabbare.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Bilden vektoriserades vid {_1} × {_2} pixlar, nedskalad från {_3} × {_4} (högst {_5} megapixlar).
@@ -5309,6 +5315,14 @@ theme Appearance Utseende
Full Justify Fullständig marginaljustering
Minimum must not exceed Desired, nor Desired Maximum. Minimum får inte överstiga Önskat, och Önskat inte Maximum.
Justification Justering
Add filters from the list above Lägg till filter från listan ovan
Add to Stack Lägg till i stacken
Applied Filters Tillämpade filter
Categories Kategorier
Choose a filter Välj ett filter
Effect Gallery Effektgalleri
Filters Filter
Select artwork to apply effects Välj grafik för att tillämpa effekter
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them filens variabler och datauppsättningar lästes inte (variabler: {variables}, datauppsättningar: {data_sets}): panelen Variabler visar dem inte
# Select by Color (select.color)
Select by Color Markera efter färg
@@ -5342,8 +5356,5 @@ theme Appearance Utseende
Shift: Förskjutning:
Fresco… Fresk…
Fresco Fresk
# Artwork drag between document tabs.
Drop Artwork Släpp grafik
@msg {key} must be [x, y] with finite coordinates {key} måste vara [x, y] med ändliga koordinater
@msg ids must contain 1–10000 object ids ids måste innehålla 1–10000 objekt-id:n
Effect Gallery… Effektgalleri…
Effect Gallery Dialog Dialogrutan Effektgalleri
Can't render this file because it contains an unexpected character in line 5 and column 25.
+37 -2
View File
@@ -870,7 +870,7 @@ fn cs() -> Lang {
}
/// Languages whose catalogs leave [`MENU_KEEP_AS_IS`] in English.
const KEEPS_MENU_NAMES: [&str; 17] = ["cs", "de", "el", "es", "fr", "hu", "it", "ja", "ka", "ko", "pl", "pt-br", "ru", "sv", "uk", "vi", "fi"];
const KEEPS_MENU_NAMES: [&str; 18] = ["cs", "de", "el", "es", "fr", "hu", "it", "ja", "ka", "ko", "pl", "pt-br", "ru", "sv", "uk", "vi", "fi", "tr"];
/// Menu labels the menu-complete catalogs (Czech, German, Spanish, Italian, Japanese, Brazilian Portuguese) show as they are: the product name, a format name, the built-in workspace
/// names and the perspective grid presets (names, shown untranslated wherever else they appear).
@@ -1190,6 +1190,41 @@ fn finnish_reads_as_finnish() {
assert_eq!(message(fi(), nested), "komento `object.group` ei ole nyt käytettävissä: mitään ei ole valittu");
}
/// The Turkish catalog registers under `tr`, claims complete menus and messages, and passes
/// locale resolution, vocabulary and count formatting checks.
#[test]
fn turkish_reads_as_turkish() {
assert_eq!(tr_lang().name(), "Türkçe");
assert!(tr_lang().complete_menus());
assert_eq!(Lang::from_pref("tr"), tr_lang());
assert_eq!(Lang::from_pref("TR"), tr_lang());
for tag in ["tr", "tr-TR", "tr_TR.UTF-8", "TR-tr", "tr-CY"] {
assert_eq!(lang_from_tag(tag), Some(tr_lang()), "{tag}");
}
for (en, want) in [
("Artboard Tool", "Çalışma Yüzeyi Aracı"),
("Swatches", "Renk Örnekleri"),
("Stroke", "Kontur"),
("Fill", "Dolgu"),
("Direct Selection Tool", "Doğrudan Seçim Aracı"),
("Save As…", "Farklı Kaydet…"),
("Undo", "Geri Al"),
("Close", "Kapat"),
] {
assert_eq!(tr(tr_lang(), en), want);
}
for n in [0, 1, 3, 21] {
assert_eq!(trn(tr_lang(), n, "{n} Layer", "{n} Layers"), format!("{n} Katman"));
}
let nested = "command `object.group` is not available right now: nothing selected";
assert_eq!(message(tr_lang(), nested), "`object.group` komutu şu anda kullanılamıyor: hiçbir şey seçilmedi");
}
/// The [`Lang`] handle for the Turkish catalog.
fn tr_lang() -> Lang {
Lang::from_code("tr").expect("tr registered")
}
/// Ambiguous English terms keep their intended Vietnamese meaning across UI contexts.
#[test]
fn vietnamese_domain_terms_are_consistent() {
@@ -2104,7 +2139,7 @@ fn shared_param_check_errors_are_translated() {
/// Languages whose catalogs cover every status and error message.
const COMPLETE_MESSAGES: &[&str] =
&["cs", "de", "el", "es", "fr", "hu", "it", "ja", "ka", "ko", "pl", "pt-br", "ru", "sv", "uk", "vi", "zh-hans", "zh-hant", "fi"];
&["cs", "de", "el", "es", "fr", "hu", "it", "ja", "ka", "ko", "pl", "pt-br", "ru", "sv", "uk", "vi", "zh-hans", "zh-hant", "fi", "tr"];
/// Crates whose error and status messages reach the status bar.
const MESSAGE_CRATES: &[&str] = &["ui-egui", "engine", "doc", "format", "svg", "pdf", "eps", "text", "plugins", "metafile", "cad", "trace"];
File diff suppressed because it is too large Load Diff
+16 -5
View File
@@ -1063,6 +1063,11 @@
Fidelity: Точність:
Figure Space Цифрова шпація
Figure: Цифри:
# Artwork drag between document tabs.
Drop Artwork Розмістити графіку
@msg {key} must be [x, y] with finite coordinates {key} має бути [x, y] зі скінченними координатами
@msg ids must contain 1–10000 object ids ids має містити від 1 до 10000 ідентифікаторів об’єктів
File Файл
File Dimensions Розміри файлу
File Format: Формат файлу:
@@ -4927,6 +4932,7 @@ lighting Light Світло
@msg Persistent libraries not found: {files} Постійні бібліотеки не знайдено: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` — не панель бібліотеки (див. window.swatchLibrary)
@msg library panel `{given}` isn't open панель бібліотеки `{given}` не відкрита
@msg library panel `{given}` isn't missing its library бібліотека панелі бібліотеки `{given}` не відсутня
@msg too many library panels were opened in this session у цьому сеансі відкрито забагато панелей бібліотек
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Зображення {_1} × {_2} пікселів, понад {LARGE_TRACE_SIDE} з одного боку: трасування виконується, але повільніше. Стиль із нижчою точністю або менша копія зображення трасуються швидше.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Зображення трасовано в розмірі {_1} × {_2} пікселів, зменшене з {_3} × {_4} (щонайбільше {_5} мегапікселів).
@@ -4948,6 +4954,14 @@ lighting Light Світло
Minimum must not exceed Desired, nor Desired Maximum. Мінімум не може перевищувати бажане значення, а бажане — максимум.
Minimum Мінімум
Justification Вирівнювання за шириною
Add filters from the list above Додайте фільтри зі списку вище
Add to Stack Додати до стека
Applied Filters Застосовані фільтри
Categories Категорії
Choose a filter Виберіть фільтр
Effect Gallery Галерея ефектів
Filters Фільтри
Select artwork to apply effects Виберіть графіку, щоб застосувати ефекти
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them змінні та набори даних файлу не прочитано (змінних: {variables}, наборів даних: {data_sets}): панель «Змінні» їх не показує
# Select by Color (select.color)
Select by Color Виділити за кольором
@@ -4981,8 +4995,5 @@ lighting Light Світло
Shift: Зсув:
Fresco… Фреска…
Fresco Фреска
# Artwork drag between document tabs.
Drop Artwork Розмістити графіку
@msg {key} must be [x, y] with finite coordinates {key} має бути [x, y] зі скінченними координатами
@msg ids must contain 1–10000 object ids ids має містити від 1 до 10000 ідентифікаторів об’єктів
Effect Gallery… Галерея ефектів…
Effect Gallery Dialog Діалог «Галерея ефектів»
Can't render this file because it contains an unexpected character in line 733 and column 40.
+16 -5
View File
@@ -1232,6 +1232,11 @@
Fidelity: Độ trung thực:
Figure Space Khoảng trắng chữ số
Figure: Chữ số:
# Artwork drag between document tabs.
Drop Artwork Thả hình đồ họa
@msg {key} must be [x, y] with finite coordinates {key} phải là [x, y] với tọa độ hữu hạn
@msg ids must contain 1–10000 object ids ids phải chứa từ 1 đến 10000 mã định danh đối tượng
File Tệp
File Dimensions Kích thước tệp
File Format: Định dạng tệp:
@@ -4927,6 +4932,7 @@ theme Appearance Giao diện
@msg Persistent libraries not found: {files} Không tìm thấy thư viện lưu giữ: {files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` không phải là bảng thư viện (xem window.swatchLibrary)
@msg library panel `{given}` isn't open bảng thư viện `{given}` chưa được mở
@msg library panel `{given}` isn't missing its library thư viện của bảng thư viện `{given}` không bị thiếu
@msg too many library panels were opened in this session đã mở quá nhiều bảng thư viện trong phiên này
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Ảnh có kích thước {_1} × {_2} điểm ảnh, hơn {LARGE_TRACE_SIDE} ở một cạnh: ảnh vẫn được dò, nhưng chậm hơn. Một thiết lập sẵn có độ trung thực thấp hơn hoặc một bản sao nhỏ hơn của ảnh sẽ dò nhanh hơn.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Ảnh đã được dò ở {_1} × {_2} điểm ảnh, thu nhỏ từ {_3} × {_4} (tối đa {_5} megapixel).
@@ -4948,6 +4954,14 @@ theme Appearance Giao diện
Minimum must not exceed Desired, nor Desired Maximum. Giá trị tối thiểu không được vượt quá giá trị mong muốn, và giá trị mong muốn không được vượt quá tối đa.
Minimum Tối thiểu
Justification Căn đều
Add filters from the list above Thêm bộ lọc từ danh sách phía trên
Add to Stack Thêm vào ngăn xếp
Applied Filters Bộ lọc đã áp dụng
Categories Danh mục
Choose a filter Chọn bộ lọc
Effect Gallery Thư viện hiệu ứng
Filters Bộ lọc
Select artwork to apply effects Chọn đồ họa để áp dụng hiệu ứng
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them các biến và tập dữ liệu của tệp chưa được đọc (biến: {variables}, tập dữ liệu: {data_sets}): bảng Biến không liệt kê chúng
# Select by Color (select.color)
Select by Color Chọn theo màu
@@ -4981,8 +4995,5 @@ theme Appearance Giao diện
Shift: Dịch chuyển:
Fresco… Bích họa…
Fresco Bích họa
# Artwork drag between document tabs.
Drop Artwork Thả hình đồ họa
@msg {key} must be [x, y] with finite coordinates {key} phải là [x, y] với tọa độ hữu hạn
@msg ids must contain 1–10000 object ids ids phải chứa từ 1 đến 10000 mã định danh đối tượng
Effect Gallery… Thư viện hiệu ứng…
Effect Gallery Dialog Hộp thoại Thư viện hiệu ứng
Can't render this file because it contains an unexpected character in line 4028 and column 10.
+16 -5
View File
@@ -1010,6 +1010,11 @@
Fidelity: 精确度:
Figure Space 数字空格
Figure: 数字:
# Artwork drag between document tabs.
Drop Artwork 放置图稿
@msg {key} must be [x, y] with finite coordinates {key} 必须是具有有限坐标的 [x, y]
@msg ids must contain 1–10000 object ids ids 必须包含 1–10000 个对象 ID
File 文件
File Dimensions 文件尺寸
File Format: 文件格式:
@@ -5166,6 +5171,7 @@ lighting Light 光源
@msg Persistent libraries not found: {files} 找不到持久库:{files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` 不是库面板 (请参阅 window.swatchLibrary)
@msg library panel `{given}` isn't open 库面板 `{given}` 未打开
@msg library panel `{given}` isn't missing its library 库面板 `{given}` 的库未缺失
@msg too many library panels were opened in this session 本次会话中打开的库面板过多
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. 图像为 {_1} × {_2} 像素,某一边超过 {LARGE_TRACE_SIDE}:会进行描摹,但速度较慢。使用保真度较低的预设或图像的较小副本会更快。
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). 图像已按 {_1} × {_2} 像素描摹,由 {_3} × {_4} 缩小而来(最多 {_5} 百万像素)。
@@ -5192,6 +5198,14 @@ lighting Light 光源
Minimum must not exceed Desired, nor Desired Maximum. 最小值不能超过所需值,所需值不能超过最大值。
Minimum 最小值
Justification 对齐设置
Add filters from the list above 从上方列表添加滤镜
Add to Stack 添加到堆栈
Applied Filters 已应用的滤镜
Categories 类别
Choose a filter 选择滤镜
Effect Gallery 效果库
Filters 滤镜
Select artwork to apply effects 选择要应用效果的图稿
@msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them 文件的变量和数据集未被读取(变量:{variables},数据集:{data_sets}):“变量”面板不会列出它们
# Select by Color (select.color)
Select by Color 按颜色选择
@@ -5225,8 +5239,5 @@ lighting Light 光源
Shift: 偏移:
Fresco… 壁画…
Fresco 壁画
# Artwork drag between document tabs.
Drop Artwork 放置图稿
@msg {key} must be [x, y] with finite coordinates {key} 必须是具有有限坐标的 [x, y]
@msg ids must contain 1–10000 object ids ids 必须包含 1–10000 个对象 ID
Effect Gallery… 效果库…
Effect Gallery Dialog 效果库对话框
Can't render this file because it contains an unexpected character in line 2 and column 73.
+16 -5
View File
@@ -1033,6 +1033,11 @@
Fidelity: 精確度:
Figure Space 數字空格
Figure: 數字:
# Artwork drag between document tabs.
Drop Artwork 放置圖稿
@msg {key} must be [x, y] with finite coordinates {key} 必須是具有有限座標的 [x, y]
@msg ids must contain 1–10000 object ids ids 必須包含 1–10000 個物件 ID
File 檔案
File Dimensions 檔案尺寸
File Format: 檔案格式:
@@ -2329,6 +2334,7 @@ file-filter Templates 範本
@msg Persistent libraries not found: {files} 找不到持久資料庫:{files}
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` 不是資料庫面板 (請參閱 window.swatchLibrary)
@msg library panel `{given}` isn't open 資料庫面板 `{given}` 未開啟
@msg library panel `{given}` isn't missing its library 資料庫面板 `{given}` 的資料庫未遺失
@msg too many library panels were opened in this session 本次工作階段開啟的資料庫面板過多
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. 影像為 {_1} × {_2} 像素,有一邊超過 {LARGE_TRACE_SIDE}:仍會描圖,但速度較慢。使用精確度較低的預設集或較小的影像拷貝,描圖會較快。
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). 影像已以 {_1} × {_2} 像素描圖,由 {_3} × {_4} 縮小而來 (最多 {_5} 百萬像素)。
@@ -4982,6 +4988,14 @@ lighting Light 光源
Minimum must not exceed Desired, nor Desired Maximum. 最小值不可超過所需值,所需值不可超過最大值。
Minimum 最小值
Justification 對齊設定
Add filters from the list above 從上方清單新增濾鏡
Add to Stack 加入堆疊
Applied Filters 已套用的濾鏡
Categories 類別
Choose a filter 選擇濾鏡
Effect Gallery 效果庫
Filters 濾鏡
Select artwork to apply effects 選取要套用效果的圖稿
# Select by Color (select.color)
Select by Color 依顏色選取
@msg missing integer `{key}` 未提供整數 `{key}`
@@ -5020,8 +5034,5 @@ lighting Light 光源
Shift: 偏移:
Fresco… 壁畫…
Fresco 壁畫
# Artwork drag between document tabs.
Drop Artwork 放置圖稿
@msg {key} must be [x, y] with finite coordinates {key} 必須是具有有限座標的 [x, y]
@msg ids must contain 1–10000 object ids ids 必須包含 1–10000 個物件 ID
Effect Gallery… 效果庫…
Effect Gallery Dialog 效果庫對話框
Can't render this file because it contains an unexpected character in line 6 and column 47.
+9 -1
View File
@@ -857,6 +857,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
"",
"{} open Document Raster Effects Settings (dialog `rasterEffectsSettings`: the document.rasterEffectsSettings fields); OK runs it. The menu item opens it too",
),
(
"ui.effectGalleryDialog",
"Effect Gallery Dialog",
"",
"{} open Effect Gallery (dialog `effectGallery`: browse raster filters, build a stack, OK applies it as separate effects in one undo step). Effect → Effect Gallery… opens it too",
),
(
"ui.pdfPresetsDialog",
"PDF Presets…",
@@ -1770,6 +1776,7 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
"file.exportAs" => io::export(app, s("format").as_deref(), s("path"), p),
"ui.fileInfoDialog" => crate::dialogs::file_info::open(app),
"ui.rasterEffectsSettingsDialog" => crate::dialogs::raster_effects::open(app),
"ui.effectGalleryDialog" => crate::dialogs::effect_gallery::open(app, p),
"ui.pdfPresetsDialog" => {
crate::dialogs::pdf_presets::open(app, s("selected").as_deref());
Ok(Value::Null)
@@ -2436,7 +2443,7 @@ pub fn enabled(app: &VectorcraftApp, id: &str) -> bool {
id if id.starts_with("view.goto") => {
id["view.goto".len()..].parse::<usize>().is_ok_and(|n| n >= 1 && app.session.active().is_some_and(|d| n <= d.doc.views.len()))
}
"effect.dialog" | "ui.recolorDialog" => app.session.active().is_some_and(|d| !d.selection.is_empty()),
"effect.dialog" | "ui.recolorDialog" | "ui.effectGalleryDialog" => app.session.active().is_some_and(|d| !d.selection.is_empty()),
"ui.cropImage" => selected_image(app, |_| true),
"effect.applyLast" | "effect.last" => app.last_effect.is_some() && app.session.active().is_some_and(|d| !d.selection.is_empty()),
"file.export.pdf" | "ui.savePdfDialog" | "ui.fileInfoDialog" | "ui.rasterEffectsSettingsDialog" => app.session.active().is_some(),
@@ -4055,6 +4062,7 @@ fn effect_menu() -> Vec<Item> {
if !raster.is_empty() {
out.push(Sep);
out.push(Item::Header("Raster Effects"));
out.push(c("Effect Gallery…", "ui.effectGalleryDialog"));
out.extend(raster);
}
// Anything not placed above (future effects) still shows up.
+1 -1
View File
@@ -767,7 +767,7 @@ pub(crate) fn load_library(app: &mut VectorcraftApp, params: Value) -> Result<Va
/// Other Library…: load the library (or document) at `path`, else one picked in an open dialog.
pub(crate) fn other_library(app: &mut VectorcraftApp, path: Option<String>) -> Result<Value, String> {
match library_panel::pick_library_file(app, path)? {
match library_panel::pick_library_file(app, path, library_panel::library_pick_filters(GraphicStyleLibraries::KIND))? {
Some(path) => load_library(app, json!({ "path": path })),
None => Ok(Value::Null),
}
+49 -9
View File
@@ -17,7 +17,9 @@ use std::sync::{Mutex, PoisonError};
use egui::{Rect, Sense, Ui};
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use vectorcraft_engine::cmd::swatchlib::LibraryInfo;
use vectorcraft_doc::style_libs::STYLES_EXT;
use vectorcraft_engine::cmd::fileio;
use vectorcraft_engine::cmd::swatchlib::{self, LibraryInfo};
use super::swatches::{View, click_selection, folder_tile, list_row, list_row_name, tile_grid};
use super::{pstate, set_pstate};
@@ -487,19 +489,24 @@ pub(crate) fn command(app: &mut VectorcraftApp, p: &Value) -> Result<Value, Stri
}
/// `ui.libraryPanel.locate {panel, path?}`: Locate Library… of a library panel whose library is
/// missing. Load the library at `path`, else one picked in an open dialog (on the web the picked
/// file arrives later and opens in a panel of its own, as Other Library…'s does), and show it in
/// open panel `panel`, which keeps its view, Show Find Field and Persistent. When the file's
/// library has a panel open already, `panel` closes and is forgotten, and that panel is brought
/// forward, made persistent when `panel` was. → what `ui.libraryPanel` answers
/// missing ([`missing_file`]; any other panel is an error). Load the library at `path`, else one
/// picked in an open dialog (on the web the picked file arrives later and opens in a panel of its
/// own, as Other Library…'s does), and show it in open panel `panel`, which keeps its view, Show
/// Find Field and Persistent. When the file's library has a panel open already, `panel` closes and
/// is forgotten, and that panel is brought forward, made persistent when `panel` was. → what
/// `ui.libraryPanel` answers
pub(crate) fn locate(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
let given = p.get("panel").and_then(Value::as_str).unwrap_or_default();
let (k, id) = parse(given).ok_or_else(|| format!("`{given}` isn't a library panel (see window.swatchLibrary)"))?;
if !is_open(&app.ui, given) {
return Err(format!("library panel `{given}` isn't open"));
}
if missing_file(app, k, id).is_none() {
return Err(format!("library panel `{given}` isn't missing its library"));
}
let path = p.get("path").and_then(Value::as_str).map(str::to_string);
let Some(path) = pick_library_file(app, path)? else { return Ok(Value::Null) };
let filters = library_pick_filters(k.kind);
let Some(path) = pick_library_file(app, path, filters)? else { return Ok(Value::Null) };
let r = app.run(k.load, json!({ "path": path }))?;
let next = r["library"].as_str().unwrap_or_default().to_string();
let to = panel_id(k.kind, &next);
@@ -525,9 +532,22 @@ fn set(app: &mut VectorcraftApp, panel: &str, mut params: Value) {
}
}
/// Open-dialog filters for Other Library… / Locate Library… of library panels of kind `kind`.
pub(crate) fn library_pick_filters(kind: &str) -> Vec<(&'static str, &'static [&'static str])> {
match kind {
super::swatches::SwatchLibraries::KIND => fileio::library_open_filters("Swatch libraries", swatchlib::LIBRARY_EXTS).collect(),
super::graphic_styles::GraphicStyleLibraries::KIND => fileio::library_open_filters("Graphic Style Libraries", &[STYLES_EXT]).collect(),
_ => fileio::open_filters().collect(),
}
}
/// Other Library…: the library file at `path`, else one picked in an open dialog; `None` when the
/// pick is asynchronous (on the web the picked file arrives later through [`crate::io::open_bytes`]).
pub(crate) fn pick_library_file(app: &mut VectorcraftApp, path: Option<String>) -> Result<Option<String>, String> {
pub(crate) fn pick_library_file(
app: &mut VectorcraftApp,
path: Option<String>,
filters: Vec<(&'static str, &'static [&'static str])>,
) -> Result<Option<String>, String> {
if path.is_none()
&& let Some(f) = app.services.open_async.as_mut()
{
@@ -535,7 +555,7 @@ pub(crate) fn pick_library_file(app: &mut VectorcraftApp, path: Option<String>)
return Ok(None);
}
path.or_else(|| {
let pick = crate::FilePick { filters: crate::FilePick::filters(vectorcraft_engine::cmd::fileio::open_filters()), ..Default::default() };
let pick = crate::FilePick { filters: crate::FilePick::filters(filters), ..Default::default() };
crate::picks::open(app, &pick)
})
.map(Some)
@@ -1293,6 +1313,26 @@ mod tests {
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn locate_library_leaves_a_panel_whose_library_is_there_alone() {
let dir = std::env::temp_dir().join(format!("vc-locate-found-library-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gpl = dir.join("Brand.gpl");
std::fs::write(&gpl, "GIMP Palette\nName: Brand\n#\n255 0 0\tRed\n").unwrap();
let mut app = app();
let pastels = panel_of(app.run("window.swatchLibrary", json!({"library": "pastels"})).unwrap());
for persistent in [false, true] {
app.run("ui.libraryPanel", json!({"panel": pastels, "persistent": persistent})).unwrap();
let e = app.run("ui.libraryPanel.locate", json!({"panel": pastels, "path": gpl.to_string_lossy()})).unwrap_err();
assert!(e.contains("isn't missing its library"), "{e}");
assert!(is_open(&app.ui, &pastels), "persistent: {persistent}");
assert_eq!(settings(&app.ui, "swatches", "pastels").map(|s| s.persistent), Some(persistent));
}
assert!(SwatchLibraries::get(&app, &format!("loaded/{}", gpl.to_string_lossy())).is_none(), "the file isn't loaded");
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn previous_and_next_show_the_neighbouring_library_in_the_same_panel() {
let mut app = app();
+43
View File
@@ -382,6 +382,12 @@ pub(crate) fn proxy(app: &mut VectorcraftApp, ui: &mut Ui, size: f32) {
if let Some(stroke) = c.pick {
app.run("ui.colorPicker", json!({ "stroke": stroke })).ok();
}
if let Some(p) = c.dropped_fill {
app.run("paint.setFill", p).ok();
}
if let Some(p) = c.dropped_stroke {
app.run("paint.setStroke", p).ok();
}
}
/// The Fill (or `stroke`) chip of the Control bar and the Properties panel, `size` square (with a
@@ -538,6 +544,43 @@ pub(crate) fn empty_state(ui: &mut Ui, icon: &str, title: &str, body: &str) {
mod tests {
use super::*;
#[test]
fn dropping_a_proxy_paint_on_the_other_proxy_applies_it() {
use egui::{Event, Modifiers, PointerButton};
use vectorcraft_color::{Color, Paint};
use crate::widgets::PanelDrag;
let mut app = crate::VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 40, "height": 40})).unwrap();
app.run("paint.setFill", json!({"color": "#ff0000"})).unwrap();
app.run("paint.setStroke", json!({"color": "#0000ff"})).unwrap();
let ctx = egui::Context::default();
let stroke_at = std::cell::Cell::new(egui::Pos2::ZERO);
let frame = |app: &mut crate::VectorcraftApp, events: Vec<Event>| {
let mut out = ctx.run_ui(egui::RawInput { events, ..Default::default() }, |ui| {
proxy(app, ui, 36.0);
if let Some(c) = ctx.read_response(ui.id().with("stroke-proxy")).map(|r| r.rect.center()) {
stroke_at.set(c);
}
});
out.textures_delta.clear();
};
frame(&mut app, vec![]);
let at = stroke_at.get();
let red = PanelDrag::paint(Paint::solid(Color::from_hex("#ff0000").unwrap()));
egui::DragAndDrop::set_payload(&ctx, red);
let release = Event::PointerButton { pos: at, button: PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE };
frame(&mut app, vec![Event::PointerMoved(at), release]);
let stroke = app.session.shown_stroke().unwrap();
assert_eq!(stroke.paint.color().map(|c| c.to_hex()), Some("#ff0000".into()), "{}", app.ui.status);
let st = app.session.active().unwrap();
let id = st.selection.objects[0];
assert_eq!(st.doc.node(id).unwrap().appearance.fill_paint().color().map(|c| c.to_hex()), Some("#ff0000".into()));
assert!(egui::DragAndDrop::payload::<PanelDrag>(&ctx).is_none());
}
#[test]
fn paint_params_roundtrip_shapes() {
assert_eq!(paint_params(&Paint::None), json!({"none": true}));
+1 -1
View File
@@ -1214,7 +1214,7 @@ pub(crate) fn load_library(app: &mut VectorcraftApp, params: Value) -> Result<Va
/// Other Library…: load the library (or document) at `path`, else one picked in an open dialog
/// (on the web the picked file arrives later and opens through [`crate::io::open_bytes`]).
pub(crate) fn other_library(app: &mut VectorcraftApp, path: Option<String>) -> Result<Value, String> {
match library_panel::pick_library_file(app, path)? {
match library_panel::pick_library_file(app, path, library_panel::library_pick_filters(SwatchLibraries::KIND))? {
Some(path) => load_library(app, json!({ "path": path })),
None => Ok(Value::Null),
}
+4 -1
View File
@@ -260,7 +260,10 @@ fn other_swatch_library_asks_off_the_ui_thread() {
app.run("swatch.new", json!({"name": "Signal", "color": "#ff3300"})).unwrap();
let (dir, file) = saved_document(&mut app, "swatches");
click(&mut app, "Other Library…", library_menu::<SwatchLibraries>);
assert!(matches!(shown.requests().as_slice(), [PickRequest::Open(_)]));
assert!(matches!(
shown.requests().as_slice(),
[PickRequest::Open(p)] if p.filters.first().is_some_and(|(label, exts)| label == "Swatch libraries" && exts.iter().any(|e| e == "ase"))
));
poll(&mut app);
assert!(library_panel::last_open(&app.ui).is_none() && app.ui.status.is_empty(), "{}", app.ui.status);
shown.answer(&[&file]);
+59 -1
View File
@@ -44,6 +44,20 @@ pub fn flat_button(ui: &mut Ui, text: &str, width: f32) -> Response {
resp
}
/// A [`flat_button`] that expands to fit localized labels wider than `min_width`.
pub fn flat_button_fit(ui: &mut Ui, text: &str, min_width: f32) -> Response {
let t = Tokens::get(ui.ctx());
let galley = ui.painter().layout_no_wrap(tl!(text).to_string(), egui::FontId::proportional(12.5), t.text_strong);
let width = (galley.size().x + 24.0).max(min_width);
let (rect, resp) = ui.allocate_exact_size(vec2(width, 24.0), Sense::click());
let rect = rect.shrink2(vec2(0.0, 0.5));
ui.painter().rect_filled(rect, CornerRadius::same(5), t.button);
flat_fill(ui, rect, &resp);
ui.painter().with_clip_rect(rect).text(rect.center(), egui::Align2::CENTER_CENTER, tl!(text), egui::FontId::proportional(12.5), t.text_strong);
resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, ui.is_enabled(), tl!(text)));
resp
}
/// Width of a [`split_button`]'s arrow.
pub const SPLIT_ARROW: f32 = 18.0;
@@ -825,7 +839,7 @@ pub fn chip_button_named(ui: &mut Ui, size: f32, chevron: bool, tip: &str, draw:
}
/// What the user did on a [`fill_stroke_proxy`].
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ProxyClicks {
pub fill: bool,
pub stroke: bool,
@@ -833,6 +847,10 @@ pub struct ProxyClicks {
pub default: bool,
/// Double-clicked a square: open the Color Picker for it (`true` = the stroke).
pub pick: Option<bool>,
/// A paint dragged from the other proxy (or a swatch) dropped on the fill square.
pub dropped_fill: Option<serde_json::Value>,
/// A paint dropped on the stroke square.
pub dropped_stroke: Option<serde_json::Value>,
}
/// The Fill/Stroke proxy pair (two overlapping squares). `mixed` (fill, stroke) draws a "?" square
@@ -845,6 +863,8 @@ pub fn fill_stroke_proxy(ui: &mut Ui, fill: &Paint, stroke: &Paint, mixed: (bool
let stroke_r = Rect::from_min_size(rect.max - Vec2::splat(s), Vec2::splat(s));
let stroke_resp = ui.interact(stroke_r, ui.id().with("stroke-proxy"), Sense::click_and_drag());
let fill_resp = ui.interact(fill_r, ui.id().with("fill-proxy"), Sense::click_and_drag());
let dropped_fill = if mixed.0 { None } else { proxy_paint_drop(ui, &fill_resp) };
let dropped_stroke = if mixed.1 { None } else { proxy_paint_drop(ui, &stroke_resp) };
// A proxy drags its paint (onto the Swatches panel or art), unless it shows "?".
for (resp, paint, mixed) in [(&fill_resp, fill, mixed.0), (&stroke_resp, stroke, mixed.1)] {
if !mixed {
@@ -901,9 +921,26 @@ pub fn fill_stroke_proxy(ui: &mut Ui, fill: &Paint, stroke: &Paint, mixed: (bool
swap: swap.on_hover_text(tl!("Swap Fill and Stroke (Shift+X)")).clicked(),
default: def.on_hover_text(tl!("Default Fill and Stroke (D)")).clicked(),
pick,
dropped_fill,
dropped_stroke,
}
}
/// A [`PanelDrag::Paint`] released on a Fill/Stroke proxy square: highlight while held over it.
fn proxy_paint_drop(ui: &Ui, resp: &Response) -> Option<serde_json::Value> {
if let Some(drag) = resp.dnd_hover_payload::<PanelDrag>()
&& let PanelDrag::Paint { params, .. } = &*drag
&& !params.is_null()
{
let t = Tokens::get(ui.ctx());
ui.painter().rect_stroke(resp.rect, 0.0, Stroke::new(2.0, t.accent), StrokeKind::Outside);
}
resp.dnd_release_payload::<PanelDrag>().and_then(|d| {
let PanelDrag::Paint { params, .. } = &*d else { return None };
(!params.is_null()).then_some(params.clone())
})
}
/// A compact dropdown of interface labels (shown in the UI language). Returns the chosen index.
pub fn dropdown(ui: &mut Ui, id: impl std::hash::Hash + std::fmt::Debug, current: &str, options: &[&str], width: f32) -> Option<usize> {
dropdown_with(ui, id, current, options, width, |_| true)
@@ -2845,3 +2882,24 @@ mod combo_keyboard_tests {
assert!(!egui::Popup::is_any_open(&ctx), "the list closes after a keyboard pick");
}
}
#[cfg(test)]
mod button_tests {
use super::*;
/// [`flat_button_fit`] preserves minimum width for short labels and expands for long ones.
#[test]
fn flat_button_fit_expands_for_long_text() {
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
let raw = egui::RawInput::default();
let mut out = ctx.run_ui(raw, |ui| {
let resp_short = flat_button_fit(ui, "OK", 100.0);
assert_eq!(resp_short.rect.width(), 100.0);
let resp_long = flat_button_fit(ui, "Çalışma Yüzeylerini Düzenle", 100.0);
assert!(resp_long.rect.width() > 160.0);
});
out.textures_delta.clear();
}
}
+3 -2
View File
@@ -431,7 +431,7 @@ onto a flyer through the command API; its screenshot was inspected, source prese
Undo/Redo checked. Physical mouse hover on the desktop is not covered by that native smoke test.
Public behavior reference: [Illustrator public duplication documentation](https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/duplicate-objects.html).
The tab-hover workflow follows the contributor’s requested behavior. All test artwork is original geometry/text generated locally.
The new command and validation messages are translated in all 23 language catalogs.
The new command and validation messages are translated in all 24 language catalogs, including Turkish.
Scores and hour estimates are unchanged.
## Revision history
@@ -444,9 +444,10 @@ Scores and hour estimates are unchanged.
| 2026-10-14 | minor | Document registration of every explicitly supplied craft-fonts face after the existing script-specific prefix; empty input and web selection remain unchanged. |
| 2026-10-13 | minor | Document pinned PngSuite files, integrity checks and download budgets (#1729). |
> **Tab-drag status (2026-10-22):** updated from upstream; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
> **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
| Date | Change | Tab-drag history |
|---|---|---|
| 2026-10-22 | minor | Merge current main and complete the Turkish tab-drag labels and validation messages requested by the maintainer; all 24 catalogs covered; scores and estimates unchanged. |
| 2026-10-22 | minor | Tab-drag follow-up: reconcile upstream progress updates and document drag lifecycle, insertion behavior and regression contracts; behavior, scores and estimates unchanged. |
| 2026-10-22 | minor | Artwork dragged with Selection switches visible document tabs after a 400 ms hover, then copies editable artwork on canvas release; source and clipboard stay intact; scores and hours unchanged |
+2 -1
View File
@@ -521,9 +521,10 @@ separate. Scores and hours unchanged. [Behavior and command details](development
| 2026-10-10 | minor | Alpha blockers checked against the core-workflow gate: none |
| 2026-10-10 | major | Moved from the ROADMAP's "Where we're lacking"; kept ids G1–G8, added G9–G19 (file formats, stability, bugs, preferences, 30.x additions, pen hardware, performance, localization, ecosystem, AI, accessibility) and re-ranked |
> **Tab-drag status (2026-10-22):** updated from upstream; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
> **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
| Date | Change | Tab-drag history |
|---|---|---|
| 2026-10-22 | minor | Merge current main and complete the Turkish tab-drag labels and validation messages requested by the maintainer; all 24 catalogs covered; scores and estimates unchanged. |
| 2026-10-22 | minor | Tab-drag follow-up: reconcile upstream progress updates and document drag lifecycle, insertion behavior and regression contracts; behavior, scores and estimates unchanged. |
| 2026-10-22 | minor | Artwork dragged with Selection switches visible document tabs after a 400 ms hover, then copies editable artwork on canvas release; source and clipboard stay intact; scores and hours unchanged |
+3 -1
View File
@@ -1718,7 +1718,9 @@ under `ui.library_panels`.
`ui.libraryPanel.locate {panel, path?}` is Locate Library…: it loads the library at `path` (without one, it
asks for a file) as Other Library… does and shows it in the open panel `panel`, which keeps its view, find
field and Persistent, and answers as `ui.libraryPanel` does. When the file's library already has a panel open,
`panel` closes and is forgotten, and that panel is brought forward, made persistent when `panel` was.
`panel` closes and is forgotten, and that panel is brought forward, made persistent when `panel` was. On a
panel whose library isn't missing, it answers an error without asking for or loading a file, and the panel
keeps its library.
`window.swatchLibrary` and `window.graphicStyleLibrary` also take a missing library's id, so a closed missing
panel opens again; they answer its file's name without the extension and `count: 0`.
+2 -1
View File
@@ -221,9 +221,10 @@ separate. Scores and hours unchanged. [Behavior and command details](development
| 2026-10-10 | minor | Added the Alpha gate table (core-workflow gate): all six workflows work end to end, `.ai` exchange partial but not blocking; stage stays alpha |
| 2026-10-10 | major | Created from ROADMAP.md's milestone table and "Where we're going"; added Current focus and the beta list |
> **Tab-drag status (2026-10-22):** updated from upstream; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
> **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
| Date | Change | Tab-drag history |
|---|---|---|
| 2026-10-22 | minor | Merge current main and complete the Turkish tab-drag labels and validation messages requested by the maintainer; all 24 catalogs covered; scores and estimates unchanged. |
| 2026-10-22 | minor | Tab-drag follow-up: reconcile upstream progress updates and document drag lifecycle, insertion behavior and regression contracts; behavior, scores and estimates unchanged. |
| 2026-10-22 | minor | Artwork dragged with Selection switches visible document tabs after a 400 ms hover, then copies editable artwork on canvas release; source and clipboard stay intact; scores and hours unchanged |
+2 -1
View File
@@ -1132,9 +1132,10 @@ separate. Scores and hours unchanged. [Behavior and command details](development
| 2026-10-05 | major | (in ROADMAP.md) M3 and M4 rows re-derived after the paint and files milestones |
| 2026-10-02 | major | (in ROADMAP.md) First 22-area weighted estimate |
> **Tab-drag status (2026-10-22):** updated from upstream; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
> **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
| Date | Change | Tab-drag history |
|---|---|---|
| 2026-10-22 | minor | Merge current main and complete the Turkish tab-drag labels and validation messages requested by the maintainer; all 24 catalogs covered; scores and estimates unchanged. |
| 2026-10-22 | minor | Tab-drag follow-up: reconcile upstream progress updates and document drag lifecycle, insertion behavior and regression contracts; behavior, scores and estimates unchanged. |
| 2026-10-22 | minor | Artwork dragged with Selection switches visible document tabs after a 400 ms hover, then copies editable artwork on canvas release; source and clipboard stay intact; scores and hours unchanged |
+2 -1
View File
@@ -383,9 +383,10 @@ separate. Scores and hours unchanged. [Behavior and command details](development
| 2026-10-11 | minor | Direct Selection: dragging a path selected whole by an anchor moves it whole; Alt-drag copies by an anchor too, toggles during the drag and snaps onto the original (#1104); score unchanged (estimated) |
| 2026-10-10 | major | First checklist, built from the tool sources and tests against Illustrator 2026's public documentation |
> **Tab-drag status (2026-10-22):** updated from upstream; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
> **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
| Date | Change | Tab-drag history |
|---|---|---|
| 2026-10-22 | minor | Merge current main and complete the Turkish tab-drag labels and validation messages requested by the maintainer; all 24 catalogs covered; scores and estimates unchanged. |
| 2026-10-22 | minor | Tab-drag follow-up: reconcile upstream progress updates and document drag lifecycle, insertion behavior and regression contracts; behavior, scores and estimates unchanged. |
| 2026-10-22 | minor | Artwork dragged with Selection switches visible document tabs after a 400 ms hover, then copies editable artwork on canvas release; source and clipboard stay intact; scores and hours unchanged |