Require IconSource in all Graphics.sprite overloads

Well, almost. The smoke animation is too weird.
This commit is contained in:
Fingercomp 2025-08-17 16:00:50 +03:00
parent 210f4b1a0c
commit ce2eeaec0a
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37
28 changed files with 304 additions and 238 deletions

View File

@ -2,7 +2,6 @@ package ocelot.desktop.graphics
import ocelot.desktop.color.{Color, RGBAColorNorm} import ocelot.desktop.color.{Color, RGBAColorNorm}
import ocelot.desktop.geometry.{Rect2D, Size2D, Transform2D, Vector2D} import ocelot.desktop.geometry.{Rect2D, Size2D, Transform2D, Vector2D}
import ocelot.desktop.graphics.IconSource.Animation
import ocelot.desktop.graphics.Texture.MinFilteringMode import ocelot.desktop.graphics.Texture.MinFilteringMode
import ocelot.desktop.graphics.mesh.{Mesh2D, MeshInstance2D, MeshVertex2D} import ocelot.desktop.graphics.mesh.{Mesh2D, MeshInstance2D, MeshVertex2D}
import ocelot.desktop.graphics.render.InstanceRenderer import ocelot.desktop.graphics.render.InstanceRenderer
@ -280,74 +279,50 @@ class Graphics(private var width: Int, private var height: Int, private var scal
// I hate scala. Overloaded methods with default arguments are not allowed // I hate scala. Overloaded methods with default arguments are not allowed
def sprite(icon: IconSource, bounds: Rect2D): Unit = { def sprite(icon: IconSource, bounds: Rect2D): Unit = {
sprite(icon.path, bounds.x, bounds.y, bounds.w, bounds.h, Color.White, icon.animation) sprite(icon, bounds.x, bounds.y, bounds.w, bounds.h, Color.White)
} }
def sprite(icon: IconSource, bounds: Rect2D, color: Color): Unit = { def sprite(icon: IconSource, bounds: Rect2D, color: Color): Unit = {
sprite(icon.path, bounds.x, bounds.y, bounds.w, bounds.h, color, icon.animation) sprite(icon, bounds.x, bounds.y, bounds.w, bounds.h, color)
} }
def sprite(icon: IconSource, pos: Vector2D, size: Size2D): Unit = { def sprite(icon: IconSource, pos: Vector2D, size: Size2D): Unit = {
sprite(icon.path, pos.x, pos.y, size.width, size.height, Color.White, icon.animation) sprite(icon, pos.x, pos.y, size.width, size.height, Color.White)
}
def sprite(icon: IconSource, pos: Vector2D, color: Color): Unit = {
sprite(icon, pos.x, pos.y, color)
} }
def sprite(icon: IconSource, pos: Vector2D, size: Size2D, color: Color): Unit = { def sprite(icon: IconSource, pos: Vector2D, size: Size2D, color: Color): Unit = {
sprite(icon.path, pos.x, pos.y, size.width, size.height, color, icon.animation) sprite(icon, pos.x, pos.y, size.width, size.height, color)
} }
def sprite(icon: IconSource, x: Float, y: Float): Unit = { def sprite(icon: IconSource, x: Float, y: Float): Unit = {
sprite(icon.path, x, y, icon.animation) sprite(icon, x, y, Color.White)
} }
def sprite(icon: IconSource, x: Float, y: Float, width: Float, height: Float): Unit = { def sprite(icon: IconSource, x: Float, y: Float, width: Float, height: Float): Unit = {
sprite(icon.path, x, y, width, height, animation = icon.animation) sprite(icon, x, y, width, height, Color.White)
} }
def sprite(icon: IconSource, x: Float, y: Float, width: Float, height: Float, color: Color): Unit = { def sprite(icon: IconSource, x: Float, y: Float, color: Color): Unit = {
sprite(icon.path, x, y, width, height, color, icon.animation) val size = Spritesheet.spriteSize(icon.path)
sprite(icon, x, y, size.width, size.height, color)
} }
def sprite(name: String, bounds: Rect2D): Unit = { def sprite(
sprite(name, bounds.origin, bounds.size, Color.White) icon: IconSource,
} x: Float,
y: Float,
def sprite(name: String, x: Float, y: Float, color: Color): Unit = { width: Float,
sprite(name, Vector2D(x, y), Spritesheet.spriteSize(name), color) height: Float,
} color: Color,
): Unit = {
def sprite(name: String, pos: Vector2D, color: Color): Unit = { sprite = icon.path
sprite(name, pos, Spritesheet.spriteSize(name), color)
}
def sprite(name: String, pos: Vector2D, size: Size2D, color: Color): Unit = {
sprite(name, pos.x, pos.y, size.width, size.height, color)
}
def sprite(name: String, pos: Vector2D, size: Size2D): Unit = {
sprite(name, pos.x, pos.y, size.width, size.height)
}
def sprite(name: String, x: Float, y: Float): Unit = {
sprite(name, x, y, Color.White, None)
}
def sprite(name: String, x: Float, y: Float, animation: Option[Animation]): Unit = {
sprite(name, x, y, Color.White, animation)
}
def sprite(name: String, x: Float, y: Float, color: Color, animation: Option[Animation]): Unit = {
val size = Spritesheet.spriteSize(name)
sprite(name, x, y, size.width, size.height, color, animation)
}
def sprite(name: String, x: Float, y: Float, width: Float, height: Float,
color: Color = Color.White,
animation: Option[Animation] = None): Unit = {
sprite = name
foreground = color foreground = color
val spriteRect = animation match { val spriteRect = icon.animation.map { animation =>
case Some(animation) =>
val duration = animation.frames.map(_._2).sum val duration = animation.frames.map(_._2).sum
var timeOffset = 0f var timeOffset = 0f
var curFrame = 0 var curFrame = 0
@ -364,21 +339,27 @@ class Graphics(private var width: Int, private var height: Int, private var scal
case Some(size) => Size2D(this.spriteRect.w, this.spriteRect.w * size.height / size.width) case Some(size) => Size2D(this.spriteRect.w, this.spriteRect.w * size.height / size.width)
case None => Size2D(this.spriteRect.w, this.spriteRect.w) case None => Size2D(this.spriteRect.w, this.spriteRect.w)
} }
Some(this.spriteRect.copy(y = this.spriteRect.y + curFrame * size.height, h = size.height))
case None => None this.spriteRect.copy(y = this.spriteRect.y + curFrame * size.height, h = size.height)
} }
_rect(x, y, width, height, fixUV = true, spriteRect) _rect(x, y, width, height, fixUV = true, spriteRect)
} }
def sprite(name: String, x: Float, y: Float, width: Float, height: Float, def sprite(
name: String,
x: Float,
y: Float,
width: Float,
height: Float,
color: Color, color: Color,
spriteRect: Rect2D): Unit = { spriteRect: Option[Rect2D],
fixUV: Boolean = true,
): Unit = {
sprite = name sprite = name
foreground = color foreground = color
_rect(x, y, width, height, fixUV = true, Some(spriteRect)) _rect(x, y, width, height, fixUV, spriteRect)
} }
def rect(r: Rect2D, color: Color): Unit = { def rect(r: Rect2D, color: Color): Unit = {
@ -386,7 +367,7 @@ class Graphics(private var width: Int, private var height: Int, private var scal
} }
def rect(x: Float, y: Float, width: Float, height: Float, color: Color = RGBAColorNorm(1f, 1f, 1f)): Unit = { def rect(x: Float, y: Float, width: Float, height: Float, color: Color = RGBAColorNorm(1f, 1f, 1f)): Unit = {
sprite("Empty", x, y, width, height, color) sprite(IconSource.Empty, x, y, width, height, color)
} }
private def checkFont(): Unit = { private def checkFont(): Unit = {

View File

@ -3,7 +3,7 @@ package ocelot.desktop.graphics
import ocelot.desktop.geometry.Size2D import ocelot.desktop.geometry.Size2D
import ocelot.desktop.ui.widget.modal.notification.NotificationType.NotificationType import ocelot.desktop.ui.widget.modal.notification.NotificationType.NotificationType
import totoro.ocelot.brain.entity.tape.Tape.{Kind => TapeKind} import totoro.ocelot.brain.entity.tape.Tape.{Kind => TapeKind}
import totoro.ocelot.brain.util.Direction.{Direction, Down, Up, North, South, West, East} import totoro.ocelot.brain.util.Direction.{Direction, Down, East, North, South, Up, West}
import totoro.ocelot.brain.util.DyeColor import totoro.ocelot.brain.util.DyeColor
import totoro.ocelot.brain.util.ExtendedTier.ExtendedTier import totoro.ocelot.brain.util.ExtendedTier.ExtendedTier
import totoro.ocelot.brain.util.Tier.Tier import totoro.ocelot.brain.util.Tier.Tier
@ -14,6 +14,19 @@ case class IconSource(
) )
object IconSource { object IconSource {
val Empty: IconSource = IconSource("Empty")
val EmptySlot: IconSource = IconSource("EmptySlot")
val ShadowCorner: IconSource = IconSource("ShadowCorner")
val ShadowBorder: IconSource = IconSource("ShadowBorder")
val TabArrow: IconSource = IconSource("TabArrow")
val BarSegment: IconSource = IconSource("BarSegment")
val BackgroundPattern: IconSource = IconSource("BackgroundPattern")
val Logo: IconSource = IconSource("Logo")
val Knob: IconSource = IconSource("Knob")
val KnobLimits: IconSource = IconSource("KnobLimits")
val KnobCenter: IconSource = IconSource("KnobCenter")
object Items { object Items {
protected val prefix: String = "items" protected val prefix: String = "items"
@ -211,6 +224,20 @@ object IconSource {
val Close: IconSource = IconSource(s"$prefix/Close") val Close: IconSource = IconSource(s"$prefix/Close")
val Grid: IconSource = IconSource(s"$prefix/Grid") val Grid: IconSource = IconSource(s"$prefix/Grid")
val GridOff: IconSource = IconSource(s"$prefix/GridOff") val GridOff: IconSource = IconSource(s"$prefix/GridOff")
val LMB: IconSource = IconSource(s"$prefix/LMB")
val RMB: IconSource = IconSource(s"$prefix/RMB")
val DragLMB: IconSource = IconSource(s"$prefix/DragLMB")
val DragRMB: IconSource = IconSource(s"$prefix/DragRMB")
val WireArrowLeft: IconSource = IconSource(s"$prefix/WireArrowLeft")
val WireArrowRight: IconSource = IconSource(s"$prefix/WireArrowRight")
val WaveSine: IconSource = IconSource(s"$prefix/WaveSine")
val WaveTriangle: IconSource = IconSource(s"$prefix/WaveTriangle")
val WaveSawtooth: IconSource = IconSource(s"$prefix/WaveSawtooth")
val WaveSquare: IconSource = IconSource(s"$prefix/WaveSquare")
val WaveNoise: IconSource = IconSource(s"$prefix/WaveNoise")
val WaveLFSR: IconSource = IconSource(s"$prefix/WaveLFSR")
} }
// ----------------------- Node icons ----------------------- // ----------------------- Node icons -----------------------
@ -388,6 +415,7 @@ object IconSource {
object Particles { object Particles {
protected val prefix: String = "particles" protected val prefix: String = "particles"
val Note: IconSource = IconSource(s"$prefix/Note")
val Smoke: IconSource = IconSource(s"$prefix/Smoke") val Smoke: IconSource = IconSource(s"$prefix/Smoke")
} }
@ -428,6 +456,14 @@ object IconSource {
object Window { object Window {
protected val prefix: String = "window" protected val prefix: String = "window"
val CornerTL: IconSource = IconSource(s"$prefix/CornerTL")
val CornerTR: IconSource = IconSource(s"$prefix/CornerTR")
val CornerBL: IconSource = IconSource(s"$prefix/CornerBL")
val CornerBR: IconSource = IconSource(s"$prefix/CornerBR")
val BorderLight: IconSource = IconSource(s"$prefix/BorderLight")
val BorderDark: IconSource = IconSource(s"$prefix/BorderDark")
object Tape { object Tape {
protected val prefix: String = s"${Window.prefix}/tape" protected val prefix: String = s"${Window.prefix}/tape"
@ -440,6 +476,91 @@ object IconSource {
object Play extends TapeButtonIconSource("Play") object Play extends TapeButtonIconSource("Play")
object Stop extends TapeButtonIconSource("Stop") object Stop extends TapeButtonIconSource("Stop")
object Forward extends TapeButtonIconSource("Forward") object Forward extends TapeButtonIconSource("Forward")
val Screen: IconSource = IconSource(s"$prefix/Screen")
}
object Case {
protected val prefix: String = s"${Window.prefix}/case"
val Motherboard: IconSource = IconSource(s"$prefix/Motherboard")
}
object Rack {
protected val prefix: String = s"${Window.prefix}/rack"
val Motherboard: IconSource = IconSource(s"$prefix/Motherboard")
val Lines: IconSource = IconSource(s"$prefix/Lines")
trait DirectionIconSource {
protected def prefix: String
val DirectionIcon: Direction => IconSource = { direction =>
IconSource(s"$prefix${direction.side.capitalize}")
} }
} }
trait ConnectorIconSource {
protected def prefix: String
val Connector: IconSource = IconSource(s"${prefix}Connector")
}
object Side extends DirectionIconSource with ConnectorIconSource {
override protected def prefix: String = s"${Rack.prefix}/Side"
}
object Network extends DirectionIconSource with ConnectorIconSource {
override protected def prefix: String = s"${Rack.prefix}/Network"
}
object Node extends DirectionIconSource {
override protected def prefix: String = s"${Rack.prefix}/Node"
}
}
object Raid {
protected val prefix: String = s"${Window.prefix}/raid"
val Slots: IconSource = IconSource(s"$prefix/Slots")
}
val OpenFMRadio: IconSource = IconSource(s"$prefix/OpenFMRadio")
}
object Panel {
protected val prefix: String = "panel"
val CornerTL: IconSource = IconSource(s"$prefix/CornerTL")
val CornerTR: IconSource = IconSource(s"$prefix/CornerTR")
val CornerBL: IconSource = IconSource(s"$prefix/CornerBL")
val CornerBR: IconSource = IconSource(s"$prefix/CornerBR")
val BorderT: IconSource = IconSource(s"$prefix/BorderT")
val BorderB: IconSource = IconSource(s"$prefix/BorderB")
val BorderL: IconSource = IconSource(s"$prefix/BorderL")
val BorderR: IconSource = IconSource(s"$prefix/BorderR")
val Fill: IconSource = IconSource(s"$prefix/Fill")
}
object LightPanel {
protected val prefix: String = "light-panel"
val CornerTL: IconSource = IconSource(s"$prefix/CornerTL")
val CornerTR: IconSource = IconSource(s"$prefix/CornerTR")
val CornerBL: IconSource = IconSource(s"$prefix/CornerBL")
val CornerBR: IconSource = IconSource(s"$prefix/CornerBR")
val BorderT: IconSource = IconSource(s"$prefix/BorderT")
val BorderB: IconSource = IconSource(s"$prefix/BorderB")
val BorderL: IconSource = IconSource(s"$prefix/BorderL")
val BorderR: IconSource = IconSource(s"$prefix/BorderR")
val Fill: IconSource = IconSource(s"$prefix/Fill")
val Vent: IconSource = IconSource(s"$prefix/Vent")
val BookmarkLeft: IconSource = IconSource(s"$prefix/BookmarkLeft")
val BookmarkRight: IconSource = IconSource(s"$prefix/BookmarkRight")
}
} }

View File

@ -104,11 +104,11 @@ abstract class Node extends Widget with MouseHandler with HoverHandler with Pers
super.update() super.update()
if (isHovered || isMoving) { if (isHovered || isMoving) {
root.get.statusBar.addMouseEntry("icons/RMB", "Menu") root.get.statusBar.addMouseEntry(IconSource.Icons.RMB, "Menu")
root.get.statusBar.addMouseEntry("icons/DragLMB", "Move node") root.get.statusBar.addMouseEntry(IconSource.Icons.DragLMB, "Move node")
if (ports.nonEmpty) { if (ports.nonEmpty) {
root.get.statusBar.addMouseEntry("icons/DragRMB", "Connect/Disconnect") root.get.statusBar.addMouseEntry(IconSource.Icons.DragRMB, "Connect/Disconnect")
} }
} }
} }
@ -263,13 +263,12 @@ abstract class Node extends Widget with MouseHandler with HoverHandler with Pers
drawHighlight(g) drawHighlight(g)
g.sprite( g.sprite(
iconSource.path, iconSource,
position.x + HighlightThickness, position.x + HighlightThickness,
position.y + HighlightThickness, position.y + HighlightThickness,
size.width - HighlightThickness * 2, size.width - HighlightThickness * 2,
size.height - HighlightThickness * 2, size.height - HighlightThickness * 2,
iconColor, iconColor,
iconSource.animation,
) )
} }

View File

@ -2,7 +2,7 @@ package ocelot.desktop.node
import ocelot.desktop.color.Color import ocelot.desktop.color.Color
import ocelot.desktop.geometry.Size2D import ocelot.desktop.geometry.Size2D
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.node.Node.Size import ocelot.desktop.node.Node.Size
import ocelot.desktop.ui.event.handlers.{HoverHandler, MouseHandler} import ocelot.desktop.ui.event.handlers.{HoverHandler, MouseHandler}
import ocelot.desktop.ui.event.{ClickEvent, HoverEvent, MouseEvent} import ocelot.desktop.ui.event.{ClickEvent, HoverEvent, MouseEvent}
@ -39,20 +39,19 @@ class NodeTypeWidget(val nodeType: NodeType) extends Widget with MouseHandler wi
val size = Spritesheet.spriteSize(nodeType.icon) * 4 val size = Spritesheet.spriteSize(nodeType.icon) * 4
g.sprite( g.sprite(
nodeType.icon.path, nodeType.icon,
position.x + Size / 2 - size.width / 2, position.x + Size / 2 - size.width / 2,
position.y + Size / 2 - size.height / 2, position.y + Size / 2 - size.height / 2,
size.width, size.width,
size.height, size.height,
nodeType.tier.map(TierColor.get).getOrElse(Color.White), nodeType.tier.map(TierColor.get).getOrElse(Color.White),
nodeType.icon.animation,
) )
} }
override def update(): Unit = { override def update(): Unit = {
super.update() super.update()
if (isHovered) { if (isHovered) {
root.get.statusBar.addMouseEntry("icons/LMB", "Add node") root.get.statusBar.addMouseEntry(IconSource.Icons.LMB, "Add node")
} }
} }
} }

