Commit Graph
378 Commits
Author SHA1 Message Date
dotCooCoo 367c092fee Layers: deleting layers that hold art asks first
The Layers panel's trash button, rows dropped on it, the panel menu's
Delete Selection, and Delete or Backspace on highlighted rows now run
ui.layerDelete. When a layer or sublayer among the rows holds art
(hidden, locked and nested objects count; guides do not), a confirm
dialog asks first. OK deletes the rows it asked about, by id, in the
document it was asked in, as one undo step; Cancel keeps them. Empty
layers, guide-only layers and object or group rows alone are deleted at
once. layer.delete itself is unchanged and never asks.
2026-11-12 20:43:56 -08:00
BFlat 39f7d33e22 Merge pull request #6943 from dotCooCoo/feat/color-rgb-percent
Color: a double-click right of an RGB field switches between percent and 0 to 255
2026-11-13 08:31:01 +07:00
dotCooCoo d3375c1656 Color: Toggle RGB Percent switches the RGB units from the keyboard
The double-click right of an RGB field was the only way to switch R, G and B
between percent and 0 to 255 from the UI. ui.colorRgbPercent (Toggle RGB
Percent) is listed in the command palette and in Keyboard Shortcuts without a
default key, and switches the same setting. A parameter answers an error and
changes nothing. The label has a row in every complete catalog.
2026-11-12 16:04:30 -08:00
dotCooCoo 5494e1aaa7 Merge main into feat/color-rgb-percent 2026-11-12 15:11:03 -08:00
dotCooCoo cfff971d06 Merge main into fix/pdf-large-page-export 2026-11-12 14:40:47 -08:00
dotCooCoo 264a6541e6 Merge main into fix/dialog-set-hidden-fields 2026-11-12 12:55:47 -08:00
dotCooCoo 7840dd33ae Save PDF: OK asks before replacing a picked file, and both routes write one title rule
File > Save as PDF... leaves the file to the save panel. When the panel
picked the file the document was opened from, and opening it left
things out, Save PDF's OK replaced it without asking. It now asks first,
as it does for a given path.

Export As PDF with Use Artboards off wrote DisplayDocTitle true for a
document without a title of its own, titled after its file, while the
same dialog with Use Artboards on, and document.exportPdf, wrote false.
Every PDF Export As writes now shows the title in the viewer only when
it is the document's own.

docs/control-protocol.md: app.export continues in savePdf for any PDF,
and ui.savePdfDialog's reply with useArtboards false is Export As's.
The progress-doc line is its own line.
2026-11-12 10:52:58 -08:00
dotCooCoo 74235d8959 Color: a double-click right of an RGB field switches between percent and 0 to 255
In RGB mode a double-click in the cell right of the R, G or B field
switches all three fields and sliders between 0 to 255 and percent (0 to
100 with a % suffix, as the CMYK fields show). The color does not change;
a typed percent converts back (50% is 127.5 of 255) and a slider click
picks a whole percent. Web Safe RGB, the hex field and the other modes
keep their units.

Only RGB rows have the cell. It is blank, is highlighted under the
pointer, and takes no keyboard focus, so Tab does not stop on it. The
RGB sliders are narrower by the cell's width and spacing, so an RGB row
is as wide as a row in the other modes and Tint, in a narrow panel too.
While a mixed selection disables the rows, a double-click on the cell
does nothing, as the fields beside it take no input.

The double-click runs ui.colorPanel {rgbPercent}, which takes a bool and
answers it. The setting is off by default and is kept with the
preferences (ui.color_rgb_percent); a saved value that is not true or
false reads as off. The color mixer in the Fill and Stroke chips'
popovers (Control bar and Properties panel) and the gradient stop dialog
show the same rows and follow the same setting.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
2026-11-12 10:33:17 -08:00
dotCooCoo e2ddeae50c Export As: a PDF without artboards opens Save PDF and its options
Export As starts with Use Artboards off. For a PDF it then wrote one
page of the art's bounds straight away with the default preset, so the
Save PDF dialog never showed and none of its options applied there,
"Write pages longer than 200 in at full size in points" included.

