Implement toggle mode for OSC buttons

When toggle mode is enabled, the button will toggle between the `Pressed` and `Released` state when it's pressed.

Without toggle mode:
ACTION_DOWN -> Pressed
ACTION_UP -> Released
ACTION_DOWN -> Pressed
ACTION_UP -> Released

With toggle mode:
ACTION_DOWN -> Pressed
ACTION_UP -> No event
ACTION_DOWN -> No event
ACTION_UP -> Released
This commit is contained in:
lynxnb 2023-04-03 03:06:30 +02:00 committed by Billy Laws
parent 78252fbcbd
commit 560fcd9442
7 changed files with 77 additions and 15 deletions

View File

@ -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

View File

@ -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

View File

@ -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 <reified T> 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)

View File

@ -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) {

View File

@ -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

View File

@ -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 {

View File

@ -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" />