From 1dee04c24647e2ec95741dba2f38078ee89c843d Mon Sep 17 00:00:00 2001 From: LeshaInc Date: Mon, 7 Jan 2019 23:29:55 +0200 Subject: [PATCH] Implement touch, drag, drop, scroll, and clipboard signals --- .../desktop/{util => ui}/KeyHandler.scala | 13 ++---- .../ocelot/desktop/ui/MouseHandler.scala | 20 ++++++++ .../ocelot/desktop/ui/ScrollHandler.scala | 17 +++++++ .../scala/ocelot/desktop/ui/UiHandler.scala | 23 ++++++++-- .../ocelot/desktop/ui/event/MouseEvent.scala | 2 +- .../ocelot/desktop/ui/event/ScrollEvent.scala | 3 ++ .../ocelot/desktop/ui/widget/RootWidget.scala | 5 ++ .../desktop/ui/widget/ScreenWidget.scala | 46 ++++++++++++++++++- 8 files changed, 114 insertions(+), 15 deletions(-) rename src/main/scala/ocelot/desktop/{util => ui}/KeyHandler.scala (75%) create mode 100644 src/main/scala/ocelot/desktop/ui/MouseHandler.scala create mode 100644 src/main/scala/ocelot/desktop/ui/ScrollHandler.scala create mode 100644 src/main/scala/ocelot/desktop/ui/event/ScrollEvent.scala diff --git a/src/main/scala/ocelot/desktop/util/KeyHandler.scala b/src/main/scala/ocelot/desktop/ui/KeyHandler.scala similarity index 75% rename from src/main/scala/ocelot/desktop/util/KeyHandler.scala rename to src/main/scala/ocelot/desktop/ui/KeyHandler.scala index 55a9840..c7e7a90 100644 --- a/src/main/scala/ocelot/desktop/util/KeyHandler.scala +++ b/src/main/scala/ocelot/desktop/ui/KeyHandler.scala @@ -1,8 +1,8 @@ -package ocelot.desktop.util +package ocelot.desktop.ui import ocelot.desktop.ui.event.KeyEvent +import ocelot.desktop.util.KeyMapping import org.apache.logging.log4j.scala.Logging -import org.lwjgl.glfw.GLFW import scala.collection.mutable 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 = { - val state = action match { - case GLFW.GLFW_PRESS => KeyEvent.State.Press - case GLFW.GLFW_REPEAT => KeyEvent.State.Repeat - case GLFW.GLFW_RELEASE => KeyEvent.State.Release - } - + val state = KeyEvent.State(action) val code = KeyMapping.map(key) val char = charMap.getOrElse(code, '\0') @@ -33,4 +28,4 @@ object KeyHandler extends Logging { charMap.put(events.last.code, char) events(events.length - 1) = KeyEvent(events.last.state, events.last.code, char) } -} \ No newline at end of file +} diff --git a/src/main/scala/ocelot/desktop/ui/MouseHandler.scala b/src/main/scala/ocelot/desktop/ui/MouseHandler.scala new file mode 100644 index 0000000..b4b4ac2 --- /dev/null +++ b/src/main/scala/ocelot/desktop/ui/MouseHandler.scala @@ -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) + } +} diff --git a/src/main/scala/ocelot/desktop/ui/ScrollHandler.scala b/src/main/scala/ocelot/desktop/ui/ScrollHandler.scala new file mode 100644 index 0000000..9f3ca30 --- /dev/null +++ b/src/main/scala/ocelot/desktop/ui/ScrollHandler.scala @@ -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]) + } +} diff --git a/src/main/scala/ocelot/desktop/ui/UiHandler.scala b/src/main/scala/ocelot/desktop/ui/UiHandler.scala index 14b429f..c6169db 100644 --- a/src/main/scala/ocelot/desktop/ui/UiHandler.scala +++ b/src/main/scala/ocelot/desktop/ui/UiHandler.scala @@ -1,9 +1,9 @@ package ocelot.desktop.ui -import ocelot.desktop.geometry.Size2D +import ocelot.desktop.geometry.{Size2D, Vector2D} import ocelot.desktop.graphics.Graphics 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.lwjgl.glfw.{GLFW, GLFWErrorCallback} import org.lwjgl.opengl.{GL, GL11} @@ -12,6 +12,8 @@ import org.lwjgl.system.MemoryUtil.NULL class UiHandler(val root: RootWidget) extends Logging { val windowSize: Size2D = Size2D(0, 0) + root.uiHandler = this + private var graphics: Graphics = _ private var window: Long = _ private var fullRedraw = true @@ -20,6 +22,16 @@ class UiHandler(val root: RootWidget) extends Logging { 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 = { GLFWErrorCallback.createPrint(System.err).set @@ -40,6 +52,8 @@ class UiHandler(val root: RootWidget) extends Logging { GLFW.glfwSetKeyCallback(window, KeyHandler.handleKey) GLFW.glfwSetCharCallback(window, KeyHandler.handleChar) + GLFW.glfwSetMouseButtonCallback(window, MouseHandler.handleMouseButton) + GLFW.glfwSetScrollCallback(window, ScrollHandler.handleScroll) GLFW.glfwSetWindowSizeCallback(window, handleResize) GLFW.glfwSetWindowRefreshCallback(window, handleRefresh) 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]) KeyHandler.reset() + MouseHandler.reset() + ScrollHandler.reset() GLFW.glfwPollEvents() + update() if (fullRedraw) { @@ -79,7 +96,7 @@ class UiHandler(val root: RootWidget) extends Logging { } private def update(): Unit = { - for (event <- KeyHandler.events) + for (event <- KeyHandler.events.iterator ++ MouseHandler.events.iterator ++ ScrollHandler.events.iterator) root.handleEvent(event) root.update() diff --git a/src/main/scala/ocelot/desktop/ui/event/MouseEvent.scala b/src/main/scala/ocelot/desktop/ui/event/MouseEvent.scala index 89d4ab3..a848009 100644 --- a/src/main/scala/ocelot/desktop/ui/event/MouseEvent.scala +++ b/src/main/scala/ocelot/desktop/ui/event/MouseEvent.scala @@ -6,7 +6,7 @@ object MouseEvent { object State extends Enumeration { 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 { diff --git a/src/main/scala/ocelot/desktop/ui/event/ScrollEvent.scala b/src/main/scala/ocelot/desktop/ui/event/ScrollEvent.scala new file mode 100644 index 0000000..5cfa4b2 --- /dev/null +++ b/src/main/scala/ocelot/desktop/ui/event/ScrollEvent.scala @@ -0,0 +1,3 @@ +package ocelot.desktop.ui.event + +case class ScrollEvent(offset: Int) extends Event diff --git a/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala index 9f858e3..7388bd3 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/RootWidget.scala @@ -1,6 +1,11 @@ package ocelot.desktop.ui.widget +import ocelot.desktop.ui.UiHandler + abstract class RootWidget extends Widget { + // TODO: Remove + var uiHandler: UiHandler = _ + def windowTitle: String def update(): Unit = {} diff --git a/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala index 1bf1a28..589f00e 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/ScreenWidget.scala @@ -1,14 +1,16 @@ package ocelot.desktop.ui.widget import ocelot.desktop.color.IntColor -import ocelot.desktop.geometry.Size2D +import ocelot.desktop.geometry.{Size2D, Vector2D} 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 org.apache.logging.log4j.scala.Logging import totoro.ocelot.brain.entity.Screen import totoro.ocelot.brain.user.User +import scala.collection.mutable + class ScreenWidget(screen: Screen) extends RootWidget with Logging { private val fontSize = 16f @@ -24,14 +26,54 @@ class ScreenWidget(screen: Screen) extends RootWidget with Logging { override def maximumSize: Option[Size2D] = minimumSize + private var lastMousePos = Vector2D(0, 0) + private var pressedMouseButtons = new mutable.HashSet[MouseEvent.Button.Value]() + eventHandlers += { case event: KeyEvent => event.state match { case KeyEvent.State.Press | KeyEvent.State.Repeat => 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 => 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"