ColorScheme, ColorSchemeRegistry, ColorSchemeSerializer and the Schemes
folder move into the toolkit-neutral library, keeping the OpenNest
namespace, so the Avalonia app can share the built-in palettes, the
scheme files and the recolour-on-open rule.
ColorScheme is now pure colour data with a Version that changes with
any colour. Its GDI+ pens and brushes move to GdiSchemeTools in the
WinForms project (still one set per thread, rebuilt after a colour
change), reached through scheme.Gdi(). The legacy part outline uses
ColorShade.Dark, a port of ControlPaint.Dark's HLS arithmetic; a
WinForms test compares the two across a colour sweep on Windows.
The registry no longer walks Application.OpenForms: Apply raises
Applied, and EditNestForm subscribes once to recolour every open nest
window as before. The saved scheme is read under the same
ActiveColorScheme setting (SavedSchemeName/ApplySaved for the shared
user-settings file); WinForms still reads it through Settings.Default.
Schemes/*.json now copies beside both desktop apps from OpenNest.Desktop.
Pure scheme tests move to OpenNest.Desktop.Tests, with new ones for
built-in round trips, scheme files, bad files, the saved name and the
recolour rule.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shift+click in Clone Parts always kept whichever axis order landed the
copy nearest the origin, which can park it in a pocket the user didn't
want. Options > Clone push placement now picks Closest to origin (the old
behavior, still the default), Push left then down, or Push down then left.
Ctrl+click settles the copy on bounding boxes alone, so it stops square
to its neighbors' boxes instead of nesting into their shapes. Shift+click
keeps its box pass then geometry settle; both follow the chosen order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A part's sequence-number label point was computed once from the drawing's
program and cached forever. Editing a drawing in the converter replaces
that program, sometimes in a different frame, so the labels of every
placed copy stayed at the old frame's point and drifted off the parts.
Keep the cached point only while the drawing program (and its rotation)
is the one it came from.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy and Cut paste through ActionClone, which added each clone to the plate
but never recorded the groups the sources were in, so a pasted common-line
pair came out as separate parts held to the part spacing. ActionClone now
reads the copied parts' groups when it starts (before Cut removes the
sources and their groups) and joins each paste's clones the same way, at the
source group's kerf.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moving one member of a common-line group used to break the group, so a drag
or nudge silently undid a join. Selecting a member, by click or window, now
selects its whole group, so drag, nudge, push, rotate and align carry the
joined parts together and keep their shared spans.
Right-clicking a part now offers Join Common Line and Remove Common Line,
running the Plate > Arrange commands on the selection. A right-click on a part
keeps its selection (or selects it with its group) instead of clearing it, so
the menu has something to act on; a right-click on empty plate still clears.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the filter on and every drawing nested, the Drawings tab was a blank
list with no hint why. It now shows a note that turns the filter off when
clicked. The filter is never turned off on its own: it is the user's
choice and would stay off when new drawings arrive.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nobody tabs every part, but tabbing by size is useful even on a plate
that has a support grid. Cutting Settings > Tabs now offers "Only tab
parts the support grid can't hold level" or "Tab parts by size"
(CuttingParameters.TabBySize), which ignores the bed and tabs each part
whose minimum-area bounding rectangle's narrow side is in the range.
The support grid choice still falls back to that range on plates with
no bed, as before.
The range fields become TabSizeMinWidth/TabSizeMaxWidth; their JSON
keys stay noBedTabMinWidth/noBedTabMaxWidth so saved settings and nests
read unchanged. TabsEnabled stays as the per-contour flag Plan Cutting,
Place Lead-in and drawing pins set on the parts they tab.
Saved user settings with "Tab every part" read as tabs by size from 0
to 9999, which tabs the same parts. Only the user's settings migrate;
a plate's recorded parameters and pins replay as planned.
Plan Cutting, Place Lead-in and the pre-post review all go through
SupportTabSettings, so they agree on which parts need a tab. A
size-tabbed part is held by any clear tab, so it is never a rapid
obstacle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Set Offset Increment gains a "Calculated distance" option. With it on, the
arrow keys move the selection by its own size plus the part spacing,
measured on its geometry like a fill's copy distance, so it lands tight
without a push back. The move stops early at an edge, clamp or part, and a
clone preview steps clear of the copy just placed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Long fills read as thousands of milliseconds. Keep milliseconds under
a second, then show seconds and minutes so the time stays readable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
F1 opening help kept taking over from placing a part. Help stays on
the Help menu and F1 belongs to the Clone tool alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clone's Delete only removed its source parts, so parts picked with
Select All stayed on the plate until Escape ended the action.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows reposts a mouse move when a dialog opens or closes, so Set
Offset Increment threw away arrow-key nudges by snapping the previews
back to the cursor. Only a real cursor move now moves them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Desktop test classes each kept identical PumpUntil, Show, Mouse, All,
PressKey, Raise, SetBackingField and Field helpers. They now import
FormTesting and TestReflection; the two Field variants that read a base
type's field or unwrap DrawingLibraryForm keep a one-line wrapper.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ten desktop test classes drew the same squares and the same 4 x 2
rectangle in private helpers, in two equivalent styles. They now use
TestPrograms.Square, ClockwiseSquare and Rectangle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The drawing library, drawing sets, saved nests, add-release and edit-set
grids each repeated the left-click header check that sorts on the
server. BrowsePager.SortByHeaderAsync now does it for the grid and
session it already drives. No behavior change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MachineConfigForm and SavedNestsForm built their tab pages, and
CuttingPanel and LeadsEditor their label / input / hint grids, with
identical private helpers. Both now use ControlFactory. No behavior
change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HorizontalLine and VerticalLine had identical constructors, Dispose and
resize handling. They now derive from SeparatorLine and only say which
way the line runs. No behavior change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repo mixed variants such as center/centre and color/colour, so a
name could be spelled either way and searches missed half the hits.
Standardize on the US spelling, matching .NET's own APIs (Color, Center).
Wire values owned by other systems keep their spelling: the material
ledger's "Cancelled" hold status and GitHub's "cancelled" job status.
No behavior change beyond the spelling of a few status messages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Help menu's F1 shortcut took the key before the plate view, so F1
in Clone/Add Part opened help rather than setting the part in place as
it always has. Actions can now claim F1; Clone does, and MainForm lets
the key through to the plate view while it is active.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plan Cutting saved its settings only on a successful Apply, so a plate
that would not plan lost them. Each open then laid the machine's leads
back over the last parameters, and the cutting panel rebuilt parameters
from scratch, dropping kerf and the machine/material/thickness stamp.
Save the settings when the dialog is accepted, keep the panel's
unexposed fields, and only apply the machine's leads when the last
parameters were not already taken from that machine, material, grade
and thickness.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PlateFillService throws for a plate with a sheet outline, but the desktop
swallowed it: Fill (Ctrl+F) caught every exception and showed nothing, and
Fill Area's async void either completed silently or let it escape.
PlateFillService.Refusal(plate) names the reason, and every caller checks
it first: Fill and Fill Area put it in the status bar and add nothing,
Pattern Tile offers a new plate only, the MCP fill/pack tools return it as
an Error result, and the console exits 2 with it unless --autonest is given.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The plate view fills the outline, hatches obstacles and draws the usable
area; Edit Plate imports an outline from a CAD file or clears it, with
the size read-only while the sheet has one.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Browsing nests in Database mode crashed with ObjectDisposedException on
DataGridView: selecting another nest drops the embedded version history,
and WinForms leaves its grid's keyboard-tooltip auto-pop timer running.
When the timer fired it hid the tooltip through the disposed grid.
GridStyle now hides that tooltip when a styled grid's window is destroyed,
which stops the timer for every grid in the app.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8dded7f1 draws cut-off ids white on a disc of the cut-off line's orange,
so the old assertion that no orange touches the id failed on the Windows
CI job. The test now checks what the disc is for: the disc is there, and
the id's white strokes survive on the cut's own pixels. Drawing the lines
after the labels fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plate-colored disc behind a cut-off id read as a notch in any part edge
the cut runs along. An orange-red disc with a white id reads as a tag on the
cut-off line instead, and still keeps the dashed line from striking it through.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drawing.Bends stay in the DXF's source frame while CadImporter moves the
program so its first pierce sits at the origin (Source.Offset). The plate
renderer added part.Location to raw bend points, so every bend and etch
mark was shifted by its drawing's pierce offset, visible on the drawing
library set preview and on plates alike. Remove Source.Offset before
rotating and placing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Shape Library, drawing library and drawing set preview each drew
parts their own way (hardcoded green fill, steel-blue fallback, black
outlines with gray etch). They now share a library style on ColorScheme
(background, fill, outline, etch and bend colors) that ignores drawing
colors, follows the active scheme (Dark gets a dark variant) and
round-trips through saved schemes, defaulting when absent. Nest part
colors are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Zoomed out, small parts and short cut-off segments piled their ids on each
other. As the CAD converter numbers entities, an id now shows only once its
part is big enough on screen to hold it: a part must be as wide and tall as
the id's text, a cut-off segment as long as the id's disc.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Typing customer, material, grade and thickness by hand let near-duplicate
spellings into the library, which then split drawings that should match.
The fields are now drop-downs of the values the library and the machine
material catalog already use, while still accepting new values; thicknesses
already used for the material are listed ahead of the standard gauges.
A library color could be set but never cleared back to the color scheme's,
so Automatic and Reset are added. The rotation start/end/step boxes gave no
sense of the range, so a dial shades it, ticks the angles the engines try
(via RotationPolicy) and lets either end be dragged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cut-off lines are painted after the parts, so the dashed line ran straight
through each segment's id, which sits on the cut. Cut-off segment ids are now
held back from the parts pass and drawn after the lines, over a disc of the
plate's fill color.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Grids opened at their designer widths and jumped a moment later, because
GridStyle waited for the first paint with rows before measuring them.
Columns now measure their header and first 50 rows directly: at handle
creation when the rows are already there, otherwise in a call posted when
rows arrive, which runs after the filling code and before the repaint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every segment of a cut-off is its own part of the one cut-off drawing, but
its sequence label was placed from the drawing's whole program, so all of a
cut-off's segments stacked their numbers on one point. The view culls parts
outside the visible area, so zooming changed which segment drew last and the
shown number appeared to change. Each segment is now labelled at the middle
of its own cutting moves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When every drawing in a set starts with the same words, as in
"4980 A111 PT01", the set preview's labels were all cut short to the
same "4980 A111 P…". The preview now drops the leading words all names
share, cutting only at a space, '-', '_' or '.' and never emptying a
name, and notes the dropped prefix above the drawings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The set preview guessed row widths and settled the scale in four rounds,
which could stick at rows of minimum-width label cells and leave much of
a narrow pane empty. At a given scale, filling each tallest-first row as
far as the pane allows is the best row split, and the packed height only
grows with scale, so the layout now bisects for the largest scale that
fits. A 21-drawing set in a 400x590 pane goes from scale 1.14 with 345 px
used to 2.23 filling the height.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CL-707 config now declares sections, sentence-case labels and ranges,
so its dialog matches the CI Fiber one instead of the generic PropertyGrid.
The sectioned editor gains what the CL-707 config needs: optional (nullable)
numbers behind an enable box, editable tables for lists of simple records,
and a text field that suggests values from a table column (Selected library).
"Lead-in arc line 2 feedrate" is relabeled "Lead-in arc feedrate", which is
what #127 drives.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each zoom step rebuilt every part's display paths from its CNC program,
and each drag step rebuilt the moved parts, which dominates for parts
with hundreds of holes. LayoutPart now keeps its paths in the drawing's
program frame and only maps them to the view on a zoom or move,
rebuilding when IsDirty is set or the program, rotation or manual
lead-ins change. Also caches the label StringFormat.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A one-pixel fill (about 2% on the Nesting Progress bar) asked GDI+ for a
zero-size corner arc, which threw "Parameter is not valid" mid-nest. Clamp
the corner radius to the rectangle and fall back to a plain rectangle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unit suffixes are painted in a reserved right margin instead of being part
of the edit text, so editing the number no longer fails to parse. Length
boxes also convert values typed in other units (mm, cm, m, in, ft,
fractions such as 3/8").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The set preview moves from its own window into a details pane beside
the list, as the Drawing Library has, with the set's notes below it.
It reads the highlighted set shortly after the selection settles and
caches drawings per revision. Parts are drawn as outlines without fill,
and the info lines sit above the fitted drawings instead of over them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preview on the Sets tab (button and right-click menu) downloads each
member's current revision and packs them into one view, labeled with
name and quantity, so part sizes compare at a glance. PlateView gains
DrawPartNumbers (default on) so the preview can hide sequence numbers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Grid columns no longer stretch to fill the control. GridStyle sizes each
column once to its header and the first rows shown (capped at 400 px),
then the widths are the user's to resize.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ColorScheme.Default and LayoutPart kept single static pens, brushes and a
font that every plate view and drawing preview painted with. GDI+ objects
are not thread-safe, so two views painting at once on different UI threads
(parallel WinForms test collections) failed in PlateRenderer.DrawPlate with
"Object is currently in use elsewhere" and crashed the test host.
The scheme now builds its pens and brushes per thread and rebuilds them
after a color change; LayoutPart's selection, lead-in and label objects are
thread-static. A regression test paints previews on four threads at once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Starting the tool while it was open built the new action before the old
one was disconnected, and the old one's teardown cleared the new muting.
The outgoing action now leaves the view alone once a successor owns it,
and opening the tool repaints the plate right away.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Delete during placement went to the plate view's delete-selected path, which
treated the unplaced previews as selected parts and deselected them, so they
drew solid like placed parts. Route Delete to the clone action instead (its
own handler, which removes the originals when cloning placed parts, never ran)
and re-flag the previews as selected whenever they are reselected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clamps could only sit on the origin-side edge and be edited as a list in
Nest > Clamps. Setting them up against a real sheet is easier by dragging
them where they are, so Plate > Edit Clamps adds an edit mode: drag a clamp
along its edge or onto another edge, click near an edge to add one, click a
clamp's locating dimension to type its distance from the origin, Delete to
remove. Dimensions measure to the clamp center or its near edge
(remembered per user). Edits replace the nest's rail so every sheet follows,
like the dialog.
Rail clamps now carry a ClampEdge (origin side, far side, origin end, far
end), positioned from the origin along that edge. Origin-side clamps keep
their ids and files; other edges persist in optional per-edge arrays in
.nest files and clamps.json, omitted when empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Changing a rate, the pierce time or the machine rebuilt the timeline and
kept the playhead's old time. That time pointed at a different move on
the retimed timeline, so the torch jumped around while settings were
adjusted. When the new timeline has the same moves, Load now finds the
same move and how far through it the torch was (CutSimulation.TimeAt
inverts FractionAt, acceleration included).
The in-progress rapid was drawn whole with a dashed pen. GDI+ cost grows
with dash count: zoomed in, one paint of a long rapid can take seconds
to minutes. It is now clipped to the visible area, as finished rapids
already were.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NestProgress gains PreviewSheet, a detached plate for the stock the preview
parts lie on; Irregular builds one per stock. PlateView draws it (size, edge
spacing, clamps) in place of the plate while the preview is shown and drops
it whenever the preview is cleared or the plate changes. Auto Nest zooms out
when a trial sheet falls outside what it has already shown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The overlay re-stroked the whole finished trail on every paint: about
275 ms at zoom-to-fit on a 392-part plate and over 11 s zoomed in, where
dashed rapids spanned millions of on-screen dashes.
The finished trail is now cached in a bitmap at the current scale, so a
pan or playback frame blits it and draws only the moves since. A wheel
zoom stretches the cached image until the wheel has been still for
150 ms, then redraws it sharp. When the trail would be too large an
image, each paint draws only the moves on screen and clips straight
rapids to the view. Arcs are added as GDI+ arcs instead of 5-degree
polylines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>