Implement touch, drag, drop, scroll, and clipboard signals

This commit is contained in:
LeshaInc 2019-01-07 23:29:55 +02:00
parent 1f55223013
commit 1dee04c246
No known key found for this signature in database
GPG Key ID: B4855290FC36DE72
8 changed files with 114 additions and 15 deletions

View File

@ -1,8 +1,8 @@
package ocelot.desktop.util package ocelot.desktop.ui
import ocelot.desktop.ui.event.KeyEvent import ocelot.desktop.ui.event.KeyEvent
import ocelot.desktop.util.KeyMapping
import org.apache.logging.log4j.scala.Logging import org.apache.logging.log4j.scala.Logging
import org.lwjgl.glfw.GLFW
import scala.collection.mutable import scala.collection.mutable
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
@ -16,12 +16,7 @@ object KeyHandler extends Logging {
} }
def handleKey(window: Long, key: Int, scancode: Int, action: Int, mods: Int): Unit = { def handleKey(window: Long, key: Int, scancode: Int, action: Int, mods: Int): Unit = {
val state = action match { val state = KeyEvent.State(action)
case GLFW.GLFW_PRESS => KeyEvent.State.Press
case GLFW.GLFW_REPEAT => KeyEvent.State.Repeat
case GLFW.GLFW_RELEASE => KeyEvent.State.Release
}
val code = KeyMapping.map(key) val code = KeyMapping.map(key)
val char = charMap.getOrElse(code, '\0') val char = charMap.getOrElse(code, '\0')
@ -33,4 +28,4 @@ object KeyHandler extends Logging {
charMap.put(events.last.code, char) charMap.put(events.last.code, char)
events(events.length - 1) = KeyEvent(events.last.state, events.last.code, char) events(events.length - 1) = KeyEvent(events.last.state, events.last.code, char)
} }
} }

View File

@ -0,0 +1,20 @@
package ocelot.desktop.ui
import ocelot.desktop.ui.event.MouseEvent
import scala.collection.mutable.ListBuffer
object MouseHandler {
val events = new ListBuffer[MouseEvent]
def reset(): Unit = {
events.clear()
}
def handleMouseButton(window: Long, _button: Int, action: Int, mods: Int): Unit = {
val state = MouseEvent.State(action)
val button = MouseEvent.Button(_button)
events += MouseEvent(state, button)
}
}

View File

@ -0,0 +1,17 @@
package ocelot.desktop.ui
import ocelot.desktop.ui.event.ScrollEvent
import scala.collection.mutable.ListBuffer
object ScrollHandler {
val events = new ListBuffer[ScrollEvent]
def reset(): Unit = {
events.clear()
}
def handleScroll(window: Long, xoffset: Double, yoffset: Double): Unit = {
events += ScrollEvent(yoffset.asInstanceOf[Int])
}
}

View File

