diff --git a/fxgl-core/src/main/kotlin/com/almasb/fxgl/core/UISettings.kt b/fxgl-core/src/main/kotlin/com/almasb/fxgl/core/UISettings.kt new file mode 100644 index 000000000..80c8a6175 --- /dev/null +++ b/fxgl-core/src/main/kotlin/com/almasb/fxgl/core/UISettings.kt @@ -0,0 +1,34 @@ +/* + * FXGL - JavaFX Game Library. The MIT License (MIT). + * Copyright (c) AlmasB (almaslvl@gmail.com). + * See LICENSE for details. + */ + +package com.almasb.fxgl.core + +import javafx.beans.property.DoubleProperty +import javafx.beans.property.SimpleDoubleProperty + +/** + * Cross-cutting runtime UI configuration accessible from any FXGL module. + * + * Lives in fxgl-core rather than on the FXGL facade because subsystems in + * fxgl-scene (and potentially other downstream modules) need to consume + * these properties at render time, and module direction prohibits an + * upward reference to the fxgl facade from fxgl-scene. + * + * The FXGL facade exposes thin @JvmStatic accessors that delegate here, + * so the public API stays unchanged. + * + * See issue #1224. + */ +object UISettings { + + /** + * Global UI font size multiplier. All dialog and notification text is + * scaled by this factor at render time. Default is 1.0 (no scaling). + * Can be modified at runtime; bound listeners will update rendered + * fonts on change. + */ + val uiFontSizeMultiplier: DoubleProperty = SimpleDoubleProperty(1.0) +} \ No newline at end of file diff --git a/fxgl-scene/src/main/kotlin/com/almasb/fxgl/notification/view/XboxNotificationView.kt b/fxgl-scene/src/main/kotlin/com/almasb/fxgl/notification/view/XboxNotificationView.kt index 7bd9fcfce..665690b96 100644 --- a/fxgl-scene/src/main/kotlin/com/almasb/fxgl/notification/view/XboxNotificationView.kt +++ b/fxgl-scene/src/main/kotlin/com/almasb/fxgl/notification/view/XboxNotificationView.kt @@ -8,6 +8,7 @@ package com.almasb.fxgl.notification.view import com.almasb.fxgl.animation.Animation import com.almasb.fxgl.animation.AnimationBuilder +import com.almasb.fxgl.core.UISettings import com.almasb.fxgl.notification.Notification import javafx.geometry.Point2D import javafx.scene.Group @@ -39,14 +40,20 @@ class XboxNotificationView : NotificationView() { * These two will be replacing one another. */ private val text1 = Text().also { - it.fill = textColor - it.font = Font.font(18.0) - } + it.fill = textColor + it.font = Font.font(18.0 * UISettings.uiFontSizeMultiplier.value) + UISettings.uiFontSizeMultiplier.addListener { _, _, newValue -> + it.font = Font.font(18.0 * newValue.toDouble()) + } + } private val text2 = Text().also { - it.fill = textColor - it.font = Font.font(18.0) - } + it.fill = textColor + it.font = Font.font(18.0 * UISettings.uiFontSizeMultiplier.value) + UISettings.uiFontSizeMultiplier.addListener { _, _, newValue -> + it.font = Font.font(18.0 * newValue.toDouble()) + } + } init { bg.arcWidth = 55.0 diff --git a/fxgl-scene/src/main/kotlin/com/almasb/fxgl/ui/FXGLDialogFactoryServiceProvider.kt b/fxgl-scene/src/main/kotlin/com/almasb/fxgl/ui/FXGLDialogFactoryServiceProvider.kt index 0306dd2f0..0cc085096 100644 --- a/fxgl-scene/src/main/kotlin/com/almasb/fxgl/ui/FXGLDialogFactoryServiceProvider.kt +++ b/fxgl-scene/src/main/kotlin/com/almasb/fxgl/ui/FXGLDialogFactoryServiceProvider.kt @@ -6,7 +6,7 @@ package com.almasb.fxgl.ui -import com.almasb.fxgl.core.Inject +import com.almasb.fxgl.core.UISettings import com.almasb.fxgl.core.util.EmptyRunnable import com.almasb.fxgl.localization.LocalizationService import com.almasb.fxgl.logging.Logger @@ -36,8 +36,35 @@ import java.util.function.Predicate */ class FXGLDialogFactoryServiceProvider : DialogFactoryService() { - @Inject("fontSizeScaleUI") - private var fontSizeScaleUI = 1.0 + /** + * Returns the current scaled font size based on the global multiplier. + * See issue #1224. + */ + private fun scaledSize(baseSize: Double): Double = + baseSize * UISettings.uiFontSizeMultiplier.value + + /** + * Creates a Text node whose font size scales with the global UI font size + * multiplier (issue #1224). The font is updated live when the multiplier changes. + */ + private fun scaledText(message: String, baseSize: Double): Text { + val text = uiFactory.newText(message, scaledSize(baseSize)) + UISettings.uiFontSizeMultiplier.addListener { _, _, _ -> + text.font = uiFactory.newFont(scaledSize(baseSize)) + } + return text + } + + /** + * Applies a scaled font to an existing node that uses setFont (Button, TextField). + * Re-applies on multiplier changes (issue #1224). + */ + private fun applyScaledFont(setFont: (javafx.scene.text.Font) -> Unit, baseSize: Double) { + setFont(uiFactory.newFont(scaledSize(baseSize))) + UISettings.uiFontSizeMultiplier.addListener { _, _, _ -> + setFont(uiFactory.newFont(scaledSize(baseSize))) + } + } private lateinit var uiFactory: UIFactoryService @@ -302,9 +329,9 @@ class FXGLDialogFactoryServiceProvider : DialogFactoryService() { } private fun createMessage(message: String): Text { - return uiFactory.newText(message, fontSizeScaleUI * 18.0) - } - + return scaledText(message, 18.0) + } + private fun localizedStringProperty(key: String): StringBinding { return local.localizedStringProperty(key) } diff --git a/fxgl/src/main/kotlin/com/almasb/fxgl/dsl/FXGL.kt b/fxgl/src/main/kotlin/com/almasb/fxgl/dsl/FXGL.kt index 28fd07100..06bed9d26 100644 --- a/fxgl/src/main/kotlin/com/almasb/fxgl/dsl/FXGL.kt +++ b/fxgl/src/main/kotlin/com/almasb/fxgl/dsl/FXGL.kt @@ -16,6 +16,7 @@ import com.almasb.fxgl.app.services.SystemBundleService import com.almasb.fxgl.audio.AudioPlayer import com.almasb.fxgl.audio.Music import com.almasb.fxgl.core.EngineService +import com.almasb.fxgl.core.UISettings import com.almasb.fxgl.core.collection.PropertyChangeListener import com.almasb.fxgl.core.concurrent.Async import com.almasb.fxgl.core.concurrent.Executor @@ -54,6 +55,8 @@ import com.almasb.fxgl.ui.DialogService import com.almasb.fxgl.ui.UIFactoryService import javafx.animation.Interpolator import javafx.application.Application +import javafx.beans.property.DoubleProperty +import javafx.beans.property.SimpleDoubleProperty import javafx.beans.binding.StringExpression import javafx.beans.property.* import javafx.concurrent.Task @@ -242,6 +245,28 @@ class FXGL private constructor() { companion object { @JvmStatic fun getTaskService() = engine.getService(IOTaskExecutorService::class.java) + + /** + * Global UI font size multiplier. All dialog and notification text is + * scaled by this factor at render time. Default is 1.0 (no scaling). Can + * be modified at runtime; bound listeners will update the rendered fonts + * on change. + * + * Backed by UISettings.uiFontSizeMultiplier in fxgl-core so downstream + * modules (e.g. fxgl-scene) can consume the property without an upward + * module dependency. + * + * See issue #1224. + */ + @JvmStatic fun uiFontSizeMultiplierProperty(): DoubleProperty = UISettings.uiFontSizeMultiplier + + @JvmStatic fun getUIFontSizeMultiplier(): Double = UISettings.uiFontSizeMultiplier.value + + @JvmStatic fun setUIFontSizeMultiplier(value: Double) { + require(value > 0) { "UI font size multiplier must be > 0, got: $value" } + UISettings.uiFontSizeMultiplier.value = value + } + /** * @return time per frame (in this frame) */