The ribbon kept its own \show_block_palette\ copy that the app had to
manually sync at every mutation point (the BLOCKPALETTE command and the
dock Close handler). Drop the copy and thread the app's authoritative
\show_block_palette\ into \Ribbon::view\ at render time, so the button
highlight can't drift from the panel's true visibility — those two
handlers are now mutate-points only and the ribbon view is the single
place that reads the state back.
The drag preview divided the edge height by the raw panel count on the target
side. Closed panels keep their stack slot, so a hidden panel (e.g. the block
palette tucked away while Properties stays open) split the ghost and the drop
index as if it were rendering — leaving a half-height preview on that edge.
Size slots from the panels actually rendered on the edge instead, via a shared
visibility helper used by both the drop-index math and the ghost/edge-tint
geometry.
The dock drag preview computed slot heights and drop indices from the full
window height, but docked panel columns only span the model viewport, so the
preview overlay and insertion point drifted below the actual dock edge. Use the
current viewport height so the ghost and drop index line up with the panels.
Clicking an editable property value field now selects its entire value instead
of only placing the caret, so typing immediately replaces it. The click is
observed through a global left-press subscription (PropPointerPressed); a focus
sweep reports which widget took focus and PropSyncActive maps it back to the
active property row, then issues a select-all operation only when focus landed
on a different field.
The active row stays highlighted while its text input holds keyboard focus and
clears when focus moves elsewhere.
Style the dock rail tab by its panel state: the expanded (active) panel's tab
gets a primary-colored highlight and border, and a tab whose panel is being
dragged gets a lighter primary tint, so the user can see which panel owns the
edge at a glance.
A paper layout painted its whole canvas in the page colour, so the sheet
had no visible edge — zooming out never reached one, because the surround
was the same colour as the page. Floating viewports then painted
themselves black over it.
Both come from the same idea, that a viewport's canvas is a colour it can
be handed. What lies behind a viewport depends on what the viewport is:
- The full-canvas sheet shows the desk. `paper_bg_color` is the page, and
the page is a bounded rectangle `paper_sheet_fill` already draws; using
it for the canvas too erased the boundary between them. The desk is now
its own colour, defined once in the scene and read by both the widget
and the renderer, so the two cannot drift apart.
- A floating viewport sits on that sheet and must paint no canvas at all.
Handing it a transparent one does not work: the background shader
returns an opaque colour whatever alpha it is given, so alpha zero came
out black. Skipping the pass is the only way to ask for see-through, so
`skip_background` now suppresses both the clear and the pass. It is part
of the frame signature too — without that, a cached frame would keep
showing the canvas the flag was just turned off for.
Shading and fog still blend toward what is behind a floating viewport,
which is the page, so the uniform keeps that colour even though nothing
paints it.
Co-Authored-By: Claude Opus 5 <[email protected]>
The readout learned to write lengths as 5'-6 1/2" and angles as
N 45d0'0" E, but typed input was still a bare parse::<f64>() — a
coordinate could be displayed and not entered. Give the formatters
their inverses.
parse_length takes feet and inches separated by a dash, a space, or
nothing, with the closing quote optional, and whole-plus-fraction in
any of those forms: 5', 60", 5'-9", 5'9-1/2, 9-1/2, 1/2. A leading
minus is a sign; the one inside 5'-9" is a separator, since after feet
there is nothing left to subtract from.
parse_angle reads the mark that says which convention an angle is in —
g for grads, r for radians, d/'/" for degrees-minutes-seconds, compass
letters for a surveyor's bearing — and reads a bare number in whichever
convention the drawing is set to.
ANGBASE and ANGDIR now apply, but only where they mean something. Which
way a thing points is measured from the drawing's zero and runs the way
it says; how wide an arc opens is the same number whatever zero is
counted from. format_direction and parse_direction are the pair for
directions, and the polar readout and polar input both go through them,
so the bearing shown is the bearing accepted. format_angle stays for
sizes, where applying a base angle would corrupt the value.
The command prompts follow the same rule, each classified rather than
swept: OFFSET distance, FILLET radius, CHAMFER distances, ARRAY and
MINSERT spacing, TRACE width, HELIX, and EXTRUDE height read lengths;
the four dimension text-rotation prompts, ARRAY's total angle and
INSERT's rotation read angles. MLINE's scale and INSERT's scale factor
are left alone — a multiplier has no unit to be written in. INSERT read
both through one parse; they are now separate.
The typed variants also take a decimal comma, which a single-value
prompt has no other use for. parse_length itself does not: inside a
coordinate the comma separates the axes.
Co-Authored-By: Claude Opus 5 <[email protected]>
The status-bar units button wrote INSUNITS, which nothing on screen reads.
INSUNITS only tells the drawing how to scale content arriving from
elsewhere, so picking a unit relabelled the drawing and changed nothing
visible — the selector looked broken because the variable it moved was
invisible.
Point the button at LUNITS instead, the setting that decides how every
coordinate and distance is written, and give the three questions the word
"units" runs together a place each:
- The button offers the five length formats, each shown beside a sample of
itself, so Engineering and Architectural are told apart by sight.
- UNITS / DDUNITS opens a real dialog: length and angle format and
precision, the direction angle zero points, whether positive angles run
clockwise, and the insertion unit. Its sample comes from the same
formatters the drawing uses, so it cannot drift from the readout.
- DWGUNITS converts. Model geometry, viewport framing, the header's length
defaults and each dimension style's scale all move together in one undo
step; paper space is left alone, since the sheet is still the same sheet.
Locked layers are converted too — a half-converted drawing would be at
two scales at once.
The coordinate readout formatted at four decimal places whatever the
drawing asked for; it now goes through the same format_length the
properties panel uses. That made the angle formats reachable in turn, so
degrees-minutes-seconds now carries the d/'/" marks that say which
convention it is, and surveyor's units are written at all.
Typed input is still plain decimal: a length the readout writes as
5'-6 1/2" cannot yet be typed back. ANGBASE and ANGDIR are stored but not
yet applied to displayed directions.
Closes#668
Co-Authored-By: Claude Opus 5 <[email protected]>
Registering as the .dwg/.dxf handler was reachable only by typing
FILEASSOC, which is also the only thing that installs the icons the
desktop shows — so a user with no reason to know the command had no way
to arrive at either.
The checkbox makes the same two calls the command does, so the stored
setting and the actual registration cannot drift apart. A registration
the system refuses puts the checkbox back rather than leaving it showing
a state that is not true.
The line under it says the icons come with it, since that is what sends
people looking for this in the first place.
Co-Authored-By: Claude Opus 5 <[email protected]>
Drawings arrive from elsewhere carrying someone else's layer names, and
folding them into a set of house layers meant renaming and merging by
hand, one layer at a time.
LAYTRANS reads a layer set out of another drawing and moves this one onto
it. Given a file it maps every name the two already share and translates
at once, which is all most incoming drawings need. Bare, it opens a
translator: the drawing's layers on one side, the loaded set on the
other, mappings built up between them and applied only on Translate, so a
mapping can be reconsidered and the whole translation is a single undo
step. Mappings can be saved and read back, objects can be forced to
ByLayer so the target layer's properties are what actually shows, and the
result can be written out as a log.
The move itself is the one LAYMRG already made for a single pair, so
LAYMRG now goes through it too rather than keeping its own copy.
Three things fell out for free or nearly so. A standards file is a
drawing, so .dws and .dwt need nothing but a place in the file filter.
The entity list is flat and holds block definitions, so objects inside
blocks travel with everything else instead of being stranded on a layer
that no longer exists. And a target layer that this drawing already has
is left alone: the drawing has an opinion about it, and restyling it
would reach past what was asked for -- only newly created targets take
the standard's properties.
Mappings are saved beside the drawing rather than inside a DWS. That is
where AutoCAD keeps them, but putting them there would mean inventing a
place in the drawing that nothing else reads back.
Closes#624
Co-Authored-By: Claude Opus 5 <[email protected]>
The ribbon offered four styles and dispatched each one's id as a command.
Two of those ids were not visual-style commands: "Shaded" carried SOLID,
which draws a 2D filled polygon, so choosing it started a draw command;
"Hidden" carried HIDDEN, which matched nothing at all, so it did nothing.
The intent had been for the button to fire its tool's event, but the
dropdown never reads one -- it dispatches the id.
Behind that sat two generations of the same feature. The render-mode
picker offered the seven styles a viewport can actually be drawn in;
everything else -- the ribbon, VSCURRENT, SHADEMODE, VISUALSTYLES and a
handful of bare verbs -- went through a binary wireframe-or-shaded flag
that could only approximate them, reporting "Hidden (shown shaded)" and
"X-Ray (shown as wireframe)" when asked for something it had no way to
draw. Four descriptions of one choice, each drifting on its own.
There is one list now. Each style names itself once -- mode, label, icon,
and the command that applies it -- and the ribbon, the picker, the
VISUALSTYLES verb and the interactive prompt all read from it, down to
the line that lists the choices, so what is offered cannot disagree with
what works. Keywords are the render modes' own names, since there is one
set of styles left to name.
The binary path is gone rather than kept alongside: its message, its
module event, the tool definitions that produced it, the ribbon's
special-cased highlight arms, the bare style verbs and the older keyword
spellings. X-Ray goes with it -- no render mode draws one, and it was
already coming out as a plain wireframe. Three files that had been left
holding a single icon constant each fold into the list.
Note: ModuleEvent::SetWireframe leaves the plugin API with it.
Closes#621
Co-Authored-By: Claude Opus 5 <[email protected]>
Add a searchable block palette with previews, file import, collision-safe nested definitions, and dependency/table-record import. Keep palette thumbnails current across drawing switches and block-definition edits.
- preserve command history colors after reopening
- remove collapsed command bar residue and split the unsaved prompt
- read system text when the drawing clipboard is empty
Refs #467
Refs #468
Refs #470
- Keep the floating panel near the selection and inside the viewport
- Persist the toggle and hide the panel without a selection
- Show only Material in 3D Visualization