Panels poliert: Ebenenkombi in Oberleiste, Satelliten-Dialoge, Caps weg, Perf

- Ebenenkombination raus aus Ebenen-Panel, in Oberleiste-Topbar +
  Editor-Satellite (AusschnittLayerDialog embedded). doc.Strings
  haelt active_comb_name, auto-clear bei manueller Eye/Lock-Aenderung.
- EbenenSettingsDialog jetzt Satellite mit Ebene-Picker-Dropdown
  (auto-save on switch via SAVE_KEEP).
- Per-Ausschnitt Einstellungen-Satellite (Massstab, Display, Overrides,
  Ebenenkombi). Alte 'Sichtbarkeit bearbeiten'-Option entfernt.
- Layouts/Ausschnitte: Top-Header weg, Sticky-Footer mit Anzahl +
  Aktionen. LayoutDialog ist jetzt Satellite mit Format-Live-Preview.
- Panel-Captions + Default-Ebenen-Namen auf Mixed-Case (Ausschnitte,
  Ebenen, Waende ...). Nur DOSSIER bleibt caps.
- DimensionenApp: Card-Optik raus, REF-Wuerfel mit Kreisen statt
  Quadraten + Hover-Scale.
- GeschossManager angeglichen an EbenenManager: Rechtsklick-Menue,
  Lock-Button, Delete-X, Duplizieren. layer_builder honoriert z.locked.
- Active Sublayer folgt jetzt dem Geschoss-Wechsel (gleicher Code
  unter neuem Parent).

Performance Geschoss-Wechsel:
- elemente._send_state() ersetzt durch _notify_active_geschoss()
  (Partial-Push statt 200+ Elements re-enumerieren).
- _apply_visibility dedupe via sticky last-applied-signature
  (STATE_SYNC-Echo loopt nicht mehr durch alle Layer).
- _update_clipping nur wenn alt oder neu hasClipping=True.
- Redundante doc.Views.Redraw() im CPlane-Pfad entfernt — die folgende
  apply_visibility-Roundtrip redrawt 30ms spaeter ohnehin.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 03:58:28 +02:00
parent e3918cb155
commit 95031ee2c0
29 changed files with 1708 additions and 713 deletions
-59
View File
@@ -255,9 +255,6 @@ function SortHeader({ label, sortKey, sortBy, sortDir, onSort, style }) {
export default function EbenenManager({
ebenen, activeCode, onActiveChange, onChange, mode, onModeChange, hatchPatterns,
combinations = [], activeCombName = null,
onPickCombination, onSaveCurrentCombination, onDeleteCombination,
onEditCombinations, onUserVisibilityChange,
}) {
const [sortBy, setSortBy] = useState('code')
const [sortDir, setSortDir] = useState('asc')
@@ -306,12 +303,10 @@ export default function EbenenManager({
const handleToggleVisible = (code) => {
const cur = ebenen.find(e => e.code === code)
if (cur) updateByCode(code, { visible: !(cur.visible !== false) })
if (onUserVisibilityChange) onUserVisibilityChange()
}
const handleToggleLock = (code) => {
const cur = ebenen.find(e => e.code === code)
if (cur) updateByCode(code, { locked: !cur.locked })
if (onUserVisibilityChange) onUserVisibilityChange()
}
const handleColorChange = (code, color) => {
updateByCode(code, { color })
@@ -426,58 +421,6 @@ export default function EbenenManager({
return (
<>
{/* Ebenenkombinationen — Label + Dropdown + Save-As-Plus */}
<div style={{
display: 'flex', flexDirection: 'column', gap: 4,
padding: '6px 14px',
background: 'var(--bg-section)',
borderBottom: '1px solid var(--border-light)',
}}>
<span className="label-xs">Ebenenkombination</span>
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<select
value={activeCombName || '__custom__'}
onChange={(ev) => {
const v = ev.target.value
if (v === '__custom__') return
if (v === '__delete__') {
if (activeCombName && onDeleteCombination) onDeleteCombination(activeCombName)
return
}
if (onPickCombination) onPickCombination(v)
}}
style={{ flex: 1, minWidth: 0 }}
title={activeCombName ? `Aktiv: ${activeCombName}` : 'Eigene Sichtbarkeit (keine Kombination)'}
>
<option value="__custom__">{activeCombName ? activeCombName : 'Eigene'}</option>
{combinations.length > 0 && <option disabled></option>}
{combinations.map(p => (
<option key={p.name} value={p.name}>{p.name}</option>
))}
{activeCombName && combinations.some(p => p.name === activeCombName) && (
<>
<option disabled></option>
<option value="__delete__">🗑 Aktuelle löschen</option>
</>
)}
</select>
<button
className="btn-icon-sm"
onClick={() => onSaveCurrentCombination && onSaveCurrentCombination()}
title="Aktuelle Sichtbarkeit als neue Kombination speichern"
>
<Icon name="add" size={14} />
</button>
<button
className="btn-icon-sm"
onClick={() => onEditCombinations && onEditCombinations()}
title="Alle Kombinationen bearbeiten (Dialog)"
>
<Icon name="edit" size={13} />
</button>
</div>
</div>
<div style={{
display: 'flex', flexDirection: 'column', gap: 4,
padding: '6px 14px',
@@ -512,7 +455,6 @@ export default function EbenenManager({
const anyVisible = ebenen.some(e => e.visible !== false)
// Wenn irgendeine sichtbar -> alle aus. Wenn keine sichtbar -> alle an.
onChange(ebenen.map(e => ({ ...e, visible: !anyVisible })))
if (onUserVisibilityChange) onUserVisibilityChange()
}}
title={ebenen.every(e => e.visible !== false)
? 'Alle Ebenen ausblenden'
@@ -534,7 +476,6 @@ export default function EbenenManager({
onClick={() => {
const anyLocked = ebenen.some(e => e.locked === true)
onChange(ebenen.map(e => ({ ...e, locked: !anyLocked })))
if (onUserVisibilityChange) onUserVisibilityChange()
}}
title={ebenen.every(e => e.locked === true)
? 'Alle Ebenen entsperren'