UI work
BIN
sprites/Circle.png
Normal file
|
After Width: | Height: | Size: 237 B |
BIN
sprites/Computer.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
sprites/DefaultNode.png
Normal file
|
After Width: | Height: | Size: 192 B |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 3.2 KiB |
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
src/main/scala/ocelot/desktop/ui/widget/CenterBox.scala
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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)))
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
package ocelot.desktop.ui.workspace
|
||||
|
||||
class ComputerNode extends Node {
|
||||
override var name: String = "Computer"
|
||||
override val icon: String = "Computer"
|
||||
}
|
||||
@ -2,4 +2,5 @@ package ocelot.desktop.ui.workspace
|
||||
|
||||
trait Node {
|
||||
var name: String
|
||||
val icon: String = "DefaultNode"
|
||||
}
|
||||
|
||||
@ -2,4 +2,5 @@ package ocelot.desktop.ui.workspace
|
||||
|
||||
class ScreenNode extends Node {
|
||||
override var name: String = "Screen"
|
||||
override val icon: String = "Screen"
|
||||
}
|
||||
|
||||