Merge pull request #5843 from sadkotheguest/feat/outer-glow-color-swatch

Effect dialogs: a colour swatch beside a hex colour opens the Color Picker (#5365)
This commit is contained in:
BFlat
2026-11-06 02:42:52 +07:00
committed by GitHub
6 changed files with 149 additions and 12 deletions
+29 -2
View File
@@ -249,6 +249,23 @@ pub fn open(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
Ok(Value::Null)
}
/// The field of a Color Picker opened over a command dialog ([`over_effect`]): the dialog's colour
/// field its OK fills.
const COLOUR_FIELD: &str = "__colourField";
/// The Color Picker over the command dialog `parent`, on `colour`, that fills the dialog's `field`
/// with its OK and goes back to it, as Cancel does. It previews nothing itself: the dialog's own
/// preview shows the colour once it is back.
pub(super) fn over_effect(parent: &Dialog, field: &str, colour: Color) -> Dialog {
let mut d = Dialog::new(
KIND,
json!({"original": color_json(&colour), "channel": Channel::default().id(), "webOnly": false, "swatches": false, COLOUR_FIELD: field}),
);
d.fields.insert(super::PARENT.into(), serde_json::to_value(parent).unwrap_or_default());
store(&mut d, &Picked::of(colour));
d
}
/// The field of a Color Picker opened over Recolor Artwork ([`over_recolor`]): the row whose new
/// color it picks.
const RECOLOR_ROW: &str = "__recolorRow";
@@ -433,8 +450,9 @@ fn body(app: &mut VectorcraftApp, ui: &mut Ui, d: &mut Dialog) -> DialogAction {
/// Opened for an artboard, the picker shows the color on that artboard's paper, with or without a
/// selection.
fn preview(app: &mut VectorcraftApp, d: &mut Dialog) {
// Over Recolor Artwork the art shows that dialog's preview, which this one must not replace.
if d.fields.contains_key(RECOLOR_ROW) {
// Over Recolor Artwork the art shows that dialog's preview, which this one must not replace;
// over a command dialog this picker only fills a field, and the dialog previews it.
if d.fields.contains_key(RECOLOR_ROW) || d.fields.contains_key(COLOUR_FIELD) {
return;
}
let (cmd, params) = paint_command(app, d);
@@ -632,6 +650,15 @@ fn swatch_list(app: &VectorcraftApp, ui: &mut Ui, current: &Color, side: f32) ->
/// OK with the starting color unchanged and nothing previewed closes the picker and leaves the
/// artboard as it was: without a background color, or with its color in its own color model.
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
if let Some(field) = d.fields.get(COLOUR_FIELD).and_then(Value::as_str) {
let mut parent = super::parent(d).ok_or("the dialog it was opened over is no longer open")?;
parent.fields.insert(field.to_string(), json!(picked(d).color.to_hex()));
// The dialog previews the new colour when it comes back: end this picker's interaction, as
// Cancel does, so the dialog starts its preview afresh.
let _ = app.session.cancel_interaction();
app.ui.dialog = Some(parent);
return Ok(Value::Null);
}
if let Some(row) = d.fields.get(RECOLOR_ROW).and_then(Value::as_u64) {
let parent = super::parent(d).ok_or("Recolor Artwork is no longer open")?;
let c = in_document_model(app, picked(d).color);
+56
View File
@@ -985,4 +985,60 @@ mod tests {
assert_eq!((&params["texture"], &params["textureImage"]), (&json!("loaded"), &json!(stored)));
let _ = std::fs::remove_dir_all(&dir);
}
/// Effect > Stylize > Outer Glow: a swatch beside Color shows the effect's colour, typing a
/// hex recolours it, and a double-click opens the Color Picker over the dialog; its OK fills
/// Color, and the effect applies that colour.
#[test]
fn outer_glow_colour_swatch_opens_the_color_picker() {
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 50})).unwrap()["id"].as_u64().unwrap();
app.run("select.all", json!({})).unwrap();
app.run("effect.dialog", json!({"effect": "stylize.outerGlow"})).unwrap();
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
crate::theme::apply(&ctx, Default::default());
let frame = |app: &mut VectorcraftApp, time: f64, events: Vec<egui::Event>| {
let mut out = ctx.run_ui(egui::RawInput { time: Some(time), events, ..Default::default() }, |ui| super::super::show(app, ui.ctx()));
out.textures_delta.clear();
out
};
for n in 0..6 {
frame(&mut app, f64::from(n) * 0.01, vec![]);
}
let rect = ctx.read_response(form::colour_swatch_id("color")).expect("the colour swatch is drawn").rect;
// The colour of the swatch drawn at `rect`.
let swatch = |out: &egui::FullOutput| {
out.shapes.iter().find_map(|c| match &c.shape {
egui::Shape::Rect(r) if r.rect == rect => Some(r.fill),
_ => None,
})
};
let yellow = egui::Color32::from_rgb(255, 255, 0);
assert_eq!(swatch(&frame(&mut app, 0.2, vec![])), Some(yellow), "the swatch shows the effect's #ffff00");
// Typing a colour recolours the swatch.
app.ui.dialog.as_mut().unwrap().fields.insert("color".into(), json!("#ff0000"));
assert_eq!(swatch(&frame(&mut app, 0.25, vec![])), Some(egui::Color32::from_rgb(255, 0, 0)), "typing a hex recolours the swatch");
// A double-click opens the Color Picker on the field's colour.
let pos = rect.center();
let button = |pressed| egui::Event::PointerButton { pos, button: egui::PointerButton::Primary, pressed, modifiers: egui::Modifiers::NONE };
frame(&mut app, 0.3, vec![egui::Event::PointerMoved(pos), button(true)]);
frame(&mut app, 0.35, vec![button(false)]);
frame(&mut app, 0.4, vec![button(true)]);
frame(&mut app, 0.45, vec![button(false)]);
frame(&mut app, 0.5, vec![]);
let d = app.ui.dialog.as_ref().expect("a dialog");
assert_eq!(d.kind, "colorPicker", "a double-click opens the Color Picker over the effect dialog");
assert_eq!(d.fields.get("color").and_then(vectorcraft_engine::cmd::color_value), Some(Color::rgb(1.0, 0.0, 0.0)), "on the field's colour");
// Its OK fills the effect's Color, and the effect applies it.
app.ui.dialog.as_mut().unwrap().fields.insert("color".into(), json!("#00ff00"));
super::super::confirm(&mut app).unwrap();
let d = app.ui.dialog.as_ref().expect("the effect dialog is back");
assert_eq!((d.kind.as_str(), d.fields.get("color")), ("effect", Some(&json!("#00ff00"))), "OK fills Color and comes back");
frame(&mut app, 0.6, vec![]);
super::super::confirm(&mut app).unwrap();
let st = app.session.doc().unwrap();
let fx = &st.doc.node(vectorcraft_doc::NodeId(id)).unwrap().appearance.effects[0];
assert_eq!(fx.params.get("color"), Some(&json!("#00ff00")), "Outer Glow takes the picked colour");
}
}
+55 -6
View File
@@ -3,6 +3,7 @@
use serde_json::{Value, json};
use vectorcraft_doc::Unit;
use vectorcraft_doc::color::Color;
use vectorcraft_plugins::{Manifest, Param, ParamSpec};
use crate::state::Dialog;
@@ -168,6 +169,26 @@ fn choices(kind: &str, key: &str) -> Vec<(&'static str, &'static str)> {
}
}
/// The id of the colour swatch beside the field `key` (a test clicks it; [`colour_swatch`] draws it).
pub(super) fn colour_swatch_id(key: &str) -> egui::Id {
egui::Id::unique(("fx-colour-swatch", key))
}
/// The colour swatch beside the colour field `key`, showing `colour`: a double-click asks for the
/// Color Picker over this dialog, whose OK fills the field ([`super::color_picker::over_effect`]).
/// Returns whether the picker was asked for.
fn colour_swatch(ui: &mut egui::Ui, key: &str, colour: Color) -> bool {
let t = Tokens::get(ui.ctx());
let (rect, _) = ui.allocate_exact_size(egui::vec2(20.0, 18.0), egui::Sense::hover());
let resp = ui.interact(rect, colour_swatch_id(key), egui::Sense::click());
let [r, g, b, _] = colour.to_rgba8(1.0);
ui.painter().rect_filled(rect, 2.0, egui::Color32::from_rgb(r, g, b));
ui.painter().rect_stroke(rect, 2.0, egui::Stroke::new(1.0, t.input_border), egui::StrokeKind::Inside);
if resp.hovered() {
ui.ctx().set_cursor_icon(egui::CursorIcon::PointingHand);
}
resp.double_clicked()
}
/// A text field `width` wide bound to `d.fields[key]`. Returns true when it changed.
pub(super) fn text(ui: &mut egui::Ui, d: &mut Dialog, key: &str, width: f32) -> bool {
text_edit(ui, d, key, width).changed()
@@ -403,6 +424,7 @@ pub(super) fn param_fields(
) -> bool {
let t = Tokens::get(ui.ctx());
let mut changed = false;
let mut pick: Option<(String, Color)> = None;
egui::Grid::new("fxgrid").num_columns(2).spacing([12.0, 8.0]).show(ui, |ui| {
let mut keys: Vec<(String, Value)> =
d.fields.iter().filter(|(k, _)| !k.starts_with("__") && k.as_str() != "preview").map(|(k, v)| (k.clone(), v.clone())).collect();
@@ -480,18 +502,42 @@ pub(super) fn param_fields(
}
}
Value::String(mut s) => {
if ui.add(egui::TextEdit::singleline(&mut s).align(egui::Align2::LEFT_CENTER).desired_width(140.0)).changed() {
d.fields.insert(k.clone(), json!(s));
changed = true;
// A hex colour (#rrggbb or #rgb) shows its swatch beside the field; the swatch's
// double-click opens the Color Picker over this dialog.
let mut colour = None;
let mut ask = false;
ui.horizontal(|ui| {
if ui.add(egui::TextEdit::singleline(&mut s).align(egui::Align2::LEFT_CENTER).desired_width(140.0)).changed() {
d.fields.insert(k.clone(), json!(s));
changed = true;
}
colour = crate::panels::color::parse_hex(&s);
if let Some(c) = colour {
ask = colour_swatch(ui, &k, c);
}
});
if ask && let Some(c) = colour {
pick = Some((k.clone(), c));
}
}
// A color object shows as its hex; typing in the field stores the typed text.
other => match color_object(&other) {
Some(c) => {
let mut s = c.to_hex();
if ui.add(egui::TextEdit::singleline(&mut s).desired_width(140.0)).changed() {
d.fields.insert(k.clone(), json!(s));
changed = true;
let mut colour = None;
let mut ask = false;
ui.horizontal(|ui| {
if ui.add(egui::TextEdit::singleline(&mut s).desired_width(140.0)).changed() {
d.fields.insert(k.clone(), json!(s));
changed = true;
}
colour = crate::panels::color::parse_hex(&s);
if let Some(c) = colour {
ask = colour_swatch(ui, &k, c);
}
});
if ask && let Some(c) = colour {
pick = Some((k.clone(), c));
}
}
None => {
@@ -503,6 +549,9 @@ pub(super) fn param_fields(
ui.end_row();
}
});
if let Some((key, colour)) = pick {
*d = super::color_picker::over_effect(d, &key, colour);
}
changed
}
+2 -1
View File
@@ -1,6 +1,6 @@
# Roadmap: milestones and what's next
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Pencil and Paintbrush: a new stroke with Keep selected off leaves nothing selected, #5752; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
## Feature submission evidence
@@ -36,6 +36,7 @@ M7 type: Touch Type moves a right-to-left character along its line and up from i
| Date | Change | Summary |
|---|---|---|
| 2026-11-05 | minor | Effect dialogs: a colour swatch beside a hex colour field follows typed values, and a double-click opens the Color Picker over the dialog, whose OK fills the field (#5365); scores and estimates unchanged. |
| 2026-11-05 | minor | Selection Tools add-on: Select Linked, Embedded, Missing and Modified select the images and placed documents with that link status (Object › Plug-ins › Selection Tools and the Links panel menu; Shift adds), and Select by Link Status… lists them by name, status and format to pick from, optionally zooming to them; what is hidden, locked, on a template layer or outside the isolated group is left out and the status bar says how many (#5526, a VectorCraft addition); scores and estimates unchanged (estimated). |
| 2026-11-05 | minor | Pencil and Paintbrush: a new stroke with Keep selected off leaves nothing selected, the earlier selection included, while Keep selected on selects only the new path (#5752); scores and estimates unchanged. |
| 2026-11-05 | minor | Layers panel: a layer whose Layer Options › Print is off shows its name italic, as the reference application shows non-printing layers, and keeps it while the row is dragged (#5739); scores and estimates unchanged. |
+4 -2
View File
@@ -1,6 +1,6 @@
# Parity with Adobe Illustrator
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Libraries panel colours keep their spot ink in every document, #5812; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
## Feature submission evidence
@@ -31,6 +31,7 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard
| Date | Change | Summary |
|---|---|---|
| 2026-11-05 | minor | Effect dialogs: a hex colour parameter (Outer Glow's Color, Inner Glow's, Drop Shadow's) shows a swatch beside the field that follows typed hex values; a double-click opens the Color Picker over the dialog on that colour, and its OK fills the field while Cancel comes back unchanged (#5365); scores and estimates unchanged. |
| 2026-11-05 | minor | Libraries panel: a spot colour added to a library (from the selection or dragged from the Swatches panel) keeps its ink name, values and tint in the library file; used in any document, also a new one or after the original was closed, it links the paint to that document's spot swatch of the same name, adding it when the document has none of that colour, in one undo step (#5812). Test: `tests::library::a_spot_colour_stays_spot_in_another_document`. Scores and estimates unchanged. |
| 2026-11-05 | minor | Eyedropper colour sampling from a path or compound path with one visible stroke no longer rebuilds its path merely to choose among stroke layers. Multiple strokes still sample the topmost one that reaches the point; colours, scores and estimates are unchanged. |
| 2026-11-05 | minor | Adding a selected colour, gradient or pattern to a library measures the source object's geometry once rather than twice. Gradient placement, library contents, scores and estimates are unchanged. |
@@ -200,7 +201,7 @@ dominate; 3D, graphs and automation are specialist). They sum to 105. Feature de
| Export for Screens, Asset Export, slices, Save for Web | 3 | 85% | anti-aliasing ghost borders (#983); TIFF choices and settings are implemented | 2–4 | estimated |
| Print, colour management, separations, flattener | 3 | 80% | print preview fidelity | 2–4 | estimated |
| Automation (Actions, Variables, scripting, batch) | 3 | 60% | a scripting surface (Illustrator: JavaScript/ExtendScript), Batch, image and graph variables, dataset import/export | 8–14 | estimated; MCP `add_text` exposes existing vertical type; score and hours unchanged |
| UI chrome (panels, Properties, workspaces, preferences) | 6 | 80% | Properties per context, 3 Preferences options stored but unused (#394, audited 2026-10-30: Open Documents As Tabs, Scratch Disks, legacy vector clipboard), SVG Interactivity, context menus beyond the canvas, accessibility | 13–20 | estimated; floating panels in OS windows of their own on the desktop (#4135), score and hours unchanged; macOS save Format menu implemented (#866), score and hours unchanged; Eyedropper cursor and precise setting checked (#1269), OS visual QA unverified; numeric-field focus and normal text drags regression-tested (#1326, in part); movements below the click threshold still select all; artboard navigation synchronizes the tool selection before destructive actions; status messages and readouts use stable responsive allocations sized for localized labels and ordinary coordinates (sample widths cached by language/unit/DPI; regression and contributor original-file evidence below; scores/hours unchanged) |
| UI chrome (panels, Properties, workspaces, preferences) | 6 | 80% | Properties per context, 3 Preferences options stored but unused (#394, audited 2026-10-30: Open Documents As Tabs, Scratch Disks, legacy vector clipboard), SVG Interactivity, context menus beyond the canvas, accessibility | 13–20 | estimated; floating panels in OS windows of their own on the desktop (#4135), score and hours unchanged; macOS save Format menu implemented (#866), score and hours unchanged; Eyedropper cursor and precise setting checked (#1269), OS visual QA unverified; numeric-field focus and normal text drags regression-tested (#1326, in part); movements below the click threshold still select all; artboard navigation synchronizes the tool selection before destructive actions; status messages and readouts use stable responsive allocations sized for localized labels and ordinary coordinates (sample widths cached by language/unit/DPI; regression and contributor original-file evidence below; scores/hours unchanged); effect dialogs' colour fields show a swatch that opens the Color Picker (#5365), score and hours unchanged |
| Libraries, Links, Package | 2 | 82% | shared libraries, linked graphics, gradients and patterns as library items (no cloud by design) | 2–3 | estimated |
| Generative AI (Text to Vector, Generative Recolor, Shape Fill, Concept to Vector, Prompt to Edit, Rewrite Text) | 2 | 0% | a pluggable provider and the panels; needs an owner decision on models | 30–60 | measured (absent) |
| **Feature depth** | **105** | **~75%** | | **~250–420** | |
@@ -1079,6 +1080,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
View › Proof Setup › Color blindness – Tritanopia-type turns Proof Colors on and proofs the canvas with the tritanopia simulation of Brettel, Viénot and Mollon (1997). The Separations Preview panel's Proof Setup list offers the same target (`view.proofSetup {target: "tritanopia"}`). Grays keep their value.
The Separations Preview panel's Gamut Check button reports one color outside the CMYK gamut in the singular and more in the plural, in English and in each language's plural forms (`gamut_check_status_takes_the_plural_form` in `crates/ui-egui/src/i18n/tests.rs`).
- **Document Color Mode outside the layers:** File › Document Color Mode (in one undo step) and `document.open {colorMode}` also convert the colors of graph designs, graphic styles, opacity-mask art, the tile that pattern editing's Cancel puts back and the art of brushes (with a Hue Shift brush's key color); a tint of a global swatch there becomes the converted swatch's color at its tint, as in the art.
- **Colour swatches in effect dialogs (#5365):** a colour parameter of an effect dialog (Outer Glow's Color, Inner Glow's, Drop Shadow's) shows a swatch beside its hex field that follows the value typed in it; a double-click on the swatch opens the Color Picker over the dialog on that colour, whose OK fills the field and whose Cancel comes back unchanged, and the dialog previews the colour when it returns (`dialogs::effect` test `outer_glow_colour_swatch_opens_the_color_picker`).
- **Document Color Mode for effects and graphs:** File › Document Color Mode and `document.open {colorMode}` convert the colors of effects (Drop Shadow, Inner Glow, Outer Glow and the other effects with a color, on objects, their fills and strokes and in graphic styles) and the series paints and label styles that a graph keeps, so a graph drawn again from new data keeps the converted colors; File › Document Color Mode also converts the fill and stroke that new art takes. Undo restores the original new-art fill and stroke and Redo applies the conversion again.
- **Recolor Artwork layout (#3416):** the Edit chip list uses the modal scroll helper and its actual remaining height; the tab's minimum-height space scrolls with the chips. `tests_recolor` covers 5/20/200/400 colors, window resizing, 100/125/150/200% UI scaling, scrolling to and editing the final chip, Preview, Cancel, Confirm and Undo, alongside the existing #1733 drag regressions. Scores and estimates unchanged.
- **Recolor Artwork Edit displays:** buttons beside the Edit tab's wheel show the colors on a smooth color wheel, a segmented color wheel or as color bars ([Edit colors using Recolor Artwork](https://helpx.adobe.com/illustrator/desktop/manage-colors/modify-colors/edit-colors-using-edit-colors-dialog.html)). The segmented wheel draws 24 hues by 5 saturations as solid patches, and its markers move freely as on the smooth wheel. The bars show one solid bar per recolored color in row order: a click selects a bar for the color sliders, and a drag moves its row without changing a color ([Advanced recolor options overview](https://helpx.adobe.com/illustrator/desktop/manage-colors/learn-color-basics/edit-colors-dialog-overview.html)). The dialog opens on the smooth wheel; `display` (`smooth`, `segmented`, `bars`) is the dialog field. `tests_recolor` covers switching, the dialog height, segmented dragging and Brightness, and bar selection, editing, reordering, scrolling, Preview, Cancel and OK. Scores and estimates unchanged.
+3 -1
View File
@@ -1,6 +1,6 @@
# UI and interaction parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Shape tools: a shape just drawn shows its bounding box and Live Shape widgets, and its corner and pie widgets drag with the shape tool, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
## Feature submission evidence
@@ -38,6 +38,7 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard
| Date | Change | Summary |
|---|---|---|
| 2026-11-05 | minor | Effect dialogs: a swatch beside a hex colour field follows typed values, and a double-click opens the Color Picker over the dialog, whose OK fills the field (#5365); scores and estimates unchanged |
| 2026-11-05 | minor | Shape tools: a shape just drawn keeps its bounding box and Live Shape widgets on show with the Rectangle, Rounded Rectangle, Ellipse, Polygon or Star tool, and its corner and pie widgets drag as with the Selection tool (#5477); scores and estimates unchanged |
| 2026-11-05 | minor | Character panel › Show Snap to Glyph Options scrolls the panel down to the Snap to Glyph section, which comes after every character attribute and could sit out of sight, and the section starts with a Snap to Glyph checkbox (View › Snap to Glyph) so its dimmed options can be turned on there (#5273); scores and estimates unchanged |
| 2026-11-05 | minor | Appearance panel: Delete Selected Item (and Delete/Backspace, and Remove Item in the panel menu) on a selected Opacity row, the object's or a fill's or stroke's, sets it back to Default (100%, Normal) as one undo step instead of being dimmed (#5742); scores and estimates unchanged |
@@ -135,6 +136,7 @@ tools, never checked side by side) isn't captured row by row.
| Add/Delete/Anchor Point tools; Anchor Point tool drags segments to reshape | done | #2267: a click on a handle end retracts that handle and leaves the anchor a corner with the other one; Shift held at the press on an anchor moves it, handles and all (Shift kept down: at 45° steps) instead of pulling out handles |
| Pencil: Fidelity, Keep selected, Alt to Smooth, edit selected paths, close by proximity | done | Fidelity goes down to 0.01 pt in the dialog, the tool and `path.freehand` (the Smooth tool keeps 0.05); its slider runs across the Tool Options row on a logarithmic rail from 0.01 to 20 pt, the field shows hundredths, and the slider's and the field's arrow keys step hundredths up to 0.1 pt, tenths up to 1 pt and whole points above (Shift ×10) (#3328); Alt key toggles to Smooth Tool (#2001); Shift held at the press draws a straight line at 45° steps from the Constrain Angle, and Alt held at the press (with Alt key toggles to Smooth Tool off) a straight line at any angle (#3799), with a straight-line cursor while Shift or Alt is held before the press, and a path-continuation cursor over an end of a selected open path, where the line continues the path; Edit Selected Paths continues a selected path from an end and, from a stroke that starts and ends on a selected path, redraws the section between (the shorter way round a closed path, #2850); with Keep selected (Pencil and Paintbrush, on by default) on, a stroke selects the path it draws or continues and replaces the earlier selection, and off a new stroke leaves nothing selected, the earlier selection included, while a continued or redrawn path is deselected and the rest of the selection stays; a filled Pencil path keeps a stroke of None (#1804, part of #1679); while a freehand stroke is drawn back to within Close Paths When Ends Are Within of its start, the Pencil and the Paintbrush show the closing cursor, and a release there closes the path |
| Pencil: Fidelity, Keep selected, Alt to Smooth, edit selected paths, close by proximity | done | Alt key toggles to Smooth Tool (#2001); Shift held at the press draws a straight line at 45° steps from the Constrain Angle, and Alt held at the press (with Alt key toggles to Smooth Tool off) a straight line at any angle (#3799), with a straight-line cursor while Shift or Alt is held before the press, and a path-continuation cursor over an end of a selected open path, where the line continues the path; Edit Selected Paths continues a selected path from an end and, from a stroke that starts and ends on a selected path, redraws the section between (the shorter way round a closed path, #2850); with Keep selected (Pencil and Paintbrush, on by default) on, a stroke selects the path it draws or continues and replaces the earlier selection, and off a new stroke leaves nothing selected, the earlier selection included, while a continued or redrawn path is deselected and the rest of the selection stays; a filled Pencil path keeps a stroke of None (#1804, part of #1679); while a freehand stroke is drawn back to within Close Paths When Ends Are Within of its start, the Pencil and the Paintbrush show the closing cursor, and a release there closes the path; a Pencil stroke from an end of one selected open path to an end of another connects the two into one path |
| Effect dialogs' colour fields: a swatch beside the hex follows typed values, and a double-click opens the Color Picker over the dialog, whose OK fills it and Cancel comes back unchanged (#5365) | done | dialogs::effect test outer_glow_colour_swatch_opens_the_color_picker; the picker previews nothing itself, the effect dialog previews the returned colour |
| Join tool scrubbing, Average, Join | done | Join merges the direct-selected anchors lying on one another along a path, as after Average, into one (#1533) |
| Average and Join in one step, with a corner or smooth choice for the joined anchor | done | Object › Path › Average & Join… (`path.averageJoin`, Cmd+Alt+Shift+J, "Create corner or smooth join" in [Default keyboard shortcuts](https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html)): two open path ends meet at their midpoint and join, a corner or smooth point as the dialog's Points choice asks (Corner first, then the last choice), in one undo step |
| Smooth tool smooths only the stretch of path under the drag | done | #1512 |