2019-09-21 14:36:10 +03:00

146 lines
4.0 KiB
Scala

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.UiHandler
import ocelot.desktop.ui.event.MouseEvent
import ocelot.desktop.util.Logging
class ScrollView(val inner: Widget) extends Widget with Logging {
inner.size = Size2D.Zero
children +:= inner
private var xOffset = 0f
private var yOffset = 0f
private var dragging = 0
private var mouseOldPos = Vector2D(0, 0)
eventHandlers += {
case event: MouseEvent if event.state == MouseEvent.State.Press =>
val pos = UiHandler.mousePosition
mouseOldPos = pos
if (vThumbBounds.contains(pos))
dragging = 1
else if (hThumbBounds.contains(pos))
dragging = 2
else
dragging = 0
case event: MouseEvent if event.state == MouseEvent.State.Release =>
dragging = 0
}
override def minimumSize: Size2D = Size2D.Zero
override def maximumSize: Size2D = inner.maximumSize
override def draw(g: Graphics): Unit = {
g.setScissor(position.x, position.y, size.width, size.height)
if (xOffset.abs > 0 || yOffset.abs > 0) {
inner.position = position - Vector2D(xOffset, yOffset)
}
inner.draw(g)
g.setScissor()
g.sprite = "Empty"
if (vThumbVisible)
drawVThumb(g)
if (hThumbVisible)
drawHThumb(g)
}
override def size_=(value: Size2D): Unit = {
super.size_=(value)
inner.size = value
clampOffsets()
}
private var vAnim = 0f
private var vAnimDir = -1
private var hAnim = 0f
private var hAnimDir = -1
override def update(): Unit = {
super.update()
val mousePos = UiHandler.mousePosition
vAnimDir = if (vThumbHoverArea.contains(mousePos) || dragging == 1) 1 else -1
hAnimDir = if (hThumbHoverArea.contains(mousePos) || dragging == 2) 1 else -1
vAnim = math.max(0f, math.min(1f, vAnim + UiHandler.dt / 0.2f * vAnimDir))
hAnim = math.max(0f, math.min(1f, hAnim + UiHandler.dt / 0.2f * hAnimDir))
if (dragging == 0) return
if (dragging == 1) {
val dy = (mousePos - mouseOldPos).y
yOffset += dy / vThumbCoeff
} else if (dragging == 2) {
val dx = (mousePos - mouseOldPos).x
xOffset += dx / hThumbCoeff
}
clampOffsets()
mouseOldPos = mousePos
}
private def drawVThumb(g: Graphics): Unit = {
val b = vThumbBounds
g.foreground = RGBAColorNorm(0.9f, 0.9f, 0.9f, vAnim * 0.15f)
g.rect(position.x + size.width - 11, position.y, 10, size.height)
g.foreground = RGBAColorNorm(0.6f, 0.15f, 0.35f, vAnim * 0.5f + 0.4f)
g.rect(b.x + 3, b.y, b.w - 6, b.h)
}
private def drawHThumb(g: Graphics): Unit = {
val b = hThumbBounds
g.foreground = RGBAColorNorm(0.9f, 0.9f, 0.9f, hAnim * 0.15f)
g.rect(position.x, position.y + size.height - 11, size.width - 12, 10)
g.foreground = RGBAColorNorm(0.6f, 0.15f, 0.35f, hAnim * 0.5f + 0.4f)
g.rect(b.x, b.y + 3, b.w, b.h - 6)
}
private def clampOffsets(): Unit = {
xOffset = math.max(0, math.min(inner.size.width - size.width, xOffset))
yOffset = math.max(0, math.min(inner.size.height - size.height, yOffset))
}
private def vThumbHoverArea: Rect2D = {
Rect2D(position.x + size.width - 12, position.y, 12, size.height)
}
private def vThumbBounds: Rect2D = {
val x = position.x + size.width - 12
val y = position.y + yOffset * vThumbCoeff
Rect2D(x, y + 2, 12, vThumbCoeff * size.height)
}
private def hThumbHoverArea: Rect2D = {
Rect2D(position.x, position.y + size.height - 12, size.width, 12)
}
private def hThumbBounds: Rect2D = {
val x = position.x + xOffset * hThumbCoeff
val y = position.y + size.height - 12
Rect2D(x + 2, y, hThumbCoeff * size.width, 12)
}
private def vThumbVisible: Boolean = inner.size.height > size.height
private def hThumbVisible: Boolean = inner.size.width > size.width
private def vThumbCoeff: Float = (size.height - 4) / inner.size.height
private def hThumbCoeff: Float = (size.width - 14) / inner.size.width
}