Export As now opens Save PDF with Use Artboards on or off. With it off,
the dialog has no Artboards section, and OK writes one page of the
visible art's bounds the way Export As writes its other formats: with
Background Export, the progress dialog and its Cancel, and the question
before replacing the file the document was opened from. View PDF after
Saving opens that file too.

document.exportPdf listed useArtboards among its options but did not
read it. false now writes the page that document.export writes, and
ignores artboard, artboards and range; both commands use one helper
for it. document.pdfSettings refuses a useArtboards that isn't true or
false, and with includeDocument it exports that page, so the Summary's
warnings are about it.

While an opacity mask or symbol is being edited, document.exportPdf
and document.pdfSettings leave out the editing layer, from the drawn
pages and from the Preserve Editing data, as document.export does.

With the artboards as pages too, Save PDF's OK over the file the
document was opened from, when opening it left things out, now asks
first (file.export.pdf), and the question stays open when the dialog
closes.
2026-11-12 09:54:09 -08:00
BFlat e618783377 Merge pull request #6084 from Taha-Mahmoodi/feat/glyph-alternates
Glyphs: alternates keep the word joined (feature values, one-piece shaping, unencoded glyphs)
2026-11-12 23:53:13 +07:00
BFlat 0cb73d0d66 Merge pull request #6845 from dotCooCoo/feat/linux-screen-color-portal
Color: Sample Color from Screen works on Linux through the desktop portal
2026-11-12 23:10:13 +07:00
Taha-Mahmoodi 7c6f51e8d6 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-12 19:37:53 +04:30
dotCooCoo 8db00cbbe2 Merge main into feat/linux-screen-color-portal 2026-11-12 05:54:25 -08:00
Ahmed Gomaa 421fead32b Merge upstream main into file/save-read-only-offers-save-as 2026-11-12 15:24:23 +02:00
dotCooCoo 1eaf4c4023 Merge main into fix/dialog-set-hidden-fields 2026-11-12 04:59:51 -08:00
Taha-Mahmoodi 2590186b32 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-12 16:45:00 +04:30
BFlat 0b4ccdfb5d Merge pull request #6830 from dotCooCoo/fix/artboard-files-ask-before-replacing
Save and Export: files written beside the picked one ask before replacing a file there
2026-11-12 19:13:47 +07:00
Ahmed Gomaa c66335eaa7 Merge upstream main into file/save-read-only-offers-save-as 2026-11-12 13:40:13 +02:00
Taha-Mahmoodi 9624b29dad Merge main into contextual glyph alternates 2026-11-12 15:56:45 +04:30
BFlat f4df78ef4a Merge pull request #6790 from dotCooCoo/feat/hpgl-export
File formats: HP-GL (.plt) plots export for pen plotters and cutters
2026-11-12 18:19:22 +07:00
Taha-Mahmoodi 4130ba226d Merge remote-tracking branch 'origin/main' into feat/glyph-alternates
# Conflicts:
#	docs/target-app-parity.md
2026-11-12 15:18:46 +04:30
dotCooCoo e6d5c8846e Color: Sample Color from Screen works on Linux through the desktop portal
On Linux, ui.sampleScreenColor and the Color Picker's eyedropper button
now show the XDG desktop portal's color sampler (Screenshot.PickColor,
https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Screenshot.html).
A thread of its own makes the call and waits for the person, and the
picked sRGB color goes through the same conversion into the working RGB
space as on macOS and the web. A cancel leaves the colors as they were.

