Merge pull request #2497 from dotCooCoo/feat/artboard-tool-shift

Artboard tool: Shift-drag draws an artboard inside another or marquee-selects artboards
This commit is contained in:
BFlat
2026-10-21 17:34:00 +07:00
committed by GitHub
27 changed files with 262 additions and 43 deletions
+3 -2
View File
@@ -1260,8 +1260,9 @@ impl Leave {
}
}
/// A box dragged from its corner or centre `at` (Rectangle, Ellipse, Arc, the grids,
/// Artboard): Shift keeps the dragged corner on a diagonal, the box a square.
/// A box dragged from its corner or centre `at` (Rectangle, Ellipse, Arc, the grids, and
/// Artboard, which passes no Shift): Shift keeps the dragged corner on a diagonal, the box a
/// square.
pub fn diagonal(at: Point, shift: bool) -> Self {
Self { at, shift: shift.then_some(Keep::Square), angles: &[] }
}
+202 -18
View File
@@ -6,13 +6,14 @@
//! Double-click an empty part of an artboard to open Artboard Options. Click an empty
//! part of an artboard to make it active (dashed bounds, 8 handles and its name); Shift-click adds
//! artboards to the selection or takes them out (dashed bounds), and a drag or Delete then acts on
//! all of them (#1139). Drag inside moves
//! it (with its artwork when the `moveArt` option is on, Shift constrains; Alt moves a copy and
//! all of them (#1139). Shift-drag inside an artboard draws a new artboard there, and Shift-drag on
//! the pasteboard is a marquee: the artboards it touches leave the selection or join it. Drag inside
//! moves it (with its artwork when the `moveArt` option is on; Alt moves a copy and
//! leaves the artboard where it was), drag a handle resizes it
//! (Shift proportional, Alt from centre; with the `scaleArt` option on, Scale Artwork with Artboard,
//! always proportional, and the art fully inside scales with it), drag on the pasteboard draws a new artboard, Delete removes
//! the active one (Copy, Cut and Paste take it with its art: `artboard.copy`) and Escape returns to
//! the Selection tool. Moving and resizing snap like drawing
//! the Selection tool (during a drag it only cancels the drag). Moving and resizing snap like drawing
//! does: to whole pixels, to the grid, or with Smart Guides to other artboards, their bleed and
//! objects (never to the dragged artboard or the art moving or scaling with it); the artboard's own bleed edges
//! snap too. A new artboard's corners snap as drawn points do ([`DrawSnap`]).
@@ -21,7 +22,7 @@ use serde_json::{Value, json};
use vectorcraft_geom::{Affine, Point, Rect, Vec2};
use super::{BLUE, polygon, rect_corners};
use crate::bbox::{Handle, hit_handle, move_delta, scale_for_drag};
use crate::bbox::{Handle, hit_handle, scale_for_drag};
use crate::guides::{DrawSnap, Leave, Targets};
use crate::{Action, Cursor, Mods, Overlay, PointerEvent, PointerKind, Tool, ToolContext, ToolKey};
@@ -50,6 +51,13 @@ enum Drag {
Create {
start: Point,
cur: Point,
/// A Shift-press inside an artboard (its index and the pressed point): released without
/// being dragged, it toggles that artboard.
toggle: Option<(usize, Point)>,
},
Marquee {
start: Point,
cur: Point,
},
}
@@ -133,6 +141,30 @@ impl ArtboardTool {
self.others = sel.into_iter().filter(|j| *j != self.active).collect();
}
/// A Shift-drag marquee `r`: the artboards it touches leave the selection when they are in
/// it and join it otherwise, the last one joining becoming active. One artboard always stays
/// selected.
fn toggle_touched(&mut self, cx: &ToolContext, r: Rect) {
let touched: Vec<usize> = cx
.doc
.artboards
.iter()
.enumerate()
.filter(|(_, a)| r.x0 <= a.rect.x1 && a.rect.x0 <= r.x1 && r.y0 <= a.rect.y1 && a.rect.y0 <= r.y1)
.map(|(i, _)| i)
.collect();
let sel = self.selected(cx);
let added: Vec<usize> = touched.iter().copied().filter(|i| !sel.contains(i)).collect();
let kept: Vec<usize> = sel.into_iter().filter(|i| !touched.contains(i)).chain(added.iter().copied()).collect();
let Some(&first) = kept.first() else { return };
self.active = match added.last() {
Some(i) => *i,
None if kept.contains(&self.active) => self.active,
None => first,
};
self.others = kept.into_iter().filter(|j| *j != self.active).collect();
}
/// Gather the Smart Guide targets for dragging artboard `index` (call before the first preview,
/// while the document still shows where everything started).
fn begin_snapping(&mut self, cx: &ToolContext, index: usize, art_moves: bool) {
@@ -268,12 +300,23 @@ impl Tool for ArtboardTool {
// artboard command's minimum side or pass non-finite bounds to it.
self.click_art = fittable_bounds(cx, p).map(|r| (p, r));
}
if m.shift {
// Shift-drag inside an artboard draws a new one there, and a Shift-click
// toggles the artboard on release. Shift-drag outside every artboard is a
// marquee: the artboards it touches toggle on release.
match cx.doc.artboard_at(p) {
Some(i) => {
let start = self.draw.press(cx, p, &[], None);
self.drag = Some(Drag::Create { start, cur: start, toggle: Some((i, p)) });
}
None => self.drag = Some(Drag::Marquee { start: p, cur: p }),
}
return vec![];
}
if let Some(i) = cx.doc.artboard_at(p)
&& let Some(a) = cx.doc.artboards.get(i)
{
if m.shift {
self.toggle(cx, i);
} else if !self.selected(cx).contains(&i) {
if !self.selected(cx).contains(&i) {
// A plain click on an artboard that isn't selected selects just it; on a
// selected one, the selection stays, so the drag moves them all.
self.others.clear();
@@ -284,7 +327,7 @@ impl Tool for ArtboardTool {
} else {
self.others.clear();
let p = self.draw.press(cx, p, &[], None);
self.drag = Some(Drag::Create { start: p, cur: p });
self.drag = Some(Drag::Create { start: p, cur: p, toggle: None });
}
vec![]
}
@@ -303,7 +346,7 @@ impl Tool for ArtboardTool {
out.push(Action::Begin(label(m.alt).into()));
}
self.drag = Some(Drag::Move { index, many, start, rect, began: true, copy: m.alt });
let d = self.snap_move(cx, rect, move_delta(start, p, m.shift), m.alt);
let d = self.snap_move(cx, rect, p - start, m.alt);
self.preview = Some(rect + d);
let mut v = json!({ "index": index, "dx": d.x, "dy": d.y, "moveArt": self.move_art, "copy": m.alt });
if many {
@@ -333,9 +376,13 @@ impl Tool for ArtboardTool {
out.push(Action::Preview("artboard.setProps".into(), v));
out
}
(PointerKind::Drag, Some(Drag::Create { start, .. })) => {
let cur = self.draw.drag(cx, p, Some(&Leave::diagonal(start, m.shift)));
self.drag = Some(Drag::Create { start, cur });
(PointerKind::Drag, Some(Drag::Create { start, toggle, .. })) => {
let cur = self.draw.drag(cx, p, Some(&Leave::diagonal(start, false)));
self.drag = Some(Drag::Create { start, cur, toggle });
vec![]
}
(PointerKind::Drag, Some(Drag::Marquee { start, .. })) => {
self.drag = Some(Drag::Marquee { start, cur: p });
vec![]
}
(PointerKind::Up, Some(d)) => {
@@ -361,7 +408,18 @@ impl Tool for ArtboardTool {
vec![Action::Commit]
}
Drag::Resize { began: true, .. } => vec![Action::Commit],
Drag::Create { start, cur } => {
Drag::Create { toggle: Some((i, at)), .. } if p.distance(at) < cx.tol(3.0) => {
self.toggle(cx, i);
vec![]
}
Drag::Marquee { start, .. } => {
let r = Rect::from_points(start, p);
if r.width() >= cx.tol(3.0) || r.height() >= cx.tol(3.0) {
self.toggle_touched(cx, r);
}
vec![]
}
Drag::Create { start, cur, .. } => {
let r = Rect::from_points(start, cur);
if r.width() < cx.tol(3.0) || r.height() < cx.tol(3.0) {
return vec![];
@@ -420,9 +478,18 @@ impl Tool for ArtboardTool {
vec![Action::Exec("artboard.delete".into(), params)]
}
ToolKey::Escape => {
let busy = matches!(self.drag, Some(Drag::Move { began: true, .. } | Drag::Resize { began: true, .. }));
// During any drag (a move, a resize, a new artboard or a marquee) Escape only
// cancels the gesture; the next one leaves the tool.
let dragging = self.drag.is_some();
let previewed = matches!(self.drag, Some(Drag::Move { began: true, .. } | Drag::Resize { began: true, .. }));
self.end_drag();
if busy { vec![Action::Cancel] } else { vec![Action::SwitchTool("selection".into())] }
if previewed {
vec![Action::Cancel]
} else if dragging {
vec![]
} else {
vec![Action::SwitchTool("selection".into())]
}
}
_ => vec![],
}
@@ -437,7 +504,7 @@ impl Tool for ArtboardTool {
fn overlays(&self, cx: &ToolContext) -> Vec<Overlay> {
let mut o = vec![];
if let Some(Drag::Create { start, cur }) = self.drag {
if let Some(Drag::Create { start, cur, .. }) = self.drag {
o.extend_from_slice(self.draw.guides());
let r = Rect::from_points(start, cur);
o.push(Overlay::Marquee(r));
@@ -446,6 +513,9 @@ impl Tool for ArtboardTool {
}
return o;
}
if let Some(Drag::Marquee { start, cur }) = self.drag {
o.push(Overlay::Marquee(Rect::from_points(start, cur)));
}
// The other selected artboards: dashed bounds (in a drag the document shows them moved).
for r in self.others.iter().filter_map(|i| cx.doc.artboards.get(*i)).map(|a| a.rect) {
o.push(Overlay::Path { path: polygon(&rect_corners(r), true), color: BLUE, width: 1.0, dashed: true });
@@ -472,7 +542,7 @@ impl Tool for ArtboardTool {
o
}
fn cursor(&self, cx: &ToolContext, p: Point, _m: Mods) -> Cursor {
fn cursor(&self, cx: &ToolContext, p: Point, m: Mods) -> Cursor {
if let Some(r) = self.active_rect(cx)
&& let Some(h) = hit_handle(r, p, cx.tol(5.0))
{
@@ -484,7 +554,8 @@ impl Tool for ArtboardTool {
}
.turned(cx.view_angle());
}
if cx.doc.artboard_at(p).is_some() { Cursor::Move } else { Cursor::Crosshair }
// With Shift a drag draws or selects, never moves.
if !m.shift && cx.doc.artboard_at(p).is_some() { Cursor::Move } else { Cursor::Crosshair }
}
fn options(&self) -> Value {
@@ -703,6 +774,119 @@ mod tests {
assert_eq!(t.options()["selected"], json!([2]));
}
/// A Shift-click toggles its artboard when the button comes up, so the press alone leaves the
/// selection as it was.
#[test]
fn a_shift_click_toggles_its_artboard_on_release() {
let d = two_boards();
let (s, p) = (Selection::default(), paint());
let c = cx(&d, &s, &p);
let shift = Mods { shift: true, ..Default::default() };
let mut t = ArtboardTool::default();
assert_eq!(t.pointer(&c, &ev(PointerKind::Down, 700.0, 100.0).with_mods(shift)), vec![]);
assert_eq!(t.options()["selected"], json!([0]), "the press alone selects nothing");
assert_eq!(t.pointer(&c, &ev(PointerKind::Up, 701.0, 100.0).with_mods(shift)), vec![]);
assert_eq!(t.options()["selected"], json!([1, 0]));
for kind in [PointerKind::Down, PointerKind::Up] {
t.pointer(&c, &ev(kind, 700.0, 100.0).with_mods(shift));
}
assert_eq!(t.options()["selected"], json!([0]), "a second Shift-click takes it out");
}
/// Shift-drag inside an artboard draws a new artboard there, neither square nor moving the
/// artboard it starts in, and the cursor shows a crosshair while Shift is held.
#[test]
fn a_shift_drag_inside_an_artboard_draws_a_new_one() {
let d = two_boards();
let (s, p) = (Selection::default(), paint());
let mut c = cx(&d, &s, &p);
c.smart_guides = false;
let shift = Mods { shift: true, ..Default::default() };
let mut t = ArtboardTool::default();
assert_eq!(t.cursor(&c, Point::new(300.0, 300.0), Mods::default()), Cursor::Move);
assert_eq!(t.cursor(&c, Point::new(300.0, 300.0), shift), Cursor::Crosshair);
assert_eq!(t.pointer(&c, &ev(PointerKind::Down, 300.0, 300.0).with_mods(shift)), vec![]);
assert_eq!(t.pointer(&c, &ev(PointerKind::Drag, 420.0, 380.0).with_mods(shift)), vec![], "no move preview");
assert!(matches!(t.overlays(&c)[0], Overlay::Marquee(_)));
let a = t.pointer(&c, &ev(PointerKind::Up, 420.0, 380.0).with_mods(shift));
assert_eq!(a, create_artboard(Rect::new(300.0, 300.0, 420.0, 380.0)));
assert_eq!(t.options()["selected"], json!([0]), "the artboard drawn in is not toggled");
}
/// Shift-drag on the pasteboard is a marquee: the artboards it touches leave the selection
/// or join it, the last one joining becoming active, and no artboard is drawn.
#[test]
fn a_shift_drag_on_the_pasteboard_selects_the_artboards_it_touches() {
let mut d = two_boards();
let mut third = d.artboards[0].clone();
third.rect = Rect::new(0.0, 600.0, 200.0, 800.0);
d.artboards.push(third);
let (s, p) = (Selection::default(), paint());
let c = cx(&d, &s, &p);
let shift = Mods { shift: true, ..Default::default() };
let mut t = ArtboardTool::default();
let marquee = |t: &mut ArtboardTool, from: (f64, f64), to: (f64, f64)| {
assert_eq!(t.pointer(&c, &ev(PointerKind::Down, from.0, from.1).with_mods(shift)), vec![]);
assert_eq!(t.pointer(&c, &ev(PointerKind::Drag, to.0, to.1).with_mods(shift)), vec![]);
assert!(t.overlays(&c).iter().any(|o| matches!(o, Overlay::Marquee(_))));
t.pointer(&c, &ev(PointerKind::Up, to.0, to.1).with_mods(shift))
};
// From between the artboards across Artboard 1 (selected) and Artboard 3: 1 leaves, 3 joins.
assert_eq!(marquee(&mut t, (550.0, 150.0), (150.0, 650.0)), vec![]);
assert_eq!(t.options()["selected"], json!([2]));
// Right of Artboard 2 across its corner: it joins and becomes active.
assert_eq!(marquee(&mut t, (850.0, -50.0), (700.0, 100.0)), vec![]);
assert_eq!(t.options()["selected"], json!([1, 2]));
// A Shift-click on the pasteboard changes nothing.
assert_eq!(marquee(&mut t, (550.0, 150.0), (551.0, 150.0)), vec![]);
assert_eq!(t.options()["selected"], json!([1, 2]));
}
/// A drag begun without Shift still moves the artboard, and on the pasteboard still draws one;
/// Shift pressed during either no longer keeps the move at 45° or the new artboard square.
#[test]
fn a_plain_drag_still_moves_and_shift_no_longer_constrains_it() {
let d = two_boards();
let (s, p) = (Selection::default(), paint());
let mut c = cx(&d, &s, &p);
c.smart_guides = false;
let shift = Mods { shift: true, ..Default::default() };
let mut t = ArtboardTool::default();
t.pointer(&c, &ev(PointerKind::Down, 700.0, 100.0));
let v = preview_params(&t.pointer(&c, &ev(PointerKind::Drag, 730.0, 110.0).with_mods(shift)));
assert_eq!((v["index"].as_u64(), v["dx"].as_f64(), v["dy"].as_f64()), (Some(1), Some(30.0), Some(10.0)));
assert_eq!(t.pointer(&c, &ev(PointerKind::Up, 730.0, 110.0).with_mods(shift)), vec![Action::Commit]);
t.pointer(&c, &ev(PointerKind::Down, 1000.0, 1000.0));
t.pointer(&c, &ev(PointerKind::Drag, 1100.0, 1050.0).with_mods(shift));
let a = t.pointer(&c, &ev(PointerKind::Up, 1100.0, 1050.0).with_mods(shift));
assert_eq!(a, create_artboard(Rect::new(1000.0, 1000.0, 1100.0, 1050.0)));
}
/// Escape during a marquee or while a new artboard is being drawn ends the gesture without
/// selecting or drawing anything and keeps the tool; the next Escape leaves it.
#[test]
fn escape_cancels_a_marquee_or_a_new_artboard_and_keeps_the_tool() {
let d = two_boards();
let (s, p) = (Selection::default(), paint());
let mut c = cx(&d, &s, &p);
c.smart_guides = false;
let shift = Mods { shift: true, ..Default::default() };
let mut t = ArtboardTool::default();
// A Shift-drag marquee on the pasteboard, a Shift-drag inside Artboard 1 and a plain drag on
// the pasteboard.
let drags =
[((850.0, -50.0), (700.0, 100.0), shift), ((300.0, 300.0), (420.0, 380.0), shift), ((1000.0, 1000.0), (1100.0, 1050.0), Mods::default())];
for (from, to, mods) in drags {
t.pointer(&c, &ev(PointerKind::Down, from.0, from.1).with_mods(mods));
t.pointer(&c, &ev(PointerKind::Drag, to.0, to.1).with_mods(mods));
assert_eq!(t.key(&c, ToolKey::Escape, Mods::default()), vec![], "Escape from {from:?} only ends the gesture");
assert!(!t.busy());
assert_eq!(t.pointer(&c, &ev(PointerKind::Up, to.0, to.1).with_mods(mods)), vec![], "the release draws nothing");
assert_eq!(t.options()["selected"], json!([0]), "the release selects nothing");
}
assert_eq!(t.key(&c, ToolKey::Escape, Mods::default()), vec![Action::SwitchTool("selection".into())]);
}
/// Scale Artwork with Artboard (#602): the resize asks for the art to scale, keeps the artboard's
/// proportions, and never snaps to the art scaling with it.
#[test]
+8 -1
View File
@@ -972,7 +972,14 @@ fn hint_for(tool: &str) -> Option<&'static [(&'static str, bool)]> {
(" to sample a color", false),
],
"gradient" => &[("Drag", true), (" across a selected object to set the gradient direction", false)],
"artboard" => &[("Click", true), (" to select an artboard | ", false), ("Drag", true), (" on the canvas to create one", false)],
"artboard" => &[
("Click", true),
(" to select an artboard | ", false),
("Drag", true),
(" on the canvas to create one (", false),
("Shift", true),
(" selects several, or draws one inside an artboard)", false),
],
"width" => &[
("Drag", true),
(" a stroke to add a width point | ", false),
+2 -1
View File
@@ -3555,7 +3555,8 @@ imageTrace Outline Контур
to sample a color за вземане на проба от цвят
across a selected object to set the gradient direction през избран обект за задаване посоката на градиента
to select an artboard | за избор на работна област |
on the canvas to create one върху платното за създаване на такава
on the canvas to create one ( върху платното за създаване на такава (
selects several, or draws one inside an artboard) избира няколко или създава нова в работна област)
a stroke to add a width point | щрих за добавяне на точка за дебелина |
to change one side | за промяна на една страна |
to select more points | за избор на още точки |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -1136,7 +1136,8 @@ lighting Light Světlo
to sample a color nabere barvu
across a selected object to set the gradient direction přes vybraný objekt nastaví směr přechodu
to select an artboard | vybere pracovní plochu |
on the canvas to create one na plátně vytvoří novou
on the canvas to create one ( na plátně vytvoří novou (
selects several, or draws one inside an artboard) vybere více nebo vytvoří novou uvnitř pracovní plochy)
a stroke to add a width point | tahu přidá bod šířky |
to change one side | změní jednu stranu |
to select more points | vybere další body |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -1057,7 +1057,8 @@ lighting Light Lys
to sample a color for at tage en farveprøve
across a selected object to set the gradient direction hen over et markeret objekt for at angive gradientretningen
to select an artboard | for at markere et tegnebræt |
on the canvas to create one på canvaset for at oprette et
on the canvas to create one ( på canvaset for at oprette et (
selects several, or draws one inside an artboard) markerer flere eller opretter et inde i et tegnebræt)
a stroke to add a width point | på en kontur for at tilføje et breddepunkt |
to change one side | for at ændre den ene side |
to select more points | for at markere flere punkter |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -3546,7 +3546,8 @@ imageTrace Outline Kontur
to sample a color nimmt eine Farbe auf
across a selected object to set the gradient direction über ein ausgewähltes Objekt legt die Verlaufsrichtung fest
to select an artboard | wählt eine Zeichenfläche aus |
on the canvas to create one auf der Arbeitsfläche erstellt eine neue
on the canvas to create one ( auf der Arbeitsfläche erstellt eine neue (
selects several, or draws one inside an artboard) wählt mehrere aus oder erstellt eine neue in einer Zeichenfläche)
a stroke to add a width point | an einer Kontur fügt einen Breitenpunkt hinzu |
to change one side | ändert nur eine Seite |
to select more points | wählt weitere Punkte aus |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -4821,7 +4821,8 @@ theme Appearance Εμφάνιση
to sample a color για δειγματοληψία χρώματος
across a selected object to set the gradient direction κατά μήκος επιλεγμένου αντικειμένου για ορισμό κατεύθυνσης ντεγκραντέ
to select an artboard | για επιλογή πίνακα σχεδίασης |
on the canvas to create one στον καμβά για δημιουργία ενός
on the canvas to create one ( στον καμβά για δημιουργία ενός (
selects several, or draws one inside an artboard) επιλέγει πολλούς ή δημιουργεί νέο μέσα σε πίνακα σχεδίασης)
a stroke to add a width point | περίγραμμα για προσθήκη σημείου πλάτους |
to change one side | για αλλαγή μίας πλευράς |
to select more points | για επιλογή περισσότερων σημείων |
Can't render this file because it contains an unexpected character in line 2021 and column 19.
+2 -1
View File
@@ -3614,7 +3614,8 @@ imageTrace Outline Contorno
to sample a color para muestrear un color
across a selected object to set the gradient direction sobre un objeto seleccionado para definir la dirección del degradado
to select an artboard | para seleccionar una mesa de trabajo |
on the canvas to create one en el lienzo para crear una
on the canvas to create one ( en el lienzo para crear una (
selects several, or draws one inside an artboard) selecciona varias o crea una dentro de una mesa de trabajo)
a stroke to add a width point | un trazo para agregar un punto de anchura |
to change one side | para cambiar un solo lado |
to select more points | para seleccionar más puntos |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -1114,7 +1114,8 @@ lighting Light Valo
to sample a color ottaaksesi värinäytteen
across a selected object to set the gradient direction valitun objektin poikki asettaaksesi liukuvärin suunnan
to select an artboard | valitaksesi piirtoalustan |
on the canvas to create one kankaalla luodaksesi uuden
on the canvas to create one ( kankaalla luodaksesi uuden (
selects several, or draws one inside an artboard) valitsee useita tai luo uuden piirtoalustan sisään)
a stroke to add a width point | viivaa lisätäksesi leveyspisteen |
to change one side | muuttaaksesi yhtä puolta |
to select more points | valitaksesi lisää pisteitä |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -3611,7 +3611,8 @@ imageTrace Outline Contour
to sample a color pour prélever une couleur
across a selected object to set the gradient direction sur un objet sélectionné pour définir la direction du dégradé
to select an artboard | pour sélectionner un plan de travail |
on the canvas to create one sur la zone de travail pour en créer un
on the canvas to create one ( sur la zone de travail pour en créer un (
selects several, or draws one inside an artboard) en sélectionne plusieurs ou en crée un dans un plan de travail)
a stroke to add a width point | sur un contour pour ajouter un point de largeur |
to change one side | pour modifier un seul côté |
to select more points | pour sélectionner d’autres points |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -38,7 +38,8 @@
from center | – rajzolás a középpontból |
keeps its proportions) – arányok megtartása)
near a selected pin to rotate | egy kijelölt tű közelében – forgatás |
on the canvas to create one a vásznon – új rajztábla
on the canvas to create one ( a vásznon – új rajztábla (
selects several, or draws one inside an artboard) – több kijelölése, vagy új rajztábla egy rajztáblán belül)
over paths to roughen their outlines | útvonalakon – a körvonaluk eldurvítása |
over paths, and hold still to keep going | útvonalakon – nyomva tartva folytatódik |
right or left to zoom in or out | jobbra vagy balra – nagyítás vagy kicsinyítés |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -1057,7 +1057,8 @@ lighting Light Cahaya
to sample a color untuk mengambil sampel warna
across a selected object to set the gradient direction melintasi objek terpilih untuk mengatur arah gradien
to select an artboard | untuk memilih artboard |
on the canvas to create one di kanvas untuk membuatnya
on the canvas to create one ( di kanvas untuk membuatnya (
selects several, or draws one inside an artboard) memilih beberapa, atau membuat satu di dalam artboard)
a stroke to add a width point | stroke untuk menambah titik lebar |
to change one side | untuk mengubah satu sisi |
to select more points | untuk memilih lebih banyak titik |
1 # Indonesian (id) catalog. Same format as zh-hant.tsv: context <TAB> source <TAB> translation
1057
1058
1059
1060
1061
1062
1063
1064
+2 -1
View File
@@ -3649,7 +3649,8 @@ imageTrace Outline Contorno
to sample a color per campionare un colore
across a selected object to set the gradient direction su un oggetto selezionato per impostare la direzione della sfumatura
to select an artboard | per selezionare una tavola da disegno |
on the canvas to create one sull'area di disegno per crearne una
on the canvas to create one ( sull'area di disegno per crearne una (
selects several, or draws one inside an artboard) ne seleziona più d'una o ne crea una dentro una tavola da disegno)
a stroke to add a width point | su una traccia per aggiungere un punto di larghezza |
to change one side | per modificare un solo lato |
to select more points | per selezionare altri punti |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -747,7 +747,8 @@
from center | :中心から描画 |
keeps its proportions) :縦横比を固定)
near a selected pin to rotate | :選択したピンの近くで回転 |
on the canvas to create one :アートボードを作成
on the canvas to create one ( :アートボードを作成(
selects several, or draws one inside an artboard) :複数を選択、またはアートボード内に作成)
over paths to roughen their outlines | :パスの輪郭を粗くする |
over paths, and hold still to keep going | :パス上で押し続けると効果が続く |
the art to add a pin | :アートにピンを追加 |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5213,3 +5213,7 @@ imageTrace Outline კონტური
Note Paper ჩანაწერების ქაღალდი
Water Paper… სველი ქაღალდი…
Water Paper სველი ქაღალდი
# Artboard tool hints (#2497)
on the canvas to create one ( ტილოზე — ახლის შესაქმნელად (
selects several, or draws one inside an artboard) რამდენიმეს მონიშნავს ან ახალს სამუშაო დაფის შიგნით ხატავს)
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -742,7 +742,8 @@
from center | 중심에서 |
keeps its proportions) 비율 유지)
near a selected pin to rotate | 선택한 핀 근처에서 회전 |
on the canvas to create one 캔버스에서 만들기
on the canvas to create one ( 캔버스에서 만들기 (
selects several, or draws one inside an artboard) 여러 개 선택 또는 아트보드 안에 만들기)
over paths to roughen their outlines | 패스 위에서 윤곽선 거칠게 만들기 |
over paths, and hold still to keep going | 패스 위에서 멈춰 있으면 계속 진행 |
the art to add a pin | 아트워크를 클릭하여 핀 추가 |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -1071,7 +1071,8 @@ lighting Light Licht
to sample a color om een kleur over te nemen
across a selected object to set the gradient direction over een geselecteerd object om de richting van het verloop in te stellen
to select an artboard | om een tekengebied te selecteren |
on the canvas to create one op het canvas om er een te maken
on the canvas to create one ( op het canvas om er een te maken (
selects several, or draws one inside an artboard) selecteert er meerdere of maakt er een binnen een tekengebied)
a stroke to add a width point | op een lijn om een breedtepunt toe te voegen |
to change one side | om één kant te wijzigen |
to select more points | om meer punten te selecteren |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -1067,7 +1067,8 @@ lighting Light Światło
to sample a color aby pobrać próbkę koloru
across a selected object to set the gradient direction przez zaznaczony obiekt, aby ustawić kierunek gradientu
to select an artboard | aby zaznaczyć obszar kompozycji |
on the canvas to create one na płótnie, aby go utworzyć
on the canvas to create one ( na płótnie, aby go utworzyć (
selects several, or draws one inside an artboard) zaznacza kilka lub tworzy nowy wewnątrz obszaru kompozycji)
a stroke to add a width point | obrys, aby dodać punkt szerokości |
to change one side | aby zmienić jedną stronę |
to select more points | aby zaznaczyć więcej punktów |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -40,7 +40,8 @@
from center | do centro |
keeps its proportions) mantém suas proporções)
near a selected pin to rotate | perto de um pino selecionado para girar |
on the canvas to create one na tela para criar um
on the canvas to create one ( na tela para criar um (
selects several, or draws one inside an artboard) seleciona várias ou cria uma dentro de uma mesa de trabalho)
over paths to roughen their outlines | sobre caminhos para enrugar seus contornos |
over paths, and hold still to keep going | sobre caminhos, e mantenha parado para continuar |
the art to add a pin | a arte para adicionar um pino |
Can't render this file because it contains an unexpected character in line 6 and column 47.
+2 -1
View File
@@ -3645,7 +3645,8 @@ imageTrace Outline Контур
to sample a color для взятия образца цвета
across a selected object to set the gradient direction по выделенному объекту для задания направления градиента
to select an artboard | для выбора монтажной области |
on the canvas to create one на холсте для создания одной
on the canvas to create one ( на холсте для создания одной (
selects several, or draws one inside an artboard) выбирает несколько или создаёт новую внутри монтажной области)
a stroke to add a width point | обводку для добавления точки ширины |
to change one side | для изменения одной стороны |
to select more points | для выделения большего числа точек |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -3555,7 +3555,8 @@ imageTrace Outline Disposition
to sample a color för att hämta en färg
across a selected object to set the gradient direction över ett markerat objekt för att ange gradientens riktning
to select an artboard | för att markera en rityta |
on the canvas to create one på arbetsytan för att skapa en
on the canvas to create one ( på arbetsytan för att skapa en (
selects several, or draws one inside an artboard) markerar flera eller skapar en ny i en rityta)
a stroke to add a width point | en kontur för att lägga till en breddpunkt |
to change one side | för att ändra en sida |
to select more points | för att markera fler punkter |
Can't render this file because it contains an unexpected character in line 5 and column 25.
+2 -1
View File
@@ -3642,7 +3642,8 @@ imageTrace Outline Контур
to sample a color для взяття зразка кольору
across a selected object to set the gradient direction по виділеному об’єкту, щоб задати напрям градієнта
to select an artboard | для вибору монтажної області |
on the canvas to create one на полотні для створення однієї
on the canvas to create one ( на полотні для створення однієї (
selects several, or draws one inside an artboard) вибирає кілька або створює нову всередині монтажної області)
a stroke to add a width point | обведення для додавання точки ширини |
to change one side | для зміни однієї сторони |
to select more points | для виділення інших точок |
Can't render this file because it contains an unexpected character in line 726 and column 40.
+2 -1
View File
@@ -24,7 +24,8 @@
from center | từ tâm |
keeps its proportions) giữ nguyên tỷ lệ)
near a selected pin to rotate | gần ghim đã chọn để xoay |
on the canvas to create one trên vùng vẽ để tạo một cái
on the canvas to create one ( trên vùng vẽ để tạo một cái (
selects several, or draws one inside an artboard) chọn nhiều cái hoặc tạo cái mới bên trong bảng vẽ)
over paths to roughen their outlines | qua đường dẫn để làm thô đường bao |
over paths, and hold still to keep going | qua đường dẫn và giữ yên để tiếp tục |
right or left to zoom in or out | sang phải hoặc trái để phóng to hoặc thu nhỏ |
1 # Vietnamese (vi) catalog. Same format as zh-hant.tsv: context <TAB> source <TAB> translation
24
25
26
27
28
29
30
31
+2 -1
View File
@@ -3503,7 +3503,8 @@ imageTrace Outline 轮廓
to sample a color 以取样颜色
across a selected object to set the gradient direction 横跨所选对象以设置渐变方向
to select an artboard | 以选择画板 |
on the canvas to create one 在画布上以创建画板
on the canvas to create one ( 在画布上以创建画板 (
selects several, or draws one inside an artboard) 可选择多个,或在画板内创建画板)
a stroke to add a width point | 描边可添加宽度点 |
to change one side | 可只更改单侧 |
to select more points | 可选择更多点 |
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2 -1
View File
@@ -4401,7 +4401,8 @@ imageTrace Outline 輪廓
to sample a color 可取樣顏色
across a selected object to set the gradient direction 橫越所選物件可設定漸層方向
to select an artboard | 可選取工作區域 |
on the canvas to create one 畫布可建立工作區域
on the canvas to create one ( 畫布可建立工作區域 (
selects several, or draws one inside an artboard) 可選取多個,或在工作區域內建立工作區域)
a stroke to add a width point | 筆畫可新增寬度點 |
to change one side | 可只變更單側 |
to select more points | 可選取更多點 |
Can't render this file because it contains an unexpected character in line 6 and column 47.
+1
View File
@@ -437,6 +437,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
- **Edit Artboards in Properties:** the active artboard's name is a field. Typing a new name and pressing Enter or clicking elsewhere renames that artboard in one undo step, as the Artboards panel's rename does (`artboard.setProps {index, name}`); pressing Escape or leaving the field empty keeps the old name. A click on the Artboard Options icon beside the field opens Artboard Options for the active artboard, as double-clicking the Artboard tool's button does (`tool.options {tool: "artboard"}`). Pointer and key tests in `panels/properties.rs` cover both. Public references: [Resize artboards](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/add-edit-artboards/resize-artboards.html) and [Create and add new artboards](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/add-edit-artboards/add-new-artboards.html).
- **Resizing several artboards:** with several artboards selected with the Artboard tool, a new W or H in Properties, the Transform panel or the Control bar, a preset or an orientation in Properties or the Control bar, and a new Width or Height in Artboard Options resize every selected artboard in one undo step (`artboard.setProps {artboards}`); with Scale Artwork with Artboard on, Properties, the Transform panel and the Control bar scale each object once, with the artboard it was inside before the change. The Transform panel, the Control bar and Artboard Options resize each one about its own reference point, a preset sizes each one in its own orientation, and X and Y still move the active artboard alone. Pointer and key tests in `panels/properties.rs`, dialog tests in `dialogs/tests.rs` and an engine test in `tests_xform.rs` cover them. Public references: [Artboard Enhancements In Illustrator CC](https://blog.adobe.com/en/publish/2017/11/10/artboard-enhancements-in-illustrator-cc) ("modify them all in bulk by defining the height and width values") and [Using multiple artboards](https://helpx.adobe.com/illustrator/using/using-multiple-artboards.html) (2019).
- **Artboard Escape routing:** Escape leaves Artboard editing for Selection; during a drag it first cancels the gesture. Headless egui key events cover idle Escape, active-drag cancellation and a subsequent Escape in `tests_distortkeys.rs`.
- **Shift with the Artboard tool:** a Shift-click adds an artboard to the selection or takes it out when the button comes up. A Shift-drag inside an artboard draws a new artboard there, and a Shift-drag on the pasteboard is a marquee that toggles the artboards it touches, as the [default keyboard shortcuts](https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) ("Create artboard inside another artboard") and [Using multiple artboards](https://web.archive.org/web/20210925094818/https://helpx.adobe.com/illustrator/using/using-multiple-artboards.html) (archived copy) describe. Shift no longer keeps an artboard move at 45° steps or a drawn artboard square. Escape during a marquee or while a new artboard is being drawn cancels it and keeps the Artboard tool. Pointer and key tests in `crates/tools/src/xform/artboard.rs` cover the four gestures and Escape.
- **Artboard deletion keys:** Delete/Backspace delete selected boards in one Undo step, retaining the original first board in the current order when all are selected, as in the public [Delete artboards guide](https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/add-edit-artboards/delete-artboards.html). The last board and active drags stay protected; neither key clears selected artwork. Headless shortcut regressions in `tests_distortkeys.rs` cover reordered boards, artwork, saved state and Undo/Redo.
- **Linux RPM packaging:** 64-bit runtime capabilities replace Fedora-specific required package names (#1275); glibc 2.35, libm and libgcc_s are declared alongside dynamically loaded xkbcommon and Vulkan/EGL. Generated x86_64/aarch64 metadata and isolated synthetic-provider resolution checked; real-distro install/start-up QA remains pending.
- **Linux file associations:** the desktop entry lists the MIME type of every format File › Open reads but PSD, PSB, `.ps` PostScript and Targa, `.ai`, `.ait` and EPS included, and the MIME package declares the types shared-mime-info lacks (VectorCraft documents and templates, `.ait`, Affinity), so file managers list VectorCraft under Open With for them, as Finder does on macOS. `the_linux_desktop_entry_opens_every_readable_format` in `apps/vectorcraft/src/main.rs` checks both files against `OPEN_EXTS`. On Debian 13, Ubuntu 24.04 and Fedora 42, `desktop-file-validate` accepts the desktop entry, `update-mime-database` accepts the MIME package, and `gio` registers the app for every one of these types.