mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 02:59:19 +01:00
Pull ScreenView out of ScreenWindow
This commit is contained in:
parent
6babdcf6d8
commit
182d42a843
@ -460,7 +460,7 @@ object UiHandler extends Logging {
|
|||||||
ScrollEvents.events.foreach(dispatchEvent(scrollTarget))
|
ScrollEvents.events.foreach(dispatchEvent(scrollTarget))
|
||||||
|
|
||||||
for (event <- MouseEvents.events) {
|
for (event <- MouseEvents.events) {
|
||||||
if (event.state == MouseEvent.State.Press) {
|
if (event.state == MouseEvent.State.Pressed) {
|
||||||
dispatchEvent(mouseTarget)(event)
|
dispatchEvent(mouseTarget)(event)
|
||||||
|
|
||||||
// TODO: this should be done in the event capturing phase in [[Window]] itself.
|
// TODO: this should be done in the event capturing phase in [[Window]] itself.
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package ocelot.desktop.ui.event
|
|||||||
|
|
||||||
object MouseEvent {
|
object MouseEvent {
|
||||||
object State extends Enumeration {
|
object State extends Enumeration {
|
||||||
val Press, Release = Value
|
val Pressed, Released = Value
|
||||||
}
|
}
|
||||||
|
|
||||||
object Button extends Enumeration {
|
object Button extends Enumeration {
|
||||||
|
|||||||
@ -25,10 +25,10 @@ trait MouseHandler extends Widget {
|
|||||||
protected def allowClickReleaseOutsideThreshold: Boolean = !receiveDragEvents
|
protected def allowClickReleaseOutsideThreshold: Boolean = !receiveDragEvents
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, button) =>
|
case MouseEvent(MouseEvent.State.Pressed, button) =>
|
||||||
startPositions += (button -> UiHandler.mousePosition)
|
startPositions += (button -> UiHandler.mousePosition)
|
||||||
|
|
||||||
case MouseEvent(MouseEvent.State.Release, button) =>
|
case MouseEvent(MouseEvent.State.Released, button) =>
|
||||||
val mousePos = UiHandler.mousePosition
|
val mousePos = UiHandler.mousePosition
|
||||||
|
|
||||||
val dragStopped = receiveDragEvents && dragButtons.remove(button)
|
val dragStopped = receiveDragEvents && dragButtons.remove(button)
|
||||||
|
|||||||
@ -25,12 +25,12 @@ object MouseEvents {
|
|||||||
|
|
||||||
if (MouseEvent.Button.values.map(_.id).contains(buttonIdx)) {
|
if (MouseEvent.Button.values.map(_.id).contains(buttonIdx)) {
|
||||||
val button = MouseEvent.Button(buttonIdx)
|
val button = MouseEvent.Button(buttonIdx)
|
||||||
val state = if (Mouse.getEventButtonState) MouseEvent.State.Press else MouseEvent.State.Release
|
val state = if (Mouse.getEventButtonState) MouseEvent.State.Pressed else MouseEvent.State.Released
|
||||||
_events += MouseEvent(state, button)
|
_events += MouseEvent(state, button)
|
||||||
state match {
|
state match {
|
||||||
case MouseEvent.State.Press =>
|
case MouseEvent.State.Pressed =>
|
||||||
_pressedButtons += button
|
_pressedButtons += button
|
||||||
case MouseEvent.State.Release =>
|
case MouseEvent.State.Released =>
|
||||||
_pressedButtons -= button
|
_pressedButtons -= button
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ object MouseEvents {
|
|||||||
|
|
||||||
def releaseButtons(): Unit = {
|
def releaseButtons(): Unit = {
|
||||||
for (button <- pressedButtons) {
|
for (button <- pressedButtons) {
|
||||||
_events += MouseEvent(MouseEvent.State.Release, button)
|
_events += MouseEvent(MouseEvent.State.Released, button)
|
||||||
}
|
}
|
||||||
|
|
||||||
_pressedButtons.clear()
|
_pressedButtons.clear()
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class Button(tooltip: Option[Tooltip] = None) extends Widget with MouseHandler w
|
|||||||
override protected def receiveClickEvents: Boolean = true
|
override protected def receiveClickEvents: Boolean = true
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, MouseEvent.Button.Left) if enabled =>
|
case MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) if enabled =>
|
||||||
clickSoundSource.press.play()
|
clickSoundSource.press.play()
|
||||||
|
|
||||||
case ClickEvent(MouseEvent.Button.Left, _) if enabled =>
|
case ClickEvent(MouseEvent.Button.Left, _) if enabled =>
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class IconButton(
|
|||||||
case HoverEvent(HoverEvent.State.Enter) => onHoverEnter()
|
case HoverEvent(HoverEvent.State.Enter) => onHoverEnter()
|
||||||
case HoverEvent(HoverEvent.State.Leave) => onHoverLeave()
|
case HoverEvent(HoverEvent.State.Leave) => onHoverLeave()
|
||||||
|
|
||||||
case MouseEvent(MouseEvent.State.Press, MouseEvent.Button.Left) =>
|
case MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) =>
|
||||||
mode match {
|
mode match {
|
||||||
case Mode.Regular => handlePress()
|
case Mode.Regular => handlePress()
|
||||||
case _ => // the other modes are triggered on click.
|
case _ => // the other modes are triggered on click.
|
||||||
@ -43,7 +43,7 @@ class IconButton(
|
|||||||
|
|
||||||
clickSoundSource.press.play()
|
clickSoundSource.press.play()
|
||||||
|
|
||||||
case MouseEvent(MouseEvent.State.Release, MouseEvent.Button.Left) => mode match {
|
case MouseEvent(MouseEvent.State.Released, MouseEvent.Button.Left) => mode match {
|
||||||
case Mode.Regular if model.pressed =>
|
case Mode.Regular if model.pressed =>
|
||||||
handleRelease()
|
handleRelease()
|
||||||
clickSoundSource.release.play()
|
clickSoundSource.release.play()
|
||||||
|
|||||||
@ -28,14 +28,14 @@ abstract class Knob(dyeColor: DyeColor = DyeColor.Red) extends Widget {
|
|||||||
private var startValue: Int = 0
|
private var startValue: Int = 0
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, MouseEvent.Button.Left) =>
|
case MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) =>
|
||||||
val mousePos = UiHandler.mousePosition
|
val mousePos = UiHandler.mousePosition
|
||||||
if (bounds.contains(mousePos)) {
|
if (bounds.contains(mousePos)) {
|
||||||
movePos = Some(mousePos)
|
movePos = Some(mousePos)
|
||||||
startValue = input
|
startValue = input
|
||||||
}
|
}
|
||||||
|
|
||||||
case MouseEvent(MouseEvent.State.Release, MouseEvent.Button.Left) =>
|
case MouseEvent(MouseEvent.State.Released, MouseEvent.Button.Left) =>
|
||||||
movePos = None
|
movePos = None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class MenuBarButton(label: String, handler: () => Unit = () => {}) extends Widge
|
|||||||
def onMouseLeave(): Unit = colorAnimation.goto(ColorScheme("TitleBarBackground"))
|
def onMouseLeave(): Unit = colorAnimation.goto(ColorScheme("TitleBarBackground"))
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, MouseEvent.Button.Left) =>
|
case MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) =>
|
||||||
clickSoundSource.press.play()
|
clickSoundSource.press.play()
|
||||||
|
|
||||||
case ClickEvent(MouseEvent.Button.Left, _) =>
|
case ClickEvent(MouseEvent.Button.Left, _) =>
|
||||||
|
|||||||
189
src/main/scala/ocelot/desktop/ui/widget/ScreenView.scala
Normal file
189
src/main/scala/ocelot/desktop/ui/widget/ScreenView.scala
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
package ocelot.desktop.ui.widget
|
||||||
|
|
||||||
|
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
|
||||||
|
import ocelot.desktop.graphics.Graphics
|
||||||
|
import ocelot.desktop.graphics.Texture.MinFilteringMode
|
||||||
|
import ocelot.desktop.node.nodes.ScreenNode
|
||||||
|
import ocelot.desktop.node.nodes.ScreenNode.{FontHeight, FontWidth}
|
||||||
|
import ocelot.desktop.ui.UiHandler
|
||||||
|
import ocelot.desktop.ui.event.{KeyEvent, MouseEvent, ScrollEvent}
|
||||||
|
import ocelot.desktop.ui.layout.Layout
|
||||||
|
import ocelot.desktop.ui.widget.ScreenView.ScaleTag
|
||||||
|
import ocelot.desktop.util.{Keybind, Persistable, Register}
|
||||||
|
import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings}
|
||||||
|
import org.lwjgl.input.Keyboard
|
||||||
|
import totoro.ocelot.brain.nbt.NBTTagCompound
|
||||||
|
import totoro.ocelot.brain.util.Tier
|
||||||
|
|
||||||
|
// TODO: use an interface instead of ScreenNode.
|
||||||
|
abstract class ScreenView(screenNode: ScreenNode) extends Widget with Persistable {
|
||||||
|
override protected val layout: Layout = new Layout(this)
|
||||||
|
|
||||||
|
private var lastMousePos = Vector2D.Zero
|
||||||
|
|
||||||
|
val scale = Register(1f)
|
||||||
|
def scaleX: Float = (FontWidth * scale.value).floor / FontWidth
|
||||||
|
def scaleY: Float = (FontHeight * scale.value).floor / FontHeight
|
||||||
|
|
||||||
|
private def screenWidth: Int = screenNode.screenWidth
|
||||||
|
private def screenHeight: Int = screenNode.screenHeight
|
||||||
|
|
||||||
|
override def minimumSize: Size2D = Size2D(
|
||||||
|
screenWidth * FontWidth * scaleX,
|
||||||
|
screenHeight * FontHeight * scaleY,
|
||||||
|
)
|
||||||
|
|
||||||
|
override def maximumSize: Size2D = minimumSize
|
||||||
|
|
||||||
|
private def toBufferCoords(p: Vector2D): Vector2D = {
|
||||||
|
// no synchronization here (see the note in ScreenNode): the method to change this property is indirect.
|
||||||
|
if (screenNode.screen.getPrecisionMode) {
|
||||||
|
Vector2D(
|
||||||
|
(p.x - position.x) / FontWidth / scaleX,
|
||||||
|
(p.y - position.y) / FontHeight / scaleY,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Vector2D(
|
||||||
|
math.floor((p.x - position.x) / FontWidth / scaleX),
|
||||||
|
math.floor((p.y - position.y) / FontHeight / scaleY),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def bufferCoordsInBounds(p: Vector2D): Boolean =
|
||||||
|
new Rect2D(0, 0, screenWidth, screenHeight).contains(p)
|
||||||
|
|
||||||
|
private def mouseCoordsInBounds: Boolean =
|
||||||
|
bufferCoordsInBounds(toBufferCoords(UiHandler.mousePosition))
|
||||||
|
|
||||||
|
override def receiveMouseEvents: Boolean = true
|
||||||
|
|
||||||
|
override def receiveScrollEvents: Boolean = true
|
||||||
|
|
||||||
|
protected def isFocused: Boolean
|
||||||
|
|
||||||
|
private def shouldHandleInput: Boolean = isFocused && !root.get.modalDialogPool.isVisible
|
||||||
|
|
||||||
|
// OC doesn't trigger several touch events in a row; the same holds for drop events.
|
||||||
|
// For the following inputs:
|
||||||
|
// LMB down, RMB down, RMB up, LMB up
|
||||||
|
// ...OC only registers LMB down and RMB up, dropping the other two events.
|
||||||
|
private var pressedButton: Option[MouseEvent.Button.Value] = None
|
||||||
|
|
||||||
|
// NOTE: events are handled before update().
|
||||||
|
// if the brain initiates a viewport size change, mouse events could be sent for coordinates outside the new bounds.
|
||||||
|
// TODO: look into how OpenComputers deals with that, if it does at all.
|
||||||
|
eventHandlers += {
|
||||||
|
case event: KeyEvent if shouldHandleInput && event.code != Keyboard.KEY_ESCAPE =>
|
||||||
|
event.state match {
|
||||||
|
case KeyEvent.State.Press | KeyEvent.State.Repeat =>
|
||||||
|
screenNode.screen.keyDown(event.char, event.code, OcelotDesktop.player)
|
||||||
|
|
||||||
|
// note: in OpenComputers, key_down signal is fired __before__ clipboard signal
|
||||||
|
if (event.code == Settings.get.keymap(Keybind.Insert)) {
|
||||||
|
screenNode.screen.clipboard(UiHandler.clipboard, OcelotDesktop.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
case KeyEvent.State.Release =>
|
||||||
|
screenNode.screen.keyUp(event.char, event.code, OcelotDesktop.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
event.consume()
|
||||||
|
|
||||||
|
case event: MouseEvent if shouldHandleInput =>
|
||||||
|
val pos = toBufferCoords(UiHandler.mousePosition)
|
||||||
|
val inBounds = bufferCoordsInBounds(pos)
|
||||||
|
|
||||||
|
if (inBounds) {
|
||||||
|
lastMousePos = pos
|
||||||
|
}
|
||||||
|
|
||||||
|
event.state match {
|
||||||
|
case MouseEvent.State.Pressed if inBounds && screenNode.screen.tier > Tier.One =>
|
||||||
|
if (pressedButton.isEmpty) {
|
||||||
|
screenNode.screen.mouseDown(pos.x, pos.y, event.button.id, OcelotDesktop.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
pressedButton = Some(event.button)
|
||||||
|
event.consume()
|
||||||
|
|
||||||
|
case MouseEvent.State.Released =>
|
||||||
|
if (inBounds && event.button == MouseEvent.Button.Middle) {
|
||||||
|
screenNode.screen.clipboard(UiHandler.clipboard, OcelotDesktop.player)
|
||||||
|
event.consume()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pressedButton.nonEmpty) {
|
||||||
|
screenNode.screen.mouseUp(lastMousePos.x, lastMousePos.y, event.button.id, OcelotDesktop.player)
|
||||||
|
pressedButton = None
|
||||||
|
|
||||||
|
if (inBounds) {
|
||||||
|
event.consume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
|
||||||
|
case event: ScrollEvent if mouseCoordsInBounds && shouldHandleInput && screenNode.screen.tier > Tier.One =>
|
||||||
|
screenNode.screen.mouseScroll(lastMousePos.x, lastMousePos.y, event.offset, OcelotDesktop.player)
|
||||||
|
event.consume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override def save(nbt: NBTTagCompound): Unit = {
|
||||||
|
nbt.setFloat(ScaleTag, scale.value)
|
||||||
|
super.save(nbt)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def load(nbt: NBTTagCompound): Unit = {
|
||||||
|
super.load(nbt)
|
||||||
|
scale.nextValue = nbt.getFloat(ScaleTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val screenSize = Register.sampling(Size2D(screenWidth, screenHeight))
|
||||||
|
|
||||||
|
override def update(): Unit = {
|
||||||
|
super.update()
|
||||||
|
|
||||||
|
// NOTE: the single bar is intentional! both operands have to be evaluated.
|
||||||
|
if (scale.update() | screenSize.update()) {
|
||||||
|
recalculateBoundsAndRelayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
val mousePos = toBufferCoords(UiHandler.mousePosition)
|
||||||
|
|
||||||
|
if (bufferCoordsInBounds(mousePos) && mousePos != lastMousePos) {
|
||||||
|
lastMousePos = mousePos
|
||||||
|
|
||||||
|
if (isFocused && screenNode.screen.tier > Tier.One) {
|
||||||
|
for (button <- pressedButton) {
|
||||||
|
screenNode.screen.mouseDrag(lastMousePos.x, lastMousePos.y, button.id, OcelotDesktop.player)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def draw(g: Graphics): Unit = {
|
||||||
|
// no synchronization here (see the note in ScreenNode): the methods to turn the screen on/off are indirect.
|
||||||
|
if (screenNode.screen.getPowerState) {
|
||||||
|
screenNode.drawScreenData(
|
||||||
|
g,
|
||||||
|
position.x,
|
||||||
|
position.y,
|
||||||
|
scaleX,
|
||||||
|
scaleY,
|
||||||
|
if (Settings.get.screenWindowMipmap) {
|
||||||
|
MinFilteringMode.LinearMipmapLinear
|
||||||
|
} else {
|
||||||
|
MinFilteringMode.Nearest
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
g.rect(bounds, ColorScheme("ScreenOff"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ScreenView {
|
||||||
|
private val ScaleTag: String = "scale"
|
||||||
|
}
|
||||||
@ -45,7 +45,7 @@ class ScrollView(val inner: Widget) extends Widget with Logging with HoverHandle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case event: MouseEvent if event.state == MouseEvent.State.Press =>
|
case event: MouseEvent if event.state == MouseEvent.State.Pressed =>
|
||||||
val pos = UiHandler.mousePosition
|
val pos = UiHandler.mousePosition
|
||||||
mouseOldPos = pos
|
mouseOldPos = pos
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class ScrollView(val inner: Widget) extends Widget with Logging with HoverHandle
|
|||||||
scrollToEnd = false
|
scrollToEnd = false
|
||||||
}
|
}
|
||||||
|
|
||||||
case event: MouseEvent if event.state == MouseEvent.State.Release =>
|
case event: MouseEvent if event.state == MouseEvent.State.Released =>
|
||||||
dragging = 0
|
dragging = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@ class Slider(var value: Float, val text: String, val snapPoints: Int = 0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, MouseEvent.Button.Left) =>
|
case MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) =>
|
||||||
clickSoundSource.press.play()
|
clickSoundSource.press.play()
|
||||||
|
|
||||||
case ClickEvent(MouseEvent.Button.Left, pos) =>
|
case ClickEvent(MouseEvent.Button.Left, pos) =>
|
||||||
|
|||||||
@ -58,7 +58,7 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w
|
|||||||
private var prevEnabled = enabled
|
private var prevEnabled = enabled
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Release, MouseEvent.Button.Left) =>
|
case MouseEvent(MouseEvent.State.Released, MouseEvent.Button.Left) =>
|
||||||
if (isFocused && !clippedBounds.contains(UiHandler.mousePosition)) {
|
if (isFocused && !clippedBounds.contains(UiHandler.mousePosition)) {
|
||||||
unfocus()
|
unfocus()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,7 +69,7 @@ class ContextMenuEntry(
|
|||||||
override protected def receiveClickEvents: Boolean = true
|
override protected def receiveClickEvents: Boolean = true
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, MouseEvent.Button.Left) if !contextMenu.isOpening =>
|
case MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) if !contextMenu.isOpening =>
|
||||||
clickSoundSource.press.play()
|
clickSoundSource.press.play()
|
||||||
case ClickEvent(MouseEvent.Button.Left, _) if !contextMenu.isOpening => clicked()
|
case ClickEvent(MouseEvent.Button.Left, _) if !contextMenu.isOpening => clicked()
|
||||||
case HoverEvent(HoverEvent.State.Enter) => enter()
|
case HoverEvent(HoverEvent.State.Enter) => enter()
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class ContextMenus extends Widget {
|
|||||||
case KeyEvent(KeyEvent.State.Press, Keyboard.KEY_ESCAPE, _) =>
|
case KeyEvent(KeyEvent.State.Press, Keyboard.KEY_ESCAPE, _) =>
|
||||||
closeAll()
|
closeAll()
|
||||||
|
|
||||||
case MouseEvent(MouseEvent.State.Press, _) =>
|
case MouseEvent(MouseEvent.State.Pressed, _) =>
|
||||||
if (!menus.map(_.bounds).exists(_.contains(UiHandler.mousePosition))) closeAll()
|
if (!menus.map(_.bounds).exists(_.contains(UiHandler.mousePosition))) closeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class VerticalMenuButton(icon: IconSource, label: String, handler: VerticalMenuB
|
|||||||
def onMouseLeave(): Unit = colorAnimation.goto(ColorScheme("VerticalMenuBackground"))
|
def onMouseLeave(): Unit = colorAnimation.goto(ColorScheme("VerticalMenuBackground"))
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, MouseEvent.Button.Left) =>
|
case MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) =>
|
||||||
clickSoundSource.press.play()
|
clickSoundSource.press.play()
|
||||||
|
|
||||||
case ClickEvent(MouseEvent.Button.Left, _) =>
|
case ClickEvent(MouseEvent.Button.Left, _) =>
|
||||||
|
|||||||
@ -53,9 +53,11 @@ trait BasicWindow extends Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected def borderRenderer: DrawUtils.BorderRenderer = DrawUtils.windowBorder
|
||||||
|
|
||||||
override def draw(g: Graphics): Unit = {
|
override def draw(g: Graphics): Unit = {
|
||||||
beginDraw(g)
|
beginDraw(g)
|
||||||
DrawUtils.windowWithShadow(g, position.x, position.y, size.width, size.height, 1f, 0.5f)
|
DrawUtils.windowWithShadow(g, position.x, position.y, size.width, size.height, 1f, 0.5f, borderRenderer)
|
||||||
drawChildren(g)
|
drawChildren(g)
|
||||||
endDraw(g)
|
endDraw(g)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,11 @@ trait PanelWindow extends BasicWindow {
|
|||||||
|
|
||||||
protected def titleMaxLength: Int = 32
|
protected def titleMaxLength: Int = 32
|
||||||
|
|
||||||
def setInner(inner: Widget, padding: Padding2D = Padding2D(bottom = 13, left = 12, right = 12)): Unit = {
|
def setInner(
|
||||||
|
inner: Widget,
|
||||||
|
padding: Padding2D = Padding2D(bottom = 13, left = 12, right = 12),
|
||||||
|
titlePadding: Padding2D = Padding2D(top = 8, left = 12, right = 12, bottom = 2),
|
||||||
|
): Unit = {
|
||||||
children = ArraySeq.empty
|
children = ArraySeq.empty
|
||||||
|
|
||||||
children :+= new PaddingBox(
|
children :+= new PaddingBox(
|
||||||
@ -22,7 +26,7 @@ trait PanelWindow extends BasicWindow {
|
|||||||
override def title: String = PanelWindow.this.title
|
override def title: String = PanelWindow.this.title
|
||||||
override def titleMaxLength: Int = PanelWindow.this.titleMaxLength
|
override def titleMaxLength: Int = PanelWindow.this.titleMaxLength
|
||||||
},
|
},
|
||||||
Padding2D(top = 8, left = 12, right = 12, bottom = 2),
|
titlePadding,
|
||||||
)
|
)
|
||||||
|
|
||||||
children :+= new PaddingBox(inner, padding)
|
children :+= new PaddingBox(inner, padding)
|
||||||
|
|||||||
@ -30,7 +30,7 @@ trait Window extends Widget with Persistable with MouseHandler {
|
|||||||
override protected def receiveDragEvents: Boolean = true
|
override protected def receiveDragEvents: Boolean = true
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case MouseEvent(MouseEvent.State.Press, _) =>
|
case MouseEvent(MouseEvent.State.Pressed, _) =>
|
||||||
focus()
|
focus()
|
||||||
|
|
||||||
case ev @ DragEvent(DragEvent.State.Start, MouseEvent.Button.Left, mousePos) =>
|
case ev @ DragEvent(DragEvent.State.Start, MouseEvent.Button.Left, mousePos) =>
|
||||||
|
|||||||
@ -17,24 +17,24 @@ object DrawUtils {
|
|||||||
h: Float,
|
h: Float,
|
||||||
color: Color = RGBAColor(255, 255, 255),
|
color: Color = RGBAColor(255, 255, 255),
|
||||||
): Unit = {
|
): Unit = {
|
||||||
g.sprite("screen/CornerTL", x - 16, y - 20, 16, 20, color)
|
g.sprite("screen/CornerTL", x, y, 16, 20, color)
|
||||||
g.sprite("screen/CornerTR", x + w, y - 20, 16, 20, color)
|
g.sprite("screen/CornerTR", x + w - 16, y, 16, 20, color)
|
||||||
g.sprite("screen/CornerBL", x - 16, y + h, 16, 16, color)
|
g.sprite("screen/CornerBL", x, y + h - 16, 16, 16, color)
|
||||||
g.sprite("screen/CornerBR", x + w, y + h, 16, 16, color)
|
g.sprite("screen/CornerBR", x + w - 16, y + h - 16, 16, 16, color)
|
||||||
|
|
||||||
g.sprite("screen/BorderT", x, y - 20, w, 20, color)
|
g.sprite("screen/BorderT", x + 16, y, w - 16 - 16, 20, color)
|
||||||
g.sprite("screen/BorderB", x, y + h, w, 16, color)
|
g.sprite("screen/BorderB", x + 16, y + h - 16, w - 16 - 16, 16, color)
|
||||||
|
|
||||||
g.save()
|
g.save()
|
||||||
g.translate(x - 16, y)
|
g.translate(x, y - 16)
|
||||||
g.rotate(270.toRadians)
|
g.rotate(270.toRadians)
|
||||||
g.sprite("screen/BorderB", -h, 0, h, 16, color)
|
g.sprite("screen/BorderB", -h, 0, h - 20 - 16, 16, color)
|
||||||
g.restore()
|
g.restore()
|
||||||
|
|
||||||
g.save()
|
g.save()
|
||||||
g.translate(x + w, y)
|
g.translate(x + w - 16, y - 16)
|
||||||
g.rotate(270.toRadians)
|
g.rotate(270.toRadians)
|
||||||
g.sprite("screen/BorderB", -h, 0, h, 16, color)
|
g.sprite("screen/BorderB", -h, 0, h - 20 - 16, 16, color)
|
||||||
g.restore()
|
g.restore()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +95,8 @@ object DrawUtils {
|
|||||||
if (alpha < 1f) g.endGroupAlpha(alpha)
|
if (alpha < 1f) g.endGroupAlpha(alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BorderRenderer = (Graphics, Float, Float, Float, Float, Color) => Unit
|
||||||
|
|
||||||
def windowWithShadow(
|
def windowWithShadow(
|
||||||
g: Graphics,
|
g: Graphics,
|
||||||
x: Float,
|
x: Float,
|
||||||
@ -103,9 +105,10 @@ object DrawUtils {
|
|||||||
h: Float,
|
h: Float,
|
||||||
backgroundAlpha: Float,
|
backgroundAlpha: Float,
|
||||||
shadowAlpha: Float,
|
shadowAlpha: Float,
|
||||||
|
borderRenderer: BorderRenderer = windowBorder
|
||||||
): Unit = {
|
): Unit = {
|
||||||
DrawUtils.shadow(g, x - 8, y - 8, w + 16, h + 20, shadowAlpha)
|
DrawUtils.shadow(g, x - 8, y - 8, w + 16, h + 20, shadowAlpha)
|
||||||
DrawUtils.windowBorder(g, x, y, w, h, RGBAColorNorm(1, 1, 1, backgroundAlpha))
|
borderRenderer(g, x, y, w, h, RGBAColorNorm(1, 1, 1, backgroundAlpha))
|
||||||
}
|
}
|
||||||
|
|
||||||
def ring(
|
def ring(
|
||||||
|
|||||||
64
src/main/scala/ocelot/desktop/util/Register.scala
Normal file
64
src/main/scala/ocelot/desktop/util/Register.scala
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package ocelot.desktop.util
|
||||||
|
|
||||||
|
import ocelot.desktop.ui.widget.Updatable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a value updated by calls to [[update]].
|
||||||
|
*/
|
||||||
|
trait Register[T] {
|
||||||
|
/**
|
||||||
|
* The currently stored value.
|
||||||
|
*/
|
||||||
|
def value: T
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the stored value.
|
||||||
|
*
|
||||||
|
* @return `true` if the value has changed.
|
||||||
|
*/
|
||||||
|
def update(): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
object Register {
|
||||||
|
class Writeable[T](initialValue: T) extends Register[T] {
|
||||||
|
private var _value: T = initialValue
|
||||||
|
override def value: T = _value
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value this register will be set to on next update.
|
||||||
|
*/
|
||||||
|
var nextValue: T = _value
|
||||||
|
|
||||||
|
override def update(): Boolean = {
|
||||||
|
val changed = nextValue != _value
|
||||||
|
_value = nextValue
|
||||||
|
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sampling[T](next: () => T) extends Register[T] {
|
||||||
|
private var _value = next()
|
||||||
|
override def value: T = _value
|
||||||
|
|
||||||
|
override def update(): Boolean = {
|
||||||
|
val nextValue = next()
|
||||||
|
val changed = nextValue != _value
|
||||||
|
_value = nextValue
|
||||||
|
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [[Register.Writeable writeable register]] with the given initial value.
|
||||||
|
*/
|
||||||
|
def apply[T](initialValue: T): Writeable[T] = new Writeable(initialValue)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [[Register.Sampling register]] that reevaluates the provided expression on every update.
|
||||||
|
*
|
||||||
|
* The expression is evaluated to compute the initial value.
|
||||||
|
*/
|
||||||
|
def sampling[T](nextValue: => T): Sampling[T] = new Sampling(() => nextValue)
|
||||||
|
}
|
||||||
@ -1,122 +1,59 @@
|
|||||||
package ocelot.desktop.windows
|
package ocelot.desktop.windows
|
||||||
|
|
||||||
import ocelot.desktop.audio.SoundSource
|
import ocelot.desktop.geometry.{Padding2D, Rect2D, Size2D, Vector2D}
|
||||||
import ocelot.desktop.color.RGBAColor
|
|
||||||
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
|
|
||||||
import ocelot.desktop.graphics.Graphics
|
|
||||||
import ocelot.desktop.graphics.Texture.MinFilteringMode
|
|
||||||
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
|
||||||
import ocelot.desktop.ui.event.sources.{KeyEvents, MouseEvents}
|
import ocelot.desktop.ui.event.sources.KeyEvents
|
||||||
import ocelot.desktop.ui.event.{DragEvent, KeyEvent, MouseEvent, ScrollEvent}
|
import ocelot.desktop.ui.event.{DragEvent, MouseEvent}
|
||||||
import ocelot.desktop.ui.widget.window.BasicWindow
|
import ocelot.desktop.ui.widget.ScreenView
|
||||||
import ocelot.desktop.util.{DrawUtils, Keybind, Logging}
|
import ocelot.desktop.ui.widget.window.PanelWindow
|
||||||
|
import ocelot.desktop.util.DrawUtils.BorderRenderer
|
||||||
|
import ocelot.desktop.util.{DrawUtils, Logging}
|
||||||
import ocelot.desktop.windows.ScreenWindow._
|
import ocelot.desktop.windows.ScreenWindow._
|
||||||
import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings}
|
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import totoro.ocelot.brain.entity.Screen
|
|
||||||
import totoro.ocelot.brain.nbt.NBTTagCompound
|
import totoro.ocelot.brain.nbt.NBTTagCompound
|
||||||
import totoro.ocelot.brain.util.Tier
|
|
||||||
|
|
||||||
class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
|
class ScreenWindow(screenNode: ScreenNode) extends PanelWindow with Logging {
|
||||||
private var lastMousePos = Vector2D(0, 0)
|
|
||||||
private var sentTouchEvent = false
|
|
||||||
private var startingWidth = 0f
|
private var startingWidth = 0f
|
||||||
private var scaleDragPoint: Option[Vector2D] = None
|
private var scaleDragPoint: Option[Vector2D] = None
|
||||||
|
|
||||||
private var _scale = 1f
|
override protected def title: String = screenNode.label.get
|
||||||
private var scaleX: Float = 1f
|
|
||||||
private var scaleY: Float = 1f
|
|
||||||
|
|
||||||
private def scale: Float = _scale
|
override protected def titleMaxLength: Int =
|
||||||
|
((screenWidth * FontWidth * View.scaleX - 15) / FontWidth).toInt
|
||||||
private def scale_=(value: Float): Any = {
|
|
||||||
_scale = value
|
|
||||||
|
|
||||||
scaleX = (FontWidth * scale).floor / FontWidth
|
|
||||||
scaleY = (FontHeight * scale).floor / FontHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
private def screen: Screen = screenNode.screen
|
|
||||||
|
|
||||||
private def screenWidth: Int = screenNode.screenWidth
|
private def screenWidth: Int = screenNode.screenWidth
|
||||||
|
|
||||||
private def screenHeight: Int = screenNode.screenHeight
|
private def screenHeight: Int = screenNode.screenHeight
|
||||||
|
|
||||||
override def minimumSize: Size2D = Size2D(
|
|
||||||
screenWidth * FontWidth * scaleX + BorderHorizontal,
|
|
||||||
screenHeight * scaleY * FontHeight + BorderVertical,
|
|
||||||
)
|
|
||||||
|
|
||||||
override def receiveScrollEvents: Boolean = true
|
override def receiveScrollEvents: Boolean = true
|
||||||
|
|
||||||
|
override def maximumSize: Size2D = minimumSize
|
||||||
|
|
||||||
|
private object View extends ScreenView(screenNode) {
|
||||||
|
override protected def isFocused: Boolean = ScreenWindow.this.isFocused
|
||||||
|
}
|
||||||
|
|
||||||
|
setInner(
|
||||||
|
View,
|
||||||
|
padding = Padding2D(
|
||||||
|
right = BorderRight,
|
||||||
|
bottom = BorderBottom,
|
||||||
|
left = BorderLeft,
|
||||||
|
),
|
||||||
|
titlePadding = Padding2D(
|
||||||
|
top = 2,
|
||||||
|
right = BorderRight - 4,
|
||||||
|
bottom = 2,
|
||||||
|
left = BorderLeft - 4,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
eventHandlers += {
|
eventHandlers += {
|
||||||
case event: KeyEvent if shouldHandleKeys =>
|
|
||||||
event.state match {
|
|
||||||
case KeyEvent.State.Press | KeyEvent.State.Repeat =>
|
|
||||||
screen.keyDown(event.char, event.code, OcelotDesktop.player)
|
|
||||||
|
|
||||||
// note: in OpenComputers, key_down signal is fired __before__ clipboard signal
|
|
||||||
if (event.code == Settings.get.keymap(Keybind.Insert))
|
|
||||||
screen.clipboard(UiHandler.clipboard, OcelotDesktop.player)
|
|
||||||
|
|
||||||
case KeyEvent.State.Release =>
|
|
||||||
screen.keyUp(event.char, event.code, OcelotDesktop.player)
|
|
||||||
}
|
|
||||||
|
|
||||||
event.consume()
|
|
||||||
|
|
||||||
case event: MouseEvent if shouldHandleKeys =>
|
|
||||||
val pos = convertMousePos(UiHandler.mousePosition)
|
|
||||||
val inside = checkBounds(pos)
|
|
||||||
|
|
||||||
if (inside)
|
|
||||||
lastMousePos = pos
|
|
||||||
|
|
||||||
event.state match {
|
|
||||||
case MouseEvent.State.Press =>
|
|
||||||
if (inside && screen.tier > Tier.One) {
|
|
||||||
screen.mouseDown(pos.x, pos.y, event.button.id, OcelotDesktop.player)
|
|
||||||
sentTouchEvent = true
|
|
||||||
event.consume()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
pinButtonBounds.contains(UiHandler.mousePosition) || closeButtonBounds.contains(UiHandler.mousePosition)
|
|
||||||
) {
|
|
||||||
SoundSource.InterfaceClick.press.play()
|
|
||||||
}
|
|
||||||
|
|
||||||
case MouseEvent.State.Release =>
|
|
||||||
if (event.button == MouseEvent.Button.Middle && inside) {
|
|
||||||
screen.clipboard(UiHandler.clipboard, OcelotDesktop.player)
|
|
||||||
event.consume()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sentTouchEvent) {
|
|
||||||
screen.mouseUp(lastMousePos.x, lastMousePos.y, event.button.id, OcelotDesktop.player)
|
|
||||||
event.consume()
|
|
||||||
sentTouchEvent = false
|
|
||||||
} else if (pinButtonBounds.contains(UiHandler.mousePosition)) {
|
|
||||||
if (isPinned) unpin() else pin()
|
|
||||||
SoundSource.InterfaceClick.release.play()
|
|
||||||
} else if (closeButtonBounds.contains(UiHandler.mousePosition)) {
|
|
||||||
close()
|
|
||||||
SoundSource.InterfaceClick.release.play()
|
|
||||||
}
|
|
||||||
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
|
|
||||||
case event: ScrollEvent if shouldHandleKeys && screen.tier > Tier.One =>
|
|
||||||
screen.mouseScroll(lastMousePos.x, lastMousePos.y, event.offset, OcelotDesktop.player)
|
|
||||||
event.consume()
|
|
||||||
|
|
||||||
case event @ DragEvent(DragEvent.State.Start, MouseEvent.Button.Left, _) =>
|
case event @ DragEvent(DragEvent.State.Start, MouseEvent.Button.Left, _) =>
|
||||||
if (scaleDragRegion.contains(event.start)) {
|
if (scaleDragRegion.contains(event.start)) {
|
||||||
scaleDragPoint = Some(event.start)
|
scaleDragPoint = Some(event.start)
|
||||||
startingWidth = screenWidth * FontWidth * scaleX
|
startingWidth = screenWidth * FontWidth * View.scaleX
|
||||||
}
|
}
|
||||||
|
|
||||||
case DragEvent(DragEvent.State.Drag, MouseEvent.Button.Left, mousePos) =>
|
case DragEvent(DragEvent.State.Drag, MouseEvent.Button.Left, mousePos) =>
|
||||||
@ -125,7 +62,7 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
|
|||||||
val sy = point.y - mousePos.y
|
val sy = point.y - mousePos.y
|
||||||
|
|
||||||
val uiScale = UiHandler.scalingFactor
|
val uiScale = UiHandler.scalingFactor
|
||||||
var newScale = scale
|
var newScale = View.scale.nextValue
|
||||||
|
|
||||||
// TODO: refactor this mess, make it consider both sizes and not have two nearby slightly off "snap points"
|
// TODO: refactor this mess, make it consider both sizes and not have two nearby slightly off "snap points"
|
||||||
|
|
||||||
@ -134,7 +71,7 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
|
|||||||
val maxWidth = screenWidth * FontWidth
|
val maxWidth = screenWidth * FontWidth
|
||||||
var midScale = (newWidth / maxWidth).max(0f)
|
var midScale = (newWidth / maxWidth).max(0f)
|
||||||
|
|
||||||
if (!KeyEvents.isShiftDown && scale <= 1.001)
|
if (!KeyEvents.isShiftDown && View.scale.nextValue <= 1.001)
|
||||||
midScale = midScale.min(1f)
|
midScale = midScale.min(1f)
|
||||||
|
|
||||||
val lowScale = (FontWidth * midScale * uiScale).floor / FontWidth / uiScale
|
val lowScale = (FontWidth * midScale * uiScale).floor / FontWidth / uiScale
|
||||||
@ -146,7 +83,7 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
|
|||||||
val maxHeight = screenHeight * FontHeight
|
val maxHeight = screenHeight * FontHeight
|
||||||
var midScale = (newHeight / maxHeight).max(0f)
|
var midScale = (newHeight / maxHeight).max(0f)
|
||||||
|
|
||||||
if (!KeyEvents.isShiftDown && scale <= 1.001)
|
if (!KeyEvents.isShiftDown && View.scale.nextValue <= 1.001)
|
||||||
midScale = midScale.min(1f)
|
midScale = midScale.min(1f)
|
||||||
|
|
||||||
val lowScale = (FontHeight * midScale * uiScale).floor / FontHeight / uiScale
|
val lowScale = (FontHeight * midScale * uiScale).floor / FontHeight / uiScale
|
||||||
@ -155,28 +92,30 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
|
|||||||
newScale = if (midScale - lowScale > highScale - midScale) highScale else lowScale
|
newScale = if (midScale - lowScale > highScale - midScale) highScale else lowScale
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newScale != scale)
|
|
||||||
scale = newScale
|
|
||||||
|
|
||||||
// enforce minimal screen size
|
// enforce minimal screen size
|
||||||
if (scale <= 0.249f) {
|
if (newScale <= 0.249f) {
|
||||||
scale = 0.25f
|
newScale = 0.25f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
View.scale.nextValue = newScale
|
||||||
}
|
}
|
||||||
|
|
||||||
case DragEvent(DragEvent.State.Stop, MouseEvent.Button.Left, _) =>
|
case DragEvent(DragEvent.State.Stop, MouseEvent.Button.Left, _) =>
|
||||||
scaleDragPoint = None
|
scaleDragPoint = None
|
||||||
}
|
}
|
||||||
|
|
||||||
private def shouldHandleKeys: Boolean = isFocused && !root.get.modalDialogPool.isVisible
|
|
||||||
|
|
||||||
override def save(nbt: NBTTagCompound): Unit = {
|
override def save(nbt: NBTTagCompound): Unit = {
|
||||||
nbt.setFloat("scale", scale)
|
View.save(nbt)
|
||||||
super.save(nbt)
|
super.save(nbt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def load(nbt: NBTTagCompound): Unit = {
|
||||||
|
super.load(nbt)
|
||||||
|
View.load(nbt)
|
||||||
|
}
|
||||||
|
|
||||||
override def fitToCenter(): Unit = {
|
override def fitToCenter(): Unit = {
|
||||||
scale = math.min(
|
View.scale.nextValue = math.min(
|
||||||
((UiHandler.root.width * 0.9f) / (screenWidth * FontWidth + BorderHorizontal)).min(1f).max(0f),
|
((UiHandler.root.width * 0.9f) / (screenWidth * FontWidth + BorderHorizontal)).min(1f).max(0f),
|
||||||
((UiHandler.root.height * 0.9f) / (screenHeight * FontHeight + BorderVertical)).min(1f).max(0f),
|
((UiHandler.root.height * 0.9f) / (screenHeight * FontHeight + BorderVertical)).min(1f).max(0f),
|
||||||
)
|
)
|
||||||
@ -184,29 +123,6 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
|
|||||||
super.fitToCenter()
|
super.fitToCenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def load(nbt: NBTTagCompound): Unit = {
|
|
||||||
scale = nbt.getFloat("scale")
|
|
||||||
|
|
||||||
super.load(nbt)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def checkBounds(p: Vector2D): Boolean = p.x >= 0 && p.y >= 0 && p.x < screenWidth && p.y < screenHeight
|
|
||||||
|
|
||||||
private def convertMousePos(p: Vector2D): Vector2D = {
|
|
||||||
// no synchronization here (see the note in ScreenNode): the method to change this property is indirect.
|
|
||||||
if (screen.getPrecisionMode) {
|
|
||||||
Vector2D(
|
|
||||||
(p.x - BorderLeft - position.x) / FontWidth / scaleX,
|
|
||||||
(p.y - BorderTop - position.y) / FontHeight / scaleY,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Vector2D(
|
|
||||||
math.floor((p.x - BorderLeft - position.x) / FontWidth / scaleX),
|
|
||||||
math.floor((p.y - BorderTop - position.y) / FontHeight / scaleY),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override protected def dragRegions: Iterator[Rect2D] = Iterator(
|
override protected def dragRegions: Iterator[Rect2D] = Iterator(
|
||||||
Rect2D(position.x, position.y, size.width, BorderTop.toFloat),
|
Rect2D(position.x, position.y, size.width, BorderTop.toFloat),
|
||||||
Rect2D(position.x, position.y, BorderLeft.toFloat, size.height),
|
Rect2D(position.x, position.y, BorderLeft.toFloat, size.height),
|
||||||
@ -230,82 +146,9 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
|
|||||||
root.get.statusBar.addMouseEntry("icons/DragLMB", "Scale screen")
|
root.get.statusBar.addMouseEntry("icons/DragLMB", "Scale screen")
|
||||||
root.get.statusBar.addKeyMouseEntry("icons/DragLMB", "SHIFT", "Scale screen (magnify)")
|
root.get.statusBar.addKeyMouseEntry("icons/DragLMB", "SHIFT", "Scale screen (magnify)")
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentMousePos = convertMousePos(UiHandler.mousePosition)
|
|
||||||
if (!checkBounds(currentMousePos) || currentMousePos == lastMousePos) return
|
|
||||||
|
|
||||||
lastMousePos = currentMousePos
|
|
||||||
|
|
||||||
if (isFocused && screen.tier > Tier.One) {
|
|
||||||
for (button <- MouseEvents.pressedButtons) {
|
|
||||||
screen.mouseDrag(lastMousePos.x, lastMousePos.y, button.id, OcelotDesktop.player)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def pinButtonBounds: Rect2D = Rect2D(
|
override protected def borderRenderer: BorderRenderer = DrawUtils.screenBorder
|
||||||
position.x + screenWidth * FontWidth * scaleX - 13,
|
|
||||||
position.y + 3,
|
|
||||||
14,
|
|
||||||
14,
|
|
||||||
)
|
|
||||||
|
|
||||||
private def closeButtonBounds: Rect2D = Rect2D(
|
|
||||||
position.x + screenWidth * FontWidth * scaleX + 2,
|
|
||||||
position.y + 3,
|
|
||||||
15,
|
|
||||||
14,
|
|
||||||
)
|
|
||||||
|
|
||||||
override def draw(g: Graphics): Unit = {
|
|
||||||
beginDraw(g)
|
|
||||||
|
|
||||||
val startX = position.x + BorderLeft
|
|
||||||
val startY = position.y + BorderTop
|
|
||||||
val windowWidth = screenWidth * FontWidth * scaleX
|
|
||||||
val windowHeight = screenHeight * FontHeight * scaleY
|
|
||||||
|
|
||||||
DrawUtils.shadow(g, startX - 22, startY - 22, windowWidth + 44, windowHeight + 52, 0.5f)
|
|
||||||
DrawUtils.screenBorder(g, startX, startY, windowWidth, windowHeight)
|
|
||||||
|
|
||||||
// no synchronization here (see the note in ScreenNode): the methods to turn the screen on/off are indirect.
|
|
||||||
if (screen.getPowerState) {
|
|
||||||
screenNode.drawScreenData(
|
|
||||||
g,
|
|
||||||
startX,
|
|
||||||
startY,
|
|
||||||
scaleX,
|
|
||||||
scaleY,
|
|
||||||
if (Settings.get.screenWindowMipmap) {
|
|
||||||
MinFilteringMode.LinearMipmapLinear
|
|
||||||
} else {
|
|
||||||
MinFilteringMode.Nearest
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
g.rect(startX, startY, windowWidth, windowHeight, ColorScheme("ScreenOff"))
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setSmallFont()
|
|
||||||
g.background = RGBAColor(0, 0, 0, 0)
|
|
||||||
g.foreground = RGBAColor(110, 110, 110)
|
|
||||||
|
|
||||||
val freeSpace = ((windowWidth - 15) / 8).toInt
|
|
||||||
val label = screenNode.label.get
|
|
||||||
val text = if (label.length <= freeSpace)
|
|
||||||
label
|
|
||||||
else
|
|
||||||
StringUtils.substring(label, 0, (freeSpace - 1).max(0).min(label.length)) + "…"
|
|
||||||
|
|
||||||
g.text(startX - 4, startY - 14, text)
|
|
||||||
g.setNormalFont()
|
|
||||||
|
|
||||||
g.sprite(if (isPinned) "icons/Unpin" else "icons/Pin", pinButtonBounds)
|
|
||||||
g.sprite("icons/Close", closeButtonBounds)
|
|
||||||
|
|
||||||
endDraw(g)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object ScreenWindow {
|
object ScreenWindow {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user