- Add host_acadrust_source and source-hash comparison helpers to ocs_plugin_api.
- Track acadrust_source and acadrust_declared in ExternalPlugin/ReleaseInfo.
- Apply repo-level policy: if any release in a repo declares acadrust_source, undeclared v4+ releases from that repo are incompatible.
- Preserve API v2/v3 backwards compatibility: legacy undeclared releases stay installable.
- Update Plugin Manager UI to only offer compatible releases and show 'acadrust mismatch' status.
- Drop acadrust_version from gate logic; only acadrust_source is required.
Enable in-place editing of inherited properties in the Properties panel:
- Transparency: Switch to PropValue::EditChoice with ByLayer and ByBlock presets to allow direct typing of any numeric percentage value (0..90%) without combo_box autocomplete interference.
- Select-all-on-click: Integrate EditChoice text inputs into build_field_key_map with dedicated widget IDs, preserving click-to-select-all across editable fields.
- Material: Provide bounded preset choices (ByLayer, ByBlock, Global, and active custom material) to avoid scanning large drawing dictionaries.
- Plot style: Implement mode-aware behavior with interactive Choice in STB mode and ReadOnlyWithTooltip in CTB mode.
- Read-only tooltips: Introduce PropValue::ReadOnlyWithTooltip to provide contextual explanations for locked fields while preserving mouse text selection and clipboard copying.
- Dropdown alignment & unified borders: Fix EditChoice internal input/caret background clipping so the container's 1px neutral/active border surrounds the entire control identically to Lineweight and text inputs.
- Document defaults & aggregation: Synchronize document header defaults when editing with No selection, and aggregate heterogeneous multi-selections (*VARIES*).
Each ribbon panel was rendered five ways every frame so CollapsePanels could
roll back to any density at layout time: full, compact, button, tight and a
full-size flyout that duplicated the full rendering.
The layout pass ran four full measure-layouts per panel even in forced modes,
and the degradation decision was an untested u8 inline in Ribbon::view.
Now the choice is a pure, unit-tested decide_levels() whose levels are a typed
Level enum (Full/Compact/Collapsed/Tight). Panel carries its four renderings
as elements: [Element; 4] indexed by Level, with a slot(i, level) helper for
the tree stride. Forced modes (Full/Compact/Collapsed) measure nothing at all
and derive the row height from the placed panel. The open flyout draws the
panel's own `full` rendering inside a self-drawn box (identical weakest-bg +
1px neutral-border to the container it replaced), so no duplicate
render_group is built per panel per frame. Level, Panel, Widths, CollapsePanels
and decide_levels are pub(crate); CollapseMode stays pub (re-exported).
Tests (collapse.rs tests module, added RED first):
- forced_modes_pin_every_panel
- auto_huge_width_keeps_everything_full
- auto_degrades_from_the_right_one_panel_at_a_time
- auto_stops_degrading_once_the_row_fits
- auto_escalates_a_single_panel_past_collapsed_to_tight
- auto_cascade_drops_every_collapsed_panel_to_tight
- auto_runs_the_compact_phase_across_the_row_first
- no_panels_stays_empty
- single_panel_walks_the_whole_ladder
- zero_widths_never_overflow
- endless_row_degrades_everything_to_tight
- unbounded_row_keeps_everything_full
- nan_budget_degrades_both_phases_but_no_tight_cascade
- exact_fit_at_full_stays_full
- matches_the_pre_refactor_algorithm: byte-equivalence sweep against the
verbatim pre-refactor u8 algorithm (280 width/budget combos incl. the
degenerate 0/0/inf/NaN inputs), proving the decision logic is unchanged.
Measured with the committed #[ignore]d benchmark
(`cargo test --lib --release -- --ignored --nocapture bench_ribbon_view_construction`)
run as one instrument across pre-change / this change: Ribbon::view()
construction ~676 -> ~425 us/frame (~37% of view construction saved); forced
modes run 1 layout call per panel per frame instead of 5.
Verification: cargo build clean; cargo test --lib = 382 passed (367 baseline
+ 15 new ribbon tests) / 2 known pre-existing failures unchanged
(save_then_open_round_trips, tilted_ucs_places_planar_entities_with_the_plane_normal).
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 \\\x01attr\\x01…\ sentinel-prefixed string was used to tell geometry
fields (\&'static str\ names) apart from block attribute rows (runtime
tags) in \ctive_field\ and \dit_buf\. Replace it with a \FieldKey\
enum (\Geom(&'static str)\ / \Attr(String)\), so the two namespaces can't
collide by construction: \dit_buf\ is now \HashMap<FieldKey, String>\,
\ctive_field\ is \Option<FieldKey>\, and the sentinel decoding in
\ctive_key_id\ is replaced by \FieldKey::widget_id\.
While touching the key plumbing, replace \prop_field_key_for_id\'s
per-event scan of every section x prop (with a \String\ format per
candidate) with an O(1) precomputed \HashMap<iced::widget::Id, FieldKey>\
(\ield_key_by_id\), built once in \
efresh_properties\ alongside the
sections — and rebuilt after \make_sections_read_only\ so rows demoted
to read-only stop mapping. \PropSyncActive\ now does a single map lookup
per event.
The Insert tab's Block Palette button now behaves like the View tab toggles
(UCS Icon, View Cube, Ortho, Properties, File Tabs, Layout Tabs): it stays
highlighted while the block palette panel is open and clears when closed.
The Ribbon gains a show_block_palette flag with a set_block_palette setter,
fed into ToggleState and mapped in is_active_tool for the BLOCKPALETTE tool
id. show_block_palette on the app remains the single source of truth; both
mutation paths now mirror it onto the ribbon:
- BLOCKPALETTE / BLOCKSPALETTE command toggles ribbon state alongside the
panel (src/app/commands/blocks.rs).
- Closing the panel via the dock rail close button clears the ribbon state,
matching how Close(Properties) already syncs (src/app/update/dialog.rs).
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.
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.
drop_index previously mapped a pointer position inside a lone full-height panel
to a top/bottom insertion split, offering an impossible drop. Clamp to the
single slot when the edge holds one panel, and cover the multi-slot mapping with
tests.
Sync projection controls from the active camera, preserve the UCS icon in perspective views, and use visible or selected 3D geometry for orbit pivots. Dense mesh vertex grips remain hidden.
Share source buffers across block placements and render nested content with GPU instance transforms.\n\nChunk silhouettes and compact mesh material data so large drawings stay under device buffer limits and remain responsive.