View File

@ -1,5 +1,6 @@
package ocelot.desktop.node package ocelot.desktop.node
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.ui.event.sources.KeyEvents import ocelot.desktop.ui.event.sources.KeyEvents
import ocelot.desktop.ui.event.{ClickEvent, MouseEvent} import ocelot.desktop.ui.event.{ClickEvent, MouseEvent}
@ -22,6 +23,6 @@ trait ShiftClickNode extends Node {
super.update() super.update()
if (isHovered || isMoving) if (isHovered || isMoving)
root.get.statusBar.addKeyMouseEntry("icons/LMB", "SHIFT", hoveredShiftStatusBarText) root.get.statusBar.addKeyMouseEntry(IconSource.Icons.LMB, "Shift", hoveredShiftStatusBarText)
} }
} }

View File

@ -43,10 +43,10 @@ trait SmokeParticleNode extends Node {
SmokeParticleSize.width, SmokeParticleSize.width,
SmokeParticleSize.height, SmokeParticleSize.height,
color, color,
spriteRect.copy( Some(spriteRect.copy(
y = spriteRect.y + animationFrame * spriteRect.w, y = spriteRect.y + animationFrame * spriteRect.w,
h = spriteRect.w, h = spriteRect.w,
), )),
) )
} }
} }

View File

