Merge main into Pallet-placement

Resolved conflicts:
- app/update/mod.rs: keep the dock's dock_open_at_default for the XREF
  manager; take main's stable xref row identity (row_index(&id)).
- app/view/mod.rs: keep the edge layout from app::dock; drop main's copy
  of the old edge-stack code (main only reformatted it there).
- ui/window/layers.rs: keep main's new visible_indices next to the
  branch's view_panel.
Files the branch only reformatted take main's version. Adds the Lao
(lo-LA) translations for the new dock texts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
This commit is contained in:
Claude committed 2026-10-11 18:44:00 +00:00
commit 2fca3fd18d
136 files changed
+12408 -949

No files matched your search

+24 -10
View File
@@ -127,11 +127,15 @@ pub struct LayerPanel {
/// All selected rows (Ctrl/Shift extend it). Bulk property changes and
/// deletion act on every row here. Empty ⇔ nothing selected.
pub selected_multi: Vec<usize>,
pub editing: Option<usize>,
/// Layer being renamed (row text-input open). Keyed by NAME so a
/// rebuild/sort between start and commit cannot retarget it (#44);
/// `selected`/`selected_multi` below stay index-based and are re-resolved.
pub editing: Option<String>,
pub edit_buf: String,
pub current_layer: String,
pub linetype_items: Vec<LinetypeItem>,
pub color_picker_row: Option<usize>,
/// Row whose color swatch is open. Name-keyed for the same reason (#44).
pub color_picker_row: Option<String>,
pub color_full_palette: bool,
pub linetype_combo: combo_box::State<LinetypeItem>,
pub lw_combo: combo_box::State<LwItem>,
@@ -320,6 +324,19 @@ impl LayerPanel {
self.linetype_items = items;
}
/// Row indices passing the live name filter — the rows the view actually
/// draws. Index math over "what the user sees" (shift-ranges) must use
/// these; raw `selected_multi` ranges would sweep in hidden rows (#50).
pub fn visible_indices(&self) -> Vec<usize> {
let filter = self.filter.to_lowercase();
self.layers
.iter()
.enumerate()
.filter(|(_, layer)| filter.is_empty() || layer.name.to_lowercase().contains(&filter))
.map(|(i, _)| i)
.collect()
}
/// The Layer Manager as a dock pallet: its title bar, the toolbar across
/// the pallet (search box on the right), then the table, at least as wide
/// as the pallet and scrolling sideways when the pallet is narrower.
@@ -505,18 +522,15 @@ impl LayerPanel {
// ── Layer rows ────────────────────────────────────────────────────
let mut rows_col = column![].spacing(0);
let filter = self.filter.to_lowercase();
for (i, layer) in self.layers.iter().enumerate() {
if !filter.is_empty() && !layer.name.to_lowercase().contains(&filter) {
continue;
}
for i in self.visible_indices() {
let layer = &self.layers[i];
// Highlight every selected row; show the editable combos only on the
// anchor (a single shared combo state can't drive several rows).
let is_anchor = self.selected == Some(i);
let is_sel = is_anchor || self.selected_multi.contains(&i);
let is_current = layer.name == self.current_layer;
let is_editing = self.editing == Some(i);
let color_open = self.color_picker_row == Some(i);
let is_editing = self.editing.as_deref() == Some(layer.name.as_str());
let color_open = self.color_picker_row.as_deref() == Some(layer.name.as_str());
let (ltc, lwc) = if is_anchor {
(Some(&self.linetype_combo), Some(&self.lw_combo))
@@ -962,7 +976,7 @@ fn layer_row<'a>(
// Per-viewport freeze columns
for (vp_idx, _vp_col) in vp_cols.iter().enumerate() {
let is_vp_frozen = layer.vp_frozen.get(vp_idx).copied().unwrap_or(false);
let vp_frz_svg = crate::ui::icons::layer_freeze(is_vp_frozen);
let vp_frz_svg = crate::ui::icons::layer_vp_freeze(is_vp_frozen);
row_content = row_content.push(
container(svg_btn(
vp_frz_svg,