Skip to content

Commit 6000a84

Browse files
committed
Gui window docking & hud serialization fix
1 parent d76c471 commit 6000a84

File tree

12 files changed

+203
-89
lines changed

12 files changed

+203
-89
lines changed

common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.lambda.config.serializer.gui
22

33
import com.google.gson.*
4+
import com.lambda.gui.api.component.core.DockingRect
45
import com.lambda.gui.impl.clickgui.LambdaClickGui
56
import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow
67
import com.lambda.module.ModuleRegistry
@@ -24,8 +25,12 @@ object CustomModuleWindowSerializer : JsonSerializer<CustomModuleWindow>, JsonDe
2425
addProperty("height", it.height)
2526
addProperty("isOpen", it.isOpen)
2627
add("position", JsonArray().apply {
27-
add(it.position.x)
28-
add(it.position.y)
28+
add(it.serializedPosition.x)
29+
add(it.serializedPosition.y)
30+
})
31+
add("docking", JsonArray().apply {
32+
add(it.dockingH.ordinal)
33+
add(it.dockingV.ordinal)
2934
})
3035
}
3136
} ?: JsonNull.INSTANCE
@@ -47,10 +52,12 @@ object CustomModuleWindowSerializer : JsonSerializer<CustomModuleWindow>, JsonDe
4752
width = it["width"].asDouble
4853
height = it["height"].asDouble
4954
isOpen = it["isOpen"].asBoolean
50-
position = Vec2d(
55+
serializedPosition = Vec2d(
5156
it["position"].asJsonArray[0].asDouble,
5257
it["position"].asJsonArray[1].asDouble
5358
)
59+
dockingH = DockingRect.HAlign.entries[it["docking"].asJsonArray[0].asInt]
60+
dockingV = DockingRect.VAlign.entries[it["docking"].asJsonArray[1].asInt]
5461
}
5562
} ?: throw JsonParseException("Invalid window data")
5663
}

common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.lambda.config.serializer.gui
22

33
import com.google.gson.*
4+
import com.lambda.gui.api.component.core.DockingRect
45
import com.lambda.gui.impl.clickgui.LambdaClickGui
56
import com.lambda.gui.impl.clickgui.windows.tag.TagWindow
67
import com.lambda.gui.impl.hudgui.LambdaHudGui
@@ -20,9 +21,14 @@ object TagWindowSerializer : JsonSerializer<TagWindow>, JsonDeserializer<TagWind
2021
addProperty("height", it.height)
2122
addProperty("isOpen", it.isOpen)
2223
add("position", JsonArray().apply {
23-
add(it.position.x)
24-
add(it.position.y)
24+
add(it.serializedPosition.x)
25+
add(it.serializedPosition.y)
2526
})
27+
add("docking", JsonArray().apply {
28+
add(it.dockingH.ordinal)
29+
add(it.dockingV.ordinal)
30+
})
31+
addProperty("group", if (it.isHudWindow) "hud" else "main")
2632
}
2733
} ?: JsonNull.INSTANCE
2834

