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 MaxScale = 2.5f
const val DefaultScale = 1f 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 DefaultTextColor = SwitchColors.BLACK.color
val DefaultBackgroundColor = SwitchColors.WHITE.color val DefaultBackgroundColor = SwitchColors.WHITE.color
} }
@ -51,6 +55,11 @@ interface OnScreenConfiguration {
var scale : Float var scale : Float
var relativeX : Float var relativeX : Float
var relativeY : 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 { 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 scale by config(OnScreenConfiguration.DefaultScale)
override var relativeX by config(defaultRelativeX) override var relativeX by config(defaultRelativeX)
override var relativeY by config(defaultRelativeY) 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() 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() { fun moveButtonUp() {
editInfo.editButton.moveUp() editInfo.editButton.moveUp()
invalidate() invalidate()
@ -462,6 +472,7 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
override var relativeX = 0f override var relativeX = 0f
override var relativeY = 0f override var relativeY = 0f
override var activationRadius = 0f
} }
override fun startMove(x : Float, y : Float) {} override fun startMove(x : Float, y : Float) {}

View File

@ -120,6 +120,9 @@ class OnScreenEditActivity : AppCompatActivity() {
populateSlider(binding.opacitySlider, getString(R.string.osc_opacity)) { populateSlider(binding.opacitySlider, getString(R.string.osc_opacity)) {
binding.onScreenControllerView.setButtonOpacity(it) binding.onScreenControllerView.setButtonOpacity(it)
} }
populateSlider(binding.activationSlider, getString(R.string.osc_activation_radius)) {
binding.onScreenControllerView.setStickActivationRadius(it)
}
binding.enabledCheckbox.setOnClickListener { _ -> binding.enabledCheckbox.setOnClickListener { _ ->
binding.onScreenControllerView.setButtonEnabled(binding.enabledCheckbox.isChecked) binding.onScreenControllerView.setButtonEnabled(binding.enabledCheckbox.isChecked)
@ -190,6 +193,8 @@ class OnScreenEditActivity : AppCompatActivity() {
if (fromUser) if (fromUser)
valueListener?.invoke(value.roundToInt()) 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 * Updates the control panel UI elements to reflect the currently selected button
*/ */
private fun updateActiveButtonDisplayInfo(button : ConfigurableButton) { 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.enabledCheckbox.checkedState = button.config.groupEnabled
binding.toggleModeCheckbox.isEnabled = button.supportsToggleMode()
binding.toggleModeCheckbox.checkedState = button.config.groupToggleMode
currentButtonName = button.buttonId.short ?: "" currentButtonName = button.buttonId.short ?: ""
binding.currentButton.text = getString(R.string.osc_current_button, currentButtonName) 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.scaleSlider.slider.value = button.config.scale.toSliderRange(OnScreenConfiguration.MinScale, OnScreenConfiguration.MaxScale)
binding.opacitySlider.slider.value = (button.config.alpha - OnScreenConfiguration.MinAlpha) / (OnScreenConfiguration.MaxAlpha - OnScreenConfiguration.MinAlpha).toFloat() * 100f 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") @SuppressLint("ClickableViewAccessibility")

View File

@ -6,6 +6,7 @@
package emu.skyline.input.onscreen package emu.skyline.input.onscreen
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.graphics.PointF import android.graphics.PointF
import android.graphics.Rect 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) private val innerButton = CircularButton(onScreenControllerView, buttonId, config.relativeX, config.relativeY, defaultRelativeRadiusToX * 0.75f, R.drawable.ic_stick)
open var recenterSticks = false 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 initialTapPosition = PointF()
private var fingerDownTime = 0L private var fingerDownTime = 0L
private var fingerUpTime = 0L private var fingerUpTime = 0L
var shortDoubleTapped = false var shortDoubleTapped = false
private set 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 supportsToggleMode() : Boolean = false
override fun renderCenteredText(canvas : Canvas, text : String, size : Float, x : Float, y : Float, alpha : Int) = Unit 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) { override fun render(canvas : Canvas) {
super.render(canvas) super.render(canvas)
innerButton.width = width innerButton.width = width
innerButton.height = height innerButton.height = height
innerButton.render(canvas) 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 { override fun onFingerDown(x : Float, y : Float) : Boolean {
@ -156,6 +180,7 @@ open class JoystickButton(
override fun resetConfig() { override fun resetConfig() {
super.resetConfig() super.resetConfig()
config.activationRadius = OnScreenConfiguration.DefaultActivationRadius
innerButton.relativeX = relativeX innerButton.relativeX = relativeX
innerButton.relativeY = relativeY innerButton.relativeY = relativeY

View File

@ -162,6 +162,15 @@
app:layout_constraintStart_toStartOf="@id/scale_slider" app:layout_constraintStart_toStartOf="@id/scale_slider"
app:layout_constraintTop_toBottomOf="@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 <androidx.constraintlayout.widget.Barrier
android:id="@+id/sliders_barrier" android:id="@+id/sliders_barrier"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

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

View File

@ -168,6 +168,7 @@
<string name="select_all">Select All</string> <string name="select_all">Select All</string>
<string name="osc_scale">Scale</string> <string name="osc_scale">Scale</string>
<string name="osc_opacity">Opacity</string> <string name="osc_opacity">Opacity</string>
<string name="osc_activation_radius">Activation Radius</string>
<string name="button_color">Button color</string> <string name="button_color">Button color</string>
<string name="toggle_grid">Toggle grid</string> <string name="toggle_grid">Toggle grid</string>
<string name="setup_guide">Setup Guide</string> <string name="setup_guide">Setup Guide</string>
@ -177,7 +178,7 @@
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<string name="osc_recenter_sticks">Recenter Sticks On Touch</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">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="controller">Controller</string>
<string name="config_controller">Configure Controller</string> <string name="config_controller">Configure Controller</string>
<string name="controller_type">Controller Type</string> <string name="controller_type">Controller Type</string>