Skip to content

Commit b69ca51

Browse files
committed
Introduce REM scaling for UI components dimensions
1 parent b89696a commit b69ca51

40 files changed

+1725
-1261
lines changed

src/com/reco1l/andengine/Initializers.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import com.reco1l.andengine.text.*
77
import com.reco1l.andengine.ui.*
88
import org.anddev.andengine.entity.IEntity
99

10-
1110
inline fun IEntity.text(builder: UIText.() -> Unit): UIText {
1211
return UIText().apply(builder).also(::attachChild)
1312
}
@@ -16,6 +15,10 @@ inline fun IEntity.container(builder: UIContainer.() -> Unit): UIContainer {
1615
return UIContainer().apply(builder).also(::attachChild)
1716
}
1817

18+
inline fun IEntity.clickableContainer(builder: UIClickableContainer.() -> Unit): UIClickableContainer {
19+
return UIClickableContainer().apply(builder).also(::attachChild)
20+
}
21+
1922
inline fun IEntity.linearContainer(builder: UILinearContainer.() -> Unit): UILinearContainer {
2023
return UILinearContainer().apply(builder).also(::attachChild)
2124
}
@@ -24,8 +27,8 @@ inline fun IEntity.constraintContainer(builder: UIConstraintContainer.() -> Unit
2427
return UIConstraintContainer().apply(builder).also(::attachChild)
2528
}
2629

