Skip to content

Commit 1ad0b71

Browse files
authored
Merge pull request #23 from Prism-Client/dev
1.3.0 Figma Fonts
2 parents 1162926 + 7c07030 commit 1ad0b71

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+2097
-2552
lines changed

README.md

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
# Aether UI
22

3-
<img src="/docs/assets/client-logo-rounded.png" align="right" width="230" height="230">
3+
<img src="/assets/client-logo-rounded.png" align="right" width="230" height="230">
44

5-
**Aether is a UI component library engine for Minecraft** and LWJGL projects (or anything really). You can create your
6-
own renderer implementation or use the default implementation
7-
with *[NanoVG](https://github.com/memononen/nanovg "An anti-aliased vector graphics library")*, which is an **
8-
Anti-Aliased vector graphics library**. **Please note the project is in the early stages of development.** Bugs may
9-
arise, and there might be incomplete/missing features. The library is licensed under GPL-v2.0 license.
5+
Aether is a UI component engine for Minecraft. It's designed with Kotlin, Figma, and Minecraft in mind. Aether is
6+
designed to allow you to customize the renderer to your own, or the default one
7+
with *[NanoVG, an anti-aliased 2D vector graphics library](https://github.com/memononen/nanovg "An anti-aliased vector graphics library")*.
8+
As mentioned before, Aether is designed with Figma in mind. Features such as [Auto Layouts](https://help.figma.com/hc/en-us/articles/360040451373-Explore-auto-layout-properties)
9+
and [Figma Font](https://help.figma.com/hc/en-us/articles/360039956434-Getting-started-with-text) are implemented to
10+
streamline the process of creating UIs from Figma. The library is licensed under GPL-v2.0 license.
1011

11-
Ready to get started? [Check out the docs!](https://aether.prismclient.net/)
12+
Convinced? [Check out the docs!](https://aether.prismclient.net/)
1213

1314
# Including the project
1415

@@ -18,11 +19,11 @@ Ready to get started? [Check out the docs!](https://aether.prismclient.net/)
1819

1920
```groovy
2021
repositories {
21-
maven { url "https://jitpack.io" }
22+
maven { url "https://jitpack.io" }
2223
}
2324
2425
dependencies {
25-
implementation "com.github.Prism-Client:Aether-UI:Release"
26+
implementation "com.github.Prism-Client:Aether-UI:Release"
2627
}
2728
```
2829

@@ -33,18 +34,19 @@ dependencies {
3334
<summary>Maven</summary>
3435

3536
```xml
37+
3638
<repositories>
3739
<repository>
3840
<id>jitpack.io</id>
3941
<url>https://jitpack.io</url>
4042
</repository>
41-
</repositories>
43+
</repositories>
4244
<dependencies>
43-
<dependency>
44-
<groupId>com.github.Prism-Client</groupId>
45-
<artifactId>Aether-UI</artifactId>
46-
<version>Release</version>
47-
</dependency>
45+
<dependency>
46+
<groupId>com.github.Prism-Client</groupId>
47+
<artifactId>Aether-UI</artifactId>
48+
<version>Release</version>
49+
</dependency>
4850
</dependencies>
4951
```
5052

@@ -55,16 +57,17 @@ dependencies {
5557
Personally, the greatest feat in making a Minecraft client is making appealing, flexible, and highly customizable UI.
5658
Very few are able to reach even 2/3 of my goals. I found that popular clients lacked quality (anti-aliasing) in their
5759
client, and in other cases, it simply wasn't that appealing (though that might be more related to the designer). Around
58-
the time of the intial creation of this library, I picked up Kotlin. Kotlin introduces a ton of useful features
59-
especially the DSL feature. It makes creating UIs just feel a whole lot easier. Because of it, I decided to design it
60+
the time of the initial creation of this library, I picked up Kotlin. Kotlin introduces a ton of useful features
61+
especially the DSL feature. It makes creating UIs just feel a lot easier. Because of it, I decided to design it
6062
with Kotlin as the main programming language. Java is still supported, however I <ins>highly</ins> suggest for you to
6163
use Kotlin.
6264

6365
# Design
6466

65-
I initially created the engine to act a bit like HTML and CSS, where you would create "style sheets" and define them as
66-
components. This design, dare I say pattern, is essentially is how it is today. However, that is about the only thing
67-
related to web stuff.
67+
I initially created the engine to act a bit like HTML and CSS, however, I decided to swerve from that. I kept the idea
68+
of styles, however, a lot of things are different from web. After all, it was initially designed for newspapers! (Obviously,
69+
it's changed a lot since then). Because I had Figma in mind, quite a few different features (such as Auto Layouts and Text) are
70+
somewhat "loosely" based on Figma.
6871

6972
# Development
7073

assets/client-logo-rounded.png

151 KB
Loading

build.gradle

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,12 @@ dependencies {
4747
testRuntimeOnly "org.lwjgl:lwjgl-stb:$lwjglVersion:$lwjglNatives"
4848
}
4949

50-
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
51-
kotlinOptions {
52-
languageVersion = "1.7"
53-
freeCompilerArgs += [
54-
'-Xno-call-assertions',
55-
'-Xno-receiver-assertions',
56-
'-Xno-param-assertions',
57-
'-Xjvm-default=enable'
58-
]
59-
}
60-
}
61-
6250
publishing {
6351
publications {
6452
maven(MavenPublication) {
6553
groupId = 'com.github.Prism-Client'
6654
artifactId = 'Aether-UI'
67-
version = '1.2-release'
55+
version = '1.2-Production'
6856
from components.kotlin
6957
}
7058
}

src/main/kotlin/net/prismclient/aether/ui/Aether.kt

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ package net.prismclient.aether.ui
33
import net.prismclient.aether.ui.Aether.Properties
44
import net.prismclient.aether.ui.component.UIComponent
55
import net.prismclient.aether.ui.component.controller.UIController
6+
import net.prismclient.aether.ui.component.type.layout.UIContainer
7+
import net.prismclient.aether.ui.component.type.layout.UIContainerSheet
68
import net.prismclient.aether.ui.component.type.layout.UIFrame
7-
import net.prismclient.aether.ui.component.type.layout.container.UIContainer
8-
import net.prismclient.aether.ui.component.type.layout.styles.UIContainerSheet
99
import net.prismclient.aether.ui.event.input.UIMouseEvent
1010
import net.prismclient.aether.ui.renderer.UIProvider
1111
import net.prismclient.aether.ui.renderer.UIRenderer
@@ -33,9 +33,10 @@ import java.util.function.Consumer
3333
* functions [Properties.updateSize] and [Properties.updateMouse] to update the values without
3434
* invoking the [update], and [mouseMoved] functions.
3535
*
36+
* [Aether Documentation](https://aether.prismclient.net/getting-started)
37+
*
3638
* @author sen
3739
* @since 1.0
38-
* @see <a href="https://aether.prismclient.net/getting-started">UICore documentation</a>
3940
* @see UIProvider
4041
*/
4142
open class Aether(renderer: UIRenderer) {
@@ -108,12 +109,14 @@ open class Aether(renderer: UIRenderer) {
108109
open fun render() {
109110
renderer {
110111
if (activeScreen != null) {
112+
timings.onFrameRenderStart()
111113
beginFrame(width, height, devicePxRatio)
112114
for (i in 0 until components!!.size) {
113115
val component = components!![i]
114116
if (component.visible) component.render()
115117
}
116118
endFrame()
119+
timings.onFrameRenderEnd()
117120
}
118121
}
119122
}
@@ -123,7 +126,7 @@ open class Aether(renderer: UIRenderer) {
123126
* eligibility to be focused or bubbled. The [Properties.mouseX] and [Properties.mouseY]
124127
* properties can be found in [Aether.Properties].
125128
*/
126-
fun mouseMoved(mouseX: Float, mouseY: Float) {
129+
open fun mouseMoved(mouseX: Float, mouseY: Float) {
127130
updateMouse(mouseX, mouseY)
128131
mouseMoveListeners?.forEach { it.value.run() }
129132
if (activeScreen != null) for (i in 0 until components!!.size) components!![i].mouseMoved(mouseX, mouseY)
@@ -139,10 +142,10 @@ open class Aether(renderer: UIRenderer) {
139142
*
140143
* @see mouseScrolled
141144
*/
142-
fun mouseChanged(mouseButton: Int, isRelease: Boolean) {
145+
open fun mouseChanged(mouseButton: Int, isRelease: Boolean) {
143146
if (isRelease) {
144147
mouseReleasedListeners?.forEach { it.value.run() }
145-
components?.forEach { it.mouseReleased(mouseX, mouseY) }
148+
components?.forEach { it.mouseReleased(it.getMouseX(), it.getMouseY()) }
146149
return
147150
}
148151

@@ -162,27 +165,25 @@ open class Aether(renderer: UIRenderer) {
162165
* mouse coordinates. Index is the index of the component.
163166
*/
164167
fun peek(list: ArrayList<UIComponent<*>>, index: Int, clickCount: Int): Boolean {
165-
var component: UIComponent<*>? = null
168+
var foundComponent: UIComponent<*>? = null
166169

167170
for (i in index until list.size) {
168171
val child = list[i]
169-
val check = child.isMouseInsideBounds()
170-
if (child.isMouseInsideBounds() || !child.style.clipContent) {
171-
if (child.childrenCount > 0) {
172-
if (peek(
173-
if (child is UIFrame) child.components else list,
174-
i + if (child is UIFrame) 0 else 1,
175-
clickCount
176-
)
177-
) return true
172+
173+
// If the mouse is inside the component
174+
if (child.isMouseInside()) {
175+
// Check if the component is a UIFrame. If it is, integrate through the children
176+
// of this frame and find the one, if applicable that should be invoked.
177+
if (child is UIFrame) {
178+
// Break the loop by returning true if the component is found
179+
if (peek(child.components, 0, clickCount)) return true
178180
}
179-
if (check) component = child
181+
foundComponent = child
180182
}
181183
}
182-
183-
return if (component != null) {
184-
component.focus()
185-
component.mousePressed(UIMouseEvent(mouseX, mouseY, mouseButton, clickCount))
184+
return if (foundComponent != null) {
185+
foundComponent.focus()
186+
foundComponent.mousePressed(UIMouseEvent(foundComponent.getMouseX(), foundComponent.getMouseY(), mouseButton, clickCount))
186187
true
187188
} else false
188189
}
@@ -211,7 +212,7 @@ open class Aether(renderer: UIRenderer) {
211212
i++
212213
}
213214
c?.focus()
214-
c?.mousePressed(UIMouseEvent(mouseX, mouseY, mouseButton, clickCount))
215+
c?.mousePressed(UIMouseEvent(c.getMouseX(), c.getMouseY(), mouseButton, clickCount))
215216
}
216217

217218
/**
@@ -220,7 +221,7 @@ open class Aether(renderer: UIRenderer) {
220221
* @param character The key which was pressed or '\u0000'
221222
* @see updateModifierKey To update keys such as Shift, Alt, Tab etc...
222223
*/
223-
fun keyPressed(character: Char) {
224+
open fun keyPressed(character: Char) {
224225
keyPressListeners?.forEach { it.value.accept(character) }
225226
(focusedComponent as? UIComponent<*>)?.keyPressed(character)
226227
}
@@ -230,6 +231,7 @@ open class Aether(renderer: UIRenderer) {
230231
* of their eligibility to be focused or bubbled.
231232
*/
232233
open fun mouseScrolled(scrollAmount: Float) {
234+
if (scrollAmount == 0f) return
233235
tryFocus()
234236
mouseScrollListeners?.forEach { it.value.accept(scrollAmount) }
235237
components?.forEach { it.mouseScrolled(mouseX, mouseY, scrollAmount) }
@@ -241,20 +243,20 @@ open class Aether(renderer: UIRenderer) {
241243
* as de-focusing the focused component and adding listeners to input.
242244
*/
243245
companion object Properties {
246+
247+
val timings: Timings = Timings()
248+
244249
@JvmStatic
245250
var debug: Boolean = true
246251

247252
@JvmStatic
248253
lateinit var instance: Aether
249-
protected set
250254

251255
@JvmStatic
252256
lateinit var renderer: UIRenderer
253-
protected set
254257

255258
@JvmStatic
256259
var activeScreen: UIScreen? = null
257-
protected set
258260

259261
/**
260262
* The focused component (if applicable).
@@ -265,92 +267,79 @@ open class Aether(renderer: UIRenderer) {
265267
*/
266268
@JvmStatic
267269
var focusedComponent: UIFocusable? = null
268-
protected set
269270

270271
/**
271272
* The width of the screen. It can be set via [update]
272273
*/
273274
@JvmStatic
274275
var width: Float = 0f
275-
protected set
276276

277277
/**
278278
* The width of the screen. It can be set via [update]
279279
*/
280280
@JvmStatic
281281
var height: Float = 0f
282-
protected set
283282

284283
/**
285284
* The device pixel ratio. It can be set via [update]. It is the equivalent of content scale.
286285
*/
287286
@JvmStatic
288287
var devicePxRatio: Float = 1f
289-
protected set
290288

291289
/**
292290
* The x position of the mouse relative to the screen
293291
*/
294292
@JvmStatic
295293
var mouseX: Float = 0f
296-
protected set
297294

298295
/**
299296
* The y position of the mouse relative to the screen
300297
*/
301298
@JvmStatic
302299
var mouseY: Float = 0f
303-
protected set
304300

305301
/**
306302
* Invoked whenever the layout needs to be updated. This can be when the screen
307303
* is resized or created. Invoked prior to components.
308304
*/
309305
@JvmStatic
310306
var updateListeners: HashMap<String, Runnable>? = null
311-
protected set
312307

313308
/**
314309
* The listeners for then the mouse is moved. Invoked prior to components.
315310
*/
316311
@JvmStatic
317312
var mouseMoveListeners: HashMap<String, Runnable>? = null
318-
protected set
319313

320314
/**
321315
* Invoked when the mouse is pressed. Invoked prior to components.
322316
*/
323317
@JvmStatic
324318
var mousePressedListeners: HashMap<String, Runnable>? = null
325-
protected set
326319

327320
/**
328321
* Invoked when the mouse is released. Invoked prior to components.
329322
*/
330323
@JvmStatic
331324
var mouseReleasedListeners: HashMap<String, Runnable>? = null
332-
protected set
333325

334326
/**
335327
* Invoked when a key is pressed. Invoked prior to components.
336328
*/
337329
@JvmStatic
338330
var keyPressListeners: HashMap<String, Consumer<Char>>? = null
339-
protected set
340331

341332
/**
342333
* Invoked when the mouse is scrolled. Invoked prior to components.
343334
*/
344335
@JvmStatic
345336
var mouseScrollListeners: HashMap<String, Consumer<Float>>? = null
346-
protected set
347337

348338
/**
349339
* Invoked when the screen is deleted. This is used to deallocate listeners added to UICore.
350340
*/
351341
@JvmStatic
352342
var deallocationListeners: HashMap<String, Runnable>? = null
353-
protected set
354343

355344
/**
356345
* The list of modifier keys. The value is if the key is pressed
@@ -502,13 +491,7 @@ open class Aether(renderer: UIRenderer) {
502491
* Focuses the component. Please use [UIComponent.focus] instead.
503492
*/
504493
@JvmStatic
505-
fun focus(component: UIFocusable) {
506-
// Check if the given value is a valid instance of UIComponent
507-
try {
508-
component as UIComponent<*>
509-
} catch (castException: ClassCastException) {
510-
throw RuntimeException("When trying to focus, the provided value is not an instance of UIComponent. Make sure you are only using the UIFocus interface to focus UIComponents.")
511-
}
494+
fun <T> focus(component: T) where T : UIComponent<*>, T : UIFocusable {
512495
focusedComponent = component
513496
}
514497

@@ -548,7 +531,8 @@ open class Aether(renderer: UIRenderer) {
548531
for (i in 0 until instance.frames!!.size) {
549532
// UIContainers are what control scrolling, so
550533
// if it is not an instance of it, skip and continue
551-
val container = instance.frames!![i] as? UIContainer<*> ?: continue
534+
@Suppress("UNCHECKED_CAST")
535+
val container = instance.frames!![i] as? UIContainer<UIContainerSheet> ?: continue
552536
if (container.isMouseInsideBounds() && container.expandedHeight > 0f && container.style.overflowY != UIContainerSheet.Overflow.None) {
553537
// Iterate through the frame to see if there are more
554538
// containers with it. If there are, it will pass true

0 commit comments

Comments
 (0)