Skip to content

Commit 7730f6f

Browse files
committed
Optimized layout positioning
1 parent 8d3fa99 commit 7730f6f

File tree

14 files changed

+159
-183
lines changed

14 files changed

+159
-183
lines changed

common/src/main/kotlin/com/lambda/gui/component/core/FilledRect.kt

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import java.awt.Color
2525
class FilledRect(
2626
owner: Layout
2727
) : Layout(owner) {
28-
@UIRenderPr0p3rty var rectangle = Rect.ZERO
29-
3028
@UIRenderPr0p3rty var leftTopRadius = 0.0
3129
@UIRenderPr0p3rty var rightTopRadius = 0.0
3230
@UIRenderPr0p3rty var rightBottomRadius = 0.0
@@ -42,15 +40,9 @@ class FilledRect(
4240
init {
4341
properties.interactionPassthrough = true
4442

45-
onUpdate {
46-
// make it pressable
47-
position = rectangle.leftTop
48-
size = rectangle.size
49-
}
50-
5143
onRender {
5244
filledRect(
53-
rectangle,
45+
rect,
5446
leftTopRadius,
5547
rightTopRadius,
5648
rightBottomRadius,

common/src/main/kotlin/com/lambda/gui/component/core/OutlineRect.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ import java.awt.Color
2424
class OutlineRect(
2525
owner: Layout
2626
) : Layout(owner) {
27-
@UIRenderPr0p3rty var rectangle = owner.rect
28-
2927
@UIRenderPr0p3rty var roundRadius = 0.0
3028
@UIRenderPr0p3rty var glowRadius = 0.0
3129

@@ -41,7 +39,7 @@ class OutlineRect(
4139

4240
onRender {
4341
outlineRect(
44-
rectangle,
42+
rect,
4543
roundRadius,
4644
glowRadius,
4745
leftTopColor,

common/src/main/kotlin/com/lambda/gui/component/core/TextField.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,16 @@ class TextField(
4343
val textHeight get() = FontRenderer.getHeight(scale)
4444

4545
init {
46-
fillParent()
4746
properties.interactionPassthrough = true
4847

48+
onUpdate {
49+
position = owner.position
50+
size = owner.size
51+
}
52+
4953
onRender {
50-
val rx = renderPositionX + lerp(textHAlignment.multiplier, offsetX, renderWidth - textWidth - offsetX)
51-
val ry = renderPositionY + lerp(textVAlignment.multiplier, offsetY, renderHeight - textHeight - offsetY)
54+
val rx = positionX + lerp(textHAlignment.multiplier, offsetX, width - textWidth - offsetX)
55+
val ry = positionY + lerp(textVAlignment.multiplier, offsetY, height - textHeight - offsetY)
5256
val renderPos = Vec2d(rx, ry + textHeight * 0.5)
5357
drawString(text, renderPos, color, scale, shadow)
5458
}

common/src/main/kotlin/com/lambda/gui/component/core/UIBuilder.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package com.lambda.gui.component.core
1919

20+
import com.lambda.event.events.GuiEvent
2021
import com.lambda.gui.component.layout.Layout
2122
import com.lambda.util.math.MathUtils.toInt
2223

@@ -37,4 +38,5 @@ fun <T : Layout> T.insertLayout(
3738
val index = owner.children.indexOf(base)
3839
check(index != -1 && base.owner == owner) { "Given layout belongs to different owner" }
3940
owner.children.add(index + next.toInt(), this)
41+
this.onEvent(GuiEvent.Update)
4042
}

common/src/main/kotlin/com/lambda/gui/component/layout/Layout.kt

Lines changed: 47 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -21,53 +21,47 @@ import com.lambda.graphics.RenderMain
2121
import com.lambda.graphics.animation.AnimationTicker
2222
import com.lambda.event.events.GuiEvent
2323
import com.lambda.graphics.pipeline.ScissorAdapter
24-
import com.lambda.graphics.renderer.gui.font.FontRenderer
25-
import com.lambda.graphics.renderer.gui.rect.OutlineRectRenderer
2624
import com.lambda.gui.component.HAlign
2725
import com.lambda.gui.component.VAlign
2826
import com.lambda.gui.component.core.*
2927
import com.lambda.util.KeyCode
3028
import com.lambda.util.Mouse
3129
import com.lambda.util.math.Rect
3230
import com.lambda.util.math.Vec2d
33-
import java.awt.Color
3431

3532
/**
3633
* Represents a component for creating complex ui structures.
3734
*/
3835
open class Layout(
3936
val owner: Layout?
4037
) {
41-
val rect get() = Rect.basedOn(renderPosition, renderSize)
38+
var rect
39+
get() = Rect.basedOn(position, size)
40+
set(value) { position = value.leftTop; size = value.size }
4241

4342
// ToDo: impl alignmentLayout: Layout, instead of being able to align to the owner only
4443
// Position of the component
4544
var position: Vec2d
4645
get() = Vec2d(positionX, positionY)
4746
set(value) { positionX = value.x; positionY = value.y }
4847

49-
private var positionX: Double
48+
var positionX: Double
5049
get() = ownerX + (relativePosX + dockingOffsetX).let {
5150
if (!properties.clampPosition) return@let it
52-
it.coerceAtMost(ownerWidth - renderWidth).coerceAtLeast(0.0)
51+
it.coerceAtMost(ownerWidth - width).coerceAtLeast(0.0)
5352
}; set(value) { relativePosX = value - ownerX - dockingOffsetX }
5453

55-
private var positionY: Double
54+
var positionY: Double
5655
get() = ownerY + (relativePosY + dockingOffsetY).let {
5756
if (!properties.clampPosition) return@let it
58-
it.coerceAtMost(ownerHeight - renderHeight).coerceAtLeast(0.0)
57+
it.coerceAtMost(ownerHeight - height).coerceAtLeast(0.0)
5958
}; set(value) { relativePosY = value - ownerY - dockingOffsetY }
6059

61-
val leftTop get() = renderPosition
62-
val rightTop get() = Vec2d(renderPositionX + renderWidth, renderPositionY)
63-
val rightBottom get() = Vec2d(renderPositionX + renderWidth, renderPositionY + renderHeight)
64-
val leftBottom get() = Vec2d(renderPositionX, renderPositionY + renderHeight)
60+
val leftTop get() = position
61+
val rightTop get() = Vec2d(positionX + width, positionY)
62+
val rightBottom get() = Vec2d(positionX + width, positionY + height)
63+
val leftBottom get() = Vec2d(positionX, positionY + height)
6564

66-
val renderPosition get() = Vec2d(renderPositionX, renderPositionY)
67-
val renderPositionX get() = positionXTransform()
68-
val renderPositionY get() = positionYTransform()
69-
private var positionXTransform = { positionX }
70-
private var positionYTransform = { positionY }
7165
private var relativePosX = 0.0
7266
private var relativePosY = 0.0
7367

@@ -76,14 +70,6 @@ open class Layout(
7670
get() = Vec2d(width, height)
7771
set(value) { width = value.x; height = value.y }
7872

79-
val renderSize get() = Vec2d(renderWidth, renderHeight)
80-
81-
val renderWidth get() = widthTransform()
82-
val renderHeight get() = heightTransform()
83-
84-
private var widthTransform = { width }
85-
private var heightTransform = { height }
86-
8773
var width = 0.0
8874
var height = 0.0
8975

@@ -93,23 +79,23 @@ open class Layout(
9379
field = to
9480

9581
val delta = to.multiplier - from.multiplier
96-
relativePosX += delta * (renderWidth - ownerWidth)
82+
relativePosX += delta * (width - ownerWidth)
9783
}
9884

9985
private val dockingOffsetX get() = if (horizontalAlignment == HAlign.LEFT) 0.0
100-
else (ownerWidth - renderWidth) * horizontalAlignment.multiplier
86+
else (ownerWidth - width) * horizontalAlignment.multiplier
10187

10288
// Vertical alignment
10389
var verticalAlignment = VAlign.TOP; set(to) {
10490
val from = field
10591
field = to
10692

10793
val delta = to.multiplier - from.multiplier
108-
relativePosY += delta * (renderHeight - ownerHeight)
94+
relativePosY += delta * (height - ownerHeight)
10995
}
11096

11197
private val dockingOffsetY get() = if (verticalAlignment == VAlign.TOP) 0.0
112-
else (ownerHeight - renderHeight) * verticalAlignment.multiplier
98+
else (ownerHeight - height) * verticalAlignment.multiplier
11399

114100
// Use screen limits if [owner] is null
115101
private var screenSize = Vec2d.ZERO
@@ -128,12 +114,12 @@ open class Layout(
128114
// Structure
129115
val children = mutableListOf<Layout>()
130116
var selectedChild: Layout? = null
131-
protected open val renderSelf: Boolean get() = renderWidth > 1 && renderHeight > 1
117+
protected open val renderSelf: Boolean get() = width > 1 && height > 1
132118
protected open val scissorRect get() = rect
133119

134120
// Inputs
135121
protected var mousePosition = Vec2d.ZERO
136-
var isHovered = false; get() = field && (owner?.isHovered ?: true)
122+
open val isHovered get() = owner?.let { it.selectedChild == this } ?: true
137123

138124
// Actions
139125
private val showActions = mutableListOf<Layout.() -> Unit>()
@@ -244,7 +230,7 @@ open class Layout(
244230
*/
245231
@LayoutBuilder
246232
fun <T : Layout> T.onMouseClick(button: Mouse.Button, action: Mouse.Action, block: T.() -> Unit) {
247-
mouseClickActions += { butt, act ->
233+
onMouseClick { butt, act ->
248234
if (butt == button && act == action) block()
249235
}
250236
}
@@ -274,15 +260,23 @@ open class Layout(
274260
*/
275261
@LayoutBuilder
276262
fun overrideX(transform: () -> Double) {
277-
positionXTransform = transform
263+
positionX = transform()
264+
265+
onUpdate {
266+
positionX = transform()
267+
}
278268
}
279269

280270
/**
281271
* Force overrides drawn y position of the layout
282272
*/
283273
@LayoutBuilder
284274
fun overrideY(transform: () -> Double) {
285-
positionYTransform = transform
275+
positionY = transform()
276+
277+
onUpdate {
278+
positionY = transform()
279+
}
286280
}
287281

288282
/**
@@ -299,15 +293,23 @@ open class Layout(
299293
*/
300294
@LayoutBuilder
301295
fun overrideWidth(transform: () -> Double) {
302-
widthTransform = transform
296+
width = transform()
297+
298+
onUpdate {
299+
width = transform()
300+
}
303301
}
304302

305303
/**
306304
* Force overrides drawn height of the layout
307305
*/
308306
@LayoutBuilder
309307
fun overrideHeight(transform: () -> Double) {
310-
heightTransform = transform
308+
height = transform()
309+
310+
onUpdate {
311+
height = transform()
312+
}
311313
}
312314

313315
/**
@@ -319,22 +321,6 @@ open class Layout(
319321
overrideHeight(height)
320322
}
321323

322-
/**
323-
* Makes this layout expand up to parents rect
324-
*/
325-
@LayoutBuilder
326-
fun fillParent(
327-
overrideX: () -> Double = { owner?.renderPositionX ?: ownerX },
328-
overrideY: () -> Double = { owner?.renderPositionY ?: ownerY },
329-
overrideWidth: () -> Double = { owner?.renderWidth ?: ownerWidth },
330-
overrideHeight: () -> Double = { owner?.renderHeight ?: ownerHeight }
331-
) {
332-
overrideX(overrideX)
333-
overrideY(overrideY)
334-
overrideWidth(overrideWidth)
335-
overrideHeight(overrideHeight)
336-
}
337-
338324
/**
339325
* Removes this layout from its parent
340326
*/
@@ -353,19 +339,17 @@ open class Layout(
353339
screenSize = RenderMain.screenSize
354340

355341
// Update relative position and bounds
356-
ownerX = owner?.renderPositionX ?: ownerX
357-
ownerY = owner?.renderPositionY ?: ownerY
358-
ownerWidth = owner?.renderWidth ?: screenSize.x
359-
ownerHeight = owner?.renderHeight ?: screenSize.y
360-
361-
// Update hover state (don't mark as hovered if hovered pixel is outside the owner)
362-
val xh = (mousePosition.x - renderPositionX) in 0.0..renderWidth
363-
val yh = (mousePosition.y - renderPositionY) in 0.0..renderHeight
364-
isHovered = xh && yh
342+
ownerX = owner?.positionX ?: ownerX
343+
ownerY = owner?.positionY ?: ownerY
344+
ownerWidth = owner?.width ?: screenSize.x
345+
ownerHeight = owner?.height ?: screenSize.y
365346

366347
// Select an element that's on foreground
367348
selectedChild = if (isHovered) children.lastOrNull {
368-
!it.properties.interactionPassthrough && mousePosition in it.rect
349+
if (it.properties.interactionPassthrough) return@lastOrNull false
350+
val xh = (mousePosition.x - it.positionX) in 0.0..it.width
351+
val yh = (mousePosition.y - it.positionY) in 0.0..it.height
352+
xh && yh
369353
} else null
370354
}
371355
}
@@ -415,8 +399,7 @@ open class Layout(
415399
children.forEach { child ->
416400
if (e is GuiEvent.Render) return@forEach
417401
if (e is GuiEvent.MouseClick) {
418-
val hovered = child == selectedChild || (child.isHovered && child.properties.interactionPassthrough)
419-
val newAction = if (hovered) e.action else Mouse.Action.Release
402+
val newAction = if (child.isHovered) e.action else Mouse.Action.Release
420403

421404
val newEvent = GuiEvent.MouseClick(e.button, newAction, e.mouse)
422405
child.onEvent(newEvent)
@@ -430,20 +413,6 @@ open class Layout(
430413
val block = {
431414
renderActions.forEach { it(this) }
432415
if (renderSelf) children.forEach { it.onEvent(e) }
433-
434-
/*if (this !is FilledRect && this !is OutlineRect && this !is TextField) {
435-
OutlineRectRenderer.outlineRect(
436-
rect,
437-
glowRadius = 0.5
438-
)
439-
440-
FontRenderer.drawString(
441-
javaClass.simpleName,
442-
leftTop + FontRenderer.getHeight(0.5) * 0.5,
443-
Color.WHITE,
444-
0.5
445-
)
446-
}*/
447416
}
448417

449418
if (!properties.scissor) block()

common/src/main/kotlin/com/lambda/gui/component/window/AnimatedWindowChild.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,12 @@ abstract class AnimatedWindowChild(
6262
// Index for smooth "ordered" animation
6363
var index = 0
6464
var lastIndex = 0
65-
protected val isLast get() = index == lastIndex
65+
66+
protected val isLast
67+
get() = index == lastIndex
68+
69+
override val isHovered: Boolean
70+
get() = super.isHovered && isShown
6671

6772
override val renderSelf: Boolean
6873
get() = showAnimation > 0.0 && super.renderSelf
@@ -81,10 +86,6 @@ abstract class AnimatedWindowChild(
8186
staticShowAnimation = 0.0
8287
}
8388

84-
onUpdate {
85-
isHovered = isHovered && isShown
86-
}
87-
8889
titleBar.textField.use {
8990
textHAlignment = HAlign.LEFT
9091

0 commit comments

Comments
 (0)