mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 12:17:14 -06:00
Merge pull request #4446 from dotCooCoo/feat/flare-options-alt-reset
Flare: preview options and restore defaults with Alt or Option
This commit is contained in:
@@ -177,6 +177,10 @@ pub(crate) struct DialogSpec {
|
||||
/// A button left of Cancel, as (label, field), that sets `field: true` and confirms, as OK
|
||||
/// does otherwise (Transform Each's Copy).
|
||||
pub alternate: Option<(&'static str, &'static str)>,
|
||||
/// Puts the fields back to their defaults. While Alt (Option on macOS) is held, the Cancel
|
||||
/// button of a dialog with an `ok` reads Reset; Reset (or `ui.dialogReset`) runs this and the
|
||||
/// dialog stays open.
|
||||
pub reset: Option<fn(&VectorcraftApp, &mut Dialog)>,
|
||||
pub min_width: f32,
|
||||
pub max_width: Option<f32>,
|
||||
/// The body runs a live preview interaction that Cancel rolls back.
|
||||
@@ -212,6 +216,7 @@ impl DialogSpec {
|
||||
ok: Some("OK"),
|
||||
discard: None,
|
||||
alternate: None,
|
||||
reset: None,
|
||||
min_width: 320.0,
|
||||
max_width: None,
|
||||
preview: false,
|
||||
@@ -379,14 +384,15 @@ registry! {
|
||||
ShortcutImport: [shortcut_import::KIND] => DialogSpec::window(shortcut_import::show, shortcut_import::confirm),
|
||||
}
|
||||
|
||||
/// The button labels the shared dialog frame can show (OK, discard and the fixed Cancel/Close),
|
||||
/// so the catalog tests can insist they are translated.
|
||||
/// The button labels the shared dialog frame can show (OK, discard, the fixed Cancel/Close and
|
||||
/// Reset), so the catalog tests can insist they are translated.
|
||||
pub fn button_labels() -> Vec<&'static str> {
|
||||
let mut v = vec!["Cancel", "Close"];
|
||||
for spec in std::iter::once(&DialogSpec::FORM).chain(DialogKind::ALL.iter().map(|k| k.spec())) {
|
||||
v.extend(spec.ok);
|
||||
v.extend(spec.discard);
|
||||
v.extend(spec.alternate.map(|(label, _)| label));
|
||||
v.extend(spec.reset.map(|_| "Reset"));
|
||||
}
|
||||
v.sort_unstable();
|
||||
v.dedup();
|
||||
@@ -455,7 +461,10 @@ pub(crate) fn parent(d: &Dialog) -> Option<Dialog> {
|
||||
pub fn cancel(app: &mut VectorcraftApp) {
|
||||
missing_fonts::requeue_replaced(app);
|
||||
if let Some(d) = app.ui.dialog.take() {
|
||||
if spec(&d.kind).preview {
|
||||
// Toolbar-only Flare options start no preview and must not cancel a gesture
|
||||
// that was already active before opening them.
|
||||
let owns_preview = d.kind != flare_options::KIND || d.fields.contains_key(form::PREVIEWED);
|
||||
if spec(&d.kind).preview && owns_preview {
|
||||
let _ = app.session.cancel_interaction();
|
||||
}
|
||||
app.ui.dialog = parent(&d);
|
||||
@@ -463,6 +472,23 @@ pub fn cancel(app: &mut VectorcraftApp) {
|
||||
settle(app);
|
||||
}
|
||||
|
||||
/// Whether the open dialog has a Reset ([`DialogSpec::reset`]).
|
||||
pub(crate) fn can_reset(app: &VectorcraftApp) -> bool {
|
||||
app.ui.dialog.as_ref().is_some_and(|d| spec(&d.kind).reset.is_some())
|
||||
}
|
||||
|
||||
/// Reset (`ui.dialogReset`, or Cancel while Alt or Option is held): the open dialog's fields go
|
||||
/// back to their defaults and it stays open → the dialog; an error when no dialog is open or the
|
||||
/// open one has no Reset.
|
||||
pub(crate) fn reset(app: &mut VectorcraftApp) -> DialogResult {
|
||||
let Some(mut d) = app.ui.dialog.clone() else { return Err("no dialog open".into()) };
|
||||
let Some(reset) = spec(&d.kind).reset else { return Err("the open dialog has no Reset".into()) };
|
||||
reset(app, &mut d);
|
||||
let out = serde_json::to_value(&d).unwrap_or_default();
|
||||
app.ui.dialog = Some(d);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Apply the open dialog (OK).
|
||||
pub fn confirm(app: &mut VectorcraftApp) -> DialogResult {
|
||||
missing_fonts::requeue_replaced(app);
|
||||
@@ -538,6 +564,7 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
let mut ok = false;
|
||||
let mut ok_enabled = true;
|
||||
let mut cancel = false;
|
||||
let mut reset = false;
|
||||
let mut discard = false;
|
||||
let mut alternate = false;
|
||||
// Opened as a save panel closed: the Enter that closed it isn't this dialog's, until it is let go.
|
||||
@@ -598,8 +625,21 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
ok = true;
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
if widgets::secondary_button(ui, if spec.ok.is_some() { "Cancel" } else { "Close" }).clicked() {
|
||||
cancel = true;
|
||||
// While Alt (Option) is held, Cancel reads Reset on a dialog that has one.
|
||||
let resets = spec.ok.is_some() && spec.reset.is_some() && ui.input(|i| i.modifiers.alt);
|
||||
let label = if resets {
|
||||
"Reset"
|
||||
} else if spec.ok.is_some() {
|
||||
"Cancel"
|
||||
} else {
|
||||
"Close"
|
||||
};
|
||||
if widgets::secondary_button(ui, label).clicked() {
|
||||
if resets {
|
||||
reset = true;
|
||||
} else {
|
||||
cancel = true;
|
||||
}
|
||||
}
|
||||
if let Some((label, _)) = spec.alternate {
|
||||
ui.add_space(8.0);
|
||||
@@ -625,6 +665,10 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
|
||||
app.ui.dialog = Some(d);
|
||||
if cancel {
|
||||
self::cancel(app);
|
||||
} else if reset {
|
||||
if let Err(e) = self::reset(app) {
|
||||
app.status(e);
|
||||
}
|
||||
} else if ok && let Err(e) = confirm(app) {
|
||||
app.status(e);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
//! Flare Tool Options (double-click the Flare tool, or click with it): the options the Flare tool
|
||||
//! keeps, which draw the next flare dragged out, last across tool switches and are saved with the
|
||||
//! preferences. OK sets them with `tool.setOption {tool: "flare", values}`; opened by a click, it
|
||||
//! then draws a flare there with them (`shape.flare`, on the active perspective plane while the
|
||||
//! grid shows).
|
||||
//! accepts a flare preview there with them (`shape.flare`, on the active perspective plane while the
|
||||
//! grid shows). While Alt (Option on macOS) is held, Cancel reads Reset, which puts every option
|
||||
//! back to the tool's default and leaves the dialog open (`ui.dialogReset`). A click-opened
|
||||
//! dialog previews its settings live; Reset refreshes that preview and Cancel rolls it back.
|
||||
//!
|
||||
//! Fields: the options (`vectorcraft_tools::extra::FLARE_OPTIONS`): `diameter` and `pathLength`
|
||||
//! (points), `opacity`, `brightness`, `growth`, `fuzziness`, `longest`, `rayFuzziness` and
|
||||
//! `largest` (%), `rays` and `rings` (counts), `direction` (degrees); `raysOn` and `ringsOn`; and
|
||||
//! `x`, `y` where a click opened it.
|
||||
//! `x`, `y` where a click opened it, with `preview` on initially for that click.
|
||||
|
||||
use serde_json::{Map, Value, json};
|
||||
use vectorcraft_geom::Point;
|
||||
@@ -21,7 +23,15 @@ use crate::{VectorcraftApp, widgets};
|
||||
/// The dialog kind of the Flare Tool Options.
|
||||
pub const KIND: &str = "flareOptions";
|
||||
|
||||
pub(super) const SPEC: DialogSpec = DialogSpec { heading: |_| tl!("Flare Tool Options").into(), body, confirm, min_width: 440.0, ..DialogSpec::FORM };
|
||||
pub(super) const SPEC: DialogSpec = DialogSpec {
|
||||
heading: |_| tl!("Flare Tool Options").into(),
|
||||
body,
|
||||
confirm,
|
||||
reset: Some(reset),
|
||||
preview: true,
|
||||
min_width: 440.0,
|
||||
..DialogSpec::FORM
|
||||
};
|
||||
|
||||
/// Width of the label column and of the fields.
|
||||
const LABEL_W: f32 = 78.0;
|
||||
@@ -35,6 +45,7 @@ pub fn open(app: &mut VectorcraftApp, at: Option<Point>) -> Value {
|
||||
_ => Map::new(),
|
||||
};
|
||||
if let Some(p) = at {
|
||||
fields.insert("preview".into(), json!(true));
|
||||
fields.insert("x".into(), json!(p.x));
|
||||
fields.insert("y".into(), json!(p.y));
|
||||
}
|
||||
@@ -102,23 +113,53 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
});
|
||||
ui.end_row();
|
||||
});
|
||||
if let Some((cmd, params)) = preview_command(app, d) {
|
||||
form::preview(app, ui, d, "Flare", &cmd, params);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// A click-created flare previews at that original click; toolbar options draw no artwork.
|
||||
fn preview_command(app: &VectorcraftApp, d: &Dialog) -> Option<(String, Value)> {
|
||||
let at = Point::new(d.fields.get("x")?.as_f64().filter(|v| v.is_finite())?, d.fields.get("y")?.as_f64().filter(|v| v.is_finite())?);
|
||||
// Use the same clamping and whole-count conversion as accepted tool settings.
|
||||
let mut tool = vectorcraft_tools::create("flare");
|
||||
for (key, default, ..) in FLARE_OPTIONS {
|
||||
tool.set_option(key, &json!(d.f64(key, default)));
|
||||
}
|
||||
for key in ["raysOn", "ringsOn"] {
|
||||
tool.set_option(key, &json!(d.bool(key)));
|
||||
}
|
||||
let params = flare_params(&tool.options(), at);
|
||||
Some(vectorcraft_engine::perspective_click(&app.session, "shape.flare", ¶ms, at).unwrap_or_else(|| ("shape.flare".into(), params)))
|
||||
}
|
||||
|
||||
/// Reset (Cancel with Alt or Option held): every option goes back to the Flare tool's default
|
||||
/// (`FLARE_OPTIONS`, with Rays and Rings on). The dialog keeps a click's `x` and `y`, so OK still draws there.
|
||||
fn reset(_: &VectorcraftApp, d: &mut Dialog) {
|
||||
if let Value::Object(defaults) = vectorcraft_tools::create("flare").options() {
|
||||
d.fields.extend(defaults);
|
||||
}
|
||||
}
|
||||
|
||||
/// OK: set the tool's options; opened by a click, draw a flare there with them.
|
||||
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> DialogResult {
|
||||
let command = preview_command(app, d);
|
||||
if command.is_none() && (d.fields.contains_key("x") || d.fields.contains_key("y") || d.fields.contains_key(form::PREVIEWED)) {
|
||||
return Err("Flare click coordinates must be finite numbers".into());
|
||||
}
|
||||
let mut values: Map<String, Value> =
|
||||
FLARE_OPTIONS.iter().filter(|(k, ..)| d.fields.contains_key(*k)).map(|(k, default, ..)| (k.to_string(), json!(d.f64(k, *default)))).collect();
|
||||
for key in ["raysOn", "ringsOn"] {
|
||||
values.insert(key.into(), json!(d.bool(key)));
|
||||
}
|
||||
let at = d.fields.get("x").and_then(Value::as_f64).zip(d.fields.get("y").and_then(Value::as_f64)).map(|(x, y)| Point::new(x, y));
|
||||
let options = run_and_close(app, "tool.setOption", json!({ "tool": "flare", "values": values }))?;
|
||||
let Some(at) = at else { return Ok(options) };
|
||||
let params = flare_params(&options, at);
|
||||
match vectorcraft_engine::perspective_click(&app.session, "shape.flare", ¶ms, at) {
|
||||
Some((id, p)) => app.run(&id, p),
|
||||
None => app.run("shape.flare", params),
|
||||
if let Some((cmd, params)) = command {
|
||||
// Accept the preview once; option persistence follows successful artwork creation.
|
||||
let result = form::commit_preview(app, &cmd, params)?;
|
||||
app.run("tool.setOption", json!({ "tool": "flare", "values": values }))?;
|
||||
Ok(result)
|
||||
} else {
|
||||
run_and_close(app, "tool.setOption", json!({ "tool": "flare", "values": values }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +189,81 @@ mod tests {
|
||||
children.iter().filter_map(|c| c.name.clone()).collect()
|
||||
}
|
||||
|
||||
/// Invalid control-channel coordinates must not turn a click dialog into toolbar options.
|
||||
#[test]
|
||||
fn invalid_click_coordinates_keep_the_dialog_and_preview_cancellable() {
|
||||
for (key, value) in [("x", Value::Null), ("y", Value::Null), ("x", json!("invalid"))] {
|
||||
let mut app = app();
|
||||
let original = app.session.doc().unwrap().doc.layers.clone();
|
||||
let depth = app.session.doc().unwrap().history.undo.len();
|
||||
let options = app.session.tool_options_of("flare");
|
||||
open(&mut app, Some(Point::new(220.0, 330.0)));
|
||||
painted(&mut app);
|
||||
let preview = app.session.doc().unwrap().doc.layers.clone();
|
||||
let d = app.ui.dialog.as_mut().unwrap();
|
||||
d.fields.insert(key.into(), value);
|
||||
d.fields.insert("rings".into(), json!(4));
|
||||
assert_eq!(super::super::confirm(&mut app).unwrap_err(), "Flare click coordinates must be finite numbers");
|
||||
assert!(app.ui.dialog.is_some());
|
||||
assert!(app.session.in_interaction());
|
||||
assert_eq!(app.session.doc().unwrap().doc.layers, preview);
|
||||
assert_eq!(app.session.doc().unwrap().history.undo.len(), depth);
|
||||
assert_eq!(app.session.tool_options_of("flare"), options);
|
||||
super::super::cancel(&mut app);
|
||||
assert!(!app.session.in_interaction());
|
||||
assert_eq!(app.session.doc().unwrap().doc.layers, original);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancelling_toolbar_options_preserves_an_existing_interaction() {
|
||||
let mut app = app();
|
||||
app.session.begin_interaction("Existing gesture").unwrap();
|
||||
app.session.preview("shape.rectangle", &json!({"x":10,"y":10,"width":40,"height":40})).unwrap();
|
||||
let previewed = app.session.doc().unwrap().doc.layers.clone();
|
||||
open(&mut app, None);
|
||||
painted(&mut app);
|
||||
super::super::cancel(&mut app);
|
||||
assert!(app.session.in_interaction());
|
||||
assert_eq!(app.session.doc().unwrap().doc.layers, previewed);
|
||||
app.session.cancel_interaction().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_updates_live_preview_and_cancel_discards_art_and_options() {
|
||||
let mut app = app();
|
||||
app.run("tool.setOption", json!({"tool":"flare", "values":{"rings":3}})).unwrap();
|
||||
let original = app.session.doc().unwrap().doc.layers.clone();
|
||||
let depth = app.session.doc().unwrap().history.undo.len();
|
||||
let options = app.session.tool_options_of("flare");
|
||||
open(&mut app, Some(Point::new(220.0, 330.0)));
|
||||
let text = painted(&mut app);
|
||||
assert!(text.contains("Preview"));
|
||||
assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 3);
|
||||
assert_eq!(app.session.doc().unwrap().history.undo.len(), depth);
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("rings".into(), json!(4.0));
|
||||
painted(&mut app);
|
||||
assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 4);
|
||||
app.run("ui.dialogReset", json!({})).unwrap();
|
||||
painted(&mut app);
|
||||
assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 10);
|
||||
assert_eq!(app.session.tool_options_of("flare"), options, "preview doesn't persist options");
|
||||
super::super::cancel(&mut app);
|
||||
assert_eq!(app.session.doc().unwrap().doc.layers, original);
|
||||
assert_eq!(app.session.doc().unwrap().history.undo.len(), depth);
|
||||
assert_eq!(app.session.tool_options_of("flare"), options);
|
||||
// Accepting the same reset preview produces one flare and one Undo step.
|
||||
open(&mut app, Some(Point::new(220.0, 330.0)));
|
||||
painted(&mut app);
|
||||
app.run("ui.dialogReset", json!({})).unwrap();
|
||||
painted(&mut app);
|
||||
super::super::confirm(&mut app).unwrap();
|
||||
assert_eq!(app.session.doc().unwrap().history.undo.len(), depth + 1);
|
||||
assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 10);
|
||||
app.run("edit.undo", json!({})).unwrap();
|
||||
assert_eq!(app.session.doc().unwrap().doc.layers, original);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_toolbar_opens_the_options_and_ok_keeps_them_for_the_next_drag() {
|
||||
let mut app = app();
|
||||
@@ -200,4 +316,24 @@ mod tests {
|
||||
let o = app.session.tool_options_of("flare");
|
||||
assert_eq!((o["opacity"].as_f64(), o["diameter"].as_f64()), (Some(100.0), Some(0.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ui_dialog_reset_puts_the_defaults_back_and_keeps_where_a_click_opened_it() {
|
||||
let mut app = app();
|
||||
assert_eq!(app.run("ui.dialogReset", json!({})).unwrap_err(), "no dialog open");
|
||||
app.run("tool.setOption", json!({"tool": "flare", "values": {"rings": 3, "raysOn": false, "largest": 120}})).unwrap();
|
||||
crate::dialogs::open_tool_dialog(&mut app, "flare", json!({"x": 300, "y": 300}));
|
||||
let d = app.run("ui.dialogReset", json!({})).unwrap();
|
||||
assert_eq!((d["kind"].as_str(), d["fields"]["rings"].as_f64(), d["fields"]["raysOn"].as_bool()), (Some(KIND), Some(10.0), Some(true)));
|
||||
let d = app.ui.dialog.as_ref().expect("the dialog stays open");
|
||||
assert_eq!((d.f64("largest", 0.0), d.f64("x", 0.0), d.f64("y", 0.0)), (50.0, 300.0, 300.0));
|
||||
// The tool keeps its options until OK, which draws the flare with the defaults where the click was.
|
||||
assert_eq!(app.session.tool_options_of("flare")["rings"].as_u64(), Some(3));
|
||||
super::super::confirm(&mut app).unwrap();
|
||||
let parts = flare_parts(&app);
|
||||
assert_eq!((parts.iter().filter(|p| *p == "Ring").count(), parts.iter().any(|p| p == "Rays")), (10, true), "{parts:?}");
|
||||
// A dialog without a Reset refuses it.
|
||||
app.ui.dialog = Some(Dialog::new("move", json!({"dx": 1})));
|
||||
assert_eq!(app.run("ui.dialogReset", json!({})).unwrap_err(), "the open dialog has no Reset");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1661,6 +1661,40 @@ fn free_distort_reset_puts_the_corners_back() {
|
||||
assert_eq!((effects.len(), effects[0].params["corners"].clone()), (1, rest));
|
||||
}
|
||||
|
||||
/// While Alt is held, the Flare Tool Options' Cancel button reads Reset; Reset puts every option
|
||||
/// back to the tool's default and leaves the dialog open, letting Alt go shows Cancel again, and OK
|
||||
/// keeps the defaults.
|
||||
#[test]
|
||||
fn flare_options_alt_turns_cancel_into_reset() {
|
||||
let mut app = app();
|
||||
app.run("tool.options", json!({"tool": "flare"})).unwrap();
|
||||
let d = app.ui.dialog.as_mut().unwrap();
|
||||
for (k, v) in [("diameter", json!(250)), ("rays", json!(4)), ("ringsOn", json!(false)), ("growth", json!(80))] {
|
||||
d.fields.insert(k.into(), v);
|
||||
}
|
||||
let mut f = Frames::new();
|
||||
f.button(&mut app, "Cancel");
|
||||
f.run(&mut app, vec![egui::Event::ModifiersChanged(egui::Modifiers::ALT)]);
|
||||
let reset = f.button(&mut app, "Reset");
|
||||
let texts = f.texts(&mut app);
|
||||
assert!(!texts.iter().any(|(t, _)| t == "Cancel"), "Reset takes Cancel's place: {texts:?}");
|
||||
f.press(&mut app, reset, true);
|
||||
f.press(&mut app, reset, false);
|
||||
let d = app.ui.dialog.as_ref().expect("Reset leaves the dialog open");
|
||||
assert_eq!(
|
||||
(d.f64("diameter", 0.0), d.f64("rays", 0.0), d.bool("ringsOn"), d.f64("growth", 0.0), d.f64("direction", 0.0)),
|
||||
(100.0, 15.0, true, 20.0, 45.0)
|
||||
);
|
||||
f.run(&mut app, vec![egui::Event::ModifiersChanged(egui::Modifiers::NONE)]);
|
||||
f.button(&mut app, "Cancel");
|
||||
confirm(&mut app).unwrap();
|
||||
let o = app.session.tool_options_of("flare");
|
||||
assert_eq!(
|
||||
(o["diameter"].as_f64(), o["rays"].as_u64(), o["ringsOn"].as_bool(), o["growth"].as_f64()),
|
||||
(Some(100.0), Some(15), Some(true), Some(20.0))
|
||||
);
|
||||
}
|
||||
|
||||
/// The slider that screen readers name `label` in `out`'s tree: its node id, number and text.
|
||||
fn slider_node(out: &egui::FullOutput, label: &str) -> (egui::accesskit::NodeId, Option<f64>, Option<String>) {
|
||||
let nodes = &out.platform_output.accesskit_update.as_ref().expect("an accessibility tree").nodes;
|
||||
|
||||
@@ -4014,6 +4014,7 @@ axis Both И двете
|
||||
@msg no current layer няма текущ слой
|
||||
@msg no data няма данни
|
||||
@msg no dialog open няма отворен диалогов прозорец
|
||||
@msg the open dialog has no Reset отвореният диалогов прозорец няма бутон „Нулиране“
|
||||
@msg no document няма документ
|
||||
@msg no document open няма отворен документ
|
||||
@msg no effect applied yet все още няма приложен ефект
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4415,6 +4415,7 @@ imageTrace Outline Obrys
|
||||
@msg no current layer žádná aktuální vrstva
|
||||
@msg no data žádná data
|
||||
@msg no dialog open není otevřeno žádné dialogové okno
|
||||
@msg the open dialog has no Reset otevřené dialogové okno nemá tlačítko Obnovit
|
||||
@msg no document žádný dokument
|
||||
@msg no document open není otevřen žádný dokument
|
||||
@msg no effect applied yet zatím nebyl použit žádný efekt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4124,6 +4124,7 @@ imageTrace Outline Kontur
|
||||
@msg no current layer intet aktuelt lag
|
||||
@msg no data ingen data
|
||||
@msg no dialog open ingen åben dialogboks
|
||||
@msg the open dialog has no Reset den åbne dialogboks har ingen Nulstil-knap
|
||||
@msg no document intet dokument
|
||||
@msg no document open intet åbent dokument
|
||||
@msg no effect applied yet ingen effekt er anvendt endnu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4033,6 +4033,7 @@ theme Appearance Erscheinungsbild
|
||||
@msg no current layer keine aktuelle Ebene
|
||||
@msg no data keine Daten
|
||||
@msg no dialog open kein Dialogfeld geöffnet
|
||||
@msg the open dialog has no Reset das geöffnete Dialogfeld hat keine Schaltfläche „Zurücksetzen“
|
||||
@msg no document kein Dokument
|
||||
@msg no document open kein Dokument geöffnet
|
||||
@msg no effect applied yet noch kein Effekt angewendet
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4075,6 +4075,7 @@ theme Appearance Εμφάνιση
|
||||
@msg no current layer δεν υπάρχει τρέχον επίπεδο
|
||||
@msg no data δεν υπάρχουν δεδομένα
|
||||
@msg no dialog open δεν υπάρχει ανοιχτό παράθυρο διαλόγου
|
||||
@msg the open dialog has no Reset το ανοιχτό παράθυρο διαλόγου δεν έχει κουμπί Επαναφορά
|
||||
@msg no document δεν υπάρχει έγγραφο
|
||||
@msg no document open δεν υπάρχει ανοιχτό έγγραφο
|
||||
@msg no effect applied yet δεν έχει εφαρμοστεί ακόμη εφέ
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2071 and column 19.
|
@@ -4112,6 +4112,7 @@ axis Both Ambos
|
||||
@msg no current layer no hay capa actual
|
||||
@msg no data no hay datos
|
||||
@msg no dialog open no hay ningún cuadro de diálogo abierto
|
||||
@msg the open dialog has no Reset el cuadro de diálogo abierto no tiene el botón Restablecer
|
||||
@msg no document no hay documento
|
||||
@msg no document open no hay ningún documento abierto
|
||||
@msg no effect applied yet todavía no se aplicó ningún efecto
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4327,6 +4327,7 @@ imageTrace Outline Ääriviiva
|
||||
@msg no current layer ei nykyistä tasoa
|
||||
@msg no data ei dataa
|
||||
@msg no dialog open valintaikkunaa ei ole auki
|
||||
@msg the open dialog has no Reset avoimessa valintaikkunassa ei ole Palauta-painiketta
|
||||
@msg no document ei asiakirjaa
|
||||
@msg no document open asiakirjaa ei ole auki
|
||||
@msg no effect applied yet tehostetta ei ole vielä käytetty
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4109,6 +4109,7 @@ axis Both Les deux
|
||||
@msg no current layer aucun calque actif
|
||||
@msg no data aucune donnée
|
||||
@msg no dialog open aucune boîte de dialogue ouverte
|
||||
@msg the open dialog has no Reset la boîte de dialogue ouverte n’a pas de bouton Réinitialiser
|
||||
@msg no document aucun document
|
||||
@msg no document open aucun document ouvert
|
||||
@msg no effect applied yet aucun effet appliqué pour l’instant
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4772,6 +4772,7 @@ imageTrace Outline Körvonal
|
||||
@msg no current layer nincs aktuális réteg
|
||||
@msg no data nincs adat
|
||||
@msg no dialog open nincs nyitott párbeszédablak
|
||||
@msg the open dialog has no Reset a nyitott párbeszédablakban nincs Visszaállít gomb
|
||||
@msg no document nincs dokumentum
|
||||
@msg no document open nincs megnyitott dokumentum
|
||||
@msg no effect applied yet még nincs alkalmazott effektus
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4124,6 +4124,7 @@ imageTrace Outline Kontur
|
||||
@msg no current layer tidak ada lapisan saat ini
|
||||
@msg no data tidak ada data
|
||||
@msg no dialog open tidak ada dialog yang terbuka
|
||||
@msg the open dialog has no Reset dialog yang terbuka tidak memiliki tombol Atur ulang
|
||||
@msg no document tidak ada dokumen
|
||||
@msg no document open tidak ada dokumen yang terbuka
|
||||
@msg no effect applied yet belum ada efek yang diterapkan
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3862 and column 19.
|
@@ -4152,6 +4152,7 @@ axis Both Entrambi
|
||||
@msg no current layer nessun livello corrente
|
||||
@msg no data nessun dato
|
||||
@msg no dialog open nessuna finestra di dialogo aperta
|
||||
@msg the open dialog has no Reset la finestra di dialogo aperta non ha il pulsante Reimposta
|
||||
@msg no document nessun documento
|
||||
@msg no document open nessun documento aperto
|
||||
@msg no effect applied yet nessun effetto ancora applicato
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4552,6 +4552,7 @@ swatch Bright Violet ビビッドバイオレット
|
||||
@msg can't parse shortcut `{c}` ショートカット `{c}` を解釈できません
|
||||
@msg can't parse shortcut `{s}` for `{k}` `{k}` のショートカット `{s}` を解釈できません
|
||||
@msg no dialog open ダイアログが開かれていません
|
||||
@msg the open dialog has no Reset 開いているダイアログにはリセットボタンがありません
|
||||
@msg no file reader ファイルの読み込み機能がありません
|
||||
@msg no file writer ファイルの書き込み機能がありません
|
||||
@msg not a VectorCraft shortcut set (missing `overrides`) VectorCraft のショートカットセットではありません (`overrides` がありません)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3889,6 +3889,7 @@ font-technology Variable ცვლადი
|
||||
@msg no current layer მიმდინარე შრე არ არის
|
||||
@msg no data მონაცემები არ არის
|
||||
@msg no dialog open დიალოგი გახსნილი არ არის
|
||||
@msg the open dialog has no Reset გახსნილ დიალოგში ღილაკი ჩამოყრა არ არის
|
||||
@msg no document დოკუმენტი არ არის
|
||||
@msg no document open გახსნილი დოკუმენტი არ არის
|
||||
@msg no effect applied yet ეფექტი ჯერ არ გამოყენებულა
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4483,6 +4483,7 @@ theme Appearance 외관
|
||||
@msg can't parse shortcut `{c}` 단축키 `{c}`을(를) 해석할 수 없습니다
|
||||
@msg can't parse shortcut `{s}` for `{k}` `{k}`의 단축키 `{s}`을(를) 해석할 수 없습니다
|
||||
@msg no dialog open 열린 대화상자가 없습니다
|
||||
@msg the open dialog has no Reset 열린 대화상자에 재설정 단추가 없습니다
|
||||
@msg no file reader 파일 판독기가 없습니다
|
||||
@msg no file writer 파일 기록기가 없습니다
|
||||
@msg not a VectorCraft shortcut set (missing `overrides`) VectorCraft 단축키 세트가 아닙니다(`overrides`가 없음)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4136,6 +4136,7 @@ imageTrace Outline Contour
|
||||
@msg no current layer geen huidige laag
|
||||
@msg no data geen gegevens
|
||||
@msg no dialog open geen dialoogvenster geopend
|
||||
@msg the open dialog has no Reset het geopende dialoogvenster heeft geen knop Opnieuw instellen
|
||||
@msg no document geen document
|
||||
@msg no document open geen document geopend
|
||||
@msg no effect applied yet nog geen effect toegepast
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4239,6 +4239,7 @@ imageTrace Outline Kontur
|
||||
@msg no current layer brak bieżącej warstwy
|
||||
@msg no data brak danych
|
||||
@msg no dialog open brak otwartego okna dialogowego
|
||||
@msg the open dialog has no Reset otwarte okno dialogowe nie ma przycisku Resetuj
|
||||
@msg no document brak dokumentu
|
||||
@msg no document open brak otwartego dokumentu
|
||||
@msg no effect applied yet nie zastosowano jeszcze żadnego efektu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3685,6 +3685,7 @@ axis Both Ambos
|
||||
@msg no current layer nenhuma camada atual
|
||||
@msg no data sem dados
|
||||
@msg no dialog open nenhuma caixa de diálogo aberta
|
||||
@msg the open dialog has no Reset a caixa de diálogo aberta não tem o botão Redefinir
|
||||
@msg no document nenhum documento
|
||||
@msg no document open nenhum documento aberto
|
||||
@msg no effect applied yet nenhum efeito aplicado ainda
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -4148,6 +4148,7 @@ axis Both Оба
|
||||
@msg no current layer нет текущего слоя
|
||||
@msg no data нет данных
|
||||
@msg no dialog open нет открытого диалогового окна
|
||||
@msg the open dialog has no Reset в открытом диалоговом окне нет кнопки «Сбросить»
|
||||
@msg no document нет документа
|
||||
@msg no document open нет открытого документа
|
||||
@msg no effect applied yet эффект ещё не применён
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4026,6 +4026,7 @@ axis Both Båda
|
||||
@msg no current layer inget aktuellt lager
|
||||
@msg no data inga data
|
||||
@msg no dialog open ingen dialogruta är öppen
|
||||
@msg the open dialog has no Reset den öppna dialogrutan har ingen Återställ-knapp
|
||||
@msg no document inget dokument
|
||||
@msg no document open inget dokument är öppet
|
||||
@msg no effect applied yet ingen effekt har använts än
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3886,6 +3886,7 @@ axis Both Her İkisi
|
||||
@msg no current layer geçerli katman yok
|
||||
@msg no data veri yok
|
||||
@msg no dialog open iletişim kutusu açık değil
|
||||
@msg the open dialog has no Reset açık iletişim kutusunda Sıfırla düğmesi yok
|
||||
@msg no document belge yok
|
||||
@msg no document open hiçbir belge açık değil
|
||||
@msg no effect applied yet henüz hiçbir efekt uygulanmadı
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -4136,6 +4136,7 @@ axis Both Обидві
|
||||
@msg no current layer немає поточного шару
|
||||
@msg no data немає даних
|
||||
@msg no dialog open немає відкритого діалогового вікна
|
||||
@msg the open dialog has no Reset у відкритому діалоговому вікні немає кнопки «Скинути»
|
||||
@msg no document немає документа
|
||||
@msg no document open немає відкритого документа
|
||||
@msg no effect applied yet ефект ще не застосований
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 749 and column 40.
|
@@ -4420,6 +4420,7 @@ theme Appearance Giao diện
|
||||
@msg no current layer không có lớp hiện tại
|
||||
@msg no data không có dữ liệu
|
||||
@msg no dialog open không có hộp thoại đang mở
|
||||
@msg the open dialog has no Reset hộp thoại đang mở không có nút Đặt lại
|
||||
@msg no document không có tài liệu
|
||||
@msg no document open không có tài liệu nào đang mở
|
||||
@msg no effect applied yet chưa áp dụng hiệu ứng
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 4079 and column 10.
|
@@ -4277,6 +4277,7 @@ imageTrace Outline 轮廓
|
||||
@msg can't parse shortcut `{c}` 无法解析快捷键 `{c}`
|
||||
@msg can't parse shortcut `{s}` for `{k}` 无法解析 `{k}` 的快捷键 `{s}`
|
||||
@msg no dialog open 没有打开的对话框
|
||||
@msg the open dialog has no Reset 打开的对话框没有重置按钮
|
||||
@msg no file reader 没有文件读取器
|
||||
@msg no file writer 没有文件写入器
|
||||
@msg not a VectorCraft shortcut set (missing `overrides`) 不是 VectorCraft 快捷键组 (缺少 `overrides`)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2232,6 +2232,7 @@ file-filter Templates 範本
|
||||
@msg can't parse shortcut `{c}` 無法剖析快速鍵 `{c}`
|
||||
@msg can't parse shortcut `{s}` for `{k}` 無法剖析 `{k}` 的快速鍵 `{s}`
|
||||
@msg no dialog open 沒有開啟的對話框
|
||||
@msg the open dialog has no Reset 開啟的對話框沒有「重設」按鈕
|
||||
@msg no file reader 沒有檔案讀取器
|
||||
@msg no file writer 沒有檔案寫入器
|
||||
@msg not a VectorCraft shortcut set (missing `overrides`) 不是 VectorCraft 快速鍵組 (沒有 `overrides`)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -696,6 +696,7 @@ fn run_ui_part10(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<Result
|
||||
"ui.simplifyAuto" => crate::dialogs::simplify_slider::auto(app),
|
||||
"ui.simplifyMoreOptions" => crate::dialogs::simplify_slider::more_options(app),
|
||||
"ui.smoothAuto" => crate::dialogs::smooth_slider::auto(app),
|
||||
"ui.dialogReset" => crate::dialogs::reset(app),
|
||||
"attributes.openUrl" => crate::panels::attributes::open_url(app, p),
|
||||
"ui.javascriptFilesDialog" => crate::panels::svg_interactivity::files_dialog(app, p),
|
||||
"ui.spotColors" => crate::dialogs::spot_colors::open(app),
|
||||
|
||||
@@ -238,6 +238,7 @@ pub fn enabled(app: &VectorcraftApp, id: &str) -> bool {
|
||||
"ui.menuDialog" => app.session.active().is_some_and(|d| !d.selection.is_empty()),
|
||||
"ui.simplifyAuto" | "ui.simplifyMoreOptions" => crate::dialogs::simplify_slider::showing(app),
|
||||
"ui.smoothAuto" => crate::dialogs::smooth_slider::showing(app),
|
||||
"ui.dialogReset" => crate::dialogs::can_reset(app),
|
||||
"ui.dxfOptionsDialog" => app.session.active().is_some(),
|
||||
"links.editOriginal" | "links.reveal" => selected_image(app, |im| im.link.is_some()) || selected_placed(app),
|
||||
"ui.placementOptionsDialog" => selected_image(app, |_| true) || selected_placed(app),
|
||||
|
||||
@@ -595,7 +595,7 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
|
||||
"tool.options",
|
||||
"Tool Options…",
|
||||
"",
|
||||
"{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x and y, draws one there with them), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (pt), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values})",
|
||||
"{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x, y and preview (on initially), previews one there and accepts it as one Undo step; Cancel rolls back the preview), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (pt), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values})",
|
||||
),
|
||||
(
|
||||
"ui.colorGuideOptions",
|
||||
@@ -870,6 +870,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
|
||||
"",
|
||||
"{} the Simplify dialog (dialog `simplify`: tolerance (pt), angleThreshold, straightLines, showOriginal, retain: ticked, OK makes Object › Path › Simplify open this dialog with these fields next time) takes the open Simplify slider's place, at the slider's tolerance → {tolerance}; an error when the slider isn't open",
|
||||
),
|
||||
(
|
||||
"ui.dialogReset",
|
||||
"Reset",
|
||||
"",
|
||||
"{} the open dialog's Reset, which its Cancel button reads while Alt (Option on macOS) is held (Flare Tool Options, dialog `flareOptions`): its fields go back to their defaults and the dialog stays open, so OK applies them → the dialog; an error when no dialog is open or the open one has no Reset",
|
||||
),
|
||||
(
|
||||
"ui.justification",
|
||||
"Justification…",
|
||||
|
||||
+2
-1
@@ -645,8 +645,8 @@ trap, and the defaults (0.25 pt, 100%, 40%) are VectorCraft's own, the pages giv
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-26 | minor | G9: EPS save-back: an opened EPS saves back to its own path as EPS, keeping the chosen artboard's page frame and transparent margins and the complete editable VectorCraft document; Save's TIFF preview is capped at 1024 px (Export keeps 2048); partly read, preview-only or damaged-editing-data sources still need confirmation before they are overwritten. This narrows G9's save-back workflow only; its import-fidelity items (layer and group structure, guides, open speed, live objects) and estimate are unchanged, and writing Illustrator's own editing data stays out of scope (#868) |
|
||||
| 2026-10-29 | minor | G8: a blend makes at most 100,000 steps in all, the steps of blends nested in its keys and steps included; past it each pair of keys keeps the same share of its steps (#3579). No entry closed, estimates unchanged. |
|
||||
| 2026-10-26 | minor | G9: EPS save-back: an opened EPS saves back to its own path as EPS, keeping the chosen artboard's page frame and transparent margins and the complete editable VectorCraft document; Save's TIFF preview is capped at 1024 px (Export keeps 2048); partly read, preview-only or damaged-editing-data sources still need confirmation before they are overwritten. This narrows G9's save-back workflow only; its import-fidelity items (layer and group structure, guides, open speed, live objects) and estimate are unchanged, and writing Illustrator's own editing data stays out of scope (#868) |
|
||||
| 2026-10-26 | minor | G7: View › New View… / Edit Views… ([public source](https://helpx.adobe.com/illustrator/using/viewing-artwork.html)): the View menu lists every one of a document's 25 saved views (it listed 10), Edit Views… lists them to rename or delete in one undo step (`view.saved.edit {edits}`), and a file's views are checked when it opens; New View/Edit Views leave G7's missing list; estimate unchanged |
|
||||
| 2026-10-25 | minor | G4: a double-click on a threaded port with the Selection tool breaks the thread there (`text.thread.break {id, port}`): the story flows into the frames before the break, the frames after it are left empty and stay threaded with each other when two or more; a double-click on a port with no thread does nothing; estimate unchanged |
|
||||
| 2026-10-25 | minor | G1: a selected Grid Repeat shows handles: the one below the grid adds or removes rows, the one right of it columns, the one past its bottom-right corner both, and the sliders between the first two columns and rows set the horizontal and vertical spacing; each drag is one undo step and Escape cancels it (#2691); bounding-box handles keep priority where they meet; Radial Repeat handles remain; estimates unchanged. |
|
||||
@@ -829,6 +829,7 @@ trap, and the defaults (0.25 pt, 100%, 40%) are VectorCraft's own, the pages giv
|
||||
| 2026-10-10 | minor | G9 evidence counted from the tracker (28 `.ai`/EPS issues, 20 fixed); impact narrowed to handing files back |
|
||||
| 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 |
|
||||
| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. 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; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
|
||||
|
||||
|
||||
+4
-1
@@ -5051,7 +5051,9 @@ active the active artboard (the navigator's and the Artboards panel's).
|
||||
`tool.options {tool}` opens what double-clicking the tool's button opens (its params doc lists every tool), in the
|
||||
desktop app. The Flare tool's are its Flare Tool Options (dialog `flareOptions`): `diameter` and `pathLength` (pt),
|
||||
`opacity`, `brightness`, `growth`, `fuzziness`, `longest`, `rayFuzziness` and `largest` (%), `rays`, `rings`,
|
||||
`direction` (°), and `raysOn` and `ringsOn` (the Rays and Rings checkboxes; off, the flare has none). OK keeps them
|
||||
`direction` (°), and `raysOn` and `ringsOn` (the Rays and Rings checkboxes; off, the flare has none). While Alt
|
||||
(Option on macOS) is held, the dialog's Cancel button reads Reset. Reset puts every option back to the tool's default,
|
||||
leaves a click's `x` and `y` unchanged and keeps the dialog open; `ui.dialogReset` does the same. OK keeps the options
|
||||
(`tool.setOption {tool: "flare", values}`) and the next flare dragged out uses them; a click with the tool opens the
|
||||
same dialog, and its OK also draws a flare there. The Artboard tool's are the active artboard's Artboard Options
|
||||
(dialog `artboardOptions`; the Artboard tool's active artboard while it is in use, else the window's; its `x` and `y`
|
||||
@@ -5064,6 +5066,7 @@ for a new artboard, with `new: true` and the name, position and size that `artbo
|
||||
`artboard.new` with the fields and makes the new artboard the active one, and Cancel adds no artboard.
|
||||
`artboard.new` and `artboard.setProps` trim the white space around `name`, and a blank name gives the artboard its
|
||||
default name, "Artboard N" for the Nth artboard.
|
||||
A canvas-click dialog also has `preview` (initially on): tentative settings draw at the remembered click, Reset refreshes that preview, and Cancel discards it without persisting settings. OK accepts one flare as one Undo step. Toolbar-only options draw no artwork.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"tool.setOption","params":{"tool":"flare","values":{"rays":24,"ringsOn":false}}}}
|
||||
|
||||
@@ -278,6 +278,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
| 2026-10-10 | minor | M9 row from main: initial Revolve |
|
||||
| 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 |
|
||||
| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. 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; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
|
||||
|
||||
|
||||
@@ -598,6 +598,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- Preferences › Type › Highlight Substituted Fonts (on by default) paints pink behind text drawn in a substitute for a missing font in every document, and turning it off removes that highlight everywhere (`prefs.set highlightSubstitutedFonts`); Document Setup keeps Highlight Substituted Glyphs ([help](https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/edit-text-without-replacing-missing-fonts.html)).
|
||||
- Dialogs move by dragging their heading (the band down from the top edge, as a title bar), stay on screen and keep where they were moved for the session; the form dialogs' choices are dropdowns (Offset Path's Joins, Average's and Shear's and Reflect's axis), and Offset Path lists Offset, Joins, Miter Limit and previews (#423).
|
||||
- Dialogs open with their first field focused and its value selected: type a value and press Enter (Move, Rotate, Scale…). A dialog opened from a menu takes the keyboard focus every time it opens, not only the first (#1367), and one whose first field starts greyed out (Blend Options on Smooth Color, Layers Panel Options) gives the focus to that field once it is enabled (#1395). Number fields in panels, the Control bar and dialogs (preferences too) step with Up/Down, or with the mouse wheel over the focused field (#485: a notch a step; the panel under it then stays put, and an unfocused field leaves the wheel to scrolling) (Shift: ten, Ctrl/Cmd: a tenth of their unit), applied at once.
|
||||
- While Alt (Option on macOS) is held, the Flare Tool Options' Cancel button reads Reset, which puts every option back to the Flare tool's default and leaves the dialog open (`ui.dialogReset`).
|
||||
- A plain step of a number field (Up/Down or a wheel notch) goes to the next whole unit in its direction and a Ctrl/Cmd step goes to the next tenth, so 5.1 mm steps up to 6 mm and down to 5 mm (#2881). A Shift step adds or takes ten and keeps the fraction.
|
||||
- In the number, text and color fields of the panels and the Control bar, Shift+Enter (Shift+Return) applies the value and keeps the field active with its value selected; a text box of several lines takes it as a line break. In a dialog, Shift+Enter applies the value and confirms the dialog, as Enter does.
|
||||
- The Pattern Options panel's Name field and the name fields that a double-click opens in the Layers, Artboards and Asset Export panels take Shift+Enter (Shift+Return) the same way: it applies the name and keeps the field active with the name selected.
|
||||
@@ -1426,6 +1427,7 @@ applies to fills). Tests: `color::gradient::tests` (perceptual midpoint, expansi
|
||||
| 2026-10-10 | major | Full re-measure against Illustrator 2026 30.x from code counts, open issues and public docs; added breadth/depth/ready-for-real-work numbers, generative-AI row, calibration from PR timestamps; merged the ROADMAP's parity estimate, honest assessment and "Shipped so far" into this file |
|
||||
| 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 |
|
||||
| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. 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; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
|
||||
|
||||
|
||||
@@ -485,6 +485,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
| 2026-10-11 | minor | Edit Toolbar opens the All Tools drawer beside the toolbar instead of a centred dialog, dims the tools the toolbar holds, and edits the toolbar by drag and drop while it is open (#1018); score unchanged (estimated) |
|
||||
| 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 |
|
||||
| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. 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; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user