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 0309f7b7..7b0b42ab 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt @@ -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) } 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 e818abea..8f66a489 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt @@ -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) {} 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 e0a27f45..b79e12ce 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt @@ -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") 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 e8c41e85..4683f2c0 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt @@ -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 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 0b858ca2..dc8dc17d 100644 --- a/app/src/main/res/layout/on_screen_edit_activity.xml +++ b/app/src/main/res/layout/on_screen_edit_activity.xml @@ -162,6 +162,15 @@ app:layout_constraintStart_toStartOf="@id/scale_slider" app:layout_constraintTop_toBottomOf="@id/scale_slider" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5f6b97d..f60a4615 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,6 +168,7 @@ Select All Scale Opacity + Activation Radius Button color Toggle grid Setup Guide @@ -177,7 +178,7 @@ Cancel Recenter Sticks On Touch Use Stick Regions - When enabled, the stick activaation radius is extended to the corresponding half of the screen. + Extend the activation area of the sticks to rectangles covering the corresponding half of the screen Controller Configure Controller Controller Type