summaryrefslogtreecommitdiff
path: root/src/android
diff options
context:
space:
mode:
authorGravatar Charles Lombardo2023-03-24 03:18:19 -0400
committerGravatar bunnei2023-06-03 00:05:47 -0700
commitb0a434b99fbfa9052ad44b15a70c4fef99aff1e3 (patch)
treeea64daea6849b5850ca5e0adc2f15d267308f971 /src/android
parentandroid: Fix popup menu going out of bounds (diff)
downloadyuzu-b0a434b99fbfa9052ad44b15a70c4fef99aff1e3.tar.gz
yuzu-b0a434b99fbfa9052ad44b15a70c4fef99aff1e3.tar.xz
yuzu-b0a434b99fbfa9052ad44b15a70c4fef99aff1e3.zip
android: Re-implement overlay editing
Diffstat (limited to 'src/android')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt113
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt48
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt36
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt72
5 files changed, 245 insertions, 25 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 4ba283ddd..18517bdf8 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -90,7 +90,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
90 binding.doneControlConfig.setOnClickListener { stopConfiguringControls() } 90 binding.doneControlConfig.setOnClickListener { stopConfiguringControls() }
91 91
92 // Setup overlay. 92 // Setup overlay.
93 resetInputOverlay()
94 updateShowFpsOverlay() 93 updateShowFpsOverlay()
95 94
96 binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text = 95 binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
index acd4a1fe2..97e0ba3df 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
@@ -45,9 +45,15 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
45 private val overlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet() 45 private val overlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet()
46 private val overlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet() 46 private val overlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet()
47 private val overlayJoysticks: MutableSet<InputOverlayDrawableJoystick> = HashSet() 47 private val overlayJoysticks: MutableSet<InputOverlayDrawableJoystick> = HashSet()
48
48 private var inEditMode = false 49 private var inEditMode = false
50 private var buttonBeingConfigured: InputOverlayDrawableButton? = null
51 private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
52 private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
53
49 private val preferences: SharedPreferences = 54 private val preferences: SharedPreferences =
50 PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) 55 PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
56
51 private val gyro = FloatArray(3) 57 private val gyro = FloatArray(3)
52 private val accel = FloatArray(3) 58 private val accel = FloatArray(3)
53 private var motionTimestamp: Long = 0 59 private var motionTimestamp: Long = 0
@@ -114,7 +120,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
114 } 120 }
115 NativeLibrary.onGamePadButtonEvent( 121 NativeLibrary.onGamePadButtonEvent(
116 NativeLibrary.Player1Device, 122 NativeLibrary.Player1Device,
117 button.id, 123 button.buttonId,
118 button.status 124 button.status
119 ) 125 )
120 shouldUpdateView = true 126 shouldUpdateView = true
@@ -224,8 +230,109 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
224 return false 230 return false
225 } 231 }
226 232
227 private fun onTouchWhileEditing(event: MotionEvent?): Boolean { 233 private fun onTouchWhileEditing(event: MotionEvent): Boolean {
228 // TODO: Reimplement this 234 val pointerIndex = event.actionIndex
235 val fingerPositionX = event.getX(pointerIndex).toInt()
236 val fingerPositionY = event.getY(pointerIndex).toInt()
237
238 // TODO: Provide support for portrait layout
239 //val orientation =
240 // if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) "-Portrait" else ""
241
242 for (button in overlayButtons) {
243 // Determine the button state to apply based on the MotionEvent action flag.
244 when (event.action and MotionEvent.ACTION_MASK) {
245 MotionEvent.ACTION_DOWN,
246 MotionEvent.ACTION_POINTER_DOWN ->
247 // If no button is being moved now, remember the currently touched button to move.
248 if (buttonBeingConfigured == null &&
249 button.bounds.contains(
250 fingerPositionX,
251 fingerPositionY
252 )
253 ) {
254 buttonBeingConfigured = button
255 buttonBeingConfigured!!.onConfigureTouch(event)
256 }
257 MotionEvent.ACTION_MOVE -> if (buttonBeingConfigured != null) {
258 buttonBeingConfigured!!.onConfigureTouch(event)
259 invalidate()
260 return true
261 }
262 MotionEvent.ACTION_UP,
263 MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) {
264 // Persist button position by saving new place.
265 saveControlPosition(
266 buttonBeingConfigured!!.buttonId,
267 buttonBeingConfigured!!.bounds.centerX(),
268 buttonBeingConfigured!!.bounds.centerY(),
269 ""
270 )
271 buttonBeingConfigured = null
272 }
273 }
274 }
275
276 for (dpad in overlayDpads) {
277 // Determine the button state to apply based on the MotionEvent action flag.
278 when (event.action and MotionEvent.ACTION_MASK) {
279 MotionEvent.ACTION_DOWN,
280 MotionEvent.ACTION_POINTER_DOWN ->
281 // If no button is being moved now, remember the currently touched button to move.
282 if (buttonBeingConfigured == null &&
283 dpad.bounds.contains(fingerPositionX, fingerPositionY)
284 ) {
285 dpadBeingConfigured = dpad
286 dpadBeingConfigured!!.onConfigureTouch(event)
287 }
288 MotionEvent.ACTION_MOVE -> if (dpadBeingConfigured != null) {
289 dpadBeingConfigured!!.onConfigureTouch(event)
290 invalidate()
291 return true
292 }
293 MotionEvent.ACTION_UP,
294 MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) {
295 // Persist button position by saving new place.
296 saveControlPosition(
297 dpadBeingConfigured!!.upId,
298 dpadBeingConfigured!!.bounds.centerX(),
299 dpadBeingConfigured!!.bounds.centerY(),
300 ""
301 )
302 dpadBeingConfigured = null
303 }
304 }
305 }
306
307 for (joystick in overlayJoysticks) {
308 when (event.action) {
309 MotionEvent.ACTION_DOWN,
310 MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null &&
311 joystick.bounds.contains(
312 fingerPositionX,
313 fingerPositionY
314 )
315 ) {
316 joystickBeingConfigured = joystick
317 joystickBeingConfigured!!.onConfigureTouch(event)
318 }
319 MotionEvent.ACTION_MOVE -> if (joystickBeingConfigured != null) {
320 joystickBeingConfigured!!.onConfigureTouch(event)
321 invalidate()
322 }
323 MotionEvent.ACTION_UP,
324 MotionEvent.ACTION_POINTER_UP -> if (joystickBeingConfigured != null) {
325 saveControlPosition(
326 joystickBeingConfigured!!.buttonId,
327 joystickBeingConfigured!!.bounds.centerX(),
328 joystickBeingConfigured!!.bounds.centerY(),
329 ""
330 )
331 joystickBeingConfigured = null
332 }
333 }
334 }
335
229 return true 336 return true
230 } 337 }
231 338
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt
index bf0c2f3e6..99d7d9521 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt
@@ -24,32 +24,30 @@ class InputOverlayDrawableButton(
24 res: Resources, 24 res: Resources,
25 defaultStateBitmap: Bitmap, 25 defaultStateBitmap: Bitmap,
26 pressedStateBitmap: Bitmap, 26 pressedStateBitmap: Bitmap,
27 buttonId: Int 27 val buttonId: Int
28) { 28) {
29 /**
30 * Gets this InputOverlayDrawableButton's button ID.
31 *
32 * @return this InputOverlayDrawableButton's button ID.
33 */
34 // The ID value what type of button this Drawable represents.
35 val id: Int
36
37 // The ID value what motion event is tracking 29 // The ID value what motion event is tracking
38 var trackId: Int 30 var trackId: Int
39 31
40 // The drawable position on the screen 32 // The drawable position on the screen
41 private var buttonPositionX = 0 33 private var buttonPositionX = 0
42 private var buttonPositionY = 0 34 private var buttonPositionY = 0
35
43 val width: Int 36 val width: Int
44 val height: Int 37 val height: Int
38
45 private val defaultStateBitmap: BitmapDrawable 39 private val defaultStateBitmap: BitmapDrawable
46 private val pressedStateBitmap: BitmapDrawable 40 private val pressedStateBitmap: BitmapDrawable
47 private var pressedState = false 41 private var pressedState = false
48 42
43 private var previousTouchX = 0
44 private var previousTouchY = 0
45 var controlPositionX = 0
46 var controlPositionY = 0
47
49 init { 48 init {
50 this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap) 49 this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap)
51 this.pressedStateBitmap = BitmapDrawable(res, pressedStateBitmap) 50 this.pressedStateBitmap = BitmapDrawable(res, pressedStateBitmap)
52 id = buttonId
53 trackId = -1 51 trackId = -1
54 width = this.defaultStateBitmap.intrinsicWidth 52 width = this.defaultStateBitmap.intrinsicWidth
55 height = this.defaultStateBitmap.intrinsicHeight 53 height = this.defaultStateBitmap.intrinsicHeight
@@ -104,6 +102,34 @@ class InputOverlayDrawableButton(
104 private val currentStateBitmapDrawable: BitmapDrawable 102 private val currentStateBitmapDrawable: BitmapDrawable
105 get() = if (pressedState) pressedStateBitmap else defaultStateBitmap 103 get() = if (pressedState) pressedStateBitmap else defaultStateBitmap
106 104
105 fun onConfigureTouch(event: MotionEvent): Boolean {
106 val pointerIndex = event.actionIndex
107 val fingerPositionX = event.getX(pointerIndex).toInt()
108 val fingerPositionY = event.getY(pointerIndex).toInt()
109
110 when (event.action) {
111 MotionEvent.ACTION_DOWN -> {
112 previousTouchX = fingerPositionX
113 previousTouchY = fingerPositionY
114 controlPositionX = fingerPositionX - (width / 2)
115 controlPositionY = fingerPositionY - (height / 2)
116 }
117 MotionEvent.ACTION_MOVE -> {
118 controlPositionX += fingerPositionX - previousTouchX
119 controlPositionY += fingerPositionY - previousTouchY
120 setBounds(
121 controlPositionX,
122 controlPositionY,
123 width + controlPositionX,
124 height + controlPositionY
125 )
126 previousTouchX = fingerPositionX
127 previousTouchY = fingerPositionY
128 }
129 }
130 return true
131 }
132
107 fun setBounds(left: Int, top: Int, right: Int, bottom: Int) { 133 fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
108 defaultStateBitmap.setBounds(left, top, right, bottom) 134 defaultStateBitmap.setBounds(left, top, right, bottom)
109 pressedStateBitmap.setBounds(left, top, right, bottom) 135 pressedStateBitmap.setBounds(left, top, right, bottom)
@@ -111,6 +137,6 @@ class InputOverlayDrawableButton(
111 137
112 val status: Int 138 val status: Int
113 get() = if (pressedState) ButtonState.PRESSED else ButtonState.RELEASED 139 get() = if (pressedState) ButtonState.PRESSED else ButtonState.RELEASED
114 private val bounds: Rect 140 val bounds: Rect
115 get() = defaultStateBitmap.bounds 141 get() = defaultStateBitmap.bounds
116} 142}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt
index 34d18eb1d..625cad661 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt
@@ -45,13 +45,19 @@ class InputOverlayDrawableDpad(
45 val leftId: Int 45 val leftId: Int
46 val rightId: Int 46 val rightId: Int
47 var trackId: Int 47 var trackId: Int
48 private var controlPositionX = 0 48
49 private var controlPositionY = 0
50 val width: Int 49 val width: Int
51 val height: Int 50 val height: Int
51
52 private val defaultStateBitmap: BitmapDrawable 52 private val defaultStateBitmap: BitmapDrawable
53 private val pressedOneDirectionStateBitmap: BitmapDrawable 53 private val pressedOneDirectionStateBitmap: BitmapDrawable
54 private val pressedTwoDirectionsStateBitmap: BitmapDrawable 54 private val pressedTwoDirectionsStateBitmap: BitmapDrawable
55
56 private var previousTouchX = 0
57 private var previousTouchY = 0
58 private var controlPositionX = 0
59 private var controlPositionY = 0
60
55 private var upButtonState = false 61 private var upButtonState = false
56 private var downButtonState = false 62 private var downButtonState = false
57 private var leftButtonState = false 63 private var leftButtonState = false
@@ -215,6 +221,32 @@ class InputOverlayDrawableDpad(
215 val rightStatus: Int 221 val rightStatus: Int
216 get() = if (rightButtonState) ButtonState.PRESSED else ButtonState.RELEASED 222 get() = if (rightButtonState) ButtonState.PRESSED else ButtonState.RELEASED
217 223
224 fun onConfigureTouch(event: MotionEvent): Boolean {
225 val pointerIndex = event.actionIndex
226 val fingerPositionX = event.getX(pointerIndex).toInt()
227 val fingerPositionY = event.getY(pointerIndex).toInt()
228
229 when (event.action) {
230 MotionEvent.ACTION_DOWN -> {
231 previousTouchX = fingerPositionX
232 previousTouchY = fingerPositionY
233 }
234 MotionEvent.ACTION_MOVE -> {
235 controlPositionX += fingerPositionX - previousTouchX
236 controlPositionY += fingerPositionY - previousTouchY
237 setBounds(
238 controlPositionX,
239 controlPositionY,
240 width + controlPositionX,
241 height + controlPositionY
242 )
243 previousTouchX = fingerPositionX
244 previousTouchY = fingerPositionY
245 }
246 }
247 return true
248 }
249
218 fun setPosition(x: Int, y: Int) { 250 fun setPosition(x: Int, y: Int) {
219 controlPositionX = x 251 controlPositionX = x
220 controlPositionY = y 252 controlPositionY = y
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
index 11ab0b829..1960eaff0 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
@@ -39,31 +39,39 @@ class InputOverlayDrawableJoystick(
39 val joystickId: Int, 39 val joystickId: Int,
40 val buttonId: Int 40 val buttonId: Int
41) { 41) {
42
43 // The ID value what motion event is tracking 42 // The ID value what motion event is tracking
44 var trackId = -1 43 var trackId = -1
44
45 var xAxis = 0f 45 var xAxis = 0f
46 private var yAxis = 0f 46 private var yAxis = 0f
47 private var controlPositionX = 0 47
48 private var controlPositionY = 0
49 val width: Int 48 val width: Int
50 val height: Int 49 val height: Int
50
51 private var virtBounds: Rect 51 private var virtBounds: Rect
52 private val origBounds: Rect 52 private var origBounds: Rect
53
53 private val outerBitmap: BitmapDrawable 54 private val outerBitmap: BitmapDrawable
54 private val defaultStateInnerBitmap: BitmapDrawable 55 private val defaultStateInnerBitmap: BitmapDrawable
55 private val pressedStateInnerBitmap: BitmapDrawable 56 private val pressedStateInnerBitmap: BitmapDrawable
57
58 private var previousTouchX = 0
59 private var previousTouchY = 0
60 var controlPositionX = 0
61 var controlPositionY = 0
62
56 private val boundsBoxBitmap: BitmapDrawable 63 private val boundsBoxBitmap: BitmapDrawable
64
57 private var pressedState = false 65 private var pressedState = false
58 66
59 // TODO: Add button support 67 // TODO: Add button support
60 val buttonStatus: Int 68 val buttonStatus: Int
61 get() = 69 get() =
62 NativeLibrary.ButtonState.RELEASED 70 NativeLibrary.ButtonState.RELEASED
63 var bounds: Rect? 71 var bounds: Rect
64 get() = outerBitmap.bounds 72 get() = outerBitmap.bounds
65 set(bounds) { 73 set(bounds) {
66 outerBitmap.bounds = bounds!! 74 outerBitmap.bounds = bounds
67 } 75 }
68 76
69 // Nintendo joysticks have y axis inverted 77 // Nintendo joysticks have y axis inverted
@@ -83,7 +91,7 @@ class InputOverlayDrawableJoystick(
83 bounds = rectOuter 91 bounds = rectOuter
84 defaultStateInnerBitmap.bounds = rectInner 92 defaultStateInnerBitmap.bounds = rectInner
85 pressedStateInnerBitmap.bounds = rectInner 93 pressedStateInnerBitmap.bounds = rectInner
86 virtBounds = bounds!! 94 virtBounds = bounds
87 origBounds = outerBitmap.copyBounds() 95 origBounds = outerBitmap.copyBounds()
88 boundsBoxBitmap.alpha = 0 96 boundsBoxBitmap.alpha = 0
89 boundsBoxBitmap.bounds = virtBounds 97 boundsBoxBitmap.bounds = virtBounds
@@ -106,8 +114,9 @@ class InputOverlayDrawableJoystick(
106 motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN 114 motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN
107 val isActionUp = 115 val isActionUp =
108 motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP 116 motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP
117
109 if (isActionDown) { 118 if (isActionDown) {
110 if (!bounds!!.contains(xPosition, yPosition)) { 119 if (!bounds.contains(xPosition, yPosition)) {
111 return false 120 return false
112 } 121 }
113 pressedState = true 122 pressedState = true
@@ -122,6 +131,7 @@ class InputOverlayDrawableJoystick(
122 boundsBoxBitmap.bounds = virtBounds 131 boundsBoxBitmap.bounds = virtBounds
123 trackId = pointerId 132 trackId = pointerId
124 } 133 }
134
125 if (isActionUp) { 135 if (isActionUp) {
126 if (trackId != pointerId) { 136 if (trackId != pointerId) {
127 return false 137 return false
@@ -147,7 +157,9 @@ class InputOverlayDrawableJoystick(
147 trackId = -1 157 trackId = -1
148 return true 158 return true
149 } 159 }
160
150 if (trackId == -1) return false 161 if (trackId == -1) return false
162
151 for (i in 0 until event.pointerCount) { 163 for (i in 0 until event.pointerCount) {
152 if (trackId != event.getPointerId(i)) { 164 if (trackId != event.getPointerId(i)) {
153 continue 165 continue
@@ -179,6 +191,50 @@ class InputOverlayDrawableJoystick(
179 return false 191 return false
180 } 192 }
181 193
194 fun onConfigureTouch(event: MotionEvent): Boolean {
195 val pointerIndex = event.actionIndex
196 val fingerPositionX = event.getX(pointerIndex).toInt()
197 val fingerPositionY = event.getY(pointerIndex).toInt()
198
199 when (event.action) {
200 MotionEvent.ACTION_DOWN -> {
201 previousTouchX = fingerPositionX
202 previousTouchY = fingerPositionY
203 controlPositionX = fingerPositionX - (width / 2)
204 controlPositionY = fingerPositionY - (height / 2)
205 }
206 MotionEvent.ACTION_MOVE -> {
207 controlPositionX += fingerPositionX - previousTouchX
208 controlPositionY += fingerPositionY - previousTouchY
209 bounds = Rect(
210 controlPositionX,
211 controlPositionY,
212 outerBitmap.intrinsicWidth + controlPositionX,
213 outerBitmap.intrinsicHeight + controlPositionY
214 )
215 virtBounds = Rect(
216 controlPositionX,
217 controlPositionY,
218 outerBitmap.intrinsicWidth + controlPositionX,
219 outerBitmap.intrinsicHeight + controlPositionY
220 )
221 setInnerBounds()
222 bounds = Rect(
223 Rect(
224 controlPositionX,
225 controlPositionY,
226 outerBitmap.intrinsicWidth + controlPositionX,
227 outerBitmap.intrinsicHeight + controlPositionY
228 )
229 )
230 previousTouchX = fingerPositionX
231 previousTouchY = fingerPositionY
232 }
233 }
234 origBounds = outerBitmap.copyBounds()
235 return true
236 }
237
182 private fun setInnerBounds() { 238 private fun setInnerBounds() {
183 var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt() 239 var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt()
184 var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt() 240 var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt()