Implement OSC customizable stick activation radius

This commit is contained in:
lynxnb 2023-04-19 23:37:17 +02:00 committed by Billy Laws
parent d86b2ec3e9
commit 563c72afa9
7 changed files with 78 additions and 5 deletions

View File

@ -26,6 +26,10 @@ interface OnScreenConfiguration {
const val MaxScale = 2.5f
const val DefaultScale = 1f
const val MinActivationRadius = 1.0f
const val DefaultActivationRadius = 1.0f
const val MaxActivationRadius = 8.0f
val DefaultTextColor = SwitchColors.BLACK.color
val DefaultBackgroundColor = SwitchColors.WHITE.color
}
@ -51,6 +55,11 @@ interface OnScreenConfiguration {
var scale : Float
var relativeX : Float
var relativeY : Float
/**
* A modifier applied to the radius of the stick, applied when determining when the stick has been touched
*/
var activationRadius : Float
}
class OnScreenConfigurationImpl(private val context : Context, private val buttonId : ButtonId, defaultRelativeX : Float, defaultRelativeY : Float, defaultEnabled : Boolean) : OnScreenConfiguration {
@ -66,4 +75,6 @@ class OnScreenConfigurationImpl(private val context : Context, private val butto
override var scale by config(OnScreenConfiguration.DefaultScale)
override var relativeX by config(defaultRelativeX)
override var relativeY by config(defaultRelativeY)
override var activationRadius by config(OnScreenConfiguration.DefaultActivationRadius)
}

View File

@ -355,6 +355,16 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
invalidate()
}
fun setStickActivationRadius(@IntRange(from = 0, to = 100) radius : Int) {
fun toRadiusRange(value : Int) : Float = (value / 100f) * (OnScreenConfiguration.MaxActivationRadius - OnScreenConfiguration.MinActivationRadius) + OnScreenConfiguration.MinActivationRadius
(editInfo.editButton as? JoystickButton)?.let { joystick ->
joystick.config.activationRadius = toRadiusRange(radius)
joystick.loadActivationRadius()
}
invalidate()
}
fun moveButtonUp() {
editInfo.editButton.moveUp()
invalidate()
@ -462,6 +472,7 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
override var relativeX = 0f
override var relativeY = 0f
override var activationRadius = 0f
}
override fun startMove(x : Float, y : Float) {}

View File

