Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Docs/architecture/grid-style-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,29 @@ column factories, `ColumnWidthCalculator`) injects the same typed record.
`GridStyleOptions` is an immutable record with a `Default` fallback used only by tests; the `#000000`
cell-palette placeholders in `Default` are never rendered in production.

## Record shape: nested per group (interim, slice 3)

`GridStyleOptions` is no longer a flat 78-field record. It is a one-level nested root that composes ~10
per-group records (`Fonts`, `Layout`, `Selection`, `ChangedCells`, `ReadOnlyCells`, `DisabledCells`,
`Execution`, `StatusBar`, `ValidationPanel`, `Chrome`) plus the root-level `Orientation`. `ReadOnlyCells`
and `DisabledCells` share one `DepthPalette` type. Consumers read short nested paths — `gridStyle.Fonts.CellFontSize`,
`gridStyle.ReadOnlyCells.Depth1`, `gridStyle.Chrome.GridLine` — instead of the old flat fields. Colors stay
`string` in this shape; typing them as `StyleColor` is slice 4.

**The YAML file, the DTOs, and `GridStyleValidator` are unchanged** by this slice: the file on disk is
byte-identical, the DTO layer keeps its nested snake_case shape and per-key error reporting, and the load
mapper owns the small DTO-tree-to-group walk. `SaveThenLoad_DistinctFixture` proves the nested record still
round-trips losslessly through the unchanged file format. Property references elsewhere in this doc that still
show a flat path (for example `GridStyleOptions.FontFamily`) now live under their group
(`GridStyleOptions.Fonts.FontFamily`); those spellings are corrected in the slice-5 doc rewrite.

**Note for slice 4.** The error-path key `colors.grid_line` and the record path `Chrome.GridLine`
deliberately diverge: `grid_line` is a loose field in the `colors:` DTO section (beside `grid_border` /
`grid_background`), but the one-level record folds it into `Chrome` so the root carries no lone `string`.
Slice 4 moves `GridStyleValidator`'s per-key checks into the load mapper; that mapper-resident validation
**must keep emitting the `colors.grid_line` key**, not rename it to `chrome.grid_line`. The key names the
YAML path the operator edits, not the record path.

## Resources projection

The typed record is projected into `Application.Resources` at startup so XAML can bind styles via
Expand Down
5 changes: 5 additions & 0 deletions SemiStep/SemiStep.Core/Configuration/ChangedCellColors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace SemiStep.Core.Configuration;

public sealed record ChangedCellColors(
string Changed,
string ChangedSelected);
17 changes: 17 additions & 0 deletions SemiStep/SemiStep.Core/Configuration/ChromeColors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace SemiStep.Core.Configuration;

public sealed record ChromeColors(
string Info,
string Connected,
string Disconnected,
string LocalMode,
string Connecting,
string PanelBackground,
string PanelHeaderBackground,
string SubtleBorder,
string Separator,
string SecondaryForeground,
string GridBorder,
string GridBackground,
string HeaderForeground,
string GridLine);
13 changes: 13 additions & 0 deletions SemiStep/SemiStep.Core/Configuration/DepthPalette.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SemiStep.Core.Configuration;

public sealed record DepthPalette(
string Depth0,
string Depth1,
string Depth2,
string Depth3,
string Depth0Past,
string Depth1Past,
string Depth2Past,
string Depth3Past,
string Selected,
string Foreground);
12 changes: 12 additions & 0 deletions SemiStep/SemiStep.Core/Configuration/ExecutionPalette.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace SemiStep.Core.Configuration;

public sealed record ExecutionPalette(
string Depth0,
string Depth1,
string Depth2,
string Depth3,
string Depth0Past,
string Depth1Past,
string Depth2Past,
string Depth3Past,
string CurrentStepMarker);
10 changes: 10 additions & 0 deletions SemiStep/SemiStep.Core/Configuration/GridStyleFonts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace SemiStep.Core.Configuration;

public sealed record GridStyleFonts(
string FontFamily,
int HeaderFontSize,
int HeaderFontWeight,
bool HeaderItalic,
int CellFontSize,
int CellFontWeight,
bool CellItalic);
8 changes: 8 additions & 0 deletions SemiStep/SemiStep.Core/Configuration/GridStyleLayout.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace SemiStep.Core.Configuration;

public sealed record GridStyleLayout(
double CellPaddingLeft,
double CellPaddingTop,
double CellPaddingRight,
double CellPaddingBottom,
double RowHeight);
251 changes: 97 additions & 154 deletions SemiStep/SemiStep.Core/Configuration/GridStyleOptions.cs
Original file line number Diff line number Diff line change
@@ -1,163 +1,106 @@
namespace SemiStep.Core.Configuration;

