2020-05-31 19:36:10 +03:00

166 lines
4.6 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.event.{MouseEvent, ScrollEvent}
import ocelot.desktop.ui.{KeyEvents, UiHandler}
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 xAcceleration = 0f
private var yAcceleration = 0f
private var dragging = 0
private var mouseOldPos = Vector2D(0, 0)
def offset: Vector2D = Vector2D(xOffset, yOffset)
receiveMouseEvents = true
eventHandlers += {
case ScrollEvent(offset) =>
if (bounds.contains(UiHandler.mousePosition))
if (KeyEvents.isDown(42)) // shift
xAcceleration -= offset * 385f
else
yAcceleration -= offset * 385f
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
shouldClip = true
override def draw(g: Graphics): Unit = {
if (xOffset.abs > 0 || yOffset.abs > 0) {
inner.position = position - Vector2D(xOffset, yOffset)
}
inner.draw(g)
g.setScissor()
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()
xAcceleration *= 1f - 5f * UiHandler.dt
xAcceleration = xAcceleration.min(1540f).max(-1540f)
xOffset += xAcceleration * UiHandler.dt
yAcceleration *= 1f - 5f * UiHandler.dt
yAcceleration = yAcceleration.min(1540f).max(-1540f)
yOffset += yAcceleration * UiHandler.dt
clampOffsets()
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.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.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.8f, 0.25f, 0.45f, hAnim * 0.5f + 0.4f))
}
private def maxXOffset: Float = inner.size.width - size.width
private def maxYOffset: Float = inner.size.height - size.height
private def clampOffsets(): Unit = {
xOffset = xOffset.min(maxXOffset).max(0f)
yOffset = yOffset.min(maxYOffset).max(0f)
}
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
}