diff --git a/src/OberleisteApp.jsx b/src/OberleisteApp.jsx
index 3c3cf7e..8e77759 100644
--- a/src/OberleisteApp.jsx
+++ b/src/OberleisteApp.jsx
@@ -125,6 +125,83 @@ function BarSelect({ icon, value, onChange, title, disabled, width, children, jo
)
}
+// BarCombo: dunklerer (bg-input) Pill-Container der select + optional gear
+// als EINE nahtlose Box rendert. Icon roh links daneben (kein Container).
+// iconClickable=true macht das Icon zum Toggle-Button (Overrides etc.).
+function BarCombo({
+ icon, iconActive, iconClickable, onIconClick, iconTitle,
+ value, onChange, width, title, children, disabled,
+ onGear, gearTitle,
+}) {
+ return (
+
+ {/* Icon links — fixe Breite fuer X-Axis-Alignment zwischen Reihen */}
+ {iconClickable ? (
+
+ ) : (
+
+
+
+ )}
+ {/* Combined pill: select + optional gear, gemeinsamer bg + border */}
+
+
+ {onGear && (
+
+ )}
+
+
+ )
+}
+
// BarButton: pill-foermiger Icon-Button im selben Stil wie BarSelect.
// joinedLeft = linke Kante flach (dockt rechts an einen BarSelect-joinedRight).
function BarButton({ icon, onClick, title, disabled, active, joinedLeft }) {
@@ -132,7 +209,7 @@ function BarButton({ icon, onClick, title, disabled, active, joinedLeft }) {
- {/* ====== DISPLAY-MODE ====== */}
- setDisplayMode(v)}
- title="Display-Mode (Wireframe / Shaded / Rendered / etc.)"
- width={160}
- >
- {!state.displayMode && }
- {(state.displayModes || []).map(dm => (
-
- ))}
-
-
-
-
- {/* ====== MASSE (Preset-Picker + Settings) ====== */}
- setMasseActive(v)}
- title="Aktives Mass — Raum-Rundung + Mass-Linien-Format"
- width={140}
- joinedRight
- >
- {(state.massePresets || []).length === 0 && }
- {(state.massePresets || []).map(p => (
-
- ))}
-
- openMasseSettings()}
- title="Masse bearbeiten / neues anlegen" joinedLeft />
+ {/* ====== 2-Reihen Preset-Block ======
+ Oben: Display | Kombi
+ Unten: Overrides | Masse
+ Gleiche Pill-Breiten, identische X-Positionen (Grid-Layout). */}
+ {(() => {
+ const PRESET_W = 150
+ return (
+
+ {/* Reihe 1, Spalte 1: Display */}
+ setDisplayMode(v)}
+ title="Display-Mode (Wireframe / Shaded / Rendered / etc.)"
+ width={PRESET_W}
+ >
+ {!state.displayMode && }
+ {(state.displayModes || []).map(dm => (
+
+ ))}
+
+ {/* Reihe 1, Spalte 2: Ebenenkombination */}
+ {
+ if (v === '__configure__') { openLayerCombinationsDialog(); return }
+ if (v === '__save__') {
+ const suggested = state.layerCombinationActive
+ || `Kombi ${(state.layerCombinations || []).length + 1}`
+ const name = (window.prompt('Name für Ebenenkombination:', suggested) || '').trim()
+ if (!name) return
+ if ((state.layerCombinations || []).includes(name) &&
+ !window.confirm(`"${name}" überschreiben?`)) return
+ saveLayerCombination(name)
+ return
+ }
+ if (v === '__delete__') {
+ if (state.layerCombinationActive &&
+ window.confirm(`Kombination "${state.layerCombinationActive}" löschen?`))
+ deleteLayerCombination(state.layerCombinationActive)
+ return
+ }
+ pickLayerCombination(v === '__none__' ? null : v)
+ }}
+ title={state.layerCombinationActive
+ ? `Aktive Kombi: ${state.layerCombinationActive}`
+ : 'Keine Kombination — manuelle Sichtbarkeit'}
+ width={PRESET_W}
+ onGear={openLayerCombinationsDialog}
+ gearTitle="Ebenenkombinationen bearbeiten"
+ >
+
+ {(state.layerCombinations || []).map(name => (
+
+ ))}
+
+
+ {state.layerCombinationActive && (
+
+ )}
+
+
+ {/* Reihe 2, Spalte 1: Overrides (Toggle als Icon links) */}
+ toggleOverrides(!state.overridesEnabled)}
+ iconTitle={state.overridesEnabled
+ ? 'Grafische Overrides aktiv — klick zum Ausschalten'
+ : 'Grafische Overrides ausgeschaltet'}
+ value={state.overridesActivePreset || '__none__'}
+ onChange={(v) => {
+ if (v === '__configure__') { openOverridesPanel(); return }
+ setOverridesPreset(v === '__none__' ? null : v)
+ }}
+ title={state.overridesActivePreset
+ ? `Aktives Preset: ${state.overridesActivePreset} (${state.overridesCount} Regeln)`
+ : `Kein Preset aktiv (${state.overridesCount} Regeln, frei editiert)`}
+ width={PRESET_W}
+ onGear={openOverridesPanel}
+ gearTitle="Overrides-Regel-Editor öffnen"
+ >
+
+ {(state.overridesPresets || []).map(name => (
+
+ ))}
+
+
+
+ {/* Reihe 2, Spalte 2: Masse */}
+ setMasseActive(v)}
+ title="Aktives Mass — Raum-Rundung + Mass-Linien-Format"
+ width={PRESET_W}
+ onGear={openMasseSettings}
+ gearTitle="Masse bearbeiten / neues anlegen"
+ >
+ {(state.massePresets || []).length === 0 && }
+ {(state.massePresets || []).map(p => (
+
+ ))}
+
+
+ )
+ })()}
@@ -473,92 +630,9 @@ export default function OberleisteApp() {
: 'Strichstärken anzeigen (Print-View)'}
/>
-
-
{/* Snap-Toggles (Ortho/Grid/OSnap) sind in Rhinos eigener Footer-Bar
schon vorhanden — hier rausgenommen um Doppelung zu vermeiden. */}
- {/* ====== STACK: Overrides + Kombi uebereinander ======
- Beide Zeilen haben identisches Spalten-Layout (Label-Spalte fix,
- Dropdown gleich breit), damit Dropdowns vertikal aligned sind. */}
- {/* ====== OVERRIDES ====== */}
- toggleOverrides(!state.overridesEnabled)}
- title={state.overridesEnabled
- ? 'Grafische Overrides aktiv — klick zum Ausschalten'
- : 'Grafische Overrides ausgeschaltet'}
- />
- {
- if (v === '__configure__') { openOverridesPanel(); return }
- setOverridesPreset(v === '__none__' ? null : v)
- }}
- title={state.overridesActivePreset
- ? `Aktives Preset: ${state.overridesActivePreset} (${state.overridesCount} Regeln)`
- : `Kein Preset aktiv (${state.overridesCount} Regeln, frei editiert)`}
- width={140}
- joinedRight
- >
-
- {(state.overridesPresets || []).map(name => (
-
- ))}
-
-
-
-
-
-
-
- {/* ====== EBENEN-KOMBINATIONEN ====== */}
- {
- if (v === '__configure__') { openLayerCombinationsDialog(); return }
- if (v === '__save__') {
- const suggested = state.layerCombinationActive
- || `Kombi ${(state.layerCombinations || []).length + 1}`
- const name = (window.prompt('Name für Ebenenkombination:', suggested) || '').trim()
- if (!name) return
- if ((state.layerCombinations || []).includes(name) &&
- !window.confirm(`"${name}" überschreiben?`)) return
- saveLayerCombination(name)
- return
- }
- if (v === '__delete__') {
- if (state.layerCombinationActive &&
- window.confirm(`Kombination "${state.layerCombinationActive}" löschen?`))
- deleteLayerCombination(state.layerCombinationActive)
- return
- }
- pickLayerCombination(v === '__none__' ? null : v)
- }}
- title={state.layerCombinationActive
- ? `Aktive Kombi: ${state.layerCombinationActive}`
- : 'Keine Kombination — manuelle Sichtbarkeit'}
- width={150}
- joinedRight
- >
-
- {(state.layerCombinations || []).map(name => (
-
- ))}
-
-
- {state.layerCombinationActive && (
-
- )}
-
-
-
-
{/* Spacer am rechten Rand */}