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:
@@ -1,23 +1,29 @@
|
||||
import { useState } from 'react'
|
||||
import Icon from './Icon'
|
||||
import ContextMenu from './ContextMenu'
|
||||
import { openGeschossSettings, openGeschossDialog } from '../lib/rhinoBridge'
|
||||
|
||||
function GeschossBadge({ name }) {
|
||||
return <span className="chip chip-info">{name}</span>
|
||||
}
|
||||
|
||||
function ZeichnungsebeneRow({ z, active, mode, onClick, onToggleVisible, onSettings }) {
|
||||
// Eye-State auch fuer die aktive Zeichnungsebene anzeigen (User-Intention)
|
||||
function ZeichnungsebeneRow({
|
||||
z, active, mode, onClick, onContextMenu,
|
||||
onToggleVisible, onToggleLock, onDelete,
|
||||
}) {
|
||||
const eyeShown = mode !== 'active'
|
||||
const isGeschoss = !!z.isGeschoss
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
onContextMenu={onContextMenu}
|
||||
style={{
|
||||
display: 'flex', alignItems: 'center', gap: 8,
|
||||
display: 'flex', alignItems: 'center', gap: 6,
|
||||
padding: '4px 12px',
|
||||
margin: active ? '1px 6px' : '0',
|
||||
background: active ? 'var(--active-dim)' : 'var(--bg-item)',
|
||||
// Pill-Form fuer die aktive Zeichnungsebene
|
||||
background: active ? 'var(--active-dim)'
|
||||
: (z.visible !== false) ? 'var(--bg-item)'
|
||||
: 'var(--bg-panel)',
|
||||
borderRadius: active ? 999 : 0,
|
||||
borderLeft: active ? 'none' : '3px solid transparent',
|
||||
borderBottom: active ? 'none' : '1px solid var(--border-light)',
|
||||
@@ -31,7 +37,7 @@ function ZeichnungsebeneRow({ z, active, mode, onClick, onToggleVisible, onSetti
|
||||
fontWeight: active ? 700 : 500,
|
||||
fontSize: 12,
|
||||
color: active ? 'var(--active-light)' : 'var(--text-label)',
|
||||
flex: 1,
|
||||
flex: 1, minWidth: 0,
|
||||
overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
|
||||
}}>{z.name}</span>
|
||||
|
||||
@@ -65,9 +71,16 @@ function ZeichnungsebeneRow({ z, active, mode, onClick, onToggleVisible, onSetti
|
||||
|
||||
<button
|
||||
className="btn-icon-xs"
|
||||
onClick={(ev) => { ev.stopPropagation(); onSettings() }}
|
||||
title="Einstellungen"
|
||||
><Icon name="settings" size={12} /></button>
|
||||
onClick={(ev) => { ev.stopPropagation(); onToggleLock() }}
|
||||
title={z.locked ? 'Entsperren' : 'Sperren'}
|
||||
style={{ color: z.locked ? 'var(--warn)' : undefined }}
|
||||
><Icon name={z.locked ? 'lock' : 'lock_open'} size={12} /></button>
|
||||
|
||||
<button
|
||||
className="btn-icon-xs"
|
||||
onClick={(ev) => { ev.stopPropagation(); onDelete() }}
|
||||
title="Löschen"
|
||||
><Icon name="close" size={12} /></button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -83,8 +96,7 @@ export default function GeschossManager({
|
||||
zeichnungsebenen, activeId, onActiveChange, onChange, recalcOkff,
|
||||
mode, onModeChange,
|
||||
}) {
|
||||
// dialogOpen-State entfaellt — Bearbeiten-Dialog laeuft jetzt als
|
||||
// Satelliten-Fenster via openGeschossDialog().
|
||||
const [ctxMenu, setCtxMenu] = useState(null) // { x, y, id }
|
||||
|
||||
const sorted = [...zeichnungsebenen].reverse()
|
||||
const gesamthoehe = zeichnungsebenen
|
||||
@@ -93,9 +105,8 @@ export default function GeschossManager({
|
||||
|
||||
const addQuick = () => {
|
||||
// Standard: NICHT-Geschoss-Zeichnungsebene (z.B. Möblierung, Bemassung,
|
||||
// Plangrafik etc.). User kann via Row-Settings-Cog auf Geschoss
|
||||
// umschalten, oder via Bearbeiten-Dialog (Pencil) ein Geschoss
|
||||
// direkt erstellen.
|
||||
// Plangrafik etc.). User kann via Row-Kontextmenue auf Geschoss
|
||||
// umschalten oder via Bearbeiten-Dialog (Pencil) ein Geschoss erstellen.
|
||||
const nonGeschossCount = zeichnungsebenen.filter(z => !z.isGeschoss).length
|
||||
const newZ = {
|
||||
id: `z_${Date.now()}`,
|
||||
@@ -103,7 +114,6 @@ export default function GeschossManager({
|
||||
isGeschoss: false,
|
||||
visible: true,
|
||||
}
|
||||
console.log('[ZEICHNUNGSEBENEN-UI] addQuick →', { newZ, countBefore: zeichnungsebenen.length })
|
||||
onChange([...zeichnungsebenen, newZ])
|
||||
}
|
||||
|
||||
@@ -111,6 +121,56 @@ export default function GeschossManager({
|
||||
onChange(zeichnungsebenen.map(z => z.id === id ? { ...z, visible: !(z.visible !== false) } : z))
|
||||
}
|
||||
|
||||
const toggleLock = (id) => {
|
||||
onChange(zeichnungsebenen.map(z => z.id === id ? { ...z, locked: !z.locked } : z))
|
||||
}
|
||||
|
||||
const duplicate = (id) => {
|
||||
const src = zeichnungsebenen.find(z => z.id === id)
|
||||
if (!src) return
|
||||
const clone = {
|
||||
...src,
|
||||
id: `z_${Date.now()}`,
|
||||
name: `${src.name} Kopie`,
|
||||
}
|
||||
// Direkt nach dem Original einfuegen
|
||||
const idx = zeichnungsebenen.findIndex(z => z.id === id)
|
||||
const next = [...zeichnungsebenen]
|
||||
next.splice(idx + 1, 0, clone)
|
||||
onChange(next)
|
||||
}
|
||||
|
||||
const remove = (id) => {
|
||||
if (zeichnungsebenen.length <= 1) return
|
||||
const target = zeichnungsebenen.find(z => z.id === id)
|
||||
if (!target) return
|
||||
if (!window.confirm(`"${target.name}" wirklich löschen?`)) return
|
||||
onChange(zeichnungsebenen.filter(z => z.id !== id))
|
||||
if (activeId === id) {
|
||||
const next = zeichnungsebenen.find(z => z.id !== id)
|
||||
if (next) onActiveChange(next.id)
|
||||
}
|
||||
}
|
||||
|
||||
const openContextMenu = (ev, id) => {
|
||||
ev.preventDefault(); ev.stopPropagation()
|
||||
setCtxMenu({ x: ev.clientX, y: ev.clientY, id })
|
||||
}
|
||||
|
||||
const ctxItems = (id) => {
|
||||
const z = zeichnungsebenen.find(x => x.id === id)
|
||||
if (!z) return []
|
||||
return [
|
||||
{ label: 'Einstellungen…', icon: 'settings', onClick: () => openGeschossSettings(z) },
|
||||
{ divider: true },
|
||||
{ label: 'Duplizieren', icon: 'content_copy', onClick: () => duplicate(id) },
|
||||
{ divider: true },
|
||||
{ label: 'Löschen', icon: 'delete', danger: true,
|
||||
disabled: zeichnungsebenen.length <= 1,
|
||||
onClick: () => remove(id) },
|
||||
]
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{
|
||||
@@ -159,12 +219,21 @@ export default function GeschossManager({
|
||||
active={z.id === activeId}
|
||||
mode={mode}
|
||||
onClick={() => onActiveChange(z.id)}
|
||||
onContextMenu={(ev) => openContextMenu(ev, z.id)}
|
||||
onToggleVisible={() => toggleVisible(z.id)}
|
||||
onSettings={() => openGeschossSettings(z)}
|
||||
onToggleLock={() => toggleLock(z.id)}
|
||||
onDelete={() => remove(z.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{ctxMenu && (
|
||||
<ContextMenu
|
||||
x={ctxMenu.x} y={ctxMenu.y}
|
||||
items={ctxItems(ctxMenu.id)}
|
||||
onClose={() => setCtxMenu(null)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user