@@ -33,20 +39,22 @@ object TagWindowSerializer : JsonSerializer<TagWindow>, JsonDeserializer<TagWind
3339
) = json?.asJsonObject?.let {
3440
val tag = ModuleTag(it["tag"].asString)
3541

36-
val gui = when (tag) {
37-
in ModuleTag.defaults -> LambdaClickGui
38-
in ModuleTag.hudDefaults -> LambdaHudGui
42+
val gui = when (it["group"].asString) {
43+
"main"-> LambdaClickGui
44+
"hud" -> LambdaHudGui
3945
else -> return@let null
4046
}
4147

4248
TagWindow(tag, gui).apply {
4349
width = it["width"].asDouble
4450
height = it["height"].asDouble
4551
isOpen = it["isOpen"].asBoolean
46-
position = Vec2d(
52+
serializedPosition = Vec2d(
4753
it["position"].asJsonArray[0].asDouble,
4854
it["position"].asJsonArray[1].asDouble
4955
)
56+
dockingH = DockingRect.HAlign.entries[it["docking"].asJsonArray[0].asInt]
57+
dockingV = DockingRect.VAlign.entries[it["docking"].asJsonArray[1].asInt]
5058
}
5159
} ?: throw JsonParseException("Invalid window data")
5260
}

common/src/main/kotlin/com/lambda/gui/AbstractGuiConfigurable.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import com.lambda.config.Configurable
44
import com.lambda.config.configurations.GuiConfig
55
import com.lambda.core.Loadable
66
import com.lambda.gui.impl.AbstractClickGui
7-
import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow
87
import com.lambda.gui.impl.clickgui.windows.tag.TagWindow
98
import com.lambda.module.tag.ModuleTag
109
import com.lambda.util.math.Vec2d
@@ -15,7 +14,6 @@ abstract class AbstractGuiConfigurable(
1514
override val name: String
1615
) : Configurable(GuiConfig), Loadable {
1716
var mainWindows by setting("windows", defaultWindows)
18-
open var customWindows = mutableListOf<CustomModuleWindow>()
1917

2018
private val defaultWindows get() =
2119
tags.mapIndexed { index, tag ->

common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ import com.lambda.module.tag.ModuleTag
77
object GuiConfigurable : AbstractGuiConfigurable(
88
LambdaClickGui, ModuleTag.defaults, "gui"
99
) {
10-
override var customWindows by setting("custom windows", listOf<CustomModuleWindow>())
10+
var customWindows by setting("custom windows", listOf<CustomModuleWindow>())
1111
}

common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ abstract class LambdaGui(
2424
override val name: String,
2525
private val owner: Module? = null
2626
) : Screen(Text.of(name)), IComponent, Nameable, Muteable {
27-
protected var screenSize = Vec2d.ZERO
27+
var screenSize = Vec2d.ZERO
2828
override val rect get() = Rect(Vec2d.ZERO, screenSize)
2929

3030
val isOpen get() = mc.currentScreen == this

common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.lambda.graphics.animation.Animation.Companion.exp
44
import com.lambda.graphics.gl.Scissor.scissor
55
import com.lambda.gui.api.GuiEvent
66
import com.lambda.gui.api.RenderLayer
7+
import com.lambda.gui.api.component.core.DockingRect
78
import com.lambda.gui.api.component.core.list.ChildComponent
89
import com.lambda.gui.api.component.core.list.ChildLayer
910
import com.lambda.gui.impl.AbstractClickGui
@@ -28,18 +29,33 @@ abstract class WindowComponent<T : ChildComponent>(
2829
abstract var width: Double
2930
abstract var height: Double
3031

31-
var position = Vec2d.ZERO
32-
3332
var isOpen = true
3433
override val isActive get() = isOpen
3534

3635
private var dragOffset: Vec2d? = null
3736
private val padding get() = ClickGui.windowPadding
3837

39-
final override val rect get() = Rect.basedOn(position, width, renderHeightAnimation + titleBarHeight)
38+
private val rectHandler = object : DockingRect() {
39+
override var relativePos = Vec2d.ZERO
40+
override val width get() = this@WindowComponent.width
41+
override val height get() = renderHeightAnimation + titleBarHeight
42+
43+
override val dockingBase get() = titleBar.center
44+
45+
override var allowHAlign = ClickGui.allowHAlign
46+
override var allowVAlign = ClickGui.allowVAlign
47+
}
48+
49+
var serializedPosition by rectHandler::relativePos
50+
var position by rectHandler::position
51+
final override val rect by rectHandler::rect
52+
53+
var dockingH by rectHandler::dockingH
54+
var dockingV by rectHandler::dockingV
55+
4056
private val contentRect get() = rect.shrink(padding).moveFirst(Vec2d(0.0, titleBarHeight - padding))
4157

42-
private val titleBar get() = Rect.basedOn(rect.leftTop, rect.size.x, titleBarHeight)
58+
private val titleBar: Rect get() = Rect.basedOn(rect.leftTop, rect.size.x, titleBarHeight)
4359
private val titleBarHeight get() = ClickGui.buttonHeight * 1.25
4460

4561
private val renderer = RenderLayer()
@@ -65,6 +81,8 @@ abstract class WindowComponent<T : ChildComponent>(
6581
}
6682

6783
is GuiEvent.Render -> {
84+
updateRect()
85+
6886
// TODO: fix blur
6987
// BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation)
7088

@@ -105,8 +123,14 @@ abstract class WindowComponent<T : ChildComponent>(
105123
}
106124

107125
is GuiEvent.MouseMove -> {
126+
val prevPos = position
127+
108128
dragOffset?.let {
109129
position = e.mouse - it
130+
131+
if (prevPos != position) {
132+
rectHandler.autoDocking()
133+
}
110134
}
111135
}
112136

@@ -133,6 +157,24 @@ abstract class WindowComponent<T : ChildComponent>(
133157
contentComponents.onEvent(e)
134158
}
135159

160+
private fun updateRect() = rectHandler.apply {
161+
screenSize = gui.screenSize
162+
163+
var updateDocking = false
164+
165+
if (allowHAlign != ClickGui.allowHAlign) {
166+
allowHAlign = ClickGui.allowHAlign
167+
updateDocking = true
168+
}
169+
170+
if (allowVAlign != ClickGui.allowVAlign) {
171+
allowVAlign = ClickGui.allowVAlign
172+
updateDocking = true
173+
}
174+
175+
if (updateDocking) autoDocking()
176+
}
177+
136178
fun focus() {
137179
// move window into foreground
138180
gui.apply {
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.lambda.gui.api.component.core
2+
3+
import com.lambda.util.math.MathUtils.coerceIn
4+
import com.lambda.util.math.Rect
5+
import com.lambda.util.math.Vec2d
6+
7+
abstract class DockingRect {
8+
abstract var relativePos: Vec2d
9+
protected abstract val width: Double
10+
protected abstract val height: Double
11+
protected val size get() = Vec2d(width, height)
12+
13+
val rect get() = Rect.basedOn(position, size)
14+
open val dockingBase get() = rect.center
15+
16+
open val autoDocking = false
17+
open val allowHAlign = true
18+
open val allowVAlign = true
19+
20+
open var dockingH = HAlign.LEFT; set(to) {
21+
val from = field
22+
field = to
23+
24+
val delta = to.multiplier - from.multiplier
25+
relativePos += Vec2d.RIGHT * delta * (size.x - screenSize.x)
26+
}
27+
28+
open var dockingV = VAlign.TOP; set(to) {
29+
val from = field
30+
field = to
31+
32+
val delta = to.multiplier - from.multiplier
33+
relativePos += Vec2d.BOTTOM * delta * (size.y - screenSize.y)
34+
}
35+
36+
var screenSize: Vec2d = Vec2d.ZERO
37+
38+
var position
39+
get() = relativeToAbs(relativePos).coerceIn(0.0, screenSize.x - size.x, 0.0, screenSize.y - size.y)
40+
set(value) { relativePos = absToRelative(value); if (autoDocking) autoDocking() }
41+
42+
private val dockingOffset get() = (screenSize - size) * Vec2d(dockingH.multiplier, dockingV.multiplier)
43+
44+
private fun relativeToAbs(posIn: Vec2d) = posIn + dockingOffset
45+
private fun absToRelative(posIn: Vec2d) = posIn - dockingOffset
46+
47+
fun autoDocking() {
48+
val screenCenterX = (screenSize.x * 0.3333)..(screenSize.x * 0.6666)
49+
val screenCenterY = (screenSize.y * 0.3333)..(screenSize.y * 0.6666)
50+
51+
val drawableCenter = dockingBase
52+
53+
dockingH = if (allowHAlign) {
54+
when {
55+
drawableCenter.x < screenCenterX.start -> HAlign.LEFT
56+
drawableCenter.x > screenCenterX.endInclusive -> HAlign.RIGHT
57+
else -> HAlign.CENTER
58+
}
59+
} else HAlign.LEFT
60+
61+
dockingV = if (allowVAlign) {
62+
when {
63+
drawableCenter.y < screenCenterY.start -> VAlign.TOP
64+
drawableCenter.y > screenCenterY.endInclusive -> VAlign.BOTTOM
65+
else -> VAlign.CENTER
66+
}
67+
} else VAlign.TOP
68+
}
69+
70+
enum class HAlign(val multiplier: Double) {
71+
LEFT(0.0),
72+
CENTER(0.5),
73+
RIGHT(1.0)
74+
}
75+
76+
enum class VAlign(val multiplier: Double) {
77+
TOP(0.0),
78+
CENTER(0.5),
79+
BOTTOM(1.0)
80+
}
81+
}

common/src/main/kotlin/com/lambda/gui/impl/AbstractClickGui.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import com.lambda.graphics.animation.Animation.Companion.exp
55
import com.lambda.graphics.buffer.FrameBuffer
66
import com.lambda.graphics.shader.Shader
77
import com.lambda.gui.AbstractGuiConfigurable
8+
import com.lambda.gui.GuiConfigurable
89
import com.lambda.gui.api.GuiEvent
910
import com.lambda.gui.api.LambdaGui
1011
import com.lambda.gui.api.component.WindowComponent
1112
import com.lambda.gui.api.component.core.list.ChildLayer
13+
import com.lambda.gui.impl.clickgui.LambdaClickGui
1214
import com.lambda.gui.impl.clickgui.buttons.SettingButton
1315
import com.lambda.gui.impl.clickgui.windows.ModuleWindow
1416
import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow
@@ -18,6 +20,8 @@ import com.lambda.module.Module
1820
import com.lambda.module.modules.client.ClickGui
1921
import com.lambda.util.Mouse
2022
import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall
23+
import kotlin.reflect.KMutableProperty
24+
import kotlin.reflect.KMutableProperty0
2125

2226
abstract class AbstractClickGui(name: String, owner: Module? = null) : LambdaGui(name, owner) {
2327
protected var hoveredWindow: WindowComponent<*>? = null
@@ -97,7 +101,9 @@ abstract class AbstractClickGui(name: String, owner: Module? = null) : LambdaGui
97101
}
98102
}
99103

100-
private inline fun <reified T : ModuleWindow> syncWindows(configWindows: MutableList<T>) = windows.apply {
104+
private inline fun <reified T : ModuleWindow> syncWindows(prop: KMutableProperty0<MutableList<T>>) = windows.apply {
105+
var configWindows by prop
106+
101107
// Add windows from config
102108
configWindows.filter { it !in children }.forEach(children::add)
103109

@@ -107,15 +113,14 @@ abstract class AbstractClickGui(name: String, owner: Module? = null) : LambdaGui
107113
}
108114

109115
// Update config
110-
configWindows.clear()
111-
configWindows.addAll(children.filterIsInstance<T>())
116+
configWindows = children.filterIsInstance<T>().toMutableList()
112117
}
113118

114-
fun updateWindows() {
115-
syncWindows<TagWindow>(configurable.mainWindows)
119+
private fun updateWindows() {
120+
syncWindows<TagWindow>(configurable::mainWindows)
116121

117-
if (this != LambdaHudGui) {
118-
syncWindows<CustomModuleWindow>(configurable.customWindows)
122+
(configurable as? GuiConfigurable)?.let {
123+
syncWindows<CustomModuleWindow>(it::customWindows)
119124
}
120125
}
121126

common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ package com.lambda.gui.impl.clickgui.windows.tag
22

33
import com.lambda.gui.impl.AbstractClickGui
44
import com.lambda.gui.impl.clickgui.windows.ModuleWindow
5+
import com.lambda.gui.impl.hudgui.LambdaHudGui
6+
import com.lambda.module.HudModule
7+
import com.lambda.module.Module
58
import com.lambda.module.ModuleRegistry
69
import com.lambda.module.tag.ModuleTag
710

811
class TagWindow(
912
val tag: ModuleTag,
1013
owner: AbstractClickGui,
1114
) : ModuleWindow(tag.name, gui = owner) {
15+
val isHudWindow = gui is LambdaHudGui
16+
private val rawFilter = { m: Module -> m is HudModule }
17+
private val filter get() = if (isHudWindow) rawFilter else { m: Module -> !rawFilter(m) }
18+
1219
override fun getModuleList() = ModuleRegistry.modules
13-
.filter { it.defaultTags.firstOrNull() == tag }
20+
.filter { it.defaultTags.firstOrNull() == tag && filter(it) }
1421
}

0 commit comments

Comments
 (0)