Skip to content

Commit 8b555a1

Browse files
committed
Animatio & Refactio
1 parent 150f419 commit 8b555a1

File tree

16 files changed

+362
-210
lines changed

16 files changed

+362
-210
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
package com.lambda.gui.component.core
1919

2020
import com.lambda.graphics.renderer.gui.rect.FilledRectRenderer.filledRect
21-
import com.lambda.gui.component.core.FilledRect.Companion.rectBehind
2221
import com.lambda.gui.component.layout.Layout
2322
import com.lambda.util.math.Rect
2423
import java.awt.Color
@@ -72,6 +71,18 @@ class FilledRect(
7271
leftBottomRadius = radius
7372
}
7473

74+
fun setRadius(
75+
leftTopRadius: Double,
76+
rightTopRadius: Double,
77+
rightBottomRadius: Double,
78+
leftBottomRadius: Double,
79+
) {
80+
this.leftTopRadius = leftTopRadius
81+
this.rightTopRadius = rightTopRadius
82+
this.rightBottomRadius = rightBottomRadius
83+
this.leftBottomRadius = leftBottomRadius
84+
}
85+
7586
fun setColor(color: Color) {
7687
leftTopColor = color
7788
rightTopColor = color
@@ -109,7 +120,7 @@ class FilledRect(
109120
fun Layout.rectBehind(
110121
layout: Layout,
111122
block: FilledRect.() -> Unit = {}
112-
) = FilledRect(this).relativeLayout(this, layout, false).apply(block)
123+
) = FilledRect(this).insertLayout(this, layout, false).apply(block)
113124

114125
/**
115126
* Adds a [FilledRect] over given [layout]
@@ -118,6 +129,6 @@ class FilledRect(
118129
fun Layout.rectOver(
119130
layout: Layout,
120131
block: FilledRect.() -> Unit = {}
121-
) = FilledRect(this).relativeLayout(this, layout, true).apply(block)
132+
) = FilledRect(this).insertLayout(this, layout, true).apply(block)
122133
}
123134
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
package com.lambda.gui.component.core
1919

2020
import com.lambda.graphics.renderer.gui.rect.OutlineRectRenderer.outlineRect
21-
import com.lambda.gui.component.core.FilledRect.Companion.rectBehind
2221
import com.lambda.gui.component.layout.Layout
2322
import java.awt.Color
2423

@@ -77,7 +76,7 @@ class OutlineRect(
7776
fun Layout.outlineBehind(
7877
layout: Layout,
7978
block: OutlineRect.() -> Unit = {}
80-
) = OutlineRect(this).relativeLayout(this, layout, false).apply(block)
79+
) = OutlineRect(this).insertLayout(this, layout, false).apply(block)
8180

8281
/**
8382
* Creates an [OutlineRect] component - layout-based rect representation
@@ -86,6 +85,6 @@ class OutlineRect(
8685
fun Layout.outlineOver(
8786
layout: Layout,
8887
block: OutlineRect.() -> Unit = {}
89-
) = OutlineRect(this).relativeLayout(this, layout, true).apply(block)
88+
) = OutlineRect(this).insertLayout(this, layout, true).apply(block)
9089
}
9190
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import com.lambda.graphics.renderer.gui.font.FontRenderer
2121
import com.lambda.graphics.renderer.gui.font.FontRenderer.drawString
2222
import com.lambda.gui.component.HAlign
2323
import com.lambda.gui.component.VAlign
24-
import com.lambda.gui.component.core.OutlineRect.Companion.outlineBehind
2524
import com.lambda.gui.component.layout.Layout
2625
import com.lambda.util.math.Vec2d
2726
import com.lambda.util.math.lerp
@@ -71,7 +70,7 @@ class TextField(
7170
fun Layout.textFieldBehind(
7271
layout: Layout,
7372
block: TextField.() -> Unit = {}
74-
) = TextField(this).relativeLayout(this, layout, false).apply(block)
73+
) = TextField(this).insertLayout(this, layout, false).apply(block)
7574

7675
/**
7776
* Adds a [TextField] over given [layout]
@@ -80,6 +79,6 @@ class TextField(
8079
fun Layout.textFieldOver(
8180
layout: Layout,
8281
block: TextField.() -> Unit = {}
83-
) = TextField(this).relativeLayout(this, layout, true).apply(block)
82+
) = TextField(this).insertLayout(this, layout, true).apply(block)
8483
}
8584
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ annotation class LayoutBuilder
2929
@DslMarker
3030
annotation class UIRenderPr0p3rty
3131

32-
fun <T : Layout> T.relativeLayout(
32+
fun <T : Layout> T.insertLayout(
3333
owner: Layout,
3434
base: Layout,
3535
next: Boolean

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

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ 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
2426
import com.lambda.gui.component.HAlign
2527
import com.lambda.gui.component.VAlign
26-
import com.lambda.gui.component.core.LayoutBuilder
27-
import com.lambda.gui.component.core.UIBuilder
28+
import com.lambda.gui.component.core.*
2829
import com.lambda.util.KeyCode
2930
import com.lambda.util.Mouse
3031
import com.lambda.util.math.Rect
3132
import com.lambda.util.math.Vec2d
33+
import java.awt.Color
3234

3335
/**
3436
* Represents a component for creating complex ui structures.
@@ -75,10 +77,13 @@ open class Layout(
7577
set(value) { width = value.x; height = value.y }
7678

7779
val renderSize get() = Vec2d(renderWidth, renderHeight)
80+
7881
val renderWidth get() = widthTransform()
7982
val renderHeight get() = heightTransform()
83+
8084
private var widthTransform = { width }
8185
private var heightTransform = { height }
86+
8287
var width = 0.0
8388
var height = 0.0
8489

@@ -123,7 +128,8 @@ open class Layout(
123128
// Structure
124129
val children = mutableListOf<Layout>()
125130
var selectedChild: Layout? = null
126-
protected open val renderChildren: Boolean get() = renderWidth > 0 && renderHeight > 0
131+
protected open val renderSelf: Boolean get() = renderWidth > 1 && renderHeight > 1
132+
protected open val scissorRect get() = rect
127133

128134
// Inputs
129135
protected var mousePosition = Vec2d.ZERO
@@ -148,7 +154,7 @@ open class Layout(
148154
*/
149155
@LayoutBuilder
150156
fun <T : Layout> T.use(action: T.() -> Unit) {
151-
action(this).apply { }
157+
action(this)
152158
}
153159

154160
/**
@@ -231,6 +237,18 @@ open class Layout(
231237
mouseClickActions += { button, mouseAction -> action(button, mouseAction) }
232238
}
233239

240+
/**
241+
* Sets the action to be performed when mouse button gets clicked.
242+
*
243+
* @param action The action to be performed.
244+
*/
245+
@LayoutBuilder
246+
fun <T : Layout> T.onMouseClick(button: Mouse.Button, action: Mouse.Action, block: T.() -> Unit) {
247+
mouseClickActions += { butt, act ->
248+
if (butt == button && act == action) block()
249+
}
250+
}
251+
234252
/**
235253
* Sets the action to be performed when mouse moves.
236254
*
@@ -272,8 +290,8 @@ open class Layout(
272290
*/
273291
@LayoutBuilder
274292
fun overridePosition(x: () -> Double, y: () -> Double) {
275-
positionXTransform = x
276-
positionYTransform = y
293+
overrideX(x)
294+
overrideY(y)
277295
}
278296

279297
/**
@@ -297,8 +315,8 @@ open class Layout(
297315
*/
298316
@LayoutBuilder
299317
fun overrideSize(width: () -> Double, height: () -> Double) {
300-
widthTransform = width
301-
heightTransform = height
318+
overrideWidth(width)
319+
overrideHeight(height)
302320
}
303321

304322
/**
@@ -374,17 +392,17 @@ open class Layout(
374392
is GuiEvent.Update -> {
375393
updateActions.forEach { it(this) }
376394
}
377-
is GuiEvent.Render -> {}
395+
is GuiEvent.Render -> {
396+
if (!renderSelf) return
397+
}
378398
is GuiEvent.MouseMove -> {
379399
mousePosition = e.mouse
380400
mouseMoveActions.forEach { it(this, e.mouse) }
381401
}
382402
is GuiEvent.MouseScroll -> {
403+
if (!isHovered) return
383404
mousePosition = e.mouse
384-
385-
if (isHovered) {
386-
mouseScrollActions.forEach { it(this, e.delta) }
387-
}
405+
mouseScrollActions.forEach { it(this, e.delta) }
388406
}
389407
is GuiEvent.MouseClick -> {
390408
mousePosition = e.mouse
@@ -411,11 +429,25 @@ open class Layout(
411429
if (e is GuiEvent.Render) {
412430
val block = {
413431
renderActions.forEach { it(this) }
414-
if (renderChildren) children.forEach { it.onEvent(e) }
432+
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+
}*/
415447
}
416448

