Skip to content
Draft
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8cb49bf
ElementaVersion: v12
Traben-0 Mar 29, 2026
7e60e5a
Dependencies: Bump UC
Traben-0 Mar 29, 2026
ac698e9
UIKeyboardEvents: Create new key events
Traben-0 Mar 29, 2026
def76ba
WindowScreen & UIComponent: implement `UScreen.InputHandler` & split …
Traben-0 Mar 29, 2026
0d413f7
Misc: usage suppressions
Traben-0 Mar 29, 2026
8b8f630
API: update
Traben-0 Mar 29, 2026
2060917
Review: fix deprecation text
Traben-0 Apr 6, 2026
92f656f
Review: convert to using `-> Boolean` functions
Traben-0 Apr 6, 2026
e94c8da
Review: comments
Traben-0 Apr 6, 2026
7e90891
Review: no longer use old listeners
Traben-0 Apr 6, 2026
67abf9f
Review: comment
Traben-0 Apr 6, 2026
5314522
Review: formatting
Traben-0 Apr 6, 2026
33f2fdd
Review: inline new functions into Window
Traben-0 Apr 6, 2026
fb410e0
Review: comment
Traben-0 Apr 6, 2026
9df4981
Review: rename functions
Traben-0 Apr 6, 2026
53c76df
Review: OVERRIDE_DEPRECATION -> Deprecation
Traben-0 Apr 6, 2026
78cdc62
Review: replace incorrect toChar() usage with a properly constructed …
Traben-0 Apr 6, 2026
cb51859
Review: call uSuperInputHandler() super methods
Traben-0 Apr 6, 2026
5dbf1ad
Review: fixup comments
Traben-0 Apr 6, 2026
daf24cb
Review: fixup function names
Traben-0 Apr 6, 2026
c5d856e
Review: keyCode -> key
Traben-0 Apr 6, 2026
6371b34
Review: revert unstable diff
Traben-0 Apr 6, 2026
3e478f7
API
Traben-0 Apr 6, 2026
299cb80
fix diff
Traben-0 Apr 6, 2026
df772bc
implement new listeners in AbstractTextInput
Traben-0 Apr 6, 2026
c9e2864
implement new listeners in MarkDownComponent
Traben-0 Apr 6, 2026
4ab4828
Review: drop functions in favour of directly modifying the listener l…
Traben-0 Apr 9, 2026
413d6ae
Review: OVERRIDE_DEPRECATION -> actual deprecation message
Traben-0 Apr 9, 2026
952c49d
Review: remove use of `run { }`
Traben-0 Apr 9, 2026
1412578
Review: uSuperInputHandler() -> super
Traben-0 Apr 9, 2026
1f717a0
Review: remove redundant checks
Traben-0 Apr 9, 2026
5f6f1a6
Review: space
Traben-0 Apr 9, 2026
41039e1
Review: return true
Traben-0 Apr 9, 2026
d749d5c
Review: call handleChar only if keycode wasn't handled
Traben-0 Apr 9, 2026
d6b9656
Review: missing condition
Traben-0 Apr 9, 2026
aa2a4d8
Review: fixup docs
Traben-0 Apr 9, 2026
443e7ba
Review: add isCopy, isCut, and isPaste helper functions to UIKeyEvent
Traben-0 Apr 9, 2026
7b7264c
API
Traben-0 Apr 9, 2026
304a3dd
Review: remove suppressions
Traben-0 Apr 26, 2026
849f494
bump UC
Traben-0 Apr 26, 2026
49d637e
implement UC modifier changes
Traben-0 Apr 26, 2026
75bda3e
suppress deprecated UKeyboard usages and note future changes to be made
Traben-0 Apr 26, 2026
a37641e
api changes
Traben-0 Apr 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion api/Elementa.api
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public final class gg/essential/elementa/ElementaVersion : java/lang/Enum {
public static final field V1 Lgg/essential/elementa/ElementaVersion;
public static final field V10 Lgg/essential/elementa/ElementaVersion;
public static final field V11 Lgg/essential/elementa/ElementaVersion;
public static final field V12 Lgg/essential/elementa/ElementaVersion;
public static final field V2 Lgg/essential/elementa/ElementaVersion;
public static final field V3 Lgg/essential/elementa/ElementaVersion;
public static final field V4 Lgg/essential/elementa/ElementaVersion;
Expand Down Expand Up @@ -70,6 +71,7 @@ public abstract class gg/essential/elementa/UIComponent : java/util/Observable,
protected final fun fireScrollEvent (Lgg/essential/elementa/events/UIScrollEvent;)V
public final fun focus ()V
public fun getBottom ()F
public final fun getCharTypedEventListeners ()Ljava/util/List;
public fun getChildren ()Lgg/essential/elementa/utils/ObservableList;
public fun getColor ()Ljava/awt/Color;
public final fun getComponentName ()Ljava/lang/String;
Expand All @@ -78,6 +80,7 @@ public abstract class gg/essential/elementa/UIComponent : java/util/Observable,
public fun getFontProvider ()Lgg/essential/elementa/font/FontProvider;
public fun getHasParent ()Z
public fun getHeight ()F
public final fun getKeyPressedEventListeners ()Ljava/util/List;
public final fun getKeyTypedListeners ()Ljava/util/List;
public final fun getLastDraggedMouseX ()Ljava/lang/Double;
public final fun getLastDraggedMouseY ()Ljava/lang/Double;
Expand Down Expand Up @@ -120,8 +123,10 @@ public abstract class gg/essential/elementa/UIComponent : java/util/Observable,
public fun mouseRelease ()V
public fun mouseScroll (D)V
public fun mouseScroll (DD)V
public final fun onCharTyped (Lkotlin/jvm/functions/Function2;)Lgg/essential/elementa/UIComponent;
public final fun onFocus (Lkotlin/jvm/functions/Function1;)Lgg/essential/elementa/UIComponent;
public final fun onFocusLost (Lkotlin/jvm/functions/Function1;)Lgg/essential/elementa/UIComponent;
public final fun onKeyPressed (Lkotlin/jvm/functions/Function2;)Lgg/essential/elementa/UIComponent;
public final fun onKeyType (Lkotlin/jvm/functions/Function3;)Lgg/essential/elementa/UIComponent;
public final fun onKeyTypeConsumer (Ljava/util/function/BiConsumer;)V
public final fun onMouseClick (Lkotlin/jvm/functions/Function2;)Lgg/essential/elementa/UIComponent;
Expand Down Expand Up @@ -243,7 +248,7 @@ public final class gg/essential/elementa/VanillaFontRenderer : gg/essential/elem
public final class gg/essential/elementa/VanillaFontRenderer$Companion {
}

public abstract class gg/essential/elementa/WindowScreen : gg/essential/universal/UScreen {
public abstract class gg/essential/elementa/WindowScreen : gg/essential/universal/UScreen, gg/essential/universal/UScreen$InputHandler {
public fun <init> ()V
public fun <init> (Lgg/essential/elementa/ElementaVersion;)V
public fun <init> (Lgg/essential/elementa/ElementaVersion;Z)V
Expand Down Expand Up @@ -278,6 +283,11 @@ public abstract class gg/essential/elementa/WindowScreen : gg/essential/universa
public fun onMouseScrolled (DDDD)V
public fun onScreenClose ()V
public final fun stopAnimating (Lkotlin/reflect/KMutableProperty0;)V
public fun uCharTyped (I)Z
public fun uKeyPressed (IILgg/essential/universal/UKeyboard$Modifiers;)Z
public fun uMouseClicked (DDILgg/essential/universal/UKeyboard$Modifiers;)Z
public fun uMouseReleased (DDILgg/essential/universal/UKeyboard$Modifiers;)Z
public fun uMouseScrolled (DDDD)Z
}

public class gg/essential/elementa/components/GradientComponent : gg/essential/elementa/components/UIBlock {
Expand Down Expand Up @@ -756,6 +766,7 @@ public final class gg/essential/elementa/components/Window : gg/essential/elemen
public final fun addFloatingComponent (Lgg/essential/elementa/UIComponent;)V
public fun afterInitialization ()V
public fun animationFrame ()V
public final fun charTyped (Lgg/essential/elementa/events/UICharEvent;)Z
public fun draw (Lgg/essential/universal/UMatrixStack;)V
public final fun drawFloatingComponents ()V
public final fun drawFloatingComponents (Lgg/essential/universal/UMatrixStack;)V
Expand All @@ -775,6 +786,7 @@ public final class gg/essential/elementa/components/Window : gg/essential/elemen
public fun hitTest (FF)Lgg/essential/elementa/UIComponent;
public final fun invalidateCachedConstraints ()V
public final fun isAreaVisible (DDDD)Z
public final fun keyPressed (Lgg/essential/elementa/events/UIKeyEvent;)Z
public fun keyType (CI)V
public fun mouseClick (DDI)V
public fun mouseRelease ()V
Expand Down Expand Up @@ -2717,6 +2729,12 @@ public final class gg/essential/elementa/effects/StencilEffect$Companion {
public final fun enableStencil ()V
}

public final class gg/essential/elementa/events/UICharEvent {
public fun <init> (I)V
public final fun getCodepoint ()I
public final fun getString ()Ljava/lang/String;
}

public final class gg/essential/elementa/events/UIClickEvent : gg/essential/elementa/events/UIEvent {
public fun <init> (FFILgg/essential/elementa/UIComponent;Lgg/essential/elementa/UIComponent;I)V
public final fun component1 ()F
Expand Down Expand Up @@ -2750,6 +2768,13 @@ public abstract class gg/essential/elementa/events/UIEvent {
public final fun stopPropagation ()V
}

public final class gg/essential/elementa/events/UIKeyEvent {
public fun <init> (IILgg/essential/universal/UKeyboard$Modifiers;)V
public final fun getKey ()I
public final fun getModifiers ()Lgg/essential/universal/UKeyboard$Modifiers;
public final fun getScanCode ()I
}

public final class gg/essential/elementa/events/UIScrollEvent : gg/essential/elementa/events/UIEvent {
public fun <init> (DDLgg/essential/elementa/UIComponent;Lgg/essential/elementa/UIComponent;)V
public fun <init> (DLgg/essential/elementa/UIComponent;Lgg/essential/elementa/UIComponent;)V
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
kotlin = "1.9.25"
kotlinx-coroutines = "1.5.2"
jetbrains-annotations = "23.0.0"
universalcraft = "466"
universalcraft = "474+feature-em-1645-closing-uscreen-via-esc-on-119-puts-you-in-the-menu-rather"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending UC PR merge

commonmark = "0.17.1"
dom4j = "2.1.1"

Expand Down
26 changes: 26 additions & 0 deletions src/main/kotlin/gg/essential/elementa/ElementaVersion.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import gg.essential.elementa.components.Window
import gg.essential.elementa.constraints.SuperConstraint
import gg.essential.elementa.constraints.animation.AnimationComponent
import gg.essential.elementa.effects.Effect
import gg.essential.universal.UScreen
import gg.essential.universal.render.URenderPipeline
import gg.essential.universal.shader.BlendState

Expand Down Expand Up @@ -204,8 +205,29 @@ enum class ElementaVersion {
*
* See [UniversalCraft#128](https://github.com/SparkUniverse/UniversalCraft/pull/128) for the underlying changes.
*/
@Deprecated(DEPRECATION_MESSAGE)
V11,

/**
* Improvements for key press inputs.
*
* WindowScreen now implements [UScreen.InputHandler] which provides new functions for key and mouse inputs that
* follow more modern Minecraft input method conventions, most notably allowing us to mark an input as handled to
* prevent followup execution in Minecraft itself.
*
* As of V12 the key & character input events have been split up and moved to these new methods.
* `keyType(typedChar: Char, keyCode: Int)` in [Window] has been split into:
* - keyPressed(keyEvent: UIKeyEvent)
* - charTyped(charEvent: UICharEvent)
* As well as all related setup functions. E.G. `onKeyType { }`
* For now any key listeners setup via the old methods will still be called.
Comment thread
Johni0702 marked this conversation as resolved.
Outdated
*
* Also see [gg.essential.elementa.events.UIKeyEvent] & [gg.essential.elementa.events.UICharEvent].
*
* See [UniversalCraft#125](https://github.com/SparkUniverse/UniversalCraft/pull/125) for the underlying changes.
*/
V12,

;

/**
Expand Down Expand Up @@ -258,14 +280,18 @@ Be sure to read through all the changes between your current version and your ne
internal val v9 = V9
@Suppress("DEPRECATION")
internal val v10 = V10
@Suppress("DEPRECATION")
internal val v11 = V11
internal val v12 = V12

internal val atLeastV9Active: Boolean
get() = active >= v9
internal val atLeastV10Active: Boolean
get() = active >= v10
internal val atLeastV11Active: Boolean
get() = active >= v11
internal val atLeastV12Active: Boolean
get() = active >= v12

@PublishedApi
internal var active: ElementaVersion = v0
Expand Down
21 changes: 21 additions & 0 deletions src/main/kotlin/gg/essential/elementa/UIComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import gg.essential.elementa.dsl.animate
import gg.essential.elementa.dsl.toConstraint
import gg.essential.elementa.effects.Effect
import gg.essential.elementa.effects.ScissorEffect
import gg.essential.elementa.events.UICharEvent
import gg.essential.elementa.events.UIClickEvent
import gg.essential.elementa.events.UIKeyEvent
import gg.essential.elementa.events.UIScrollEvent
import gg.essential.elementa.font.FontProvider
import gg.essential.elementa.state.v2.ReferenceHolder
Expand Down Expand Up @@ -119,7 +121,12 @@ abstract class UIComponent : Observable(), ReferenceHolder {
get() = field.also { ownFlags += Flags.RequiresMouseMove }
val mouseDragListeners = mutableListOf<UIComponent.(mouseX: Float, mouseY: Float, button: Int) -> Unit>()
get() = field.also { ownFlags += Flags.RequiresMouseDrag }
@Deprecated("See [ElementaVersion.V12].")
val keyTypedListeners = mutableListOf<UIComponent.(typedChar: Char, keyCode: Int) -> Unit>()
// Requires ElementaVersion.V12
val keyPressedEventListeners = mutableListOf<UIComponent.(keyEvent: UIKeyEvent) -> Boolean>()
// Requires ElementaVersion.V12
val charTypedEventListeners = mutableListOf<UIComponent.(keyEvent: UICharEvent) -> Boolean>()

private var currentlyHovered = false
private val beforeHideAnimations = mutableListOf<AnimatingConstraints.() -> Unit>()
Expand Down Expand Up @@ -836,7 +843,9 @@ abstract class UIComponent : Observable(), ReferenceHolder {
this.forEachChild { it.superCall() }
}

@Deprecated("See [ElementaVersion.V12]. Listeners are now directly called from [Window].")
open fun keyType(typedChar: Char, keyCode: Int) {
@Suppress("DEPRECATION")
for (listener in keyTypedListeners)
this.listener(typedChar, keyCode)
}
Expand Down Expand Up @@ -1021,11 +1030,23 @@ abstract class UIComponent : Observable(), ReferenceHolder {
mouseScrollListeners.add { method.accept(it) }
}

@Deprecated("See [ElementaVersion.V12].")
fun onKeyType(method: UIComponent.(typedChar: Char, keyCode: Int) -> Unit) = apply {
@Suppress("DEPRECATION")
keyTypedListeners.add(method)
}

fun onKeyPressed(method: UIComponent.(keyEvent: UIKeyEvent) -> Boolean) = apply {
keyPressedEventListeners.add(method)
}

fun onCharTyped(method: UIComponent.(keyEvent: UICharEvent) -> Boolean) = apply {
charTypedEventListeners.add(method)
}

@Deprecated("See [ElementaVersion.V12].")
fun onKeyTypeConsumer(method: BiConsumer<Char, Int>) {
@Suppress("DEPRECATION")
keyTypedListeners.add { t: Char, u: Int -> method.accept(t, u) }
}

Expand Down
69 changes: 66 additions & 3 deletions src/main/kotlin/gg/essential/elementa/WindowScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package gg.essential.elementa

import gg.essential.elementa.components.Window
import gg.essential.elementa.constraints.animation.*
import gg.essential.elementa.events.UICharEvent
import gg.essential.elementa.events.UIKeyEvent
import gg.essential.universal.UKeyboard
import gg.essential.universal.UMatrixStack
import gg.essential.universal.UMouse
Expand All @@ -21,7 +23,7 @@ abstract class WindowScreen @JvmOverloads constructor(
private val drawDefaultBackground: Boolean = true,
restoreCurrentGuiOnClose: Boolean = false,
newGuiScale: Int = -1
) : UScreen(restoreCurrentGuiOnClose, newGuiScale) {
) : UScreen(restoreCurrentGuiOnClose, newGuiScale), UScreen.InputHandler {
val window = Window(version)
private var isInitialized = false

Expand All @@ -35,8 +37,22 @@ abstract class WindowScreen @JvmOverloads constructor(
) : this(ElementaVersion.v0, enableRepeatKeys, drawDefaultBackground, restoreCurrentGuiOnClose, newGuiScale)

init {
window.onKeyType { typedChar, keyCode ->
defaultKeyBehavior(typedChar, keyCode)
if (version >= ElementaVersion.v12) {
window.onKeyPressed { keyEvent ->
super.uKeyPressed(keyEvent.key, keyEvent.scanCode, keyEvent.modifiers)
}
window.onCharTyped { charEvent ->
super.uCharTyped(charEvent.codepoint)
}
} else {
@Suppress("DEPRECATION")
window.onKeyType { typedChar, keyCode ->
defaultKeyBehavior(typedChar, keyCode)
}

// This will ensure that inputs go to the old `on*(): Unit` input functions
// rather than the V12+ `u*(): Boolean` functions
inputHandler = null
}
}

Expand All @@ -60,6 +76,8 @@ abstract class WindowScreen @JvmOverloads constructor(
window.draw(matrixStack)
}

@Deprecated("See [ElementaVersion.V12]")
@Suppress("DEPRECATION")
override fun onMouseClicked(mouseX: Double, mouseY: Double, mouseButton: Int) {
super.onMouseClicked(mouseX, mouseY, mouseButton)

Expand All @@ -79,13 +97,34 @@ abstract class WindowScreen @JvmOverloads constructor(
window.mouseClick(adjustedMouseX, adjustedMouseY, mouseButton)
Comment thread
Johni0702 marked this conversation as resolved.
}

// Called only when ElementaVersion >= V12
override fun uMouseClicked(x: Double, y: Double, button: Int, modifiers: UKeyboard.Modifiers): Boolean {
uSuperInputHandler().uMouseClicked(x, y, button, modifiers)
Comment thread
Johni0702 marked this conversation as resolved.
Outdated

// We also need to pass along clicks
window.mouseClick(x, y, button)

return false // TODO returning implementation, see uKeyPressed()
}

@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
override fun onMouseReleased(mouseX: Double, mouseY: Double, state: Int) {
super.onMouseReleased(mouseX, mouseY, state)

// We also need to pass along mouse releases
window.mouseRelease()
}

// Called only when ElementaVersion >= V12
override fun uMouseReleased(x: Double, y: Double, button: Int, modifiers: UKeyboard.Modifiers): Boolean {
uSuperInputHandler().uMouseReleased(x, y, button, modifiers)

// We also need to pass along mouse releases
window.mouseRelease()

return false // TODO returning implementation, see uKeyPressed()
}

@Suppress("DEPRECATION")
@Deprecated(
"Provided `delta` values have different units depending on Minecraft versions. See ElementaVersion.V11 for details.",
Expand All @@ -100,6 +139,7 @@ abstract class WindowScreen @JvmOverloads constructor(
}
}

@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
override fun onMouseScrolled(mouseX: Double, mouseY: Double, deltaHorizontal: Double, deltaVertical: Double) {
super.onMouseScrolled(mouseX, mouseY, deltaHorizontal, deltaVertical)

Expand All @@ -108,11 +148,32 @@ abstract class WindowScreen @JvmOverloads constructor(
}
}

// Called only when ElementaVersion >= V12
override fun uMouseScrolled(x: Double, y: Double, scrollX: Double, scrollY: Double): Boolean {
uSuperInputHandler().uMouseScrolled(x, y, scrollX, scrollY)

window.mouseScroll(scrollX, scrollY)

return false // TODO returning implementation, see uKeyPressed()
}

@Suppress("DEPRECATION")
@Deprecated("Method is not called when ElementaVersion >= V12. See ElementaVersion.V12 for details.")
override fun onKeyPressed(keyCode: Int, typedChar: Char, modifiers: UKeyboard.Modifiers?) {
// We also need to pass along typed keys
window.keyType(typedChar, keyCode)
}

// Called only when ElementaVersion >= V12
override fun uKeyPressed(key: Int, scanCode: Int, modifiers: UKeyboard.Modifiers): Boolean {
return window.keyPressed(UIKeyEvent(key, scanCode, modifiers))
}

// Called only when ElementaVersion >= V12
override fun uCharTyped(codepoint: Int): Boolean {
return window.charTyped(UICharEvent(codepoint))
}

override fun initScreen(width: Int, height: Int) {
window.onWindowResize()

Expand All @@ -133,7 +194,9 @@ abstract class WindowScreen @JvmOverloads constructor(
UKeyboard.allowRepeatEvents(false)
}

@Deprecated("[See ElementaVersion.V12] This method is not called when ElementaVersion >= V12.")
fun defaultKeyBehavior(typedChar: Char, keyCode: Int) {
@Suppress("DEPRECATION")
super.onKeyPressed(keyCode, typedChar, UKeyboard.getModifiers())
}

Expand Down
Loading
Loading