mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2026-01-09 04:32:37 +01:00
Major node selector improvements
This commit is contained in:
parent
e13b522030
commit
2f4b7dd596
BIN
sprites/nodes/NewNode.png
Normal file
BIN
sprites/nodes/NewNode.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 B |
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
@ -77,17 +77,18 @@ nodes/Computer 339 180 16 16
|
||||
nodes/ComputerActivityOverlay 356 180 16 16
|
||||
nodes/ComputerErrorOverlay 373 180 16 16
|
||||
nodes/ComputerOnOverlay 390 180 16 16
|
||||
nodes/Screen 407 180 16 16
|
||||
nodes/ScreenOnOverlay 424 180 16 16
|
||||
nodes/NewNode 407 180 16 16
|
||||
nodes/Screen 424 180 16 16
|
||||
nodes/ScreenOnOverlay 441 180 16 16
|
||||
screen/BorderB 310 197 2 8
|
||||
screen/BorderT 307 197 2 10
|
||||
screen/CornerBL 459 180 8 8
|
||||
screen/CornerBR 468 180 8 8
|
||||
screen/CornerTL 441 180 8 10
|
||||
screen/CornerTR 450 180 8 10
|
||||
screen/CornerBL 476 180 8 8
|
||||
screen/CornerBR 485 180 8 8
|
||||
screen/CornerTL 458 180 8 10
|
||||
screen/CornerTR 467 180 8 10
|
||||
window/BorderDark 333 197 1 4
|
||||
window/BorderLight 335 197 1 4
|
||||
window/CloseButton 477 180 7 6
|
||||
window/CloseButton 494 180 7 6
|
||||
window/CornerBL 313 197 4 4
|
||||
window/CornerBR 318 197 4 4
|
||||
window/CornerTL 323 197 4 4
|
||||
|
||||
@ -7,6 +7,8 @@ object Rect2D {
|
||||
case class Rect2D(x: Float, y: Float, w: Float, h: Float) {
|
||||
def contains(p: Vector2D): Boolean = p.x >= x && p.y >= y && p.x <= x + w && p.y <= y + h
|
||||
|
||||
def contains(r: Rect2D): Boolean = r.x >= x && r.y >= y && r.x + r.w <= x + w && r.y + r.h <= y + h
|
||||
|
||||
def origin: Vector2D = Vector2D(x, y)
|
||||
|
||||
def min: Vector2D = origin
|
||||
|
||||
@ -3,8 +3,8 @@ package ocelot.desktop.ui.widget
|
||||
import ocelot.desktop.color.RGBAColorNorm
|
||||
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
|
||||
import ocelot.desktop.graphics.Graphics
|
||||
import ocelot.desktop.ui.{KeyEvents, UiHandler}
|
||||
import ocelot.desktop.ui.event.{MouseEvent, ScrollEvent}
|
||||
import ocelot.desktop.ui.{KeyEvents, UiHandler}
|
||||
import ocelot.desktop.util.Logging
|
||||
|
||||
class ScrollView(val inner: Widget) extends Widget with Logging {
|
||||
@ -114,13 +114,13 @@ class ScrollView(val inner: Widget) extends Widget with Logging {
|
||||
private def drawVThumb(g: Graphics): Unit = {
|
||||
val b = vThumbBounds
|
||||
g.rect(position.x + size.width - 11, position.y, 10, size.height, RGBAColorNorm(0.9f, 0.9f, 0.9f, vAnim * 0.15f))
|
||||
g.rect(b.x + 3, b.y, b.w - 6, b.h, RGBAColorNorm(0.6f, 0.15f, 0.35f, vAnim * 0.5f + 0.4f))
|
||||
g.rect(b.x + 3, b.y, b.w - 6, b.h, RGBAColorNorm(0.8f, 0.25f, 0.45f, vAnim * 0.5f + 0.4f))
|
||||
}
|
||||
|
||||
private def drawHThumb(g: Graphics): Unit = {
|
||||
val b = hThumbBounds
|
||||
g.rect(position.x, position.y + size.height - 11, size.width - 12, 10, RGBAColorNorm(0.9f, 0.9f, 0.9f, hAnim * 0.15f))
|
||||
g.rect(b.x, b.y + 3, b.w, b.h - 6, RGBAColorNorm(0.6f, 0.15f, 0.35f, hAnim * 0.5f + 0.4f))
|
||||
g.rect(b.x, b.y + 3, b.w, b.h - 6, RGBAColorNorm(0.8f, 0.25f, 0.45f, hAnim * 0.5f + 0.4f))
|
||||
}
|
||||
|
||||
private def maxXOffset: Float = inner.size.width - size.width
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package ocelot.desktop.ui.window
|
||||
|
||||
import ocelot.desktop.color.RGBAColorNorm
|
||||
import ocelot.desktop.geometry.{Padding2D, Rect2D}
|
||||
import ocelot.desktop.graphics.Graphics
|
||||
import ocelot.desktop.ui.UiHandler
|
||||
@ -7,7 +8,7 @@ import ocelot.desktop.ui.event.CloseWindowEvent
|
||||
import ocelot.desktop.ui.layout.LinearLayout
|
||||
import ocelot.desktop.ui.widget.{PaddingBox, ScrollView, Widget}
|
||||
import ocelot.desktop.ui.workspace.{NodeRegistry, NodeTypeWidget}
|
||||
import ocelot.desktop.util.animation.UnitAnimation
|
||||
import ocelot.desktop.util.animation.{ColorAnimation, UnitAnimation}
|
||||
import ocelot.desktop.util.{DrawUtils, Logging, Orientation}
|
||||
|
||||
class NodeSelector extends Window with Logging {
|
||||
@ -52,10 +53,14 @@ class NodeSelector extends Window with Logging {
|
||||
private var heightAnimation: UnitAnimation = _
|
||||
private var animationTime: Float = 0f
|
||||
|
||||
private var FinalRingColor: RGBAColorNorm = RGBAColorNorm(0.3f, 0.5f, 0.4f)
|
||||
val colorAnimation: ColorAnimation = new ColorAnimation(FinalRingColor.copy(a = 0f), speed = 3f)
|
||||
|
||||
def isShown: Boolean = _isShown
|
||||
|
||||
override def update(): Unit = {
|
||||
if (isShown) {
|
||||
colorAnimation.update()
|
||||
heightAnimation.update()
|
||||
|
||||
if (isClosing) {
|
||||
@ -81,7 +86,9 @@ class NodeSelector extends Window with Logging {
|
||||
|
||||
override def draw(g: Graphics): Unit = {
|
||||
if (!isShown) return
|
||||
DrawUtils.windowWithShadow(g, position.x, position.y, size.width, size.height, 0.5f, 0.3f)
|
||||
|
||||
g.rect(position.x, position.y, size.width, size.height, RGBAColorNorm(0, 0, 0, colorAnimation.getHSVA.a * 0.4f))
|
||||
DrawUtils.ring(g, position.x, position.y, size.width, size.height, thickness = 1, color = colorAnimation.color)
|
||||
|
||||
super.draw(g)
|
||||
}
|
||||
@ -113,6 +120,8 @@ class NodeSelector extends Window with Logging {
|
||||
override def show(): Unit = {
|
||||
if (isClosing) return;
|
||||
|
||||
colorAnimation.goto(FinalRingColor.copy(a = 1f))
|
||||
|
||||
_isOpen = true
|
||||
_isFocused = true
|
||||
_isShown = true
|
||||
@ -125,6 +134,8 @@ class NodeSelector extends Window with Logging {
|
||||
override def hide(): Unit = {
|
||||
if (isClosing) return;
|
||||
|
||||
colorAnimation.goto(FinalRingColor.copy(a = 0f))
|
||||
|
||||
heightAnimation = UnitAnimation.easeInQuad(0.25f)
|
||||
heightAnimation.time = 1
|
||||
heightAnimation.goDown()
|
||||
|
||||
@ -9,7 +9,15 @@ object NodeRegistry {
|
||||
types += t;
|
||||
}
|
||||
|
||||
for (i <- 0 to 100) {
|
||||
register(NodeType("Screen" + i, "nodes/Screen", () => new ScreenNode))
|
||||
for (i <- 0 to 79) {
|
||||
register(NodeType("Screen" + i, "nodes/Screen", i % 4, () => new ScreenNode))
|
||||
}
|
||||
|
||||
for (i <- 0 to 3) {
|
||||
register(NodeType("Screen" + i, "nodes/Screen", i % 4, () => new ScreenNode))
|
||||
}
|
||||
|
||||
for (i <- 0 to 3) {
|
||||
register(NodeType("Computer" + i, "nodes/Computer", i % 4, () => new ScreenNode))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
package ocelot.desktop.ui.workspace
|
||||
|
||||
case class NodeType(name: String, icon: String, factory: () => Node) extends Ordered[NodeType] {
|
||||
case class NodeType(name: String, icon: String, tier: Int, factory: () => Node) extends Ordered[NodeType] {
|
||||
override def compare(that: NodeType): Int = this.name.compare(that.name)
|
||||
}
|
||||
@ -3,6 +3,7 @@ package ocelot.desktop.ui.workspace
|
||||
import ocelot.desktop.geometry.Size2D
|
||||
import ocelot.desktop.graphics.Graphics
|
||||
import ocelot.desktop.ui.widget.Widget
|
||||
import ocelot.desktop.util.TierColor
|
||||
|
||||
class NodeTypeWidget(nodeType: NodeType) extends Widget {
|
||||
override def minimumSize: Size2D = Size2D(68, 68)
|
||||
@ -12,6 +13,6 @@ class NodeTypeWidget(nodeType: NodeType) extends Widget {
|
||||
size = maximumSize
|
||||
|
||||
override def draw(g: Graphics): Unit = {
|
||||
g.sprite(nodeType.icon, position.x + 2, position.y + 2, size.width - 4, size.height - 4)
|
||||
g.sprite(nodeType.icon, position.x + 2, position.y + 2, size.width - 4, size.height - 4, TierColor.get(nodeType.tier))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package ocelot.desktop.ui.workspace
|
||||
|
||||
import ocelot.desktop.OcelotDesktop
|
||||
import ocelot.desktop.color.RGBAColor
|
||||
import ocelot.desktop.color.{Color, RGBAColor}
|
||||
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
|
||||
import ocelot.desktop.graphics.Graphics
|
||||
import ocelot.desktop.ui.event._
|
||||
@ -19,8 +19,9 @@ class WorkspaceView extends Widget with DragHandler with ClickHandler {
|
||||
private var nodeGrabPoint = Vector2D(0, 0)
|
||||
private var cameraOffset = Vector2D(0, 0)
|
||||
|
||||
private val nodeSelector: NodeSelector = new NodeSelector
|
||||
private val windowPool: WindowPool = new WindowPool
|
||||
private var newNodePos = Vector2D(0, 0)
|
||||
private val nodeSelector = new NodeSelector
|
||||
private val windowPool = new WindowPool
|
||||
children +:= windowPool
|
||||
|
||||
override def minimumSize: Size2D = Size2D(200, 200)
|
||||
@ -67,12 +68,31 @@ class WorkspaceView extends Widget with DragHandler with ClickHandler {
|
||||
if (nodeSelector.isShown) {
|
||||
nodeSelector.hide()
|
||||
} else {
|
||||
windowPool.handleEvent(OpenWindowEvent(nodeSelector))
|
||||
openSelector(pos)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private def openSelector(p: Vector2D): Unit = {
|
||||
val pos = p - Vector2D(32, 32)
|
||||
windowPool.handleEvent(OpenWindowEvent(nodeSelector))
|
||||
newNodePos = pos - cameraOffset
|
||||
|
||||
val size = Size2D(nodeSelector.maximumSize.width, 250)
|
||||
|
||||
val offsets = Array(
|
||||
Vector2D(-size.width / 2 + 40, 100),
|
||||
Vector2D(-size.width - 100, -size.height / 2 + 40),
|
||||
Vector2D(100, -size.height / 2 + 40),
|
||||
Vector2D(-size.width / 2 + 40, -size.height - 100),
|
||||
)
|
||||
|
||||
for (offset <- offsets) {
|
||||
nodeSelector.position = (p + offset).max(Vector2D(20, 20)).min(Vector2D(width - size.width - 20, height - size.height - 20))
|
||||
if (!Rect2D(pos.x, pos.y, 64, 64).collides(Rect2D(nodeSelector.position, size))) return
|
||||
}
|
||||
}
|
||||
|
||||
private def checkCollision(node: Node, obstacle: Node): Unit = {
|
||||
val a = node.bounds
|
||||
val b = obstacle.bounds
|
||||
@ -83,7 +103,9 @@ class WorkspaceView extends Widget with DragHandler with ClickHandler {
|
||||
node.position -= penetrationVector
|
||||
}
|
||||
|
||||
private def drawConnection(g: Graphics, a: Rect2D, b: Rect2D, thickness: Float = 4): Unit = {
|
||||
private def drawConnection(g: Graphics, a: Rect2D, b: Rect2D, thickness: Float = 4, col: Color = RGBAColor(150, 150, 150)): Unit = {
|
||||
if (a.collides(b)) return
|
||||
|
||||
val dist = a.distanceTo(b) / 2f
|
||||
|
||||
val addition = if (dist <= 58.885f)
|
||||
@ -96,16 +118,20 @@ class WorkspaceView extends Widget with DragHandler with ClickHandler {
|
||||
val aRect = a.inflate(addition.toFloat)
|
||||
val bRect = b.inflate(addition.toFloat)
|
||||
|
||||
val pairs: Array[(Vector2D, Vector2D)] =
|
||||
for (a <- aRect.centerPoints; b <- bRect.centerPoints)
|
||||
yield (a, b)
|
||||
val aCPInf = aRect.centerPoints
|
||||
val bCPInf = bRect.centerPoints
|
||||
val aCP = a.centerPoints
|
||||
val bCP = b.centerPoints
|
||||
|
||||
val pair = pairs.minBy(pair => (pair._1 - pair._2).length.toInt)
|
||||
val (start, end) = pair
|
||||
val col = RGBAColor(150, 150, 150)
|
||||
g.line(start, end, thickness, col)
|
||||
g.line(start, a.center, thickness, col)
|
||||
g.line(end, b.center, thickness, col)
|
||||
val pairs =
|
||||
for (a <- 0 to 3; b <- 0 to 3)
|
||||
yield (aCP(a), bCP(b), aCPInf(a), bCPInf(b))
|
||||
|
||||
val pair = pairs.minBy(pair => (pair._3 - pair._4).length.toInt)
|
||||
val (aStart, bStart, aEnd, bEnd) = pair
|
||||
g.line(aEnd, bEnd, thickness, col)
|
||||
g.line(aStart, aEnd, thickness, col)
|
||||
g.line(bStart, bEnd, thickness, col)
|
||||
}
|
||||
|
||||
override def draw(g: Graphics): Unit = {
|
||||
@ -129,9 +155,19 @@ class WorkspaceView extends Widget with DragHandler with ClickHandler {
|
||||
g.save()
|
||||
g.translate(cameraOffset.x + position.x, cameraOffset.y + position.y)
|
||||
drawConnection(g, nodes(0).bounds, nodes(1).bounds)
|
||||
|
||||
nodes.foreach(_.draw(g))
|
||||
|
||||
val col = nodeSelector.colorAnimation.color
|
||||
if (nodeSelector.isShown) {
|
||||
g.sprite("nodes/NewNode", newNodePos.x, newNodePos.y, 64, 64, col)
|
||||
}
|
||||
|
||||
g.restore()
|
||||
|
||||
if (nodeSelector.isShown)
|
||||
drawConnection(g, Rect2D(newNodePos.x + cameraOffset.x, newNodePos.y + cameraOffset.y, 64, 64), nodeSelector.bounds, col = col)
|
||||
|
||||
drawChildren(g)
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,13 @@ object DrawUtils {
|
||||
DrawUtils.windowBorder(g, x, y, w, h, RGBAColorNorm(1, 1, 1, backgroundAlpha))
|
||||
}
|
||||
|
||||
def ring(g: Graphics, x: Float, y: Float, w: Float, h: Float, thickness: Float = 4, color: Color = RGBAColor(255, 255, 255)): Unit = {
|
||||
g.rect(x, y, thickness, h, color)
|
||||
g.rect(x + w - thickness, y, thickness, h, color)
|
||||
g.rect(x + thickness, y, w - thickness * 2f, thickness, color)
|
||||
g.rect(x + thickness, y + h - thickness, w - thickness * 2f, thickness, color)
|
||||
}
|
||||
|
||||
def windowBorder(g: Graphics, x: Float, y: Float, w: Float, h: Float,
|
||||
color: Color = RGBAColor(255, 255, 255)): Unit = {
|
||||
g.sprite("window/CornerTL", x, y, 8, 8, color)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user