Wand-Grips + Schnitt-Grips + Referenz-Sublayer pro Bauteil + Print-Auto-Hide
Custom-Grip-Overlays via DisplayConduit + MouseCallback: - wand_grips.py: dicke klickbare Marker an wand_axis-Endpunkten, auch wenn die Referenz-Layer ausgeblendet ist. GetPoint mit fixem Anker. - schnitt_grips.py: 3 Marker pro Schnitt (P1, P2, Mid). Mid translatiert ganze Linie, P1/P2 verschieben Endpunkt. Hide Clipping-Planes waehrend GetPoint damit kein Verbots-Cursor durch Locked-Edges erscheint. skip_view=True bei Re-Activate damit Drag nicht in Section springt. Referenz-Architektur umgebaut: - wand_axis + oeffnung_point liegen jetzt unter <Geschoss>::20_Waende:: 20r_Referenz statt eigener top-level 19_Referenzlinien-Ebene. - Migration v4 zieht existierende Sources auf den neuen Pfad. - Toggle in Oberleiste keyword-driven: findet alle 'Referenz'-Sub-Ebenen rekursiv, toggelt alle Praefixe gemeinsam. Bauteil-uebergreifend. Oberleiste-Layout: - Druck-Ansicht-Button hoch neben Massstab-Dropdown (Reihe 1). - Referenzlinien-Toggle in Reihe 2 neben Zoom-Pill, symmetrisch zum Druck-Button. Zoom-Pill auf 3 Buttons reduziert. - Print-View AN → Referenz-Layer automatisch ausblenden, Snapshot restored beim Ausschalten. Fix: clear_schnitt_clipping respektiert Mode=Locked nicht — vor Delete auf Normal-Mode wechseln + Modify damit's persistiert. Schnitt-Loeschen raeumt Clipping-Planes jetzt sauber auf. Fix: Schnitt-Doppelklick-Handler aktiviert nur bei expliziter Schnitt- Auswahl, ignoriert andere Selektionen. Fix: _send_state Selection-Detection mit Source-ODER-Volume-Fallback — Fenster-Properties erscheinen jetzt auch wenn oeffnung_point auf hidden Referenz-Layer liegt. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+76
-60
@@ -16,6 +16,7 @@ import {
|
||||
applyTextStyle, saveTextStyle, deleteTextStyle,
|
||||
setDarstellung,
|
||||
arrangeSelection,
|
||||
toggleReferenzlinien,
|
||||
} from './lib/rhinoBridge'
|
||||
|
||||
const PRESETS = [
|
||||
@@ -470,7 +471,7 @@ export default function OberleisteApp() {
|
||||
// Buttons-Pill: gleiche Logik wie View-Toggle (weiss default,
|
||||
// grün on hover, accent-fill wenn active)
|
||||
const PILL_W = 140 // Gleiche Breite fuer Dropdown + Buttons-Pill
|
||||
const N_BTN = 4
|
||||
const N_BTN = 3 // ohne Lineweights — der sitzt jetzt oben neben Dropdown
|
||||
const BTN_W = Math.floor(PILL_W / N_BTN) // jeder Button gleich breit
|
||||
const SegBtn = ({ icon, onClick, title, disabled, active, isFirst, isLast }) => (
|
||||
<button onClick={onClick} disabled={disabled} title={title}
|
||||
@@ -560,70 +561,85 @@ export default function OberleisteApp() {
|
||||
</div>
|
||||
{/* Reihe 1, Spalte 2: Gesetzter Massstab Dropdown — KEIN Icon, gleiche
|
||||
Breite wie Buttons-Pill darunter, exakt uebereinander */}
|
||||
{customMode ? (
|
||||
<input
|
||||
ref={customInputRef}
|
||||
disabled={isPerspective}
|
||||
type="text" placeholder="1:N"
|
||||
value={draft}
|
||||
onChange={(e) => setDraft(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') applyDraft()
|
||||
else if (e.key === 'Escape') cancelDraft()
|
||||
}}
|
||||
onBlur={applyDraft}
|
||||
style={{
|
||||
height: BAR_H, width: PILL_W,
|
||||
background: 'var(--bg-input)',
|
||||
color: 'var(--text-primary)',
|
||||
border: '1px solid var(--border)',
|
||||
borderRadius: 999,
|
||||
padding: '0 12px', fontSize: 11,
|
||||
fontFamily: 'DM Mono, monospace',
|
||||
outline: 'none',
|
||||
}}
|
||||
title="Massstab eingeben (Enter = uebernehmen, Esc = abbrechen)"
|
||||
/>
|
||||
) : (
|
||||
<BarCombo
|
||||
value={dropdownValue}
|
||||
onChange={(v) => applyDropdown(v)}
|
||||
disabled={isPerspective}
|
||||
width={PILL_W}
|
||||
title="Gesetzter Massstab"
|
||||
>
|
||||
<option value="__none__">—</option>
|
||||
{PRESETS.map(p => (
|
||||
<option key={p.value} value={String(p.value)}>{p.label}</option>
|
||||
))}
|
||||
{appliedScale != null && !PRESETS.some(p => p.value === appliedScale) && (
|
||||
<option value={String(appliedScale)}>1:{appliedScale}</option>
|
||||
)}
|
||||
<option value="__custom__">Eigener…</option>
|
||||
</BarCombo>
|
||||
)}
|
||||
{/* Reihe 2, Spalte 2: Buttons-Pill — gleiche Breite wie Dropdown */}
|
||||
<div style={{
|
||||
display: 'inline-flex', width: PILL_W,
|
||||
height: BAR_H + 2, boxSizing: 'border-box',
|
||||
border: '1px solid var(--border)', borderRadius: 999,
|
||||
overflow: 'hidden', flexShrink: 0, justifySelf: 'start',
|
||||
}}>
|
||||
<SegBtn icon="percent" onClick={apply100} isFirst
|
||||
disabled={isPerspective || !appliedScale}
|
||||
title={appliedScale ? `Zoom auf 1:${appliedScale} snappen` : 'Erst einen Massstab wählen'} />
|
||||
<SegBtn icon="fit_screen" onClick={zoomExtents}
|
||||
title="Auf gesamten Inhalt zoomen" />
|
||||
<SegBtn icon="center_focus_strong" onClick={zoomSelection}
|
||||
title="Auf Selektion zoomen" />
|
||||
<SegBtn
|
||||
{/* Dropdown + Druck-Ansicht-Toggle in einer Flex-Reihe — der
|
||||
Toggle sitzt jetzt oben statt unten im Zoom-Pill, weil er
|
||||
massstabs-nah ist (Print-View = scale-korrekte Strichstaerken). */}
|
||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||
{customMode ? (
|
||||
<input
|
||||
ref={customInputRef}
|
||||
disabled={isPerspective}
|
||||
type="text" placeholder="1:N"
|
||||
value={draft}
|
||||
onChange={(e) => setDraft(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') applyDraft()
|
||||
else if (e.key === 'Escape') cancelDraft()
|
||||
}}
|
||||
onBlur={applyDraft}
|
||||
style={{
|
||||
height: BAR_H, width: PILL_W,
|
||||
background: 'var(--bg-input)',
|
||||
color: 'var(--text-primary)',
|
||||
border: '1px solid var(--border)',
|
||||
borderRadius: 999,
|
||||
padding: '0 12px', fontSize: 11,
|
||||
fontFamily: 'DM Mono, monospace',
|
||||
outline: 'none',
|
||||
}}
|
||||
title="Massstab eingeben (Enter = uebernehmen, Esc = abbrechen)"
|
||||
/>
|
||||
) : (
|
||||
<BarCombo
|
||||
value={dropdownValue}
|
||||
onChange={(v) => applyDropdown(v)}
|
||||
disabled={isPerspective}
|
||||
width={PILL_W}
|
||||
title="Gesetzter Massstab"
|
||||
>
|
||||
<option value="__none__">—</option>
|
||||
{PRESETS.map(p => (
|
||||
<option key={p.value} value={String(p.value)}>{p.label}</option>
|
||||
))}
|
||||
{appliedScale != null && !PRESETS.some(p => p.value === appliedScale) && (
|
||||
<option value={String(appliedScale)}>1:{appliedScale}</option>
|
||||
)}
|
||||
<option value="__custom__">Eigener…</option>
|
||||
</BarCombo>
|
||||
)}
|
||||
<BarButton
|
||||
icon={state.showLineweights ? 'print' : 'edit'}
|
||||
active={state.showLineweights}
|
||||
onClick={() => setShowLineweights(!state.showLineweights)}
|
||||
isLast
|
||||
title={state.showLineweights
|
||||
? 'Print-View aktiv — klick zum Ausschalten'
|
||||
: 'Strichstärken anzeigen (Print-View)'} />
|
||||
: 'Strichstaerken anzeigen (Print-View)'} />
|
||||
</div>
|
||||
{/* Reihe 2, Spalte 2: Zoom-Pill + Referenzlinien-Toggle.
|
||||
Symmetrisch zur Reihe 1 (Dropdown + Lineweights-Button). */}
|
||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||
<div style={{
|
||||
display: 'inline-flex', width: PILL_W,
|
||||
height: BAR_H + 2, boxSizing: 'border-box',
|
||||
border: '1px solid var(--border)', borderRadius: 999,
|
||||
overflow: 'hidden', flexShrink: 0,
|
||||
}}>
|
||||
<SegBtn icon="percent" onClick={apply100} isFirst
|
||||
disabled={isPerspective || !appliedScale}
|
||||
title={appliedScale ? `Zoom auf 1:${appliedScale} snappen` : 'Erst einen Massstab wählen'} />
|
||||
<SegBtn icon="fit_screen" onClick={zoomExtents}
|
||||
title="Auf gesamten Inhalt zoomen" />
|
||||
<SegBtn icon="center_focus_strong" onClick={zoomSelection}
|
||||
isLast
|
||||
title="Auf Selektion zoomen" />
|
||||
</div>
|
||||
<BarButton
|
||||
icon={state.referenzlinienVisible === false ? 'visibility_off' : 'visibility'}
|
||||
active={state.referenzlinienVisible !== false}
|
||||
onClick={() => toggleReferenzlinien(state.referenzlinienVisible === false)}
|
||||
title={state.referenzlinienVisible === false
|
||||
? 'Referenzlinien einblenden (Wandachsen, Oeffnungs-Punkte)'
|
||||
: 'Referenzlinien ausblenden (Wandachsen, Oeffnungs-Punkte)'} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -175,6 +175,12 @@ export function openElementeProperties() { send('OPEN_ELEMENTE_PROPERTIES', {})
|
||||
export function setDarstellung(d) { send('SET_DARSTELLUNG', { darstellung: d || '' }) }
|
||||
// Anordnen — 2D-Z-Stack via Rhino-DisplayOrder. dir: 'front'|'forward'|'backward'|'back'
|
||||
export function arrangeSelection(dir) { send('ARRANGE', { dir }) }
|
||||
// Referenzlinien-Layer (Code 19) on/off — Shortcut zur Layer-Sichtbarkeit
|
||||
// damit der User nicht durchs Ebenen-Panel muss. Layer bleibt erhalten,
|
||||
// Ausschnitte speichern den State automatisch mit.
|
||||
export function toggleReferenzlinien(visible) {
|
||||
send('TOGGLE_REFERENZLINIEN', { visible: !!visible })
|
||||
}
|
||||
// Schnitt/Ansicht — interaktiver 2-Punkt-Pick im Rhino-Viewport. Erzeugt
|
||||
// eine neue Zeichnungsebene type=schnitt + 2D-Plan-Symbol + aktiviert sie.
|
||||
// opts: { cutAtLine: bool, depthBack: m, heightMin: m, heightMax: m, namePrefix }
|
||||
|
||||
Reference in New Issue
Block a user