diff --git a/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/Visualizer.kt b/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/Visualizer.kt index 413d4ee01..69bcded78 100644 --- a/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/Visualizer.kt +++ b/modules/config-impl/src/main/kotlin/org/polyfrost/oneconfig/api/config/v1/Visualizer.kt @@ -72,15 +72,19 @@ fun interface Visualizer { val options: Array = prop.getMetadata("options") ?: emptyArray() if (prop.type.isEnum) { require(options.isEmpty()) { "Dropdowns should not have options when used with enums (offender=${prop.id})" } - val index = prop.type.enumConstants.indexOf(prop.get()) + val constants = prop.type.enumConstants + val index = constants.indexOf(prop.get()) return Dropdown( optPadding = 24f, initial = index, - entries = prop.type.enumConstants.mapToArray { + entries = constants.mapToArray { it as Enum<*> null to (it::class.java.fields[0].get(it) as? String ?: it.name) }, - ) + ).onChange { i: Int -> + prop.setAs(constants[i]) + false + } } else { require(prop.type == Int::class.java) { "Dropdowns can only be used with enums or integers (offender=${prop.id}, type=${prop.type})" } require(options.size >= 2) { "Dropdowns must have at least two options (offender=${prop.id})" } @@ -88,7 +92,10 @@ fun interface Visualizer { optPadding = 24f, initial = prop.getAs(), entries = options.mapToArray { null to it }, - ) + ).onChange { i: Int -> + prop.setAs(i) + false + } } } } diff --git a/modules/events/src/main/java/org/polyfrost/oneconfig/api/event/v1/invoke/EventHandler.java b/modules/events/src/main/java/org/polyfrost/oneconfig/api/event/v1/invoke/EventHandler.java index cf84d789f..4e0d642c2 100644 --- a/modules/events/src/main/java/org/polyfrost/oneconfig/api/event/v1/invoke/EventHandler.java +++ b/modules/events/src/main/java/org/polyfrost/oneconfig/api/event/v1/invoke/EventHandler.java @@ -137,7 +137,7 @@ public final EventHandler register() { @ApiStatus.Internal public final boolean onError() { - return !(errors++ > ERROR_THRESHOLD); + return errors++ > ERROR_THRESHOLD; } @Override diff --git a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigUI.kt b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigUI.kt index c89b5b10b..d83a9d942 100644 --- a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigUI.kt +++ b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigUI.kt @@ -38,14 +38,15 @@ import org.polyfrost.oneconfig.internal.ui.pages.ModsPage import org.polyfrost.oneconfig.internal.ui.pages.ThemesPage import org.polyfrost.polyui.animate.Animations import org.polyfrost.polyui.color.rgba -import org.polyfrost.polyui.component.* +import org.polyfrost.polyui.component.Component +import org.polyfrost.polyui.component.Drawable import org.polyfrost.polyui.component.extensions.* import org.polyfrost.polyui.component.impl.* +import org.polyfrost.polyui.data.Cursor +import org.polyfrost.polyui.data.PolyImage import org.polyfrost.polyui.event.Event import org.polyfrost.polyui.operations.Move import org.polyfrost.polyui.operations.Recolor -import org.polyfrost.polyui.data.Cursor -import org.polyfrost.polyui.data.PolyImage import org.polyfrost.polyui.unit.Align import org.polyfrost.polyui.unit.Vec2 import org.polyfrost.polyui.unit.seconds @@ -59,149 +60,154 @@ object OneConfigUI { private val searchNoneFound = Text("oneconfig.search.nonefound", fontSize = 16f) private val search = Group(searchNoneFound, visibleSize = Vec2(1130f, 635f)) - lateinit var ui: Drawable + private lateinit var ui: Drawable + private var window: Any? = null @JvmOverloads fun open(initialScreen: Component = ModsPage(ConfigManager.active().trees())) { - val builder = OCPolyUIBuilder.create().blurs().atResolution(1920f, 1080f) - .backgroundColor(rgba(21, 21, 21)).size(1400f, 700f) as OCPolyUIBuilder - builder.translatorDelegate("assets/oneconfig") - builder.onClose { _ -> - for (t in ConfigManager.active().trees()) { - ConfigManager.active().save(t) + if (window == null) { + val builder = OCPolyUIBuilder.create().blurs().atResolution(1920f, 1080f) + .backgroundColor(rgba(21, 21, 21)).size(1400f, 700f) as OCPolyUIBuilder + builder.translatorDelegate("assets/oneconfig") + builder.onClose { _ -> + for (t in ConfigManager.active().trees()) { + ConfigManager.active().save(t) + } } - } - builder.makeAndOpen( - Group( - Block( - size = Vec2(225f, 32f), - ).ignoreLayout().afterParentInit { - val modsBtn = parent[3] - Move(this, modsBtn.x, modsBtn.y, false).add() - }, - Image("assets/oneconfig/brand/oneconfig.svg".image()).named("Logo"), - Text("oneconfig.sidebar.title.options", fontSize = 11f).setPalette { text.secondary }.padded(0f, 24f, 0f, 0f), - SidebarButton( - "assets/oneconfig/ico/settings.svg".image(), - "oneconfig.mods", - ).onClick { openPage(ModsPage(ConfigManager.active().trees()), "oneconfig.mods") }, - SidebarButton( - "assets/oneconfig/ico/profiles.svg".image(), - "oneconfig.profiles", - ).disable().addHoverInfo(Text("this feature is experimental and is coming soon!")), - SidebarButton("assets/oneconfig/ico/keyboard.svg".image(), "oneconfig.keybinds").disable(), - Text("oneconfig.sidebar.title.personal", fontSize = 11f).setPalette { text.secondary }.padded(0f, 12f, 0f, 0f), - SidebarButton("assets/oneconfig/ico/paintbrush.svg".image(), "oneconfig.themes", label("oneconfig.soon")).onClick { - openPage(ThemesPage(), "oneconfig.themes") - }.disable(), - SidebarButton("assets/oneconfig/ico/cog.svg".image(), "oneconfig.preferences"), - Text("oneconfig.sidebar.title.extra", fontSize = 11f).setPalette { text.secondary }.padded(0f, 12f, 0f, 0f), - SidebarButton("assets/oneconfig/ico/refresh.svg".image(), "oneconfig.changelog"), - SidebarButton( - "assets/oneconfig/ico/text.svg".image(), "oneconfig.feedback" - ).onClick { openPage(FeedbackPage(), "oneconfig.feedback") }, - SidebarButton0( - "assets/oneconfig/ico/hud.svg".image(), - "oneconfig.edithud", - label("oneconfig.beta") - ).onClick { - Platform.screen().display(HudManager.getWithEditor()) - }.padded(0f, 200f, 0f, 0f), - size = Vec2(273f, 700f), - alignment = Align(mode = Align.Mode.Vertical, pad = Vec2(6f, 8f)), - ).named("Sidebar"), - Group( + val (polyUI, win) = builder.makeAndOpenWithRef( + Group( + Block( + size = Vec2(225f, 32f), + ).ignoreLayout().afterParentInit { + val modsBtn = parent[3] + Move(this, modsBtn.x, modsBtn.y, false).add() + }, + Image("assets/oneconfig/brand/oneconfig.svg".image()).named("Logo"), + Text("oneconfig.sidebar.title.options", fontSize = 11f).setPalette { text.secondary }.padded(0f, 24f, 0f, 0f), + SidebarButton( + "assets/oneconfig/ico/settings.svg".image(), + "oneconfig.mods", + ).onClick { openPage(ModsPage(ConfigManager.active().trees()), "oneconfig.mods") }, + SidebarButton( + "assets/oneconfig/ico/profiles.svg".image(), + "oneconfig.profiles", + ).disable().addHoverInfo(Text("this feature is experimental and is coming soon!")), + SidebarButton("assets/oneconfig/ico/keyboard.svg".image(), "oneconfig.keybinds").disable(), + Text("oneconfig.sidebar.title.personal", fontSize = 11f).setPalette { text.secondary }.padded(0f, 12f, 0f, 0f), + SidebarButton("assets/oneconfig/ico/paintbrush.svg".image(), "oneconfig.themes", label("oneconfig.soon")).onClick { + openPage(ThemesPage(), "oneconfig.themes") + }.disable(), + SidebarButton("assets/oneconfig/ico/cog.svg".image(), "oneconfig.preferences"), + Text("oneconfig.sidebar.title.extra", fontSize = 11f).setPalette { text.secondary }.padded(0f, 12f, 0f, 0f), + SidebarButton("assets/oneconfig/ico/refresh.svg".image(), "oneconfig.changelog"), + SidebarButton( + "assets/oneconfig/ico/text.svg".image(), "oneconfig.feedback" + ).onClick { openPage(FeedbackPage(), "oneconfig.feedback") }, + SidebarButton0( + "assets/oneconfig/ico/hud.svg".image(), + "oneconfig.edithud", + label("oneconfig.beta") + ).onClick { + Platform.screen().display(HudManager.getWithEditor()) + }.padded(0f, 200f, 0f, 0f), + size = Vec2(273f, 700f), + alignment = Align(mode = Align.Mode.Vertical, pad = Vec2(6f, 8f)), + ).named("Sidebar"), Group( - Group( - Image("assets/oneconfig/ico/left-arrow.svg".image()).named("Back").disable(), - Image("assets/oneconfig/ico/right-arrow.svg".image()).named("Forward").disable(), - Text( - "oneconfig.mods", - fontSize = 24f, - ).setFont { medium }.named("Current"), - alignment = Align(pad = Vec2(16f, 8f)), - ).named("Controls"), Group( Group( - Image("assets/oneconfig/ico/cloud.svg".image()), - Image( - "assets/oneconfig/ico/bell.svg".image(), - ), - Image(playerHead).radius(6f).named("ProfileImage").withBoarder( - rgba(255, 255, 255, 0.14f), - width = 1f, - ).addHoverInfo(Text(Platform.player().playerName.ifEmpty { "Steve" })), + Image("assets/oneconfig/ico/left-arrow.svg".image()).named("Back").disable(), + Image("assets/oneconfig/ico/right-arrow.svg".image()).named("Forward").disable(), + Text( + "oneconfig.mods", + fontSize = 24f, + ).setFont { medium }.named("Current"), alignment = Align(pad = Vec2(16f, 8f)), + ).named("Controls"), + Group( + Group( + Image("assets/oneconfig/ico/cloud.svg".image()), + Image( + "assets/oneconfig/ico/bell.svg".image(), + ), + Image(playerHead).radius(6f).named("ProfileImage").withBoarder( + rgba(255, 255, 255, 0.14f), + width = 1f, + ).addHoverInfo(Text(Platform.player().playerName.ifEmpty { "Steve" })), + alignment = Align(pad = Vec2(16f, 8f)), + ), + Block( + Image("assets/oneconfig/ico/search.svg".image()), + TextInput( + placeholder = "oneconfig.search.placeholder", + visibleSize = Vec2(210f, 12f), + ).onChange { text: String -> + if (text.length > 2) { + search.children?.clear() + search.children?.addAll(ConfigVisualizer.INSTANCE.getMatching(text)) + if (search.children?.size == 0) search.children?.add(searchNoneFound) + if (ui[1][1] !== search) openPage(search, "oneconfig.search") + search.recalculate() + } else if (ui[1][1] === search) { + openPage(ModsPage(ConfigManager.active().trees()), "oneconfig.mods") + } + false + }, + size = Vec2(256f, 32f), + alignment = Align(pad = Vec2(10f, 8f)), + ).named("SearchField"), + Image( + "assets/oneconfig/ico/close.svg".image(), + ).named("Close").onClick { + }.withStates().setDestructivePalette(), + alignment = Align(pad = Vec2(24f, 8f)), ), - Block( - Image("assets/oneconfig/ico/search.svg".image()), - TextInput( - placeholder = "oneconfig.search.placeholder", - visibleSize = Vec2(210f, 12f), - ).onChange { text: String -> - if (text.length > 2) { - search.children?.clear() - search.children?.addAll(ConfigVisualizer.INSTANCE.getMatching(text)) - if (search.children?.size == 0) search.children?.add(searchNoneFound) - if (ui[1][1] !== search) openPage(search, "oneconfig.search") - search.recalculate() - } else if (ui[1][1] === search) { - openPage(ModsPage(ConfigManager.active().trees()), "oneconfig.mods") - } - false - }, - size = Vec2(256f, 32f), - alignment = Align(pad = Vec2(10f, 8f)), - ).named("SearchField"), - Image( - "assets/oneconfig/ico/close.svg".image(), - ).named("Close").onClick { - }.withStates().setDestructivePalette(), - alignment = Align(pad = Vec2(24f, 8f)), - ), - size = Vec2(1130f, 64f), - alignment = Align(main = Align.Main.SpaceBetween), - ).named("Header"), - initialScreen, - size = Vec2(1127f, 700f), - alignment = Align(cross = Align.Cross.Start, pad = Vec2.ZERO), - ), - ).also { - ui = it.master - searchNoneFound.setup(it) + size = Vec2(1130f, 64f), + alignment = Align(main = Align.Main.SpaceBetween), + ).named("Header"), + initialScreen, + size = Vec2(1127f, 700f), + alignment = Align(cross = Align.Cross.Start, pad = Vec2.ZERO), + ), + ) + ui = polyUI.master + window = win + searchNoneFound.setup(polyUI) (ui as Block).radius(8f) + } else { + Platform.screen().display(window) + if (ui[1][1] != initialScreen) { + openPage(initialScreen, "oneconfig.mods") + } } } - fun openPage(page: Drawable, name: String) { + fun openPage(page: Component, name: String) { val title = ui[1][0][0][2] as Text val translated = ui.polyUI.translator.translate(name) title.text = translated.string ui[1][1] = page } - fun label(text: String): Drawable { - return Block( - Text(text).setFont { bold }, - alignment = Align(main = Align.Main.Center), - size = Vec2(54f, 18f), - ).setPalette { brand.fg } - } + fun label(text: String) = Block( + Text(text).setFont { bold }, + alignment = Align(main = Align.Main.Center), + size = Vec2(54f, 18f), + ).setPalette { brand.fg } private val sidebarBtnAlign = Align(pad = Vec2(16f, 6f)) - fun SidebarButton(image: PolyImage, text: String, extra: Drawable? = null): Group { - return SidebarButton0(image, text, extra).onClick { _ -> + fun SidebarButton(image: PolyImage, text: String, extra: Drawable? = null) = + SidebarButton0(image, text, extra).onClick { _ -> val it = parent[0] Move(it, this.x, this.y, false, Animations.Default.create(0.15.seconds)).add() false } - } - fun SidebarButton0(image: PolyImage, text: String, extra: Drawable? = null): Group { - return Group( + fun SidebarButton0(image: PolyImage, text: String, extra: Drawable? = null) = + Group( Image(image), Text(text, fontSize = 14f), extra, @@ -227,5 +233,4 @@ object OneConfigUI { false } } - } } diff --git a/modules/ui/api/ui.api b/modules/ui/api/ui.api index b37e928ed..93fe0198a 100644 --- a/modules/ui/api/ui.api +++ b/modules/ui/api/ui.api @@ -1,21 +1,21 @@ -public final class org/polyfrost/oneconfig/api/ui/v1/NotificationsManager { - public static final field INSTANCE Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager; - public final fun enqueue (Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type;Ljava/lang/String;J)Lorg/polyfrost/polyui/component/impl/Block; - public final fun enqueue (Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type;Ljava/lang/String;Ljava/lang/String;J)Lorg/polyfrost/polyui/component/impl/Block; - public static synthetic fun enqueue$default (Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager;Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lorg/polyfrost/polyui/component/impl/Block; - public final fun enqueueCustom ([Lorg/polyfrost/polyui/component/Component;Lorg/polyfrost/polyui/animate/Animation;)Lorg/polyfrost/polyui/component/impl/Block; +public final class org/polyfrost/oneconfig/api/ui/v1/Notifications { + public static final field INSTANCE Lorg/polyfrost/oneconfig/api/ui/v1/Notifications; + public static final fun enqueue (Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type;Ljava/lang/String;J)Lorg/polyfrost/polyui/component/impl/Block; + public static final fun enqueue (Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type;Ljava/lang/String;Ljava/lang/String;J)Lorg/polyfrost/polyui/component/impl/Block; + public static synthetic fun enqueue$default (Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lorg/polyfrost/polyui/component/impl/Block; + public static final fun enqueueCustom ([Lorg/polyfrost/polyui/component/Component;Lorg/polyfrost/polyui/animate/Animation;)Lorg/polyfrost/polyui/component/impl/Block; } -public final class org/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type : java/lang/Enum { - public static final field Error Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type; - public static final field Info Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type; - public static final field Success Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type; - public static final field Warning Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type; +public final class org/polyfrost/oneconfig/api/ui/v1/Notifications$Type : java/lang/Enum { + public static final field Error Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type; + public static final field Info Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type; + public static final field Success Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type; + public static final field Warning Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type; public static fun getEntries ()Lkotlin/enums/EnumEntries; public final fun getIcon ()Ljava/lang/String; public final fun getTitle ()Ljava/lang/String; - public static fun valueOf (Ljava/lang/String;)Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type; - public static fun values ()[Lorg/polyfrost/oneconfig/api/ui/v1/NotificationsManager$Type; + public static fun valueOf (Ljava/lang/String;)Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type; + public static fun values ()[Lorg/polyfrost/oneconfig/api/ui/v1/Notifications$Type; } public final class org/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder : org/polyfrost/polyui/utils/PolyUIBuilder { @@ -25,6 +25,7 @@ public final class org/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder : org/polyf public static fun create ()Lorg/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder; public fun make ([Lorg/polyfrost/polyui/component/Drawable;)Lorg/polyfrost/polyui/PolyUI; public fun makeAndOpen ([Lorg/polyfrost/polyui/component/Drawable;)Lorg/polyfrost/polyui/PolyUI; + public fun makeAndOpenWithRef ([Lorg/polyfrost/polyui/component/Drawable;)Lkotlin/Pair; public fun onClose (Ljava/lang/Runnable;)Lorg/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder; public fun onClose (Ljava/util/function/Consumer;)Lorg/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder; public fun pauses ()Lorg/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder; @@ -92,7 +93,6 @@ public abstract interface class org/polyfrost/oneconfig/api/ui/v1/api/NanoVgApi public abstract fun strokeColor (J)V public abstract fun strokePaint (J)V public abstract fun strokeWidth (F)V - public abstract fun svgBounds (J)[F public abstract fun svgHandle ()J public abstract fun text (FFLjava/lang/String;)V public abstract fun textAlign (I)V diff --git a/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder.java b/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder.java index 9140b4568..f2c593f66 100644 --- a/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder.java +++ b/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/OCPolyUIBuilder.java @@ -27,6 +27,7 @@ package org.polyfrost.oneconfig.api.ui.v1; import org.polyfrost.oneconfig.api.platform.v1.Platform; +import org.polyfrost.oneconfig.api.platform.v1.ScreenPlatform; import org.polyfrost.polyui.PolyUI; import org.polyfrost.polyui.Settings; import org.polyfrost.polyui.component.Drawable; @@ -35,7 +36,7 @@ import java.util.function.Consumer; public final class OCPolyUIBuilder extends PolyUIBuilder { - private float desiredScreenWidth, desiredScreenHeight; + private float designedWidth, designedHeight; private Consumer onClose; private boolean pauses, blurs; @@ -56,9 +57,9 @@ public OCPolyUIBuilder onClose(Runnable onClose) { return this; } - public OCPolyUIBuilder atResolution(float desiredScreenWidth, float desiredScreenHeight) { - this.desiredScreenWidth = desiredScreenWidth; - this.desiredScreenHeight = desiredScreenHeight; + public OCPolyUIBuilder atResolution(float designedWidth, float designedHeight) { + this.designedWidth = designedWidth; + this.designedHeight = designedHeight; return this; } @@ -90,12 +91,25 @@ public PolyUI make(Drawable... drawables) { */ public PolyUI makeAndOpen(Drawable... drawables) { PolyUI p = make(drawables); - Object screen = UIManager.INSTANCE.createPolyUIScreen(p, desiredScreenWidth, desiredScreenHeight, pauses, blurs, onClose); + Object screen = UIManager.INSTANCE.createPolyUIScreen(p, designedWidth, designedHeight, pauses, blurs, onClose); p.setWindow(UIManager.INSTANCE.createWindow()); Platform.screen().display(screen); return p; } + /** + * create, and open a new PolyUI screen, backed by the returned instance. Additionally, a window is also created and assigned to the instance. + *
+ * Also returns a reference to the window object. use {@link Platform#screen()} and {@link ScreenPlatform#display(Object)} to display it. + */ + public kotlin.Pair makeAndOpenWithRef(Drawable... drawables) { + PolyUI p = make(drawables); + Object screen = UIManager.INSTANCE.createPolyUIScreen(p, designedWidth, designedHeight, pauses, blurs, onClose); + p.setWindow(UIManager.INSTANCE.createWindow()); + Platform.screen().display(screen); + return new kotlin.Pair<>(p, screen); + } + public static OCPolyUIBuilder create() { return new OCPolyUIBuilder(); } diff --git a/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/UIManager.java b/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/UIManager.java index 3ba80be71..b0bc3f64e 100644 --- a/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/UIManager.java +++ b/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/UIManager.java @@ -72,13 +72,13 @@ public interface UIManager { * Wrap this PolyUI instance in a Minecraft screen object, ready to be displayed to the user. {@link org.polyfrost.oneconfig.api.platform.v1.ScreenPlatform#display(Object) Platform.screen().display(this)} * * @param polyUI the PolyUI instance to use - * @param desiredScreenWidth the resolution that this PolyUI instance was designed to use + * @param designedWidth the resolution that this PolyUI instance was designed to use * @param pauses weather to pause the game when the screen is opened * @param blurs if true blur will be used on the background * @param onClose callback to run when the screen is closed * @return a Minecraft screen object. Will be a GuiScreen or Screen depending on the Minecraft version. */ - Object createPolyUIScreen(@NotNull PolyUI polyUI, float desiredScreenWidth, float desiredScreenHeight, boolean pauses, boolean blurs, @Nullable Consumer onClose); + Object createPolyUIScreen(@NotNull PolyUI polyUI, float designedWidth, float designedHeight, boolean pauses, boolean blurs, @Nullable Consumer onClose); /** * return a PolyUI instance that is mounted to the entire screen. It is used internally for displaying and managing HUD components and notifications. diff --git a/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/api/NanoVgApi.java b/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/api/NanoVgApi.java index c6f44bb11..aebead54a 100644 --- a/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/api/NanoVgApi.java +++ b/modules/ui/src/main/java/org/polyfrost/oneconfig/api/ui/v1/api/NanoVgApi.java @@ -1,7 +1,5 @@ package org.polyfrost.oneconfig.api.ui.v1.api; -import kotlin.Triple; - import java.nio.ByteBuffer; public interface NanoVgApi { @@ -23,15 +21,15 @@ interface Constants { Constants constants(); long handle(); + long svgHandle(); /** * If this instance is not set up already, it will set up the instance (initializes it's NVG and NSVG context). * * @throws IllegalStateException if the instance failed to set up. - * - * @since 0.2.0 * @author Deftu + * @since 0.2.0 */ void maybeSetup(); @@ -135,8 +133,6 @@ interface Constants { void deleteImage(int address); - float[] svgBounds(long address); - SVG parseSvg(ByteBuffer data); void deleteSvg(long address); diff --git a/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/NotificationsManager.kt b/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/Notifications.kt similarity index 99% rename from modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/NotificationsManager.kt rename to modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/Notifications.kt index 94683275b..8442e284c 100644 --- a/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/NotificationsManager.kt +++ b/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/Notifications.kt @@ -42,7 +42,7 @@ import org.polyfrost.polyui.unit.seconds import org.polyfrost.polyui.utils.image -object NotificationsManager { +object Notifications { private const val PADDING = 8f private const val MAX = 5 private val polyUI = UIManager.INSTANCE.defaultInstance @@ -51,6 +51,7 @@ object NotificationsManager { private var lastY = 0f private var i = 0 + @JvmStatic fun enqueueCustom(vararg components: Component, progressFunc: Animation): Block { val out = Block(children = components, at = Vec2(polyUI.size.x + PADDING, 0f)).withBoarder().withStates() var failedToFinishNormally = false @@ -87,6 +88,7 @@ object NotificationsManager { } @JvmOverloads + @JvmStatic fun enqueue(type: Type, title: String = type.title, description: String, durationNanos: Long) = enqueueCustom( Block( Image("polyui/chevron-down.svg".image(), size = Vec2(32f, 32f)), diff --git a/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/NanoVgImpl.kt b/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/NanoVgImpl.kt index 3d4f310ff..5405a8492 100644 --- a/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/NanoVgImpl.kt +++ b/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/NanoVgImpl.kt @@ -3,11 +3,10 @@ package org.polyfrost.oneconfig.api.ui.v1.internal import org.lwjgl.nanovg.NSVGImage import org.lwjgl.nanovg.NVGColor import org.lwjgl.nanovg.NVGPaint -import org.lwjgl.nanovg.NanoSVG -import org.lwjgl.nanovg.NanoVG +import org.lwjgl.nanovg.NanoSVG.* +import org.lwjgl.nanovg.NanoVG.* import org.lwjgl.nanovg.NanoVGGL2 import org.lwjgl.nanovg.NanoVGGL3 -import org.lwjgl.system.MemoryUtil import org.polyfrost.oneconfig.api.ui.v1.api.NanoVgApi import java.nio.ByteBuffer @@ -18,30 +17,29 @@ class NanoVgImpl( private val isOpenGl3: JBoolean ) : NanoVgApi { - private companion object { // ByteBuffer.of("px\u0000") - private val PIXELS: ByteBuffer = MemoryUtil.memAlloc(3).put(112).put(120).put(0).flip() as ByteBuffer + private val PIXELS = ByteBuffer.allocateDirect(3).put(112).put(120).put(0).flip() as ByteBuffer } object ConstantsImpl : NanoVgApi.Constants { - override fun NVG_ROUND() = NanoVG.NVG_ROUND + override fun NVG_ROUND() = NVG_ROUND - override fun NVG_ALIGN_LEFT() = NanoVG.NVG_ALIGN_LEFT + override fun NVG_ALIGN_LEFT() = NVG_ALIGN_LEFT - override fun NVG_ALIGN_TOP() = NanoVG.NVG_ALIGN_TOP + override fun NVG_ALIGN_TOP() = NVG_ALIGN_TOP - override fun NVG_HOLE() = NanoVG.NVG_HOLE + override fun NVG_HOLE() = NVG_HOLE - override fun NVG_IMAGE_FLIPY() = NanoVG.NVG_IMAGE_FLIPY + override fun NVG_IMAGE_FLIPY() = NVG_IMAGE_FLIPY } - private var handle: Long = -1 - private var svgHandle: Long = -1 + private var handle: Long = -1L + private var svgHandle: Long = -1L override fun constants() = ConstantsImpl @@ -56,7 +54,7 @@ class NanoVgImpl( false -> NanoVGGL2.nvgCreate(NanoVGGL2.NVG_ANTIALIAS) } - if (handle == MemoryUtil.NULL) { + if (handle == 0L /* NULL */) { throw IllegalStateException("Failed to create NanoVG context") } @@ -65,8 +63,8 @@ class NanoVgImpl( } if (svgHandle == -1L) { - val svgHandle = NanoSVG.nsvgCreateRasterizer() - if (svgHandle == MemoryUtil.NULL) { + val svgHandle = nsvgCreateRasterizer() + if (svgHandle == 0L /* NULL */) { throw IllegalStateException("Failed to create NanoSVG context") } @@ -76,49 +74,49 @@ class NanoVgImpl( } override fun beginFrame(width: Float, height: Float, scale: Float) { - NanoVG.nvgBeginFrame(handle, width, height, scale) + nvgBeginFrame(handle, width, height, scale) } override fun endFrame() { - NanoVG.nvgEndFrame(handle) + nvgEndFrame(handle) } override fun globalAlpha(alpha: Float) { - NanoVG.nvgGlobalAlpha(handle, alpha) + nvgGlobalAlpha(handle, alpha) } override fun translate(x: Float, y: Float) { - NanoVG.nvgTranslate(handle, x, y) + nvgTranslate(handle, x, y) } override fun scale(x: Float, y: Float) { - NanoVG.nvgScale(handle, x, y) + nvgScale(handle, x, y) } override fun rotate(angle: Float) { - NanoVG.nvgRotate(handle, angle) + nvgRotate(handle, angle) } override fun skewX(angle: Float) { - NanoVG.nvgSkewX(handle, angle) + nvgSkewX(handle, angle) } override fun skewY(angle: Float) { - NanoVG.nvgSkewY(handle, angle) + nvgSkewY(handle, angle) } override fun save() { - NanoVG.nvgSave(handle) + nvgSave(handle) } override fun restore() { - NanoVG.nvgRestore(handle) + nvgRestore(handle) } override fun createPaint() = NVGPaint.malloc().address() override fun fillPaint(address: Long) { - NanoVG.nvgFillPaint(handle, NVGPaint.create(address)) + nvgFillPaint(handle, NVGPaint.create(address)) } override fun getPaintColor(address: Long) = NVGPaint.create(address).innerColor().address() @@ -126,11 +124,11 @@ class NanoVgImpl( override fun createColor() = NVGColor.malloc().address() override fun fillColor(address: Long) { - NanoVG.nvgFillColor(handle, NVGColor.create(address)) + nvgFillColor(handle, NVGColor.create(address)) } override fun rgba(address: Long, rgba: Int) { - NanoVG.nvgRGBA( + nvgRGBA( (rgba shr 16 and 0xFF).toByte(), (rgba shr 8 and 0xFF).toByte(), (rgba and 0xFF).toByte(), @@ -140,19 +138,19 @@ class NanoVgImpl( } override fun beginPath() { - NanoVG.nvgBeginPath(handle) + nvgBeginPath(handle) } override fun pathWinding(winding: Int) { - NanoVG.nvgPathWinding(handle, winding) + nvgPathWinding(handle, winding) } override fun fill() { - NanoVG.nvgFill(handle) + nvgFill(handle) } override fun roundedRect(x: Float, y: Float, w: Float, h: Float, r: Float) { - NanoVG.nvgRoundedRect(handle, x, y, w, h, r) + nvgRoundedRect(handle, x, y, w, h, r) } override fun roundedRectVarying( @@ -165,79 +163,79 @@ class NanoVgImpl( br: Float, bl: Float ) { - NanoVG.nvgRoundedRectVarying(handle, x, y, w, h, tl, tr, br, bl) + nvgRoundedRectVarying(handle, x, y, w, h, tl, tr, br, bl) } override fun lineJoin(join: Int) { - NanoVG.nvgLineJoin(handle, join) + nvgLineJoin(handle, join) } override fun lineCap(cap: Int) { - NanoVG.nvgLineCap(handle, cap) + nvgLineCap(handle, cap) } override fun stroke() { - NanoVG.nvgStroke(handle) + nvgStroke(handle) } override fun strokeWidth(width: Float) { - NanoVG.nvgStrokeWidth(handle, width) + nvgStrokeWidth(handle, width) } override fun strokePaint(address: Long) { - NanoVG.nvgStrokePaint(handle, NVGPaint.create(address)) + nvgStrokePaint(handle, NVGPaint.create(address)) } override fun strokeColor(address: Long) { - NanoVG.nvgStrokeColor(handle, NVGColor.create(address)) + nvgStrokeColor(handle, NVGColor.create(address)) } override fun moveTo(x: Float, y: Float) { - NanoVG.nvgMoveTo(handle, x, y) + nvgMoveTo(handle, x, y) } override fun lineTo(x: Float, y: Float) { - NanoVG.nvgLineTo(handle, x, y) + nvgLineTo(handle, x, y) } override fun createFont(name: String, buffer: ByteBuffer): Int { - return NanoVG.nvgCreateFontMem(handle, name, buffer, false) + return nvgCreateFontMem(handle, name, buffer, false) } override fun fontSize(size: Float) { - NanoVG.nvgFontSize(handle, size) + nvgFontSize(handle, size) } override fun fontFaceId(id: Int) { - NanoVG.nvgFontFaceId(handle, id) + nvgFontFaceId(handle, id) } override fun textAlign(align: Int) { - NanoVG.nvgTextAlign(handle, align) + nvgTextAlign(handle, align) } override fun text(x: Float, y: Float, text: String) { - NanoVG.nvgText(handle, x, y, text) + nvgText(handle, x, y, text) } override fun textBounds(x: Float, y: Float, text: String, bounds: FloatArray): Float { - return NanoVG.nvgTextBounds(handle, x, y, text, bounds) + return nvgTextBounds(handle, x, y, text, bounds) } override fun createImage(width: Float, height: Float, buffer: ByteBuffer, flags: Int): Int { - return NanoVG.nvgCreateImageRGBA(handle, width.toInt(), height.toInt(), flags, buffer) + return nvgCreateImageRGBA(handle, width.toInt(), height.toInt(), flags, buffer) } override fun scissor(x: Float, y: Float, w: Float, h: Float) { - NanoVG.nvgScissor(handle, x, y, w, h) + nvgScissor(handle, x, y, w, h) } override fun intersectScissor(x: Float, y: Float, w: Float, h: Float) { - NanoVG.nvgIntersectScissor(handle, x, y, w, h) + nvgIntersectScissor(handle, x, y, w, h) } override fun resetScissor() { - NanoVG.nvgResetScissor(handle) + nvgResetScissor(handle) } override fun imagePattern( @@ -250,15 +248,15 @@ class NanoVgImpl( alpha: Float, address: Long ) { - NanoVG.nvgImagePattern(handle, x, y, w, h, angle, image, alpha, NVGPaint.create(address)) + nvgImagePattern(handle, x, y, w, h, angle, image, alpha, NVGPaint.create(address)) } override fun linearGradient(address: Long, x0: Float, y0: Float, x1: Float, y1: Float, startColor: Long, endColor: Long) { - NanoVG.nvgLinearGradient(handle, x0, y0, x1, y1, NVGColor.create(startColor), NVGColor.create(endColor), NVGPaint.create(address)) + nvgLinearGradient(handle, x0, y0, x1, y1, NVGColor.create(startColor), NVGColor.create(endColor), NVGPaint.create(address)) } override fun radialGradient(address: Long, cx: Float, cy: Float, inr: Float, outr: Float, startColor: Long, endColor: Long) { - NanoVG.nvgRadialGradient(handle, cx, cy, inr, outr, NVGColor.create(startColor), NVGColor.create(endColor), NVGPaint.create(address)) + nvgRadialGradient(handle, cx, cy, inr, outr, NVGColor.create(startColor), NVGColor.create(endColor), NVGPaint.create(address)) } override fun boxGradient( @@ -272,25 +270,20 @@ class NanoVgImpl( startColor: Long, endColor: Long ) { - NanoVG.nvgBoxGradient(handle, x, y, w, h, r, f, NVGColor.create(startColor), NVGColor.create(endColor), NVGPaint.create(address)) + nvgBoxGradient(handle, x, y, w, h, r, f, NVGColor.create(startColor), NVGColor.create(endColor), NVGPaint.create(address)) } override fun deleteImage(address: Int) { - NanoVG.nvgDeleteImage(handle, address) - } - - override fun svgBounds(address: Long): FloatArray { - val svg = NSVGImage.create(address) - return floatArrayOf(svg.width(), svg.height()) + nvgDeleteImage(handle, address) } override fun parseSvg(data: ByteBuffer): NanoVgApi.SVG { - val result = NanoSVG.nsvgParse(data, PIXELS, 96f) ?: throw IllegalStateException("Failed to parse SVG data") + val result = nsvgParse(data, PIXELS, 96f) ?: throw IllegalStateException("Failed to parse SVG data") return NanoVgApi.SVG(result.address(), result.width(), result.height()) } override fun deleteSvg(address: Long) { - NanoSVG.nsvgDelete(NSVGImage.create(address)) + nsvgDelete(NSVGImage.create(address)) } override fun rasterizeSvg( @@ -303,7 +296,7 @@ class NanoVgImpl( h: Int, stride: Int ) { - NanoSVG.nsvgRasterize(svgHandle, NSVGImage.create(address), x, y, scale, data, w, h, stride) + nsvgRasterize(svgHandle, NSVGImage.create(address), x, y, scale, data, w, h, stride) } } diff --git a/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/RendererImpl.kt b/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/RendererImpl.kt index c903dd5e4..ac25e7a3a 100644 --- a/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/RendererImpl.kt +++ b/modules/ui/src/main/kotlin/org/polyfrost/oneconfig/api/ui/v1/internal/RendererImpl.kt @@ -46,7 +46,7 @@ import org.polyfrost.polyui.color.PolyColor as Color class RendererImpl( private val isGl3: Boolean, private val lwjgl: LwjglApi, - private val nanoVg: NanoVgApi, + private val vg: NanoVgApi, private val stb: StbApi ) : Renderer { @@ -68,7 +68,7 @@ class RendererImpl( private var paintAddress = -1L get() { if (field == -1L) { - field = nanoVg.createPaint() + field = vg.createPaint() } return field @@ -77,7 +77,7 @@ class RendererImpl( private var color1Address = -1L get() { if (field == -1L) { - field = nanoVg.createColor() + field = vg.createColor() } return field @@ -86,7 +86,7 @@ class RendererImpl( private var color2Address = -1L get() { if (field == -1L) { - field = nanoVg.createColor() + field = vg.createColor() } return field @@ -106,12 +106,12 @@ class RendererImpl( private val errorHandler: (Throwable) -> Unit = { LOGGER.error("failed to load resource!", it) } override fun init() { - nanoVg.maybeSetup() + vg.maybeSetup() if (defaultFont == null) { val font = PolyUI.defaultFonts.regular val fdata = font.load().toDirectByteBuffer() - val fit = NvgFont(nanoVg.createFont(font.name, fdata), fdata) + val fit = NvgFont(vg.createFont(font.name, fdata), fdata) this.defaultFont = fit fonts[font] = fit } @@ -119,7 +119,7 @@ class RendererImpl( if (defaultImage == 0) { val iImage = PolyUI.defaultImage val iData = iImage.load() - val iHandle = nanoVg.createImage(iImage.size.x, iImage.size.y, iData.toDirectByteBuffer(), 0) + val iHandle = vg.createImage(iImage.size.x, iImage.size.y, iData.toDirectByteBuffer(), 0) require(iHandle != 0) { "NanoVG failed to initialize default image" } defaultImageData = iData images[iImage] = iHandle @@ -136,14 +136,14 @@ class RendererImpl( GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) } - nanoVg.beginFrame(width, height, pixelRatio) + vg.beginFrame(width, height, pixelRatio) isDrawing = true } override fun endFrame() { if (!isDrawing) throw IllegalStateException("Not drawing") - nanoVg.endFrame() + vg.endFrame() if (!isGl3) { GL11.glPopAttrib() } @@ -151,29 +151,29 @@ class RendererImpl( isDrawing = false } - override fun globalAlpha(alpha: Float) = nanoVg.globalAlpha(alpha) + override fun globalAlpha(alpha: Float) = vg.globalAlpha(alpha) - override fun translate(x: Float, y: Float) = nanoVg.translate(x, y) + override fun translate(x: Float, y: Float) = vg.translate(x, y) - override fun scale(sx: Float, sy: Float, px: Float, py: Float) = nanoVg.scale(sx, sy) + override fun scale(sx: Float, sy: Float, px: Float, py: Float) = vg.scale(sx, sy) - override fun rotate(angleRadians: Double, px: Float, py: Float) = nanoVg.rotate(angleRadians.toFloat()) + override fun rotate(angleRadians: Double, px: Float, py: Float) = vg.rotate(angleRadians.toFloat()) - override fun skewX(angleRadians: Double, px: Float, py: Float) = nanoVg.skewX(angleRadians.toFloat()) + override fun skewX(angleRadians: Double, px: Float, py: Float) = vg.skewX(angleRadians.toFloat()) - override fun skewY(angleRadians: Double, px: Float, py: Float) = nanoVg.skewY(angleRadians.toFloat()) + override fun skewY(angleRadians: Double, px: Float, py: Float) = vg.skewY(angleRadians.toFloat()) override fun transformsWithPoint() = false - override fun push() = nanoVg.save() + override fun push() = vg.save() - override fun pop() = nanoVg.restore() + override fun pop() = vg.restore() - override fun pushScissor(x: Float, y: Float, width: Float, height: Float) = nanoVg.scissor(x, y, width, height) + override fun pushScissor(x: Float, y: Float, width: Float, height: Float) = vg.scissor(x, y, width, height) - override fun pushScissorIntersecting(x: Float, y: Float, width: Float, height: Float) = nanoVg.intersectScissor(x, y, width, height) + override fun pushScissorIntersecting(x: Float, y: Float, width: Float, height: Float) = vg.intersectScissor(x, y, width, height) - override fun popScissor() = nanoVg.resetScissor() + override fun popScissor() = vg.resetScissor() override fun text( font: Font, @@ -185,13 +185,13 @@ class RendererImpl( ) { if (color.transparent) return - nanoVg.beginPath() - nanoVg.fontSize(fontSize) - nanoVg.fontFaceId(getOrPopulateFont(font).id) - nanoVg.textAlign(nanoVg.constants().NVG_ALIGN_LEFT() or nanoVg.constants().NVG_ALIGN_TOP()) + vg.beginPath() + vg.fontSize(fontSize) + vg.fontFaceId(getOrPopulateFont(font).id) + vg.textAlign(vg.constants().NVG_ALIGN_LEFT() or vg.constants().NVG_ALIGN_TOP()) populateFillOrColor(color, x, y, 0f, 0f) - nanoVg.fillColor(color1Address) - nanoVg.text(x, y, text) + vg.fillColor(color1Address) + vg.text(x, y, text) } override fun image( @@ -206,15 +206,15 @@ class RendererImpl( bottomLeftRadius: Float, bottomRightRadius: Float, ) { - nanoVg.imagePattern(x, y, width, height, 0f, getOrPopulateImage(image, width, height), 1f, paintAddress) + vg.imagePattern(x, y, width, height, 0f, getOrPopulateImage(image, width, height), 1f, paintAddress) if (colorMask != 0) { - populateNvgColor(colorMask, nanoVg.getPaintColor(paintAddress)) + populateNvgColor(colorMask, vg.getPaintColor(paintAddress)) } - nanoVg.beginPath() - nanoVg.roundedRectVarying(x, y, width, height, topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius) - nanoVg.fillPaint(paintAddress) - nanoVg.fill() + vg.beginPath() + vg.roundedRectVarying(x, y, width, height, topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius) + vg.fillPaint(paintAddress) + vg.fill() } override fun delete(font: Font?) { @@ -224,15 +224,15 @@ class RendererImpl( override fun delete(image: PolyImage?) { images.remove(image).also { if (it != null) { - nanoVg.deleteImage(it) + vg.deleteImage(it) return } } svgs.remove(image).also { if (it != null) { - nanoVg.deleteSvg(it.first.address) + vg.deleteSvg(it.first.address) it.second.forEach { _, handle -> - nanoVg.deleteImage(handle) + vg.deleteImage(handle) } } } @@ -255,8 +255,8 @@ class RendererImpl( ) { if (color.transparent) return // note: nvg checks params and draws classic rect if 0, so we don't need to - nanoVg.beginPath() - nanoVg.roundedRectVarying( + vg.beginPath() + vg.roundedRectVarying( x, y, width, @@ -267,7 +267,7 @@ class RendererImpl( bottomLeftRadius, ) populateFillOrColor(color, x, y, width, height) - nanoVg.fill() + vg.fill() } override fun hollowRect( @@ -283,8 +283,8 @@ class RendererImpl( bottomRightRadius: Float, ) { if (color.transparent) return - nanoVg.beginPath() - nanoVg.roundedRectVarying( + vg.beginPath() + vg.roundedRectVarying( x, y, width, @@ -294,19 +294,19 @@ class RendererImpl( bottomRightRadius, bottomLeftRadius, ) - nanoVg.strokeWidth(lineWidth) + vg.strokeWidth(lineWidth) populateStrokeColor(color, x, y, width, height) - nanoVg.stroke() + vg.stroke() } override fun line(x1: Float, y1: Float, x2: Float, y2: Float, color: Color, width: Float) { if (color.transparent) return - nanoVg.beginPath() - nanoVg.moveTo(x1, y1) - nanoVg.lineTo(x2, y2) - nanoVg.strokeWidth(width) + vg.beginPath() + vg.moveTo(x1, y1) + vg.lineTo(x2, y2) + vg.strokeWidth(width) populateStrokeColor(color, x1, y1, x2, y2) - nanoVg.stroke() + vg.stroke() } override fun dropShadow( @@ -318,13 +318,13 @@ class RendererImpl( spread: Float, radius: Float, ) { - nanoVg.boxGradient(paintAddress, x - spread, y - spread, width + spread * 2f, height + spread * 2f, radius + spread, blur, color1Address, color2Address) - nanoVg.beginPath() - nanoVg.roundedRect(x - spread, y - spread - blur, width + spread * 2f + blur * 2f, height + spread * 2f + blur * 2f, radius + spread) - nanoVg.roundedRect(x, y, width, height, radius) - nanoVg.pathWinding(nanoVg.constants().NVG_HOLE()) - nanoVg.fillPaint(paintAddress) - nanoVg.fill() + vg.boxGradient(paintAddress, x - spread, y - spread, width + spread * 2f, height + spread * 2f, radius + spread, blur, color1Address, color2Address) + vg.beginPath() + vg.roundedRect(x - spread, y - spread - blur, width + spread * 2f + blur * 2f, height + spread * 2f + blur * 2f, radius + spread) + vg.roundedRect(x, y, width, height, radius) + vg.pathWinding(vg.constants().NVG_HOLE()) + vg.fillPaint(paintAddress) + vg.fill() } @Suppress("NAME_SHADOWING") @@ -333,10 +333,10 @@ class RendererImpl( val output = FloatArray(4) val loadedFont = getOrPopulateFont(font) - nanoVg.fontFaceId(loadedFont.id) - nanoVg.textAlign(nanoVg.constants().NVG_ALIGN_LEFT() or nanoVg.constants().NVG_ALIGN_TOP()) - nanoVg.fontSize(fontSize) - nanoVg.textBounds(0f, 0f, text, output) + vg.fontFaceId(loadedFont.id) + vg.textAlign(vg.constants().NVG_ALIGN_LEFT() or vg.constants().NVG_ALIGN_TOP()) + vg.fontSize(fontSize) + vg.textBounds(0f, 0f, text, output) val width = output[2] - output[0] val height = output[3] - output[1] @@ -353,7 +353,7 @@ class RendererImpl( val buffer = ByteBuffer.allocateDirect(data.size).order(ByteOrder.nativeOrder()).put(data).flip() as ByteBuffer queue.add { - val id = nanoVg.createFont( + val id = vg.createFont( font.name, buffer ) @@ -370,7 +370,7 @@ class RendererImpl( return fonts.getOrPut(font) { val data = font.load { errorHandler(it); return@getOrPut defaultFont!! } val buffer = ByteBuffer.allocateDirect(data.size).order(ByteOrder.nativeOrder()).put(data).flip() as ByteBuffer - val id = nanoVg.createFont(font.name, buffer) + val id = vg.createFont(font.name, buffer) NvgFont(id, buffer) } } @@ -422,11 +422,11 @@ class RendererImpl( val h = IntArray(1) val d = stb.loadFromMemory(data, w, h, IntArray(1), 4) ?: throw IllegalStateException("Failed to load image ${image.resourcePath}: ${stb.failureReason()}") if (!image.size.isPositive) PolyImage.setImageSize(image, Vec2(w[0].toFloat(), h[0].toFloat())) - return nanoVg.createImage(w[0].toFloat(), h[0].toFloat(), d, 0) + return vg.createImage(w[0].toFloat(), h[0].toFloat(), d, 0) } private fun loadSvg(image: PolyImage, data: ByteBuffer): Int { - val svg = nanoVg.parseSvg(data) + val svg = vg.parseSvg(data) val map = Int2IntMap(4) if (!image.size.isPositive) PolyImage.setImageSize(image, Vec2(svg.width, svg.height)) val o = resizeSvg(svg, svg.width, svg.height) @@ -440,12 +440,12 @@ class RendererImpl( val hi = ((if (height == 0f) svg.height else height) * 2f).toInt() val dst = lwjgl.memAlloc(wi * hi * 4) val scale = cl1(width / svg.width, height / svg.height) * 2f - nanoVg.rasterizeSvg(svg.address, 0f, 0f, scale, dst, wi, hi, wi * 4) - return nanoVg.createImage(wi.toFloat(), hi.toFloat(), dst, 0) + vg.rasterizeSvg(svg.address, 0f, 0f, scale, dst, wi, hi, wi * 4) + return vg.createImage(wi.toFloat(), hi.toFloat(), dst, 0) } private fun populateNvgColor(argb: Int, colorAddress: Long) { - nanoVg.rgba(colorAddress, argb) + vg.rgba(colorAddress, argb) } private fun populateStaticColor(color: Color) { @@ -466,7 +466,7 @@ class RendererImpl( if (color !is Color.Gradient) return false when (color.type) { - is Color.Gradient.Type.TopToBottom -> nanoVg.linearGradient( + is Color.Gradient.Type.TopToBottom -> vg.linearGradient( paintAddress, x, y, @@ -476,7 +476,7 @@ class RendererImpl( color2Address ) - is Color.Gradient.Type.TopLeftToBottomRight -> nanoVg.linearGradient( + is Color.Gradient.Type.TopLeftToBottomRight -> vg.linearGradient( paintAddress, x, y, @@ -486,7 +486,7 @@ class RendererImpl( color2Address ) - is Color.Gradient.Type.LeftToRight -> nanoVg.linearGradient( + is Color.Gradient.Type.LeftToRight -> vg.linearGradient( paintAddress, x, y, @@ -496,7 +496,7 @@ class RendererImpl( color2Address ) - is Color.Gradient.Type.BottomLeftToTopRight -> nanoVg.linearGradient( + is Color.Gradient.Type.BottomLeftToTopRight -> vg.linearGradient( paintAddress, x, y + height, @@ -508,7 +508,7 @@ class RendererImpl( is Color.Gradient.Type.Radial -> { val type = color.type as Color.Gradient.Type.Radial - nanoVg.radialGradient( + vg.radialGradient( paintAddress, if (type.centerX == -1f) x + (width / 2f) else type.centerX, if (type.centerY == -1f) y + (height / 2f) else type.centerY, @@ -519,7 +519,7 @@ class RendererImpl( ) } - is PolyColor.Gradient.Type.Box -> nanoVg.boxGradient( + is PolyColor.Gradient.Type.Box -> vg.boxGradient( paintAddress, x, y, @@ -536,17 +536,17 @@ class RendererImpl( private fun populateFillOrColor(color: Color, x: Float, y: Float, width: Float, height: Float) { if (populateColor(color, x, y, width, height)) { - nanoVg.fillPaint(paintAddress) + vg.fillPaint(paintAddress) } else { - nanoVg.fillColor(color1Address) + vg.fillColor(color1Address) } } private fun populateStrokeColor(color: Color, x: Float, y: Float, width: Float, height: Float) { if (populateColor(color, x, y, width, height)) { - nanoVg.strokePaint(paintAddress) + vg.strokePaint(paintAddress) } else { - nanoVg.strokeColor(color1Address) + vg.strokeColor(color1Address) } } diff --git a/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/UIManagerImpl.java b/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/UIManagerImpl.java index b44acf4a3..6f2d90fe5 100644 --- a/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/UIManagerImpl.java +++ b/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/UIManagerImpl.java @@ -112,8 +112,8 @@ public TinyFdApi getTinyFD() { } @Override - public Object createPolyUIScreen(@NotNull PolyUI polyUI, float desiredScreenWidth, float desiredScreenHeight, boolean pauses, boolean blurs, Consumer onClose) { - return new PolyUIScreen(polyUI, desiredScreenWidth, desiredScreenHeight, pauses, blurs, onClose); + public Object createPolyUIScreen(@NotNull PolyUI polyUI, float designedWidth, float designedHeight, boolean pauses, boolean blurs, Consumer onClose) { + return new PolyUIScreen(polyUI, designedWidth, designedHeight, pauses, blurs, onClose); } @Override diff --git a/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/wrappers/PolyUIScreen.java b/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/wrappers/PolyUIScreen.java index 499e7e1b9..5bedd0b15 100644 --- a/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/wrappers/PolyUIScreen.java +++ b/versions/src/main/java/org/polyfrost/oneconfig/api/ui/v1/internal/wrappers/PolyUIScreen.java @@ -33,6 +33,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.polyfrost.oneconfig.api.platform.v1.Platform; +import org.polyfrost.oneconfig.api.ui.v1.Notifications; import org.polyfrost.oneconfig.api.ui.v1.screen.BlurScreen; import org.polyfrost.polyui.PolyUI; import org.polyfrost.polyui.component.Drawable; @@ -53,7 +54,7 @@ public class PolyUIScreen extends UScreen implements BlurScreen { @NotNull public final PolyUI polyUI; - private final float desiredScreenWidth, desiredScreenHeight; + private final float designedWidth, designedHeight, initialWidth, initialHeight; private final boolean pauses, blurs; private final Consumer close; @@ -61,11 +62,13 @@ public class PolyUIScreen extends UScreen implements BlurScreen { private int mx, my; //#endif - public PolyUIScreen(@NotNull PolyUI polyUI, float desiredScreenWidth, float desiredScreenHeight, boolean pauses, boolean blurs, Consumer onClose) { + public PolyUIScreen(@NotNull PolyUI polyUI, float designedWidth, float designedHeight, boolean pauses, boolean blurs, Consumer onClose) { super(true); this.polyUI = polyUI; - this.desiredScreenWidth = desiredScreenWidth; - this.desiredScreenHeight = desiredScreenHeight; + this.designedWidth = designedWidth; + this.designedHeight = designedHeight; + this.initialWidth = polyUI.getMaster().getWidth(); + this.initialHeight = polyUI.getMaster().getHeight(); this.blurs = blurs; this.pauses = pauses; this.close = onClose; @@ -76,14 +79,12 @@ protected final void adjustResolution(float w, float h, boolean force) { // asm: normally, a polyui instance is as big as its window and that is it. // however, inside minecraft, the actual content is smaller than the window size, so resizing it directly would just fuck it up. // so instead, the developer specifies a resolution that their UI was designed for, and we resize accordingly. - if (desiredScreenWidth == 0f || desiredScreenHeight == 0f) return; - float sx = w / desiredScreenWidth; - float sy = h / desiredScreenHeight; + if (designedWidth == 0f || designedHeight == 0f) return; + float sx = w / designedWidth; + float sy = h / designedHeight; if (sx == 1f && sy == 1f) return; - float currentW = polyUI.getMaster().getWidth(); - float currentH = polyUI.getMaster().getHeight(); try { - polyUI.resize(currentW * sx, currentH * sy, force); + polyUI.resize(initialWidth * sx, initialHeight * sy, force); } catch (Exception e) { death(e); } @@ -121,8 +122,8 @@ public void onDrawScreen(@NotNull UMatrixStack matrices, int mouseX, int mouseY, @Override @MustBeInvokedByOverriders public final void onResize(Minecraft client, int width, int height) { - float w = (float) Platform.screen().viewportWidth(); - float h = (float) Platform.screen().viewportHeight(); + float w = (float) Platform.screen().windowWidth(); + float h = (float) Platform.screen().windowHeight(); adjustResolution(w, h, false); } @@ -189,7 +190,13 @@ public boolean uMouseReleased(double mouseX, double mouseY, int mouseButton) { @MustBeInvokedByOverriders public boolean uMouseScrolled(double delta) { try { - polyUI.getInputManager().mouseScrolled(0f, (float) delta); + float v = (float) + //#if MC<13000 + //$$ delta / 8f; + //#else + delta; + //#endif + polyUI.getInputManager().mouseScrolled(0f, v); } catch (Exception e) { death(e); } @@ -244,6 +251,7 @@ public void mouseMoved(double mouseX, double mouseY) { @Override @MustBeInvokedByOverriders public void onScreenClose() { + polyUI.getInputManager().unfocus(); if (close != null) close.accept(polyUI); // noinspection DataFlowIssue this.polyUI.getWindow().setCursor(Cursor.Pointer); @@ -251,7 +259,7 @@ public void onScreenClose() { private void death(Exception e) { Platform.screen().close(); - LOGGER.error("An unexpected error occurred processing {}", getClass().getName(), e); - // todo notify + LOGGER.error("Unexpected error", e); + Notifications.enqueue(Notifications.Type.Error, "An unexpected error occurred with this screen.\nPlease report this to the developer!", 5_000_000_000L); } } \ No newline at end of file diff --git a/versions/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java b/versions/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java index af2905825..3d6d7876e 100644 --- a/versions/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java +++ b/versions/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java @@ -97,7 +97,7 @@ private void init() { CommandManager.registerCommand(b.build()); OCKeybindHelper builder = OCKeybindHelper.builder(); builder.mods(KeyModifiers.RSHIFT).does((s) -> { - OneConfigUI.INSTANCE.open(); + if (s) OneConfigUI.INSTANCE.open(); return Unit.INSTANCE; }); builder.register();