@ -120,6 +120,9 @@ class OnScreenEditActivity : AppCompatActivity() {
populateSlider(binding.opacitySlider, getString(R.string.osc_opacity)) {
binding.onScreenControllerView.setButtonOpacity(it)
}
populateSlider(binding.activationSlider, getString(R.string.osc_activation_radius)) {
binding.onScreenControllerView.setStickActivationRadius(it)
}
binding.enabledCheckbox.setOnClickListener { _ ->
binding.onScreenControllerView.setButtonEnabled(binding.enabledCheckbox.isChecked)
@ -190,6 +193,8 @@ class OnScreenEditActivity : AppCompatActivity() {
if (fromUser)
valueListener?.invoke(value.roundToInt())
}
// Update the value label with the initial value to avoid it being blank
slider.valueLabel.text = "${value.roundToInt()}%"
}
}
@ -197,13 +202,23 @@ class OnScreenEditActivity : AppCompatActivity() {
* Updates the control panel UI elements to reflect the currently selected button
*/
private fun updateActiveButtonDisplayInfo(button : ConfigurableButton) {
fun Float.toSliderRange(min : Float, max : Float) : Float = ((this - min) / (max - min) * 100f).coerceIn(0f, 100f)
fun Int.toSliderRange(min : Int, max : Int) : Float = ((this - min) / (max - min).toFloat() * 100f).coerceIn(0f, 100f)
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
binding.opacitySlider.slider.value = (button.config.alpha - OnScreenConfiguration.MinAlpha) / (OnScreenConfiguration.MaxAlpha - OnScreenConfiguration.MinAlpha).toFloat() * 100f
binding.scaleSlider.slider.value = button.config.scale.toSliderRange(OnScreenConfiguration.MinScale, OnScreenConfiguration.MaxScale)
binding.opacitySlider.slider.value = button.config.alpha.toSliderRange(OnScreenConfiguration.MinAlpha, OnScreenConfiguration.MaxAlpha)
if (button is JoystickButton) {
binding.toggleModeCheckbox.isGone = true
binding.activationSlider.all.isGone = false
binding.activationSlider.slider.value = button.config.activationRadius.toSliderRange(OnScreenConfiguration.MinActivationRadius, OnScreenConfiguration.MaxActivationRadius)
} else {
binding.toggleModeCheckbox.isGone = false
binding.toggleModeCheckbox.checkedState = button.config.groupToggleMode
binding.activationSlider.all.isGone = true
}
}
@SuppressLint("ClickableViewAccessibility")

View File

@ -6,6 +6,7 @@
package emu.skyline.input.onscreen
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PointF
import android.graphics.Rect
@ -67,22 +68,45 @@ open class JoystickButton(
private val innerButton = CircularButton(onScreenControllerView, buttonId, config.relativeX, config.relativeY, defaultRelativeRadiusToX * 0.75f, R.drawable.ic_stick)
open var recenterSticks = false
set(value) {
field = value
radiusModifier = getRadiusModifier()
}
private var radiusModifier = getRadiusModifier()
private fun getRadiusModifier() = if (recenterSticks) config.activationRadius else OnScreenConfiguration.DefaultActivationRadius
fun loadActivationRadius() {
radiusModifier = getRadiusModifier()
}
private var initialTapPosition = PointF()
private var fingerDownTime = 0L
private var fingerUpTime = 0L
var shortDoubleTapped = false
private set
override fun isTouched(x : Float, y : Float) = (PointF(currentX, currentY) - (PointF(x, y))).length() <= radius * radiusModifier
override fun supportsToggleMode() : Boolean = false
override fun renderCenteredText(canvas : Canvas, text : String, size : Float, x : Float, y : Float, alpha : Int) = Unit
private val activationRadiusPaint = Paint().apply {
color = onScreenControllerView.context.obtainStyledAttributes(intArrayOf(R.attr.colorPrimary)).use { it.getColor(0, Color.RED) }
alpha = 64
}
override fun render(canvas : Canvas) {
super.render(canvas)
innerButton.width = width
innerButton.height = height
innerButton.render(canvas)
if (editInfo.isEditing && editInfo.editButton == this) {
canvas.drawCircle(currentX, currentY, radius * config.activationRadius, activationRadiusPaint)
}
}
override fun onFingerDown(x : Float, y : Float) : Boolean {
@ -156,6 +180,7 @@ open class JoystickButton(
override fun resetConfig() {
super.resetConfig()
config.activationRadius = OnScreenConfiguration.DefaultActivationRadius
innerButton.relativeX = relativeX
innerButton.relativeY = relativeY

View File

@ -162,6 +162,15 @@
app:layout_constraintStart_toStartOf="@id/scale_slider"
app:layout_constraintTop_toBottomOf="@id/scale_slider" />
<include
android:id="@+id/activation_slider"
layout="@layout/osc_slider"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="@id/scale_slider"
app:layout_constraintTop_toBottomOf="@id/opacity_slider" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/sliders_barrier"
android:layout_width="wrap_content"

View File

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

View File

@ -168,6 +168,7 @@
<string name="select_all">Select All</string>
<string name="osc_scale">Scale</string>
<string name="osc_opacity">Opacity</string>
<string name="osc_activation_radius">Activation Radius</string>
<string name="button_color">Button color</string>
<string name="toggle_grid">Toggle grid</string>
<string name="setup_guide">Setup Guide</string>
@ -177,7 +178,7 @@
<string name="cancel">Cancel</string>
<string name="osc_recenter_sticks">Recenter Sticks On Touch</string>
<string name="osc_use_stick_regions">Use Stick Regions</string>
<string name="osc_use_stick_regions_desc">When enabled, the stick activaation radius is extended to the corresponding half of the screen.</string>
<string name="osc_use_stick_regions_desc">Extend the activation area of the sticks to rectangles covering the corresponding half of the screen</string>
<string name="controller">Controller</string>
<string name="config_controller">Configure Controller</string>
<string name="controller_type">Controller Type</string>