Files
code_of_conquest_dnd/client/scripts/theme/theme_keys.gd
Phillip Tarrant 63cbc8c16e fix(creation-screen): the white text, the badge on top of the roll, and a window too big for the laptop
The human's first F6 run found four defects headless GUT could not see, all
now fixed and break-proven.

1. Fifteen Labels shipped invisible. _fonts() sets a default font and size but
   never a default font_color for the base Label type, so a Label with no
   type-variation inherited Godot's built-in default — WHITE — and rendered
   white-on-parchment: the four race names, four race blurbs, and seven calling
   names, every unreadable string on the sheet. New CardTitle / CardBody roles
   (mock #3a2f1c / #6a5a3a) fix it. NOT a global default Label colour: the Title
   screen has 12 bare Labels on a dark background that rely on white.

2. The PRIMARY badge covered the rolled value. The ability card is a
   PanelContainer, and a Container force-fits its children, so the badge's
   authored anchors were dead letters — it stretched to the card's full width
   and centred over the value. Nesting it under a plain Control (not a
   Container) restores absolute positioning. The badges also carried _flat()'s
   12/6 card padding; a new tight pill stylebox matches the mock's 2px 9px.

3. Race cards overflowed their own border (108px card, 114px of content). Bumped
   to 140. The CHOSEN badge on the calling card moved from centre to the mock's
   top-right, and the ability card got its own AbilityCard variation with 16px
   top headroom for the badge (ParchmentCard is shared with the shell).

4. The default window (1600x900) was larger than a 1600x900 laptop's usable
   area, so the WM clamped it to 1589x752 and the run came up pillarboxed.
   Default is now 1280x720, resizable; the 1920x1080 design canvas is unchanged
   (canvas_items + keep scales it, so no layout number moved).

Also closes M4-b's two open copy items: the cutpurse origin fragment (it
contradicted its own blurb) and the Hint label (it omitted the roll's floor of
8, now pinned to NewGame.roll_attributes).

Guards for 1-4 are new and each was re-broken and watched go red. The overflow
guard in 3 was FIRST WRITTEN AS A TAUTOLOGY — Godot clamps Control.size up to
its combined minimum, so `min <= size` is `x <= x` — and passed against the bug,
29/29, until it was rewritten to measure against the card that clips. That is
traps.md #17 and the thirteenth cannot-fail assertion this branch has caught.

319 client tests green, content build green, theme drift guard satisfied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:56:09 -05:00

93 lines
4.0 KiB
GDScript

# client/scripts/theme/theme_keys.gd
class_name ThemeKeys
extends RefCounted
## Type-variation names for game_theme.tres. Scripts set `theme_type_variation`
## to one of these so a typo is a compile-time symbol error, not a silent miss.
## §2: presentation.
const PRIMARY_CTA := &"PrimaryCTA"
const TAB := &"Tab"
const TAB_ACTIVE := &"TabActive"
const CHIP := &"Chip"
const DOCK_BUTTON := &"DockButton"
const PARCHMENT_BUTTON := &"ParchmentButton"
const ITEM_TILE := &"ItemTile"
const ITEM_TILE_EMPTY := &"ItemTileEmpty"
const PARCHMENT_CARD := &"ParchmentCard"
const PARCHMENT_INSET := &"ParchmentInset"
const DARK_PANEL := &"DarkPanel"
const SELECT_CARD := &"SelectCard" # race/calling card: a Button whose `pressed` is CHOSEN
const SKILL_CHIP := &"SkillChip" # toggle: unpicked / picked / granted-so-inert
const CHOSEN_TAG := &"ChosenTag" # the little crimson "CHOSEN" flag
const PRIMARY_TAG := &"PrimaryTag" # the little gold "PRIMARY" flag
const PRIMARY_CARD := &"PrimaryCard" # the ability card ringed as the calling's primary
const ABILITY_CARD := &"AbilityCard" # ...and its UNringed state. Not ParchmentCard: the
# ability card carries a badge on its top edge and
# needs the headroom for it (mock padding-top 16 vs
# the generic card's 6), and ParchmentCard is shared
# with the shell.
## Font roles (Label type-variations carrying a font, not a stylebox). Kept
## separate from ALL below, which is stylebox variations + their base type only.
const HEADING := &"Heading"
const ACCENT := &"Accent"
const MONO := &"Mono"
const TITLE_LOGO := &"TitleLogo"
const TITLE_KICKER := &"TitleKicker"
const SECTION_LABEL := &"SectionLabel"
const CARD_TITLE := &"CardTitle" # a select-card's name, dark ink ON PARCHMENT
const CARD_BODY := &"CardBody" # a select-card's blurb, muted ink ON PARCHMENT
## Every FONT role + the base Control type it decorates. Deliberately NOT folded
## into ALL — ALL's "stylebox variations only" contract is relied on elsewhere
## (test_every_variation_resolves, and the styleboxes the screens set). Kept as a
## second enumerable set so a guard that means "every variation the builder
## touches" can iterate BOTH and never silently cover only half of them: the
## drift guard used to iterate ALL alone, so a font, a font size or a font colour
## could change in the builder and the committed .tres stay stale, suite green.
const FONT_ROLES := {
HEADING: "Label",
ACCENT: "Label",
MONO: "Label",
TITLE_LOGO: "Label",
TITLE_KICKER: "Label",
SECTION_LABEL: "Label",
CARD_TITLE: "Label",
CARD_BODY: "Label",
}
## Base Control types the builder styles DIRECTLY — no set_type_variation is
## ever called for these, so a fresh Theme reports get_type_variation_base("")
## for them. Kept as its own set (not folded into ALL or FONT_ROLES) because a
## base type is not a variation: nothing sets `theme_type_variation` to
## "RichTextLabel" anywhere, the node's own class name is the lookup key.
## Today: RichTextLabel, the builder's prose voice (mock README Typography:
## serif body/italic emphasis) — the creation screen's origin panel and
## calling detail panel are RichTextLabels rendering this styling directly,
## i.e. every line of DM prose the screen shows.
const BASE_TYPES := {
&"RichTextLabel": true,
}
## Every variation name + the base Control type it decorates. The builder and the
## test both iterate this so they can never drift apart.
const ALL := {
PRIMARY_CTA: "Button",
TAB: "Button",
TAB_ACTIVE: "Button",
CHIP: "Button",
DOCK_BUTTON: "Button",
PARCHMENT_BUTTON: "Button",
ITEM_TILE: "PanelContainer",
ITEM_TILE_EMPTY: "PanelContainer",
PARCHMENT_CARD: "PanelContainer",
PARCHMENT_INSET: "PanelContainer",
DARK_PANEL: "PanelContainer",
SELECT_CARD: "Button",
SKILL_CHIP: "Button",
CHOSEN_TAG: "Label",
PRIMARY_TAG: "Label",
PRIMARY_CARD: "PanelContainer",
ABILITY_CARD: "PanelContainer",
}