mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 02:59:19 +01:00
Merge branch 'feature/scrollable-context-menu' into develop
This commit is contained in:
commit
9ced3b99b4
@ -4,6 +4,6 @@ object FloatUtils {
|
||||
implicit class ExtendedFloat(val v: Float) extends AnyVal {
|
||||
def lerp(that: Float, alpha: Float): Float = v * (1 - alpha) + that * alpha
|
||||
|
||||
def clamp(min: Float = 0f, max: Float = 1f): Float = v.min(max).max(min)
|
||||
def clamped(min: Float = 0f, max: Float = 1f): Float = v.min(max).max(min)
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ case class Vector3D(x: Float, y: Float, z: Float) {
|
||||
)
|
||||
|
||||
def angle(that: Vector3D): Float = {
|
||||
math.acos((dot(that) / length / that.length).clamp(-1, 1)).toFloat
|
||||
math.acos((dot(that) / length / that.length).clamped(-1, 1)).toFloat
|
||||
}
|
||||
|
||||
def lerp(that: Vector3D, alpha: Float): Vector3D = {
|
||||
|
||||
@ -39,9 +39,9 @@ trait OcelotLogParticleNode extends Node {
|
||||
private class LogParticle extends Particle(time = -LogParticleGrow, speed = LogParticleMoveSpeed, origin = Some(this)) {
|
||||
private val angle: Float = Random.between(0f, 2 * math.Pi.toFloat * LogParticleMaxAngle)
|
||||
override def draw(g: Graphics): Unit = {
|
||||
val size = (1 + time / LogParticleGrow).clamp() * LogParticleSize
|
||||
val offset = time.clamp() * LogParticleMoveDistance
|
||||
val alpha = 1 - time.clamp()
|
||||
val size = (1 + time / LogParticleGrow).clamped() * LogParticleSize
|
||||
val offset = time.clamped() * LogParticleMoveDistance
|
||||
val alpha = 1 - time.clamped()
|
||||
|
||||
val r1 = (bounds.w max bounds.h) / math.sqrt(2) + offset + LogParticlePadding
|
||||
val r2 = r1 + size
|
||||
|
||||
@ -64,7 +64,7 @@ class OcelotBlockNode(val ocelot: OcelotBlock)
|
||||
}
|
||||
|
||||
private def drawActivity(g: Graphics, icon: IconSource, lastActivity: Long, currentTime: Long): Unit = {
|
||||
val alpha = (1 - (currentTime - lastActivity) / ActivityFadeOutMs).clamp()
|
||||
val alpha = (1 - (currentTime - lastActivity) / ActivityFadeOutMs).clamped()
|
||||
|
||||
if (alpha > 0) {
|
||||
g.sprite(
|
||||
|
||||
@ -92,7 +92,7 @@ class ScrollView(val inner: Widget) extends Widget with Logging with HoverHandle
|
||||
private def nextOffsetVelocity(x: Float, v: Float, dt: Float): (Float, Float) = {
|
||||
var x_ = x
|
||||
var v_ = v
|
||||
v_ = v_.clamp(-MaxScrollVelocity, MaxScrollVelocity)
|
||||
v_ = v_.clamped(-MaxScrollVelocity, MaxScrollVelocity)
|
||||
x_ += v_ * dt
|
||||
// exponential decay.
|
||||
v_ *= math.exp(-DecayFactor * UiHandler.dt).toFloat
|
||||
@ -141,8 +141,8 @@ class ScrollView(val inner: Widget) extends Widget with Logging with HoverHandle
|
||||
val vAnimDir = if (isHovered && vThumbHoverArea.contains(mousePos) || dragState.isVertical) 1 else -1
|
||||
val hAnimDir = if (isHovered && hThumbHoverArea.contains(mousePos) || dragState.isHorizontal) 1 else -1
|
||||
|
||||
vAnim = (vAnim + UiHandler.dt / 0.2f * vAnimDir).clamp()
|
||||
hAnim = (hAnim + UiHandler.dt / 0.2f * hAnimDir).clamp()
|
||||
vAnim = (vAnim + UiHandler.dt / 0.2f * vAnimDir).clamped()
|
||||
hAnim = (hAnim + UiHandler.dt / 0.2f * hAnimDir).clamped()
|
||||
|
||||
dragState match {
|
||||
case DragState.Vertical(startOffset, startPos) =>
|
||||
@ -178,8 +178,8 @@ class ScrollView(val inner: Widget) extends Widget with Logging with HoverHandle
|
||||
private def maxYOffset: Float = inner.size.height - size.height
|
||||
|
||||
private def clampOffsets(resetVelocities: Boolean): Unit = {
|
||||
val newXOffset = xOffset.clamp(max = maxXOffset)
|
||||
val newYOffset = yOffset.clamp(max = maxYOffset)
|
||||
val newXOffset = xOffset.clamped(max = maxXOffset)
|
||||
val newYOffset = yOffset.clamped(max = maxYOffset)
|
||||
|
||||
if (resetVelocities) {
|
||||
if (xOffset != newXOffset) {
|
||||
|
||||
@ -29,7 +29,7 @@ class Slider(var value: Float, val text: String, val snapPoints: Int = 0)
|
||||
private val soundInterval = 3.0f
|
||||
|
||||
private def calculateValue(x: Float): Unit = {
|
||||
value = ((x - bounds.x - handleWidth / 2f) / (bounds.w - handleWidth)).clamp(0f, 1f)
|
||||
value = ((x - bounds.x - handleWidth / 2f) / (bounds.w - handleWidth)).clamped(0f, 1f)
|
||||
onValueChanged(value)
|
||||
}
|
||||
|
||||
|
||||
@ -113,7 +113,7 @@ abstract class Viewport3DWidget extends Widget with MouseHandler with HoverHandl
|
||||
eventHandlers += {
|
||||
case ScrollEvent(offset) =>
|
||||
cameraFinalDistance = (if (offset > 0) cameraFinalDistance / ScrollSpeed else cameraFinalDistance * ScrollSpeed)
|
||||
.clamp(MinDistance, MaxDistance)
|
||||
.clamped(MinDistance, MaxDistance)
|
||||
|
||||
case event @ DragEvent(DragEvent.State.Drag, MouseEvent.Button.Left, _) if KeyEvents.isShiftDown =>
|
||||
val basis = cameraFinalTransform.basis
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package ocelot.desktop.ui.widget.contextmenu
|
||||
|
||||
import ocelot.desktop.ColorScheme
|
||||
import ocelot.desktop.geometry.Padding2D
|
||||
import ocelot.desktop.geometry.{Padding2D, Size2D}
|
||||
import ocelot.desktop.graphics.Graphics
|
||||
import ocelot.desktop.ui.layout.LinearLayout
|
||||
import ocelot.desktop.ui.widget.{PaddingBox, Widget}
|
||||
import ocelot.desktop.ui.layout.{CopyLayout, Layout, LinearLayout}
|
||||
import ocelot.desktop.ui.widget.{PaddingBox, ScrollView, Widget}
|
||||
import ocelot.desktop.util.animation.ValueAnimation
|
||||
import ocelot.desktop.util.animation.easing.EaseInOutQuad
|
||||
import ocelot.desktop.util.{DrawUtils, Orientation}
|
||||
@ -12,6 +12,8 @@ import ocelot.desktop.util.{DrawUtils, Orientation}
|
||||
import scala.collection.immutable.ArraySeq
|
||||
|
||||
class ContextMenu extends Widget {
|
||||
override protected val layout: Layout = new CopyLayout(this)
|
||||
|
||||
private[contextmenu] var isClosing = false
|
||||
private[contextmenu] var isOpening = false
|
||||
|
||||
@ -22,7 +24,11 @@ class ContextMenu extends Widget {
|
||||
override protected val layout = new LinearLayout(this, orientation = Orientation.Vertical)
|
||||
}
|
||||
|
||||
children :+= new PaddingBox(inner, Padding2D(top = 4, bottom = 4))
|
||||
private val scrollViewContents = new PaddingBox(inner, Padding2D(top = 4, bottom = 4))
|
||||
|
||||
children :+= new ScrollView(scrollViewContents)
|
||||
|
||||
def preferredSize: Size2D = scrollViewContents.minimumSize
|
||||
|
||||
private[contextmenu] def contextMenus: ContextMenus = _contextMenus
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package ocelot.desktop.ui.widget.contextmenu
|
||||
|
||||
import ocelot.desktop.geometry.FloatUtils.ExtendedFloat
|
||||
import ocelot.desktop.geometry.Vector2D
|
||||
import ocelot.desktop.graphics.Graphics
|
||||
import ocelot.desktop.ui.UiHandler
|
||||
@ -47,17 +48,28 @@ class ContextMenus extends Widget {
|
||||
if (!isSubmenu) for (child <- menus) close(child)
|
||||
|
||||
menu.recalculateBounds()
|
||||
menu.size = menu.minimumSize
|
||||
|
||||
val size = menu.size
|
||||
var pos = openPos
|
||||
def fit(openPos: Float, flipPos: Float, menuSize: Float, size: Float): Float = {
|
||||
if (openPos + menuSize <= size) {
|
||||
// fits in the positive direction.
|
||||
openPos
|
||||
} else if (flipPos >= menuSize) {
|
||||
// fits in the negative direction.
|
||||
flipPos - menuSize
|
||||
} else {
|
||||
// lay in the positive direction, moving back to fit, but not outside the edge.
|
||||
(size - menuSize).max(0)
|
||||
}
|
||||
}
|
||||
|
||||
if (pos.x + size.width > width)
|
||||
pos = pos.setX(xFlipPos - size.width)
|
||||
if (pos.y + size.height > height)
|
||||
pos = pos.setY(yFlipPos - size.height)
|
||||
val size = menu.preferredSize
|
||||
val pos = Vector2D(
|
||||
fit(openPos.x, xFlipPos, size.width, width),
|
||||
fit(openPos.y, yFlipPos, size.height, height),
|
||||
)
|
||||
|
||||
menu.position = pos
|
||||
menu.size = size.copy(height = size.height.clamped(max = height))
|
||||
|
||||
menu.contextMenus = this
|
||||
menu.open()
|
||||
|
||||
@ -174,7 +174,7 @@ class HologramProjectorWindow(val hologramProjectorNode: HologramProjectorNode)
|
||||
|
||||
val subTick =
|
||||
(System.nanoTime() - workspace.getLastTickNanoTime).toFloat / 1e9f / OcelotDesktop.tpsCounter.dt.max(1e-9f)
|
||||
val time = workspace.getIngameTime + subTick.clamp(0, 1)
|
||||
val time = workspace.getIngameTime + subTick.clamped(0, 1)
|
||||
|
||||
var transform = Transform3D.translate(0.5f, 0.5f, 0.5f) *
|
||||
Transform3D.rotate(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user