@ -1,9 +1,9 @@
package ocelot.desktop.node package ocelot.desktop.node
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.ui.event.sources.KeyEvents import ocelot.desktop.ui.event.sources.KeyEvents
import ocelot.desktop.ui.event.{ClickEvent, MouseEvent} import ocelot.desktop.ui.event.{ClickEvent, MouseEvent}
import ocelot.desktop.ui.widget.window.{Window, Windowed} import ocelot.desktop.ui.widget.window.{Window, Windowed}
import org.lwjgl.input.Keyboard
trait WindowedNode[T <: Window] extends Node with Windowed[T] { trait WindowedNode[T <: Window] extends Node with Windowed[T] {
override def dispose(): Unit = { override def dispose(): Unit = {
@ -14,7 +14,7 @@ trait WindowedNode[T <: Window] extends Node with Windowed[T] {
override def update(): Unit = { override def update(): Unit = {
if (isHovered || isMoving) if (isHovered || isMoving)
root.get.statusBar.addMouseEntry("icons/LMB", if (windowCreated && window.isOpen) "Close" else "Open") root.get.statusBar.addMouseEntry(IconSource.Icons.LMB, if (windowCreated && window.isOpen) "Close" else "Open")
super.update() super.update()
} }

View File

@ -3,7 +3,7 @@ package ocelot.desktop.node.nodes
import ocelot.desktop.ColorScheme import ocelot.desktop.ColorScheme
import ocelot.desktop.audio.{SoundBuffers, SoundCategory, SoundSource} import ocelot.desktop.audio.{SoundBuffers, SoundCategory, SoundSource}
import ocelot.desktop.geometry.{Size2D, Vector2D} import ocelot.desktop.geometry.{Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.node.{EntityNode, LabeledEntityNode} import ocelot.desktop.node.{EntityNode, LabeledEntityNode}
import ocelot.desktop.ui.UiHandler import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.event.BrainEvent import ocelot.desktop.ui.event.BrainEvent
@ -27,15 +27,19 @@ abstract class NoteBlockNodeBase(entity: Entity with Environment) extends Entity
override def update(): Unit = { override def update(): Unit = {
super.update() super.update()
if (isHovered || isMoving) { if (isHovered || isMoving) {
root.get.statusBar.addMouseEntry("icons/LMB", "Play sample") root.get.statusBar.addMouseEntry(IconSource.Icons.LMB, "Play sample")
} }
} }
private class NoteParticle(pitch: Int) extends Particle(speed = 1.2f) { private class NoteParticle(pitch: Int) extends Particle(speed = 1.2f) {
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
val col = ColorScheme("Note" + pitch.min(24).max(0)).withAlpha(1 - (2 * time - 1).min(1).max(0)) val col = ColorScheme("Note" + pitch.min(24).max(0)).withAlpha(1 - (2 * time - 1).min(1).max(0))
g.sprite("particles/Note", position + Vector2D(pitch / 24f * 40f + 5, height / 2 - 10 - 100 * time), g.sprite(
Size2D(14, 20), col) IconSource.Particles.Note,
position + Vector2D(pitch / 24f * 40f + 5, height / 2 - 10 - 100 * time),
Size2D(14, 20),
col,
)
} }
} }
} }

View File

@ -68,13 +68,12 @@ class OcelotBlockNode(val ocelot: OcelotBlock)
if (alpha > 0) { if (alpha > 0) {
g.sprite( g.sprite(
icon.path, icon,
position.x + HighlightThickness, position.x + HighlightThickness,
position.y + HighlightThickness, position.y + HighlightThickness,
size.width - HighlightThickness * 2, size.width - HighlightThickness * 2,
size.height - HighlightThickness * 2, size.height - HighlightThickness * 2,
RGBAColorNorm(1f, 1f, 1f, alpha), RGBAColorNorm(1f, 1f, 1f, alpha),
icon.animation,
) )
} }
} }

