mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 01:35:28 +03:00
Rework OSC edit mode handling for better extensibility
Edit mode configuration parameters are now shared between the view and the buttons in a small `OnScreenEditInfo` object, avoiding variable duplication about edit state. The `editingTouchHandler` has also been simplified to only lookup the button if one wasn't being edited already.
This commit is contained in:
parent
c4d0d02509
commit
81eb8fd231
@ -82,8 +82,10 @@ abstract class OnScreenButton(
|
||||
|
||||
var hapticFeedback = false
|
||||
|
||||
var isEditing = false
|
||||
private set
|
||||
/**
|
||||
* The edit session information, populated by the view
|
||||
*/
|
||||
protected var editInfo = onScreenControllerView.editInfo
|
||||
|
||||
protected open fun renderCenteredText(canvas : Canvas, text : String, size : Float, x : Float, y : Float, alpha : Int) {
|
||||
buttonSymbolPaint.apply {
|
||||
@ -133,19 +135,35 @@ abstract class OnScreenButton(
|
||||
relativeY = config.relativeY
|
||||
}
|
||||
|
||||
fun startEdit() {
|
||||
isEditing = true
|
||||
/**
|
||||
* Starts an edit session
|
||||
* @param x The x coordinate of the initial touch
|
||||
* @param y The y coordinate of the initial touch
|
||||
*/
|
||||
open fun startEdit(x : Float, y : Float) {
|
||||
}
|
||||
|
||||
open fun edit(x : Float, y : Float) {
|
||||
when (editInfo.editMode) {
|
||||
EditMode.Move -> move(x, y)
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves this button to the given coordinates
|
||||
*/
|
||||
open fun move(x : Float, y : Float) {
|
||||
relativeX = x / width
|
||||
relativeY = (y - heightDiff) / adjustedHeight
|
||||
}
|
||||
|
||||
fun endEdit() {
|
||||
/**
|
||||
* Ends the current edit session
|
||||
*/
|
||||
open fun endEdit() {
|
||||
config.relativeX = relativeX
|
||||
config.relativeY = relativeY
|
||||
isEditing = false
|
||||
}
|
||||
|
||||
open fun resetRelativeValues() {
|
||||
|
@ -43,7 +43,6 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
|
||||
private val ALPHA_RANGE = 55..255
|
||||
}
|
||||
|
||||
private val controls = Controls(this)
|
||||
private var onButtonStateChangedListener : OnButtonStateChangedListener? = null
|
||||
private var onStickStateChangedListener : OnStickStateChangedListener? = null
|
||||
private val joystickAnimators = mutableMapOf<JoystickButton, Animator?>()
|
||||
@ -63,10 +62,15 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
|
||||
(controls.circularButtons + controls.rectangularButtons + controls.triggerButtons).forEach { it.hapticFeedback = hapticFeedback }
|
||||
}
|
||||
|
||||
val editInfo = OnScreenEditInfo()
|
||||
val isEditing get() = editInfo.isEditing
|
||||
|
||||
// Populated externally by the activity, as retrieving the vibrator service inside the view crashes the layout editor
|
||||
lateinit var vibrator : Vibrator
|
||||
private val effectClick = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
|
||||
|
||||
private val controls = Controls(this)
|
||||
|
||||
override fun onDraw(canvas : Canvas) {
|
||||
super.onDraw(canvas)
|
||||
|
||||
@ -218,42 +222,50 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
|
||||
}
|
||||
|
||||
private val editingTouchHandler = OnTouchListener { _, event ->
|
||||
controls.allButtons.any { button ->
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP,
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
if (button.isEditing) {
|
||||
button.endEdit()
|
||||
return@any true
|
||||
}
|
||||
}
|
||||
var handled = false
|
||||
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
// Handle this event only if no other button is being edited
|
||||
if (editInfo.editButton == null) {
|
||||
handled = controls.allButtons.any { button ->
|
||||
if (button.config.enabled && button.isTouched(event.x, event.y)) {
|
||||
button.startEdit()
|
||||
editInfo.editButton = button
|
||||
button.startEdit(event.x, event.y)
|
||||
performClick()
|
||||
return@any true
|
||||
true
|
||||
} else false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (button.isEditing) {
|
||||
button.edit(event.x, event.y)
|
||||
return@any true
|
||||
editInfo.editButton?.edit(event.x, event.y)
|
||||
handled = true
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP,
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
editInfo.editButton?.endEdit()
|
||||
editInfo.editButton = null
|
||||
handled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}.also { handled -> if (handled) invalidate() }
|
||||
|
||||
handled.also { if (it) invalidate() }
|
||||
}
|
||||
|
||||
init {
|
||||
setOnTouchListener(playingTouchHandler)
|
||||
}
|
||||
|
||||
fun setEditMode(editMode : Boolean) = setOnTouchListener(if (editMode) editingTouchHandler else playingTouchHandler)
|
||||
fun setEditMode(editMode : EditMode) {
|
||||
editInfo.editMode = editMode
|
||||
setOnTouchListener(if (editMode == EditMode.None) playingTouchHandler else editingTouchHandler)
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun resetControls() {
|
||||
controls.allButtons.forEach {
|
||||
@ -301,7 +313,9 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
|
||||
onStickStateChangedListener = listener
|
||||
}
|
||||
|
||||
fun getButtonProps() = controls.allButtons.map { Pair(it.buttonId, it.config.enabled) }
|
||||
data class ButtonProp(val buttonId : ButtonId, val enabled : Boolean)
|
||||
|
||||
fun getButtonProps() = controls.allButtons.map { ButtonProp(it.buttonId, it.config.enabled) }
|
||||
|
||||
fun setButtonEnabled(buttonId : ButtonId, enabled : Boolean) {
|
||||
controls.allButtons.first { it.buttonId == buttonId }.config.enabled = enabled
|
||||
|
@ -29,16 +29,14 @@ class OnScreenEditActivity : AppCompatActivity() {
|
||||
private val binding by lazy { OnScreenEditActivityBinding.inflate(layoutInflater) }
|
||||
|
||||
private var fullEditVisible = true
|
||||
private var editMode = false
|
||||
|
||||
@Inject
|
||||
lateinit var appSettings : AppSettings
|
||||
|
||||
private val closeAction : () -> Unit = {
|
||||
if (editMode) {
|
||||
if (binding.onScreenControllerView.isEditing) {
|
||||
toggleFabVisibility(true)
|
||||
binding.onScreenControllerView.setEditMode(false)
|
||||
editMode = false
|
||||
binding.onScreenControllerView.setEditMode(EditMode.None)
|
||||
} else {
|
||||
fullEditVisible = !fullEditVisible
|
||||
toggleFabVisibility(fullEditVisible)
|
||||
@ -55,28 +53,32 @@ class OnScreenEditActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private val editAction = {
|
||||
editMode = true
|
||||
binding.onScreenControllerView.setEditMode(true)
|
||||
private val moveAction = {
|
||||
binding.onScreenControllerView.setEditMode(EditMode.Move)
|
||||
toggleFabVisibility(false)
|
||||
}
|
||||
|
||||
private val toggleAction : () -> Unit = {
|
||||
val buttonProps = binding.onScreenControllerView.getButtonProps()
|
||||
val checkArray = buttonProps.map { it.second }.toBooleanArray()
|
||||
val checkedButtonsArray = buttonProps.map { it.enabled }.toBooleanArray()
|
||||
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setMultiChoiceItems(buttonProps.map {
|
||||
val longText = getString(it.first.long!!)
|
||||
if (it.first.short == longText) longText else "$longText: ${it.first.short}"
|
||||
}.toTypedArray(), checkArray) { _, which, isChecked ->
|
||||
checkArray[which] = isChecked
|
||||
}.setPositiveButton(R.string.confirm) { _, _ ->
|
||||
buttonProps.forEachIndexed { index, pair ->
|
||||
if (checkArray[index] != pair.second)
|
||||
binding.onScreenControllerView.setButtonEnabled(pair.first, checkArray[index])
|
||||
.setMultiChoiceItems(
|
||||
buttonProps.map { button ->
|
||||
val longText = getString(button.buttonId.long!!)
|
||||
if (button.buttonId.short == longText) longText else "$longText: ${button.buttonId.short}"
|
||||
}.toTypedArray(),
|
||||
checkedButtonsArray
|
||||
) { _, which, isChecked ->
|
||||
checkedButtonsArray[which] = isChecked
|
||||
}
|
||||
}.setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(R.string.confirm) { _, _ ->
|
||||
buttonProps.forEachIndexed { index, button ->
|
||||
if (checkedButtonsArray[index] != button.enabled)
|
||||
binding.onScreenControllerView.setButtonEnabled(button.buttonId, checkedButtonsArray[index])
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnDismissListener { fullScreen() }
|
||||
.show()
|
||||
}
|
||||
@ -105,7 +107,7 @@ class OnScreenEditActivity : AppCompatActivity() {
|
||||
Pair(R.drawable.ic_palette, paletteAction),
|
||||
Pair(R.drawable.ic_restore) { binding.onScreenControllerView.resetControls() },
|
||||
Pair(R.drawable.ic_toggle, toggleAction),
|
||||
Pair(R.drawable.ic_edit, editAction),
|
||||
Pair(R.drawable.ic_edit, moveAction),
|
||||
Pair(R.drawable.ic_zoom_out) { binding.onScreenControllerView.decreaseScale() },
|
||||
Pair(R.drawable.ic_zoom_in) { binding.onScreenControllerView.increaseScale() },
|
||||
Pair(R.drawable.ic_opacity_minus) { binding.onScreenControllerView.decreaseOpacity() },
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
* Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
*/
|
||||
|
||||
package emu.skyline.input.onscreen
|
||||
|
||||
enum class EditMode {
|
||||
None,
|
||||
Move,
|
||||
}
|
||||
|
||||
/**
|
||||
* A small class that holds information about the current edit session
|
||||
* This is used to share information between the [OnScreenControllerView] and the individual [OnScreenButton]s
|
||||
*/
|
||||
class OnScreenEditInfo {
|
||||
/**
|
||||
* The current edit mode
|
||||
*/
|
||||
var editMode : EditMode = EditMode.None
|
||||
|
||||
/**
|
||||
* The button that is currently being edited
|
||||
*/
|
||||
var editButton : OnScreenButton? = null
|
||||
|
||||
val isEditing get() = editMode != EditMode.None
|
||||
}
|
Loading…
Reference in New Issue
Block a user