Browse Source
[android] input over(lay)haul 2: Individual scaling of buttons (#2562)
[android] input over(lay)haul 2: Individual scaling of buttons (#2562)
### (Needs testing) This PR makes it possible to adjust the scale of each touch input overlay button independently from the global scale This individual value always goes on top of the global scale. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2562 Co-authored-by: nyx <contact@innix.space> Co-committed-by: nyx <contact@innix.space>pull/2606/head
committed by
crueter
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
15 changed files with 506 additions and 77 deletions
-
2src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
-
255src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
-
6src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt
-
6src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
-
124src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/OverlayScaleDialog.kt
-
61src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt
-
7src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt
-
7src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
-
6src/android/app/src/main/jni/android_config.cpp
-
1src/android/app/src/main/jni/android_settings.h
-
13src/android/app/src/main/jni/native_config.cpp
-
74src/android/app/src/main/res/layout/dialog_overlay_scale.xml
-
1src/android/app/src/main/res/values/strings.xml
-
14src/common/android/id_cache.cpp
-
6src/common/android/id_cache.h
@ -0,0 +1,124 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-3.0-or-later |
||||
|
|
||||
|
package org.yuzu.yuzu_emu.overlay |
||||
|
|
||||
|
import android.app.Dialog |
||||
|
import android.content.Context |
||||
|
import android.view.Gravity |
||||
|
import android.view.LayoutInflater |
||||
|
import android.view.WindowManager |
||||
|
import android.widget.TextView |
||||
|
import com.google.android.material.button.MaterialButton |
||||
|
import com.google.android.material.slider.Slider |
||||
|
import org.yuzu.yuzu_emu.R |
||||
|
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData |
||||
|
|
||||
|
class OverlayScaleDialog( |
||||
|
context: Context, |
||||
|
private val overlayControlData: OverlayControlData, |
||||
|
private val onScaleChanged: (Float) -> Unit |
||||
|
) : Dialog(context) { |
||||
|
|
||||
|
private var currentScale = overlayControlData.individualScale |
||||
|
private val originalScale = overlayControlData.individualScale |
||||
|
private lateinit var scaleValueText: TextView |
||||
|
private lateinit var scaleSlider: Slider |
||||
|
|
||||
|
init { |
||||
|
setupDialog() |
||||
|
} |
||||
|
|
||||
|
private fun setupDialog() { |
||||
|
val view = LayoutInflater.from(context).inflate(R.layout.dialog_overlay_scale, null) |
||||
|
setContentView(view) |
||||
|
|
||||
|
window?.setBackgroundDrawable(null) |
||||
|
|
||||
|
window?.apply { |
||||
|
attributes = attributes.apply { |
||||
|
flags = flags and WindowManager.LayoutParams.FLAG_DIM_BEHIND.inv() |
||||
|
flags = flags or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
scaleValueText = view.findViewById(R.id.scaleValueText) |
||||
|
scaleSlider = view.findViewById(R.id.scaleSlider) |
||||
|
val resetButton = view.findViewById<MaterialButton>(R.id.resetButton) |
||||
|
val confirmButton = view.findViewById<MaterialButton>(R.id.confirmButton) |
||||
|
val cancelButton = view.findViewById<MaterialButton>(R.id.cancelButton) |
||||
|
|
||||
|
scaleValueText.text = String.format("%.1fx", currentScale) |
||||
|
scaleSlider.value = currentScale |
||||
|
|
||||
|
scaleSlider.addOnChangeListener { _, value, input -> |
||||
|
if (input) { |
||||
|
currentScale = value |
||||
|
scaleValueText.text = String.format("%.1fx", currentScale) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
scaleSlider.addOnSliderTouchListener(object : Slider.OnSliderTouchListener { |
||||
|
override fun onStartTrackingTouch(slider: Slider) { |
||||
|
// pass |
||||
|
} |
||||
|
|
||||
|
override fun onStopTrackingTouch(slider: Slider) { |
||||
|
onScaleChanged(currentScale) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
resetButton.setOnClickListener { |
||||
|
currentScale = 1.0f |
||||
|
scaleSlider.value = 1.0f |
||||
|
scaleValueText.text = String.format("%.1fx", currentScale) |
||||
|
onScaleChanged(currentScale) |
||||
|
} |
||||
|
|
||||
|
confirmButton.setOnClickListener { |
||||
|
overlayControlData.individualScale = currentScale |
||||
|
//slider value is already saved on touch dispatch but just to be sure |
||||
|
onScaleChanged(currentScale) |
||||
|
dismiss() |
||||
|
} |
||||
|
|
||||
|
// both cancel button and back gesture should revert the scale change |
||||
|
cancelButton.setOnClickListener { |
||||
|
onScaleChanged(originalScale) |
||||
|
dismiss() |
||||
|
} |
||||
|
|
||||
|
setOnCancelListener { |
||||
|
onScaleChanged(originalScale) |
||||
|
dismiss() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
fun showDialog(anchorX: Int, anchorY: Int, anchorHeight: Int, anchorWidth: Int) { |
||||
|
show() |
||||
|
|
||||
|
show() |
||||
|
|
||||
|
// TODO: this calculation is a bit rough, improve it later on |
||||
|
window?.let { window -> |
||||
|
val layoutParams = window.attributes |
||||
|
layoutParams.gravity = Gravity.TOP or Gravity.START |
||||
|
|
||||
|
val density = context.resources.displayMetrics.density |
||||
|
val dialogWidthPx = (320 * density).toInt() |
||||
|
val dialogHeightPx = (400 * density).toInt() // set your estimated dialog height |
||||
|
|
||||
|
val screenHeight = context.resources.displayMetrics.heightPixels |
||||
|
|
||||
|
|
||||
|
layoutParams.x = anchorX + anchorWidth / 2 - dialogWidthPx / 2 |
||||
|
layoutParams.y = anchorY + anchorHeight / 2 - dialogHeightPx / 2 |
||||
|
layoutParams.width = dialogWidthPx |
||||
|
|
||||
|
|
||||
|
window.attributes = layoutParams |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,74 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
android:layout_width="320dp" |
||||
|
android:layout_height="wrap_content" |
||||
|
app:cardCornerRadius="16dp" |
||||
|
app:cardElevation="8dp" |
||||
|
app:cardBackgroundColor="#CC222222"> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="vertical" |
||||
|
android:padding="12dp"> |
||||
|
|
||||
|
<com.google.android.material.textview.MaterialTextView |
||||
|
android:id="@+id/scaleValueText" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:text="1.0x" |
||||
|
android:textAppearance="?attr/textAppearanceBody1" |
||||
|
android:gravity="center" |
||||
|
android:layout_marginBottom="4dp" |
||||
|
android:textColor="#FFFFFF" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
<com.google.android.material.slider.Slider |
||||
|
android:id="@+id/scaleSlider" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:valueFrom="0.5" |
||||
|
android:valueTo="4.0" |
||||
|
android:stepSize="0.1" |
||||
|
android:value="1.0" |
||||
|
android:layout_marginBottom="8dp" |
||||
|
app:trackColorActive="@color/eden_border_gradient_start" |
||||
|
app:trackColorInactive="@color/eden_border_gradient_end" |
||||
|
app:tickColor="@color/eden_border_gradient_start"/> |
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="horizontal" |
||||
|
android:gravity="end"> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/resetButton" |
||||
|
style="@style/Widget.Material3.Button.TextButton" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:text="@string/reset" |
||||
|
android:layout_marginEnd="4dp" /> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/cancelButton" |
||||
|
style="@style/Widget.Material3.Button.TextButton" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:text="@android:string/cancel" |
||||
|
android:layout_marginEnd="4dp" /> |
||||
|
|
||||
|
<com.google.android.material.button.MaterialButton |
||||
|
android:id="@+id/confirmButton" |
||||
|
style="@style/Widget.Material3.Button" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:backgroundTint="@color/eden_button_secondary_bg" |
||||
|
android:textColor="@color/eden_border_gradient_end" |
||||
|
android:text="@string/confirm" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
</com.google.android.material.card.MaterialCardView> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue