Skip to content

Commit

Permalink
Merge pull request #1 from NeptuneMC/stylesheets
Browse files Browse the repository at this point in the history
Basic Stylesheets
  • Loading branch information
Hobbyshop authored Jun 8, 2024
2 parents ac95c8a + a554df9 commit 84e348a
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 15 deletions.
12 changes: 11 additions & 1 deletion src/main/kotlin/com/neptuneclient/voidui/event/events/events.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,14 @@ class MouseClickedEvent(val button: Int, val x: Float, val y: Float) : Event()
* @param x The x position of the mouse.
* @param y The y position of the mouse.
*/
class MouseReleasedEvent(val button: Int, val x: Float, val y: Float) : Event()
class MouseReleasedEvent(val button: Int, val x: Float, val y: Float) : Event()

/**
* Called whenever the mouse is moved.
*
* **This event needs to be called when implementing the library.**
*
* @param x The x position of the mouse.
* @param y The y position of the mouse.
*/
class MouseMovementEvent(val x: Float, val y: Float) : Event()
27 changes: 27 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/framework/State.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.neptuneclient.voidui.framework

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
* A property delegation which rebuilds the widget tree once its value changes.
*
* @param initialValue The initial value of the state property.
* @param onStateChange The action which is run when the value changes. See [Widget.state] for more info.
*/
class State<T>(initialValue: T, private val onStateChange: (T) -> Unit) : ReadWriteProperty<Any?, T> {

/**
* Holds the actual value of the property.
*/
var value: T = initialValue
private set

override fun getValue(thisRef: Any?, property: KProperty<*>) = value

override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
onStateChange(value)
}

}
3 changes: 1 addition & 2 deletions src/main/kotlin/com/neptuneclient/voidui/framework/Widget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.neptuneclient.voidui.event.Event
import com.neptuneclient.voidui.rendering.RenderObject
import com.neptuneclient.voidui.theme.Theme
import com.neptuneclient.voidui.widgets.Placeholder
import kotlin.properties.Delegates
import kotlin.reflect.KClass

