mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 12:21:54 +00:00
Merge pull request #6408 from dotCooCoo/fix/outline-mode-canvas
View: Outline draws on a white canvas, with artboards as their edges
This commit is contained in:
@@ -543,8 +543,9 @@ fn ruler_bands(app: &VectorcraftApp, ui: &Ui, xf: &Xf, (full, rect): (egui::Rect
|
||||
let painter = ui.painter_at(rect);
|
||||
if let Some(origin) = origin_preview {
|
||||
let at = xf.to_screen(origin);
|
||||
painter.line_segment([pos2(at.x, rect.top()), pos2(at.x, rect.bottom())], Stroke::new(1.0, t.text_dim));
|
||||
painter.line_segment([pos2(rect.left(), at.y), pos2(rect.right(), at.y)], Stroke::new(1.0, t.text_dim));
|
||||
let color = dim_on_canvas(t, app.outline_view());
|
||||
painter.line_segment([pos2(at.x, rect.top()), pos2(at.x, rect.bottom())], Stroke::new(1.0, color));
|
||||
painter.line_segment([pos2(rect.left(), at.y), pos2(rect.right(), at.y)], Stroke::new(1.0, color));
|
||||
}
|
||||
// View › Rulers › Show Video Rulers counts the active artboard in video pixels.
|
||||
let video = app.ui.view.video_rulers.then(|| crate::dialogs::artboard_options::active_index(app));
|
||||
@@ -793,8 +794,17 @@ fn draw_frame(app: &mut VectorcraftApp, ui: &Ui, frame: Frame) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The pasteboard, the artboards' shadows and paper, and the outline mode's white artboards, of
|
||||
/// document `st`, in Outline when `outline`.
|
||||
/// The canvas color in Outline, whatever the interface brightness and Canvas Color: the paths draw
|
||||
/// as black hairlines, and the artboards as their edges only.
|
||||
const OUTLINE_CANVAS: Color32 = Color32::WHITE;
|
||||
|
||||
/// The color of the artboards' names and the ruler origin's crosshair in Outline, on
|
||||
/// [`OUTLINE_CANVAS`].
|
||||
const OUTLINE_DIM: Color32 = Color32::from_gray(0x4b);
|
||||
|
||||
/// The pasteboard and the artboards' shadows and paper of document `st`, or in Outline (`outline`)
|
||||
/// the whole canvas in [`OUTLINE_CANVAS`], with no paper drawn for the artboards: no Simulate
|
||||
/// Colored Paper color, no artboard background color, and no paper with View › Hide Artboards.
|
||||
fn paint_paper(
|
||||
app: &VectorcraftApp,
|
||||
st: &vectorcraft_engine::DocState,
|
||||
@@ -805,6 +815,12 @@ fn paint_paper(
|
||||
(t, outline): (&Tokens, bool),
|
||||
) {
|
||||
let doc = &st.doc;
|
||||
if outline {
|
||||
// The art draws in black on white over the pasteboard and the artboards alike, and the
|
||||
// artboards show as their edges (`artboard_outlines`).
|
||||
painter.rect_filled(rect, 0.0, OUTLINE_CANVAS);
|
||||
return;
|
||||
}
|
||||
// Pasteboard, artboard shadows and paper (Document Setup: the transparency grid's look, the
|
||||
// simulated paper colour; a white Background Contents hides the grid).
|
||||
// An artboard with a background color draws its paper in that color. With Simulate Colored Paper
|
||||
@@ -815,7 +831,7 @@ fn paint_paper(
|
||||
// View › Hide Artboards: no edges and no pasteboard, the whole canvas paper (#4038).
|
||||
let setup = &doc.setup;
|
||||
painter.rect_filled(rect, 0.0, if setup.simulate_paper { crate::panels::c32(&setup.paper()) } else { Color32::WHITE });
|
||||
} else if !outline {
|
||||
} else {
|
||||
let setup = &doc.setup;
|
||||
let grid = (st.transparency_grid && setup.background == vectorcraft_doc::Background::Transparent).then(|| checker_texture(ui.ctx(), setup));
|
||||
let paper = if setup.simulate_paper { crate::panels::c32(&setup.paper()) } else { Color32::WHITE };
|
||||
@@ -833,10 +849,6 @@ fn paint_paper(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ab in &doc.artboards {
|
||||
painter.add(Shape::convex_polygon(xf.quad(ab.rect), Color32::WHITE, Stroke::NONE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,16 +1019,22 @@ fn artboard_outlines(app: &VectorcraftApp, ui: &Ui, painter: &egui::Painter, xf:
|
||||
let tool_selected = artboards::tool_labelled(app);
|
||||
let editing_name = ui.data(|d| d.get_temp::<ArtboardNameEdit>(name_edit_id()).map(|e| e.index));
|
||||
let unlabelled = |i: usize| editing_name == Some(i) || u64::try_from(i).ok().is_some_and(|idx| tool_selected.contains(&idx));
|
||||
artboard_edges(app, doc, (painter, xf, t), active_ab, unlabelled);
|
||||
artboard_edges(app, doc, (painter, xf, t), (active_ab, dim_on_canvas(t, app.outline_view())), unlabelled);
|
||||
}
|
||||
|
||||
/// The edges, bleeds, marks and names of `doc`'s artboards, `active_ab` the active one; the
|
||||
/// artboards `unlabelled` gives are not named.
|
||||
/// The color of the artboards' names and the ruler origin's crosshair over the pasteboard, or over
|
||||
/// [`OUTLINE_CANVAS`] in Outline (`outline`).
|
||||
fn dim_on_canvas(t: &Tokens, outline: bool) -> Color32 {
|
||||
if outline { OUTLINE_DIM } else { t.text_dim }
|
||||
}
|
||||
|
||||
/// The edges, bleeds, marks and names of `doc`'s artboards, `active_ab` the active one, the names
|
||||
/// in `label`; the artboards `unlabelled` gives are not named.
|
||||
fn artboard_edges(
|
||||
app: &VectorcraftApp,
|
||||
doc: &vectorcraft_doc::Document,
|
||||
(painter, xf, t): (&egui::Painter, &Xf, &Tokens),
|
||||
active_ab: usize,
|
||||
(active_ab, label): (usize, Color32),
|
||||
unlabelled: impl Fn(usize) -> bool,
|
||||
) {
|
||||
let artboard_tool = app.session.tool_id() == "artboard";
|
||||
@@ -1034,7 +1052,7 @@ fn artboard_edges(
|
||||
// At the artboard's own top-left corner, which a rotated view turns away from its
|
||||
// bounding box's (#1095).
|
||||
let corner = xf.to_screen(Point::new(ab.rect.x0, ab.rect.y0));
|
||||
artboard_label(painter, corner, (ab.rect.width() * xf.zoom) as f32, &format!("{:02} - {}", i + 1, ab.name), t.text_dim);
|
||||
artboard_label(painter, corner, (ab.rect.width() * xf.zoom) as f32, &format!("{:02} - {}", i + 1, ab.name), label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ use super::outline::{c32, node_outline, stroke_path, too_many_anchors};
|
||||
use super::view::fit_zoom;
|
||||
use super::{
|
||||
Affine, CacheKey, Point, Rect, RulerScale, Sense, Stroke, StrokeKind, Tokens, Ui, VectorcraftApp, View, Xf, artboard_edges, cache_key,
|
||||
frame_options, frame_view, grid, guides_of, json, paint_paper, pixel_region, pos2, rulers, shows_artboards, textured_quad, vec2, view_rects,
|
||||
dim_on_canvas, frame_options, frame_view, grid, guides_of, json, paint_paper, pixel_region, pos2, rulers, shows_artboards, textured_quad, vec2,
|
||||
view_rects,
|
||||
};
|
||||
use crate::doc_windows::Win;
|
||||
use crate::thumb_worker::ThumbWorker;
|
||||
@@ -315,7 +316,7 @@ pub(crate) fn pane(app: &mut VectorcraftApp, ui: &Ui, w: Win, cell: egui::Rect)
|
||||
grid(&painter, &xf, st.doc.grid.spacing, st.doc.grid.subdivisions, look);
|
||||
}
|
||||
if shows_artboards(app) {
|
||||
artboard_edges(app, &st.doc, (&painter, &xf, &t), v.artboard, |_| false);
|
||||
artboard_edges(app, &st.doc, (&painter, &xf, &t), (v.artboard, dim_on_canvas(&t, v.outline)), |_| false);
|
||||
}
|
||||
if app.ui.view.guides {
|
||||
guides_of(app, st, (&painter, &xf, &t), rect);
|
||||
|
||||
@@ -4189,6 +4189,203 @@ fn outline_is_per_document_and_new_documents_start_in_preview() {
|
||||
assert!(app.run("view.outline", json!({})).is_err());
|
||||
}
|
||||
|
||||
/// One headless canvas frame → (the colors of the filled rectangles that cover the canvas, the
|
||||
/// fills of the shapes laid over an artboard, the artboards' edges drawn, the colors of the
|
||||
/// artboards' names).
|
||||
fn canvas_look(app: &mut VectorcraftApp, ctx: &egui::Context) -> (Vec<Color32>, Vec<Color32>, usize, Vec<Color32>) {
|
||||
let s = shapes(app, ctx);
|
||||
let canvas = app.canvas_rect.unwrap();
|
||||
let xf = Xf::new(canvas, app.view().unwrap());
|
||||
let quads: Vec<Vec<Pos2>> = app.session.active().unwrap().doc.artboards.iter().map(|a| xf.quad(a.rect).to_vec()).collect();
|
||||
let on = |p: &[Pos2]| quads.iter().any(|q| q.len() == p.len() && q.iter().zip(p).all(|(a, b)| (*a - *b).length() < 0.01));
|
||||
let covers: Vec<Color32> = s
|
||||
.iter()
|
||||
.filter_map(|s| match s {
|
||||
Shape::Rect(r) if r.rect.contains_rect(canvas) => Some(r.fill),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let papers: Vec<Color32> = s
|
||||
.iter()
|
||||
.filter_map(|s| match s {
|
||||
Shape::Path(p) if p.fill != Color32::TRANSPARENT && on(&p.points) => Some(p.fill),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let edges = s.iter().filter(|s| matches!(s, Shape::Path(p) if p.closed && p.fill == Color32::TRANSPARENT && on(&p.points))).count();
|
||||
let names: Vec<Color32> = s
|
||||
.iter()
|
||||
.filter_map(|s| match s {
|
||||
Shape::Text(t) if names_an_artboard(t.galley.text()) => Some(t.fallback_color),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
(covers, papers, edges, names)
|
||||
}
|
||||
|
||||
/// In Outline, in every interface brightness, color scheme and User Interface › Canvas Color, the
|
||||
/// whole canvas is white, pasteboard included, so the black outlines of art on the pasteboard show.
|
||||
/// The artboards draw no paper there, only their edges, and their names draw in a dark gray. In
|
||||
/// Preview the pasteboard keeps its color and the artboards their white paper.
|
||||
#[test]
|
||||
fn outline_draws_on_a_white_canvas_with_artboards_as_edges() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.session.execute("file.new", &json!({"width": 200, "height": 100, "artboards": 2})).unwrap();
|
||||
for brightness in crate::theme::Brightness::ALL {
|
||||
for scheme in crate::theme::Scheme::ALL {
|
||||
// Canvas Color: matching the brightness, Dark Gray and Medium Gray, as `prefs_dialog` sets it.
|
||||
for canvas_color in [None, Some(Color32::from_gray(0x5a)), Some(Color32::from_gray(0x96))] {
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::apply_with(&ctx, brightness, Default::default(), scheme);
|
||||
if let Some(c) = canvas_color {
|
||||
let mut t = Tokens::get(&ctx);
|
||||
t.pasteboard = c;
|
||||
ctx.data_mut(|d| d.insert_temp(egui::Id::NULL, t));
|
||||
}
|
||||
let case = format!("{brightness:?} {scheme:?} {canvas_color:?}");
|
||||
let pasteboard = Tokens::get(&ctx).pasteboard;
|
||||
assert_ne!(pasteboard, Color32::WHITE, "{case}");
|
||||
app.view_mut().unwrap().outline = false;
|
||||
let (covers, papers, edges, names) = canvas_look(&mut app, &ctx);
|
||||
assert_eq!(covers.last(), Some(&pasteboard), "{case}: Preview keeps the pasteboard");
|
||||
assert_eq!(papers, [Color32::WHITE; 2], "{case}: and the artboards' paper");
|
||||
assert_eq!(edges, 2, "{case}");
|
||||
assert_eq!(names, [Tokens::get(&ctx).text_dim; 2], "{case}");
|
||||
app.view_mut().unwrap().outline = true;
|
||||
let (covers, papers, edges, names) = canvas_look(&mut app, &ctx);
|
||||
assert_eq!(covers.last(), Some(&Color32::WHITE), "{case}: the canvas is white in Outline");
|
||||
assert!(!covers.contains(&pasteboard), "{case}: no pasteboard in Outline");
|
||||
assert!(papers.is_empty(), "{case}: no paper over the artboards in Outline: {papers:?}");
|
||||
assert_eq!(edges, 2, "{case}: the artboards show as their edges");
|
||||
assert_eq!(names, [OUTLINE_DIM; 2], "{case}: names readable on white");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In Outline the canvas stays white with Simulate Colored Paper on, with an artboard's own
|
||||
/// background color, and with View › Hide Artboards, which in Preview show the paper color, the
|
||||
/// artboard's color and the paper color over the whole canvas.
|
||||
#[test]
|
||||
fn outline_draws_no_colored_paper() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.session.execute("file.new", &json!({"width": 200, "height": 100, "artboards": 2})).unwrap();
|
||||
{
|
||||
let doc = std::sync::Arc::make_mut(&mut app.session.active_mut().unwrap().doc);
|
||||
doc.setup.simulate_paper = true;
|
||||
doc.setup.grid_colors = [vectorcraft_color::Color::rgb(0.9, 0.8, 0.6), vectorcraft_color::Color::rgb(0.5, 0.5, 0.5)];
|
||||
doc.artboards[1].color = Some(vectorcraft_color::Color::rgb(0.6, 0.8, 1.0));
|
||||
}
|
||||
let paper = crate::panels::c32(&app.session.active().unwrap().doc.setup.paper());
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::apply(&ctx, crate::theme::Brightness::Dark);
|
||||
app.view_mut().unwrap().outline = false;
|
||||
let (_, papers, _, _) = canvas_look(&mut app, &ctx);
|
||||
assert_eq!(papers.len(), 2);
|
||||
assert_eq!(papers[0], paper, "Preview: the simulated paper");
|
||||
assert_ne!(papers[1], paper, "Preview: the artboard's own color");
|
||||
app.view_mut().unwrap().outline = true;
|
||||
let (covers, papers, edges, _) = canvas_look(&mut app, &ctx);
|
||||
assert_eq!(covers.last(), Some(&Color32::WHITE));
|
||||
assert!(papers.is_empty(), "{papers:?}");
|
||||
assert_eq!(edges, 2);
|
||||
app.ui.view.artboards = false;
|
||||
app.view_mut().unwrap().outline = false;
|
||||
let (covers, _, edges, _) = canvas_look(&mut app, &ctx);
|
||||
assert_eq!(covers.last(), Some(&paper), "Preview with Hide Artboards: the paper over the whole canvas");
|
||||
assert_eq!(edges, 0);
|
||||
app.view_mut().unwrap().outline = true;
|
||||
let (covers, papers, edges, _) = canvas_look(&mut app, &ctx);
|
||||
assert_eq!(covers.last(), Some(&Color32::WHITE), "Outline with Hide Artboards");
|
||||
assert!(!covers.contains(&paper));
|
||||
assert!(papers.is_empty());
|
||||
assert_eq!(edges, 0);
|
||||
}
|
||||
|
||||
/// A split-view pane or floating window draws its own view's Outline, whatever the current view
|
||||
/// shows: the white canvas and dark gray artboard names in Outline, and the pasteboard and the
|
||||
/// theme's names in Preview.
|
||||
#[test]
|
||||
fn a_pane_draws_its_own_views_outline() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 100, "artboards": 2})).unwrap();
|
||||
crate::doc_windows::new_window(&mut app).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::apply(&ctx, crate::theme::Brightness::Dark);
|
||||
let t = Tokens::get(&ctx);
|
||||
let other = (0, 1);
|
||||
for pane_outline in [true, false] {
|
||||
crate::doc_windows::view_mut(&mut app, other).unwrap().outline = pane_outline;
|
||||
app.view_mut().unwrap().outline = !pane_outline;
|
||||
let cell = egui::Rect::from_min_size(pos2(0.0, 0.0), vec2(600.0, 400.0));
|
||||
let raw = egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(Pos2::ZERO, vec2(800.0, 600.0))), ..Default::default() };
|
||||
let mut out = ctx.run_ui(raw, |ui| {
|
||||
panes::pane(&mut app, ui, other, cell);
|
||||
});
|
||||
out.textures_delta.clear();
|
||||
let mut s = vec![];
|
||||
fn flat(s: Shape, out: &mut Vec<Shape>) {
|
||||
match s {
|
||||
Shape::Vec(v) => v.into_iter().for_each(|s| flat(s, out)),
|
||||
s => out.push(s),
|
||||
}
|
||||
}
|
||||
out.shapes.into_iter().for_each(|c| flat(c.shape, &mut s));
|
||||
let fills: Vec<Color32> = s.iter().filter_map(|s| if let Shape::Rect(r) = s { Some(r.fill) } else { None }).collect();
|
||||
let names: Vec<Color32> = s
|
||||
.iter()
|
||||
.filter_map(|s| if let Shape::Text(x) = s { names_an_artboard(x.galley.text()).then_some(x.fallback_color) } else { None })
|
||||
.collect();
|
||||
let (canvas, name) = if pane_outline { (Color32::WHITE, OUTLINE_DIM) } else { (t.pasteboard, t.text_dim) };
|
||||
assert_eq!(fills.first(), Some(&canvas), "pane in Outline: {pane_outline}");
|
||||
assert_eq!(names, [name; 2], "pane in Outline: {pane_outline}");
|
||||
}
|
||||
}
|
||||
|
||||
/// While the rulers' origin is dragged out of their corner, its crosshair draws over the canvas in
|
||||
/// the theme's dim text color in Preview, and in Outline in the dark gray that shows on the white
|
||||
/// canvas.
|
||||
#[test]
|
||||
fn the_ruler_origin_crosshair_shows_on_the_outline_canvas() {
|
||||
use egui::Event;
|
||||
for outline in [false, true] {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
|
||||
app.ui.view.rulers = true;
|
||||
app.view_mut().unwrap().outline = outline;
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::apply(&ctx, crate::theme::Brightness::Dark);
|
||||
frame(&mut app, &ctx, vec![]);
|
||||
frame(&mut app, &ctx, vec![]);
|
||||
let rect = app.canvas_rect.unwrap();
|
||||
let corner = pos2(rect.left() - RULER / 2.0, rect.top() - RULER / 2.0);
|
||||
let to = rect.center();
|
||||
let button = |pos, pressed| Event::PointerButton { pos, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
frame(&mut app, &ctx, vec![Event::PointerMoved(corner)]);
|
||||
frame(&mut app, &ctx, vec![button(corner, true)]);
|
||||
frame(&mut app, &ctx, vec![Event::PointerMoved(to)]);
|
||||
let (s, mut delta) = frame_output(&mut app, &ctx);
|
||||
delta.clear();
|
||||
let lines: Vec<Color32> = s
|
||||
.iter()
|
||||
.filter_map(|s| match s {
|
||||
Shape::LineSegment { points, stroke }
|
||||
if (points[0].x - to.x).abs() < 1.5
|
||||
&& (points[1].x - to.x).abs() < 1.5
|
||||
&& points[0].y <= rect.top() + 1.0
|
||||
&& points[1].y >= rect.bottom() - 1.0 =>
|
||||
{
|
||||
Some(stroke.color)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let want = if outline { OUTLINE_DIM } else { Tokens::get(&ctx).text_dim };
|
||||
assert_eq!(lines, [want], "Outline: {outline}");
|
||||
frame(&mut app, &ctx, vec![button(to, false)]);
|
||||
}
|
||||
}
|
||||
|
||||
/// #3797: a preferences file saved while View › Outline was an interface setting still loads, with
|
||||
/// its other view settings, and its Outline value does not put a document in Outline.
|
||||
#[test]
|
||||
|
||||
@@ -1006,7 +1006,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- **Artboard click-to-fit (#1227):** a plain click fits the topmost editable object or group to a new artboard, including its stroke like Fit to Selected Art, and makes the new artboard active. Art and its selection stay unchanged; creation is one undo step. Handles, modified clicks, drags, Escape and tool changes retain their meaning. Tested inside an artboard and on the pasteboard (`crates/engine/tests/it/artboard_click.rs`); the public [CS6 Printing Guide](https://helpx.adobe.com/content/dam/help/en/indesign/pdf/CS6_PrintGuide.pdf) documents the object-click gesture. This legacy gesture adds evidence without regrading the 2026 canvas controls.
|
||||
- **Rotated views:** with the view rotated, Fit Artboard in Window, Fit All in Window and the status bar's artboard navigator fit the artboard or the art as the view turns it, and a Zoom tool marquee (Animated Zoom or GPU Performance off) zooms to the area dragged across. Ruler guides on no artboard turn with the view. The canvas draws the selection marquee where the tools select, Show Hidden Characters draws the marks of type partly inside the canvas, the Contextual Task Bar stays under the selection, and the Navigator's red box outlines what the window shows.
|
||||
- **Navigator panel options:** the Navigator panel menu's Panel Options… sets the color the view box is drawn in, from a preset list (VectorCraft's own: Light Red, the default, then the layer colors) or a custom color, and Draw Dashed Lines as Solid Lines, off by default, which draws dashed strokes without their dashes in the panel's thumbnail only (`ui.navigatorPanelOptions`; kept with the UI state; behavior reference: [View artwork](https://helpx.adobe.com/illustrator/using/viewing-artwork.html)).
|
||||
- **Views:** the status bar's artboard navigator (first, previous, next, last; `view.goToArtboard`) goes to an artboard, fits it and synchronizes the Artboard tool selection when that tool is active; ordinary object selection is preserved. Its four buttons are also commands of their own (`view.firstArtboard`, `view.previousArtboard`, `view.nextArtboard`, `view.lastArtboard`), listed in Edit › Keyboard Shortcuts without a default key, so a user can give them keys such as Page Up and Page Down (#5218). Actual Next-button regressions cover keyboard/Properties deletion and Undo in `chrome.rs`. Fit Artboard in Window and Actual Size show the navigator's artboard. The Artboards panel highlights that active artboard: clicking a row makes it active (the Artboard tool's too, while it is chosen) as does clicking an artboard with the Artboard tool, double-clicking its number also fits it in the window and double-clicking its name renames it. Duplicate Artboards, or a row dragged onto New Artboard, copies the artboard with its art (#446). Escape leaves Presentation Mode, `view.screenMode` from it goes back to Normal Screen Mode, and the screen mode isn't saved with the preferences: the app always starts in Normal Screen Mode with its menus and panels (#472). View › Pixel Preview shows the art as the document pixels it rasterizes to, one per point and hard-edged when magnified, turning with a rotated view (it used to draw the smooth vectors, with only the pixel grid over them). In Outline view a template layer keeps drawing in Preview, dimmed, so a picture placed to be traced stays visible under the outlines (#1505, fixes #1486).
|
||||
- **Views:** the status bar's artboard navigator (first, previous, next, last; `view.goToArtboard`) goes to an artboard, fits it and synchronizes the Artboard tool selection when that tool is active; ordinary object selection is preserved. Its four buttons are also commands of their own (`view.firstArtboard`, `view.previousArtboard`, `view.nextArtboard`, `view.lastArtboard`), listed in Edit › Keyboard Shortcuts without a default key, so a user can give them keys such as Page Up and Page Down (#5218). Actual Next-button regressions cover keyboard/Properties deletion and Undo in `chrome.rs`. Fit Artboard in Window and Actual Size show the navigator's artboard. The Artboards panel highlights that active artboard: clicking a row makes it active (the Artboard tool's too, while it is chosen) as does clicking an artboard with the Artboard tool, double-clicking its number also fits it in the window and double-clicking its name renames it. Duplicate Artboards, or a row dragged onto New Artboard, copies the artboard with its art (#446). Escape leaves Presentation Mode, `view.screenMode` from it goes back to Normal Screen Mode, and the screen mode isn't saved with the preferences: the app always starts in Normal Screen Mode with its menus and panels (#472). View › Pixel Preview shows the art as the document pixels it rasterizes to, one per point and hard-edged when magnified, turning with a rotated view (it used to draw the smooth vectors, with only the pixel grid over them). In Outline view a template layer keeps drawing in Preview, dimmed, so a picture placed to be traced stays visible under the outlines (#1505, fixes #1486). Outline view draws on a white canvas in every interface brightness and Canvas Color, pasteboard included, with the artboards as their edges and no paper (VectorCraft's own rule), so the black outlines of art on the pasteboard show.
|
||||
In Presentation Mode, → and ← go to the next and the previous artboard, and a click anywhere goes to the next one, as the status bar navigator's Next and Previous do (`view.goToArtboard`): on the last artboard → and a click leave the view as it is, and so does ← on the first. The arrow keys do not move the selection there, and the tool does not receive a click, so a click selects and draws nothing (behavior reference: [View artwork](https://helpx.adobe.com/illustrator/using/viewing-artwork.html)).
|
||||
Full Screen Mode and Presentation Mode put the window full screen, covering the taskbar and the window's frame, and Normal Screen Mode or Full Screen Mode with Menu Bar puts it back (#4365); a window the user made full screen stays so.
|
||||
An unmodified Escape in either Full Screen Mode exits to Normal Screen Mode after any open popup, focused field, tool gesture, ruler-origin drag, floating Tools panel move, edit mode, drawer, flyout or view rotation has taken its Escape; a later Escape exits when that action is finished. This is a VectorCraft choice for both full screen variants, based on the public [shortcut list](https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html); the list does not specify that priority or the return mode.
|
||||
|
||||
@@ -428,6 +428,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Preferences › General › Constrain Angle | done | arrow keys and Shift drags along the turned axes; the Rectangle, Rounded Rectangle, Ellipse and grid tools, point and area type and the shape size dialogs draw along them with the bounding box turned; Shift-drawn polygons and stars keep the turned base orientation; the Line Segment tool's Shift steps count from it (#394, <https://helpx.adobe.com/illustrator/desktop/manage-objects/arrange-objects/rotate-objects-by-specific-angles.html>); arcs, spirals, flares and Pen paths are not turned |
|
||||
| Tabs panel: a stop drags from where the press landed, a stop just added included | done | #1458 |
|
||||
| Outline view keeps template layers in Preview, dimmed | done | #1486; a picture placed to be traced stays visible under the outlines |
|
||||
| Outline view draws on a white canvas, the artboards as their edges | done | Outline shows only the paths ([Outline mode](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/preview-artwork-as-outlines.html)). VectorCraft's own rule for the canvas: in every interface brightness and Canvas Color the whole canvas is white, pasteboard included; the artboards draw no paper (no Simulate Colored Paper or artboard color, and no paper with Hide Artboards); the artboard names and the ruler origin's crosshair are dark gray; split views and floating windows follow their own view. Tests `outline_draws_on_a_white_canvas_with_artboards_as_edges`, `outline_draws_no_colored_paper`, `a_pane_draws_its_own_views_outline`, `the_ruler_origin_crosshair_shows_on_the_outline_canvas` |
|
||||
| Arrange Tools add-on (VectorCraft addition): Object › Plug-ins › Arrange Tools runs Arrange in Grid… (grid by row, one row or one column; columns, H and V spacing, Center on Artboard; Preview), Swap Objects, Swap Objects and Sizes, Replace with Top Object… (Actual Size, Bounds or Bounds (Fit Proportionally); Keep Original; Scale Strokes & Effects; Preview), Set Size of Each… (Width and Height each ticked on or off, Constrain Width and Height Proportions with one side, the reference point, Scale Strokes & Effects; Preview) and Zoom to Selection, each one undo step | done | `addon.arrange.*`, `crates/engine/src/cmd/addons/arrange.rs`, `crates/ui-egui/src/addons/arrange.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
| Arrange Tools add-on (VectorCraft addition): Object › Plug-ins › Arrange Tools › Group Overlapping Objects groups the selected objects whose visual bounds overlap or touch (chains included, within one layer or group), each group at its frontmost member's stacking place, one undo step | done | #4928; `addon.arrange.groupOverlapping`, `crates/engine/src/cmd/addons/arrange.rs` and its tests; not a feature of the reference app, so it is not scored |
|
||||
| Arrange Tools add-on (VectorCraft addition): Object › Plug-ins › Arrange Tools › Randomize Opacity… gives each selected object its own opacity at random between Minimum and Maximum (%), with a Seed that repeats it and Preview, one undo step | done | #4925; `addon.arrange.randomizeOpacity`, `crates/engine/src/cmd/addons/arrange.rs`, `crates/ui-egui/src/addons/arrange.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
|
||||
Reference in New Issue
Block a user