Rework legal consent to match the provided design

Drop the bordered card - it wasn't the right direction. Instead:
- Plain small checkbox with just a blue border (no fill/icon when
  unchecked), matching the reference exactly.
- "Terms of Service"/"Privacy Policy" render as inline blue links
  within the sentence (RichTextLabel + BBCode [url], routed through
  the same _open_legal_document as the footer), instead of a duplicate
  link row underneath. meta_underlined = false to match the
  reference's plain (non-underlined) link style.

Verified with real rendered screenshots at each step, including a
pixel-level crop confirming the underline was actually gone.
This commit is contained in:
hz
2026-07-25 10:13:18 -05:00
parent 7e977e0d30
commit 5a2d825181
+43 -37
View File
@@ -26,6 +26,7 @@ var steam_view: VBoxContainer
var login_input: LineEdit
var password_input: LineEdit
var password_reveal_entries: Array[Dictionary] = []
var legal_consent_texts: Array[RichTextLabel] = []
var registration_username_input: LineEdit
var registration_email_input: LineEdit
var registration_password_input: LineEdit
@@ -345,38 +346,45 @@ func _build_steam_view() -> VBoxContainer:
func _add_legal_consent(parent: VBoxContainer) -> CheckBox:
# A bare CheckBox's own word-wrap left-aligns every wrapped line flush
# with the checkbox glyph, so a second line reads as un-indented and
# sloppy. Split the toggle from its label into a row instead - the
# label's own wrapping then stays confined to its column, and the whole
# thing sits in a card so it doesn't look like a stray unstyled control
# next to the app's otherwise fully themed form fields.
var card := PanelContainer.new()
card.set_meta("legal_consent_card", true)
parent.add_child(card)
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 16)
margin.add_theme_constant_override("margin_right", 16)
margin.add_theme_constant_override("margin_top", 12)
margin.add_theme_constant_override("margin_bottom", 12)
card.add_child(margin)
# with the checkbox glyph, so a second line reads as un-indented. Split
# the toggle from its text into a row instead - the RichTextLabel's own
# wrapping then stays confined to its column, and "Terms of Service"/
# "Privacy Policy" render as inline links rather than a duplicate row
# of link buttons underneath.
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 12)
margin.add_child(row)
parent.add_child(row)
var check := CheckBox.new()
check.custom_minimum_size = Vector2(26, 26)
check.add_theme_icon_override("unchecked", _blank_icon())
row.add_child(check)
var label := Label.new()
label.text = "I agree to the Terms of Service and acknowledge the Privacy Policy."
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
label.mouse_filter = Control.MOUSE_FILTER_STOP
label.gui_input.connect(func(event: InputEvent):
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
check.button_pressed = not check.button_pressed
)
row.add_child(label)
var consent_text := RichTextLabel.new()
consent_text.bbcode_enabled = true
consent_text.fit_content = true
consent_text.scroll_active = false
consent_text.meta_underlined = false
consent_text.size_flags_horizontal = Control.SIZE_EXPAND_FILL
consent_text.add_theme_font_override("normal_font", Brand.font)
consent_text.add_theme_font_size_override("normal_font_size", 15)
consent_text.meta_clicked.connect(func(meta: Variant): _open_legal_document(str(meta)))
legal_consent_texts.append(consent_text)
row.add_child(consent_text)
return check
func _blank_icon() -> ImageTexture:
return ImageTexture.create_from_image(Image.create(1, 1, false, Image.FORMAT_RGBA8))
func _refresh_legal_consent_text(consent_text: RichTextLabel, dark: bool) -> void:
var text_hex := Brand.text_color(dark).to_html(false)
var link_hex := (Brand.SKY_BLUE if dark else Brand.ROYAL_BLUE).to_html(false)
consent_text.text = (
"[color=#%s]I agree to the [/color][url=terms][color=#%s]Terms of Service[/color][/url][color=#%s] and acknowledge the [/color][url=privacy][color=#%s]Privacy Policy[/color][/url][color=#%s].[/color]"
% [text_hex, link_hex, text_hex, link_hex, text_hex]
)
func _add_legal_links(parent: HBoxContainer) -> void:
for spec in [["Terms of Service", "terms"], ["Privacy Policy", "privacy"]]:
var link := Button.new()
@@ -581,9 +589,16 @@ func _apply_theme() -> void:
label.add_theme_color_override("font_color", Brand.text_color(dark))
for input in fields:
_style_auth_field(input, dark)
for node in find_children("*", "PanelContainer", true, false):
if node.has_meta("legal_consent_card"):
(node as PanelContainer).add_theme_stylebox_override("panel", _legal_consent_box(dark))
for consent_text in legal_consent_texts:
_refresh_legal_consent_text(consent_text, dark)
var checkbox_box := StyleBoxFlat.new()
checkbox_box.bg_color = Color.TRANSPARENT
checkbox_box.border_color = Brand.SKY_BLUE if dark else Brand.ROYAL_BLUE
checkbox_box.set_border_width_all(2)
checkbox_box.set_corner_radius_all(6)
for cb in find_children("*", "CheckBox", true, false):
for state in ["normal", "hover", "pressed", "focus"]:
cb.add_theme_stylebox_override(state, checkbox_box)
for button in find_children("*", "Button", true, false):
var typed := button as Button
typed.add_theme_font_override("font", Brand.font)
@@ -613,15 +628,6 @@ func _apply_theme() -> void:
brand_tagline.add_theme_color_override("default_color", Brand.muted_color(dark))
func _legal_consent_box(dark: bool) -> StyleBoxFlat:
var box := StyleBoxFlat.new()
box.bg_color = Color("0d172a") if dark else Brand.LIGHT_SURFACE
box.border_color = Color("33415d") if dark else Brand.LIGHT_BORDER
box.set_border_width_all(1)
box.set_corner_radius_all(10)
return box
func _style_auth_field(input: LineEdit, dark: bool) -> void:
input.add_theme_color_override("font_color", Brand.text_color(dark))
input.add_theme_color_override("font_uneditable_color", Brand.text_color(dark))