/**
Expand Down Expand Up @@ -117,7 +116,7 @@ abstract class Widget {
/**
* Defines a stateful variable, which rebuilds the widget once it changes its value.
*/
fun <T> state(initialValue: T) = Delegates.observable(initialValue) { _, _, _ ->
fun <T> state(initialValue: T) = State(initialValue) {
// temp
screen.remove()
screen.init()
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/theme/StyleSheet.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.neptuneclient.voidui.theme

/**
* The pure reason for this interface is, so that all stylesheet classes have the same superclass.
*/
interface StyleSheet
45 changes: 45 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/theme/StyledWidget.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.neptuneclient.voidui.theme

import com.neptuneclient.voidui.event.events.MouseMovementEvent
import com.neptuneclient.voidui.framework.Screen
import com.neptuneclient.voidui.framework.Widget

abstract class StyledWidget<T : StyleSheet> : Widget() {

private lateinit var styles: Styles<T>

private var stylesheetState: T? by state(null)

protected val stylesheet: T
get() = stylesheetState!!

override fun init(screen: Screen, parent: Widget) {
try {
this.voidUI = screen.voidUI
this.screen = screen
styles = voidUI.theme.getStyles(this::class)
checkStylesheetUpdate()

root = build()
root!!.init(screen, this)
} catch (t: Throwable) {
t.printStackTrace()
}

registerEventAction(MouseMovementEvent::class) {
//println("${hovered()} && ${stylesheetState == styles.hovered}")
checkStylesheetUpdate()
}
}

private fun checkStylesheetUpdate() {
if (stylesheetState != styles.hovered && hovered()) {
//println("hovered")
stylesheetState = styles.hovered
} else if (!hovered() && stylesheetState != styles.regular) {
//println("regular")
stylesheetState = styles.regular
}
}

}
16 changes: 16 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/theme/Styles.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.neptuneclient.voidui.theme

/**
* A data class which holds multiple stylesheets in different states.
*
* @param regular The regular style of the widget.
* @param hovered The style when the widget is hovered.
* @param active The style when the widget is clicked.
*
* TODO add transitions
*/
data class Styles<T : StyleSheet>(
val regular: T,
val hovered: T = regular,
val active: T = hovered
)
36 changes: 34 additions & 2 deletions src/main/kotlin/com/neptuneclient/voidui/theme/Theme.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
package com.neptuneclient.voidui.theme

import com.neptuneclient.voidui.theme.stylesheets.PanelStyleSheet
import com.neptuneclient.voidui.ui.Panel
import kotlin.reflect.KClass

/**
* Holds values which define the general style of the whole library.
*/
abstract class Theme(
val defaultStyles: DefaultStyles
)
val defaultStyles: DefaultStyles,

panelStyles: Styles<PanelStyleSheet>
) {

/**
* A map which holds every styled widget type and its adjacent styles.
*/
private val styles = mapOf(
panelStyles to Panel::class
)

/**
* Returns the styles of the given styled widget.
*
* @param widget The widget class.
*
* @return The styles of the given element.
*
* @throws IllegalArgumentException If the given widget class has no style sheet in the registry map.
*/
fun <T : StyleSheet> getStyles(widget: KClass<out StyledWidget<T>>): Styles<T> {
for ((k, v) in styles) {
if (v != widget) continue
return k as Styles<T>
}
throw IllegalArgumentException("No style sheet found for type: ${widget.simpleName}")
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.neptuneclient.voidui.theme.stylesheets

import com.neptuneclient.voidui.objects.Border
import com.neptuneclient.voidui.objects.CornerRadius
import com.neptuneclient.voidui.theme.StyleSheet
import java.awt.Color

data class PanelStyleSheet(
val color: Color,
val border: Border = Border(0f, Color(0)),
val cornerRadius: CornerRadius = CornerRadius.zero,
) : StyleSheet
33 changes: 33 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/ui/Panel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.neptuneclient.voidui.ui

import com.neptuneclient.voidui.framework.Widget
import com.neptuneclient.voidui.objects.EdgeInsets
import com.neptuneclient.voidui.theme.StyledWidget
import com.neptuneclient.voidui.theme.stylesheets.PanelStyleSheet
import com.neptuneclient.voidui.widgets.Container

/**
* TODO
*
* @param child The child widget inside the panel.
* @param margin The margin around the panel.
* @param padding The padding inside the panel.
*/
class Panel(
private val child: Widget,
private val margin: EdgeInsets = EdgeInsets.zero,
private val padding: EdgeInsets = EdgeInsets.zero
) : StyledWidget<PanelStyleSheet>() {

override fun build(): Widget {
return Container(
color = stylesheet.color,
border = stylesheet.border,
cornerRadius = stylesheet.cornerRadius,
margin = margin,
padding = padding,
child = child
)
}

}
11 changes: 5 additions & 6 deletions src/test/kotlin/com/neptuneclient/voidui/tests/ScreenTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.neptuneclient.voidui.objects.EdgeInsets
import com.neptuneclient.voidui.objects.TextAlign
import com.neptuneclient.voidui.shaders.ShaderProgram
import com.neptuneclient.voidui.shaders.vec3
import com.neptuneclient.voidui.ui.Panel
import com.neptuneclient.voidui.utils.image
import com.neptuneclient.voidui.utils.path
import com.neptuneclient.voidui.widgets.*
Expand Down Expand Up @@ -74,14 +75,12 @@ class TestScreen(voidUI: VoidUI) : Screen(voidUI) {
"testColor" to vec3(1.0f, 0.5f, 0.0f)
)
),
Center(
Container(
/*Center(
Panel(
padding = EdgeInsets.all(20f),
color = Color(20, 24, 35),
cornerRadius = CornerRadius.all(10f),
child = Text("Hello World")
)
)
)*/
)
)
)
Expand All @@ -103,7 +102,7 @@ private val template = Template { slot ->
val voidUI = VoidUI(TestRenderer(), TestTheme(), Settings(centeredScreen = true, useShaders = true), /*template*/)

fun main() {
val screen = MainMenu(voidUI)
val screen = TestScreen(voidUI)
screen.init()

if (voidUI.renderer is TestRenderer) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.neptuneclient.voidui.tests

import com.neptuneclient.voidui.event.events.MouseMovementEvent
import com.neptuneclient.voidui.rendering.Renderer
import com.neptuneclient.voidui.framework.Offset
import com.neptuneclient.voidui.framework.Size
Expand Down Expand Up @@ -69,6 +70,10 @@ class TestRenderer : Renderer {
mouseEvent(button, action, x, y)
}

GLFW.glfwSetCursorPosCallback(window) { _, x, y ->
MouseMovementEvent(x.toFloat(), y.toFloat()).call(voidUI)
}

MemoryStack.stackPush().use { stack ->
val fWidth = stack.mallocInt(1)
val fHeight = stack.mallocInt(1)
Expand Down
19 changes: 15 additions & 4 deletions src/test/kotlin/com/neptuneclient/voidui/tests/TestTheme.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
package com.neptuneclient.voidui.tests

import com.neptuneclient.voidui.objects.Border
import com.neptuneclient.voidui.objects.CornerRadius
import com.neptuneclient.voidui.theme.DefaultStyles
import com.neptuneclient.voidui.theme.ImageStyle
import com.neptuneclient.voidui.theme.TextStyle
import com.neptuneclient.voidui.theme.Theme
import com.neptuneclient.voidui.theme.*
import com.neptuneclient.voidui.theme.stylesheets.PanelStyleSheet
import com.neptuneclient.voidui.utils.Font
import java.awt.Color
import java.nio.file.Path

class TestTheme : Theme(
panelStyles = Styles(
regular = PanelStyleSheet(
color = Color(39, 41, 53),
border = Border(1f, Color(255, 255, 255, 38)),
cornerRadius = CornerRadius.all(10f)
),
hovered = PanelStyleSheet(
color = Color(39, 41, 255),
border = Border(1f, Color(255, 255, 255, 38)),
cornerRadius = CornerRadius.all(10f)
)
),
defaultStyles = DefaultStyles(
regularText = TextStyle(
font = Font("WorkSans", Path.of("fonts/WorkSans-Regular.ttf")),
Expand Down

0 comments on commit 84e348a

Please sign in to comment.