diff --git a/sprites/Circle.png b/sprites/Circle.png new file mode 100644 index 0000000..1c486c8 Binary files /dev/null and b/sprites/Circle.png differ diff --git a/sprites/Computer.png b/sprites/Computer.png new file mode 100644 index 0000000..53be80d Binary files /dev/null and b/sprites/Computer.png differ diff --git a/sprites/DefaultNode.png b/sprites/DefaultNode.png new file mode 100644 index 0000000..16df145 Binary files /dev/null and b/sprites/DefaultNode.png differ diff --git a/sprites/Screen.png b/sprites/Screen.png index 41113b1..92d0d65 100644 Binary files a/sprites/Screen.png and b/sprites/Screen.png differ diff --git a/src/main/resources/ocelot/desktop/spritesheet.png b/src/main/resources/ocelot/desktop/spritesheet.png index d45259a..290b6ee 100644 Binary files a/src/main/resources/ocelot/desktop/spritesheet.png and b/src/main/resources/ocelot/desktop/spritesheet.png differ diff --git a/src/main/resources/ocelot/desktop/spritesheet.txt b/src/main/resources/ocelot/desktop/spritesheet.txt index e91334f..f276891 100644 --- a/src/main/resources/ocelot/desktop/spritesheet.txt +++ b/src/main/resources/ocelot/desktop/spritesheet.txt @@ -1,7 +1,10 @@ -Border 122 24 2 8 -CornerBL 114 0 8 8 -CornerBR 114 8 8 8 -CornerTL 114 16 8 8 -CornerTR 114 24 8 8 -Empty 124 24 1 1 -Screen 0 0 114 125 +Border 96 8 2 8 +Circle 0 0 24 24 +Computer 24 0 24 24 +CornerBL 96 0 8 8 +CornerBR 104 0 8 8 +CornerTL 112 0 8 8 +CornerTR 120 0 8 8 +DefaultNode 48 0 24 24 +Empty 98 8 1 1 +Screen 72 0 24 24 diff --git a/src/main/scala/ocelot/desktop/geometry/Vector2D.scala b/src/main/scala/ocelot/desktop/geometry/Vector2D.scala index 84f8904..ddbf704 100644 --- a/src/main/scala/ocelot/desktop/geometry/Vector2D.scala +++ b/src/main/scala/ocelot/desktop/geometry/Vector2D.scala @@ -51,6 +51,8 @@ case class Vector2D(var x: Float, var y: Float) { if (l > 0) this /= this.length } + def rounded(): Vector2D = Vector2D(x.round, y.round) + def angle: Float = math.atan2(this.y, this.x).asInstanceOf def angle(that: Vector2D): Float = angle - that.angle diff --git a/src/main/scala/ocelot/desktop/graphics/Graphics.scala b/src/main/scala/ocelot/desktop/graphics/Graphics.scala index 4b686a6..6b35f08 100644 --- a/src/main/scala/ocelot/desktop/graphics/Graphics.scala +++ b/src/main/scala/ocelot/desktop/graphics/Graphics.scala @@ -166,10 +166,10 @@ class Graphics extends Logging { z += 2 } - def sprite(name: String, x: Float, y: Float, width: Float, height: Float, rotation: Float = 0f): Unit = { + def sprite(name: String, x: Float, y: Float, width: Float, height: Float, rotation: Float = 0f, color: Color = RGBAColorNorm(1f, 1f, 1f)): Unit = { flush() sprite = name - background = RGBAColorNorm(1f, 1f, 1f, 1f) + foreground = color rect(x, y, width, height, rotation) } diff --git a/src/main/scala/ocelot/desktop/ui/UiHandler.scala b/src/main/scala/ocelot/desktop/ui/UiHandler.scala index b22c2c1..57316d6 100644 --- a/src/main/scala/ocelot/desktop/ui/UiHandler.scala +++ b/src/main/scala/ocelot/desktop/ui/UiHandler.scala @@ -72,7 +72,6 @@ object UiHandler extends Logging { GLFW.glfwSetCharCallback(window, KeyHandler.handleChar) GLFW.glfwSetMouseButtonCallback(window, MouseHandler.handleMouseButton) GLFW.glfwSetScrollCallback(window, ScrollHandler.handleScroll) - // GLFW.glfwSetWindowSizeCallback(window, handleResize) GLFW.glfwSetWindowRefreshCallback(window, handleRefresh) GLFW.glfwSetWindowFocusCallback(window, handleFocus) GLFW.glfwSetInputMode(window, GLFW.GLFW_STICKY_KEYS, GLFW.GLFW_FALSE) diff --git a/src/main/scala/ocelot/desktop/ui/layout/LinearLayout.scala b/src/main/scala/ocelot/desktop/ui/layout/LinearLayout.scala index 56216f6..1f2ccec 100644 --- a/src/main/scala/ocelot/desktop/ui/layout/LinearLayout.scala +++ b/src/main/scala/ocelot/desktop/ui/layout/LinearLayout.scala @@ -139,6 +139,8 @@ class LinearLayout(widget: Widget, case (Orientation.Horizontal, AlignItems.Center) => child.position.y = widget.position.y + widget.size.height / 2 - child.size.height / 2 } + + child.position = child.position.rounded() } } } diff --git a/src/main/scala/ocelot/desktop/ui/widget/CenterBox.scala b/src/main/scala/ocelot/desktop/ui/widget/CenterBox.scala new file mode 100644 index 0000000..e1638d3 --- /dev/null +++ b/src/main/scala/ocelot/desktop/ui/widget/CenterBox.scala @@ -0,0 +1,29 @@ +package ocelot.desktop.ui.widget + +import ocelot.desktop.color.{Color, RGBAColorNorm} +import ocelot.desktop.geometry.Size2D +import ocelot.desktop.graphics.Graphics +import ocelot.desktop.ui.layout.{AlignItems, JustifyContent, Layout, LinearLayout} +import ocelot.desktop.util.Orientation + +class CenterBox(inner: Widget, + orientation: Orientation.Value = Orientation.Vertical, + background: Color = RGBAColorNorm(1f, 1f, 1f, 0f)) + extends Widget { + override val children: Array[Widget] = Array[Widget](inner) + override protected val layout: Layout = new LinearLayout(this, orientation, alignItems = AlignItems.Center, justifyContent = JustifyContent.Center) + + maximumSize = Size2D.Inf + + override def updateBounds(min: Size2D, max: Size2D): Unit = { + minimumSize = min + } + + override def draw(g: Graphics): Unit = { + g.sprite = "Empty" + g.foreground = background + g.rect(position.x, position.y, size.width, size.height) + + super.draw(g) + } +} diff --git a/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala index c91cbee..a8fdec3 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala @@ -1,5 +1,6 @@ package ocelot.desktop.ui.widget +import ocelot.desktop.color.RGBAColor import ocelot.desktop.ui.layout.LinearLayout import totoro.ocelot.brain.entity.Screen @@ -10,5 +11,5 @@ class RootWidget(screen: Screen) extends Widget { children :+= new ScrollView(new WorkspaceView) - children :+= new ScrollView(screenWidget) + children :+= new ScrollView(new CenterBox(screenWidget, background = RGBAColor(30, 30, 30))) } diff --git a/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala index e45edba..bc9779a 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala @@ -1,6 +1,6 @@ package ocelot.desktop.ui.widget -import ocelot.desktop.color.IntColor +import ocelot.desktop.color.{IntColor, RGBAColor} import ocelot.desktop.geometry.{Size2D, Vector2D} import ocelot.desktop.graphics.Graphics import ocelot.desktop.ui.event.{KeyEvent, MouseEvent, ScrollEvent} @@ -74,6 +74,9 @@ class ScreenWidget(screen: Screen) extends Widget with Logging { } override def update(): Unit = { + super.update() + UiHandler.windowTitle = f"Ocelot Desktop [FPS: ${UiHandler.fps}%2.3f]" + val currentMousePos = convertMousePos(UiHandler.mousePosition) if (!checkBounds(currentMousePos) || currentMousePos == lastMousePos) return @@ -82,8 +85,6 @@ class ScreenWidget(screen: Screen) extends Widget with Logging { for (button <- MouseHandler.pressedButtons) { screen.mouseDrag(lastMousePos.x, lastMousePos.y, button.id, User("myself")) } - - UiHandler.windowTitle = f"Ocelot Desktop [FPS: ${UiHandler.fps}%2.3f]" } override def draw(g: Graphics): Unit = { @@ -92,7 +93,7 @@ class ScreenWidget(screen: Screen) extends Widget with Logging { val w = fontSize * width / 2f + 32 val h = fontSize * height + 32 - g.foreground = IntColor(0x333333) + g.foreground = RGBAColor(30, 30, 30) g.sprite = "Empty" g.rect(sx, sy, w, h) @@ -182,6 +183,8 @@ class ScreenWidget(screen: Screen) extends Widget with Logging { this.width = width this.height = height + minimumSize = Size2D(width * fontSize / 2f + 32, height * fontSize + 32) + maximumSize = minimumSize size = Size2D.Zero } diff --git a/src/main/scala/ocelot/desktop/ui/widget/ScrollView.scala b/src/main/scala/ocelot/desktop/ui/widget/ScrollView.scala index 33d9b8e..ae73cc3 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/ScrollView.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/ScrollView.scala @@ -71,7 +71,7 @@ class ScrollView(inner: Widget) extends Widget with Logging { private var hAnimDir = -1 override def update(): Unit = { - updateChildren() + super.update() val mousePos = UiHandler.mousePosition diff --git a/src/main/scala/ocelot/desktop/ui/widget/Widget.scala b/src/main/scala/ocelot/desktop/ui/widget/Widget.scala index d82190c..d359889 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/Widget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/Widget.scala @@ -2,7 +2,7 @@ package ocelot.desktop.ui.widget import ocelot.desktop.geometry.{Size2D, Vector2D} import ocelot.desktop.graphics.Graphics -import ocelot.desktop.ui.EventHandlers +import ocelot.desktop.ui.{EventHandlers, UiHandler} import ocelot.desktop.ui.event.Event import ocelot.desktop.ui.layout.Layout @@ -10,8 +10,10 @@ class Widget { val eventHandlers = new EventHandlers protected var _children: Array[Widget] = Array[Widget]() + protected var parent: Option[Widget] = None protected val layout: Layout = new Layout(this) protected var _size: Size2D = Size2D(0, 0) + protected var oldSize: Size2D = _size.copy() var position: Vector2D = Vector2D(0, 0) var minimumSize: Size2D = Size2D.Zero @@ -33,7 +35,7 @@ class Widget { if (clamped != _size) { recalculateBounds() - _size = clamped + _size = clamped.copy() relayout() } } @@ -42,6 +44,10 @@ class Widget { def children_=(value: Array[Widget]): Unit = { _children = value + + for (child <- _children) + child.parent = Some(this) + recalculateBounds() size = _size relayout() @@ -60,6 +66,11 @@ class Widget { } def update(): Unit = { + if (_size != oldSize) { + UiHandler.root.relayout() // FIXME + oldSize = _size.copy() + } + updateChildren() } diff --git a/src/main/scala/ocelot/desktop/ui/widget/WorkspaceView.scala b/src/main/scala/ocelot/desktop/ui/widget/WorkspaceView.scala index 140d3b2..76f7ef1 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/WorkspaceView.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/WorkspaceView.scala @@ -3,23 +3,17 @@ package ocelot.desktop.ui.widget import ocelot.desktop.color.RGBAColor import ocelot.desktop.geometry.Size2D import ocelot.desktop.graphics.Graphics -import ocelot.desktop.ui.workspace.{Node, ScreenNode} +import ocelot.desktop.ui.workspace._ import scala.collection.mutable.ArrayBuffer class WorkspaceView extends Widget { - private val nodes = new ArrayBuffer[Node] - - for (i <- 1 to 20) { - nodes += new ScreenNode { - name = s"Screen $i" - } - } + private val nodes = ArrayBuffer[Node](new ComputerNode, new ScreenNode) recalculateBounds() override def draw(g: Graphics): Unit = { - g.foreground = RGBAColor(30, 30, 30) + g.foreground = RGBAColor(20, 20, 20) g.rect(position.x, position.y, size.width, size.height) for ((node, i) <- nodes.zipWithIndex) { @@ -31,18 +25,18 @@ class WorkspaceView extends Widget { g.save() g.translate(position.x, position.y + 32 * idx) - if (idx > 0) { - // draw separator - g.foreground = RGBAColor(50, 50, 50) - g.rect(0, 0, size.width, 1) - } + g.foreground = RGBAColor(50, 50, 50) + g.rect(0, 31, size.width, 1) - g.background = RGBAColor(30, 30, 30) - g.foreground = RGBAColor(255, 255, 255) + g.background = RGBAColor(20, 20, 20) + g.foreground = RGBAColor(230, 230, 230) g.text(40, 8, node.name) - g.sprite("Screen", 8, 6, 24, 24) + g.sprite(node.icon, 8, 6, 24, 24) + g.sprite("Circle", size.width - 32, 6, 24, 24, color = RGBAColor(117, 72, 94)) + g.sprite = "Empty" + g.rect(size.width - 22, 0, 4, 32) g.restore() } diff --git a/src/main/scala/ocelot/desktop/ui/workspace/ComputerNode.scala b/src/main/scala/ocelot/desktop/ui/workspace/ComputerNode.scala new file mode 100644 index 0000000..8eba417 --- /dev/null +++ b/src/main/scala/ocelot/desktop/ui/workspace/ComputerNode.scala @@ -0,0 +1,6 @@ +package ocelot.desktop.ui.workspace + +class ComputerNode extends Node { + override var name: String = "Computer" + override val icon: String = "Computer" +} diff --git a/src/main/scala/ocelot/desktop/ui/workspace/Node.scala b/src/main/scala/ocelot/desktop/ui/workspace/Node.scala index 98aae77..009fe60 100644 --- a/src/main/scala/ocelot/desktop/ui/workspace/Node.scala +++ b/src/main/scala/ocelot/desktop/ui/workspace/Node.scala @@ -2,4 +2,5 @@ package ocelot.desktop.ui.workspace trait Node { var name: String + val icon: String = "DefaultNode" } diff --git a/src/main/scala/ocelot/desktop/ui/workspace/ScreenNode.scala b/src/main/scala/ocelot/desktop/ui/workspace/ScreenNode.scala index f50f0b5..a3740ff 100644 --- a/src/main/scala/ocelot/desktop/ui/workspace/ScreenNode.scala +++ b/src/main/scala/ocelot/desktop/ui/workspace/ScreenNode.scala @@ -2,4 +2,5 @@ package ocelot.desktop.ui.workspace class ScreenNode extends Node { override var name: String = "Screen" + override val icon: String = "Screen" }