Skip to content

Commit

Permalink
Move shortcut handling to KeyManager & improve pasting logic with mou…
Browse files Browse the repository at this point in the history
…se pos
  • Loading branch information
serivesmejia committed Dec 2, 2024
1 parent 50972f8 commit 7d8a2f6
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,9 @@ object GlfwKeys : PlatformKeys {
if(isMac) glfwGetKeyScancode(GLFW_KEY_RIGHT_SUPER) else glfwGetKeyScancode(GLFW_KEY_RIGHT_CONTROL)
}

override val Z = glfwGetKeyScancode(GLFW_KEY_Z) //44
override val Y = glfwGetKeyScancode(GLFW_KEY_Y) //52
override val X = glfwGetKeyScancode(GLFW_KEY_X) //45
override val C = glfwGetKeyScancode(GLFW_KEY_C) //46
override val V = glfwGetKeyScancode(GLFW_KEY_V) //47
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import imgui.extension.imnodes.ImNodes
import imgui.extension.imnodes.flag.ImNodesMiniMapLocation
import imgui.extension.texteditor.TextEditorLanguageDefinition
import imgui.flag.ImGuiCol
import imgui.flag.ImGuiKey
import imgui.flag.ImGuiMouseButton
import imgui.flag.ImGuiWindowFlags
import imgui.type.ImInt
Expand Down Expand Up @@ -55,11 +54,11 @@ import io.github.deltacv.papervision.node.FlagsNode
import io.github.deltacv.papervision.node.InvisibleNode
import io.github.deltacv.papervision.node.Link
import io.github.deltacv.papervision.node.Node
import io.github.deltacv.papervision.node.instantiateNode
import io.github.deltacv.papervision.node.vision.InputMatNode
import io.github.deltacv.papervision.node.vision.OutputMatNode
import io.github.deltacv.papervision.serialization.PaperVisionSerializer
import io.github.deltacv.papervision.util.ElapsedTime
import io.github.deltacv.papervision.util.clip
import io.github.deltacv.papervision.util.event.PaperVisionEventHandler
import io.github.deltacv.papervision.util.flags
import io.github.deltacv.papervision.util.loggerForThis
Expand Down Expand Up @@ -128,6 +127,7 @@ class NodeEditor(val paperVision: PaperVision, private val keyManager: KeyManage
private val scrollTimer = ElapsedTime()

private var pasteCount = 0
private var pasteInitialMousePos = ImVec2()
private var cutting = false
var clipboard: String? = null

Expand Down Expand Up @@ -225,6 +225,25 @@ class NodeEditor(val paperVision: PaperVision, private val keyManager: KeyManage

logger.info("Restored editor panning from flags to $editorPanning")
}

registerShortcuts()
}

private fun registerShortcuts() {
keyManager.addShortcut(keyManager.keys.NativeLeftSuper, keyManager.keys.Z, ::undo)
keyManager.addShortcut(keyManager.keys.NativeRightSuper, keyManager.keys.Z, ::undo)

keyManager.addShortcut(keyManager.keys.NativeLeftSuper, keyManager.keys.Y, ::redo)
keyManager.addShortcut(keyManager.keys.NativeRightSuper, keyManager.keys.Y, ::redo)

keyManager.addShortcut(keyManager.keys.NativeLeftSuper, keyManager.keys.X, ::cut)
keyManager.addShortcut(keyManager.keys.NativeRightSuper, keyManager.keys.X, ::cut)

keyManager.addShortcut(keyManager.keys.NativeLeftSuper, keyManager.keys.C, ::copy)
keyManager.addShortcut(keyManager.keys.NativeRightSuper, keyManager.keys.C, ::copy)

keyManager.addShortcut(keyManager.keys.NativeLeftSuper, keyManager.keys.V, ::paste)
keyManager.addShortcut(keyManager.keys.NativeRightSuper, keyManager.keys.V, ::paste)
}

