import { useState } from 'react' import Icon from './Icon' import ContextMenu from './ContextMenu' import { BarCombo, BarButton } from './BarControls' import { openGeschossSettings, openGeschossDialog } from '../lib/rhinoBridge' function GeschossBadge({ name }) { return {name} } function ZeichnungsebeneRow({ z, active, mode, onClick, onContextMenu, onToggleVisible, onToggleLock, onToggleClipping, onDelete, }) { const isGeschoss = !!z.isGeschoss // Eye-Logik: die aktive Z ist IMMER sichtbar (Backend forciert das), also // zeigen wir ihr Auge immer als "an" — ohne Ruecksicht aufs visible-Flag. // Nicht-aktive: in 'all_force' ist visible-Flag ueberschrieben (alle an), // in 'active' ueberschrieben (alle aus) — Auge dimmt. Sonst (Ausgewaehlte/ // grey) reflektiert es das Flag direkt. let eyeIcon, eyeOn, eyeOpacity, eyeTitle if (active) { eyeIcon = 'visibility' eyeOn = true eyeOpacity = 1 eyeTitle = z.visible !== false ? 'Sichtbar (aktive Zeichnungsebene)' : 'Normalerweise ausgeblendet — wird gezeigt weil aktiv' } else if (mode === 'all_force') { eyeIcon = 'visibility' eyeOn = true eyeOpacity = 0.35 eyeTitle = 'Im „Alle anzeigen"-Mode immer sichtbar — Klick wechselt in „Ausgewählte"' } else if (mode === 'active') { eyeIcon = z.visible !== false ? 'visibility' : 'visibility_off' eyeOn = false eyeOpacity = 0.35 eyeTitle = 'Im „Nur aktive"-Mode ausgeblendet — Klick wechselt in „Ausgewählte"' } else { eyeIcon = z.visible !== false ? 'visibility' : 'visibility_off' eyeOn = z.visible !== false eyeOpacity = 1 eyeTitle = z.visible !== false ? 'Ausblenden' : 'Einblenden' } return (
{z.name} {isGeschoss && ( +{(z.okff ?? 0).toFixed(2)} )} {isGeschoss && } {isGeschoss ? ( ) : ( )}
) } const MODES = [ { value: 'all_force', label: 'Alle anzeigen' }, { value: 'all', label: 'Ausgewählte' }, { value: 'active', label: 'Nur aktive' }, { value: 'grey', label: 'Andere grau' }, { value: 'grey_locked', label: 'Andere grau & gesperrt' }, ] export default function GeschossManager({ zeichnungsebenen, activeId, onActiveChange, onChange, recalcOkff, mode, onModeChange, }) { const [ctxMenu, setCtxMenu] = useState(null) // { x, y, id } const sorted = [...zeichnungsebenen].reverse() const addQuick = () => { // Standard: NICHT-Geschoss-Zeichnungsebene (z.B. Möblierung, Bemassung, // 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()}`, name: `Zeichnung ${nonGeschossCount + 1}`, isGeschoss: false, visible: true, } onChange([...zeichnungsebenen, newZ]) } const toggleVisible = (id) => { onChange(zeichnungsebenen.map(z => z.id === id ? { ...z, visible: !(z.visible !== false) } : z)) // In "active" / "all_force" greift visible-Flag nicht — wer aufs Auge // klickt will offensichtlich Sichtbarkeit kontrollieren, also direkt // in den "Ausgewählte"-Mode wechseln damit die Aktion wirkt. if (mode === 'active' || mode === 'all_force') onModeChange('all') } const toggleLock = (id) => { onChange(zeichnungsebenen.map(z => z.id === id ? { ...z, locked: !z.locked } : z)) } const toggleClipping = (id) => { onChange(zeichnungsebenen.map(z => z.id === id ? { ...z, hasClipping: !z.hasClipping } : 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 ( <>
Sichtbarkeit
{MODES.map(m => ( ))}
openGeschossDialog(zeichnungsebenen)} title="Einstellungen" />
{/* Master-Row: Master-Eye links + Master-Lock rechts (analog EbenenManager). */}
{sorted.map(z => ( onActiveChange(z.id)} onContextMenu={(ev) => openContextMenu(ev, z.id)} onToggleVisible={() => toggleVisible(z.id)} onToggleLock={() => toggleLock(z.id)} onToggleClipping={() => toggleClipping(z.id)} onDelete={() => remove(z.id)} /> ))}
{ctxMenu && ( setCtxMenu(null)} /> )} ) }