Clicking an Opacity row in the Appearance panel (a fill's or stroke's, or
the object's) opens a popup with the same blend-mode dropdown, opacity
field and slider as the Transparency panel (widgets::opacity_blend), and
edits that item through transparency.set. The blend-mode dropdown draws a
separator between the BlendMode::group() groups, also for the blend-mode
parameters of effect dialogs and inline effect editors. Fills and strokes
of type objects composite with their own opacity and blend mode.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
effect.apply, effect.remove, effect.setParams and the new effect.duplicate
take item (omitted: the Appearance panel's active item, else the object;
null: the object's own effects), so the fx button, the Effect menu, Apply
Last Effect and the effect dialogs (effect.dialog {item}) put the effect on
the selected fill or stroke. effect.list reports each object's item effects
and the active item. appearance.addEffect is an alias of effect.apply.
In the Appearance panel, item effect rows sit under their fill or stroke
with working eyes and inline editors, and can be selected for Duplicate
and Delete; a selected effect row is remembered per object.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No behaviour change: every command keeps its id, label, menu, shortcut and
params doc.
- Engine: swatch.* -> cmd/swatch.rs, graphicStyle.* -> cmd/style.rs,
appearance.* (incl. copyFrom) -> cmd/appearance.rs, stroke.set/setAdvanced
-> cmd/stroke.rs, paint.editGradient/setGradientGeom -> cmd/gradient.rs.
Shared helpers in cmd/mod.rs: leaf_targets/paint_targets (replacing three
copies) and unique_name (swatch and graphic style naming).
- UI: dialogs.rs -> dialogs/ with one file per dialog and a DialogSpec
registry (one DialogKind row per dialog); shared field widgets in
dialogs/form.rs. Headless frame tests draw and confirm every dialog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>