A session without a portal that has PickColor, a portal that does not
return from the call within 25 seconds (VectorCraft's own limit) or
leaves the bus before it answers, and a portal that ends the request in
another way each show a status message and end the wait. The two new
messages are translated in every catalog that has the sampler's other
messages. The request token is random, as the Request documentation
asks (https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Request.html).

The window is named for the portal on the UI thread, as for the save
dialog, and the sampler's thread keeps the window and its export until
the portal answers.
2026-11-12 01:12:13 -08:00
dotCooCoo cc2d090335 Merge main into fix/artboard-files-ask-before-replacing 2026-11-12 00:41:07 -08:00
dotCooCoo 18fe6ad6fd Automation: ui.dialog.set cannot open Save Preset in Save PDF or Print
`__savePresetAs` makes OK save a preset instead of writing the PDF or
printing. ui.dialog.set now accepts it only while Save Preset... has
added the field, so a request cannot add it and confirm in one step.
2026-11-12 00:37:35 -08:00
BFlat 1a7aa834db Merge pull request #6786 from dotCooCoo/fix/save-export-show-every-note
Save and Export: the status bar's hover lists every note
2026-11-12 15:13:51 +07:00
Taha-Mahmoodi 5144f22976 Merge main 48e066f47 into glyph alternates #6084 2026-11-12 12:34:54 +04:30
dotCooCoo e6f330afd2 Automation: ui.dialog.set cannot change the command a dialog runs
ui.dialog.set took every field whose name starts with `__`, so a control
request (or MCP's answer_dialog, which goes through it) could rewrite the
`__command` and `__params` of a confirmation or the generic parameter
dialog, a plug-in command dialog's `__command`, or the paste a swatch
conflict waits to finish, after a person opened the dialog. The person's
OK then ran something else.

A `__` field is now settable only when it is a control of that kind of
dialog: a section or tab shown, a link between two fields, a name or
search being typed (for example Save PDF's `__section`, Transform Each's
`__constrain`, the Preferences `__search`). Every other `__` field, held
or not, is refused with "the `<kind>` dialog cannot set protected field
`<field>`". The request sets no field, and with `action: "confirm"` OK
does not run. Flags a button sets together with other fields are refused
too: the style dialogs' `__reset*`, Artboard Options' `__fit`,
`__sizeChoice`, `__refx` and `__refy`, and Scribble's `__scribbleSetting`.

Recolor's Merge takes a row listed twice in the selection once, and
Randomize keeps a seed at u64::MAX instead of overflowing it.

Docs: docs/control-protocol.md, docs/mcp.md, docs/target-app-parity.md.
2026-11-11 23:59:18 -08:00
dotCooCoo 7da7c2c456 Merge main into fix/artboard-files-ask-before-replacing 2026-11-11 23:51:03 -08:00
dotCooCoo b262d10e89 Save and Export: files written beside the picked one ask before replacing a file there
A save or export that writes a file per artboard, linked images or image
maps names them after the file picked in the save panel, which asked only
about that name. A file already there under one of the other names was
replaced without a question.

Save As, Save a Copy, Save as Template, Save and Export now check those
files before writing anything. When any is there, nothing is written and
a replaceFiles question names it (and lists all of them when there are
several). OK runs the save or export again on the document that asked and
replaces the named files; a file it would now write that the question did
not name is asked about again. Cancel writes nothing. A background save
or export checks from its worker and asks once it ends, after a dialog
open then. Files the document's last Save or Save As wrote are replaced
without asking.

Services::exists is now an Arc<dyn Fn(&str) -> bool + Send + Sync>.
2026-11-11 23:39:32 -08:00
dotCooCoo 9c5d22bccc Merge main into feat/hpgl-export 2026-11-11 23:31:04 -08:00
BFlat 5e63104d88 Merge pull request #6800 from dotCooCoo/fix/plugin-automation-install-approval
Plug-ins: an install that automation asked for is not approved in its dialog
2026-11-12 14:16:59 +07:00
BFlat abfd776ef4 Merge pull request #6797 from dotCooCoo/feat/dxf-leave-out-images-hatches
DXF: export options leave placed images and fill hatches out, and CNC / CAM turns both off
2026-11-12 14:16:20 +07:00
dotCooCoo 60c2130960 Merge main into feat/hpgl-export 2026-11-11 22:29:22 -08:00
BFlat ee6aae1d1d Merge pull request #6769 from dotCooCoo/fix/options-dialog-menus
EPS: Save As options are menus with readable names, and Export As's Range shows an example
2026-11-12 13:17:11 +07:00
dotCooCoo ad05c3b99d Plug-ins: an install that automation asked for is not approved in its dialog
An approval question that a control request, MCP, injected input, or a
file dialog one of them opened leads to now keeps OK disabled and
refuses every confirm, a person's click included. The dialog says to
choose Object › Plug-ins › Install Plug-in…, and ui.installPlugin answers
approval: "personMustStartInstall". The person's own Install Plug-in…,
File › Open or drop inspects the module again and asks a new question
with its half-second delay.

The origin is fixed when the request is made and goes with a native
file dialog's deferred answer and the web picker's answers, which now
arrive apart from drops and from window.vectorcraft.openFile (always
automation). A question about taking another module's place now opens
in the approval dialog, and automation's replace: true no longer skips
it. A module that needs no approval still installs at once.
2026-11-11 21:56:58 -08:00
dotCooCoo f1251af6e4 DXF: export options leave placed images and fill hatches out, and CNC / CAM turns both off
DXF Options gets Include Placed Images and Include Fill Hatches, and
document.exportDxf and document.export {format: dxf} take
includeImages and includeHatches. Both are VectorCraft's own options
and default to true, so Custom exports write what they wrote before.

- includeImages: false writes no IMAGE entity, IMAGEDEF, reactor or
  linked file for a placed image, and does not decode its pixels.
- includeHatches: false writes each filled area's outlines without the
  solid HATCH after them.
- Each adds one note to warnings when it left something out. R12,
  which has neither, keeps its own notes.
- The CNC / CAM preset sets both to false, so its drawing holds the
  cutting paths alone; the options given still override it, and
  changing either checkbox shows Custom.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
2026-11-11 21:10:30 -08:00
dotCooCoo 35be7952c8 Save and Export: the status bar's hover lists every note
A save or an export with several notes named only the first of them in
the status bar, with the count, and the others could not be seen. The
status bar now keeps every note of a save or an export for the status
message's hover, as it does for an open's notes since #6752: resting
the pointer on the message lists them in the order the reply gives them
(a save's notes start with what the format loses), and screen readers
receive the list after the message. The status text is unchanged.

This covers Save, Save As, Save a Copy, Save as Template, Save a
Timestamped Copy, Save as PDF, Export As, Export Selection, Export for
Screens, Asset Export, Save for Web, Preview in Browser, Save for Office
Documents, Text Export Options, a print to a file and the CSS Properties
panel's export. The open, the saves and the exports read a reply's notes
through one helper.

Docs: docs/mcp.md and the css.exportFile params text,
docs/control-protocol.md, docs/target-app-parity.md.
2026-11-11 20:44:53 -08:00
dotCooCoo 987dd18aff File formats: HP-GL (.plt) plots export for pen plotters and cutters
VectorCraft could open and place HP-GL plot files but not write them,
so art for a pen plotter or a vinyl cutter had to go through another
program.

Export As, document.export and Export Selection now write HP-GL.
vectorcraft_cad::hpgl::export draws each visible path once along its
own line: a filled shape is its closed outline and a stroked path its
center line. Type is drawn as glyph outlines, a gradient mesh as its
outline, and a symbol instance as its art with its effects and the
instance's stain. Clipping masks cut the art they clip, and the art is
cut at the artboard's edges. Hidden and non-printing layers, hidden objects,
objects at 0% opacity, template layers, guides and placed images are
left out. Coordinates are plotter units (1016 to the inch, y up) from
the artboard's bottom-left corner or its center, and art more than
8,388,607 units from the origin is cut off.

Each color is a pen, in the order the plot first draws in it (up to
255), or a pen table maps each path to the pen of the nearest color.
With Use Artboards every file of the export uses the same numbering.
The pens draw in turn, each in paint order or, with sortPaths, nearest
path first. Curves are flattened to curveTolerance (0.1 pt by default).
hpglVersion "hpgl" writes IN, SP, PU and PD; "hpgl2" also writes the
palette (NP, PC) and each pen's paths as one encoded polyline (PE).
Options are checked, and Export As writes the file with the defaults.
Plots read back by the HP-GL reader give the same lines.

Docs: docs/mcp.md, docs/control-protocol.md, docs/file-format-parity.md,
docs/target-app-parity.md.
2026-11-11 20:44:32 -08:00
dotCooCoo a9e7dfb2f8 Merge main into fix/options-dialog-menus 2026-11-11 19:59:50 -08:00
dotCooCoo 7559607037 Document Setup: a Color tab sets the color mode and the assigned profiles
Document Setup gets a Color tab with the document color mode (RGB Color
or CMYK Color), a Convert to CMYK or Convert to RGB box for a mode
change (cleared, the colors keep their numbers), and the RGB and CMYK
profiles assigned to the document, with a working-space entry for none.

When the tab changes something, OK runs document.setup, then
edit.assignProfile, then file.documentColorMode in one command.batch,
and the document's changes are one undo step. Assign Profile runs first,
so a mode change converts through the profile picked with it. An
unchanged Color tab adds no color commands, and Cancel, or OK with
nothing changed, records no undo step. A Color tab field with a value of
the wrong kind is an error, and the dialog stays open with nothing
changed. File › Document Color Mode and Edit › Assign Profile… stay
where they are.

Catalogs: "Working RGB (don't tag)" and "Assign Profile" rows in every
complete catalog, and the "`{key}` must be a profile name or null"
message in every complete-message catalog. Docs: docs/mcp.md,
docs/control-protocol.md, docs/target-app-parity.md.
2026-11-11 19:08:06 -08:00
dotCooCoo 935ebccc25 EPS: Save As options are menus with readable names, and Export As's Range shows an example
Save As to an EPS file showed Preview Format, Overprints and Flattener
Preset as text fields holding their ids (tiffColor, preserve, medium),
the PostScript level as a number field, and labeled every EPS option
except Use Artboards from its name ("Cmyk Post Script", "Thumbnails").

The dialog now shows the options Export's EPS Options shows. Preview,
Overprints, Flattener preset (the built-in presets, then saved ones) and
PostScript are menus of readable names. Transparent and Opaque apply to
the color TIFF preview only. Embed Fonts shows checked and disabled. The
PostScript level comes last. A pick writes the same values as before
(previewFormat "tiffColor", a built-in preset's id, a saved preset's
name, the level as a number). A value that the save would reject shows
as it is.

Every option the dialog shows has a written label. "Preview:" has a row
in every catalog, and the de, it, ja, ko, uk, vi and zh-hant catalogs
gain the menu names, which Export's EPS Options also showed in English.

Export As's Range field shows the "1-3, 5" example when emptied, as
Save As's does.
2026-11-11 19:04:27 -08:00
BFlat 765bd30783 Merge pull request #6744 from dotCooCoo/feat/color-show-recent-colors
Color: the panel menu's Show Recent Colors shows or hides the Recent Colors row
2026-11-12 09:55:35 +07:00
BFlat 01efd56ee3 Merge pull request #6752 from dotCooCoo/fix/open-shows-every-import-note
Open: the status bar names what the file left out first, and its hover lists the notes
2026-11-12 09:40:03 +07:00
dotCooCoo 912610eb60 Open: the status bar names what the file left out first, and its hover lists the notes
After File > Open the status bar showed only the first of the import's
notes. A file whose layers weren't read could give another note first:
the EPS reader adds its note about brushes left out of the Brushes panel
before the note that the file came in as its page, so the status bar
named the brushes and not the page.

The status bar now names the first note that says reading the file left
something out (the notes that make Save ask before writing over the
file), else the first note, and still counts them all. When there are
several, hovering the message lists them in that order, translated where
the catalogs have them, as many as fit in the window and at most 30,
then how many more. Screen readers get the list after the message. The
status bar shows the list only while it shows the open's message. The
open's reply keeps its notes in the import's order.

Docs: docs/control-protocol.md (app.open), docs/target-app-parity.md.
2026-11-11 17:52:53 -08:00
dotCooCoo 62b6f53533 Color: the panel menu's Show Recent Colors shows or hides the Recent Colors row
The Color panel's menu gets a checked Show Recent Colors item under Show
Options / Hide Options. Unchecking it hides the panel's Recent Colors row;
checking it shows the row again. Applied colors still join the list while
the row is hidden, Hide Options hides the row either way, and the Swatches
panel keeps its own row.

The setting is on by default and is kept with the preferences
(ui.color_show_recent_colors); a saved value that is not true or false
reads as on. ui.colorPanel takes recentColors: bool and answers it.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
2026-11-11 17:26:16 -08:00
Ahmed Gomaa f0e50437c2 Save on a read-only location offers Save As
A plain Save that the location refuses (read-only filesystem or permission denied) now opens Save As with the name filled in, instead of ending in an error dialog. The refusal travels as a typed engine error (READ_ONLY_LOCATION), so the control protocol and MCP still return an error and never open a panel. Recovery failures, explicit destinations, a busy picker and Close/Quit keep their existing flow.

Closes #6146
2026-11-11 23:16:03 +02:00
dotCooCoo 3d7803289c Toolbars: a + button on a new toolbar adds and removes tools from a menu
A toolbar made with New Toolbar was filled only by dragging tools from
its All Tools drawer, which the ••• button opens. It now also has a +
button (Add Tool…) above the ••• button. Its menu lists every tool under
the drawer's headings; a click adds the tool at the end of that toolbar
(toolbar.addTool with toolbar), and the tools already in it are dimmed.
Under Remove Tool the menu lists the toolbar's tools, and a click takes
one out (toolbar.removeTool). The button takes the keyboard focus, and
the menu scrolls inside the window like the other long menus.

The drawer and its drags work as before. Add Tool… and Remove Tool have
rows in every catalog.
2026-11-11 11:57:53 -08:00
dotCooCoo 5d7e2fa8e1 MCP: ui.inspect leaves out paths outside the read roots
Under --automation-read-root, ui.inspect returned the paths of documents
still opening, the recent files, library panels' files and the folder
preferences even when they lay outside the read roots. The reply now
leaves them out, checked with file_access::check_read as ui.menu.list
checks recent files and listed scripts:

- opening and ui.recent_files keep only the readable paths, in order.
- A library panel keeps its row without its path; a library loaded from
  outside the roots shows as loaded/<file name> in its id and panel id,
  in ui.inspect and ui.docking.
- The folder preferences in ui.engine_prefs and in an open Preferences
  dialog are left out; an empty folder and the scratch disk choices
  Startup and None stay.

The app's own state is not changed. Without roots the replies are as
before.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
2026-11-11 06:13:33 -08:00
Taha-Mahmoodi a990a6fc45 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 16:59:07 +04:30
dotCooCoo dfa6e6ea60 MCP: ui.menu.list leaves out recent files outside the read roots
Under --automation-read-root, a control client's ui.menu.list (and
ui.contextMenu.list, which shares the listing) left every File › Open
Recent Files row in, so the client saw the names of recent files it may
not read. file.recentFiles returned their full paths, and
file.openRecentN for such a file answered with a refusal naming the path.

Now the listing leaves out a recent file outside the read roots, as it
already leaves out listed scripts outside them. The other rows keep their
ids, so file.openRecent3 still opens the third file. file.recentFiles
returns only the files inside the roots, in order, and file.openRecentN
for a file outside them ends with "no such recent file", as an empty slot
does. The person's own menus and Home screen are unchanged.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
2026-11-11 03:20:14 -08:00