417449
if (!properties.scissor) block()
418-
else ScissorAdapter.scissor(rect, block)
450+
else ScissorAdapter.scissor(scissorRect, block)
419451
}
420452
}
421453

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.gui.component.window
19+
20+
import com.lambda.graphics.animation.Animation.Companion.exp
21+
import com.lambda.gui.component.HAlign
22+
import com.lambda.gui.component.layout.Layout
23+
import com.lambda.module.modules.client.ClickGui
24+
import com.lambda.util.math.MathUtils.toInt
25+
import com.lambda.util.math.Vec2d
26+
import com.lambda.util.math.lerp
27+
import com.lambda.util.math.setAlpha
28+
import com.lambda.util.math.transform
29+
import java.awt.Color
30+
31+
abstract class AnimatedWindowChild(
32+
owner: Layout,
33+
initialTitle: String = "Untitled",
34+
initialPosition: Vec2d = Vec2d.ZERO,
35+
initialSize: Vec2d = Vec2d(110, 350),
36+
draggable: Boolean = true,
37+
scrollable: Boolean = true,
38+
minimizing: Minimizing = Minimizing.Relative,
39+
resizable: Boolean = true,
40+
autoResize: AutoResize = AutoResize.Disabled
41+
) : Window(owner, initialTitle, initialPosition, initialSize, draggable, scrollable, minimizing, resizable, autoResize) {
42+
private val window get() = owner?.owner as? Window
43+
private val animatedWindow get() = owner?.owner as? AnimatedWindowChild
44+
45+
// Show animation for when the component is shown or hidden
46+
open val isShown get() = true
47+
private val isShownInternal get() = window?.isExpand != false && isShown
48+
var showAnimation by animation.exp(0.0, 1.0, {
49+
var speed = 0.7
50+
51+
if (lastIndex != 0)
52+
speed = transform(index.toDouble(), 0.0, lastIndex.toDouble(), 0.4, speed)
53+
54+
speed + isShownInternal.toInt() * 0.1
55+
}) { isShownInternal }.apply {
56+
if (window == null) this.setValue(1.0)
57+
}; protected set
58+
59+
// Animation without index-based slowdown
60+
var staticShowAnimation by animation.exp(0.0, 1.0, 0.7, ::isShown)
61+
62+
// Index for smooth "ordered" animation
63+
var index = 0
64+
var lastIndex = 0
65+
protected val isLast get() = index == lastIndex
66+
67+
override val renderSelf: Boolean
68+
get() = showAnimation > 0.0 && super.renderSelf
69+
70+
init {
71+
titleBar.textField.onUpdate {
72+
textHAlignment = HAlign.LEFT
73+
offsetX = lerp(showAnimation, -5.0, ClickGui.fontOffset)
74+
color = Color.WHITE.setAlpha(showAnimation)
75+
}
76+
}
77+
78+
init {
79+
onShow {
80+
showAnimation = 0.0
81+
staticShowAnimation = 0.0
82+
}
83+
84+
onUpdate {
85+
isHovered = isHovered && isShown
86+
}
87+
88+
titleBar.textField.use {
89+
textHAlignment = HAlign.LEFT
90+
91+
onUpdate {
92+
offsetX = lerp(showAnimation, -5.0, ClickGui.fontOffset)
93+
scale = lerp(showAnimation, 0.7, 1.0)
94+
color = Color.WHITE.setAlpha(showAnimation)
95+
}
96+
}
97+
}
98+
}

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.lambda.gui.component.layout.Layout
2626
import com.lambda.util.Mouse
2727
import com.lambda.util.math.Vec2d
2828
import com.lambda.util.math.lerp
29+
import com.lambda.util.math.transform
2930

3031
/**
3132
* Represents a titlebar component
@@ -47,10 +48,9 @@ class TitleBar(
4748
dragOffset = null
4849
}
4950

50-
onMouseClick { button: Mouse.Button, action: Mouse.Action ->
51-
dragOffset = if (drag && button == Mouse.Button.Left && action == Mouse.Action.Click) {
52-
mousePosition - owner.position
53-
} else null
51+
onMouseClick { _, _ -> dragOffset = null }
52+
onMouseClick(Mouse.Button.Left, Mouse.Action.Click) {
53+
if (drag) dragOffset = mousePosition - owner.position
5454
}
5555

5656
onMouseMove { mouse ->
@@ -69,7 +69,13 @@ class TitleBar(
6969
leftTopRadius = radius
7070
rightTopRadius = radius
7171

72-
val bottomRadius = lerp(owner.content.renderHeight, radius, 0.0)
72+
val bottomRadius = transform(
73+
owner.renderHeight,
74+
this.renderHeight,
75+
this.renderHeight + 1,
76+
radius,
77+
0.0
78+
)
7379
leftBottomRadius = bottomRadius
7480
rightBottomRadius = bottomRadius
7581

0 commit comments

Comments
 (0)