diff --git a/src/main/scala/ocelot/desktop/ui/event/handlers/MouseHandler.scala b/src/main/scala/ocelot/desktop/ui/event/handlers/MouseHandler.scala index 3228ee9..64e0a57 100644 --- a/src/main/scala/ocelot/desktop/ui/event/handlers/MouseHandler.scala +++ b/src/main/scala/ocelot/desktop/ui/event/handlers/MouseHandler.scala @@ -36,7 +36,7 @@ trait MouseHandler extends Widget { case MouseEvent(MouseEvent.State.Pressed, button) => startPositions += (button -> UiHandler.mousePosition) - case MouseEvent(MouseEvent.State.Released, button) => + case event @ MouseEvent(MouseEvent.State.Released, button) => val mousePos = UiHandler.mousePosition val dragStopped = receiveDragEvents && dragButtons.remove(button) @@ -57,19 +57,11 @@ trait MouseHandler extends Widget { } if (clicked) { - val time = System.currentTimeMillis() - val info = ClickInfo(mousePos, time, button, 1) - - for (lastInfo <- lastClickInfo if lastInfo.isConsecutive(info)) { - if (lastInfo.count < 3) { - info.count = lastInfo.count + 1 - } - } - - lastClickInfo = Some(info) - handleEvent(ClickEvent(button, mousePos)) + val info = ClickInfo(lastClickInfo, mousePos, event) + lastClickInfo = Some(info) + info.count match { case 2 => handleEvent(DoubleClickEvent(button, mousePos)) case 3 => handleEvent(TripleClickEvent(button, mousePos)) @@ -119,7 +111,7 @@ object MouseHandler { private def withinTolerance(a: Vector2D, b: Vector2D): Boolean = (b - a).lengthSquared < Tolerance * Tolerance - private case class ClickInfo(position: Vector2D, time: Long, button: MouseEvent.Button.Value, var count: Int) { + case class ClickInfo(position: Vector2D, time: Long, button: MouseEvent.Button.Value, var count: Int) { def isConsecutive(prev: ClickInfo): Boolean = { val quickEnough = time - prev.time < ConsecutiveClickTimeMillis val sameButton = button == prev.button @@ -128,4 +120,18 @@ object MouseHandler { quickEnough && sameButton && closeEnough } } + + object ClickInfo { + def apply(prev: Option[ClickInfo], position: Vector2D, event: MouseEvent): ClickInfo = { + val info = ClickInfo(position, System.currentTimeMillis(), event.button, 1) + + for (prev <- prev if prev.isConsecutive(info)) { + if (prev.count < 3) { + info.count = prev.count + 1 + } + } + + info + } + } } diff --git a/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala b/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala index 8cd4246..eb4332f 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala @@ -7,12 +7,12 @@ import ocelot.desktop.graphics.{Font, Graphics, IconSource} import ocelot.desktop.ui.UiHandler import ocelot.desktop.ui.event.handlers.MouseHandler import ocelot.desktop.ui.event.sources.KeyEvents -import ocelot.desktop.ui.event.{DoubleClickEvent, DragEvent, KeyEvent, MouseEvent, TripleClickEvent} +import ocelot.desktop.ui.event.{DragEvent, KeyEvent, MouseEvent} import ocelot.desktop.ui.widget.TextInput.{Cursor, Selection, Text} import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry} import ocelot.desktop.ui.widget.traits.HoverAnimation -import ocelot.desktop.util.{BaseWatcher, DrawUtils, Register, Watcher} import ocelot.desktop.util.animation.ColorAnimation +import ocelot.desktop.util.{BaseWatcher, DrawUtils, Register, Watcher} import org.lwjgl.input.Keyboard import java.lang.Character.isWhitespace @@ -40,6 +40,8 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w private var cursorOffset = 0f private var selectionOffsets: Option[(Int, Int)] = None + private var lastLeftClickInfo = Option.empty[MouseHandler.ClickInfo] + private val enabledRegister = Register.sampling(enabled) private def selection: Option[Selection] = selectionWatcher.value @@ -49,8 +51,8 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w cursor.onChange = { position => cursorOffset = charsWidth(_text.chars, 0, position) - blinkTimer = 0 - adjustScroll() + blinkTimer = 0 + adjustScroll() } selectionWatcher.onChange = { newValue => @@ -177,14 +179,21 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w root.get.contextMenus.open(menu) + case event @ MouseEvent(MouseEvent.State.Pressed, MouseEvent.Button.Left) if isFocused && mouseInBounds => + // we can't use MouseHandler's double/triple click events because they are emitted when the button is released, + // whereas we want to update the selection when the button is pressed. + val clickInfo = MouseHandler.ClickInfo(lastLeftClickInfo, UiHandler.mousePosition, event) + lastLeftClickInfo = Some(clickInfo) + + clickInfo.count match { + case 1 => selection = None + case 2 => selectWord() + case 3 => selectAll() + } + case MouseEvent(MouseEvent.State.Pressed, _) if isFocused && mouseInBounds => selection = None - - case DoubleClickEvent(MouseEvent.Button.Left, _) if isFocused && mouseInBounds => - selectWord() - - case TripleClickEvent(MouseEvent.Button.Left, _) if isFocused && mouseInBounds => - selectAll() + lastLeftClickInfo = None case DragEvent(DragEvent.State.Start | DragEvent.State.Drag, MouseEvent.Button.Left, mouse) if isFocused => val pos = if (mouse.y < bounds.y) { @@ -303,7 +312,7 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w } pos } - + private def extendSelection(position: Int, cursorPosition: Int = cursor.position): Unit = { selection = Selection(selection.fold(cursorPosition)(_.start), position) }