mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 21:57:04 +00:00
Merge pull request #7793 from dotCooCoo/feat/the-basic-shape-tools-show-their-items
Task bar: the basic shape tools show Edit Path, Fill, Stroke and Shape Properties
This commit is contained in:
@@ -55,6 +55,26 @@ fn selection_tool_with_selection(app: &VectorcraftApp) -> bool {
|
||||
&& app.session.active().is_some_and(|st| !st.selection.is_empty())
|
||||
}
|
||||
|
||||
/// The basic shape tools whose Contextual Task Bar shows Edit Path, Fill, Stroke and the selected
|
||||
/// shape's properties. The Line Segment tool is not one of them.
|
||||
const SHAPE_TOOLS: [&str; 5] = ["rectangle", "roundedRectangle", "ellipse", "polygon", "star"];
|
||||
|
||||
/// Whether a basic shape tool is in use with one closed path selected whole, as each of those tools
|
||||
/// leaves the shape it draws.
|
||||
fn shape_tool_on_shape(app: &VectorcraftApp) -> bool {
|
||||
SHAPE_TOOLS.contains(&app.session.tool_id())
|
||||
&& app.session.active().is_some_and(|st| {
|
||||
st.selection.objects.len() == 1
|
||||
&& st.selection.anchors.is_empty()
|
||||
&& st
|
||||
.selection
|
||||
.objects
|
||||
.first()
|
||||
.and_then(|id| st.doc.node(*id))
|
||||
.is_some_and(|n| matches!(&n.kind, NodeKind::Path { path, .. } if path.is_closed()))
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether the bar shows its blank canvas actions, Draw (Pencil) and Place Image: a selection tool is
|
||||
/// in use and the active document has no artwork, only layers and guides.
|
||||
fn blank_canvas(app: &VectorcraftApp) -> bool {
|
||||
@@ -107,7 +127,11 @@ pub(crate) fn task_bar_shows_type(app: &VectorcraftApp) -> bool {
|
||||
/// With the Artboard tool it sits under the selected artboards and offers Resize (Artboard
|
||||
/// Options), Duplicate, Rearrange All (with two or more artboards) and Export (Export for Screens).
|
||||
/// A basic shape selected with the Selection tool shows a Shape Properties button in place of Lock.
|
||||
/// Selected type also shows the font family, font style and Font Size controls before its Fill.
|
||||
/// While a basic shape tool (Rectangle, Rounded Rectangle, Ellipse, Polygon or Star) has one closed
|
||||
/// path selected, as after it draws one, the bar offers Edit Path, Fill and Stroke, and Shape
|
||||
/// Properties for a live rectangle, rounded rectangle, ellipse or polygon; with nothing selected, or
|
||||
/// any other selection, those tools show no bar. Selected type also shows the font family, font
|
||||
/// style and Font Size controls before its Fill.
|
||||
/// While a Type tool edits type, or has type selected, the bar shows only those controls and the
|
||||
/// Fill. When one row would be wider than the canvas, the font controls take a row of their own,
|
||||
/// narrowed to fit it, and the actions wrap onto rows under the handle's ([`bar_layout`]).
|
||||
@@ -123,7 +147,10 @@ pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
let typing = type_tool_on_type(app);
|
||||
// A blank canvas offers Draw (Pencil) and Place Image, as the same help page describes.
|
||||
let blank = !on_artboards && blank_canvas(app);
|
||||
if !(on_artboards || typing || blank || selection_tool_with_selection(app)) {
|
||||
// A basic shape tool with its shape selected offers Edit Path, Fill, Stroke and the shape's
|
||||
// properties, as the same help page describes.
|
||||
let shaping = shape_tool_on_shape(app);
|
||||
if !(on_artboards || typing || blank || shaping || selection_tool_with_selection(app)) {
|
||||
return;
|
||||
}
|
||||
// Selected type has the font controls too, as the help page describes
|
||||
@@ -153,20 +180,22 @@ pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
f.name.as_deref() == Some("Image Trace") && f.children().is_some_and(|c| c.first().is_some_and(|i| matches!(i.kind, NodeKind::Image(_))))
|
||||
});
|
||||
// A basic shape (a live rectangle, rounded rectangle, ellipse or polygon) selected whole with the
|
||||
// Selection tool: its properties take the place of Lock, as in the reference app
|
||||
// (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>).
|
||||
// Selection tool or a basic shape tool: its properties take the place of Lock, as the help page
|
||||
// describes (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>).
|
||||
use vectorcraft_doc::LiveShape;
|
||||
let shape = first
|
||||
.filter(|f| {
|
||||
n == 1
|
||||
&& st.selection.anchors.is_empty()
|
||||
&& app.session.tool_id() == "selection"
|
||||
&& (app.session.tool_id() == "selection" || shaping)
|
||||
&& matches!(&f.kind, NodeKind::Path { live: Some(l), .. }
|
||||
if matches!(**l, LiveShape::Rectangle { .. } | LiveShape::Ellipse { .. } | LiveShape::Polygon { .. }))
|
||||
})
|
||||
.cloned();
|
||||
let mut items: Vec<(&str, &str, &str, serde_json::Value)> = vec![]; // (label, icon, command, params)
|
||||
let none = || json!({});
|
||||
// Edit Path: the Direct Selection tool, to edit the path's anchors.
|
||||
let edit_path = || (tl!("Edit Path"), "dc-direct", "tool.select", json!({"tool": "directSelection"}));
|
||||
if on_artboards {
|
||||
// As in the reference app, the Artboard tool offers to resize, duplicate and export the
|
||||
// artboards (<https://community.adobe.com/questions-652/contextual-task-bar-in-illustrator-2025-quick-actions-when-you-need-them-1546580>),
|
||||
@@ -181,11 +210,12 @@ pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
// Draw (Pencil) switches to the Pencil tool; Place Image picks files for the Place dialog.
|
||||
items.push((tl!("Draw (Pencil)"), "pencil", "tool.select", json!({"tool": "pencil"})));
|
||||
items.push((tl!("Place Image"), "image", "file.place", none()));
|
||||
} else if shaping {
|
||||
// A basic shape tool's one action; its Fill, Stroke and Shape Properties follow as chips.
|
||||
items.push(edit_path());
|
||||
} else if !typing {
|
||||
// The selection tools' object actions. A Type tool's bar leaves them out, Create Outlines
|
||||
// and the type conversions included.
|
||||
// Edit Path: the Direct Selection tool, to edit the path's anchors.
|
||||
let edit_path = || (tl!("Edit Path"), "dc-direct", "tool.select", json!({"tool": "directSelection"}));
|
||||
// As in the reference app, an image offers Image Trace, Crop Image and Remove Background, and
|
||||
// traced art offers Expand (<https://community.adobe.com/announcements-651/contextual-task-bar-in-illustrator-2025-quick-actions-when-you-need-them-1546580>,
|
||||
// <https://community.adobe.com/announcements-651/ai-powered-image-editing-features-in-illustrator-1624061>).
|
||||
@@ -288,13 +318,18 @@ pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
let fonts = fonts && room >= crate::panels::character::task_bar_min_room();
|
||||
// The selected objects' Fill, Stroke, Recolor Artwork (when they have colours to recolour) and
|
||||
// Lock (a basic shape's properties instead), left out with the Artboard tool and on a blank
|
||||
// canvas, which have no selected objects. A Type tool's bar has the Fill alone.
|
||||
// canvas, which have no selected objects. A Type tool's bar has the Fill alone. A basic shape
|
||||
// tool's bar has the Fill, the Stroke and a live shape's Shape Properties.
|
||||
let objects = !on_artboards && !blank;
|
||||
let chips: Vec<Chip> =
|
||||
[(objects, Chip::Fill), (objects && !typing, Chip::Stroke), (objects && !typing && colored, Chip::Recolor), (objects && !typing, Chip::Lock)]
|
||||
.into_iter()
|
||||
.filter_map(|(shown, chip)| shown.then_some(chip))
|
||||
.collect();
|
||||
let chips: Vec<Chip> = [
|
||||
(objects, Chip::Fill),
|
||||
(objects && !typing, Chip::Stroke),
|
||||
(objects && !typing && !shaping && colored, Chip::Recolor),
|
||||
(objects && !typing && (!shaping || shape.is_some()), Chip::Lock),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(shown, chip)| shown.then_some(chip))
|
||||
.collect();
|
||||
let widths: Vec<f32> = items.iter().map(|(label, _, cmd, _)| if icon_only(cmd) { BAR_MORE } else { action_width(ui, label) }).collect();
|
||||
let font_w = fonts.then(|| {
|
||||
let w = crate::panels::character::TASK_BAR_WIDTHS;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
//! The Contextual Task Bar's actions for each kind of selection: open paths offer Join and Edit
|
||||
//! Path, compound paths and clipping masks their Release, images selected with vector art Make
|
||||
//! Clipping Mask, type converts between point and area type, type on a path opens its options, and
|
||||
//! a basic shape shows its properties in place of Lock. Type, and the Type tools while they edit it,
|
||||
//! a basic shape shows its properties in place of Lock. The basic shape tools show Edit Path, Fill,
|
||||
//! Stroke and Shape Properties for the shape they draw. Type, and the Type tools while they edit it,
|
||||
//! show the font family, font style and Font Size controls.
|
||||
|
||||
use egui::{Event, PointerButton, Pos2, Rect, vec2};
|
||||
@@ -571,6 +572,155 @@ fn other_selections_keep_lock() {
|
||||
}
|
||||
}
|
||||
|
||||
/// The basic shape tools: the tool ids, and the Shape Properties heading each tool's shape shows
|
||||
/// (none for the star, a plain path).
|
||||
const SHAPE_TOOLS: [(&str, Option<&str>); 5] = [
|
||||
("rectangle", Some("Rectangle Properties:")),
|
||||
("roundedRectangle", Some("Rectangle Properties:")),
|
||||
("ellipse", Some("Ellipse Properties:")),
|
||||
("polygon", Some("Polygon Properties:")),
|
||||
("star", None),
|
||||
];
|
||||
|
||||
/// Draw with `tool` by dragging across the canvas from the document point `from` to `to`, and return
|
||||
/// whether the task bar showed partway through the drag.
|
||||
fn drag_with(app: &mut VectorcraftApp, tool: &str, from: (f64, f64), to: (f64, f64)) -> bool {
|
||||
app.run("tool.select", json!({ "tool": tool })).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
frame(app, &ctx, vec![]);
|
||||
frame(app, &ctx, vec![]);
|
||||
let xf = canvas::Xf::new(app.canvas_rect.unwrap(), app.view().unwrap());
|
||||
let (a, b) = (xf.to_screen(vectorcraft_geom::Point::new(from.0, from.1)), xf.to_screen(vectorcraft_geom::Point::new(to.0, to.1)));
|
||||
let press = |pos, pressed| Event::PointerButton { pos, button: PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
frame(app, &ctx, vec![Event::PointerMoved(a), press(a, true)]);
|
||||
frame(app, &ctx, vec![Event::PointerMoved(a + (b - a) / 2.0)]);
|
||||
frame(app, &ctx, vec![Event::PointerMoved(b)]);
|
||||
let shown_mid_drag = canvas::task_bar_rect(&ctx).is_some();
|
||||
frame(app, &ctx, vec![press(b, false)]);
|
||||
frame(app, &ctx, vec![]);
|
||||
shown_mid_drag
|
||||
}
|
||||
|
||||
fn names(named: &[(String, Rect)]) -> Vec<&str> {
|
||||
named.iter().map(|(n, _)| n.as_str()).collect()
|
||||
}
|
||||
|
||||
/// Each basic shape tool, just after it draws a shape, shows Edit Path, Fill and Stroke for it, and
|
||||
/// Shape Properties for a live rectangle, rounded rectangle, ellipse or polygon. The bar leaves out
|
||||
/// the selection tools' Duplicate, Offset Path, Simplify, Recolor Artwork and Lock, and shows
|
||||
/// nothing during the drag that draws the shape.
|
||||
#[test]
|
||||
fn shape_tools_show_edit_path_paint_and_properties_after_drawing() {
|
||||
let mut app = app();
|
||||
for (i, (tool, heading)) in SHAPE_TOOLS.into_iter().enumerate() {
|
||||
let x = 30.0 + 70.0 * i as f64;
|
||||
let shown_mid_drag = drag_with(&mut app, tool, (x, 60.0), (x + 50.0, 120.0));
|
||||
assert!(!shown_mid_drag, "{tool}: no bar while the shape is dragged out");
|
||||
assert_eq!(app.session.tool_id(), tool);
|
||||
let st = app.session.active().unwrap();
|
||||
assert_eq!(st.selection.objects.len(), 1, "{tool} drew and selected a shape");
|
||||
let shape = st.selection.objects[0].0;
|
||||
let (_, named) = buttons(&mut app);
|
||||
let names = names(&named);
|
||||
for name in ["Edit Path", "Fill", "Stroke", "More Options"] {
|
||||
assert!(names.contains(&name), "{tool}: {name} in {names:?}");
|
||||
}
|
||||
assert_eq!(names.contains(&"Shape Properties"), heading.is_some(), "{tool}: {names:?}");
|
||||
for name in ["Duplicate", "Offset Path", "Simplify", "Recolor Artwork", "Lock (⌘2)"] {
|
||||
assert!(!names.contains(&name), "{tool}: {name} is left out of {names:?}");
|
||||
}
|
||||
if let Some(heading) = heading {
|
||||
let (_, texts) = click_lock_slot(&mut app);
|
||||
assert!(has(&texts, heading), "{tool}: {heading} in {texts:?}");
|
||||
assert!(!locked(&app, shape), "{tool}: the button doesn't lock the shape");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// With a basic shape tool in use, the bar shows only for one closed path selected whole: not with
|
||||
/// nothing selected, several objects, a group, an open path, type or picked-out anchors. The Line
|
||||
/// Segment tool shows no bar for a selected rectangle.
|
||||
#[test]
|
||||
fn shape_tools_have_no_shape_bar_without_a_single_shape() {
|
||||
let mut app = app();
|
||||
let a = id(app.run("shape.rectangle", json!({"x": 20, "y": 20, "width": 30, "height": 30})).unwrap());
|
||||
let b = id(app.run("shape.ellipse", json!({"x": 60, "y": 20, "width": 30, "height": 30})).unwrap());
|
||||
let c = id(app.run("shape.rectangle", json!({"x": 20, "y": 250, "width": 30, "height": 30})).unwrap());
|
||||
let d = id(app.run("shape.rectangle", json!({"x": 60, "y": 250, "width": 30, "height": 30})).unwrap());
|
||||
select(&mut app, &[c, d]);
|
||||
let group = id(app.run("object.group", json!({})).unwrap());
|
||||
let line = id(app.run("shape.line", json!({"x1": 150, "y1": 50, "x2": 300, "y2": 120})).unwrap());
|
||||
let text = id(app.run("text.create", json!({"x": 150, "y": 200, "text": "Type"})).unwrap());
|
||||
let cases: [(&str, Vec<u64>); 5] =
|
||||
[("nothing", vec![]), ("several", vec![a, b]), ("a group", vec![group]), ("an open path", vec![line]), ("type", vec![text])];
|
||||
for (tool, _) in SHAPE_TOOLS {
|
||||
app.run("tool.select", json!({ "tool": tool })).unwrap();
|
||||
for (what, ids) in &cases {
|
||||
select(&mut app, ids);
|
||||
let (ctx, _) = bar(&mut app);
|
||||
assert!(canvas::task_bar_rect(&ctx).is_none(), "{tool} with {what}: no bar");
|
||||
}
|
||||
app.run("select.anchors", json!({"id": a, "anchors": [[0, 1]]})).unwrap();
|
||||
let (ctx, _) = bar(&mut app);
|
||||
assert!(canvas::task_bar_rect(&ctx).is_none(), "{tool} with anchors: no bar");
|
||||
select(&mut app, &[a]);
|
||||
let (ctx, _) = bar(&mut app);
|
||||
assert!(canvas::task_bar_rect(&ctx).is_some(), "{tool} with the rectangle: the bar");
|
||||
}
|
||||
app.run("tool.select", json!({"tool": "lineSegment"})).unwrap();
|
||||
select(&mut app, &[a]);
|
||||
let (ctx, _) = bar(&mut app);
|
||||
assert!(canvas::task_bar_rect(&ctx).is_none(), "the Line Segment tool: no bar");
|
||||
}
|
||||
|
||||
/// A basic shape tool's bar follows the selection: Shape Properties shows the shape drawn last,
|
||||
/// edits it with Undo restoring it, and after an Undo of the drawing shows the shape selected
|
||||
/// then. Fill makes the Fill active, Stroke the Stroke, and Edit Path switches to the Direct
|
||||
/// Selection tool.
|
||||
#[test]
|
||||
fn shape_tool_bar_retargets_after_another_shape_and_undo() {
|
||||
let mut app = app();
|
||||
app.run("tool.select", json!({"tool": "ellipse"})).unwrap();
|
||||
let rect = id(app.run("shape.rectangle", json!({"x": 40, "y": 40, "width": 80, "height": 60, "radius": 10})).unwrap());
|
||||
let (ctx, texts) = click_lock_slot(&mut app);
|
||||
assert!(has(&texts, "Rectangle Properties:"), "{texts:?}");
|
||||
type_into(&mut app, &ctx, &texts, "10 pt", "20");
|
||||
let corners = |app: &VectorcraftApp| match live(app, rect) {
|
||||
vectorcraft_doc::LiveShape::Rectangle { radii, .. } => radii,
|
||||
l => panic!("{l:?}"),
|
||||
};
|
||||
assert_eq!(corners(&app), [20.0; 4]);
|
||||
app.run("edit.undo", json!({})).unwrap();
|
||||
assert_eq!(corners(&app), [10.0; 4]);
|
||||
|
||||
let ellipse = id(app.run("shape.ellipse", json!({"x": 200, "y": 40, "width": 80, "height": 60})).unwrap());
|
||||
let (_, texts) = click_lock_slot(&mut app);
|
||||
assert!(has(&texts, "Ellipse Properties:") && !has(&texts, "Rectangle Properties:"), "{texts:?}");
|
||||
app.run("edit.undo", json!({})).unwrap();
|
||||
assert!(app.session.active().unwrap().doc.node(NodeId(ellipse)).is_none(), "the ellipse is undone");
|
||||
let selected: Vec<u64> = app.session.active().unwrap().selection.objects.iter().map(|i| i.0).collect();
|
||||
let (ctx, texts) = bar(&mut app);
|
||||
assert!(!has(&texts, "Ellipse Properties:"), "{texts:?}");
|
||||
if selected == [rect] {
|
||||
assert!(canvas::task_bar_rect(&ctx).is_some(), "the rectangle selected again: the bar");
|
||||
} else {
|
||||
assert!(canvas::task_bar_rect(&ctx).is_none(), "{selected:?}: no bar");
|
||||
select(&mut app, &[rect]);
|
||||
}
|
||||
let (_, texts) = click_lock_slot(&mut app);
|
||||
assert!(has(&texts, "Rectangle Properties:"), "{texts:?}");
|
||||
|
||||
app.session.fill_active = false;
|
||||
click_button(&mut app, "Fill");
|
||||
assert!(app.session.fill_active, "Fill makes the Fill active");
|
||||
click_button(&mut app, "Stroke");
|
||||
assert!(!app.session.fill_active, "Stroke makes the Stroke active");
|
||||
assert_eq!(app.session.tool_id(), "ellipse");
|
||||
click_button(&mut app, "Edit Path");
|
||||
assert_eq!(app.session.tool_id(), "directSelection");
|
||||
}
|
||||
|
||||
/// A compound path under the Direct Selection tool isn't offered Edit Path, which would only switch
|
||||
/// to the tool already in use; the Selection tool still offers it.
|
||||
#[test]
|
||||
|
||||
@@ -898,7 +898,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- With automation read roots in force, `svgInteractivity.info`, `addFile` and `removeFile`, the JavaScript Files dialog in a frame a request drives and `ui_inspect`'s selected file name a linked JavaScript file outside the roots by its file name alone, as `document.json` does; `removeFile` unlinks it by that name and refuses a name that fits more than one linked file (`tests/interactivity.rs`).
|
||||
- Numeric fields keep the pointer's pressed character as the text-drag start when movement exceeds the click threshold (#1326); a completed focus click selects the unit too. Pixel/point, plain and optional fields are regression-tested in both directions, before/after focus, with replacement text; keyboard focus, double-click, arrows and wheel keep their prior behavior. Native egui input confirms partial replacement gives 17 px instead of 700 px, one Undo/Redo, window captures and an exact saved-document read in a separate CLI process. A focus click released more than 1 pt from its press keeps the caret, and a tap within 1 pt still selects all (#6659; short-drag and jitter-tap regressions in `tests/numfields.rs`).
|
||||
- Unit fields and length strings take `%` in arithmetic: `3cm*50%` reads as 1.5 cm, and `50pt+25%` reads as 62.5 pt.
|
||||
- The contextual task bar's handle drags it anywhere on the canvas (kept whole on it as the window resizes); unpinned it keeps that offset as it follows the selection, and its More Options menu hides it, pins its position across selection changes (`window.taskBar.pin`), resets it under the selection (`window.taskBar.reset`) and shows the Properties panel. As in Illustrator the position isn't kept across launches. Not done: the bar's variants for other tools (only the selection tools, the Type tools and the Artboard tool show it).
|
||||
- The contextual task bar's handle drags it anywhere on the canvas (kept whole on it as the window resizes); unpinned it keeps that offset as it follows the selection, and its More Options menu hides it, pins its position across selection changes (`window.taskBar.pin`), resets it under the selection (`window.taskBar.reset`) and shows the Properties panel. As in Illustrator the position isn't kept across launches. Not done: the bar's variants for other tools (only the selection tools, the Type tools, the basic shape tools and the Artboard tool show it).
|
||||
- A click on another object moves the contextual task bar under it without hiding it for the press; it gives way only to a drag (#4681).
|
||||
- With one image selected, the contextual task bar offers Image Trace, which traces the image at once with the Default preset (the Image Trace panel is left as it was), and Crop Image; with an Image Trace object it offers Expand, which keeps only the traced paths. This follows Illustrator's bar: for a selected image it includes Image Trace, Retype and Crop Image, and traced artwork can be expanded from it ([Contextual Task Bar announcement](https://community.adobe.com/announcements-651/contextual-task-bar-in-illustrator-2025-quick-actions-when-you-need-them-1546580)). Offset Path and Simplify, which don't apply to an image, aren't offered for one. Not done: Retype, which the app doesn't have.
|
||||
- With the Artboard tool, the contextual task bar sits under the selected artboards and offers Resize (Artboard Options for the active artboard), Duplicate (each selected artboard, in one undo step, the copies then selected), Rearrange All (with two or more artboards) and Export (Export for Screens with the selected artboards checked). This follows Illustrator's bar: while the Artboard tool is in use, it has options for resizing, duplicating and exporting artboards (the [Contextual Task Bar announcement](https://community.adobe.com/questions-652/contextual-task-bar-in-illustrator-2025-quick-actions-when-you-need-them-1546580); Rearrange and Export on the bar: [Managing Artboards in Illustrator](https://creativepro.com/managing-artboards-in-illustrator/)).
|
||||
@@ -907,6 +907,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- While a Type tool (Type, Area Type, Type on a Path and their vertical versions) adds or edits type, the contextual task bar shows the font family menu, the font style menu, the Font Size combo and the Fill chip (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>); the Touch Type tool shows no bar, as the same page describes. Type selected with a selection tool shows the same three font controls beside its Create Outlines, conversion and Type on a Path items (<https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/font-options-overview.html>). The controls act as the Character panel's do: on the characters a Type tool selects, else on every selected type object, with the size left blank where the sizes differ. VectorCraft's own rules: a Type tool's bar leaves out the object actions, the Stroke chip, Recolor Artwork and Lock; a Type tool shows no bar before it adds type or with other art selected; type selected with other art shows no font controls; the font controls go on a second row when one row would be wider than the canvas, and narrow to fit a canvas narrower than they are; while a Type tool edits type, the Fill chip shows the edited characters' fill ("?" where it differs). Evidence: `the_type_tools_show_font_and_fill_controls`, `the_type_tools_show_no_bar_without_type`, `selected_type_shows_font_controls_beside_its_actions`, `the_task_bars_font_size_sets_what_the_character_panel_would`, `the_type_tools_fill_chip_activates_the_fill`, `the_type_tools_bar_is_named_and_stays_on_the_canvas`, `selected_types_font_controls_take_a_second_row_on_a_narrow_canvas` and `the_type_tools_fill_chip_shows_the_edited_characters_fill` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- The help page describes the contextual task bar as one horizontal row (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/workspace-overview.html>) and gives no rule for a canvas narrower than that row. VectorCraft's own rule: the bar stays whole on the canvas. When its actions don't fit in one row, they wrap, in order, onto rows under the row with the handle, the chips and More Options; an action wider than any row, or one that would need a row past the canvas's height, is listed in More Options instead; when the chips don't fit beside the handle and More Options, they take rows after the actions; with no row to spare for the font controls, the bar leaves them out; a canvas too small for the handle and More Options shows no bar. Evidence: `a_task_bars_actions_wrap_on_a_narrow_canvas` and `a_task_bar_action_wider_than_the_canvas_goes_in_more_options` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- With a live rectangle, rounded rectangle, ellipse or polygon selected with the Selection tool, the contextual task bar shows a Shape Properties button in place of Lock. It opens a popup with the shape's rows from the Transform panel (corner radius, pie angles, or sides, angle, corner and radius), which edit it through `object.setLiveShape`. The overview describes this: when a shape drawn with a shape tool (Rectangle, Star) is selected, the bar offers to change its properties where Lock Object would be ([Contextual Task Bar overview](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html)). Object › Lock and ⌘2 still lock the shape. Not done: stars, which the app draws as plain paths. Evidence: `a_basic_shape_shows_its_properties_in_place_of_lock`, `the_shape_properties_popup_edits_the_shape` and `other_selections_keep_lock` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- While the Rectangle, Rounded Rectangle, Ellipse, Polygon or Star tool is in use, the contextual task bar offers Edit Path (the Direct Selection tool), the Fill and Stroke chips, and Shape Properties for the shape it draws, as the help page lists for those five tools (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>). VectorCraft's own rules: the bar shows while one of those tools has one closed path selected whole, as right after it draws one, and not with nothing selected, several objects, a group, an open path, type or picked-out anchors; it shows nothing during the drag that draws the shape; it leaves out the selection tools' Duplicate, Offset Path, Simplify, Recolor Artwork and Lock; the Line Segment tool shows no bar. Not done: Shape Properties for a star, which the app draws as a plain path, and Gen Shape Fill and Generate Vectors, which the app doesn't have. Evidence: `shape_tools_show_edit_path_paint_and_properties_after_drawing`, `shape_tools_have_no_shape_bar_without_a_single_shape` and `shape_tool_bar_retargets_after_another_shape_and_undo` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- The contextual task bar has a Stroke chip beside the Fill chip, drawn with the paint the Stroke proxy shows (a "?" when the selected objects' strokes differ, as on the Fill chip); a click brings the Stroke proxy forward and shows the Swatches panel wherever it is docked, floating or closed, as a click on the Fill chip does for the Fill proxy. The reference app's bar has Fill and Stroke controls for changing an object's colors ([Contextual Task Bar overview](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html)). Evidence: `the_task_bar_shows_a_stroke_chip_beside_fill` and `the_task_bar_chips_follow_the_proxies_and_show_swatches_anywhere` in `crates/ui-egui/src/canvas/tests.rs`.
|
||||
- With anchor points selected with Direct Selection, the contextual task bar offers Remove Anchor Points, Connect (`path.join`), Cut Path, and Convert Selected Anchor Points to Corner and to Smooth (`path.convertAnchors` with `to` set to `corner` or `smooth`), the commands of the Control bar's anchor buttons; the two convert buttons show their icons alone, named by their tool tips as on the Control bar (VectorCraft's own choice). The overview lists items that delete the selected anchors, join selected end points, split the path at the selected anchors, and make the selected anchors corner or smooth points ([Contextual Task Bar overview](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html)). With a path selected whole with Direct Selection, the bar also offers Simplify and Smooth, which open the Simplify and Smooth sliders as Object › Path › Simplify… and Smooth… do; the same overview names Smooth as adjusting the path's curvature (#6784). VectorCraft's own rule: while anchors are picked out, the bar offers the anchor items without Simplify and Smooth. Evidence: `direct_selection_smooth_opens_the_smooth_slider` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- Tool flyouts tear off: dragging or clicking the tear-off bar on a flyout's right side (or releasing the long press over it) floats its group as a strip of tool buttons, moved by the same bar and put back in the toolbar by the × at its top (`window.floatTools`). While a group floats, the presses that would open its flyout raise the strip instead. Floating strips are kept with the preferences and in user workspaces. Not done: turning a strip vertical, docking it.
|
||||
|
||||
Reference in New Issue
Block a user