27-
inline fun IEntity.flexContainer(builder: UIFlexContainer.() -> Unit): UIFlexContainer {
28-
return UIFlexContainer().apply(builder).also(::attachChild)
30+
inline fun IEntity.fillContainer(builder: UIFillContainer.() -> Unit): UIFillContainer {
31+
return UIFillContainer().apply(builder).also(::attachChild)
2932
}
3033

3134
inline fun IEntity.scrollableContainer(builder: UIScrollableContainer.() -> Unit): UIScrollableContainer {

src/com/reco1l/andengine/UIEngine.kt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.reco1l.andengine
22

33
import android.app.Activity
4+
import android.util.Log
45
import android.view.*
56
import androidx.core.view.ViewCompat
67
import androidx.core.view.WindowInsetsCompat
78
import com.reco1l.andengine.component.*
89
import com.reco1l.andengine.ui.*
10+
import com.reco1l.framework.math.Vec4
911
import org.anddev.andengine.engine.Engine
1012
import org.anddev.andengine.engine.camera.hud.*
1113
import org.anddev.andengine.engine.options.EngineOptions
@@ -17,6 +19,14 @@ import kotlin.math.*
1719

1820
class UIEngine(val context: Activity, options: EngineOptions) : Engine(options) {
1921

22+
private val displayDensity = context.resources.displayMetrics.density
23+
24+
/**
25+
* The root font size in pixels, adjusted for display density.
26+
*/
27+
val rootFontSize
28+
get() = CSS_BASE_ROOT_FONT_SIZE * displayDensity * fontScale
29+
2030
/**
2131
* The global HUD used for overlays (menus, dialogs, etc).
2232
*/
@@ -27,6 +37,23 @@ class UIEngine(val context: Activity, options: EngineOptions) : Engine(options)
2737
*/
2838
val resources = UIResourceManager(context)
2939

40+
/**
41+
* The safe area insets of the display, in pixels. This is used to avoid placing UI elements in areas that
42+
* may be obscured by notches, rounded corners, etc.
43+
*/
44+
var safeArea = Vec4.Zero
45+
46+
/**
47+
* The current font scale factor. Changing this will scale all UI elements accordingly.
48+
*/
49+
var fontScale = 1f
50+
set(value) {
51+
if (field != value) {
52+
field = value
53+
onThemeChange(Theme.current)
54+
}
55+
}
56+
3057
/**
3158
* The current focused entity.
3259
*/
@@ -58,6 +85,7 @@ class UIEngine(val context: Activity, options: EngineOptions) : Engine(options)
5885
init {
5986
current = this
6087
camera.hud = overlay
88+
Log.i("UI", "Root font size: ${rootFontSize}px")
6189
}
6290

6391

@@ -122,7 +150,7 @@ class UIEngine(val context: Activity, options: EngineOptions) : Engine(options)
122150
fun IEntity.propagateThemeChange() {
123151

124152
if (this is UIComponent) {
125-
onThemeChanged(theme)
153+
onStyle(theme)
126154
}
127155

128156
if (this is Scene) {
@@ -195,6 +223,8 @@ class UIEngine(val context: Activity, options: EngineOptions) : Engine(options)
195223

196224
companion object {
197225

226+
private const val CSS_BASE_ROOT_FONT_SIZE = 16f
227+
198228
@JvmStatic
199229
lateinit var current: UIEngine
200230
private set

src/com/reco1l/andengine/UIScene.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ open class UIScene : Scene(), IShape {
7474
fun IEntity.propagateSkinChanges() {
7575

7676
if (this is UIComponent) {
77-
onThemeChanged(Theme.current)
77+
onStyle(Theme.current)
7878
}
7979

8080
if (this is ISkinnable) {

src/com/reco1l/andengine/component/Components.kt

Lines changed: 40 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.reco1l.andengine.component
22

33
import androidx.annotation.*
4-
import com.reco1l.andengine.component.AttachmentMode.*
4+
import com.reco1l.andengine.container.UIContainer
5+
import com.reco1l.andengine.shape.UIBox
56
import com.reco1l.andengine.text.*
67
import com.reco1l.andengine.ui.*
78
import com.reco1l.framework.*
89
import com.reco1l.framework.math.Vec2
10+
import com.reco1l.framework.math.Vec4
911
import org.anddev.andengine.entity.IEntity
1012
import org.anddev.andengine.entity.scene.CameraScene
1113
import org.anddev.andengine.entity.scene.Scene
@@ -15,113 +17,80 @@ import ru.nsu.ccfit.zuev.osu.helper.StringTable
1517

1618
//region Size related properties
1719

18-
fun IEntity?.getWidth() = when (this) {
19-
is UIComponent -> width
20-
is CameraScene -> camera?.widthRaw ?: 0f
21-
is IShape -> width
22-
is Scene -> Config.getRES_WIDTH().toFloat()
23-
else -> 0f
24-
}
25-
26-
fun IEntity?.getHeight() = when (this) {
27-
is UIComponent -> height
28-
is CameraScene -> camera?.heightRaw ?: 0f
29-
is IShape -> height
30-
is Scene -> Config.getRES_HEIGHT().toFloat()
31-
else -> 0f
32-
}
33-
34-
3520
/**
36-
* The size of the entity.
21+
* @see UIComponent.width
3722
*/
38-
var UIComponent.size: Vec2
39-
get() = Vec2(width, height)
40-
set(value) = setSize(value.x, value.y)
41-
42-
/**
43-
* The content size of the entity.
44-
*/
45-
val UIComponent.contentSize: Vec2
46-
get() = Vec2(contentWidth, contentHeight)
47-
48-
/**
49-
* The position of the content in the x-axis of the entity.
50-
*/
51-
val IEntity?.contentX: Float
52-
get() = if (this is UIComponent) padding.left else 0f
53-
54-
/**
55-
* The position of the content in the y-axis of the entity.
56-
*/
57-
val IEntity?.contentY: Float
58-
get() = if (this is UIComponent) padding.top else 0f
23+
val IEntity.width
24+
get() = when (this) {
25+
is UIComponent -> width
26+
is CameraScene -> camera?.widthRaw ?: 0f
27+
is IShape -> width
28+
is Scene -> Config.getRES_WIDTH().toFloat()
29+
else -> 0f
30+
}
5931

6032
/**
61-
* The size with transformations applied.
33+
* @see UIComponent.height
6234
*/
63-
val UIComponent.transformedSize: Vec2
64-
get() = Vec2(transformedWidth, transformedHeight)
35+
val IEntity.height
36+
get() = when (this) {
37+
is UIComponent -> height
38+
is CameraScene -> camera?.heightRaw ?: 0f
39+
is IShape -> height
40+
is Scene -> Config.getRES_HEIGHT().toFloat()
41+
else -> 0f
42+
}
6543

66-
/**
67-
* The width with transformations applied.
68-
*/
69-
val UIComponent.transformedWidth: Float
70-
get() = width * scaleX
7144

7245
/**
73-
* The height with transformations applied.
46+
* Wraps [width] and [height] into a [Vec2].
7447
*/
75-
val UIComponent.transformedHeight: Float
76-
get() = height * scaleY
48+
var UIComponent.size: Vec2
49+
get() = Vec2(width, height)
50+
set(value) = setSize(value.x, value.y)
7751

7852
/**
79-
* The size minus padding of the entity.
53+
* @see UIComponent.padding
8054
*/
81-
val UIComponent.innerSize: Vec2
82-
get() = Vec2(innerWidth, innerHeight)
55+
val IEntity?.padding: Vec4
56+
get() = if (this is UIComponent) padding else Vec4.Zero
8357

8458
/**
8559
* The width minus padding of the entity.
8660
*/
87-
val IEntity?.innerWidth: Float
88-
get() = if (this is UIComponent) width - padding.horizontal else getWidth()
61+
val IEntity.innerWidth: Float
62+
get() = if (this is UIComponent) innerWidth else width - padding.horizontal
8963

9064
/**
9165
* The height minus padding of the entity.
9266
*/
93-
val IEntity?.innerHeight: Float
94-
get() = if (this is UIComponent) height - padding.vertical else getHeight()
67+
val IEntity.innerHeight: Float
68+
get() = if (this is UIComponent) innerHeight else height - padding.vertical
9569

9670
//endregion
9771

9872
//region Position related properties
9973

10074
/**
101-
* The absolute position of the entity in the parent coordinate system.
102-
* This takes into account the anchor and origin but not transformations.
75+
* Wraps [absoluteX] and [absoluteY] into a [Vec2].
10376
*/
104-
val UIComponent.absolutePosition: Vec2
77+
val IEntity.absolutePosition: Vec2
10578
get() = Vec2(absoluteX, absoluteY)
10679

107-
/**
108-
* The absolute position of the X axis of the entity in the parent coordinate system.
109-
* This takes into account the anchor and origin.
110-
*/
80+
/** @see UIComponent.absoluteX */
11181
val IEntity.absoluteX: Float
112-
get() = if (this is UIComponent) (if (attachmentMode == Child) parent.contentX else 0f) + anchorPositionX - originPositionX + x + translationX else x
82+
get() = if (this is UIComponent) absoluteX else x
11383

11484
/**
115-
* The absolute position of the Y axis of the entity in the parent coordinate system.
116-
* This takes into account the anchor and origin but not transformations.
85+
* @see UIComponent.absoluteY
11786
*/
11887
val IEntity.absoluteY: Float
119-
get() = if (this is UIComponent) (if (attachmentMode == Child) parent.contentY else 0f) + anchorPositionY - originPositionY + y + translationY else y
88+
get() = if (this is UIComponent) absoluteY else y
12089

12190
/**
122-
* The position of the entity. This does not take into account the anchor and origin.
91+
* Wraps [IEntity.getX] and [IEntity.getY] into a [Vec2].
12392
*/
124-
var UIComponent.position
93+
var IEntity.position
12594
get() = Vec2(x, y)
12695
set(value) = setPosition(value.x, value.y)
12796

@@ -131,36 +100,6 @@ var UIComponent.position
131100
val UIComponent.anchorPosition: Vec2
132101
get() = Vec2(anchorPositionX, anchorPositionY)
133102

134-
/**
135-
* The anchor position of the entity in the X axis.
136-
*/
137-
val UIComponent.anchorPositionX: Float
138-
get() = parent.innerWidth * anchor.x
139-
140-
/**
141-
* The anchor position of the entity in the Y axis.
142-
*/
143-
val UIComponent.anchorPositionY: Float
144-
get() = parent.innerHeight * anchor.y
145-
146-
147-
/**
148-
* The origin position of the entity.
149-
*/
150-
val UIComponent.originPosition: Vec2
151-
get() = Vec2(originPositionX, originPositionY)
152-
153-
/**
154-
* The origin position of the entity in the X axis.
155-
*/
156-
val UIComponent.originPositionX: Float
157-
get() = width * origin.x
158-
159-
/**
160-
* The origin position of the entity in the Y axis.
161-
*/
162-
val UIComponent.originPositionY: Float
163-
get() = height * origin.y
164103

165104
//endregion
166105

@@ -231,28 +170,14 @@ var IEntity.color4
231170

232171
//endregion
233172

234-
235173
//region Utilities
236174

237-
/**
238-
* Traverses the parent hierarchy of the entity to find the first scene it belongs to.
239-
*/
240-
fun IEntity.getParentScene(): Scene? {
241-
return if (this is Scene) this else parent?.getParentScene()
242-
}
243-
244175
inline fun IEntity.forEach(block: (IEntity) -> Unit) {
245176
for (i in 0 until childCount) {
246177
block(getChild(i))
247178
}
248179
}
249180

250-
inline fun IEntity.forEachIndexed(block: (Int, IEntity) -> Unit) {
251-
for (i in 0 until childCount) {
252-
block(i, getChild(i))
253-
}
254-
}
255-
256181
fun UIText.setText(@StringRes resourceId: Int) {
257182
text = StringTable.get(resourceId)
258183
}

0 commit comments

Comments
 (0)