public sealed record GridStyleOptions(
string FontFamily,
int HeaderFontSize,
int HeaderFontWeight,
bool HeaderItalic,
int CellFontSize,
int CellFontWeight,
bool CellItalic,
double CellPaddingLeft,
double CellPaddingTop,
double CellPaddingRight,
double CellPaddingBottom,
double RowHeight,
string SelectionBackgroundColor,
string SelectionForegroundColor,
string CellChangedColor,
string CellChangedSelectedColor,
string DisabledCellDepth0Color,
string DisabledCellDepth1Color,
string DisabledCellDepth2Color,
string DisabledCellDepth3Color,
string DisabledCellDepth0PastColor,
string DisabledCellDepth1PastColor,
string DisabledCellDepth2PastColor,
string DisabledCellDepth3PastColor,
string DisabledCellSelectedColor,
string DisabledCellForegroundColor,
string ReadOnlyCellDepth0Color,
string ReadOnlyCellDepth1Color,
string ReadOnlyCellDepth2Color,
string ReadOnlyCellDepth3Color,
string ReadOnlyCellDepth0PastColor,
string ReadOnlyCellDepth1PastColor,
string ReadOnlyCellDepth2PastColor,
string ReadOnlyCellDepth3PastColor,
string ReadOnlyCellSelectedColor,
string ReadOnlyCellForegroundColor,
string GridLineColor,
string StatusBarBackgroundColor,
string StatusBarForegroundColor,
double StatusBarPadding,
double StatusBarItemSpacing,
int StatusBarFontSize,
int StatusBarFontWeight,
bool StatusBarItalic,
int StatusBarTimerLabelFontSize,
int StatusBarTimerLabelFontWeight,
bool StatusBarTimerLabelItalic,
int StatusBarTimerValueFontSize,
int StatusBarTimerValueFontWeight,
bool StatusBarTimerValueItalic,
string ValidationPanelBackgroundColor,
string ValidationPanelForegroundColor,
string ValidationPanelErrorColor,
string ValidationPanelWarningColor,
double ValidationPanelMaxHeight,
string ExecutionDepth0Color,
string ExecutionDepth1Color,
string ExecutionDepth2Color,
string ExecutionDepth3Color,
string ExecutionDepth0PastColor,
string ExecutionDepth1PastColor,
string ExecutionDepth2PastColor,
string ExecutionDepth3PastColor,
string ExecutionCurrentStepMarkerColor,
string InfoColor,
string ConnectedColor,
string DisconnectedColor,
string LocalModeColor,
string ConnectingColor,
string PanelBackgroundColor,
string PanelHeaderBackgroundColor,
string SubtleBorderColor,
string SeparatorColor,
string SecondaryForegroundColor,
string GridBorderColor,
string GridBackgroundColor,
string HeaderForegroundColor,
GridStyleFonts Fonts,
GridStyleLayout Layout,
SelectionColors Selection,
ChangedCellColors ChangedCells,
DepthPalette ReadOnlyCells,
DepthPalette DisabledCells,
ExecutionPalette Execution,
StatusBarStyle StatusBar,
ValidationPanelStyle ValidationPanel,
ChromeColors Chrome,
GridOrientation Orientation)
{
// Test-only fallback; the #000000 cell palettes are placeholders, never rendered in production.
public static GridStyleOptions Default { get; } = new(
FontFamily: "",
HeaderFontSize: 14,
HeaderFontWeight: 700,
HeaderItalic: false,
CellFontSize: 12,
CellFontWeight: 400,
CellItalic: false,
CellPaddingLeft: 6,
CellPaddingTop: 4,
CellPaddingRight: 6,
CellPaddingBottom: 4,
RowHeight: 28,
SelectionBackgroundColor: "#CCE4F7",
SelectionForegroundColor: "#202020",
CellChangedColor: "#FFCC80",
CellChangedSelectedColor: "#EFD3A4",
DisabledCellDepth0Color: "#000000",
DisabledCellDepth1Color: "#000000",
DisabledCellDepth2Color: "#000000",
DisabledCellDepth3Color: "#000000",
DisabledCellDepth0PastColor: "#000000",
DisabledCellDepth1PastColor: "#000000",
DisabledCellDepth2PastColor: "#000000",
DisabledCellDepth3PastColor: "#000000",
DisabledCellSelectedColor: "#000000",
DisabledCellForegroundColor: "#000000",
ReadOnlyCellDepth0Color: "#000000",
ReadOnlyCellDepth1Color: "#000000",
ReadOnlyCellDepth2Color: "#000000",
ReadOnlyCellDepth3Color: "#000000",
ReadOnlyCellDepth0PastColor: "#000000",
ReadOnlyCellDepth1PastColor: "#000000",
ReadOnlyCellDepth2PastColor: "#000000",
ReadOnlyCellDepth3PastColor: "#000000",
ReadOnlyCellSelectedColor: "#000000",
ReadOnlyCellForegroundColor: "#000000",
GridLineColor: "#E0E0E0",
StatusBarBackgroundColor: "#F0F0F0",
StatusBarForegroundColor: "#000000",
StatusBarPadding: 5,
StatusBarItemSpacing: 10,
StatusBarFontSize: 12,
StatusBarFontWeight: 400,
StatusBarItalic: false,
StatusBarTimerLabelFontSize: 14,
StatusBarTimerLabelFontWeight: 400,
StatusBarTimerLabelItalic: false,
StatusBarTimerValueFontSize: 24,
StatusBarTimerValueFontWeight: 400,
StatusBarTimerValueItalic: false,
ValidationPanelBackgroundColor: "#FFFFFF",
ValidationPanelForegroundColor: "#000000",
ValidationPanelErrorColor: "#D32F2F",
ValidationPanelWarningColor: "#F57C00",
ValidationPanelMaxHeight: 100,
ExecutionDepth0Color: "#000000",
ExecutionDepth1Color: "#000000",
ExecutionDepth2Color: "#000000",
ExecutionDepth3Color: "#000000",
ExecutionDepth0PastColor: "#000000",
ExecutionDepth1PastColor: "#000000",
ExecutionDepth2PastColor: "#000000",
ExecutionDepth3PastColor: "#000000",
ExecutionCurrentStepMarkerColor: "#000000",
InfoColor: "#1976D2",
ConnectedColor: "#44BB44",
DisconnectedColor: "#FF4444",
LocalModeColor: "#6C707E",
ConnectingColor: "#FFAF0F",
PanelBackgroundColor: "#F8F8F8",
PanelHeaderBackgroundColor: "#EEEEEE",
SubtleBorderColor: "#D0D0D0",
SeparatorColor: "#C0C0C0",
SecondaryForegroundColor: "#888888",
GridBorderColor: "#808080",
GridBackgroundColor: "#FFFFFF",
HeaderForegroundColor: "#000000",
Fonts: new GridStyleFonts(
FontFamily: "",
HeaderFontSize: 14,
HeaderFontWeight: 700,
HeaderItalic: false,
CellFontSize: 12,
CellFontWeight: 400,
CellItalic: false),
Layout: new GridStyleLayout(
CellPaddingLeft: 6,
CellPaddingTop: 4,
CellPaddingRight: 6,
CellPaddingBottom: 4,
RowHeight: 28),
Selection: new SelectionColors(
Background: "#CCE4F7",
Foreground: "#202020"),
ChangedCells: new ChangedCellColors(
Changed: "#FFCC80",
ChangedSelected: "#EFD3A4"),
ReadOnlyCells: new DepthPalette(
Depth0: "#000000",
Depth1: "#000000",
Depth2: "#000000",
Depth3: "#000000",
Depth0Past: "#000000",
Depth1Past: "#000000",
Depth2Past: "#000000",
Depth3Past: "#000000",
Selected: "#000000",
Foreground: "#000000"),
DisabledCells: new DepthPalette(
Depth0: "#000000",
Depth1: "#000000",
Depth2: "#000000",
Depth3: "#000000",
Depth0Past: "#000000",
Depth1Past: "#000000",
Depth2Past: "#000000",
Depth3Past: "#000000",
Selected: "#000000",
Foreground: "#000000"),
Execution: new ExecutionPalette(
Depth0: "#000000",
Depth1: "#000000",
Depth2: "#000000",
Depth3: "#000000",
Depth0Past: "#000000",
Depth1Past: "#000000",
Depth2Past: "#000000",
Depth3Past: "#000000",
CurrentStepMarker: "#000000"),
StatusBar: new StatusBarStyle(
Background: "#F0F0F0",
Foreground: "#000000",
Padding: 5,
ItemSpacing: 10,
FontSize: 12,
Weight: 400,
Italic: false,
TimerLabelFontSize: 14,
TimerLabelWeight: 400,
TimerLabelItalic: false,
TimerValueFontSize: 24,
TimerValueWeight: 400,
TimerValueItalic: false),
ValidationPanel: new ValidationPanelStyle(
Background: "#FFFFFF",
Foreground: "#000000",
ErrorColor: "#D32F2F",
WarningColor: "#F57C00",
MaxHeight: 100),
Chrome: new ChromeColors(
Info: "#1976D2",
Connected: "#44BB44",
Disconnected: "#FF4444",
LocalMode: "#6C707E",
Connecting: "#FFAF0F",
PanelBackground: "#F8F8F8",
PanelHeaderBackground: "#EEEEEE",
SubtleBorder: "#D0D0D0",
Separator: "#C0C0C0",
SecondaryForeground: "#888888",
GridBorder: "#808080",
GridBackground: "#FFFFFF",
HeaderForeground: "#000000",
GridLine: "#E0E0E0"),
Orientation: GridOrientation.RowsAsSteps);
}
Loading