From 1282362fce5c8df8d4ce38d7fdef32ef062257f7 Mon Sep 17 00:00:00 2001 From: KikiManjaro Date: Thu, 4 Aug 2022 01:25:29 +0200 Subject: [PATCH] Add color selection to OSC * Add bold text and antialiasing for osc buttons * Fix osc dpad and button position (widder than taller) * Set default OSC color to white background with black text --- app/build.gradle | 1 + .../skyline/input/onscreen/OnScreenButton.kt | 38 ++++++--- .../input/onscreen/OnScreenConfiguration.kt | 7 ++ .../input/onscreen/OnScreenControllerView.kt | 22 ++++++ .../input/onscreen/OnScreenEditActivity.kt | 78 +++++++++++++------ .../input/onscreen/OnScreenItemDefinitions.kt | 28 +++++-- app/src/main/java/emu/skyline/utils/Colors.kt | 25 ++++++ app/src/main/res/drawable/ic_palette.xml | 10 +++ app/src/main/res/values/strings.xml | 2 + build.gradle | 2 + 10 files changed, 173 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/emu/skyline/utils/Colors.kt create mode 100644 app/src/main/res/drawable/ic_palette.xml diff --git a/app/build.gradle b/app/build.gradle index 0dda02c2..fe3996e6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -184,6 +184,7 @@ dependencies { /* Other Java */ implementation 'info.debatty:java-string-similarity:2.0.0' + implementation 'com.github.KikiManjaro:colorpicker:v1.1.12' } kapt { diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt index 7bd43cfb..1ff87fe3 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt @@ -6,9 +6,12 @@ package emu.skyline.input.onscreen import android.graphics.Canvas -import android.graphics.Color import android.graphics.Paint import android.graphics.Rect +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.graphics.drawable.LayerDrawable import androidx.core.content.ContextCompat import emu.skyline.input.ButtonId import kotlin.math.roundToInt @@ -17,13 +20,13 @@ import kotlin.math.roundToInt * Converts relative values, such as coordinates and boundaries, to their absolute counterparts, also handles layout modifications like scaling and custom positioning */ abstract class OnScreenButton( - onScreenControllerView : OnScreenControllerView, - val buttonId : ButtonId, - private val defaultRelativeX : Float, - private val defaultRelativeY : Float, - private val defaultRelativeWidth : Float, - private val defaultRelativeHeight : Float, - drawableId : Int + onScreenControllerView : OnScreenControllerView, + val buttonId : ButtonId, + private val defaultRelativeX : Float, + private val defaultRelativeY : Float, + private val defaultRelativeWidth : Float, + private val defaultRelativeHeight : Float, + drawableId : Int ) { companion object { /** @@ -37,7 +40,11 @@ abstract class OnScreenButton( protected val drawable = ContextCompat.getDrawable(onScreenControllerView.context, drawableId)!! - private val buttonSymbolPaint = Paint().apply { color = Color.GRAY } + internal val buttonSymbolPaint = Paint().apply { + color = config.textColor + typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD) + isAntiAlias = true + } private val textBoundsRect = Rect() var relativeX = config.relativeX @@ -83,6 +90,7 @@ abstract class OnScreenButton( buttonSymbolPaint.apply { textSize = size textAlign = Paint.Align.LEFT + color = config.textColor this.alpha = alpha getTextBounds(text, 0, text.length, textBoundsRect) } @@ -92,15 +100,25 @@ abstract class OnScreenButton( open fun render(canvas : Canvas) { val bounds = currentBounds val alpha = if (isPressed) (config.alpha - 130).coerceIn(30..255) else config.alpha + renderColors(drawable) drawable.apply { this.bounds = bounds this.alpha = alpha draw(canvas) } - renderCenteredText(canvas, buttonId.short!!, itemWidth.coerceAtMost(itemHeight) * 0.4f, bounds.centerX().toFloat(), bounds.centerY().toFloat(), alpha) } + private fun renderColors(drawable : Drawable) { + when (drawable) { + is GradientDrawable -> drawable.setColor(config.backgroundColor) + is LayerDrawable -> { + for (i in 0 until drawable.numberOfLayers) renderColors(drawable.getDrawable(i)) + } + else -> drawable.setTint(config.backgroundColor) + } + } + abstract fun isTouched(x : Float, y : Float) : Boolean open fun onFingerDown(x : Float, y : Float) { 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 4eae0167..0679c3f8 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt @@ -6,11 +6,14 @@ package emu.skyline.input.onscreen import android.content.Context +import android.graphics.Color import emu.skyline.input.ButtonId import emu.skyline.utils.sharedPreferences interface ControllerConfiguration { var alpha : Int + var textColor : Int + var backgroundColor : Int var enabled : Boolean var globalScale : Float var relativeX : Float @@ -22,6 +25,8 @@ interface ControllerConfiguration { */ class ControllerConfigurationDummy(defaultRelativeX : Float, defaultRelativeY : Float) : ControllerConfiguration { override var alpha : Int = 255 + override var textColor = Color.argb(180, 0, 0, 0) + override var backgroundColor = Color.argb(180, 255, 255, 255) override var enabled = true override var globalScale = 1f override var relativeX = defaultRelativeX @@ -32,6 +37,8 @@ class ControllerConfigurationImpl(private val context : Context, private val but private inline fun config(default : T, prefix : String = "${buttonId.name}_") = sharedPreferences(context, default, prefix, "controller_config") override var alpha by config(255, "") + override var textColor by config(Color.argb(180, 0, 0, 0)) + override var backgroundColor by config(Color.argb(180, 255, 255, 255)) override var enabled by config(true) override var globalScale by config(1.15f, "") override var relativeX by config(defaultRelativeX) 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 52983cab..1459a540 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt @@ -292,6 +292,14 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs invalidate() } + fun getTextColor() : Int { + return controls.globalTextColor + } + + fun getBackGroundColor() : Int { + return controls.globalBackgroundColor + } + fun setOnButtonStateChangedListener(listener : OnButtonStateChangedListener) { onButtonStateChangedListener = listener } @@ -306,4 +314,18 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs controls.allButtons.first { it.buttonId == buttonId }.config.enabled = enabled invalidate() } + + fun setTextColor(color : Int) { + for (button in controls.allButtons) { + button.config.textColor = color + } + invalidate() + } + + fun setBackGroundColor(color : Int) { + for (button in controls.allButtons) { + button.config.backgroundColor = color + } + invalidate() + } } 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 187e5168..53585289 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenEditActivity.kt @@ -16,6 +16,10 @@ import dagger.hilt.android.AndroidEntryPoint import emu.skyline.R import emu.skyline.databinding.OnScreenEditActivityBinding import emu.skyline.settings.AppSettings +import emu.skyline.utils.SwitchColors +import emu.skyline.utils.SwitchColors.* +import petrov.kristiyan.colorpicker.DoubleColorPicker +import petrov.kristiyan.colorpicker.DoubleColorPicker.OnChooseDoubleColorListener import javax.inject.Inject @AndroidEntryPoint @@ -41,10 +45,11 @@ class OnScreenEditActivity : AppCompatActivity() { } private fun toggleFabVisibility(visible : Boolean) { - actions.forEach { - if (it.first != R.drawable.ic_close) - if (visible) fabMapping[it.first]!!.show() - else fabMapping[it.first]!!.hide() + fabMapping.forEach { (id, fab) -> + if (id != R.drawable.ic_close) { + if (visible) fab.show() + else fab.hide() + } } } @@ -59,30 +64,53 @@ class OnScreenEditActivity : AppCompatActivity() { val checkArray = buttonProps.map { it.second }.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]) - } - }.setNegativeButton(R.string.cancel, null) - .setOnDismissListener { fullScreen() } - .show() + .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]) + } + }.setNegativeButton(R.string.cancel, null) + .setOnDismissListener { fullScreen() } + .show() + } + + private val paletteAction : () -> Unit = { + DoubleColorPicker(this@OnScreenEditActivity).apply { + setTitle(this@OnScreenEditActivity.getString(R.string.osc_background_color)) + setDefaultColorButton(binding.onScreenControllerView.getBackGroundColor()) + setRoundColorButton(true) + setColors(*SwitchColors.colors.toIntArray()) + setDefaultDoubleColorButton(binding.onScreenControllerView.getTextColor()) + setSecondTitle(this@OnScreenEditActivity.getString(R.string.osc_text_color)) + setOnChooseDoubleColorListener(object : OnChooseDoubleColorListener { + override fun onChooseColor(position : Int, color : Int, position2 : Int, color2 : Int) { + binding.onScreenControllerView.setBackGroundColor(SwitchColors.colors[position]) + binding.onScreenControllerView.setTextColor(SwitchColors.colors[position2]) + } + + override fun onCancel() {} + }) + show() + } + + } private val actions : List Unit>> = listOf( - Pair(R.drawable.ic_restore, { binding.onScreenControllerView.resetControls() }), - Pair(R.drawable.ic_toggle, toggleAction), - Pair(R.drawable.ic_edit, editAction), - 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() }, - Pair(R.drawable.ic_opacity_plus) { binding.onScreenControllerView.increaseOpacity() }, - Pair(R.drawable.ic_close, closeAction) + 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_zoom_out) { binding.onScreenControllerView.decreaseScale() }, + Pair(R.drawable.ic_zoom_in) { binding.onScreenControllerView.increaseScale() }, + Pair(R.drawable.ic_opacity_minus) { binding.onScreenControllerView.decreaseOpacity() }, + Pair(R.drawable.ic_opacity_plus) { binding.onScreenControllerView.increaseOpacity() }, + Pair(R.drawable.ic_close, closeAction) ) private val fabMapping = mutableMapOf() 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 1eaf077a..1cdc56ee 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt @@ -7,13 +7,15 @@ package emu.skyline.input.onscreen import android.graphics.Canvas import android.graphics.PointF +import android.graphics.Typeface import android.os.SystemClock import androidx.core.graphics.minus import emu.skyline.R import emu.skyline.input.ButtonId import emu.skyline.input.ButtonId.* import emu.skyline.input.StickId -import emu.skyline.input.StickId.* +import emu.skyline.input.StickId.Left +import emu.skyline.input.StickId.Right import emu.skyline.utils.add import emu.skyline.utils.multiply import kotlin.math.roundToInt @@ -65,6 +67,10 @@ class JoystickButton( var shortDoubleTapped = false private set + init { + innerButton.buttonSymbolPaint.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL) + } + override fun renderCenteredText(canvas : Canvas, text : String, size : Float, x : Float, y : Float, alpha : Int) = Unit override fun render(canvas : Canvas) { @@ -193,14 +199,14 @@ class TriggerButton( class Controls(onScreenControllerView : OnScreenControllerView) { private val buttonA = CircularButton(onScreenControllerView, A, 0.95f, 0.65f, 0.025f) - private val buttonB = CircularButton(onScreenControllerView, B, 0.9f, 0.75f, 0.025f) - private val buttonX = CircularButton(onScreenControllerView, X, 0.9f, 0.55f, 0.025f) + private val buttonB = CircularButton(onScreenControllerView, B, 0.9f, 0.765f, 0.025f) + private val buttonX = CircularButton(onScreenControllerView, X, 0.9f, 0.535f, 0.025f) private val buttonY = CircularButton(onScreenControllerView, Y, 0.85f, 0.65f, 0.025f) private val buttonDpadLeft = CircularButton(onScreenControllerView, DpadLeft, 0.2f, 0.65f, 0.025f) - private val buttonDpadUp = CircularButton(onScreenControllerView, DpadUp, 0.25f, 0.55f, 0.025f) + private val buttonDpadUp = CircularButton(onScreenControllerView, DpadUp, 0.25f, 0.535f, 0.025f) private val buttonDpadRight = CircularButton(onScreenControllerView, DpadRight, 0.3f, 0.65f, 0.025f) - private val buttonDpadDown = CircularButton(onScreenControllerView, DpadDown, 0.25f, 0.75f, 0.025f) + private val buttonDpadDown = CircularButton(onScreenControllerView, DpadDown, 0.25f, 0.765f, 0.025f) private val buttonL = RectangularButton(onScreenControllerView, L, 0.1f, 0.25f, 0.09f, 0.1f) private val buttonR = RectangularButton(onScreenControllerView, R, 0.9f, 0.25f, 0.09f, 0.1f) @@ -248,4 +254,16 @@ class Controls(onScreenControllerView : OnScreenControllerView) { set(value) { circularButtons.first().config.alpha = value } + + /** + * We can take any of the global text color variables from the buttons + */ + val globalTextColor + get() = circularButtons.first().config.textColor + + /** + * We can take any of the global background color variables from the buttons + */ + val globalBackgroundColor + get() = circularButtons.first().config.backgroundColor } diff --git a/app/src/main/java/emu/skyline/utils/Colors.kt b/app/src/main/java/emu/skyline/utils/Colors.kt new file mode 100644 index 00000000..9a2b4ad3 --- /dev/null +++ b/app/src/main/java/emu/skyline/utils/Colors.kt @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) + */ + +package emu.skyline.utils + +import android.graphics.Color + +enum class SwitchColors(val color : Int) { + GRAY(Color.GRAY), + TRANSPARENT(Color.argb(180, 0, 0, 0)), + WHITE(Color.argb(180, 255, 255, 255)), + NEON_YELLOW(Color.argb(180, 230, 255, 0)), + NEON_PURPLE(Color.argb(180, 180, 0, 230)), + NEON_RED(Color.argb(180, 255, 60, 40)), + MARIO_RED(Color.argb(180, 225, 15, 0)), + NEON_BLUE(Color.argb(180, 10, 185, 230)), + BLUE(Color.argb(180, 70, 85, 245)), + NEON_GREEN(Color.argb(180, 30, 220, 0)); + + companion object { + val colors = SwitchColors.values().map { clr -> clr.color } + } +} diff --git a/app/src/main/res/drawable/ic_palette.xml b/app/src/main/res/drawable/ic_palette.xml new file mode 100644 index 00000000..c5713a0e --- /dev/null +++ b/app/src/main/res/drawable/ic_palette.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c9cad705..dd8eecfc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -155,6 +155,8 @@ Enable Haptic Feedback Excludes joysticks and hardware controls Edit On-Screen Controls layout + Text color + Background color Setup Guide Sequentially map every stick and button Joystick diff --git a/build.gradle b/build.gradle index fd8787de..74ac91a4 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ buildscript { repositories { google() mavenCentral() + maven { url 'https://www.jitpack.io' } } dependencies { @@ -28,6 +29,7 @@ allprojects { repositories { google() mavenCentral() + maven { url 'https://www.jitpack.io' } } }