Skip to content

Commit

Permalink
oh god i documented the entire library please kill me
Browse files Browse the repository at this point in the history
  • Loading branch information
Hobbyshop committed Apr 18, 2024
1 parent bbd0d0b commit c6a1ce1
Show file tree
Hide file tree
Showing 19 changed files with 312 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/main/kotlin/com/neptuneclient/voidui/VoidUI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class VoidUI
* @param renderer The renderer used to draw all components in the screens. Void does not come with a renderer implementation
* out of the box so the user has to create his own implementation.
*
* @param theme The theme used to style UI elements.
* @param theme The theme used to style UI.
*/
constructor(val renderer: Renderer, val theme: Theme) {

Expand Down
29 changes: 29 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/framework/Screen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@ package com.neptuneclient.voidui.framework
import com.neptuneclient.voidui.VoidUI
import com.neptuneclient.voidui.rendering.RenderStack

/**
* A screen which can render widgets.
*
* @param voidUI The instance of void ui.
*/
abstract class Screen(voidUI: VoidUI) : Widget() {

/**
* The render stack used to render the screen.
*/
val renderStack = RenderStack(voidUI.renderer)

init {
super.voidUI = voidUI
}

/**
* Initializes the screen.
*
* **Needs to be called by the user.**
*/
fun init() {
root = build()
root.init(this, this)
Expand All @@ -19,18 +32,34 @@ abstract class Screen(voidUI: VoidUI) : Widget() {
layout(offset, BoxConstraints.loose(size))
}

/**
* Renders a frame of the screen.
*
* **Needs to be called by the user.**
*/
fun render() {
renderStack.render()
}

/**
* Cleans up any resources from the screen.
*
* **Needs to be called by the user.**
*/
override fun remove() {
root.remove()
renderStack.clear()
}

/**
* The width of the screen in pixels.
*/
inline val width
get() = voidUI.renderer.windowWidth()

/**
* The height of the screen in pixels.
*/
inline val height
get() = voidUI.renderer.windowHeight()

Expand Down
83 changes: 82 additions & 1 deletion src/main/kotlin/com/neptuneclient/voidui/framework/Widget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,49 @@ import com.neptuneclient.voidui.widgets.Placeholder
import kotlin.properties.Delegates
import kotlin.reflect.KClass

/**
* The base for every node in the widget tree.
*/
abstract class Widget {

/**
* Quick access to the void ui instance.
*/
lateinit var voidUI: VoidUI

/**
* Quick access to the screen instance.
*/
protected lateinit var screen: Screen

/**
* The offset from the screen origin.
*/
var offset = Offset.zero

/**
* The size of the widget.
*/
var size = Size.zero

/**
* The child widget defined in [build].
*/
protected lateinit var root: Widget

/**
* Builds the widgets children tree.
*
* @return The top of the child tree.
*/
abstract fun build(): Widget

/**
* Initializes the widget.
*
* @param screen The screen in which the widget is initialized.
* @param parent The parent widget.
*/
internal open fun init(screen: Screen, parent: Widget) {
this.voidUI = screen.voidUI
this.screen = screen
Expand All @@ -29,50 +59,101 @@ abstract class Widget {
root.init(screen, this)
}

/**
* This is responsible for setting [offset] and [size] of the widget.
*
* @param parentOffset The offset of the parent widget.
* @param constraints The constraints of the widget's size.
*/
open fun layout(parentOffset: Offset, constraints: BoxConstraints) {
root.layout(parentOffset, constraints)

offset = parentOffset
size = constraints.constrain(root.size)
}

/**
* Cleans up code from the widget when it is removed from the tree.
*/
open fun remove() {
root.remove()
voidUI.eventHandler.unregister(this)
}

/**
* Defines a stateful variable, which rebuilds the widget once it changes it's value.
*/
fun <T> stateOf(initialValue: T) = Delegates.observable(initialValue) { _, _, _ ->
// redo ui
}

/**
* Registers a new event action.
*
* @see com.neptuneclient.voidui.event.EventHandler.register
*/
fun <T : Event> registerEventAction(event: KClass<T>, action: (event: T) -> Unit) {
voidUI.eventHandler.register(event, this, action)
}

}

/**
* A special type of widget which does not build a widget tree but instead renders directly to the screen. These
* types of widgets will be pushed onto the [com.neptuneclient.voidui.rendering.RenderStack] and rendered for
* every frame.
*/
abstract class LeafWidget : Widget() {

/**
* A shortcut to the current theme from the library instance.
*/
protected val theme: Theme
get() = screen.voidUI.theme

/**
* Initializes the widget.
*
* @param screen The screen in which the widget is initialized.
* @param parent The parent widget.
*/
override fun init(screen: Screen, parent: Widget) {
this.voidUI = screen.voidUI
this.screen = screen

screen.renderStack.push(this)
}

/**
* This is responsible for setting [offset] and [size] of the widget.
*
* @param parentOffset The offset of the parent widget.
* @param constraints The constraints of the widget's size.
*/
override fun layout(parentOffset: Offset, constraints: BoxConstraints) {
offset = parentOffset
size = Size(constraints.minWidth, constraints.minHeight)
}

/**
* This method is never called on a leaf widget, that is why it only returns a placeholder widget.
*/
final override fun build(): Widget {
return Placeholder()
}

override fun remove() {}
/**
* Cleans up code from the widget when it is removed from the tree.
*/
override fun remove() {
voidUI.eventHandler.unregister(this)
}

/**
* Renders the widget to the screen.
*
* @param renderer The renderer of the library instance.
*/
abstract fun render(renderer: Renderer)

}
49 changes: 49 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/framework/constraints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,51 @@ package com.neptuneclient.voidui.framework

import com.neptuneclient.voidui.objects.EdgeInsets

/**
* Describes the bounds of a widget.
*
* It contains two boxes, a minimum size of the widget and a maximum size.
*/
data class BoxConstraints(
val minWidth: Float = 0f,
val maxWidth: Float = Float.POSITIVE_INFINITY,
val minHeight: Float = 0f,
val maxHeight: Float = Float.POSITIVE_INFINITY,
) {
companion object {
/**
* Sets both the minimum and maximum size of the constraints.
*
* @param size The size of the constraints.
*/
fun tight(size: Size) = BoxConstraints(size.width, size.width, size.height, size.height)

/**
* Sets both the minimum and maximum size of the constraints.
*
* @param width The optional width of the constraints.
* @param height The optional height of the constraints.
*/
fun tight(width: Float?, height: Float?) = BoxConstraints(
width ?: 0f,
width ?: Float.POSITIVE_INFINITY,
height ?: 0f,
height ?: Float.POSITIVE_INFINITY
)

/**
* Sets only the maximum size of the constraints.
*
* @param size The maximum size.
*/
fun loose(size: Size) = BoxConstraints(0f, size.width, 0f, size.height)

/**
* Sets only the maximum size of the constraints.
*
* @param width The optional maximum width of the constraints.
* @param height The optional maximum height of the constraints.
*/
fun loose(width: Float?, height: Float?) = BoxConstraints(
0f,
width ?: Float.POSITIVE_INFINITY,
Expand All @@ -33,17 +62,34 @@ data class BoxConstraints(
)
}

/**
* Whether the minimum size and the maximum size are the same.
*/
val isTight
get() = minWidth == maxWidth && minHeight == maxHeight

/**
* The biggest possible size within the constraints.
*/
val biggest get() = Size(maxWidth, maxHeight)
/**
* The smallest possible size within the constraints.
*/
val smallest get() = Size(minWidth, minHeight)

/**
* Adjusts the given size object to fit into the constraints.
*/
fun constrain(size: Size) = Size(
size.width.coerceIn(minWidth, maxWidth),
size.height.coerceIn(minHeight, maxHeight)
)

/**
* Subtract the amount of padding from each side of both constraint boxes.
*
* @param padding The given padding.
*/
fun deflate(padding: EdgeInsets) = BoxConstraints(
(minWidth - padding.horizontal).coerceAtLeast(0f),
(maxWidth - padding.horizontal).coerceAtLeast(0f),
Expand All @@ -58,5 +104,8 @@ data class BoxConstraints(
maxHeight.coerceIn(constraints.minHeight, constraints.maxHeight)
)

/**
* Whether the given size object satisfies the constraints.
*/
fun isSatisfiedBy(size: Size) = size.width in minWidth..maxWidth && size.height in minHeight..maxHeight
}
9 changes: 9 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/framework/size.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.neptuneclient.voidui.framework

/**
* Represents the size of a widget.
*
* @param width The width of the widget.
* @param height The width of the height.
*/
data class Size(val width: Float, val height: Float) {
companion object {
val zero = Size(0f, 0f)
Expand All @@ -13,6 +19,9 @@ data class Size(val width: Float, val height: Float) {
operator fun div(other: Size) = Size(width / other.width, height / other.height)
}

/**
* Represents the offset of a widget from the screen origin.
*/
data class Offset(val x: Float, val y: Float) {
companion object {
val zero = Offset(0f, 0f)
Expand Down
10 changes: 10 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/objects/CornerRadius.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.neptuneclient.voidui.objects

/**
* Holds values for corner radius on all four sides.
*/
data class CornerRadius(
val topLeft: Float,
val topRight: Float,
Expand All @@ -8,9 +11,16 @@ data class CornerRadius(
) {

companion object {
/**
* Returns a corner radius object which is the same on all sides.
*/
@JvmStatic
fun all(value: Float) = CornerRadius(value, value, value, value)
}

/**
* Whether all sides of the corner radius is zero.
*/
fun isEmpty() = (topLeft + topRight + bottomLeft + bottomRight) == 0.0f

}
Loading

0 comments on commit c6a1ce1

Please sign in to comment.