mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-10-19 13:53:01 +02:00
Document the adjustable colours, and record the design and the plan
Both manuals get the Colours tab in full: the six roles, that a change applies at once but survives a restart only after Save settings, the three ways back with their keyboard shortcuts, what each provenance label means, and the readability notice that warns without refusing. Two things an operator would otherwise have to discover. The reset button is always drawn in the shipped colours and works when nothing else can be read -- the risk section of the design says plainly that a keyboard path only helps whoever knows it, so the manual is where this has to be written down. And the root profile already has both stylesheet files, because KST4Contest has been writing them at startup for years, so most of its roles report "from file" rather than "shipped" with identical values. PROJECT_CONTEXT.md records the decisions that outlive this stage: the three sources and their precedence, that a role is a selector and a property, that the theme must read the store's state rather than remember, where the contrast pairs come from, why the root profile's file layer always exists, and why the lifeline refuses the active palette. Also corrects its claim that CSS stays global -- a profile now owns its stylesheets. The design document and the implementation plan are kept as they were written, including the plan's own corrections where measuring the code contradicted it.
This commit is contained in:
5 files changed
+2582
-1
No files matched your search
+44
-1
@@ -70,7 +70,7 @@ A batch of changes belongs in one `SimpleRoster.mutate(...)`, not one call per e
|
|||||||
|
|
||||||
## Operator Profiles and Per-Profile Persistence
|
## Operator Profiles and Per-Profile Persistence
|
||||||
|
|
||||||
- One operator profile owns one `preferences.xml` and one worked-station database. Everything else under `~/.praktiKST/` stays global: CSS, audio files, DEM and terrain packages, the error log and the version-info feed.
|
- One operator profile owns one `preferences.xml`, one worked-station database and, since release 1.50, its own pair of stylesheets. Everything else under `~/.praktiKST/` stays global: audio files, DEM and terrain packages, the error log and the version-info feed.
|
||||||
- The **root profile** is the historic flat installation: `preferences.xml` and `praktiKST.db` directly below the application directory. It is never moved, and it always uses the common station database, because that database is the installation's own.
|
- The **root profile** is the historic flat installation: `preferences.xml` and `praktiKST.db` directly below the application directory. It is never moved, and it always uses the common station database, because that database is the installation's own.
|
||||||
- Additional profiles live under `profiles/<profileId>/`. `profileId` is a stable, file-system-safe slug assigned once; renaming a profile changes only its display name and never moves a directory.
|
- Additional profiles live under `profiles/<profileId>/`. `profileId` is a stable, file-system-safe slug assigned once; renaming a profile changes only its display name and never moves a directory.
|
||||||
- The registry `profiles.xml` is created lazily. An installation that has only the flat layout gets no registry and no `profiles/` directory; the root profile is synthesised in memory. Startup with no or exactly one profile therefore asks nothing and writes nothing, and a downgrade to an older release is a no-op.
|
- The registry `profiles.xml` is created lazily. An installation that has only the flat layout gets no registry and no `profiles/` directory; the root profile is synthesised in memory. Startup with no or exactly one profile therefore asks nothing and writes nothing, and a downgrade to an older release is a no-op.
|
||||||
@@ -270,6 +270,49 @@ section records only the durable architecture and operational boundaries.
|
|||||||
|
|
||||||
## Important Decisions and Workarounds
|
## Important Decisions and Workarounds
|
||||||
|
|
||||||
|
- **The palette has three sources, and the later one wins role by role** (release 1.50): the
|
||||||
|
shipped stylesheet from the classpath, then the profile's own stylesheet file if present,
|
||||||
|
then the six role overrides stored in that profile's preferences. `resolvePalette` is a pure
|
||||||
|
function and reports the provenance of every role, which the colours tab shows per field --
|
||||||
|
with two sources able to decide the same colour, that is the only thing that keeps "why is
|
||||||
|
this colour what it is" answerable, and it is not optional.
|
||||||
|
- **A role is a selector and a property, not a property alone.** Three of the six are stated
|
||||||
|
outside `.root` (text on `.label`, the separator on `.separator *.line`), and
|
||||||
|
`-fx-background-color` alone appears a dozen times in the evening sheet. `JavaFxStylesheet.read`
|
||||||
|
returns a complete palette with Modena fallbacks and is right for layer 1;
|
||||||
|
`declaredRoles` returns only what a sheet actually names and is the only thing correct for
|
||||||
|
layer 2. Measured: the shipped daylight sheet states no colour at all, the evening sheet five.
|
||||||
|
- **The root profile's layer 2 always exists, and that is not a bug.** `copyResourceIfRequired`
|
||||||
|
writes `KST4ContestDefaultDay.css` and `…Evening.css` at every startup, and those are exactly
|
||||||
|
the paths `paletteRelativeFileName(rootProfile, …)` resolves to — reading them is what fixes
|
||||||
|
the long-standing defect that the copies were written and never read. Consequence to keep in
|
||||||
|
mind: on the default installation most roles report *from file*, not *shipped*, with the same
|
||||||
|
values. Anything keyed on provenance rather than on a colour's value will therefore misfire
|
||||||
|
there; `textAccent` did, and repainted the evening accent on upgrade.
|
||||||
|
- **A file stating `-fx-base` and no `-fx-background` states the derived window surface too**,
|
||||||
|
because that is what JavaFX does with it. The settings tab keeps the two roles independent —
|
||||||
|
the spec separates them so an operator can set one without the other — but a hand-edited
|
||||||
|
sheet follows the stylesheet language, or `-fx-base: #303030` would leave every window the
|
||||||
|
shipped light grey.
|
||||||
|
- **The contrast guard's pairs come from `Theme.kt`'s Material mapping, not from the role
|
||||||
|
names.** `background` and `surface` are both `windowBackground` with `labelTextFill` on them,
|
||||||
|
and `primary` is `textAccent`, not `accent`; `base` reaches the screen only through the menu
|
||||||
|
strip and the selection tint. Measuring text against `base` alone let an operator black out
|
||||||
|
every window and hear nothing.
|
||||||
|
- **`Kst4ContestTheme` must read the palette from the `PaletteStore`'s state, never from
|
||||||
|
`remember`.** That read is what makes a colour change recompose every open window;
|
||||||
|
`remember(darkMode)` held the palette until someone toggled day/evening, so a change reached
|
||||||
|
nothing. `ThemeReadsPaletteStoreTest` pins it.
|
||||||
|
- **The contrast guard is relative to the shipped sheet, not an absolute WCAG floor.** Measured:
|
||||||
|
the shipped sheets have three pairs under 4.5 themselves (daylight accent 2.86, evening accent
|
||||||
|
2.26, evening text-in-field about 2.9), so an absolute rule would warn on an untouched client
|
||||||
|
and teach the operator to ignore warnings. It reports a pair only when it is both under the
|
||||||
|
floor and worse than shipped, so the shipped state and any improvement never warn.
|
||||||
|
- **The "reset to the shipped colours" button never takes the active palette.** It receives the
|
||||||
|
shipped palette as a required parameter and reads no composition local, so it has no path to
|
||||||
|
the resolved one. An operator who sets text and surface to the same black cannot see any
|
||||||
|
other control, this one included, unless it refuses their palette.
|
||||||
|
|
||||||
- Preserve full callsign/category identity while applying base-call normalisation only to specifically defined features.
|
- Preserve full callsign/category identity while applying base-call normalisation only to specifically defined features.
|
||||||
- Keep canonical worker-thread domain state separate from the row lists the user interface draws from.
|
- Keep canonical worker-thread domain state separate from the row lists the user interface draws from.
|
||||||
- The station map is a Compose canvas that fetches its own tiles. The JavaFX WebView, the bundled Leaflet resources, the CSS-3D-transform workaround and the `TileProxyServer` were removed with JavaFX; offline DEM, terrain packages and the profile cache are unaffected and must stay that way.
|
- The station map is a Compose canvas that fetches its own tiles. The JavaFX WebView, the bundled Leaflet resources, the CSS-3D-transform workaround and the `TileProxyServer` were removed with JavaFX; offline DEM, terrain packages and the profile cache are unaffected and must stay that way.
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,240 @@
|
|||||||
|
# Entwurf — die Farben pro Operateurprofil anpassbar machen
|
||||||
|
|
||||||
|
Vertieft: `docs/superpowers/specs/2026-09-25-compose-migration-design.md`, Etappe 8.
|
||||||
|
|
||||||
|
Dieser Entwurf ersetzt den dortigen Abschnitt. Er ist im September geschrieben worden, und
|
||||||
|
zwei seiner Annahmen stimmen nicht mehr.
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
|
||||||
|
Der Operateur bestimmt die Farben seines Clients, ohne Dateien im Installationsverzeichnis
|
||||||
|
anfassen zu müssen. Erfolg ist nachprüfbar:
|
||||||
|
|
||||||
|
- Eine geänderte Palette überlebt den Neustart.
|
||||||
|
- Sie gilt in **allen offenen Fenstern gleichzeitig**, nicht erst nach einem Fensterneubau.
|
||||||
|
- Sie ist **pro Profil** verschieden.
|
||||||
|
- Das Zurücksetzen stellt **exakt** die ausgelieferten Farben her — nicht etwas, das ihnen
|
||||||
|
gleicht.
|
||||||
|
|
||||||
|
## Was sich gegenüber dem Ursprungsabschnitt geändert hat
|
||||||
|
|
||||||
|
**Die Voraussetzung ist entfallen.** Er schreibt: „Ab Etappe 6 gibt es kein JavaFX mehr, das
|
||||||
|
dagegenhält — vorher muss beides dieselbe Datei lesen." Es gibt kein JavaFX mehr. Und der
|
||||||
|
`derive`-Pin, auf den er ausdrücklich wartet, ist seit Etappe 3 eine JavaFX-freie Umsetzung,
|
||||||
|
gegen eingecheckte Referenzwerte geprüft. Diese Etappe ist frei.
|
||||||
|
|
||||||
|
**Ein Befund kommt hinzu, den er nicht hatte.** `Kst4ContestTheme` liest die Palette als
|
||||||
|
`remember(darkMode)` (`Theme.kt:32`). Eine Palettenänderung erreicht die Fenster damit **gar
|
||||||
|
nicht**, bis jemand Tag/Abend umschaltet. Das Abnahmekriterium „gilt für alle Fenster
|
||||||
|
gleichzeitig" hängt also nicht an der Speicherung, sondern hier. Der Weg dafür existiert
|
||||||
|
bereits: `applyTheme` (`Kst4ContestApplication`) ruft `applyDarkMode` auf sechs Fenster-Wirten,
|
||||||
|
jeder hält einen `mutableStateOf` — nur trägt der heute bloß ein Boolean.
|
||||||
|
|
||||||
|
**Der Defektbefund bleibt richtig.** `copyResourceIfRequired` legt beim Start Kopien von
|
||||||
|
`KST4ContestDefaultDay.css` und `KST4ContestDefaultEvening.css` nach
|
||||||
|
`~/.kst4contest/` (`Kst4ContestApplication:2138`–`:2139`). Geprüft: **nichts liest sie.** Wer
|
||||||
|
seine Kopie bearbeitet, sieht keinerlei Wirkung.
|
||||||
|
|
||||||
|
## Die Quelle der Farben: drei Schichten
|
||||||
|
|
||||||
|
| | Schicht | Woher | Vorrang |
|
||||||
|
|---|---|---|---|
|
||||||
|
1 | **Auslieferung** | die Vorlage aus dem Klassenpfad | Boden, immer vorhanden |
|
||||||
|
2 | **Datei** | die CSS-Datei im Profilverzeichnis, falls vorhanden | überschreibt 1 |
|
||||||
|
3 | **Geändert** | die sechs Rollen aus den Einstellungen des Profils | überschreibt 1 und 2 |
|
||||||
|
|
||||||
|
**Die spätere Schicht gewinnt, Rolle für Rolle.** Eine Datei, die nur `-fx-base` nennt, ändert
|
||||||
|
nur diese Rolle; die übrigen kommen weiter aus der Auslieferung.
|
||||||
|
|
||||||
|
### Warum drei und nicht eine
|
||||||
|
|
||||||
|
Abgewogen wurden zwei Wege.
|
||||||
|
|
||||||
|
**Nur die CSS-Datei maßgeblich**, wie der Ursprungsabschnitt es wörtlich sagt, wurde
|
||||||
|
verworfen: eine Farbänderung müsste `-fx-base` in die 6,4-KB-Vorlage zurückschreiben, und das
|
||||||
|
braucht einen Serialisierer, der jede übrige Regel unverändert durchträgt. Ein Rundlauf, der
|
||||||
|
eine Regel verliert, zerstört das Aussehen still. `JavaFxStylesheet` ist ein Leser; ein
|
||||||
|
Schreiber daneben wäre die risikoreichste Stelle dieser Etappe, und die Anforderung — „ohne
|
||||||
|
Dateien anfassen zu müssen" — verlangt ihn nicht.
|
||||||
|
|
||||||
|
**Nur die Einstellungen** wäre das Einfachste und wurde bewusst nicht gewählt: es nimmt dem
|
||||||
|
Operateur den Handweg, den er heute zu haben *glaubt* (die Kopie liegt ja da), und der
|
||||||
|
Defektbefund würde gelöscht statt behoben.
|
||||||
|
|
||||||
|
**Gewählt: beide, mit ausdrücklichem Vorrang.** Der Preis ist benannt und wird im nächsten
|
||||||
|
Abschnitt bezahlt: bei zwei Quellen ist später nicht mehr ersichtlich, warum eine Farbe so
|
||||||
|
ist, wie sie ist.
|
||||||
|
|
||||||
|
### Was diesen Preis bezahlt
|
||||||
|
|
||||||
|
**Jede der sechs Rollen zeigt in der Oberfläche, woher ihr geltender Wert kommt** —
|
||||||
|
*Auslieferung*, *Datei* oder *geändert*. Die Auflösung weiß das ohnehin, es kostet nichts, und
|
||||||
|
ohne das ist die Frage „warum ist diese Farbe so?" unbeantwortbar. Das ist keine Zierde,
|
||||||
|
sondern die Bedingung, unter der die Dreischicht-Lösung vertretbar ist.
|
||||||
|
|
||||||
|
## Die sechs Rollen
|
||||||
|
|
||||||
|
Die, die `JavaFxPalette` benennt. Der Ursprungsabschnitt zählt fünf auf; es sind sechs,
|
||||||
|
weil `base` und `windowBackground` getrennt geführt werden — siehe unter der Tabelle.
|
||||||
|
|
||||||
|
| Rolle | im Palettenobjekt |
|
||||||
|
|---|---|
|
||||||
|
Fläche | `base` |
|
||||||
|
Fensterfläche | `windowBackground` |
|
||||||
|
Feldinneres | `controlInnerBackground` |
|
||||||
|
Text | `labelTextFill` |
|
||||||
|
Akzent | `accent` |
|
||||||
|
Trennlinie | `separatorLine` |
|
||||||
|
|
||||||
|
`base` und `windowBackground` sind getrennt, weil die Vorlagen sie getrennt führen und die
|
||||||
|
Fensterfläche aus der Fläche abgeleitet wird (`derive(base, 26.4%)`) — wer nur eine davon
|
||||||
|
setzen könnte, bekäme die andere ungefragt mitgezogen.
|
||||||
|
|
||||||
|
**Nicht anpassbar** bleiben `textAccent`, `buttonHoverGradient` und `buttonPressedBorder`. Sie
|
||||||
|
sind abgeleitete Werte, keine Rollen, die jemand einzeln wählen will; sie folgen dem Akzent.
|
||||||
|
`fontSizePx` ist eine bestehende Einstellung und wird hier nicht angefasst.
|
||||||
|
|
||||||
|
**Tag und Abend sind zwei Paletten.** Jede Rolle existiert zweimal, und eine Änderung am
|
||||||
|
Abendentwurf lässt den Tagentwurf unberührt.
|
||||||
|
|
||||||
|
## Die Wirkung ist sofort, und es gibt drei Wege zurück
|
||||||
|
|
||||||
|
**Eine Änderung gilt unmittelbar in allen offenen Fenstern.** Kein Musterfeld, kein
|
||||||
|
„noch nicht gespeichert"-Zustand.
|
||||||
|
|
||||||
|
Der Grund gegen ein Musterfeld ist die Geschichte dieses Projekts: die Fehlerklassen, die hier
|
||||||
|
wiederholt mit grünem Bau auslieferten, waren „sah einzeln richtig aus und war an seinem Platz
|
||||||
|
falsch". Ein zweihundert Pixel breites Muster ist genau diese Isolation. Es sagt nichts
|
||||||
|
darüber, wie die Stationsliste mit 22 Spalten in einer Palette liest. Das Einstellungsfenster
|
||||||
|
selbst ist die bessere Vorschau: es färbt sich mit und enthält Beschriftungen, Felder, Knöpfe
|
||||||
|
und Trennlinien — alles, was die sechs Rollen betrifft.
|
||||||
|
|
||||||
|
Weil es keinen Zwischenzustand gibt, sind die Rückwege keine Bequemlichkeit, sondern der
|
||||||
|
Ersatz dafür:
|
||||||
|
|
||||||
|
- **„Zurück zum Stand von vorher"** — beim Öffnen des Reiters wird die geltende Palette
|
||||||
|
gemerkt; dieser Knopf stellt sie wieder her. Das ist der Rückweg für den Normalfall: eine
|
||||||
|
Farbe im echten Fenster ausprobiert, gefällt nicht, weg damit.
|
||||||
|
- **„Meine Änderungen verwerfen"** — leert Schicht 3. Es gilt wieder Datei oder Auslieferung,
|
||||||
|
je nachdem, was da ist.
|
||||||
|
- **„Auf Auslieferung zurücksetzen"** — setzt alle Rollen auf die ausgelieferten Werte, als
|
||||||
|
ausdrückliche Änderung der Schicht 3. Damit spielt eine vorhandene Datei keine Rolle mehr.
|
||||||
|
**Das ist die Aktion, die das Abnahmekriterium erfüllt**, und sie erfüllt es auch dann, wenn
|
||||||
|
eine Datei im Spiel ist.
|
||||||
|
|
||||||
|
Mit einer Datei zwischen Auslieferung und Änderung kann **ein** Knopf nicht alle drei Fälle
|
||||||
|
abdecken: löscht er nur die Änderungen, gilt wieder die Datei und nicht die Auslieferung.
|
||||||
|
|
||||||
|
### „Auf Auslieferung zurücksetzen" wird immer in den ausgelieferten Farben gezeichnet
|
||||||
|
|
||||||
|
**Dieser eine Knopf nimmt die aktive Palette nicht an.** Er wird in den ausgelieferten Farben
|
||||||
|
gezeichnet, ganz gleich, was der Operateur eingestellt hat — Fläche, Text und Rahmen aus
|
||||||
|
Schicht 1, nicht aus der Auflösung.
|
||||||
|
|
||||||
|
Der Grund ist die Fehlerart, die sich sonst selbst einschließt: wer Text und Fläche auf
|
||||||
|
dasselbe Schwarz stellt, sieht die Knöpfe nicht mehr, mit denen er es zurücknehmen könnte. Ein
|
||||||
|
Tastaturweg allein hilft dann nur, wer ihn kennt. Ein Knopf, der die kaputte Palette nicht
|
||||||
|
annimmt, hilft immer.
|
||||||
|
|
||||||
|
Dass er dadurch bei einer stark angepassten Palette **fremd aussieht, ist beabsichtigt.** Er ist
|
||||||
|
eine Rettungsleine, keine Zierde; dass er sich nicht einfügt, macht ihn auffindbar.
|
||||||
|
|
||||||
|
Die anderen zwei Rückwege nehmen die aktive Palette an. Sie sind Bequemlichkeit für den
|
||||||
|
Normalfall; die Rettungsleine ist diese eine, und genau eine ist leichter zu merken als drei.
|
||||||
|
|
||||||
|
Ein Tastaturweg kommt zusätzlich, für alle drei. Er ist jetzt die zweite Absicherung, nicht
|
||||||
|
mehr die einzige.
|
||||||
|
|
||||||
|
## Die Datei im Profilverzeichnis
|
||||||
|
|
||||||
|
**Für das Wurzelprofil existiert sie schon:** `~/.kst4contest/KST4ContestDefaultDay.css` und
|
||||||
|
`…Evening.css`, von `copyResourceIfRequired` geschrieben. Sie wird jetzt **gelesen**. Das
|
||||||
|
behebt den dokumentierten Defekt, statt seine Spuren zu beseitigen, und gibt dem Operateur den
|
||||||
|
Handweg, den die Datei ihm die ganze Zeit versprochen hat.
|
||||||
|
|
||||||
|
**Für andere Profile wird nicht ungefragt kopiert.** Der Pfad folgt dem Muster, das
|
||||||
|
`OperatorProfilePaths` für Einstellungen und Datenbank schon benutzt: Wurzelprofil flach, sonst
|
||||||
|
`profiles/<id>/<datei>`. Eine Datei, die ungefragt entsteht und niemand braucht, ist dieselbe
|
||||||
|
Falle wie die bisherige ungelesene Kopie. Stattdessen schreibt ein Knopf im Reiter die Vorlage
|
||||||
|
ins Profilverzeichnis, wenn der Operateur von Hand bearbeiten will.
|
||||||
|
|
||||||
|
**Eine unlesbare oder fehlerhafte Datei darf den Start nicht verhindern.** Sie wird
|
||||||
|
übersprungen, die Rolle fällt auf die Auslieferung zurück, und der Reiter sagt es. Ein Client,
|
||||||
|
der wegen einer kaputten Farbdatei nicht startet, ist schlimmer als einer in den falschen
|
||||||
|
Farben.
|
||||||
|
|
||||||
|
## Dass es alle Fenster erreicht
|
||||||
|
|
||||||
|
Ein **`PaletteStore`** hält die Palette beider Entwürfe für das aktive Profil als
|
||||||
|
Compose-Zustand. `Kst4ContestTheme` liest daraus statt aus `remember(darkMode)`. Damit zeichnet
|
||||||
|
eine Änderung jedes offene Fenster neu — über denselben Weg, den der Tag/Abend-Wechsel schon
|
||||||
|
benutzt, und ohne dass `applyTheme` oder die sechs Fenster-Wirte etwas Neues lernen müssen.
|
||||||
|
|
||||||
|
Der Store wird beim Profilwechsel neu gebildet, wie jeder andere profilgebundene Zustand.
|
||||||
|
|
||||||
|
## Der Kontrastwächter
|
||||||
|
|
||||||
|
Eine frei gewählte Textfarbe auf einer frei gewählten Fläche kann unlesbar werden. Die
|
||||||
|
Oberfläche **sagt es, speichert aber trotzdem**: ein Funker, der im Contest bewusst eine harte
|
||||||
|
Kombination will, bekommt sie. Das Maß ist das WCAG-Kontrastverhältnis aus relativer
|
||||||
|
Leuchtdichte — eine reine Funktion, und damit der Teil, der falsch sein kann, ohne dass es
|
||||||
|
auffällt.
|
||||||
|
|
||||||
|
Geprüft werden die Paare, die tatsächlich übereinanderliegen: Text auf Fläche, Text auf
|
||||||
|
Feldinnerem, und Akzent auf Fläche.
|
||||||
|
|
||||||
|
## Prüfung
|
||||||
|
|
||||||
|
Das Wertvolle hier sind die Regeln, nicht die Oberfläche. Alle ohne Bildschirm prüfbar:
|
||||||
|
|
||||||
|
- **Die Dreischicht-Auflösung** samt Vorrang und Herkunftsangabe, einschließlich: Datei fehlt;
|
||||||
|
Datei nennt nur eine Rolle; Datei ist unlesbar; Änderung und Datei widersprechen sich.
|
||||||
|
- **Die drei Rückwege** — besonders, dass „auf Auslieferung" auch bei vorhandener Datei exakt
|
||||||
|
die ausgelieferten Werte ergibt, und dass „zum Stand von vorher" die Palette herstellt, die
|
||||||
|
beim Öffnen des Reiters galt, einschließlich einer damals schon vorhandenen Änderung.
|
||||||
|
- **Dass der Auslieferungs-Knopf die ausgelieferten Farben benutzt und nicht die aufgelöste
|
||||||
|
Palette** — geprüft mit einer Palette, in der jede Rolle auf etwas anderes gesetzt ist. Das
|
||||||
|
ist der Test, der die Rettungsleine davor bewahrt, still an der Palette zu hängen, die sie
|
||||||
|
retten soll.
|
||||||
|
- **Das Kontrastverhältnis**, gegen von Hand nachgerechnete Werte.
|
||||||
|
- **Dass Tag und Abend getrennt bleiben.**
|
||||||
|
- Dazu die Rückfalltests aus Etappe 7: Klasse 4 prüft, dass die Farben aus der Stilvorlage
|
||||||
|
kommen, und muss mit dieser Etappe weiter gelten.
|
||||||
|
|
||||||
|
## Was unverändert bleibt
|
||||||
|
|
||||||
|
- Die ausgelieferten Vorlagen selbst.
|
||||||
|
- `JavaFxStylesheet` als **Leser**. Kein CSS-Schreiber, nirgends.
|
||||||
|
- Der `derive`-Pin samt eingecheckter Referenztabelle und `JavaFxStylesheetTest`.
|
||||||
|
- Die Speicherung pro Profil über `ChatPreferences` — dieselbe wie jede andere Einstellung.
|
||||||
|
- `fontSizePx` und die bestehende Schriftgrößeneinstellung.
|
||||||
|
- Die Invarianten aus `AGENTS.md`.
|
||||||
|
|
||||||
|
## Risiken
|
||||||
|
|
||||||
|
**Die zweite Quelle ist der Preis dieser Etappe.** Zwei Schichten, die dasselbe bestimmen
|
||||||
|
können, sind eine Stelle, an der später niemand weiß, warum eine Farbe so ist. Die
|
||||||
|
Herkunftsangabe pro Rolle ist die einzige Gegenmaßnahme, und sie ist deshalb nicht optional.
|
||||||
|
|
||||||
|
**Eine Änderung, die alle Fenster erreicht, erreicht sie auch alle falsch.** Der `PaletteStore`
|
||||||
|
ist eine Stelle, an der ein Fehler sich überall gleichzeitig zeigt. Dafür zeigt er sich
|
||||||
|
wenigstens sofort und nicht erst nach einem Fensterneubau.
|
||||||
|
|
||||||
|
**Der Kontrastwächter warnt nur.** Ein Operateur kann sich einen unlesbaren Client bauen. Das
|
||||||
|
ist die Entscheidung, die hier bewusst bei ihm liegt, und der Ausweg ist der Knopf, der die
|
||||||
|
kaputte Palette nicht annimmt.
|
||||||
|
|
||||||
|
**Die Warnung des Wächters hat dieselbe Angreifbarkeit wie die Knöpfe** und ist nicht
|
||||||
|
ausgenommen: in einer unlesbaren Palette ist auch sie unlesbar. Sie auszunehmen wäre
|
||||||
|
folgerichtig, würde aber den Reiter mit zwei fremd aussehenden Flächen besetzen statt mit
|
||||||
|
einer. Ich lasse es bei der einen Rettungsleine und halte den Punkt hier fest, statt ihn
|
||||||
|
stillschweigend auszuweiten.
|
||||||
|
|
||||||
|
## Zwei Festlegungen, die sonst im Bau beliebig würden
|
||||||
|
|
||||||
|
**Die Wirkung ist sofort, der Rückweg gemerkt.** Kein Musterfeld — die Begründung steht unter
|
||||||
|
„Die Wirkung ist sofort". Beurteilt wird im echten Fenster, zurück geht es über eine beim
|
||||||
|
Öffnen des Reiters gemerkte Palette.
|
||||||
|
|
||||||
|
**Alle drei Rückwege bleiben.** Ohne Zwischenzustand sind sie der einzige Weg zurück, und alle
|
||||||
|
drei müssen ohne Farbwahrnehmung erreichbar sein — also auch über die Tastatur.
|
||||||
@@ -324,6 +324,95 @@ Die grüne Altersskala der Privatnachrichten bleibt in beiden Darstellungen erha
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Eigene Farben (ab v1.50)
|
||||||
|
|
||||||
|
Der Reiter **Colours** im Einstellungsfenster setzt sechs Farben pro Entwurf und **pro
|
||||||
|
Operator-Profil**: Fläche, Fensterfläche, Feldinneres, Text, Akzent und Trennlinie. Tag und
|
||||||
|
Abend sind getrennt — eine Änderung am Abendentwurf lässt den Tagentwurf unberührt.
|
||||||
|
|
||||||
|
Eine Farbe wird als sechsstellige Hexzahl mit führendem Rautezeichen eingetragen, etwa
|
||||||
|
`#3C7A4B`, und gilt **sofort in allen offenen Fenstern**. Es gibt keinen „noch nicht
|
||||||
|
gespeichert"-Zustand.
|
||||||
|
|
||||||
|
**Sie überlebt den Neustart aber erst nach „Save settings".** Das ist derselbe Vertrag wie bei
|
||||||
|
jeder anderen Einstellung — nur ist dies der einzige Reiter, dessen Wirkung man sofort in
|
||||||
|
allen Fenstern sieht, und „es sah richtig aus, also ist es gespeichert" ist hier der
|
||||||
|
naheliegende Fehlschluss. Der Reiter sagt es deshalb auch selbst.
|
||||||
|
|
||||||
|
Was nicht als Farbe lesbar ist, wird abgelehnt und das Feld springt zurück; ein Hinweisfenster
|
||||||
|
sagt, warum.
|
||||||
|
|
||||||
|
### Die drei Wege zurück
|
||||||
|
|
||||||
|
| Knopf | Wirkung |
|
||||||
|
|---|---|
|
||||||
|
| **Back to how it was** | die Palette, die beim Öffnen des Reiters galt — einschließlich einer damals schon vorhandenen Änderung |
|
||||||
|
| **Discard my changes** | leert die eigenen Änderungen dieses Entwurfs; es gilt wieder die Datei oder die Auslieferung |
|
||||||
|
| **Reset to the shipped colours** | setzt alle sechs Rollen auf die ausgelieferten Werte, auch wenn eine eigene Stilvorlage vorhanden ist |
|
||||||
|
|
||||||
|
**Der Knopf „Reset to the shipped colours" ist immer in den ausgelieferten Farben gezeichnet,
|
||||||
|
ganz gleich, was eingestellt ist.** Das ist Absicht: wer Text und Fläche auf dasselbe Schwarz
|
||||||
|
stellt, sieht die übrigen Knöpfe nicht mehr — auch die nicht, mit denen er es zurücknehmen
|
||||||
|
könnte. Dieser eine nimmt die kaputte Palette nicht an und bleibt deshalb lesbar. Dass er bei
|
||||||
|
einer stark angepassten Palette fremd aussieht, macht ihn auffindbar.
|
||||||
|
|
||||||
|
**Alle drei haben ein Tastenkürzel**, als zweite Absicherung für den Fall, dass gar nichts mehr
|
||||||
|
zu lesen ist. Sie wirken, solange der Reiter offen ist, auch wenn der Schreibzeiger in einem
|
||||||
|
der Farbfelder steht:
|
||||||
|
|
||||||
|
| Taste | Rückweg |
|
||||||
|
|---|---|
|
||||||
|
| **Ctrl+Z** | Zurück zum Stand von vorher |
|
||||||
|
| **Ctrl+D** | Meine Änderungen verwerfen |
|
||||||
|
| **Ctrl+R** | Auf Auslieferung zurücksetzen |
|
||||||
|
|
||||||
|
„Zurück zum Stand von vorher" stellt **beide** Entwürfe her, nicht nur den gerade
|
||||||
|
sichtbaren — wer eine Farbe am Tag ändert, auf Abend umschaltet und dort noch eine ändert,
|
||||||
|
nimmt mit diesem Knopf beides zurück.
|
||||||
|
|
||||||
|
### Woher eine Farbe kommt
|
||||||
|
|
||||||
|
Hinter jedem Feld steht, woher der geltende Wert stammt:
|
||||||
|
|
||||||
|
| Angabe | Bedeutung |
|
||||||
|
|---|---|
|
||||||
|
| *shipped* | aus dem ausgelieferten Entwurf |
|
||||||
|
| *from file* | aus der eigenen Stilvorlage im Profilverzeichnis |
|
||||||
|
| *changed* | hier im Reiter gesetzt |
|
||||||
|
|
||||||
|
Eine Einstellung im Reiter überstimmt immer die Datei, und die Datei überstimmt die
|
||||||
|
Auslieferung — Rolle für Rolle.
|
||||||
|
|
||||||
|
### Lesbarkeitshinweis
|
||||||
|
|
||||||
|
Liegt ein Paar, das tatsächlich übereinanderliegt — Text auf Fläche, Text im Feld, Akzent auf
|
||||||
|
Fläche — schlechter als im ausgelieferten Entwurf und unter dem WCAG-AA-Wert von 4,5, erscheint
|
||||||
|
ein Hinweis mit beiden Verhältnissen. **Gespeichert wird trotzdem:** eine harte Kombination im
|
||||||
|
Contest kann gewollt sein.
|
||||||
|
|
||||||
|
### Die Stilvorlage von Hand bearbeiten
|
||||||
|
|
||||||
|
Wer mehr als die sechs Rollen ändern will, lässt sich mit **Write this design's stylesheet into
|
||||||
|
my profile** die ausgelieferte Vorlage ins Profilverzeichnis schreiben. Der Reiter nennt den
|
||||||
|
Pfad. Für das Wurzelprofil ist das `~/.praktiKST/KST4ContestDefaultDay.css` beziehungsweise
|
||||||
|
`…Evening.css`, für jedes weitere Profil `profiles/<Kennung>/` darunter.
|
||||||
|
|
||||||
|
**Eine vorhandene Datei wird nie überschrieben** — der Knopf meldet dann nur, dass sie schon da
|
||||||
|
ist. Änderungen an der Datei gelten nach einem Neustart. Eine unlesbare oder fehlerhafte Datei
|
||||||
|
verhindert den Start nicht: die betroffene Rolle fällt auf die Auslieferung zurück.
|
||||||
|
|
||||||
|
**Beim Wurzelprofil liegen diese beiden Dateien schon.** KST4Contest legt sie seit Jahren beim
|
||||||
|
Start an; bis Version 1.50 hat sie nur niemand gelesen. Deshalb steht dort bei den meisten
|
||||||
|
Rollen von Anfang an *from file* und nicht *shipped*, und der Knopf meldet, dass die Datei
|
||||||
|
bereits da ist. Inhaltlich ist es die ausgelieferte Vorlage — es sieht also aus wie
|
||||||
|
*shipped*, weil es dasselbe ist.
|
||||||
|
|
||||||
|
Wer dort `-fx-base` ändert, bekommt auch die Fensterfläche mit: KST4Contest leitet sie daraus
|
||||||
|
ab, genau wie JavaFX es getan hat. Wer beide getrennt haben will, nennt `-fx-background`
|
||||||
|
ausdrücklich — oder setzt sie oben im Reiter, wo die beiden immer unabhängig bleiben.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Opposite Station Multi-Callsign Login-Tagging (ab v1.26)
|
## Opposite Station Multi-Callsign Login-Tagging (ab v1.26)
|
||||||
|
|
||||||
Unterstützung für Gegenstationen, die mit mehreren vollständigen sichtbaren Rufzeichenvarianten gleichzeitig im Chat aktiv sind (z. B. Expedition-Setups). Vollständiges Rufzeichen und Chat-Kategorie bleiben getrennte Teilnehmeridentitäten; Worked-, Band- und Prioritätsdaten werden über das Basisrufzeichen gemeinsam ausgewertet.
|
Unterstützung für Gegenstationen, die mit mehreren vollständigen sichtbaren Rufzeichenvarianten gleichzeitig im Chat aktiv sind (z. B. Expedition-Setups). Vollständiges Rufzeichen und Chat-Kategorie bleiben getrennte Teilnehmeridentitäten; Worked-, Band- und Prioritätsdaten werden über das Basisrufzeichen gemeinsam ausgewertet.
|
||||||
|
|||||||
@@ -323,6 +323,93 @@ The green private-message age scale remains available in both designs. Text colo
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Own Colours (from v1.50)
|
||||||
|
|
||||||
|
The **Colours** tab in the settings window sets six colours per design and **per operator
|
||||||
|
profile**: surface, window surface, field interior, text, accent and separator line. Daylight
|
||||||
|
and evening are separate — a change to the evening design leaves the daylight one untouched.
|
||||||
|
|
||||||
|
A colour is entered as six hexadecimal digits with a leading hash, for example `#3C7A4B`, and
|
||||||
|
applies **immediately in every open window**. There is no "not yet applied" state.
|
||||||
|
|
||||||
|
**It survives a restart only after Save settings.** That is the same contract as every other
|
||||||
|
setting — but this is the only tab whose effect is visible at once in every window, and "it
|
||||||
|
looked right, so it must be stored" is the easy wrong conclusion here. The tab says so itself
|
||||||
|
for that reason.
|
||||||
|
|
||||||
|
Anything that cannot be read as a colour is refused and the field snaps back; a notice window
|
||||||
|
says why.
|
||||||
|
|
||||||
|
### The three ways back
|
||||||
|
|
||||||
|
| Button | What it does |
|
||||||
|
|---|---|
|
||||||
|
| **Back to how it was** | the palette in force when the tab was opened, including a change already present then |
|
||||||
|
| **Discard my changes** | empties this design's own changes, so the file or the shipped design applies again |
|
||||||
|
| **Reset to the shipped colours** | sets all six roles to the shipped values, even when an own stylesheet is present |
|
||||||
|
|
||||||
|
**The "Reset to the shipped colours" button is always drawn in the shipped colours, whatever
|
||||||
|
has been set.** This is deliberate: an operator who sets text and surface to the same black can
|
||||||
|
no longer see any other button — including the ones that would undo it. This one does not take
|
||||||
|
the broken palette and therefore stays readable. That it looks out of place under a heavily
|
||||||
|
customised palette is what makes it findable.
|
||||||
|
|
||||||
|
**All three have a keyboard shortcut**, as a second safety net for when nothing can be read at
|
||||||
|
all. They work while the tab is open, including when the caret sits in one of the colour
|
||||||
|
fields:
|
||||||
|
|
||||||
|
| Key | Way back |
|
||||||
|
|---|---|
|
||||||
|
| **Ctrl+Z** | Back to how it was |
|
||||||
|
| **Ctrl+D** | Discard my changes |
|
||||||
|
| **Ctrl+R** | Reset to the shipped colours |
|
||||||
|
|
||||||
|
"Back to how it was" restores **both** designs, not only the one on screen — change a colour
|
||||||
|
in daylight, switch to evening, change one there, and this button undoes both.
|
||||||
|
|
||||||
|
### Where a colour comes from
|
||||||
|
|
||||||
|
Each field says where its value in force came from:
|
||||||
|
|
||||||
|
| Label | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| *shipped* | from the shipped design |
|
||||||
|
| *from file* | from the own stylesheet in the profile directory |
|
||||||
|
| *changed* | set here in the tab |
|
||||||
|
|
||||||
|
A setting in the tab always overrides the file, and the file overrides the shipped design —
|
||||||
|
role by role.
|
||||||
|
|
||||||
|
### Readability notice
|
||||||
|
|
||||||
|
When a pair that actually sits on top of each other — text on the surface, text inside a field,
|
||||||
|
accent on the surface — reads worse than the shipped design makes it and below the WCAG AA
|
||||||
|
value of 4.5, a notice appears with both ratios. **It is saved anyway:** a hard combination can
|
||||||
|
be deliberate in a contest.
|
||||||
|
|
||||||
|
### Editing the stylesheet by hand
|
||||||
|
|
||||||
|
To change more than the six roles, **Write this design's stylesheet into my profile** writes
|
||||||
|
the shipped template into the profile directory. The tab names the path. For the root profile
|
||||||
|
that is `~/.praktiKST/KST4ContestDefaultDay.css` or `…Evening.css`; every other profile gets it
|
||||||
|
under `profiles/<id>/`.
|
||||||
|
|
||||||
|
**An existing file is never overwritten** — the button then only reports that it is already
|
||||||
|
there. Changes to the file take effect after a restart. An unreadable or faulty file does not
|
||||||
|
prevent startup: the role concerned falls back to the shipped design.
|
||||||
|
|
||||||
|
**For the root profile these two files are already present.** KST4Contest has been writing
|
||||||
|
them at startup for years; until release 1.50 nothing read them. So most roles there show
|
||||||
|
*from file* rather than *shipped* from the outset, and the button reports that the file is
|
||||||
|
already there. Its content is the shipped template — so it looks like *shipped* because it is
|
||||||
|
the same thing.
|
||||||
|
|
||||||
|
Changing `-fx-base` there also changes the window surface: KST4Contest derives it from the
|
||||||
|
base, exactly as JavaFX did. To keep the two apart, name `-fx-background` explicitly — or set
|
||||||
|
them in the tab above, where the two roles always stay independent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Opposite Station Multi-Callsign Login Tagging (from v1.26)
|
## Opposite Station Multi-Callsign Login Tagging (from v1.26)
|
||||||
|
|
||||||
Support for remote stations which are active in the chat under several complete visible callsign variants at the same time (e.g. expedition setups). The complete callsign and chat category remain separate participant identities, while Worked, band and priority data are shared through the base callsign.
|
Support for remote stations which are active in the chat under several complete visible callsign variants at the same time (e.g. expedition setups). The complete callsign and chat category remain separate participant identities, while Worked, band and priority data are shared through the base callsign.
|
||||||
|
|||||||
Reference in new issue
Block a user