Give the Custom colour scheme a Panel Color for the panels and the title band, and have Button Color change the buttons alone, their orange choices included.

Button Color recoloured the list panel, the description box and the title band, and left the orange choices in the rows as they were, so the buttons themselves seemed not to change. It now takes the rows' label cells, their value cells and the orange choices, which come out a lighter shade of the picked colour; the new Panel Color takes the panels, the dividers and the title band. Text on a light button or panel turns dark, and so does the text in choices that come out bright. The colour is kept as custom_panel in launcher.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
epicmeme546
2026-11-11 03:11:09 -05:00
parent 4cc4663008
commit 3fe6965df9
7 changed files with 75 additions and 42 deletions

View File

@@ -17,7 +17,8 @@ DEFAULTS = {
'export_with_log': True, # Export Save adds the game's latest log and nx2navi.ini (for a bug report)
'theme': 'forest', # the colour scheme (launcher/ui/art.py THEMES)
'custom_background': '', # the Custom scheme's backdrop colour, #rrggbb; empty: the first scheme's
'custom_buttons': '', # the Custom scheme's colour of the buttons, panels and title band
'custom_panel': '', # the Custom scheme's colour of the panels and the title band
'custom_buttons': '', # the Custom scheme's colour of the buttons
'background': '', # the picture the player chose as the background; its fitted copy is data/background.npy
'background_dim': 40, # how much that picture is darkened, in percent
'animations': True, # the cursor glides, screens slide in, sparks drift, Navi bobs

View File

@@ -60,7 +60,9 @@ DEPTH = {'first_run': 0, 'home': 0, 'job': 1, 'saves': 1, 'settings': 1, 'custom
PICKER_BOX = (614, 100, 336, 452)
SQUARE = (667, 160, 897, 390)
BAR = (667, 408, 897, 430)
CUSTOM_LABELS = {'background': 'Background Color', 'buttons': 'Button Color'}
CUSTOM_LABELS = {'background': 'Background Color', 'panel': 'Panel Color', 'buttons': 'Button Color'}
CUSTOM_DESC = {'background': 'The color behind the menus.', 'panel': 'The color of the panels and the top bar.',
'buttons': 'The color of the buttons.'}
DIMS = (0, 20, 40, 60, 80) # Background Dimming, in percent
SOUND_LEVELS = (('off', 'Off'), ('low', 'Low'), ('medium', 'Medium'), ('high', 'High'))
@@ -980,13 +982,9 @@ class App:
desc=('The launcher\'s colours. Custom lets you pick your own.',)),
]
if art.theme == 'custom':
rows += [
Row('value', CUSTOM_LABELS['background'], art.CUSTOM['background'], 'swatch',
on=lambda: self.open_picker('background'), desc=('The color behind the menus.',)),
Row('value', CUSTOM_LABELS['buttons'], art.CUSTOM['buttons'], 'swatch',
on=lambda: self.open_picker('buttons'),
desc=('The color of the buttons, the panels and the top bar.',)),
]
rows += [Row('value', CUSTOM_LABELS[slot], art.CUSTOM[slot], 'swatch',
on=lambda sl=slot: self.open_picker(sl), desc=(CUSTOM_DESC[slot],))
for slot in art.CUSTOM_SLOTS]
rows += [
Row('value', 'Background', Path(self.settings['background']).name if custom else 'Choose a Picture',
'arrow', on=self.choose_background, desc=bg_desc),

View File

@@ -7,9 +7,9 @@ shape is a picture; flat rectangles and text stay canvas items.
Colours follow the game's options menu (docs/launcher.md, "Look"). Sizes are in logical pixels times the display
scale s. PALETTE holds the colours of the colour scheme in use: set_theme fills it from THEMES, each scheme the
first one with its woods, accents, backdrop and glow turned to other hues. The Custom scheme takes two colours the
player picks on a colour square (color_square, hue_bar): one for the backdrop, one for the buttons, panels and title
band.
first one with its woods, accents, backdrop and glow turned to other hues. The Custom scheme takes three colours the
player picks on a colour square (color_square, hue_bar): one for the backdrop, one for the panels and the title band,
one for the buttons.
"""
import base64
import colorsys
@@ -81,11 +81,21 @@ THEMES = {
}
DEFAULT_THEME = 'forest'
# The Custom scheme: each colour the player picks takes the place of one colour of the first scheme, and the rest of
# that colour's group follows it, lighter and darker as in the first scheme (follow). Its two colours start as the
# first scheme's.
CUSTOM_SLOTS = {'background': ('scene', 'tint_mid'), 'buttons': ('wood', 'label_mid')}
CUSTOM_DEFAULT = {slot: BASE[ref] for slot, (_, ref) in CUSTOM_SLOTS.items()}
# The Custom scheme: each colour the player picks takes the place of one colour of the first scheme (ref), and the
# rest of that colour's part of the window follows it, lighter and darker as in the first scheme (follow). Each part:
# (ref, the colours that follow it, the text on it, which turns dark when the picked colour is light). The buttons are
# the rows' label cells, their value cells and the orange choices in them; the panel is the list panel, the
# description box, the dividers and the title band. The colours start as the first scheme's.
CUSTOM_SLOTS = {
'background': ('tint_mid', GROUPS['scene'], ()),
'panel': ('panel', ('panel', 'desc', 'desc_border', 'line', 'dot', 'filigree', 'button_hover', 'wood_0', 'wood_1',
'wood_2', 'wood_3', 'band_line_dark', 'band_line_light', 'band_shadow', 'frame'),
('desc_text', 'muted', 'band_text', 'status', 'log_text')),
'buttons': ('label_mid', ('label_top', 'label_mid', 'label_bottom', 'label_border', 'ring', 'value', 'value_border',
'text_shadow') + GROUPS['accent'],
('text', 'text_bright', 'value_text', 'on_text', 'icon_frame', 'icon_fill', 'chevron_dim')),
}
CUSTOM_DEFAULT = {slot: BASE[ref] for slot, (ref, _, _) in CUSTOM_SLOTS.items()}
CUSTOM = dict(CUSTOM_DEFAULT)
HEX = re.compile(r'^#[0-9a-f]{6}$')
@@ -134,20 +144,22 @@ def luminance(hexcolor):
def custom_palette(colors):
"""The Custom scheme's colours from {slot: '#rrggbb'} (CUSTOM_SLOTS); a slot left out or not a colour keeps the
first scheme's. Light buttons get dark text, so the labels stay readable on them."""
first scheme's. Text on a light button or panel turns dark, so it stays readable, and its shadow light."""
pal = dict(BASE)
for slot, (group, ref) in CUSTOM_SLOTS.items():
for slot, (ref, keys, text) in CUSTOM_SLOTS.items():
c = str((colors or {}).get(slot) or '').lower()
if not HEX.match(c) or c == BASE[ref]: # the first scheme's own colour: its colours as written
continue
for k in GROUPS[group]:
for k in keys:
pal[k] = follow(BASE[k], BASE[ref], c)
if slot == 'buttons' and luminance(c) > 0.5:
if text and luminance(c) > 0.5:
h = hls(c)[0] * 360
for k in GROUPS['text']:
pal[k] = recolor(BASE[k], h, 0.5, 0.18)
pal['text_shadow'] = follow(BASE['label_top'], BASE[ref], c)
pal['chevron_dim'] = recolor(BASE['chevron_dim'], h, 0.5, 0.3)
for k in text:
pal[k] = recolor(BASE[k], h, 0.5, 0.3 if k == 'chevron_dim' else 0.18)
shadow = 'text_shadow' if slot == 'buttons' else 'band_shadow'
pal[shadow] = follow(BASE['label_top'], BASE[ref], c)
if slot == 'buttons' and luminance(pal['orange']) > 0.65: # the choices come out lighter than the cells
pal['on_text'] = recolor(BASE['on_text'], hls(c)[0] * 360, 0.5, 0.18)
return pal

View File

@@ -205,8 +205,8 @@ def states(app):
def custom_picker(): # the Custom scheme with two picked colours, and its picker on the button colour
from . import art
was = {k: s.get(k) for k in ('theme', 'custom_background', 'custom_buttons')}
s.update(theme='custom', custom_background='#3a1d5c', custom_buttons='#2f6fb0')
was = {k: s.get(k) for k in ('theme', 'custom_background', 'custom_panel', 'custom_buttons')}
s.update(theme='custom', custom_background='#3a1d5c', custom_panel='#24324a', custom_buttons='#2f6fb0')
app.apply_look()
app.open_picker('buttons')
s.update(was)