From 6e3f97487f3976ce09c4c377c0c10398400fe2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 16 Oct 2026 16:01:12 -0300 Subject: [PATCH] Settings: Add Large Text option for dialogues and signposts Add a "Large Text" toggle to the video settings. When on, dialogue balloons use Jersey 20 at 34 and signs use Jersey 15 at 27, the sizes where each font is crisp. If the player hasn't changed it, it defaults to on for small screens like phones, detected as touchscreens whose shortest side is under 600 dp. For the dialogue a new theme is added. For the signposts, 2 constants do the work. Resolve https://github.com/endlessm/threadbare/issues/3021 --- .../props/sign/components/sign.gd | 9 +++++ scenes/globals/settings/settings.gd | 33 +++++++++++++++++++ .../options/components/video_settings.tscn | 7 ++++ .../dialogue/components/balloon.gd | 6 ++++ .../dialogue/components/large_text_theme.tres | 7 ++++ 5 files changed, 62 insertions(+) create mode 100644 scenes/ui_elements/dialogue/components/large_text_theme.tres diff --git a/scenes/game_elements/props/sign/components/sign.gd b/scenes/game_elements/props/sign/components/sign.gd index 541fc68837..4ae15e38de 100644 --- a/scenes/game_elements/props/sign/components/sign.gd +++ b/scenes/game_elements/props/sign/components/sign.gd @@ -8,6 +8,11 @@ enum Frame { LEFT_AND_RIGHT = 1, } +## Font for the label when [member Settings.large_text] is on. It's +## Jersey 15 instead of Jersey 10, at the size where it's crisp. +const LARGE_TEXT_FONT := preload("uid://db8kp7xkv7gyn") +const LARGE_TEXT_FONT_SIZE := 27 + @export var direction: Enums.LookAtSide = Enums.LookAtSide.LEFT: set(a_direction): direction = a_direction @@ -28,6 +33,10 @@ func _ready() -> void: if Engine.is_editor_hint(): return + if Settings.large_text: + %Label.add_theme_font_override(&"font", LARGE_TEXT_FONT) + %Label.add_theme_font_size_override(&"font_size", LARGE_TEXT_FONT_SIZE) + update_label_visiblity() diff --git a/scenes/globals/settings/settings.gd b/scenes/globals/settings/settings.gd index ffdccd7227..2524069ee5 100644 --- a/scenes/globals/settings/settings.gd +++ b/scenes/globals/settings/settings.gd @@ -12,6 +12,7 @@ const VOLUME_SECTION := "Volume" const DISPLAY_SECTION := "Display" const SHOW_HUD_KEY := "Show HUD" +const LARGE_TEXT_KEY := "Large Text" const LANGUAGE_SECTION := "Language" const LOCALE_KEY := "Locale" @@ -23,6 +24,10 @@ const MINIMUM_ASPECT_RATIO := 1.25 ## An arbitrary wide ratio, lower than 21:9 ("ultrawide"). const MAXIMUM_ASPECT_RATIO := 2.2 +## Screens whose shortest side is under this are considered small, like phones. +## This is the threshold that Android uses to tell phones from tablets. +const SMALL_SCREEN_SHORTEST_SIDE_DP := 600.0 + @export var fullscreen: bool: get = is_fullscreen, set = set_fullscreen @@ -34,6 +39,15 @@ const MAXIMUM_ASPECT_RATIO := 2.2 _settings.set_value(DISPLAY_SECTION, SHOW_HUD_KEY, new_value) _save() +## Show the text of dialogues and signs with a bigger font. Unless the player +## changes it, this is on for small screens like phones, and off otherwise. +@export var large_text: bool: + get: + return _settings.get_value(DISPLAY_SECTION, LARGE_TEXT_KEY, is_small_screen()) + set(new_value): + _settings.set_value(DISPLAY_SECTION, LARGE_TEXT_KEY, new_value) + _save() + var _settings := ConfigFile.new() var _overrides_path: String @@ -124,6 +138,25 @@ func set_fullscreen(toggled_on: bool) -> void: set_window_mode(DisplayServer.WINDOW_MODE_WINDOWED) +## Return true on touchscreen devices with a small screen, like phones, and +## false on tablets and desktops. +func is_small_screen() -> bool: + if not DisplayServer.is_touchscreen_available(): + return false + var screen_size := Vector2(DisplayServer.screen_get_size()) + var shortest_side := minf(screen_size.x, screen_size.y) + var shortest_side_dp: float + if OS.has_feature("web"): + # On the web, the screen size divided by the scale is in CSS pixels, + # which are close to density-independent pixels. The DPI can't be used, + # because browsers derive it from the scale instead of the real screen. + shortest_side_dp = shortest_side / DisplayServer.screen_get_scale() + else: + # Density-independent pixels are 1/160 inch. + shortest_side_dp = shortest_side * 160.0 / DisplayServer.screen_get_dpi() + return shortest_side_dp < SMALL_SCREEN_SHORTEST_SIDE_DP + + func get_locale() -> String: return TranslationServer.get_locale() diff --git a/scenes/menus/options/components/video_settings.tscn b/scenes/menus/options/components/video_settings.tscn index 3cd33d176e..36b93548a1 100644 --- a/scenes/menus/options/components/video_settings.tscn +++ b/scenes/menus/options/components/video_settings.tscn @@ -51,6 +51,13 @@ text = "Fullscreen" script = ExtResource("2_qb52c") setting = &"fullscreen" +[node name="LargeTextButton" type="CheckButton" parent="VBoxContainer/GridContainer" unique_id=1394617293] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Large Text" +script = ExtResource("2_qb52c") +setting = &"large_text" + [node name="BackButton" type="Button" parent="VBoxContainer" unique_id=1300000002] unique_name_in_owner = true layout_mode = 2 diff --git a/scenes/ui_elements/dialogue/components/balloon.gd b/scenes/ui_elements/dialogue/components/balloon.gd index 7ccc107190..a37f101b95 100644 --- a/scenes/ui_elements/dialogue/components/balloon.gd +++ b/scenes/ui_elements/dialogue/components/balloon.gd @@ -7,6 +7,10 @@ extends CanvasLayer const PLAYER_RIBBON_TYPE_VARIATION := &"PlayerRibbon" const NPC_RIBBON_TYPE_VARIATION := &"NPCRibbon" +## Theme with a bigger font, used when [member Settings.large_text] is +## on. It uses Jersey 20 instead of Jersey 15, so it's still crisp. +const LARGE_TEXT_THEME := preload("uid://nymvlhys46nm") + ## The dialogue resource @export var dialogue_resource: DialogueResource @@ -101,6 +105,8 @@ var _player_name: String = Player.DEFAULT_PLAYER_NAME func _ready() -> void: if Engine.is_editor_hint(): return + if Settings.large_text: + balloon.theme = LARGE_TEXT_THEME balloon.hide() Engine.get_singleton("DialogueManager").mutated.connect(_on_mutated) diff --git a/scenes/ui_elements/dialogue/components/large_text_theme.tres b/scenes/ui_elements/dialogue/components/large_text_theme.tres new file mode 100644 index 0000000000..4d9c723c2c --- /dev/null +++ b/scenes/ui_elements/dialogue/components/large_text_theme.tres @@ -0,0 +1,7 @@ +[gd_resource type="Theme" format=3 uid="uid://nymvlhys46nm"] + +[ext_resource type="FontFile" uid="uid://c3bb7lmvdqc5e" path="res://assets/third_party/fonts/jersey/Jersey20-Regular.ttf" id="1_7a9qj"] + +[resource] +default_font = ExtResource("1_7a9qj") +default_font_size = 34