Skip to content

Commit

Permalink
Add color selection to OSC
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
KikiManjaro authored and nickbeth committed Mar 5, 2023
1 parent 66d2965 commit 1282362
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 40 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
38 changes: 28 additions & 10 deletions app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
/**
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -32,6 +37,8 @@ class ControllerConfigurationImpl(private val context : Context, private val but
private inline fun <reified T> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
}
}
}

Expand All @@ -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<Pair<Int, () -> 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<Int, FloatingActionButton>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
25 changes: 25 additions & 0 deletions app/src/main/java/emu/skyline/utils/Colors.kt
Original file line number Diff line number Diff line change
@@ -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 }
}
}
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_palette.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z" />
</vector>
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@
<string name="osc_feedback">Enable Haptic Feedback</string>
<string name="osc_feedback_description">Excludes joysticks and hardware controls</string>
<string name="osc_edit">Edit On-Screen Controls layout</string>
<string name="osc_text_color">Text color</string>
<string name="osc_background_color">Background color</string>
<string name="setup_guide">Setup Guide</string>
<string name="setup_guide_description">Sequentially map every stick and button</string>
<string name="joystick">Joystick</string>
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ buildscript {
repositories {
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}

dependencies {
Expand All @@ -28,6 +29,7 @@ allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}
}

Expand Down

0 comments on commit 1282362

Please sign in to comment.