Progress commit for better impl, need to have the pop up menu show up to select buttons

This commit is contained in:
ADAS2024 2026-03-29 14:54:22 -04:00
parent 3ef66be317
commit 13e80ec1fe
9 changed files with 134 additions and 199 deletions

View File

@ -1,9 +0,0 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model
interface AbstractMultiIntSetting : AbstractSetting {
var ints: MutableSet<Int>
}

View File

@ -1,9 +0,0 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model
interface AbstractMultiShortSetting : AbstractSetting {
var shorts: MutableSet<Short>
}

View File

@ -7,11 +7,24 @@ package org.citra.citra_emu.features.settings.model
enum class StringListSetting(
override val key: String,
override val section: String,
override val defaultValue: List<String>
override val defaultValue: List<String>,
val canBeEmpty: Boolean = true
) : AbstractListSetting<String> {
COMBO_KEY_LIST("combo_key_list", Settings.SECTION_CONTROLS, listOf("A", "B", "X", "Y", "L", "R", "ZL", "ZR", "Start", "Select"));
COMBO_KEYS("combo_keys", Settings.SECTION_CONTROLS, listOf("A", "B", "X", "Y", "L", "R", "ZL", "ZR", "Start", "Select"));
override var list: List<String> = defaultValue
private var backingList: List<String> = defaultValue
private var lastValidList : List<String> = defaultValue
override var list: List<String>
get() = backingList
set(value) {
if (!canBeEmpty && value.isEmpty()) {
backingList = lastValidList
} else {
backingList = value
lastValidList = value
}
}
override val valueAsString: String
get() = list.joinToString()

View File

@ -3,12 +3,8 @@
// Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model.view
import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractMultiShortSetting
import org.citra.citra_emu.features.settings.model.AbstractMultiStringSetting
import org.citra.citra_emu.features.settings.model.StringListSetting
class StringMultiChoiceSetting(
setting: AbstractSetting?,
titleId: Int,
@ -29,77 +25,29 @@ class StringMultiChoiceSetting(
""
}
}
val selectedValues: List<String>
get() {
if (setting == null) {
return defaultValue!!
}
try {
val setting = setting as AbstractMultiStringSetting
return setting.strings.toList()
} catch (_: ClassCastException) {
}
try {
val setting = setting as AbstractMultiShortSetting
return setting.shorts.map { it.toString() }
} catch (_: ClassCastException) {
val setting = setting as StringListSetting
return setting.list
}catch (_: ClassCastException) {
}
return defaultValue!!
}
val selectValueIndices: BooleanArray
get() {
val noneList = values?.let {
ArrayList(BooleanArray(it.size) { false }.toList())
} ?: ArrayList()
val chosenindices = mutableListOf<Boolean>()
val selectedValues = selectedValues
for (i in values!!.indices) {
if (values[i] in selectedValues) {
chosenindices.add(true)
} else {
chosenindices.add(false)
}
}
if (chosenindices == null) {
return noneList.toBooleanArray()
} else {
return chosenindices.toBooleanArray()
}
}
/**
* Add values to multi choice through the backing mutable sets.
* Write a value to the backing list. If that list was previously null,
* initializes a new one and returns it, so it can be added to the Hashmap.
*
* @param selection New value of the int.
* @return the existing setting with the new value added.
* @return the existing setting with the new value applied.
*/
fun addSelectedValue(selection: String): AbstractMultiStringSetting {
val stringSetting = setting as AbstractMultiStringSetting
stringSetting.strings.add(selection)
fun setSelectedValue(selection: List<String>): StringListSetting {
val stringSetting = setting as StringListSetting
stringSetting.list = selection
return stringSetting
}
fun addSelectedValue(selection: Short): AbstractMultiShortSetting {
val shortSetting = setting as AbstractMultiShortSetting
shortSetting.shorts.add(selection)
return shortSetting
}
fun removeSelectedValue(selection: String): AbstractMultiStringSetting {
val stringSetting = setting as AbstractMultiStringSetting
stringSetting.strings.remove(selection)
return stringSetting
}
fun removeSelectedValue(selection: Short): AbstractMultiShortSetting {
val shortSetting = setting as AbstractMultiShortSetting
shortSetting.shorts.remove(selection)
return shortSetting
}
}

View File

@ -38,7 +38,6 @@ import org.citra.citra_emu.databinding.ListItemSettingsHeaderBinding
import org.citra.citra_emu.features.settings.model.AbstractBooleanSetting
import org.citra.citra_emu.features.settings.model.AbstractFloatSetting
import org.citra.citra_emu.features.settings.model.AbstractIntSetting
import org.citra.citra_emu.features.settings.model.AbstractMultiShortSetting
import org.citra.citra_emu.features.settings.model.AbstractMultiStringSetting
import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractStringSetting
@ -61,7 +60,6 @@ import org.citra.citra_emu.features.settings.model.view.SwitchSetting
import org.citra.citra_emu.features.settings.ui.viewholder.DateTimeViewHolder
import org.citra.citra_emu.features.settings.ui.viewholder.HeaderViewHolder
import org.citra.citra_emu.features.settings.ui.viewholder.InputBindingSettingViewHolder
import org.citra.citra_emu.features.settings.ui.viewholder.StringMultiChoiceViewHolder // TODO: Remove and integrate within MultiChoiceViewHolder
import org.citra.citra_emu.features.settings.ui.viewholder.MultiChoiceViewHolder
import org.citra.citra_emu.features.settings.ui.viewholder.RunnableViewHolder
import org.citra.citra_emu.features.settings.ui.viewholder.SettingViewHolder
@ -143,7 +141,7 @@ class SettingsAdapter(
}
SettingsItem.TYPE_MULTI_CHOICE, SettingsItem.TYPE_STRING_MULTI_CHOICE -> {
StringMultiChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this)
MultiChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
else -> {
@ -285,6 +283,26 @@ class SettingsAdapter(
onMultiChoiceClick(item)
}
private fun onStringMultiChoiceClick(item: StringMultiChoiceSetting) {
clickedItem = item
val values: BooleanArray = getSelectionForStringMultiChoiceValue(item);
dialog = MaterialAlertDialogBuilder(context)
.setTitle(item.nameId)
.setMultiChoiceItems(item.choices, values, this)
.setOnDismissListener {
if (clickedPosition != -1) {
notifyItemChanged(clickedPosition)
clickedPosition = -1
}
}
.show()
}
fun onStringMultiChoiceClick(item: StringMultiChoiceSetting, position: Int) {
clickedPosition = position
onStringMultiChoiceClick(item)
}
private fun onStringSingleChoiceClick(item: StringSingleChoiceSetting) {
clickedItem = item
dialog = context?.let {
@ -585,15 +603,34 @@ class SettingsAdapter(
//onclick for multichoice
override fun onClick(dialog: DialogInterface?, which: Int, isChecked: Boolean) {
val mcsetting = clickedItem as? MultiChoiceSetting
mcsetting?.let {
val value = getValueForMultiChoiceSelection(it, which)
if (it.selectedValues.contains(value) != isChecked) {
val setting = it.setSelectedValue((if (isChecked) it.selectedValues + value else it.selectedValues - value).sorted())
fragmentView?.putSetting(setting)
fragmentView?.onSettingChanged()
when (clickedItem) {
is MultiChoiceSetting -> {
val mcsetting = clickedItem as? MultiChoiceSetting
mcsetting?.let {
val value = getValueForMultiChoiceSelection(it, which)
if (it.selectedValues.contains(value) != isChecked) {
val setting =
it.setSelectedValue((if (isChecked) it.selectedValues + value else it.selectedValues - value).sorted())
fragmentView?.putSetting(setting)
fragmentView?.onSettingChanged()
}
fragmentView.loadSettingsList()
}
}
is StringMultiChoiceSetting -> {
val mcsetting = clickedItem as? StringMultiChoiceSetting
mcsetting?.let {
val value = it.getValueAt(which)
if (it.selectedValues.contains(value) != isChecked) {
val setting =
it.setSelectedValue((if (isChecked) it.selectedValues + value.toString() else it.selectedValues - value.toString()).sorted())
fragmentView?.putSetting(setting)
fragmentView?.onSettingChanged()
}
fragmentView.loadSettingsList()
}
}
fragmentView.loadSettingsList()
}
}
@ -728,6 +765,7 @@ class SettingsAdapter(
}
}
private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int {
val value = item.selectedValue
val valuesId = item.valuesId
@ -760,8 +798,33 @@ class SettingsAdapter(
}
return BooleanArray(1){false};
}
//TODO: Properly Implement in line with string single choice
private fun getSelectionForStringMultiChoiceValue(item: StringMultiChoiceSetting): BooleanArray {
val values = item.selectedValues;
val available_values = item.values;
val res = BooleanArray(available_values?.size ?: 0){false}
var index = 0;
if (available_values != null) {
for (choice_val in available_values) {
if (values.contains(choice_val)) {
res[index] = true;
index++;
}
}
}
return if (res.isNotEmpty()) {
res;
} else {
BooleanArray(1) { false };
}
}
//TODO: I only added MultiChoice for fleshing out backend, debating whether to remove MultiChoiceSetting and related code for cleaning up
/*
override fun onClick(dialog: DialogInterface?, which: Int, is_checked: Boolean) {
when (clickedItem) {
/*
@ -836,4 +899,6 @@ class SettingsAdapter(
}
}
}
*/
}

View File

@ -22,7 +22,6 @@ import org.citra.citra_emu.display.StereoMode
import org.citra.citra_emu.display.StereoWhichDisplay
import org.citra.citra_emu.features.settings.model.AbstractBooleanSetting
import org.citra.citra_emu.features.settings.model.AbstractIntSetting
import org.citra.citra_emu.features.settings.model.AbstractMultiStringSetting
import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractShortSetting
import org.citra.citra_emu.features.settings.model.AbstractStringSetting
@ -32,6 +31,7 @@ import org.citra.citra_emu.features.settings.model.IntSetting
import org.citra.citra_emu.features.settings.model.IntListSetting
import org.citra.citra_emu.features.settings.model.ScaledFloatSetting
import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.features.settings.model.StringListSetting
import org.citra.citra_emu.features.settings.model.StringSetting
import org.citra.citra_emu.features.settings.model.view.DateTimeSetting
import org.citra.citra_emu.features.settings.model.view.HeaderSetting
@ -781,25 +781,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
private fun addControlsSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_controls))
val comboSetting = object : AbstractMultiStringSetting {
override var strings: MutableSet<String>
get() {
return Settings.comboSelection
}
set(values) {
for (item in values) {
Settings.comboSelection.add(item)
}
}
override val key = null
override val section = null
override val isRuntimeEditable = true
override val valueAsString get() = ""
override val defaultValue = ""
}
val buttons = settingsActivity.resources.getStringArray(R.array.n3dsButtons).take(10).toTypedArray()
sl.apply {
add(
RunnableSetting(
@ -861,13 +842,17 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
BooleanSetting.USE_ARTIC_BASE_CONTROLLER.defaultValue
)
)
val buttons = settingsActivity.resources.getStringArray(R.array.n3dsButtons).take(10).toTypedArray()
add(
StringMultiChoiceSetting(
comboSetting,
StringListSetting.COMBO_KEYS,
R.string.combo_key_options,
0,
R.string.combo_key_description,
buttons,
buttons
buttons,
StringListSetting.COMBO_KEYS.key,
StringListSetting.COMBO_KEYS.defaultValue
)
)
}

View File

@ -8,6 +8,7 @@ import android.view.View
import org.citra.citra_emu.databinding.ListItemSettingBinding
import org.citra.citra_emu.features.settings.model.view.SettingsItem
import org.citra.citra_emu.features.settings.model.view.MultiChoiceSetting
import org.citra.citra_emu.features.settings.model.view.StringMultiChoiceSetting
import org.citra.citra_emu.features.settings.ui.SettingsAdapter
class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@ -51,6 +52,16 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
return resList.joinToString();
}
is StringMultiChoiceSetting -> {
var resList:List<String> = emptyList();
item.values?.forEachIndexed { i: Int, value: String ->
if (value in item.selectedValues) {
resList = resList + item.choices[i]
}
}
return resList.joinToString()
}
else -> return ""
}
}
@ -67,6 +78,12 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
bindingAdapterPosition
)
}
if (setting is StringMultiChoiceSetting) {
adapter.onStringMultiChoiceClick(
(setting as StringMultiChoiceSetting),
bindingAdapterPosition
)
}
}
override fun onLongClick(clicked: View): Boolean {

View File

@ -1,77 +0,0 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.ui.viewholder
import android.view.View
import org.citra.citra_emu.databinding.ListItemSettingBinding
import org.citra.citra_emu.features.settings.model.view.SettingsItem
import org.citra.citra_emu.features.settings.model.view.StringMultiChoiceSetting
import org.citra.citra_emu.features.settings.ui.SettingsAdapter
class StringMultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: SettingsItem
override fun bind(item: SettingsItem) {
setting = item
binding.textSettingName.setText(item.nameId)
if (item.descriptionId != 0) {
binding.textSettingDescription.visibility = View.VISIBLE
binding.textSettingDescription.setText(item.descriptionId)
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
binding.textSettingValue.text = getTextSetting()
if (setting.isActive) {
binding.textSettingName.alpha = 1f
binding.textSettingDescription.alpha = 1f
binding.textSettingValue.alpha = 1f
} else {
binding.textSettingName.alpha = 0.5f
binding.textSettingDescription.alpha = 0.5f
binding.textSettingValue.alpha = 0.5f
}
}
private fun getTextSetting(): String {
when (val item = setting) {
is StringMultiChoiceSetting -> {
item.values?.forEachIndexed { i: Int, value: String ->
if (value in item.selectedValues) {
return item.choices[i]
}
}
return ""
}
else -> return ""
}
}
override fun onClick(clicked: View) {
if (!setting.isEditable || !setting.isEnabled) {
adapter.onClickDisabledSetting(!setting.isEditable)
return
}
if (setting is StringMultiChoiceSetting) {
adapter.onStringMultiChoiceClick(
(setting as StringMultiChoiceSetting),
bindingAdapterPosition
)
}
}
override fun onLongClick(clicked: View): Boolean {
if (setting.isActive) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
}
return false
}
}

View File

@ -7,6 +7,7 @@ package org.citra.citra_emu.utils
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.overlay.InputOverlayDrawableButton
import org.citra.citra_emu.features.settings.model.StringListSetting
object ComboHelper {
@ -27,16 +28,17 @@ object ComboHelper {
}
fun comboActivate(button: InputOverlayDrawableButton) {
var comboArray = Settings.comboSelection
for (selectedbutton in comboArray) {
var nativebutton = getButton(selectedbutton)
if (nativebutton == -1)
var comboArray = StringListSetting.COMBO_KEYS.list
for (selected_button in comboArray) {
var native_button = getButton(selected_button)
if (native_button == -1)
{
//TODO: Need proper error handling here
println("Bad Button")
}
else
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, nativebutton, button.status)
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, native_button, button.status)
}
}
}