@ -1,9 +1,9 @@
package ocelot.desktop.ui package ocelot.desktop.ui
import ocelot.desktop.geometry.Size2D import ocelot.desktop.geometry.{Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.Graphics
import ocelot.desktop.ui.widget.RootWidget import ocelot.desktop.ui.widget.RootWidget
import ocelot.desktop.util.{FPSCalculator, FontLoader, KeyHandler} import ocelot.desktop.util.{FPSCalculator, FontLoader}
import org.apache.logging.log4j.scala.Logging import org.apache.logging.log4j.scala.Logging
import org.lwjgl.glfw.{GLFW, GLFWErrorCallback} import org.lwjgl.glfw.{GLFW, GLFWErrorCallback}
import org.lwjgl.opengl.{GL, GL11} import org.lwjgl.opengl.{GL, GL11}
@ -12,6 +12,8 @@ import org.lwjgl.system.MemoryUtil.NULL
class UiHandler(val root: RootWidget) extends Logging { class UiHandler(val root: RootWidget) extends Logging {
val windowSize: Size2D = Size2D(0, 0) val windowSize: Size2D = Size2D(0, 0)
root.uiHandler = this
private var graphics: Graphics = _ private var graphics: Graphics = _
private var window: Long = _ private var window: Long = _
private var fullRedraw = true private var fullRedraw = true
@ -20,6 +22,16 @@ class UiHandler(val root: RootWidget) extends Logging {
def fps: Float = fpsCalculator.fps def fps: Float = fpsCalculator.fps
def mousePosition: Vector2D = {
val x = Array(0.0)
val y = Array(0.0)
GLFW.glfwGetCursorPos(window, x, y)
Vector2D(x.head, y.head)
}
def clipboard: String = GLFW.glfwGetClipboardString(window)
def init(): Unit = { def init(): Unit = {
GLFWErrorCallback.createPrint(System.err).set GLFWErrorCallback.createPrint(System.err).set
@ -40,6 +52,8 @@ class UiHandler(val root: RootWidget) extends Logging {
GLFW.glfwSetKeyCallback(window, KeyHandler.handleKey) GLFW.glfwSetKeyCallback(window, KeyHandler.handleKey)
GLFW.glfwSetCharCallback(window, KeyHandler.handleChar) GLFW.glfwSetCharCallback(window, KeyHandler.handleChar)
GLFW.glfwSetMouseButtonCallback(window, MouseHandler.handleMouseButton)
GLFW.glfwSetScrollCallback(window, ScrollHandler.handleScroll)
GLFW.glfwSetWindowSizeCallback(window, handleResize) GLFW.glfwSetWindowSizeCallback(window, handleResize)
GLFW.glfwSetWindowRefreshCallback(window, handleRefresh) GLFW.glfwSetWindowRefreshCallback(window, handleRefresh)
GLFW.glfwSetInputMode(window, GLFW.GLFW_STICKY_KEYS, GLFW.GLFW_FALSE) GLFW.glfwSetInputMode(window, GLFW.GLFW_STICKY_KEYS, GLFW.GLFW_FALSE)
@ -59,7 +73,10 @@ class UiHandler(val root: RootWidget) extends Logging {
graphics.setViewport(windowSize.width.asInstanceOf[Int], windowSize.height.asInstanceOf[Int]) graphics.setViewport(windowSize.width.asInstanceOf[Int], windowSize.height.asInstanceOf[Int])
KeyHandler.reset() KeyHandler.reset()
MouseHandler.reset()
ScrollHandler.reset()
GLFW.glfwPollEvents() GLFW.glfwPollEvents()
update() update()
if (fullRedraw) { if (fullRedraw) {
@ -79,7 +96,7 @@ class UiHandler(val root: RootWidget) extends Logging {
} }
private def update(): Unit = { private def update(): Unit = {
for (event <- KeyHandler.events) for (event <- KeyHandler.events.iterator ++ MouseHandler.events.iterator ++ ScrollHandler.events.iterator)
root.handleEvent(event) root.handleEvent(event)
root.update() root.update()

View File

@ -6,7 +6,7 @@ object MouseEvent {
object State extends Enumeration { object State extends Enumeration {
val Press: State.Value = Value(GLFW.GLFW_PRESS) val Press: State.Value = Value(GLFW.GLFW_PRESS)
val Release: State.Value = Value(GLFW.GLFW_PRESS) val Release: State.Value = Value(GLFW.GLFW_RELEASE)
} }
object Button extends Enumeration { object Button extends Enumeration {

View File

@ -0,0 +1,3 @@
package ocelot.desktop.ui.event
case class ScrollEvent(offset: Int) extends Event

View File

@ -1,6 +1,11 @@
package ocelot.desktop.ui.widget package ocelot.desktop.ui.widget
import ocelot.desktop.ui.UiHandler
abstract class RootWidget extends Widget { abstract class RootWidget extends Widget {
// TODO: Remove
var uiHandler: UiHandler = _
def windowTitle: String def windowTitle: String
def update(): Unit = {} def update(): Unit = {}

View File

@ -1,14 +1,16 @@
package ocelot.desktop.ui.widget package ocelot.desktop.ui.widget
import ocelot.desktop.color.IntColor import ocelot.desktop.color.IntColor
import ocelot.desktop.geometry.Size2D import ocelot.desktop.geometry.{Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics import ocelot.desktop.graphics.Graphics
import ocelot.desktop.ui.event.KeyEvent import ocelot.desktop.ui.event.{KeyEvent, MouseEvent, ScrollEvent}
import ocelot.desktop.util.FontLoader import ocelot.desktop.util.FontLoader
import org.apache.logging.log4j.scala.Logging import org.apache.logging.log4j.scala.Logging
import totoro.ocelot.brain.entity.Screen import totoro.ocelot.brain.entity.Screen
import totoro.ocelot.brain.user.User import totoro.ocelot.brain.user.User
import scala.collection.mutable
class ScreenWidget(screen: Screen) extends RootWidget with Logging { class ScreenWidget(screen: Screen) extends RootWidget with Logging {
private val fontSize = 16f private val fontSize = 16f
@ -24,14 +26,54 @@ class ScreenWidget(screen: Screen) extends RootWidget with Logging {
override def maximumSize: Option[Size2D] = minimumSize override def maximumSize: Option[Size2D] = minimumSize
private var lastMousePos = Vector2D(0, 0)
private var pressedMouseButtons = new mutable.HashSet[MouseEvent.Button.Value]()
eventHandlers += { eventHandlers += {
case event: KeyEvent => case event: KeyEvent =>
event.state match { event.state match {
case KeyEvent.State.Press | KeyEvent.State.Repeat => case KeyEvent.State.Press | KeyEvent.State.Repeat =>
screen.keyDown(event.char, event.code, User("myself")) screen.keyDown(event.char, event.code, User("myself"))
// note: in opencomputers, key_down signal is fired __before__ clipboard signal
if (event.code == 210)
screen.clipboard(uiHandler.clipboard, User("myself"))
case KeyEvent.State.Release => case KeyEvent.State.Release =>
screen.keyUp(event.char, event.code, User("myself")) screen.keyUp(event.char, event.code, User("myself"))
} }
case event: MouseEvent =>
lastMousePos = convertMousePos(uiHandler.mousePosition)
if (event.button == MouseEvent.Button.Middle)
screen.clipboard(uiHandler.clipboard, User("myself"))
else {
event.state match {
case MouseEvent.State.Press =>
pressedMouseButtons += event.button
screen.mouseDown(lastMousePos.x, lastMousePos.y, event.button.id, User("myself"))
case MouseEvent.State.Release =>
pressedMouseButtons -= event.button
screen.mouseUp(lastMousePos.x, lastMousePos.y, event.button.id, User("myself"))
}
}
case event: ScrollEvent =>
screen.mouseScroll(lastMousePos.x, lastMousePos.y, event.offset, User("myself"))
}
def convertMousePos(p: Vector2D): Vector2D = Vector2D(p.x / fontSize * 2f, p.y / fontSize)
override def update(): Unit = {
val currentMousePos = convertMousePos(uiHandler.mousePosition)
if (currentMousePos == lastMousePos) return
lastMousePos = currentMousePos
for (button <- pressedMouseButtons) {
screen.mouseDrag(lastMousePos.x, lastMousePos.y, button.id, User("myself"))
}
} }
override def windowTitle: String = f"Ocelot Desktop" override def windowTitle: String = f"Ocelot Desktop"