Attribut-Panel: Vordergrund/Hintergrund mit 'Nach System'

Die Attribut-Sektion 'Fuellung' zeigt statt der einen Fuellfarbe jetzt zwei
Felder: Vordergrund (Muster-/Schraffurfarbe) und Hintergrund (Fuellung),
jeweils per Element ueberschreibbar. Leerer Override = 'Nach System' (erbt);
Farbe waehlen setzt den Override, x loescht ihn wieder. Schreibt
Wall/Ceiling/Drawing2D.foreground/background ueber neue Store-Mutationen
(setElementForeground/Background), gespiegelt zum bestehenden Fuellfarbe-Pfad.
Die Resolve-Schicht (generatePlan) liest diese Overrides bereits, wirkt also
sofort im Plan.
This commit is contained in:
2026-07-04 00:26:32 +02:00
parent 6288f755a8
commit f3639cfb15
7 changed files with 157 additions and 34 deletions
+51
View File
@@ -134,6 +134,24 @@ export interface ProjectSlice {
* `null` entfernt das Feld (Fläche wieder transparent).
*/
setElementFillColor: (id: string, fillColor: string | null) => void;
/**
* Setzt/entfernt den Vordergrund-Override (Muster-/Schraffurfarbe) — Wand,
* Decke oder Drawing2D. `null` = „Nach System" (Feld entfernen → erben).
*/
setElementForeground: (
kind: "wall" | "ceiling" | "drawing2d",
id: string,
value: string | null,
) => void;
/**
* Setzt/entfernt den Hintergrund-Override (Füllfarbe/Poché) — Wand, Decke
* oder Drawing2D. `null` = „Nach System" (Feld entfernen → erben).
*/
setElementBackground: (
kind: "wall" | "ceiling" | "drawing2d",
id: string,
value: string | null,
) => void;
/**
* Skaliert die Geometrie eines Elements auf Zielbreite×-höhe (Meter) um einen
* Ankerpunkt (fx/fy ∈ [0,1] relativ zur bbox; 0,0 = oben-links).
@@ -723,6 +741,13 @@ export function createProjectSlice(
}),
})),
// Vordergrund-/Hintergrund-Override (Wand/Decke/Drawing2D); `null` löscht
// das Feld (→ „Nach System", erbt wieder vom Bauteil/System).
setElementForeground: (kind, id, value) =>
setProject((p) => setOverrideField(p, kind, id, "foreground", value)),
setElementBackground: (kind, id, value) =>
setProject((p) => setOverrideField(p, kind, id, "background", value)),
// ── Größe (Resize um Anker) ────────────────────────────────────────────
resizeElement: (kind, id, w, h, anchor) =>
setProject((p) => resizeElement(p, kind, id, w, h, anchor)),
@@ -879,6 +904,32 @@ function mapStair(
}
/** Immutabler Map über eine Decke (per ID); No-op ohne Treffer. */
/**
* Setzt/entfernt einen optionalen Farb-Override (`foreground`/`background`) an
* einem Element (Wand, Decke oder Drawing2D). `value === null` entfernt das Feld
* (→ „Nach System", erbt wieder). Immutable; unbekannte IDs sind ein No-op.
*/
function setOverrideField(
project: Project,
kind: "wall" | "ceiling" | "drawing2d",
id: string,
field: "foreground" | "background",
value: string | null,
): Project {
const apply = <T extends { id: string }>(item: T): T => {
if (item.id !== id) return item;
if (value === null) {
const { [field]: _omit, ...rest } = item as Record<string, unknown>;
return rest as unknown as T;
}
return { ...item, [field]: value };
};
if (kind === "wall") return { ...project, walls: project.walls.map(apply) };
if (kind === "ceiling")
return { ...project, ceilings: (project.ceilings ?? []).map(apply) };
return { ...project, drawings2d: project.drawings2d.map(apply) };
}
function mapCeiling(
project: Project,
ceilingId: string,
+17
View File
@@ -218,6 +218,17 @@ export interface Selection {
* keine (transparent). Bei Wänden/Türen `undefined` (nicht anwendbar).
*/
fillColor?: string | null;
/**
* Vordergrund-Override (Muster-/Schraffurfarbe) des Elements; `undefined` =
* „Nach System" (erbt vom Bauteil/System). Gesetzt bei Wand, Decke und
* geschlossener Drawing2D.
*/
foreground?: string;
/**
* Hintergrund-Override (Füllfarbe/Poché) des Elements; `undefined` = „Nach
* System". Nachfolger von `fillColor`; hat im Plan Vorrang.
*/
background?: string;
/** Ob die Form geschlossen ist (rect/circle/closed polyline) — nur Drawing2D. */
closed?: boolean;
/** Achsparallele Bounding-Box in Modell-Metern. */
@@ -342,6 +353,8 @@ function wallSelection(project: Project, wall: Wall): Selection {
weightMm,
fillHatchId: undefined,
fillColor: undefined,
foreground: wall.foreground,
background: wall.background,
closed: undefined,
bbox: { minX, minY, maxX, maxY },
wall: wallInfo,
@@ -386,6 +399,8 @@ function ceilingSelection(project: Project, ceiling: Ceiling): Selection {
weightMm,
fillHatchId: undefined,
fillColor: undefined,
foreground: ceiling.foreground,
background: ceiling.background,
closed: true,
bbox: { minX: box.minX, minY: box.minY, maxX: box.maxX, maxY: box.maxY },
ceiling: ceilingInfo,
@@ -542,6 +557,8 @@ function drawingSelection(project: Project, d: Drawing2D): Selection {
weightMm,
fillHatchId: closed ? d.hatchId ?? null : null,
fillColor: closed ? d.fillColor ?? null : null,
foreground: closed ? d.foreground : undefined,
background: closed ? d.background : undefined,
closed,
bbox: geomBBox(d.geom),
};