From beaa3df4082cc3359bdeefd02ab37e7d29024438 Mon Sep 17 00:00:00 2001 From: Kirill Grouchnikov Date: Mon, 30 Oct 2023 13:49:26 -0400 Subject: [PATCH] Initial skeleton of the key tip manager And handling of left/right arrows to change selected task For #56 --- .../aurora/common/AuroraPopupManager.kt | 4 ++ .../component/ribbon/impl/KeyTipTracker.kt | 10 ++++ .../aurora/window/AuroraRibbonWindow.kt | 60 ++++++++++++++++--- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/common/src/desktopMain/kotlin/org/pushingpixels/aurora/common/AuroraPopupManager.kt b/common/src/desktopMain/kotlin/org/pushingpixels/aurora/common/AuroraPopupManager.kt index 765fa47f..548d4a35 100644 --- a/common/src/desktopMain/kotlin/org/pushingpixels/aurora/common/AuroraPopupManager.kt +++ b/common/src/desktopMain/kotlin/org/pushingpixels/aurora/common/AuroraPopupManager.kt @@ -262,6 +262,10 @@ object AuroraPopupManager { return match != null } + fun isShowingPopups(): Boolean { + return shownPath.isNotEmpty() + } + fun dump() { println("Popups") for (link in shownPath) { diff --git a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt index da335016..4705bc69 100644 --- a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt +++ b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt @@ -106,6 +106,16 @@ object KeyTipTracker { } internal fun getKeyTips(): List = keyTips + + fun isShowingKeyTips(): Boolean = true + + fun showPreviousChain() {} + + fun hideAllKeyTips() {} + + fun showRootKeyTipChain() {} + + fun handleKeyPress(char: Char) {} } @Immutable diff --git a/window/src/desktopMain/kotlin/org/pushingpixels/aurora/window/AuroraRibbonWindow.kt b/window/src/desktopMain/kotlin/org/pushingpixels/aurora/window/AuroraRibbonWindow.kt index 2c897044..203a24dd 100644 --- a/window/src/desktopMain/kotlin/org/pushingpixels/aurora/window/AuroraRibbonWindow.kt +++ b/window/src/desktopMain/kotlin/org/pushingpixels/aurora/window/AuroraRibbonWindow.kt @@ -65,10 +65,7 @@ import org.pushingpixels.aurora.theming.utils.getColorSchemeFilter import org.pushingpixels.aurora.window.WindowSizingConstants.DecoratedBorderThickness import org.pushingpixels.aurora.window.ribbon.* import java.awt.* -import java.awt.event.AWTEventListener -import java.awt.event.KeyEvent -import java.awt.event.MouseEvent -import java.awt.event.WindowEvent +import java.awt.event.* import javax.swing.JFrame import javax.swing.SwingUtilities import kotlin.math.max @@ -767,13 +764,60 @@ fun AuroraWindowScope.AuroraRibbonWindowContent( ) } + val prevAltModif = remember(this, window) { mutableStateOf(false) } val awtEventListener = remember(this, window) { AWTEventListener { event -> val src = event.source - if ((event is KeyEvent) && (event.id == KeyEvent.KEY_RELEASED) - && (event.keyCode == KeyEvent.VK_ESCAPE) - ) { - AuroraPopupManager.hideLastPopup() + if ((event is KeyEvent) && (event.id == KeyEvent.KEY_RELEASED)) { + val wasAltModif: Boolean = prevAltModif.value + prevAltModif.value = (event.modifiersEx == InputEvent.ALT_DOWN_MASK) + if (wasAltModif && event.keyCode == KeyEvent.VK_ALT) { + return@AWTEventListener + } + + val keyChar: Char = event.keyChar + if (Character.isLetter(keyChar) || Character.isDigit(keyChar)) { + KeyTipTracker.handleKeyPress(keyChar) + } + + if ((event.keyCode == KeyEvent.VK_ALT) || (event.getKeyCode() == KeyEvent.VK_F10)) { + if (event.modifiersEx != 0) { + return@AWTEventListener + } + val hadPopups: Boolean = AuroraPopupManager.isShowingPopups() + AuroraPopupManager.hidePopups(null) + if (hadPopups || KeyTipTracker.isShowingKeyTips()) { + KeyTipTracker.hideAllKeyTips() + } else { + KeyTipTracker.showRootKeyTipChain() + } + } + if (event.keyCode == KeyEvent.VK_ESCAPE) { + // Hide last shown popup + AuroraPopupManager.hideLastPopup() + // Dismiss currently shown key tip chain + if (KeyTipTracker.isShowingKeyTips()) { + KeyTipTracker.showPreviousChain() + } + } + if (KeyTipTracker.isShowingKeyTips()) { + // Traversal of ribbon tasks while keytips are showing + when (event.keyCode) { + KeyEvent.VK_LEFT -> { + val selectedIndex = ribbon.tasks.indexOfFirst { it == ribbon.getSelectedTask() } + if (selectedIndex > 0) { + ribbon.tasks[selectedIndex - 1].onClick.invoke() + } + } + + KeyEvent.VK_RIGHT -> { + val selectedIndex = ribbon.tasks.indexOfFirst { it == ribbon.getSelectedTask() } + if ((selectedIndex >= 0) && (selectedIndex < (ribbon.tasks.size - 1))) { + ribbon.tasks[selectedIndex + 1].onClick.invoke() + } + } + } + } } if ((event is MouseEvent) && (event.id == MouseEvent.MOUSE_PRESSED) && (src is Component)) { // This can be in our custom popup menu or in the top-level window