override fun drawContents() {
Expand Down Expand Up @@ -285,8 +304,9 @@ class NodeEditor(val paperVision: PaperVision, private val keyManager: KeyManage
ImNodes.clearNodeSelection()
} else if (
ImGui.isMouseDown(ImGuiMouseButton.Middle) ||
(ImGui.isMouseDown(ImGuiMouseButton.Right)
&& rightClickMenuPopupTimer.millis >= 100 && (!rightClickedWhileHoveringNode || keyManager.pressing(Keys.LeftControl)))
(ImGui.isMouseDown(ImGuiMouseButton.Right) && rightClickMenuPopupTimer.millis >= 100 &&
(!rightClickedWhileHoveringNode || keyManager.pressing(Keys.LeftControl))
)
) {
editorPanning.x += (ImGui.getMousePosX() - prevMouseX)
editorPanning.y += (ImGui.getMousePosY() - prevMouseY)
Expand Down Expand Up @@ -358,34 +378,6 @@ class NodeEditor(val paperVision: PaperVision, private val keyManager: KeyManage
handleDeleteLink()
handleCreateLink()
handleDeleteSelection()

if (keyManager.pressing(keyManager.keys.NativeLeftSuper) || keyManager.pressing(keyManager.keys.NativeRightSuper)) {
val pressingShift = keyManager.pressing(keyManager.keys.LeftShift)

val pressedZ = ImGui.isKeyPressed(ImGuiKey.Z)
val pressedY = ImGui.isKeyPressed(ImGuiKey.Y)
val pressedS = ImGui.isKeyPressed(ImGuiKey.S)

val pressedC = ImGui.isKeyPressed(ImGuiKey.C)
val pressedV = ImGui.isKeyPressed(ImGuiKey.V)
val pressedX = ImGui.isKeyPressed(ImGuiKey.X)

if (pressingShift && pressedZ) {
redo() // Ctrl + Shift + Z
} else if (pressedZ) {
undo() // Ctrl + Z
} else if (pressedY) {
redo() // Ctrl + Y
} else if (pressedS) {
logger.info(PaperVisionSerializer.serialize(nodes.inmutable, links.inmutable))
} else if(pressedC) {
copy()
} else if(pressedV) {
paste()
} else if(pressedX) {
cut()
}
}
}

fun undo() {
Expand Down Expand Up @@ -448,6 +440,16 @@ class NodeEditor(val paperVision: PaperVision, private val keyManager: KeyManage

val (nodes, _) = PaperVisionSerializer.deserialize(clipboard!!)

if(pasteCount == 0) {
pasteInitialMousePos = ImGui.getMousePos()
}

// reset on mouse movement
if(pasteInitialMousePos.x != ImGui.getMousePos().x || pasteInitialMousePos.y != ImGui.getMousePos().y) {
pasteCount = 0
pasteInitialMousePos = ImGui.getMousePos()
}

var totalX = 0f
var totalY = 0f
var count = 0
Expand Down Expand Up @@ -769,7 +771,6 @@ class NodeEditor(val paperVision: PaperVision, private val keyManager: KeyManage

ImGui.popStyleColor()
}

}

class SourceCodeExportSelectLanguageWindow(
Expand Down Expand Up @@ -1030,15 +1031,4 @@ class NodeEditor(val paperVision: PaperVision, private val keyManager: KeyManage
ImGui.popFont()
}
}
}

fun instantiateNode(nodeClazz: Class<out Node<*>>) = try {
nodeClazz.getConstructor().newInstance()
} catch (e: NoSuchMethodException) {
throw UnsupportedOperationException(
"Node ${nodeClazz.typeName} does not implement a constructor with no parameters",
e
)
} catch (e: Exception) {
throw RuntimeException("Error while instantiating node ${nodeClazz.typeName}", e)
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ class NodeList(
paperVision.onUpdate {
if (isCompletelyDeleted) {
it.removeThis()
} else if (!paperVision.nodeEditor.isNodeFocused && keyManager.released(Keys.Spacebar)) {
showList()
} else if (!paperVision.nodeEditor.isNodeFocused && keyManager.released(Keys.Spacebar) && !paperVision.isModalWindowOpen) {
showList() // open the list when the spacebar is pressed
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,34 @@
package io.github.deltacv.papervision.io

import io.github.deltacv.papervision.platform.PlatformKeys
import io.github.deltacv.papervision.util.ElapsedTime

data class KeyShortcut(
val modifiers: List<Int>,
val key: Int,
val oneshot: Boolean = false,
val action: () -> Unit
)

private data class ShortcutTriggerData(
val timer: ElapsedTime,
var count: Int
)

class KeyManager(val keys: PlatformKeys) {

companion object {
const val SHORTCUT_INITIAL_TRIGGER_RATE_SECS = 0.5
const val SHORTCUT_TRIGGER_RATE_SECS = 0.06
}

private val pressedKeys = mutableMapOf<Int, Boolean>()
private val pressingKeys = mutableMapOf<Int, Boolean>()
private val releasedKeys = mutableMapOf<Int, Boolean>()

private val shortcuts = mutableListOf<KeyShortcut>()
private val shortcutTriggerData = mutableMapOf<KeyShortcut, ShortcutTriggerData>()

fun update() {
if(pressedKeys.isNotEmpty()) {
for (key in pressedKeys.keys.toTypedArray()) {
Expand All @@ -38,6 +59,32 @@ class KeyManager(val keys: PlatformKeys) {
releasedKeys[key] = false
}
}

for(shortcut in shortcuts) {
if(shortcut.modifiers.all { pressing(it) } && pressing(shortcut.key)) {
val data = shortcutTriggerData.getOrPut(shortcut) {
ShortcutTriggerData(ElapsedTime(), 0)
}

val timer = data.timer.seconds

if(shortcut.oneshot && data.count == 0) {
shortcut.action() // trigger once
data.count++
} else {
if (data.count == 0 ||
(data.count == 1 && timer > SHORTCUT_INITIAL_TRIGGER_RATE_SECS) ||
(data.count > 1 && timer > SHORTCUT_TRIGGER_RATE_SECS)
) {
shortcut.action()
data.timer.reset()
data.count++
}
}
} else {
shortcutTriggerData.remove(shortcut)
}
}
}

fun updateKey(scancode: Int, action: KeyAction) {
Expand Down Expand Up @@ -65,9 +112,25 @@ class KeyManager(val keys: PlatformKeys) {
}
}

fun pressed(scancode: Int) = pressedKeys[scancode] ?: false
fun pressing(scancode: Int) = pressingKeys[scancode] ?: false
fun released(scancode: Int) = releasedKeys[scancode] ?: false
fun addShortcut(modifiers: List<Int>, key: Int, oneshot: Boolean, action: () -> Unit) {
shortcuts.add(KeyShortcut(modifiers, key, oneshot, action))
}

fun addShortcut(modifier: Int, key: Int, oneshot: Boolean, action: () -> Unit) {
addShortcut(listOf(modifier), key, oneshot, action)
}

// we have to manually do overloads...
fun addShortcut(modifiers: List<Int>, key: Int, action: () -> Unit) {
addShortcut(modifiers, key, false, action)
}
fun addShortcut(modifier: Int, key: Int, action: () -> Unit) {
addShortcut(listOf(modifier), key, false, action)
}

fun pressed(scancode: Int) = pressedKeys[scancode] == true
fun pressing(scancode: Int) = pressingKeys[scancode] == true
fun released(scancode: Int) = releasedKeys[scancode] == true

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,15 @@ abstract class Node<S: CodeGenSession>(
forgetSerializedId = true
}

}

fun instantiateNode(nodeClazz: Class<out Node<*>>) = try {
nodeClazz.getConstructor().newInstance()
} catch (e: NoSuchMethodException) {
throw UnsupportedOperationException(
"Node ${nodeClazz.typeName} does not implement a constructor with no parameters",
e
)
} catch (e: Exception) {
throw RuntimeException("Error while instantiating node ${nodeClazz.typeName}", e)
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,10 @@ interface PlatformKeys {

val NativeLeftSuper: Int
val NativeRightSuper: Int

val Z: Int
val Y: Int
val X: Int
val C: Int
val V: Int
}

0 comments on commit 7d8a2f6

Please sign in to comment.