class_name InterfaceFontController extends Node const STANDARD_FONT: Font = preload("res://ui/fonts/Tuffy_Bold.otf") const COMPACT_FILE_DIALOG_LIMIT := Vector2i(800, 600) const COMPACT_FILE_DIALOG_MARGIN := Vector2i(12, 12) const COMPACT_FILE_DIALOG_FONT_SIZE: int = 17 var _game_theme: Theme = preload("res://ui/game_theme.tres") var _utility_theme: Theme var _compact_file_dialog_theme: Theme func _ready() -> void: enforce_standard_font() _utility_theme = _game_theme.duplicate(true) _utility_theme.default_font = STANDARD_FONT func enforce_standard_font() -> void: _game_theme.default_font = STANDARD_FONT if _utility_theme != null: _utility_theme.default_font = STANDARD_FONT func set_readable_font_enabled(_enabled: bool) -> void: # Compatibility seam for callers compiled against the old setting. enforce_standard_font() func is_readable_font_enabled() -> bool: return true func apply_utility_theme(themed_node: Node) -> void: if themed_node == null: return if _utility_theme == null: _utility_theme = _game_theme.duplicate(true) _utility_theme.default_font = STANDARD_FONT if themed_node is Control: (themed_node as Control).theme = _utility_theme elif themed_node is Window: (themed_node as Window).theme = _utility_theme func popup_file_dialog(dialog: FileDialog) -> void: if dialog == null or not dialog.is_inside_tree(): return var host_window: Window = dialog.get_parent().get_window() var host_size: Vector2i = host_window.size var compact: bool = ( host_size.x <= COMPACT_FILE_DIALOG_LIMIT.x or host_size.y <= COMPACT_FILE_DIALOG_LIMIT.y ) if not compact: apply_utility_theme(dialog) dialog.min_size = Vector2i(200, 70) dialog.max_size = Vector2i.ZERO dialog.popup_centered_ratio(0.75) return if _compact_file_dialog_theme == null: _compact_file_dialog_theme = _utility_theme.duplicate(true) _compact_file_dialog_theme.default_font_size = ( COMPACT_FILE_DIALOG_FONT_SIZE ) dialog.theme = _compact_file_dialog_theme var available_size := Vector2i( maxi(1, host_size.x - COMPACT_FILE_DIALOG_MARGIN.x * 2), maxi(1, host_size.y - COMPACT_FILE_DIALOG_MARGIN.y * 2), ) dialog.min_size = Vector2i.ZERO dialog.max_size = available_size dialog.popup_centered(available_size) # FileDialog's desktop-oriented intrinsic minimum can exceed a compact # 4:3 display. The compact font keeps its controls usable while this final # clamp guarantees the embedded window cannot escape the physical screen. dialog.size = available_size if dialog.get_viewport().gui_embed_subwindows: dialog.position = (host_size - available_size) / 2 _finalize_compact_file_dialog.call_deferred( dialog, host_size, available_size ) func _finalize_compact_file_dialog( dialog: FileDialog, host_size: Vector2i, requested_size: Vector2i, ) -> void: await get_tree().process_frame if dialog == null or not dialog.visible: return # Embedded windows report their content origin below the title bar. Account # for that inset after Godot has laid the window out so its bottom and right # edges retain the same safe margin as its decorated top and left edges. var safe_bottom_right: Vector2i = host_size - COMPACT_FILE_DIALOG_MARGIN var fitted_size: Vector2i = requested_size fitted_size.x -= maxi( 0, dialog.position.x + fitted_size.x - safe_bottom_right.x ) fitted_size.y -= maxi( 0, dialog.position.y + fitted_size.y - safe_bottom_right.y ) dialog.size = Vector2i(maxi(1, fitted_size.x), maxi(1, fitted_size.y)) func readable_font() -> Font: return STANDARD_FONT