diff --git a/app/src/main/java/emu/skyline/input/onscreen/ConfigurableButton.kt b/app/src/main/java/emu/skyline/input/onscreen/ConfigurableButton.kt index 3f4fd0eb..c544ec69 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/ConfigurableButton.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/ConfigurableButton.kt @@ -14,6 +14,12 @@ interface ConfigurableButton { val buttonId : ButtonId val config : OnScreenConfiguration + /** + * Returns whether this button supports toggle mode + * Usually true for buttons and false for sticks + */ + fun supportsToggleMode() : Boolean = true + /** * Starts a button move session * @param x The x coordinate of the initial touch diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt index a7f28e23..95893966 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt @@ -107,6 +107,7 @@ abstract class OnScreenButton( var partnerPointerId = -1 var isPressed = false + var isToggled = false var hapticFeedback = false @@ -167,12 +168,26 @@ abstract class OnScreenButton( abstract fun isTouched(x : Float, y : Float) : Boolean - open fun onFingerDown(x : Float, y : Float) { - isPressed = true + /** + * @return Whether button events should be sent to guest + */ + open fun onFingerDown(x : Float, y : Float) : Boolean { + if (!config.toggleMode || !isToggled) + isPressed = true + + isToggled = !isToggled + + return !config.toggleMode || isToggled } - open fun onFingerUp(x : Float, y : Float) { - isPressed = false + /** + * @return Whether button events should be sent to guest + */ + open fun onFingerUp(x : Float, y : Float) : Boolean { + if (!config.toggleMode || !isToggled) + isPressed = false + + return !isPressed } fun loadConfigValues() { @@ -264,6 +279,7 @@ abstract class OnScreenButton( override fun resetConfig() { config.enabled = defaultEnabled + config.toggleMode = OnScreenConfiguration.DefaultToggleMode config.alpha = OnScreenConfiguration.DefaultAlpha config.textColor = OnScreenConfiguration.DefaultTextColor config.backgroundColor = OnScreenConfiguration.DefaultBackgroundColor diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt index 66381456..a4065855 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt @@ -16,6 +16,8 @@ interface OnScreenConfiguration { const val GroupEnabled = 1 const val GroupIndeterminate = 2 + const val DefaultToggleMode = false + const val MinAlpha = 0 const val MaxAlpha = 255 const val DefaultAlpha = 128 @@ -35,6 +37,13 @@ interface OnScreenConfiguration { */ val groupEnabled get() = if (enabled) GroupEnabled else GroupDisabled + var toggleMode : Boolean + + /** + * The toggle mode of group of buttons, returns an integer that can be used to set the state of a MaterialCheckBox + */ + val groupToggleMode get() = if (toggleMode) GroupEnabled else GroupDisabled + var alpha : Int var textColor : Int var backgroundColor : Int @@ -48,6 +57,7 @@ class OnScreenConfigurationImpl(private val context : Context, private val butto private inline fun config(default : T, prefix : String = "${buttonId.name}_") = sharedPreferences(context, default, prefix, "controller_config") override var enabled by config(defaultEnabled) + override var toggleMode by config(OnScreenConfiguration.DefaultToggleMode) override var alpha by config(OnScreenConfiguration.DefaultAlpha) override var textColor by config(OnScreenConfiguration.DefaultTextColor) diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt index dd57de23..3d398b95 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt @@ -122,13 +122,13 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs MotionEvent.ACTION_POINTER_UP -> { if (pointerId == button.touchPointerId) { button.touchPointerId = -1 - button.onFingerUp(x, y) - onButtonStateChangedListener?.invoke(button.buttonId, ButtonState.Released) + if (button.onFingerUp(x, y)) + onButtonStateChangedListener?.invoke(button.buttonId, ButtonState.Released) handled = true } else if (pointerId == button.partnerPointerId) { button.partnerPointerId = -1 - button.onFingerUp(x, y) - onButtonStateChangedListener?.invoke(button.buttonId, ButtonState.Released) + if (button.onFingerUp(x, y)) + onButtonStateChangedListener?.invoke(button.buttonId, ButtonState.Released) handled = true } } @@ -137,10 +137,10 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs MotionEvent.ACTION_POINTER_DOWN -> { if (button.config.enabled && button.isTouched(x, y)) { button.touchPointerId = pointerId - button.onFingerDown(x, y) + if (button.onFingerDown(x, y)) + onButtonStateChangedListener?.invoke(button.buttonId, ButtonState.Pressed) if (hapticFeedback) vibrator.vibrate(effectClick) performClick() - onButtonStateChangedListener?.invoke(button.buttonId, ButtonState.Pressed) handled = true } } @@ -153,9 +153,9 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs for (otherButton in buttonPair) { if (otherButton != button && otherButton.config.enabled && otherButton.isTouched(event.getX(fingerId), event.getY(fingerId))) { otherButton.partnerPointerId = fingerId - otherButton.onFingerDown(x, y) + if (otherButton.onFingerDown(x, y)) + onButtonStateChangedListener?.invoke(otherButton.buttonId, ButtonState.Pressed) performClick() - onButtonStateChangedListener?.invoke(otherButton.buttonId, ButtonState.Pressed) handled = true } } @@ -318,6 +318,11 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs invalidate() } + fun setButtonToggleMode(toggleMode : Boolean) { + editInfo.editButton.config.toggleMode = toggleMode + invalidate() + } + fun setButtonScale(@IntRange(from = 0, to = 100) scale : Int) { fun toScaleRange(value : Int) : Float = (value / 100f) * (OnScreenConfiguration.MaxScale - OnScreenConfiguration.MinScale) + OnScreenConfiguration.MinScale @@ -398,6 +403,21 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs return OnScreenConfiguration.GroupIndeterminate } + override var toggleMode : Boolean + get() = controls.allButtons.all { it.supportsToggleMode() == it.config.toggleMode } + set(value) { + controls.allButtons.forEach { if (it.supportsToggleMode()) it.config.toggleMode = value } + } + + override val groupToggleMode : Int + get() { + if (controls.allButtons.all { !it.supportsToggleMode() || it.config.toggleMode }) + return OnScreenConfiguration.GroupEnabled + if (controls.allButtons.all { !it.supportsToggleMode() || !it.config.toggleMode }) + return OnScreenConfiguration.GroupDisabled + return OnScreenConfiguration.GroupIndeterminate + } + override var alpha : Int get() = controls.allButtons.sumOf { it.config.alpha } / controls.allButtons.size set(value) { diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt index 81929b24..94ad9fee 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt @@ -123,6 +123,9 @@ class OnScreenEditActivity : AppCompatActivity() { binding.enabledCheckbox.setOnClickListener { _ -> binding.onScreenControllerView.setButtonEnabled(binding.enabledCheckbox.isChecked) } + binding.toggleModeCheckbox.setOnClickListener { _ -> + binding.onScreenControllerView.setButtonToggleMode(binding.toggleModeCheckbox.isChecked) + } binding.moveUpButton.setOnClickListener { binding.onScreenControllerView.moveButtonUp() } binding.moveDownButton.setOnClickListener { binding.onScreenControllerView.moveButtonDown() } @@ -194,6 +197,8 @@ class OnScreenEditActivity : AppCompatActivity() { */ private fun updateActiveButtonDisplayInfo(button : ConfigurableButton) { binding.enabledCheckbox.checkedState = button.config.groupEnabled + binding.toggleModeCheckbox.isEnabled = button.supportsToggleMode() + binding.toggleModeCheckbox.checkedState = button.config.groupToggleMode currentButtonName = button.buttonId.short ?: "" binding.currentButton.text = getString(R.string.osc_current_button, currentButtonName) binding.scaleSlider.slider.value = (button.config.scale - OnScreenConfiguration.MinScale) / (OnScreenConfiguration.MaxScale - OnScreenConfiguration.MinScale) * 100f diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt index 175e73ce..9691f20e 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt @@ -68,6 +68,8 @@ class JoystickButton( var shortDoubleTapped = false private set + override fun supportsToggleMode() : Boolean = false + override fun renderCenteredText(canvas : Canvas, text : String, size : Float, x : Float, y : Float, alpha : Int) = Unit override fun render(canvas : Canvas) { @@ -78,7 +80,7 @@ class JoystickButton( innerButton.render(canvas) } - override fun onFingerDown(x : Float, y : Float) { + override fun onFingerDown(x : Float, y : Float) : Boolean { val relativeX = x / width val relativeY = (y - heightDiff) / adjustedHeight if (recenterSticks) { @@ -99,9 +101,11 @@ class JoystickButton( isPressed = true } fingerDownTime = currentTime + + return true } - override fun onFingerUp(x : Float, y : Float) { + override fun onFingerUp(x : Float, y : Float) : Boolean { loadConfigValues() innerButton.relativeX = relativeX innerButton.relativeY = relativeY @@ -109,6 +113,8 @@ class JoystickButton( fingerUpTime = SystemClock.elapsedRealtime() shortDoubleTapped = false isPressed = false + + return true } fun onFingerMoved(x : Float, y : Float, manualMove : Boolean = true) : PointF { diff --git a/app/src/main/res/layout/on_screen_edit_activity.xml b/app/src/main/res/layout/on_screen_edit_activity.xml index 94e9f90e..0b858ca2 100644 --- a/app/src/main/res/layout/on_screen_edit_activity.xml +++ b/app/src/main/res/layout/on_screen_edit_activity.xml @@ -137,7 +137,6 @@ android:minHeight="0dp" android:paddingVertical="8dp" android:text="@string/osc_toggle_mode" - android:visibility="gone" app:layout_constraintStart_toStartOf="@+id/enabled_checkbox" app:layout_constraintTop_toBottomOf="@id/enabled_checkbox" tools:ignore="TouchTargetSizeCheck" />