From 982b72b74c8e7f4e5b23a3523d5b8c8aac9b4291 Mon Sep 17 00:00:00 2001 From: Luca Raddatz Date: Fri, 10 Jan 2025 14:40:15 +0100 Subject: [PATCH] Changed the hexagon size to be adjustable --- .../tools/aqua/bgw/application/Config.kt | 4 +- .../builder/GameComponentContainerBuilder.kt | 8 +- .../bgw/builder/GameComponentViewBuilder.kt | 6 +- .../gamecomponentviews/HexagonView.kt | 27 +- .../aqua/bgw/main/view/HexGridGameScene.kt | 344 +++--- .../tools/aqua/bgw/mapper/ComponentMapper.kt | 1065 +++++++++-------- 6 files changed, 736 insertions(+), 718 deletions(-) diff --git a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/application/Config.kt b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/application/Config.kt index b9a2f790a..e7ee87fd8 100644 --- a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/application/Config.kt +++ b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/application/Config.kt @@ -2,6 +2,6 @@ package tools.aqua.bgw.application internal object Config { val USE_SOCKETS = true - val GENERATE_SAMPLES = true - val BGW_VERSION = "0.9-new_backend-81-064a1ee-SNAPSHOT" + val GENERATE_SAMPLES = false + val BGW_VERSION = "0.9-new_backend-82-c96d621-SNAPSHOT" } \ No newline at end of file diff --git a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentContainerBuilder.kt b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentContainerBuilder.kt index 0272b007a..971d0a21c 100644 --- a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentContainerBuilder.kt +++ b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentContainerBuilder.kt @@ -38,7 +38,9 @@ internal object GameComponentContainerBuilder { is LinearLayout -> buildLinearLayout(gameComponentContainer) is Satchel -> buildSatchel(gameComponentContainer) } - gameComponentContainer.components.forEach { ComponentViewBuilder.build(it) } + gameComponentContainer.components.forEach { + ComponentViewBuilder.build(it) + } } private fun buildArea(area: Area) {} @@ -47,7 +49,9 @@ internal object GameComponentContainerBuilder { cardStack.alignmentProperty.guiListener = { _, _ -> Frontend.updateComponent(cardStack) } } - private fun buildHexagonGrid(hexagonGrid: HexagonGrid) {} + private fun buildHexagonGrid(hexagonGrid: HexagonGrid) { + + } private fun buildLinearLayout(linearLayout: LinearLayout) { linearLayout.spacingProperty.guiListener = { _, _ -> Frontend.updateComponent(linearLayout) } diff --git a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentViewBuilder.kt b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentViewBuilder.kt index 2553204b3..cfdee44a3 100644 --- a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentViewBuilder.kt +++ b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/builder/GameComponentViewBuilder.kt @@ -38,7 +38,11 @@ internal object GameComponentViewBuilder { diceView.visuals.guiListener = { _, _ -> Frontend.updateComponent(diceView) } } - private fun buildHexagonView(hexagonView: HexagonView) {} + private fun buildHexagonView(hexagonView: HexagonView) { + hexagonView.sizeProperty.guiListener = { _, _ -> + Frontend.updateComponent(hexagonView) + } + } private fun buildTokenView(tokenView: TokenView) {} } diff --git a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/components/gamecomponentviews/HexagonView.kt b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/components/gamecomponentviews/HexagonView.kt index d302dbd8e..190605bda 100644 --- a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/components/gamecomponentviews/HexagonView.kt +++ b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/components/gamecomponentviews/HexagonView.kt @@ -19,6 +19,8 @@ package tools.aqua.bgw.components.gamecomponentviews import tools.aqua.bgw.core.DEFAULT_HEXAGON_SIZE import tools.aqua.bgw.core.HexOrientation +import tools.aqua.bgw.observable.properties.DoubleProperty +import tools.aqua.bgw.observable.properties.Property import tools.aqua.bgw.visual.Visual /** @@ -28,8 +30,7 @@ import tools.aqua.bgw.visual.Visual * * @param posX Horizontal coordinate for this [HexagonView]. Default: 0. * @param posY Vertical coordinate for this [HexagonView]. Default: 0. - * @param size Represents the radius of the outer circle of the [HexagonView] all six points lie on. - * Default: [DEFAULT_HEXAGON_SIZE]. + * @param size Represents the distance to the outermost corner of the [HexagonView]. Default: [DEFAULT_HEXAGON_SIZE]. * @param visual Visual for this [HexagonView]. * @param orientation Orientation of the [HexagonView]. Default: [HexOrientation.POINTY_TOP]. * @@ -41,7 +42,7 @@ import tools.aqua.bgw.visual.Visual open class HexagonView( posX: Number = 0, posY: Number = 0, - val size: Number = DEFAULT_HEXAGON_SIZE, + size: Number = DEFAULT_HEXAGON_SIZE, visual: Visual, /** @@ -58,4 +59,22 @@ open class HexagonView( posY = posY, width = 2 * size.toDouble(), height = 2 * size.toDouble(), - visual = visual) + visual = visual + ) { + + /** + * [Property] for the size of the [HexagonView]. + */ + internal val sizeProperty: DoubleProperty = DoubleProperty(size.toDouble()) + + /** + * Size of the [HexagonView]. For [HexOrientation.POINTY_TOP] this is the distance from the center + * to the top or bottom corner representing half the height of the container. For [HexOrientation.FLAT_TOP] + * this is the distance from the center to the left or right corner representing half the width of the container. + */ + var size: Double + get() = sizeProperty.value + set(value) { + sizeProperty.value = value + } +} diff --git a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/main/view/HexGridGameScene.kt b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/main/view/HexGridGameScene.kt index 1deba852a..d6dfdb0c4 100644 --- a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/main/view/HexGridGameScene.kt +++ b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/main/view/HexGridGameScene.kt @@ -25,212 +25,162 @@ import tools.aqua.bgw.components.layoutviews.CameraPane import tools.aqua.bgw.components.layoutviews.Pane import tools.aqua.bgw.components.uicomponents.Button import tools.aqua.bgw.components.uicomponents.Label -import tools.aqua.bgw.core.* +import tools.aqua.bgw.core.BoardGameScene +import tools.aqua.bgw.core.Color +import tools.aqua.bgw.core.HexOrientation import tools.aqua.bgw.style.BorderRadius import tools.aqua.bgw.util.BidirectionalMap -import tools.aqua.bgw.visual.* +import tools.aqua.bgw.visual.ColorVisual +import tools.aqua.bgw.visual.ImageVisual +import tools.aqua.bgw.visual.Visual internal class HexGridGameScene : BoardGameScene() { - private val hexGrid = - HexagonGrid( - width = 500, - height = 500, - posX = 0, - posY = 0, - coordinateSystem = HexagonGrid.CoordinateSystem.OFFSET, - visual = Visual.EMPTY, - orientation = HexOrientation.POINTY_TOP) - .apply { + private val hexGrid = HexagonGrid( + width = 500, + height = 500, + posX = 0, + posY = 0, + coordinateSystem = HexagonGrid.CoordinateSystem.OFFSET, + visual = Visual.EMPTY, + orientation = HexOrientation.POINTY_TOP + ).apply { + onMouseClicked = { + placeOnHexGrid(HexagonView(visual = ColorVisual(Color(0, 0, 255)), size = 40).apply {}) + } + } + + private val satchel = Satchel( + posX = 1100, + posY = 0, + width = 100, + height = 100, + // visual = + // ImageVisual("https://static.vecteezy.com/system/resources/previews/010/256/326/non_2x/premium-flat-icon-of-game-bag-vector.jpg") + ).apply { + dropAcceptor = { it.draggedComponent is HexagonView } + onDragDropped = { placeInSatchel(it.draggedComponent as HexagonView) } + } + + private val singleHex = HexagonView(posX = 1100, posY = 0, visual = ColorVisual.BLUE.copy().apply { + style.borderRadius = BorderRadius(4) + }, size = 50).apply { + onMouseClicked = { + size = 100.0 + } + } + + val paneDot = Label(posX = -3, + posY = -3, + width = 6, + height = 6, + visual = ColorVisual.BLUE.copy().apply { style.borderRadius = BorderRadius.FULL }) + + val paneDot2 = Label(posX = 200 - 3, + posY = 100 - 3, + width = 6, + height = 6, + visual = ColorVisual.MAGENTA.copy().apply { style.borderRadius = BorderRadius.FULL }) + + private val targetPane = Pane( + width = 1920, height = 1080, posX = 0, posY = 0, visual = ImageVisual("assets/3.jpg") + ).apply { + add(hexGrid) + add(paneDot) + add(paneDot2) + } + + private val cameraPane = CameraPane( + width = 1200, height = 800, target = Pane( + width = 1920, height = 1080, posX = 0, posY = 0, visual = ImageVisual("assets/3.jpg") + ), posX = 200, posY = 100, visual = ColorVisual.YELLOW, limitBounds = true + ).apply { + interactive = true + + onZoomed = { println("Zoomed to $it") } + } + + val centerDot = Label(posX = cameraPane.width / 2 - 2 + cameraPane.posX, + posY = cameraPane.height / 2 - 2 + cameraPane.posY, + width = 4, + height = 4, + visual = ColorVisual.RED.copy().apply { style.borderRadius = BorderRadius.FULL }) + + val panButton = Button( + posX = 5, posY = 1020, width = 100, height = 50, text = "Pan By", visual = ColorVisual(Color(0, 255, 0)) + ).apply { onMouseClicked = { cameraPane.panBy(200, 100) } } + + val panZeroButton = Button( + posX = 105, posY = 1020, width = 100, height = 50, text = "Pan", visual = ColorVisual(Color(0, 125, 0)) + ).apply { onMouseClicked = { cameraPane.pan(0, 0, smooth = false) } } + + val zoomButton = Button( + posX = 205, posY = 1020, width = 100, height = 50, text = "Zoom", visual = ColorVisual(Color(0, 255, 0)) + ).apply { + onMouseClicked = { + Application.showGameScene(Application.cardLayoutScene) + } + } + + private val hexPointy = HexagonView( + posX = 800, + posY = 200, + visual = ColorVisual(Color(255, 0, 0)), + size = 50, + orientation = HexOrientation.POINTY_TOP + ) + private val hexFlat = HexagonView( + posX = 900, posY = 200, visual = ColorVisual(Color(0, 255, 0)), size = 50, orientation = HexOrientation.FLAT_TOP + ) + + fun placeOnHexGrid(hexagon: HexagonView) { + hexGrid[10, 0] = HexagonView( + visual = ColorVisual(Color(255, 0, 0)), size = 50, orientation = HexOrientation.POINTY_TOP + ).apply { onMouseClicked = { - placeOnHexGrid(HexagonView(visual = ColorVisual(Color(0, 0, 255)), size = 40)) + println("Before: ${(visual as ColorVisual).color.toHex()}") + visual = ColorVisual.GREEN + println("After: ${(visual as ColorVisual).color.toHex()}") } - } - - private val satchel = - Satchel( - posX = 1100, - posY = 0, - width = 100, - height = 100, - // visual = - // ImageVisual("https://static.vecteezy.com/system/resources/previews/010/256/326/non_2x/premium-flat-icon-of-game-bag-vector.jpg") - ) - .apply { - dropAcceptor = { it.draggedComponent is HexagonView } - onDragDropped = { placeInSatchel(it.draggedComponent as HexagonView) } - } - - private val singleHex = - HexagonView(posX = 1100, posY = 0, visual = ColorVisual.BLUE.copy().apply { - style.borderRadius = BorderRadius(4) - }, size = 50).apply { - isDraggable = true - } - - val paneDot = - Label( - posX = -3, - posY = -3, - width = 6, - height = 6, - visual = ColorVisual.BLUE.copy().apply { style.borderRadius = BorderRadius.FULL }) - - val paneDot2 = - Label( - posX = 200 - 3, - posY = 100 - 3, - width = 6, - height = 6, - visual = ColorVisual.MAGENTA.copy().apply { style.borderRadius = BorderRadius.FULL }) - - private val targetPane = - Pane( - width = 1920, height = 1080, posX = 0, posY = 0, visual = ImageVisual("assets/3.jpg")) - .apply { - add(hexGrid) - add(paneDot) - add(paneDot2) - } - - private val cameraPane = - CameraPane( - width = 1200, - height = 800, - target = targetPane, - posX = 200, - posY = 100, - visual = ColorVisual.YELLOW, - limitBounds = true) - .apply { - interactive = true - - onZoomed = { println("Zoomed to $it") } - } - - val centerDot = - Label( - posX = cameraPane.width / 2 - 2 + cameraPane.posX, - posY = cameraPane.height / 2 - 2 + cameraPane.posY, - width = 4, - height = 4, - visual = ColorVisual.RED.copy().apply { style.borderRadius = BorderRadius.FULL }) - - val panButton = - Button( - posX = 5, - posY = 1020, - width = 100, - height = 50, - text = "Pan By", - visual = ColorVisual(Color(0, 255, 0))) - .apply { onMouseClicked = { cameraPane.panBy(200, 100) } } - - val panZeroButton = - Button( - posX = 105, - posY = 1020, - width = 100, - height = 50, - text = "Pan", - visual = ColorVisual(Color(0, 125, 0))) - .apply { onMouseClicked = { cameraPane.pan(0, 0, smooth = false) } } - - val zoomButton = - Button( - posX = 205, - posY = 1020, - width = 100, - height = 50, - text = "Zoom", - visual = ColorVisual(Color(0, 255, 0))) - .apply { onMouseClicked = { - Application.showGameScene(Application.cardLayoutScene) - } } - - private val hexPointy = - HexagonView( - posX = 800, - posY = 200, - visual = ColorVisual(Color(255, 0, 0)), - size = 50, - orientation = HexOrientation.POINTY_TOP) - private val hexFlat = - HexagonView( - posX = 900, - posY = 200, - visual = ColorVisual(Color(0, 255, 0)), - size = 50, - orientation = HexOrientation.FLAT_TOP) - - fun placeOnHexGrid(hexagon: HexagonView) { - hexGrid[10, 0] = - HexagonView( - visual = ColorVisual(Color(255, 0, 0)), - size = 50, - orientation = HexOrientation.POINTY_TOP) - targetPane.width = hexGrid.width - targetPane.height = hexGrid.height - } - - fun placeInSatchel(hexagon: HexagonView) { - hexGrid.remove(hexagon) - satchel.add(hexagon) - } - - val hexMap = BidirectionalMap, HexagonView>() - - fun buildHexGrid() { - for (q in -5..5) { - for (r in -5..5) { - if (q + r >= -5 && q + r <= 5) { - if (hexMap.containsForward(Pair(q, r))) { - hexGrid[q, r] = hexMap[Pair(q, r)]!! as HexagonView - continue - } - val hexagon = - HexagonView(visual = ColorVisual.LIGHT_GRAY, size = 40).apply { - dropAcceptor = { it.draggedComponent is HexagonView } - - onDragDropped = { - hexGrid[q, r] = it.draggedComponent as HexagonView - satchel.remove(it.draggedComponent) - } + } + targetPane.width = hexGrid.width + targetPane.height = hexGrid.height + } + + fun placeInSatchel(hexagon: HexagonView) { + hexGrid.remove(hexagon) + satchel.add(hexagon) + } + + val hexMap = BidirectionalMap, HexagonView>() - onDragGestureEntered = { visual = ColorVisual.GRAY } + fun buildHexGrid() { + for (q in -1..1) { + for (r in -1..1) { + if (q + r >= -1 && q + r <= 1) { - onDragGestureExited = { visual = ColorVisual.LIGHT_GRAY } - } - hexGrid[q, r] = hexagon - hexMap[Pair(q, r)] = hexagon + val hexagon = HexagonView(visual = ColorVisual.LIGHT_GRAY, size = 40).apply { + onMouseClicked = { + visual = ColorVisual.CYAN + size = 100.0 + } + } + hexGrid[q, r] = hexagon + } + } } - } + + targetPane.width = hexGrid.width + targetPane.height = hexGrid.height } - targetPane.width = hexGrid.width - targetPane.height = hexGrid.height - } - - fun refreshHexGrid() { - buildHexGrid() - } - - init { - buildHexGrid() - - addComponents(cameraPane, panButton, panZeroButton, zoomButton, centerDot) - // repeat(20) { - // val hexagon = HexagonView(posX = 800, posY = 800, visual = - // ImageVisual("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSwc4YbxNBYXWRkgqzh9tbaSQh2Uy-f4e1Nl0teHHWFisub3gxv4rxn1eFjgVUUMASaNSg&usqp=CAU"), size = 40, orientation = HexOrientation.FLAT_TOP).apply { - // isDraggable = true - // onKeyPressed = { - // if(it.keyCode == KeyCode.Q) { - // rotation -= 60.0 - // } else if(it.keyCode == KeyCode.E) { - // rotation += 60.0 - // } - // } - // } - // satchel.add(hexagon) - // } - } + fun refreshHexGrid() { + buildHexGrid() + } + + init { + buildHexGrid() + + targetPane.add(singleHex) + addComponents(targetPane, panButton, panZeroButton, zoomButton, centerDot) + } } diff --git a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/mapper/ComponentMapper.kt b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/mapper/ComponentMapper.kt index cd4b952f4..a99d5ae70 100644 --- a/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/mapper/ComponentMapper.kt +++ b/bgw-gui/src/jvmMain/kotlin/tools/aqua/bgw/mapper/ComponentMapper.kt @@ -16,7 +16,6 @@ */ import ComponentMapper.fillData -import kotlin.math.max import tools.aqua.bgw.application.Constants import tools.aqua.bgw.components.ComponentView import tools.aqua.bgw.components.container.* @@ -31,569 +30,611 @@ import tools.aqua.bgw.style.Filter import tools.aqua.bgw.style.Style import tools.aqua.bgw.util.Font import tools.aqua.bgw.visual.* +import kotlin.math.max internal object ComponentMapper { - fun ComponentViewData.fillData(componentView: ComponentView): ComponentViewData { - return this.apply { - id = componentView.id - posX = componentView.posX.toInt() - posY = componentView.posY.toInt() - width = componentView.width.toInt() - height = componentView.height.toInt() - visual = VisualMapper.map(componentView.visual) - zIndex = componentView.zIndex - opacity = componentView.opacity - isVisible = componentView.isVisible - isDisabled = componentView.isDisabled - // isFocusable - scaleX = componentView.scaleX - scaleY = componentView.scaleY - rotation = componentView.rotation - - if (componentView.dropAcceptor != null) { - isDroppable = true - } - // layoutFromCenter - // isDraggable - hasMouseEnteredEvent = componentView.onMouseEntered != null - hasMouseExitedEvent = componentView.onMouseExited != null + fun ComponentViewData.fillData(componentView: ComponentView): ComponentViewData { + return this.apply { + id = componentView.id + posX = componentView.posX.toInt() + posY = componentView.posY.toInt() + width = componentView.width.toInt() + height = componentView.height.toInt() + visual = VisualMapper.map(componentView.visual) + zIndex = componentView.zIndex + opacity = componentView.opacity + isVisible = componentView.isVisible + isDisabled = componentView.isDisabled + // isFocusable + scaleX = componentView.scaleX + scaleY = componentView.scaleY + rotation = componentView.rotation + + if (componentView.dropAcceptor != null) { + isDroppable = true + } + // layoutFromCenter + // isDraggable + hasMouseEnteredEvent = componentView.onMouseEntered != null + hasMouseExitedEvent = componentView.onMouseExited != null + } } - } - - private fun mapSpecific(componentView: ComponentView): ComponentViewData { - return when (componentView) { - is ListView<*> -> - (ListViewData().fillData(componentView) as ListViewData).apply { - items = componentView.items.map { item -> componentView.formatItem(item) } - selectionMode = componentView.selectionMode.name.lowercase() - selectionBackground = componentView.selectionBackground.color.toHex() - selectedItems = componentView.selectedIndicesList.toList() - font = FontMapper.map(componentView.font) - } - is TableView<*> -> - (TableViewData().fillData(componentView) as TableViewData).apply { - items = componentView.items.map { it.toString() } - columns = - componentView.columns.map { - TableColumnData().apply { - title = it.title - width = it.width.toInt() - font = FontMapper.map(it.font) - items = componentView.items.map { item -> it.formatItem(item) } - } + + private fun mapSpecific(componentView: ComponentView): ComponentViewData { + return when (componentView) { + is ListView<*> -> + (ListViewData().fillData(componentView) as ListViewData).apply { + items = componentView.items.map { item -> componentView.formatItem(item) } + selectionMode = componentView.selectionMode.name.lowercase() + selectionBackground = componentView.selectionBackground.color.toHex() + selectedItems = componentView.selectedIndicesList.toList() + font = FontMapper.map(componentView.font) } - selectionMode = componentView.selectionMode.name.lowercase() - selectionBackground = componentView.selectionBackground.color.toHex() - selectedItems = componentView.selectedIndicesList.toList() - font = FontMapper.map(componentView.font) - } - is LabeledUIComponent -> { - when (componentView) { - is Button -> ButtonData().fillData(componentView) as ButtonData - is CheckBox -> CheckBoxData().fillData(componentView) as CheckBoxData - is Label -> LabelData().fillData(componentView) as LabelData - is RadioButton -> RadioButtonData().fillData(componentView) as RadioButtonData - is ToggleButton -> ToggleButtonData().fillData(componentView) as ToggleButtonData - else -> - throw IllegalArgumentException( - "Unknown component type: ${componentView::class.simpleName}") - }.apply { - font = FontMapper.map(componentView.font) - alignment = - Pair( - componentView.alignment.horizontalAlignment.name.lowercase(), - componentView.alignment.verticalAlignment.name.lowercase()) - text = componentView.text - isWrapText = componentView.isWrapText - } - } - is TextInputUIComponent -> { - when (componentView) { - is PasswordField -> PasswordFieldData().fillData(componentView) as PasswordFieldData - is TextField -> TextFieldData().fillData(componentView) as TextFieldData - is TextArea -> TextAreaData().fillData(componentView) as TextAreaData - else -> - throw IllegalArgumentException( - "Unknown component type: ${componentView::class.simpleName}") - }.apply { - font = FontMapper.map(componentView.font) - text = componentView.text - prompt = componentView.prompt - } - } - is UIComponent -> { - when (componentView) { - is ComboBox<*> -> ComboBoxData().fillData(componentView) as ComboBoxData - is ColorPicker -> ColorPickerData().fillData(componentView) as ColorPickerData - is ProgressBar -> ProgressBarData().fillData(componentView) as ProgressBarData - else -> - throw IllegalArgumentException( - "Unknown component type: ${componentView::class.simpleName}") - }.apply { font = FontMapper.map(componentView.font) } - } - is CameraPane<*> -> - (CameraPaneData().fillData(componentView) as CameraPaneData).apply { - target = LayoutMapper.map(componentView.target) - interactive = componentView.interactive - internalPanData = componentView.panData - panButton = componentView.panMouseButton.name.lowercase() - limitBounds = componentView.limitBounds - - // ! nightly - isVerticalLocked - // ! nightly - isHorizontalLocked - // ! nightly - isZoomLocked - // ! nightly - panMouseButton - } - is GameComponentView -> { - when (componentView) { - is CardView -> CardViewData().fillData(componentView) as CardViewData - is DiceView -> DiceViewData().fillData(componentView) as DiceViewData - is HexagonView -> HexagonViewData().fillData(componentView) as HexagonViewData - is TokenView -> TokenViewData().fillData(componentView) as TokenViewData - else -> - throw IllegalArgumentException( - "Unknown component type: ${componentView::class.simpleName}") - }.apply { - isDraggable = componentView.isDraggable - isDragged = componentView.isDragged + + is TableView<*> -> + (TableViewData().fillData(componentView) as TableViewData).apply { + items = componentView.items.map { it.toString() } + columns = + componentView.columns.map { + TableColumnData().apply { + title = it.title + width = it.width.toInt() + font = FontMapper.map(it.font) + items = componentView.items.map { item -> it.formatItem(item) } + } + } + selectionMode = componentView.selectionMode.name.lowercase() + selectionBackground = componentView.selectionBackground.color.toHex() + selectedItems = componentView.selectedIndicesList.toList() + font = FontMapper.map(componentView.font) + } + + is LabeledUIComponent -> { + when (componentView) { + is Button -> ButtonData().fillData(componentView) as ButtonData + is CheckBox -> CheckBoxData().fillData(componentView) as CheckBoxData + is Label -> LabelData().fillData(componentView) as LabelData + is RadioButton -> RadioButtonData().fillData(componentView) as RadioButtonData + is ToggleButton -> ToggleButtonData().fillData(componentView) as ToggleButtonData + else -> + throw IllegalArgumentException( + "Unknown component type: ${componentView::class.simpleName}" + ) + }.apply { + font = FontMapper.map(componentView.font) + alignment = + Pair( + componentView.alignment.horizontalAlignment.name.lowercase(), + componentView.alignment.verticalAlignment.name.lowercase() + ) + text = componentView.text + isWrapText = componentView.isWrapText + } + } + + is TextInputUIComponent -> { + when (componentView) { + is PasswordField -> PasswordFieldData().fillData(componentView) as PasswordFieldData + is TextField -> TextFieldData().fillData(componentView) as TextFieldData + is TextArea -> TextAreaData().fillData(componentView) as TextAreaData + else -> + throw IllegalArgumentException( + "Unknown component type: ${componentView::class.simpleName}" + ) + }.apply { + font = FontMapper.map(componentView.font) + text = componentView.text + prompt = componentView.prompt + } + } + + is UIComponent -> { + when (componentView) { + is ComboBox<*> -> ComboBoxData().fillData(componentView) as ComboBoxData + is ColorPicker -> ColorPickerData().fillData(componentView) as ColorPickerData + is ProgressBar -> ProgressBarData().fillData(componentView) as ProgressBarData + else -> + throw IllegalArgumentException( + "Unknown component type: ${componentView::class.simpleName}" + ) + }.apply { font = FontMapper.map(componentView.font) } + } + + is CameraPane<*> -> + (CameraPaneData().fillData(componentView) as CameraPaneData).apply { + target = LayoutMapper.map(componentView.target) + interactive = componentView.interactive + internalPanData = componentView.panData + panButton = componentView.panMouseButton.name.lowercase() + limitBounds = componentView.limitBounds + + // ! nightly - isVerticalLocked + // ! nightly - isHorizontalLocked + // ! nightly - isZoomLocked + // ! nightly - panMouseButton + } + + is GameComponentView -> { + when (componentView) { + is CardView -> CardViewData().fillData(componentView) as CardViewData + is DiceView -> DiceViewData().fillData(componentView) as DiceViewData + is HexagonView -> HexagonViewData().fillData(componentView) as HexagonViewData + is TokenView -> TokenViewData().fillData(componentView) as TokenViewData + else -> + throw IllegalArgumentException( + "Unknown component type: ${componentView::class.simpleName}" + ) + }.apply { + isDraggable = componentView.isDraggable + isDragged = componentView.isDragged + } + } + + else -> + throw IllegalArgumentException( + "Unknown component type: ${componentView::class.simpleName}" + ) } - } - else -> - throw IllegalArgumentException( - "Unknown component type: ${componentView::class.simpleName}") } - } - - fun map(componentView: ComponentView): ComponentViewData { - return when (componentView) { - - // TODO - LabeledUIComponent - is Button -> (mapSpecific(componentView) as ButtonData) - is CheckBox -> - (mapSpecific(componentView) as CheckBoxData).apply { - isChecked = componentView.isChecked - allowIndeterminate = componentView.isIndeterminateAllowed - isIndeterminate = componentView.isIndeterminate - } - is Label -> (mapSpecific(componentView) as LabelData) - is RadioButton -> - (mapSpecific(componentView) as RadioButtonData).apply { - isSelected = componentView.isSelected - group = componentView.toggleGroup.id - } - is ToggleButton -> - (mapSpecific(componentView) as ToggleButtonData).apply { - isSelected = componentView.isSelected - group = componentView.toggleGroup.id - } - - // TODO - TextInputUIComponent - is PasswordField -> (mapSpecific(componentView) as PasswordFieldData) - is TextField -> (mapSpecific(componentView) as TextFieldData) - is TextArea -> (mapSpecific(componentView) as TextAreaData) - - // TODO - UIComponent - is ComboBox<*> -> mapComboBox(componentView) - is ColorPicker -> - (mapSpecific(componentView) as ColorPickerData).apply { - selectedColor = componentView.selectedColor.toHex() - } - is ProgressBar -> - (mapSpecific(componentView) as ProgressBarData).apply { - progress = componentView.progress - barColor = - "rgba(${componentView.barColor.red}, ${componentView.barColor.green}, ${componentView.barColor.blue}, ${componentView.barColor.alpha})" - } - - // TODO - StructuredDataView - is ListView<*> -> - (mapSpecific(componentView) as ListViewData).apply { - orientation = componentView.orientation.name.lowercase() - } - is TableView<*> -> - (mapSpecific(componentView) as TableViewData).apply { - // columns (as TableColumnData) - } - - // TODO - ComponentView - is CameraPane<*> -> (mapSpecific(componentView) as CameraPaneData) - - // TODO - GameComponentView - is CardView -> - (mapSpecific(componentView) as CardViewData).apply { - front = VisualMapper.map(componentView.frontVisual) - back = VisualMapper.map(componentView.backVisual) - currentVisual = - if (componentView.currentSide == CardView.CardSide.BACK) - VisualMapper.map(componentView.backVisual) - else VisualMapper.map(componentView.frontVisual) - } - is DiceView -> - (mapSpecific(componentView) as DiceViewData).apply { - currentSide = componentView.currentSide - visuals = componentView.visuals.map { VisualMapper.map(it) } - } - is HexagonView -> - (mapSpecific(componentView) as HexagonViewData).apply { - size = componentView.size.toInt() - orientation = componentView.orientation.name.lowercase() - } - is TokenView -> (mapSpecific(componentView) as TokenViewData) - else -> TODO("Not implemented") + + fun map(componentView: ComponentView): ComponentViewData { + return when (componentView) { + + // TODO - LabeledUIComponent + is Button -> (mapSpecific(componentView) as ButtonData) + is CheckBox -> + (mapSpecific(componentView) as CheckBoxData).apply { + isChecked = componentView.isChecked + allowIndeterminate = componentView.isIndeterminateAllowed + isIndeterminate = componentView.isIndeterminate + } + + is Label -> (mapSpecific(componentView) as LabelData) + is RadioButton -> + (mapSpecific(componentView) as RadioButtonData).apply { + isSelected = componentView.isSelected + group = componentView.toggleGroup.id + } + + is ToggleButton -> + (mapSpecific(componentView) as ToggleButtonData).apply { + isSelected = componentView.isSelected + group = componentView.toggleGroup.id + } + + // TODO - TextInputUIComponent + is PasswordField -> (mapSpecific(componentView) as PasswordFieldData) + is TextField -> (mapSpecific(componentView) as TextFieldData) + is TextArea -> (mapSpecific(componentView) as TextAreaData) + + // TODO - UIComponent + is ComboBox<*> -> mapComboBox(componentView) + is ColorPicker -> + (mapSpecific(componentView) as ColorPickerData).apply { + selectedColor = componentView.selectedColor.toHex() + } + + is ProgressBar -> + (mapSpecific(componentView) as ProgressBarData).apply { + progress = componentView.progress + barColor = + "rgba(${componentView.barColor.red}, ${componentView.barColor.green}, ${componentView.barColor.blue}, ${componentView.barColor.alpha})" + } + + // TODO - StructuredDataView + is ListView<*> -> + (mapSpecific(componentView) as ListViewData).apply { + orientation = componentView.orientation.name.lowercase() + } + + is TableView<*> -> + (mapSpecific(componentView) as TableViewData).apply { + // columns (as TableColumnData) + } + + // TODO - ComponentView + is CameraPane<*> -> (mapSpecific(componentView) as CameraPaneData) + + // TODO - GameComponentView + is CardView -> + (mapSpecific(componentView) as CardViewData).apply { + front = VisualMapper.map(componentView.frontVisual) + back = VisualMapper.map(componentView.backVisual) + currentVisual = + if (componentView.currentSide == CardView.CardSide.BACK) + VisualMapper.map(componentView.backVisual) + else VisualMapper.map(componentView.frontVisual) + } + + is DiceView -> + (mapSpecific(componentView) as DiceViewData).apply { + currentSide = componentView.currentSide + visuals = componentView.visuals.map { VisualMapper.map(it) } + } + + is HexagonView -> + (mapSpecific(componentView) as HexagonViewData).apply { + size = componentView.size.toInt() + orientation = componentView.orientation.name.lowercase() + } + + is TokenView -> (mapSpecific(componentView) as TokenViewData) + else -> TODO("Not implemented") + } } - } - - fun mapComboBox(comboBox: ComboBox): ComboBoxData { - return (mapSpecific(comboBox) as ComboBoxData).apply { - val selItem = comboBox.selectedItem - prompt = comboBox.prompt - items = - comboBox.items.mapIndexed { index, it -> - Pair(index, comboBox.formatFunction?.invoke(it) ?: it.toString()) - } - selectedItem = - if (selItem == null) null - else - Pair( - comboBox.getSelectedIndex(), - comboBox.formatFunction?.invoke(selItem) ?: comboBox.selectedItem.toString()) + + fun mapComboBox(comboBox: ComboBox): ComboBoxData { + return (mapSpecific(comboBox) as ComboBoxData).apply { + val selItem = comboBox.selectedItem + prompt = comboBox.prompt + items = + comboBox.items.mapIndexed { index, it -> + Pair(index, comboBox.formatFunction?.invoke(it) ?: it.toString()) + } + selectedItem = + if (selItem == null) null + else + Pair( + comboBox.getSelectedIndex(), + comboBox.formatFunction?.invoke(selItem) ?: comboBox.selectedItem.toString() + ) + } } - } } internal object FontMapper { - private val fontWeightMap = - mapOf( - Font.FontWeight.THIN to 100, - Font.FontWeight.EXTRA_LIGHT to 200, - Font.FontWeight.LIGHT to 300, - Font.FontWeight.NORMAL to 400, - Font.FontWeight.MEDIUM to 500, - Font.FontWeight.SEMI_BOLD to 600, - Font.FontWeight.BOLD to 700, - Font.FontWeight.EXTRA_BOLD to 800, - Font.FontWeight.BLACK to 900) - fun map(font: Font): FontData { - return FontData().apply { - size = font.size.toInt() - color = - "rgba(${font.color.red}, ${font.color.green}, ${font.color.blue}, ${font.color.alpha})" - family = font.family - fontWeight = fontWeightMap[font.fontWeight] ?: 400 - fontStyle = font.fontStyle.name.lowercase() + private val fontWeightMap = + mapOf( + Font.FontWeight.THIN to 100, + Font.FontWeight.EXTRA_LIGHT to 200, + Font.FontWeight.LIGHT to 300, + Font.FontWeight.NORMAL to 400, + Font.FontWeight.MEDIUM to 500, + Font.FontWeight.SEMI_BOLD to 600, + Font.FontWeight.BOLD to 700, + Font.FontWeight.EXTRA_BOLD to 800, + Font.FontWeight.BLACK to 900 + ) + + fun map(font: Font): FontData { + return FontData().apply { + size = font.size.toInt() + color = + "rgba(${font.color.red}, ${font.color.green}, ${font.color.blue}, ${font.color.alpha})" + family = font.family + fontWeight = fontWeightMap[font.fontWeight] ?: 400 + fontStyle = font.fontStyle.name.lowercase() + } } - } } internal object LayoutMapper { - fun map(layout: LayoutView<*>): LayoutViewData { - return when (layout) { - is Pane<*> -> - (PaneData().fillData(layout) as PaneData).apply { - components = layout.components.map { RecursiveMapper.map(it) } - if (layout.dropAcceptor != null) { - isDroppable = true - } - } - is GridPane<*> -> - (GridPaneData().fillData(layout) as GridPaneData).apply { - val grid = - layout.grid.clone().apply { - removeEmptyColumns() - removeEmptyRows() + fun map(layout: LayoutView<*>): LayoutViewData { + return when (layout) { + is Pane<*> -> + (PaneData().fillData(layout) as PaneData).apply { + components = layout.components.map { RecursiveMapper.map(it) } + if (layout.dropAcceptor != null) { + isDroppable = true + } } - columns = grid.columns - rows = grid.rows - this.grid = - grid.map { - val alignment = layout.getCellCenterMode(it.columnIndex, it.rowIndex) - GridElementData( - it.columnIndex, - it.rowIndex, - if (it.component != null) RecursiveMapper.map(it.component) else null, - alignment = - alignment.horizontalAlignment.name.lowercase() to - alignment.verticalAlignment.name.lowercase()) + + is GridPane<*> -> + (GridPaneData().fillData(layout) as GridPaneData).apply { + val grid = + layout.grid.clone().apply { + removeEmptyColumns() + removeEmptyRows() + } + columns = grid.columns + rows = grid.rows + this.grid = + grid.map { + val alignment = layout.getCellCenterMode(it.columnIndex, it.rowIndex) + GridElementData( + it.columnIndex, + it.rowIndex, + if (it.component != null) RecursiveMapper.map(it.component) else null, + alignment = + alignment.horizontalAlignment.name.lowercase() to + alignment.verticalAlignment.name.lowercase() + ) + } + spacing = layout.spacing.toInt() + layoutFromCenter = layout.isLayoutFromCenter + if (layout.dropAcceptor != null) { + isDroppable = true + } } - spacing = layout.spacing.toInt() - layoutFromCenter = layout.isLayoutFromCenter - if (layout.dropAcceptor != null) { - isDroppable = true - } - } - else -> throw IllegalArgumentException("Unknown layout type: ${layout::class.simpleName}") + + else -> throw IllegalArgumentException("Unknown layout type: ${layout::class.simpleName}") + } } - } } internal object RecursiveMapper { - fun map(component: ComponentView): ComponentViewData { - return when (component) { - is LayoutView<*> -> { - LayoutMapper.map(component) - } - is GameComponentContainer<*> -> { - ContainerMapper.map(component) - } - is ComponentView -> { - ComponentMapper.map(component) - } - else -> - throw IllegalArgumentException("Unknown component type: ${component::class.simpleName}") + fun map(component: ComponentView): ComponentViewData { + return when (component) { + is LayoutView<*> -> { + LayoutMapper.map(component) + } + + is GameComponentContainer<*> -> { + ContainerMapper.map(component) + } + + else -> { + ComponentMapper.map(component) + } + } } - } } internal object ContainerMapper { - fun map(container: GameComponentContainer<*>): GameComponentContainerData { - return when (container) { - is Area<*> -> - (AreaData().fillData(container) as AreaData).apply { - components = - container.components.map { RecursiveMapper.map(it) } as List - if (container.dropAcceptor != null) { - isDroppable = true - } - } - is CardStack<*> -> - (CardStackData().fillData(container) as CardStackData).apply { - components = - container.components.map { RecursiveMapper.map(it) } as List - if (container.dropAcceptor != null) { - isDroppable = true + fun map(container: GameComponentContainer<*>): GameComponentContainerData { + return when (container) { + is Area<*> -> + (AreaData().fillData(container) as AreaData).apply { + components = + container.components.map { RecursiveMapper.map(it) } as List + if (container.dropAcceptor != null) { + isDroppable = true + } + } + + is CardStack<*> -> + (CardStackData().fillData(container) as CardStackData).apply { + components = + container.components.map { RecursiveMapper.map(it) } as List + if (container.dropAcceptor != null) { + isDroppable = true + } + } + + is HexagonGrid<*> -> { + val tempMap = mutableMapOf() + container.map.forEach { (key, value) -> + tempMap["${key.first}/${key.second}"] = + (HexagonViewData().fillData(value) as HexagonViewData).apply { + id = value.id + posX = value.posX.toInt() + posY = value.posY.toInt() + visual = VisualMapper.map(value.visual) + size = value.size.toInt() + orientation = container.orientation.name.lowercase() + // isDraggable = value.isDraggable // TODO - Element has no root node + // dragging out + } + } + + (HexagonGridData().fillData(container) as HexagonGridData).apply { + coordinateSystem = container.coordinateSystem.name.lowercase() + map = tempMap + spacing = 0 + orientation = container.orientation.name.lowercase() + // components ?! + + if (container.dropAcceptor != null) { + isDroppable = true + } + } } - } - is HexagonGrid<*> -> { - val tempMap = mutableMapOf() - container.map.forEach { (key, value) -> - tempMap["${key.first}/${key.second}"] = - (HexagonViewData().fillData(value) as HexagonViewData).apply { - id = value.id - posX = value.posX.toInt() - posY = value.posY.toInt() - visual = VisualMapper.map(value.visual) - size = value.size.toInt() - orientation = container.orientation.name.lowercase() - // isDraggable = value.isDraggable // TODO - Element has no root node - // dragging out - } - } - (HexagonGridData().fillData(container) as HexagonGridData).apply { - coordinateSystem = container.coordinateSystem.name.lowercase() - map = tempMap - spacing = 0 - orientation = container.orientation.name.lowercase() - // components ?! + is LinearLayout<*> -> + (LinearLayoutData().fillData(container) as LinearLayoutData).apply { + components = + container.components.map { RecursiveMapper.map(it) } as List + spacing = container.spacing.toInt() + orientation = container.orientation.name.lowercase() + alignment = + Pair( + container.alignment.horizontalAlignment.name.lowercase(), + container.alignment.verticalAlignment.name.lowercase() + ) + + if (container.dropAcceptor != null) { + isDroppable = true + } + } - if (container.dropAcceptor != null) { - isDroppable = true - } + is Satchel -> + (SatchelData().fillData(container) as SatchelData).apply { + components = + container.components.map { RecursiveMapper.map(it) } as List + + if (container.dropAcceptor != null) { + isDroppable = true + } + } } - } - is LinearLayout<*> -> - (LinearLayoutData().fillData(container) as LinearLayoutData).apply { - components = - container.components.map { RecursiveMapper.map(it) } as List - spacing = container.spacing.toInt() - orientation = container.orientation.name.lowercase() - alignment = - Pair( - container.alignment.horizontalAlignment.name.lowercase(), - container.alignment.verticalAlignment.name.lowercase()) - - if (container.dropAcceptor != null) { - isDroppable = true - } - } - is Satchel -> - (SatchelData().fillData(container) as SatchelData).apply { - components = - container.components.map { RecursiveMapper.map(it) } as List - - if (container.dropAcceptor != null) { - isDroppable = true - } - } } - } } internal object StyleMapper { - fun map(style: Style): Map { - return style.getDeclarations() - } + fun map(style: Style): Map { + return style.getDeclarations() + } } internal object FilterMapper { - fun map(filters: Filter): Map { - return filters.getDeclarations() - } + fun map(filters: Filter): Map { + return filters.getDeclarations() + } } internal object VisualMapper { - fun map(visual: Visual): VisualData { - val visualData = - when (visual) { - is ColorVisual -> - ColorVisualData().apply { - id = visual.id - color = - "rgba(${visual.color.red}, ${visual.color.green}, ${visual.color.blue}, ${visual.color.alpha})" - transparency = visual.transparency - style = StyleMapper.map(visual.style) - filters = FilterMapper.map(visual.filters) - flipped = visual.flipped.name.lowercase() - } - is ImageVisual -> - ImageVisualData().apply { - id = visual.id - if (isRelativeFilePath(visual.path)) - path = "http://localhost:${Constants.PORT}/static/${visual.path}" - else path = visual.path - width = visual.width - height = visual.height - offsetX = visual.offsetX - offsetY = visual.offsetY - transparency = visual.transparency - style = StyleMapper.map(visual.style) - filters = FilterMapper.map(visual.filters) - flipped = visual.flipped.name.lowercase() - } - is TextVisual -> - TextVisualData().apply { - id = visual.id - text = visual.text - font = FontMapper.map(visual.font) - offsetX = visual.offsetX.toInt() - offsetY = visual.offsetY.toInt() - transparency = visual.transparency - style = StyleMapper.map(visual.style) - filters = FilterMapper.map(visual.filters) - flipped = visual.flipped.name.lowercase() - alignment = - Pair( - visual.alignment.horizontalAlignment.name.lowercase(), - visual.alignment.verticalAlignment.name.lowercase()) - } - - // --- Compound Visuals --- + fun map(visual: Visual): VisualData { + val visualData = + when (visual) { + is ColorVisual -> + ColorVisualData().apply { + id = visual.id + color = + "rgba(${visual.color.red}, ${visual.color.green}, ${visual.color.blue}, ${visual.color.alpha})" + transparency = visual.transparency + style = StyleMapper.map(visual.style) + filters = FilterMapper.map(visual.filters) + flipped = visual.flipped.name.lowercase() + } + + is ImageVisual -> + ImageVisualData().apply { + id = visual.id + if (isRelativeFilePath(visual.path)) + path = "http://localhost:${Constants.PORT}/static/${visual.path}" + else path = visual.path + width = visual.width + height = visual.height + offsetX = visual.offsetX + offsetY = visual.offsetY + transparency = visual.transparency + style = StyleMapper.map(visual.style) + filters = FilterMapper.map(visual.filters) + flipped = visual.flipped.name.lowercase() + } + + is TextVisual -> + TextVisualData().apply { + id = visual.id + text = visual.text + font = FontMapper.map(visual.font) + offsetX = visual.offsetX.toInt() + offsetY = visual.offsetY.toInt() + transparency = visual.transparency + style = StyleMapper.map(visual.style) + filters = FilterMapper.map(visual.filters) + flipped = visual.flipped.name.lowercase() + alignment = + Pair( + visual.alignment.horizontalAlignment.name.lowercase(), + visual.alignment.verticalAlignment.name.lowercase() + ) + } + + // --- Compound Visuals --- + + is CompoundVisual -> { + CompoundVisualData().apply { + id = visual.id + children = visual.children.map { mapChildren(it) } + } + } - is CompoundVisual -> { + else -> { + throw IllegalArgumentException("Unknown visual type: ${visual::class.simpleName}") + } + } + return if (visualData is SingleLayerVisualData) { CompoundVisualData().apply { - id = visual.id - children = visual.children.map { mapChildren(it) } + id = visualData.id + children = listOf(visualData) } - } - else -> { - throw IllegalArgumentException("Unknown visual type: ${visual::class.simpleName}") - } + } else { + visualData } - return if (visualData is SingleLayerVisualData) { - CompoundVisualData().apply { - id = visualData.id - children = listOf(visualData) - } - } else { - visualData } - } - private fun mapChildren(visual: SingleLayerVisual): SingleLayerVisualData { - return when (visual) { - is ColorVisual -> - ColorVisualData().apply { - id = visual.id - color = - "rgba(${visual.color.red}, ${visual.color.green}, ${visual.color.blue}, ${visual.color.alpha})" - transparency = visual.transparency - style = StyleMapper.map(visual.style) - filters = FilterMapper.map(visual.filters) - flipped = visual.flipped.name.lowercase() - } - is ImageVisual -> - ImageVisualData().apply { - id = visual.id - if (isRelativeFilePath(visual.path)) - path = "http://localhost:${Constants.PORT}/static/${visual.path}" - else path = visual.path - width = visual.width - height = visual.height - offsetX = visual.offsetX - offsetY = visual.offsetY - transparency = visual.transparency - style = StyleMapper.map(visual.style) - filters = FilterMapper.map(visual.filters) - flipped = visual.flipped.name.lowercase() - } - is TextVisual -> - TextVisualData().apply { - id = visual.id - text = visual.text - font = FontMapper.map(visual.font) - offsetX = visual.offsetX.toInt() - offsetY = visual.offsetY.toInt() - transparency = visual.transparency - style = StyleMapper.map(visual.style) - filters = FilterMapper.map(visual.filters) - flipped = visual.flipped.name.lowercase() - alignment = - Pair( - visual.alignment.horizontalAlignment.name.lowercase(), - visual.alignment.verticalAlignment.name.lowercase()) - } + private fun mapChildren(visual: SingleLayerVisual): SingleLayerVisualData { + return when (visual) { + is ColorVisual -> + ColorVisualData().apply { + id = visual.id + color = + "rgba(${visual.color.red}, ${visual.color.green}, ${visual.color.blue}, ${visual.color.alpha})" + transparency = visual.transparency + style = StyleMapper.map(visual.style) + filters = FilterMapper.map(visual.filters) + flipped = visual.flipped.name.lowercase() + } + + is ImageVisual -> + ImageVisualData().apply { + id = visual.id + if (isRelativeFilePath(visual.path)) + path = "http://localhost:${Constants.PORT}/static/${visual.path}" + else path = visual.path + width = visual.width + height = visual.height + offsetX = visual.offsetX + offsetY = visual.offsetY + transparency = visual.transparency + style = StyleMapper.map(visual.style) + filters = FilterMapper.map(visual.filters) + flipped = visual.flipped.name.lowercase() + } + + is TextVisual -> + TextVisualData().apply { + id = visual.id + text = visual.text + font = FontMapper.map(visual.font) + offsetX = visual.offsetX.toInt() + offsetY = visual.offsetY.toInt() + transparency = visual.transparency + style = StyleMapper.map(visual.style) + filters = FilterMapper.map(visual.filters) + flipped = visual.flipped.name.lowercase() + alignment = + Pair( + visual.alignment.horizontalAlignment.name.lowercase(), + visual.alignment.verticalAlignment.name.lowercase() + ) + } + } + } + + // TODO: Check properly if path is URL or local path + private fun isRelativeFilePath(path: String): Boolean { + return !path.startsWith("http://") && + !path.startsWith("https://") && + !path.startsWith("data:image/png;base64,") } - } - - // TODO: Check properly if path is URL or local path - private fun isRelativeFilePath(path: String): Boolean { - return !path.startsWith("http://") && - !path.startsWith("https://") && - !path.startsWith("data:image/png;base64,") - } } internal object FontFaceMapper { - private val fontWeightMap = - mapOf( - Font.FontWeight.THIN to 100, - Font.FontWeight.EXTRA_LIGHT to 200, - Font.FontWeight.LIGHT to 300, - Font.FontWeight.NORMAL to 400, - Font.FontWeight.MEDIUM to 500, - Font.FontWeight.SEMI_BOLD to 600, - Font.FontWeight.BOLD to 700, - Font.FontWeight.EXTRA_BOLD to 800, - Font.FontWeight.BLACK to 900) - - fun map(font: Triple): Triple { - return Triple(font.first, font.second, fontWeightMap[font.third] ?: 400) - } + private val fontWeightMap = + mapOf( + Font.FontWeight.THIN to 100, + Font.FontWeight.EXTRA_LIGHT to 200, + Font.FontWeight.LIGHT to 300, + Font.FontWeight.NORMAL to 400, + Font.FontWeight.MEDIUM to 500, + Font.FontWeight.SEMI_BOLD to 600, + Font.FontWeight.BOLD to 700, + Font.FontWeight.EXTRA_BOLD to 800, + Font.FontWeight.BLACK to 900 + ) + + fun map(font: Triple): Triple { + return Triple(font.first, font.second, fontWeightMap[font.third] ?: 400) + } } internal object SceneMapper { - private fun mapScene(scene: Scene<*>): SceneData { - // FIXME - DONE - return SceneData().apply { - components = scene.components.map { RecursiveMapper.map(it) } - width = scene.width.toInt() - height = scene.height.toInt() - background = VisualMapper.map(scene.background) + private fun mapScene(scene: Scene<*>): SceneData { + // FIXME - DONE + return SceneData().apply { + components = scene.components.map { RecursiveMapper.map(it) } + width = scene.width.toInt() + height = scene.height.toInt() + background = VisualMapper.map(scene.background) + } } - } - - fun map(menuScene: MenuScene? = null, gameScene: BoardGameScene? = null): AppData { - return AppData().apply { - this.width = - max( - menuScene?.width?.toInt() ?: DEFAULT_SCENE_WIDTH.toInt(), - gameScene?.width?.toInt() ?: DEFAULT_SCENE_WIDTH.toInt()) - this.height = - max( - menuScene?.height?.toInt() ?: DEFAULT_SCENE_HEIGHT.toInt(), - gameScene?.height?.toInt() ?: DEFAULT_SCENE_HEIGHT.toInt()) - this.menuScene = if (menuScene != null) mapScene(menuScene) else null - this.gameScene = if (gameScene != null) mapScene(gameScene) else null + + fun map(menuScene: MenuScene? = null, gameScene: BoardGameScene? = null): AppData { + return AppData().apply { + this.width = + max( + menuScene?.width?.toInt() ?: DEFAULT_SCENE_WIDTH.toInt(), + gameScene?.width?.toInt() ?: DEFAULT_SCENE_WIDTH.toInt() + ) + this.height = + max( + menuScene?.height?.toInt() ?: DEFAULT_SCENE_HEIGHT.toInt(), + gameScene?.height?.toInt() ?: DEFAULT_SCENE_HEIGHT.toInt() + ) + this.menuScene = if (menuScene != null) mapScene(menuScene) else null + this.gameScene = if (gameScene != null) mapScene(gameScene) else null + } } - } }