diff options
| author | JosJuice <josjuice@gmail.com> | 2025-05-14 18:14:38 +0200 |
|---|---|---|
| committer | JosJuice <josjuice@gmail.com> | 2025-06-07 10:20:20 +0200 |
| commit | 1002f296918153c55dca674b3d70a54485f00306 (patch) | |
| tree | e3ab47ee263fb29c865c74c6f97ba164b0dd0351 /Source/Android | |
| parent | 0dd601577d20140b78fe2fddf0382d91ec97eeff (diff) | |
Android: Show input indicators in controller settings
Diffstat (limited to 'Source/Android')
10 files changed, 218 insertions, 25 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.kt index 80771a6f4b..017bc1e642 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.kt @@ -2,13 +2,15 @@ package org.dolphinemu.dolphinemu.features.input.ui +import android.view.View import androidx.lifecycle.Lifecycle import org.dolphinemu.dolphinemu.databinding.ListItemAdvancedMappingControlBinding import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface import org.dolphinemu.dolphinemu.features.input.model.CoreDevice import org.dolphinemu.dolphinemu.utils.LifecycleViewHolder -import org.dolphinemu.dolphinemu.utils.Log +import java.text.DecimalFormat import java.util.function.Consumer +import kotlin.math.abs class AdvancedMappingControlViewHolder( private val binding: ListItemAdvancedMappingControlBinding, @@ -19,12 +21,16 @@ class AdvancedMappingControlViewHolder( private lateinit var control: CoreDevice.Control + private var previousState = Float.POSITIVE_INFINITY + init { binding.root.setOnClickListener { onClickCallback.accept(control.getName()) } if (isInput) { ControllerInterface.inputStateChanged.observe(this) { updateInputValue() } + } else { + binding.layoutState.visibility = View.GONE } } @@ -41,8 +47,23 @@ class AdvancedMappingControlViewHolder( throw IllegalStateException("AdvancedMappingControlViewHolder leak") } - // TODO - Log.info("AdvancedMappingControlViewHolder: Value of " + control.getName() + " is " + - control.getState()) + var state = control.getState().toFloat() + if (abs(state - previousState) >= stateUpdateThreshold) { + previousState = state + + // Don't print a minus sign for signed zeroes + if (state == -0.0f) + state = 0.0f + + binding.textState.setText(stateFormat.format(state)) + binding.controlStateBar.state = state + } + } + + companion object { + private val stateFormat = DecimalFormat("#.####") + + // For performance, require state to change by a certain threshold before we update the UI + private val stateUpdateThreshold = 0.00005f } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarHorizontal.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarHorizontal.kt new file mode 100644 index 0000000000..a7a02921e8 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarHorizontal.kt @@ -0,0 +1,25 @@ +package org.dolphinemu.dolphinemu.features.input.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import org.dolphinemu.dolphinemu.databinding.ViewControlStateBarHorizontalBinding + +class ControlStateBarHorizontal @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + private val binding = + ViewControlStateBarHorizontalBinding.inflate(LayoutInflater.from(context), this) + + private val impl = ControlStateBarImpl(binding.viewFilled, binding.viewUnfilled) + + var state: Float + get() = impl.state + set(value) { + impl.state = value + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarImpl.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarImpl.kt new file mode 100644 index 0000000000..027448b0e3 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarImpl.kt @@ -0,0 +1,28 @@ +package org.dolphinemu.dolphinemu.features.input.ui + +import android.view.View +import android.widget.LinearLayout +import androidx.core.math.MathUtils + +class ControlStateBarImpl(private val filledView: View, private val unfilledView: View) { + private var _state = 0.0f + + var state: Float + get() = _state + set(value) { + val clampedState = MathUtils.clamp(value, 0.0f, 1.0f) + if (clampedState != _state) { + setLinearLayoutWeight(filledView, clampedState) + setLinearLayoutWeight(unfilledView, 1.0f - clampedState) + } + _state = clampedState + } + + companion object { + private fun setLinearLayoutWeight(view: View, weight: Float) { + val layoutParams = view.layoutParams as LinearLayout.LayoutParams + layoutParams.weight = weight + view.layoutParams = layoutParams + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarVertical.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarVertical.kt new file mode 100644 index 0000000000..cb7c37ad70 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ControlStateBarVertical.kt @@ -0,0 +1,30 @@ +package org.dolphinemu.dolphinemu.features.input.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import org.dolphinemu.dolphinemu.databinding.ViewControlStateBarVerticalBinding + +class ControlStateBarVertical @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + init { + // Setting this in the XML file has no effect for some reason + orientation = VERTICAL + } + + private val binding = + ViewControlStateBarVerticalBinding.inflate(LayoutInflater.from(context), this) + + private val impl = ControlStateBarImpl(binding.viewFilled, binding.viewUnfilled) + + var state: Float + get() = impl.state + set(value) { + impl.state = value + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.kt index b6b30da53d..312fc9f6a5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.kt @@ -10,14 +10,17 @@ import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSe import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SettingViewHolder -import org.dolphinemu.dolphinemu.utils.Log +import kotlin.math.abs class InputMappingControlSettingViewHolder( private val binding: ListItemMappingBinding, adapter: SettingsAdapter ) : SettingViewHolder(binding.getRoot(), adapter) { + lateinit var setting: InputMappingControlSetting + private var previousState = Float.POSITIVE_INFINITY + init { ControllerInterface.inputStateChanged.observe(this) { updateInputValue() @@ -34,6 +37,10 @@ class InputMappingControlSettingViewHolder( binding.textSettingDescription.text = setting.value binding.buttonAdvancedSettings.setOnClickListener { clicked: View -> onLongClick(clicked) } + if (!setting.isInput) { + binding.controlStateBar.visibility = View.INVISIBLE + } + setStyle(binding.textSettingName, setting) updateInputValue() } @@ -69,9 +76,16 @@ class InputMappingControlSettingViewHolder( } if (setting.isInput) { - // TODO - Log.info("InputMappingControlSettingViewHolder: Value of " + setting.name + " is " + - setting.state) + val state = setting.state.toFloat() + if (abs(state - previousState) >= stateUpdateThreshold) { + previousState = state + binding.controlStateBar.state = state + } } } + + companion object { + // For performance, require state to change by a certain threshold before we update the UI + private val stateUpdateThreshold = 0.01f + } } diff --git a/Source/Android/app/src/main/res/layout-ldrtl/list_item_mapping.xml b/Source/Android/app/src/main/res/layout-ldrtl/list_item_mapping.xml index 94f219b4c1..e1a2118b36 100644 --- a/Source/Android/app/src/main/res/layout-ldrtl/list_item_mapping.xml +++ b/Source/Android/app/src/main/res/layout-ldrtl/list_item_mapping.xml @@ -22,7 +22,7 @@ android:layout_marginTop="@dimen/spacing_large" android:textSize="16sp" android:textAlignment="viewStart" - android:layout_toStartOf="@+id/button_advanced_settings" + android:layout_toStartOf="@id/control_state_bar" tools:text="Setting Name" /> <TextView @@ -30,16 +30,23 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentStart="true" - android:layout_alignStart="@+id/text_setting_name" - android:layout_below="@+id/text_setting_name" + android:layout_alignStart="@id/text_setting_name" + android:layout_below="@id/text_setting_name" android:layout_marginBottom="@dimen/spacing_large" android:layout_marginEnd="@dimen/spacing_large" android:layout_marginStart="@dimen/spacing_large" android:layout_marginTop="@dimen/spacing_small" - android:layout_toStartOf="@+id/button_advanced_settings" + android:layout_toStartOf="@id/control_state_bar" android:textAlignment="viewStart" tools:text="@string/overclock_enable_description" /> + <org.dolphinemu.dolphinemu.features.input.ui.ControlStateBarVertical + android:id="@+id/control_state_bar" + android:layout_width="4dp" + android:layout_height="16dp" + android:layout_centerVertical="true" + android:layout_toStartOf="@id/button_advanced_settings" /> + <Button android:id="@+id/button_advanced_settings" style="?attr/materialIconButtonStyle" diff --git a/Source/Android/app/src/main/res/layout/list_item_advanced_mapping_control.xml b/Source/Android/app/src/main/res/layout/list_item_advanced_mapping_control.xml index b5ea979a09..5f4515a53e 100644 --- a/Source/Android/app/src/main/res/layout/list_item_advanced_mapping_control.xml +++ b/Source/Android/app/src/main/res/layout/list_item_advanced_mapping_control.xml @@ -1,27 +1,48 @@ <?xml version="1.0" encoding="utf-8"?> -<RelativeLayout +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + android:orientation="horizontal" android:minHeight="54dp" android:background="?android:attr/selectableItemBackground" android:focusable="true" android:clickable="true"> <TextView - android:layout_width="match_parent" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_weight="2" style="@style/TextAppearance.MaterialComponents.Headline5" tools:text="Button A" - android:layout_alignParentEnd="true" - android:layout_alignParentStart="true" - android:layout_alignParentTop="true" - android:layout_marginStart="@dimen/spacing_large" - android:layout_marginEnd="@dimen/spacing_large" - android:layout_marginTop="@dimen/spacing_large" + android:padding="@dimen/spacing_large" android:id="@+id/text_name" android:textAlignment="viewStart" android:textSize="16sp" /> -</RelativeLayout> + <FrameLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:id="@+id/layout_state"> + + <org.dolphinemu.dolphinemu.features.input.ui.ControlStateBarHorizontal + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/control_state_bar" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal|center_vertical" + style="@style/TextAppearance.MaterialComponents.Headline5" + tools:text="0.1234" + android:padding="@dimen/spacing_large" + android:id="@+id/text_state" + android:textAlignment="center" + android:textSize="16sp" /> + + </FrameLayout> + +</LinearLayout> diff --git a/Source/Android/app/src/main/res/layout/list_item_mapping.xml b/Source/Android/app/src/main/res/layout/list_item_mapping.xml index de504d3187..30b9e56fb1 100644 --- a/Source/Android/app/src/main/res/layout/list_item_mapping.xml +++ b/Source/Android/app/src/main/res/layout/list_item_mapping.xml @@ -22,7 +22,7 @@ android:layout_marginTop="@dimen/spacing_large" android:textSize="16sp" android:textAlignment="viewStart" - android:layout_toStartOf="@+id/button_advanced_settings" + android:layout_toStartOf="@id/control_state_bar" tools:text="Setting Name" /> <TextView @@ -30,16 +30,23 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentStart="true" - android:layout_alignStart="@+id/text_setting_name" - android:layout_below="@+id/text_setting_name" + android:layout_alignStart="@id/text_setting_name" + android:layout_below="@id/text_setting_name" android:layout_marginBottom="@dimen/spacing_large" android:layout_marginEnd="@dimen/spacing_large" android:layout_marginStart="@dimen/spacing_large" android:layout_marginTop="@dimen/spacing_small" - android:layout_toStartOf="@+id/button_advanced_settings" + android:layout_toStartOf="@id/control_state_bar" android:textAlignment="viewStart" tools:text="@string/overclock_enable_description" /> + <org.dolphinemu.dolphinemu.features.input.ui.ControlStateBarVertical + android:id="@+id/control_state_bar" + android:layout_width="4dp" + android:layout_height="16dp" + android:layout_centerVertical="true" + android:layout_toStartOf="@id/button_advanced_settings" /> + <Button android:id="@+id/button_advanced_settings" style="?attr/materialIconButtonStyle" diff --git a/Source/Android/app/src/main/res/layout/view_control_state_bar_horizontal.xml b/Source/Android/app/src/main/res/layout/view_control_state_bar_horizontal.xml new file mode 100644 index 0000000000..bf252725ff --- /dev/null +++ b/Source/Android/app/src/main/res/layout/view_control_state_bar_horizontal.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:parentTag="LinearLayout"> + + <View + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="0" + android:id="@+id/view_filled" + android:background="@color/dolphin_errorContainer" /> + + <View + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:id="@+id/view_unfilled" /> + +</merge> diff --git a/Source/Android/app/src/main/res/layout/view_control_state_bar_vertical.xml b/Source/Android/app/src/main/res/layout/view_control_state_bar_vertical.xml new file mode 100644 index 0000000000..2063df22b4 --- /dev/null +++ b/Source/Android/app/src/main/res/layout/view_control_state_bar_vertical.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:parentTag="LinearLayout"> + + <View + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:id="@+id/view_unfilled" /> + + <View + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="0" + android:id="@+id/view_filled" + android:background="@color/dolphin_error" /> + +</merge> |