View File

@ -2,7 +2,7 @@ package ocelot.desktop.ui.widget
import ocelot.desktop.ColorScheme import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color import ocelot.desktop.color.Color
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
@ -13,8 +13,8 @@ class Histogram extends Widget {
private def drawBars(g: Graphics): Unit = { private def drawBars(g: Graphics): Unit = {
def drawBarSegment(i: Int, color: Color): Unit = { def drawBarSegment(i: Int, color: Color): Unit = {
g.sprite("BarSegment", position.x, position.y + i * 6, 16, 4, color) g.sprite(IconSource.BarSegment, position.x, position.y + i * 6, 16, 4, color)
g.sprite("BarSegment", position.x + 18, position.y + i * 6, 16, 4, color) g.sprite(IconSource.BarSegment, position.x + 18, position.y + i * 6, 16, 4, color)
} }
val ratio = history.last val ratio = history.last

View File

@ -17,16 +17,13 @@ class Icon(icon: IconSource, size: Size2D = null, private val color: Color = Col
def iconColor: Color = color def iconColor: Color = color
def iconSize: Size2D = { def iconSize: Size2D = {
if (size != null) size Option(size).getOrElse(Spritesheet.spriteSize(icon))
else if (icon.animation.isDefined && icon.animation.get.frameSize.isDefined)
icon.animation.get.frameSize.get
else Spritesheet.spriteSize(icon.path)
} }
override def minimumSize: Size2D = iconSize override def minimumSize: Size2D = iconSize
override def maximumSize: Size2D = minimumSize override def maximumSize: Size2D = minimumSize
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
g.sprite(icon.path, bounds.x, bounds.y, bounds.w, bounds.h, iconColor, icon.animation) g.sprite(icon, bounds, iconColor)
} }
} }

View File

@ -2,7 +2,7 @@ package ocelot.desktop.ui.widget
import ocelot.desktop.color.{Color, IntColor} import ocelot.desktop.color.{Color, IntColor}
import ocelot.desktop.geometry.{Size2D, Vector2D} import ocelot.desktop.geometry.{Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.ui.UiHandler import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.event.MouseEvent import ocelot.desktop.ui.event.MouseEvent
import totoro.ocelot.brain.util.DyeColor import totoro.ocelot.brain.util.DyeColor
@ -47,14 +47,14 @@ abstract class Knob(dyeColor: DyeColor = DyeColor.Red) extends Widget {
} }
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
g.sprite("KnobLimits", position.x, position.y, 25, 25) g.sprite(IconSource.KnobLimits, position.x, position.y, 25, 25)
g.save() g.save()
g.translate(position.x + 12.5f, position.y + 12.5f) g.translate(position.x + 12.5f, position.y + 12.5f)
g.rotate(input.toFloat / 15f * 4.71239f - 0.785398f) g.rotate(input.toFloat / 15f * 4.71239f - 0.785398f)
g.sprite("Knob", -12.5f, -12.5f, 25, 25, color) g.sprite(IconSource.Knob, -12.5f, -12.5f, 25, 25, color)
g.restore() g.restore()
g.sprite("KnobCenter", position.x, position.y, 25, 25) g.sprite(IconSource.KnobCenter, position.x, position.y, 25, 25)
val centerColor = color.toRGBANorm.copy(a = output / 15f) val centerColor = color.toRGBANorm.copy(a = output / 15f)
g.sprite("KnobCenter", position.x - 1, position.y - 1, 27, 27, centerColor) g.sprite(IconSource.KnobCenter, position.x - 1, position.y - 1, 27, 27, centerColor)
} }
} }

View File

@ -150,8 +150,8 @@ abstract class Viewport3DWidget extends Widget with MouseHandler with HoverHandl
scene = createScene() scene = createScene()
if (isHovered) { if (isHovered) {
root.get.statusBar.addMouseEntry("icons/LMB", "Rotate view") root.get.statusBar.addMouseEntry(IconSource.Icons.LMB, "Rotate view")
root.get.statusBar.addKeyMouseEntry("icons/LMB", "Shift", "Pan view") root.get.statusBar.addKeyMouseEntry(IconSource.Icons.LMB, "Shift", "Pan view")
} }
} }

View File

@ -574,7 +574,7 @@ class WorkspaceView extends Widget with Persistable with MouseHandler with Hover
for (x <- 0 to numRepeatsX) { for (x <- 0 to numRepeatsX) {
for (y <- 0 to numRepeatsY) { for (y <- 0 to numRepeatsY) {
g.sprite("BackgroundPattern", x.toFloat * 304, y.toFloat * 304, 304, 304) g.sprite(IconSource.BackgroundPattern, x.toFloat * 304, y.toFloat * 304, 304, 304)
} }
} }
@ -660,11 +660,11 @@ class WorkspaceView extends Widget with Persistable with MouseHandler with Hover
} }
if (isHovered && newConnection.isEmpty) { if (isHovered && newConnection.isEmpty) {
if (nodeSelector.isClosed) root.get.statusBar.addMouseEntry(
root.get.statusBar.addMouseEntry("icons/LMB", "Add node") IconSource.Icons.LMB,
else if (nodeSelector.isClosed) "Add node" else "Close selector",
root.get.statusBar.addMouseEntry("icons/LMB", "Close selector") )
root.get.statusBar.addMouseEntry("icons/DragLMB", "Move camera") root.get.statusBar.addMouseEntry(IconSource.Icons.DragLMB, "Move camera")
} }
} }
} }

View File

@ -3,7 +3,7 @@ package ocelot.desktop.ui.widget.card
import ocelot.desktop.ColorScheme import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color import ocelot.desktop.color.Color
import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D, Vector2D} import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.ui.layout.{Layout, LinearLayout} import ocelot.desktop.ui.layout.{Layout, LinearLayout}
import ocelot.desktop.ui.widget.card.SoundCardWindow._ import ocelot.desktop.ui.widget.card.SoundCardWindow._
import ocelot.desktop.ui.widget.window.{PanelWindow, Window} import ocelot.desktop.ui.widget.window.{PanelWindow, Window}
@ -167,9 +167,9 @@ class SoundCardWindow(card: SoundCard) extends PanelWindow {
g.line(b, Vector2D(mx, b.y), 2, col) g.line(b, Vector2D(mx, b.y), 2, col)
if (b.x > px) { if (b.x > px) {
g.sprite("icons/WireArrowRight", b.x - 4, b.y - 4, col) g.sprite(IconSource.Icons.WireArrowRight, b.x - 4, b.y - 4, col)
} else { } else {
g.sprite("icons/WireArrowLeft", b.x, b.y - 4, col) g.sprite(IconSource.Icons.WireArrowLeft, b.x, b.y - 4, col)
} }
existingConnectors += Connector(column, colorIdx, from, to) existingConnectors += Connector(column, colorIdx, from, to)
@ -275,12 +275,12 @@ object SoundCardWindow {
} }
private val waves = Array( private val waves = Array(
("icons/WaveSine", SignalGenerator.Sine.getClass), (IconSource.Icons.WaveSine, SignalGenerator.Sine.getClass),
("icons/WaveTriangle", SignalGenerator.Triangle.getClass), (IconSource.Icons.WaveTriangle, SignalGenerator.Triangle.getClass),
("icons/WaveSawtooth", SignalGenerator.Sawtooth.getClass), (IconSource.Icons.WaveSawtooth, SignalGenerator.Sawtooth.getClass),
("icons/WaveSquare", SignalGenerator.Square.getClass), (IconSource.Icons.WaveSquare, SignalGenerator.Square.getClass),
("icons/WaveNoise", classOf[SignalGenerator.Noise]), (IconSource.Icons.WaveNoise, classOf[SignalGenerator.Noise]),
("icons/WaveLFSR", classOf[SignalGenerator.LFSR]), (IconSource.Icons.WaveLFSR, classOf[SignalGenerator.LFSR]),
) )
private def drawEnvelope(g: Graphics, env: ADSREnvelope, bounds: Rect2D, elapsedMs: Float): Unit = { private def drawEnvelope(g: Graphics, env: ADSREnvelope, bounds: Rect2D, elapsedMs: Float): Unit = {
@ -445,21 +445,21 @@ object SoundCardWindow {
val sh = (if (isFirst) 10 else 0) + (if (isLast) 50 else 0) val sh = (if (isFirst) 10 else 0) + (if (isLast) 50 else 0)
h -= sh h -= sh
g.sprite("light-panel/BorderL", x, y, 4, h) g.sprite(IconSource.LightPanel.BorderL, x, y, 4, h)
g.sprite("light-panel/BorderR", x + w - 4, y, 4, h) g.sprite(IconSource.LightPanel.BorderR, x + w - 4, y, 4, h)
g.sprite("light-panel/Fill", x + 4, y, w - 8, h) g.sprite(IconSource.LightPanel.Fill, x + 4, y, w - 8, h)
if (isFirst) { if (isFirst) {
g.sprite("light-panel/CornerTL", x, y - 4, 4, 4) g.sprite(IconSource.LightPanel.CornerTL, x, y - 4, 4, 4)
g.sprite("light-panel/CornerTR", x + w - 4, y - 4, 4, 4) g.sprite(IconSource.LightPanel.CornerTR, x + w - 4, y - 4, 4, 4)
g.sprite("light-panel/BorderT", x + 4, y - 4, w - 8, 4) g.sprite(IconSource.LightPanel.BorderT, x + 4, y - 4, w - 8, 4)
} }
if (isLast) { if (isLast) {
g.sprite("light-panel/CornerBL", x, y + h, 4, 4) g.sprite(IconSource.LightPanel.CornerBL, x, y + h, 4, 4)
g.sprite("light-panel/CornerBR", x + w - 4, y + h, 4, 4) g.sprite(IconSource.LightPanel.CornerBR, x + w - 4, y + h, 4, 4)
g.sprite("light-panel/BorderB", x + 4, y + h, w - 8, 4) g.sprite(IconSource.LightPanel.BorderB, x + 4, y + h, w - 8, 4)
g.sprite("light-panel/Vent", x, y + h + 8, w, 38) g.sprite(IconSource.LightPanel.Vent, x, y + h + 8, w, 38)
} }
for (i <- 0 until 6) { for (i <- 0 until 6) {
@ -469,13 +469,13 @@ object SoundCardWindow {
y -= sy y -= sy
h += sh h += sh
g.sprite("light-panel/BookmarkLeft", x, y + 16, 18, 14) g.sprite(IconSource.LightPanel.BookmarkLeft, x, y + 16, 18, 14)
g.sprite("light-panel/BookmarkLeft", x, y + 32, 18, 14) g.sprite(IconSource.LightPanel.BookmarkLeft, x, y + 32, 18, 14)
g.sprite("light-panel/BookmarkLeft", x, y + 48, 18, 14) g.sprite(IconSource.LightPanel.BookmarkLeft, x, y + 48, 18, 14)
g.sprite("light-panel/BookmarkRight", x + w - 20, y + 16, 20, 14) g.sprite(IconSource.LightPanel.BookmarkRight, x + w - 20, y + 16, 20, 14)
g.sprite("light-panel/BookmarkRight", x + w - 20, y + 32, 20, 14) g.sprite(IconSource.LightPanel.BookmarkRight, x + w - 20, y + 32, 20, 14)
g.sprite("light-panel/BookmarkRight", x + w - 20, y + 48, 20, 14) g.sprite(IconSource.LightPanel.BookmarkRight, x + w - 20, y + 48, 20, 14)
g.setSmallFont() g.setSmallFont()
g.background = Color.Transparent g.background = Color.Transparent

View File

@ -4,7 +4,7 @@ import buildinfo.BuildInfo
import ocelot.desktop.ColorScheme import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color import ocelot.desktop.color.Color
import ocelot.desktop.geometry.{Padding2D, Size2D} import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.ui.layout.LinearLayout import ocelot.desktop.ui.layout.LinearLayout
import ocelot.desktop.ui.widget.{Button, Filler, Label, PaddingBox, Widget} import ocelot.desktop.ui.widget.{Button, Filler, Label, PaddingBox, Widget}
import ocelot.desktop.ui.widget.modal.ModalDialog import ocelot.desktop.ui.widget.modal.ModalDialog
@ -25,7 +25,7 @@ class AboutDialog extends ModalDialog {
override def minimumSize: Size2D = Spritesheet.spriteSize("Logo") + 40 override def minimumSize: Size2D = Spritesheet.spriteSize("Logo") + 40
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
g.sprite("Logo", bounds.x + 20, bounds.y + 80, ColorScheme("AboutLogo")) g.sprite(IconSource.Logo, bounds.x + 20, bounds.y + 80, ColorScheme("AboutLogo"))
drawChildren(g) drawChildren(g)
} }
} }

View File

@ -230,7 +230,7 @@ class SlotWidget[I <: Item](private val slot: Inventory#Slot)(implicit slotItemT
} }
override final def draw(g: Graphics): Unit = { override final def draw(g: Graphics): Unit = {
g.sprite("EmptySlot", bounds) g.sprite(IconSource.EmptySlot, bounds)
val iconBounds = bounds.inflated(-2) val iconBounds = bounds.inflated(-2)

View File

@ -3,11 +3,11 @@ package ocelot.desktop.ui.widget.statusbar
import ocelot.desktop.ColorScheme import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color import ocelot.desktop.color.Color
import ocelot.desktop.geometry.Size2D import ocelot.desktop.geometry.Size2D
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.ui.widget.Widget import ocelot.desktop.ui.widget.Widget
import ocelot.desktop.util.{DrawUtils, Spritesheet} import ocelot.desktop.util.{DrawUtils, Spritesheet}
class KeyMouseEntry(val icon: String, val key: String, val text: String) extends Widget { class KeyMouseEntry(val icon: IconSource, val key: String, val text: String) extends Widget {
private val iconSize = Spritesheet.spriteSize(icon) private val iconSize = Spritesheet.spriteSize(icon)
override def minimumSize: Size2D = Size2D(iconSize.width + key.length * 8 + 40 + text.length * 8, 16) override def minimumSize: Size2D = Size2D(iconSize.width + key.length * 8 + 40 + text.length * 8, 16)

View File

@ -3,11 +3,11 @@ package ocelot.desktop.ui.widget.statusbar
import ocelot.desktop.ColorScheme import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color import ocelot.desktop.color.Color
import ocelot.desktop.geometry.Size2D import ocelot.desktop.geometry.Size2D
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.ui.widget.Widget import ocelot.desktop.ui.widget.Widget
import ocelot.desktop.util.Spritesheet import ocelot.desktop.util.Spritesheet
class MouseEntry(val icon: String, val text: String) extends Widget { class MouseEntry(val icon: IconSource, val text: String) extends Widget {
private val iconSize = Spritesheet.spriteSize(icon) private val iconSize = Spritesheet.spriteSize(icon)
override def minimumSize: Size2D = Size2D(iconSize.width + 24 + text.length * 8, 16) override def minimumSize: Size2D = Size2D(iconSize.width + 24 + text.length * 8, 16)

View File

@ -102,7 +102,7 @@ class StatusBar extends Widget {
super.update() super.update()
if (isHovered) { if (isHovered) {
root.get.statusBar.addMouseEntry("icons/RMB", "Change simulation speed") root.get.statusBar.addMouseEntry(IconSource.Icons.RMB, "Change simulation speed")
} }
} }
@ -135,23 +135,17 @@ class StatusBar extends Widget {
Padding2D(left = 8), Padding2D(left = 8),
) )
def addMouseEntry(icon: String, text: String): Unit = { def addMouseEntry(icon: IconSource, text: String): Unit = {
if ( if (!keyMouseEntries.children.collect({ case e: MouseEntry => e.icon }).contains(icon)) {
!keyMouseEntries.children.filter(_.isInstanceOf[MouseEntry]).map(_.asInstanceOf[MouseEntry]).exists(
_.icon == icon
)
)
keyMouseEntries.children :+= new MouseEntry(icon, text) keyMouseEntries.children :+= new MouseEntry(icon, text)
} }
}
def addKeyMouseEntry(icon: String, key: String, text: String): Unit = { def addKeyMouseEntry(icon: IconSource, key: String, text: String): Unit = {
if ( if (!keyMouseEntries.children.collect({ case e: KeyMouseEntry => e }).exists(e => e.icon == icon && e.key == key)) {
!keyMouseEntries.children.filter(_.isInstanceOf[KeyMouseEntry]).map(_.asInstanceOf[KeyMouseEntry]).exists(v =>
v.icon == icon && v.key == key
)
)
keyMouseEntries.children :+= new KeyMouseEntry(icon, key, text) keyMouseEntries.children :+= new KeyMouseEntry(icon, key, text)
} }
}
def addKeyEntry(key: String, text: String): Unit = { def addKeyEntry(key: String, text: String): Unit = {
if (!keyEntries.children.map(_.asInstanceOf[KeyEntry]).exists(_.key == key)) if (!keyEntries.children.map(_.asInstanceOf[KeyEntry]).exists(_.key == key))

View File

@ -64,7 +64,7 @@ class VerticalMenuButton(icon: IconSource, label: String, handler: VerticalMenuB
colorAnimation.update() colorAnimation.update()
g.rect(bounds, colorAnimation.color) g.rect(bounds, colorAnimation.color)
g.rect(bounds.x + bounds.w - 2f, bounds.y, 2f, bounds.h, ColorScheme("VerticalMenuBorder")) g.rect(bounds.x + bounds.w - 2f, bounds.y, 2f, bounds.h, ColorScheme("VerticalMenuBorder"))
if (selected) g.sprite("TabArrow", bounds.x + bounds.w - 8f, bounds.y + bounds.h / 2f - 7f, 8, 14) if (selected) g.sprite(IconSource.TabArrow, bounds.x + bounds.w - 8f, bounds.y + bounds.h / 2f - 7f, 8, 14)
drawChildren(g) drawChildren(g)
} }

View File

@ -92,17 +92,17 @@ object DrawUtils {
} }
def panel(g: Graphics, x: Float, y: Float, w: Float, h: Float): Unit = { def panel(g: Graphics, x: Float, y: Float, w: Float, h: Float): Unit = {
g.sprite("panel/CornerTL", x, y, 4, 4) g.sprite(IconSource.Panel.CornerTL, x, y, 4, 4)
g.sprite("panel/CornerTR", x + w - 4, y, 4, 4) g.sprite(IconSource.Panel.CornerTR, x + w - 4, y, 4, 4)
g.sprite("panel/CornerBL", x, y + h - 4, 4, 4) g.sprite(IconSource.Panel.CornerBL, x, y + h - 4, 4, 4)
g.sprite("panel/CornerBR", x + w - 4, y + h - 4, 4, 4) g.sprite(IconSource.Panel.CornerBR, x + w - 4, y + h - 4, 4, 4)
g.sprite("panel/BorderT", x + 4, y, w - 8, 4) g.sprite(IconSource.Panel.BorderT, x + 4, y, w - 8, 4)
g.sprite("panel/BorderB", x + 4, y + h - 4, w - 8, 4) g.sprite(IconSource.Panel.BorderB, x + 4, y + h - 4, w - 8, 4)
g.sprite("panel/BorderL", x, y + 4, 4, h - 8) g.sprite(IconSource.Panel.BorderL, x, y + 4, 4, h - 8)
g.sprite("panel/BorderR", x + w - 4, y + 4, 4, h - 8) g.sprite(IconSource.Panel.BorderR, x + w - 4, y + 4, 4, h - 8)
g.sprite("panel/Fill", x + 4, y + 4, w - 8, h - 8) g.sprite(IconSource.Panel.Fill, x + 4, y + 4, w - 8, h - 8)
} }
def isValidPolyline(points: Array[Vector2D]): Boolean = { def isValidPolyline(points: Array[Vector2D]): Boolean = {
@ -186,19 +186,19 @@ object DrawUtils {
h: Float, h: Float,
color: Color = RGBAColor(255, 255, 255), color: Color = RGBAColor(255, 255, 255),
): Unit = { ): Unit = {
g.sprite("window/CornerTL", x, y, 8, 8, color) g.sprite(IconSource.Window.CornerTL, x, y, 8, 8, color)
g.sprite("window/CornerTR", x + w - 8, y, 8, 8, color) g.sprite(IconSource.Window.CornerTR, x + w - 8, y, 8, 8, color)
g.sprite("window/CornerBL", x, y + h - 8, 8, 8, color) g.sprite(IconSource.Window.CornerBL, x, y + h - 8, 8, 8, color)
g.sprite("window/CornerBR", x + w - 8, y + h - 8, 8, 8, color) g.sprite(IconSource.Window.CornerBR, x + w - 8, y + h - 8, 8, 8, color)
g.sprite("window/BorderLight", x + 8, y, w - 16, 8, color) g.sprite(IconSource.Window.BorderLight, x + 8, y, w - 16, 8, color)
g.sprite("window/BorderDark", x + 8, y + h - 8, w - 16, 8, color) g.sprite(IconSource.Window.BorderDark, x + 8, y + h - 8, w - 16, 8, color)
g.save() g.save()
g.translate(x, y + 8) g.translate(x, y + 8)
g.rotate(270.toRadians) g.rotate(270.toRadians)
g.sprite("window/BorderLight", 0, 0, -h + 16, 8, color) g.sprite(IconSource.Window.BorderLight, 0, 0, -h + 16, 8, color)
g.sprite("window/BorderDark", 0, w - 8, -h + 16, 8, color) g.sprite(IconSource.Window.BorderDark, 0, w - 8, -h + 16, 8, color)
g.restore() g.restore()
g.rect(x + 8, y + 8, w - 16, h - 16, RGBAColor(198, 198, 198, color.toRGBA.a)) g.rect(x + 8, y + 8, w - 16, h - 16, RGBAColor(198, 198, 198, color.toRGBA.a))
@ -207,24 +207,24 @@ object DrawUtils {
def shadow(g: Graphics, x: Float, y: Float, w: Float, h: Float, a: Float = 0.8f): Unit = { def shadow(g: Graphics, x: Float, y: Float, w: Float, h: Float, a: Float = 0.8f): Unit = {
val col = RGBAColorNorm(1, 1, 1, a) val col = RGBAColorNorm(1, 1, 1, a)
rotSprite(g, "ShadowCorner", x, y, 24, 24, 180.toRadians, col) rotSprite(g, IconSource.ShadowCorner, x, y, 24, 24, 180.toRadians, col)
rotSprite(g, "ShadowCorner", x + w - 24, y, 24, 24, 270.toRadians, col) rotSprite(g, IconSource.ShadowCorner, x + w - 24, y, 24, 24, 270.toRadians, col)
rotSprite(g, "ShadowCorner", x, y + h - 24, 24, 24, 90.toRadians, col) rotSprite(g, IconSource.ShadowCorner, x, y + h - 24, 24, 24, 90.toRadians, col)
g.sprite("ShadowCorner", x + w - 24, y + h - 24, 24, 24, col) g.sprite(IconSource.ShadowCorner, x + w - 24, y + h - 24, 24, 24, col)
g.sprite("ShadowBorder", x + 24, y + 24, w - 48, -24, col) g.sprite(IconSource.ShadowBorder, x + 24, y + 24, w - 48, -24, col)
g.sprite("ShadowBorder", x + 24, y + h - 24, w - 48, 24, col) g.sprite(IconSource.ShadowBorder, x + 24, y + h - 24, w - 48, 24, col)
g.save() g.save()
g.translate(x + 24, y + 24) g.translate(x + 24, y + 24)
g.rotate(90.toRadians) g.rotate(90.toRadians)
g.sprite("ShadowBorder", 0, 0, h - 48, 24, col) g.sprite(IconSource.ShadowBorder, 0, 0, h - 48, 24, col)
g.restore() g.restore()
g.save() g.save()
g.translate(x + w - 24, y + h - 24) g.translate(x + w - 24, y + h - 24)
g.rotate(270.toRadians) g.rotate(270.toRadians)
g.sprite("ShadowBorder", 0, 0, h - 48, 24, col) g.sprite(IconSource.ShadowBorder, 0, 0, h - 48, 24, col)
g.restore() g.restore()
g.rect(x + 24, y + 24, w - 48, h - 48, RGBAColorNorm(0, 0, 0, a)) g.rect(x + 24, y + 24, w - 48, h - 48, RGBAColorNorm(0, 0, 0, a))
@ -232,7 +232,7 @@ object DrawUtils {
private def rotSprite( private def rotSprite(
g: Graphics, g: Graphics,
sprite: String, icon: IconSource,
x: Float, x: Float,
y: Float, y: Float,
w: Float, w: Float,
@ -243,7 +243,7 @@ object DrawUtils {
g.save() g.save()
g.translate(x + w / 2f, y + h / 2f) g.translate(x + w / 2f, y + h / 2f)
g.rotate(angle) g.rotate(angle)
g.sprite(sprite, -w / 2f, -h / 2f, w, h, col) g.sprite(icon, -w / 2f, -h / 2f, w, h, col)
g.restore() g.restore()
} }

View File

@ -277,7 +277,11 @@ class ComputerWindow(computerAware: ComputerAware) extends BasicWindow {
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
// Background image // Background image
g.sprite( g.sprite(
s"window/${if (isServerMachineType) "rack" else "case"}/Motherboard", if (isServerMachineType) {
IconSource.Window.Rack.Motherboard
} else {
IconSource.Window.Case.Motherboard
},
position.x, position.x,
position.y, position.y,
width, width,

View File

@ -186,7 +186,7 @@ class OpenFMRadioWindow(radioNode: OpenFMRadioNode) extends BasicWindow {
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
beginDraw(g) beginDraw(g)
// I hate this // I hate this
g.sprite("window/OpenFMRadio", position.x, position.y, size.width, size.height) g.sprite(IconSource.Window.OpenFMRadio, position.x, position.y, size.width, size.height)
drawChildren(g) drawChildren(g)
endDraw(g) endDraw(g)
} }

View File

@ -25,10 +25,6 @@ class RackWindow(rackNode: RackNode) extends PanelWindow {
private val nodeButtonsGap = 12 private val nodeButtonsGap = 12
private val nodeButtonsWidth = 10 private val nodeButtonsWidth = 10
private def directionToSpriteName(prefix: String, direction: Direction): String = {
s"$prefix${direction.side.capitalize}"
}
private def shouldConnectionBeVisible(slotWidget: RackMountableSlotWidget, connectableIndex: Int) = { private def shouldConnectionBeVisible(slotWidget: RackMountableSlotWidget, connectableIndex: Int) = {
connectableIndex == 0 || connectableIndex == 0 ||
( (
@ -77,23 +73,11 @@ class RackWindow(rackNode: RackNode) extends PanelWindow {
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
// Relay mode line // Relay mode line
if (rackNode.rack.isRelayEnabled) { if (rackNode.rack.isRelayEnabled) {
g.sprite( g.sprite(IconSource.Window.Rack.Network.Connector, position.x + 12, position.y + 172, 102, 4)
s"window/rack/NetworkConnector",
position.x + 12,
position.y + 172,
102,
4,
)
} }
// Lines background // Lines background
g.sprite( g.sprite(IconSource.Window.Rack.Lines, position.x + linesMarginLeft, position.y, size.width, size.height)
"window/rack/Lines",
position.x + linesMarginLeft,
position.y,
size.width,
size.height,
)
super.draw(g) super.draw(g)
} }
@ -120,31 +104,28 @@ class RackWindow(rackNode: RackNode) extends PanelWindow {
var y = position.y var y = position.y
var connectionHeight: Float = 0 var connectionHeight: Float = 0
var prefix: String = null
for (connectableIndex <- 0 until 4) { for (connectableIndex <- 0 until 4) {
connectionHeight = if (connectableIndex == 0) lineSideHeight else lineNetworkHeight connectionHeight = if (connectableIndex == 0) lineSideHeight else lineNetworkHeight
if (shouldConnectionBeVisible(mountableSlotWidget, connectableIndex)) { if (shouldConnectionBeVisible(mountableSlotWidget, connectableIndex)) {
val connection = rackNode.rack.nodeMapping(mountableIndex)(connectableIndex) val connection = rackNode.rack.nodeMapping(mountableIndex)(connectableIndex)
prefix = s"window/rack/${if (connectableIndex == 0) "Side" else "Network"}" val source = if (connectableIndex == 0) {
IconSource.Window.Rack.Side
} else {
IconSource.Window.Rack.Network
}
// Connector // Connector
g.sprite( g.sprite(source.Connector, position.x, y, 2, connectionHeight)
s"${prefix}Connector",
position.x,
y,
2,
connectionHeight,
)
// Line // Line
if (connection.isDefined) { for (connection <- connection) {
g.sprite( g.sprite(
directionToSpriteName(prefix, connection.get), source.DirectionIcon(connection),
position.x + 2, position.x + 2,
y, y,
connection.get match { connection match {
case Direction.Bottom => nodeButtonsGap case Direction.Bottom => nodeButtonsGap
case Direction.Top => nodeButtonsGap * 2 + nodeButtonsWidth case Direction.Top => nodeButtonsGap * 2 + nodeButtonsWidth
case Direction.Back => nodeButtonsGap * 3 + nodeButtonsWidth * 2 case Direction.Back => nodeButtonsGap * 3 + nodeButtonsWidth * 2
@ -195,21 +176,13 @@ class RackWindow(rackNode: RackNode) extends PanelWindow {
rackNode.rack.connect( rackNode.rack.connect(
mountableIndex, mountableIndex,
connectableIndex - 1, connectableIndex - 1,
// Connection already exists, removing it Option.unless(oldConnection.contains(direction))(direction),
if (oldConnection.isDefined && oldConnection.get == direction)
None
// Connecting normally
else
Some(direction),
) )
} }
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
if (enabled) { if (enabled) {
g.sprite( g.sprite(IconSource.Window.Rack.Node.DirectionIcon(direction), bounds)
directionToSpriteName("window/rack/Node", direction),
bounds,
)
drawHighlight(g) drawHighlight(g)
} }
} }

View File

@ -3,7 +3,7 @@ package ocelot.desktop.windows
import ocelot.desktop.ColorScheme import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color import ocelot.desktop.color.Color
import ocelot.desktop.geometry.{Padding2D, Size2D} import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.node.nodes.RaidNode import ocelot.desktop.node.nodes.RaidNode
import ocelot.desktop.ui.layout.{AlignItems, Layout, LinearLayout} import ocelot.desktop.ui.layout.{AlignItems, Layout, LinearLayout}
import ocelot.desktop.ui.widget._ import ocelot.desktop.ui.widget._
@ -37,13 +37,7 @@ class RaidWindow(raidNode: RaidNode) extends PanelWindow {
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
// Background border // Background border
g.sprite( g.sprite(IconSource.Window.Raid.Slots, position, size)
"window/raid/Slots",
position.x,
position.y,
size.width,
size.height,
)
super.draw(g) super.draw(g)
} }

View File

@ -2,7 +2,7 @@ package ocelot.desktop.windows
import ocelot.desktop.color.RGBAColorNorm import ocelot.desktop.color.RGBAColorNorm
import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D, Vector2D} import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.node.nodes.ScreenNode import ocelot.desktop.node.nodes.ScreenNode
import ocelot.desktop.node.nodes.ScreenNode.{FontHeight, FontWidth} import ocelot.desktop.node.nodes.ScreenNode.{FontHeight, FontWidth}
import ocelot.desktop.ui.UiHandler import ocelot.desktop.ui.UiHandler
@ -147,8 +147,8 @@ class ScreenWindow(screenNode: ScreenNode) extends PanelWindow with Logging {
super.update() super.update()
if (scaleDragPoint.isDefined || scaleDragRegion.contains(UiHandler.mousePosition)) { if (scaleDragPoint.isDefined || scaleDragRegion.contains(UiHandler.mousePosition)) {
root.get.statusBar.addMouseEntry("icons/DragLMB", "Scale screen") root.get.statusBar.addMouseEntry(IconSource.Icons.DragLMB, "Scale screen")
root.get.statusBar.addKeyMouseEntry("icons/DragLMB", "SHIFT", "Scale screen (magnify)") root.get.statusBar.addKeyMouseEntry(IconSource.Icons.DragLMB, "Shift", "Scale screen (magnify)")
} }
} }

View File

@ -39,12 +39,12 @@ class TapeDriveWindow(val tapeDriveNode: TapeDriveNode) extends PanelWindow {
override def draw(g: Graphics): Unit = { override def draw(g: Graphics): Unit = {
// Screen background // Screen background
g.sprite( g.sprite(
"window/tape/Screen", IconSource.Window.Tape.Screen,
bounds, bounds,
) )
// A barely noticeable overlay showing the playback progress // A barely noticeable overlay showing the playback progress
// Btw Computronix doesn't have this feature, so I won't ruin the canon and make it too annoying // Btw Computronics doesn't have this feature, so I won't ruin the canon and make it too annoying
val playedPart = tapeDriveNode.tapeDrive.position.toFloat / tapeDriveNode.tapeDrive.size.toFloat val playedPart = tapeDriveNode.tapeDrive.position.toFloat / tapeDriveNode.tapeDrive.size.toFloat
if (playedPart > 0) { if (playedPart > 0) {