Skip to content

Commit

Permalink
Simplified DispatcherVetoer, explained dispatcher
Browse files Browse the repository at this point in the history
  • Loading branch information
yairm210 committed Jun 18, 2024
1 parent 3b74e33 commit 109955c
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 44 deletions.
36 changes: 9 additions & 27 deletions core/src/com/unciv/ui/components/input/KeyShortcutDispatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,38 +41,14 @@ open class KeyShortcutDispatcher {
add(KeyCharAndCode(keyCode), action)
}

fun remove(shortcut: KeyShortcut?) {
shortcuts.removeAll { it.shortcut == shortcut }
}

fun remove(binding: KeyboardBinding) {
shortcuts.removeAll { it.shortcut.binding == binding }
}

fun remove(key: KeyCharAndCode?) {
shortcuts.removeAll { it.shortcut.key == key }
}

fun remove(char: Char?) {
shortcuts.removeAll { it.shortcut.key.char == char }
}

fun remove(keyCode: Int?) {
shortcuts.removeAll { it.shortcut.key.code == keyCode }
}

operator fun contains(binding: KeyboardBinding) =
shortcuts.any { it.shortcut.binding == binding }
operator fun contains(key: KeyCharAndCode) =
shortcuts.any { it.shortcut.key == key || it.shortcut.binding.defaultKey == key }
operator fun contains(char: Char) =
shortcuts.any { it.shortcut.key.char == char }
operator fun contains(keyCode: Int) =
shortcuts.any { it.shortcut.key.code == keyCode }

open fun isActive(): Boolean = true


/** Given that several different shortcuts could be mapped to the same key,
* this class decides what will actually happen when the key is pressed */
class Resolver(val key: KeyCharAndCode) {
private var priority = Int.MIN_VALUE
val triggeredActions: MutableList<ActivationAction> = mutableListOf()
Expand All @@ -81,12 +57,18 @@ open class KeyShortcutDispatcher {
if (!dispatcher.isActive()) return

for ((shortcut, action) in dispatcher.shortcuts) {
// shortcutKey in shortcut is used for non-user-configurable key shortcuts
var (binding, shortcutKey, shortcutPriority) = shortcut

// Bindings are used for user-configurable shortcuts
if (binding != KeyboardBinding.None) {
shortcutKey = KeyboardBindings[binding]
if (shortcutKey == binding.defaultKey) shortcutPriority--
}
if (shortcutKey != key || shortcutPriority < priority) continue

if (shortcutKey != key) continue
// We always want to take the highest priority action, but if there are several of the same priority we do them all
if (shortcutPriority < priority) continue
if (shortcutPriority > priority) {
priority = shortcutPriority
triggeredActions.clear()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,31 @@ import com.unciv.ui.components.tilegroups.TileGroupMap
import com.unciv.ui.screens.basescreen.BaseScreen

/**
* A lambda testing for a given *associatedActor* whether the shortcuts in *keyDispatcher*
* A lambda testing for a given *associatedActor* whether the shortcuts
* should be processed and whether the deep scan for child actors should continue.
* *associatedActor* == `null` means *keyDispatcher* is *BaseScreen.globalShortcuts*
*/
typealias DispatcherVetoer = (associatedActor: Actor?, keyDispatcher: KeyShortcutDispatcher?) -> KeyShortcutDispatcherVeto.DispatcherVetoResult
typealias DispatcherVetoer = (associatedActor: Actor?) -> KeyShortcutDispatcherVeto.DispatcherVetoResult

object KeyShortcutDispatcherVeto {
enum class DispatcherVetoResult { Accept, Skip, SkipWithChildren }

internal val defaultDispatcherVetoer: DispatcherVetoer = { _, _ -> DispatcherVetoResult.Accept }
internal val defaultDispatcherVetoer: DispatcherVetoer = { _ -> DispatcherVetoResult.Accept }

/** When a Popup ([activePopup]) is active, this creates a [DispatcherVetoer] that disables all
* shortcuts on actors outside the popup and also the global shortcuts on the screen itself.
*/
fun createPopupBasedDispatcherVetoer(activePopup: Actor): DispatcherVetoer? {
return { associatedActor: Actor?, _: KeyShortcutDispatcher? ->
when {
associatedActor == null -> DispatcherVetoResult.Skip
associatedActor.isDescendantOf(activePopup) -> DispatcherVetoResult.Accept
else -> DispatcherVetoResult.SkipWithChildren
}
fun createPopupBasedDispatcherVetoer(activePopup: Actor): DispatcherVetoer = { associatedActor: Actor? ->
when {
associatedActor == null -> DispatcherVetoResult.Skip
associatedActor.isDescendantOf(activePopup) -> DispatcherVetoResult.Accept
else -> DispatcherVetoResult.SkipWithChildren
}
}

/** Return this from [BaseScreen.getShortcutDispatcherVetoer] for Screens containing a [TileGroupMap] */
fun createTileGroupMapDispatcherVetoer(): DispatcherVetoer {
return { associatedActor: Actor?, _: KeyShortcutDispatcher? ->
return { associatedActor: Actor? ->
if (associatedActor is TileGroupMap<*>) DispatcherVetoResult.SkipWithChildren
else DispatcherVetoResult.Accept
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/com/unciv/ui/components/input/KeyShortcutListener.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ import com.unciv.ui.components.input.KeyShortcutDispatcherVeto.DispatcherVetoRes
val shortcutResolver = KeyShortcutDispatcher.Resolver(key)
val pendingActors = ArrayDeque(actors.toList())

if (additionalShortcuts != null && dispatcherVetoer(null, additionalShortcuts) == DispatcherVetoResult.Accept)
if (additionalShortcuts != null && dispatcherVetoer(null) == DispatcherVetoResult.Accept)
shortcutResolver.updateFor(additionalShortcuts)

while (true) {
val actor = pendingActors.removeFirstOrNull()
?: break
val shortcuts = ActorAttachments.getOrNull(actor)?.keyShortcuts
val vetoResult = dispatcherVetoer(actor, shortcuts)
val vetoResult = dispatcherVetoer(actor)

if (shortcuts != null && vetoResult == DispatcherVetoResult.Accept)
shortcutResolver.updateFor(shortcuts)
Expand Down
5 changes: 1 addition & 4 deletions docs/Modders/uniques.md
Original file line number Diff line number Diff line change
Expand Up @@ -1794,10 +1794,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Irremovable"
Applicable to: Improvement

??? example "Will be replaced by automated workers"
Applicable to: Improvement

??? example "Will not be replaced by automated workers"
??? example "Will not be replaced by automated units"
Applicable to: Improvement

## Resource uniques
Expand Down

0 comments on commit 109955c

Please sign in to comment.