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
+46 -15
View File
@@ -27,7 +27,10 @@ function SectionLabel({ children }) {
)
}
export default function EbenenSettingsDialog({ ebene, hatchPatterns = ['Solid'], onSave, onClose, embedded = false }) {
export default function EbenenSettingsDialog({
ebene, hatchPatterns = ['Solid'], onSave, onClose, embedded = false,
pickerEbenen = null, pickerSelected = null, onPickEbene = null,
}) {
const [draft, setDraft] = useState({
...ebene,
fill: {
@@ -107,21 +110,49 @@ export default function EbenenSettingsDialog({ ebene, hatchPatterns = ['Solid'],
return (
<div style={wrapperStyle}>
<div style={innerStyle}>
{/* Header */}
<div style={{
display: 'flex', alignItems: 'center', gap: 6,
padding: '10px 12px',
borderBottom: '1px solid var(--border)',
}}>
<Icon name="settings" size={14} style={{ color: 'var(--text-secondary)', flexShrink: 0 }} />
<span style={{
flex: 1, fontWeight: 600, fontSize: 11,
overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
{/* Header — embedded zeigt nur das Ebenen-Picker-Dropdown (kein
Title + kein Close, dafuer hat das Fenster seine native Title-
Bar). Modal-Variante zeigt den klassischen Header. */}
{embedded && pickerEbenen ? (
<div style={{
display: 'flex', alignItems: 'center', gap: 6,
padding: '8px 12px',
borderBottom: '1px solid var(--border)',
}}>
{ebene.code} {ebene.name}
</span>
<button onClick={onClose} style={{ color: 'var(--text-muted)', fontSize: 16, padding: '0 4px', lineHeight: 1 }}>×</button>
</div>
<span style={{ fontSize: 9, color: 'var(--text-muted)',
textTransform: 'uppercase', letterSpacing: 0.5 }}>
Ebene
</span>
<select
value={pickerSelected || draft.code}
onChange={(ev) => onPickEbene && onPickEbene(ev.target.value, draft)}
style={{ flex: 1, fontSize: 11, minWidth: 0,
fontFamily: 'var(--font-mono)' }}
title="Zwischen Ebenen wechseln — aktuelle Änderungen werden mit übernommen"
>
{pickerEbenen.map(e => (
<option key={e.code} value={e.code}>
{e.code} {e.name}
</option>
))}
</select>
</div>
) : !embedded && (
<div style={{
display: 'flex', alignItems: 'center', gap: 6,
padding: '10px 12px',
borderBottom: '1px solid var(--border)',
}}>
<Icon name="settings" size={14} style={{ color: 'var(--text-secondary)', flexShrink: 0 }} />
<span style={{
flex: 1, fontWeight: 600, fontSize: 11,
overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
}}>
{ebene.code} {ebene.name}
</span>
<button onClick={onClose} style={{ color: 'var(--text-muted)', fontSize: 16, padding: '0 4px', lineHeight: 1 }}>×</button>
</div>
)}
{/* Body */}
<div style={{ padding: '6px 12px 4px', overflowY: 'auto' }}>