All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tools.aqua.bgw.builder.LayoutNodeBuilder.kt Maven / Gradle / Ivy

There is a newer version: 0.5
Show newest version
/*
 *    Copyright 2021 The BoardGameWork Authors
 *    SPDX-License-Identifier: Apache-2.0
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package tools.aqua.bgw.builder

import javafx.scene.Node
import javafx.scene.layout.Region
import tools.aqua.bgw.components.ComponentView
import tools.aqua.bgw.components.layoutviews.GridPane
import tools.aqua.bgw.components.layoutviews.LayoutView
import tools.aqua.bgw.components.layoutviews.Pane
import tools.aqua.bgw.core.Scene
import tools.aqua.bgw.util.ComponentViewGrid
import javafx.scene.layout.Pane as FXPane

/**
 * LayoutNodeBuilder.
 * Factory for all BGW layout components.
 */
internal class LayoutNodeBuilder {
	companion object {
		/**
		 * Switches between LayoutComponents.
		 */
		internal fun buildLayoutView(
			scene: Scene,
			layoutViewView: LayoutView
		): Region =
			when (layoutViewView) {
				is GridPane<*> ->
					buildGrid(scene, layoutViewView)
				is Pane<*> ->
					buildPane(scene, layoutViewView)
			}
		
		private fun buildPane(scene: Scene, pane: Pane): Region =
			FXPane().apply {
				pane.observableComponents.setGUIListenerAndInvoke {
					refreshPane(scene, pane)
				}
			}
		
		private fun FXPane.refreshPane(scene: Scene, pane: Pane) {
			children.clear()
			children.addAll(pane.observableComponents.map { NodeBuilder.build(scene, it) })
		}
		
		/**
		 * Builds [GridPane].
		 */
		private fun buildGrid(scene: Scene, gridView: GridPane): Region =
			FXPane().apply {
				gridView.updateGui = { refreshGrid(scene, gridView) }
			}
		
		/**
		 * Refreshes [GridPane].
		 */
		private fun FXPane.refreshGrid(scene: Scene, gridView: GridPane) {
			val grid: ComponentViewGrid = gridView.grid
			
			children.clear()
			
			//Build Nodes
			val nodes = ArrayList, ComponentView, Node>>()
			grid.getColumns().forEachIndexed { colIndex, col ->
				for (rowIndex in col.indices) {
					val gameComponent = col[rowIndex] ?: continue
					
					nodes.add(
						Triple(
							Pair(colIndex, rowIndex),
							gameComponent,
							NodeBuilder.build(scene = scene, componentView = gameComponent)
						)
					)
				}
			}
			
			gridView.renderedRowHeights = DoubleArray(grid.rows) {
				grid.getRow(it).maxOf { entry -> entry?.let { t -> t.height + t.posY } ?: 0.0 }
			}
			gridView.renderedColWidths = DoubleArray(grid.columns) {
				grid.getColumn(it).maxOf { entry -> entry?.let { t -> t.width + t.posY } ?: 0.0 }
			}
			
			//TODO: Disable auto resizing if desired
			gridView.width = gridView.renderedColWidths.sum() + (gridView.renderedColWidths.size - 1) * gridView.spacing
			gridView.height =
				gridView.renderedRowHeights.sum() + (gridView.renderedRowHeights.size - 1) * gridView.spacing
			
			nodes.forEach { triple ->
				val colIndex = triple.first.first
				val rowIndex = triple.first.second
				val component = triple.second
				val node = triple.third
				val posX = (0 until colIndex).sumOf { gridView.renderedColWidths[it] } + colIndex * gridView.spacing
				val posY = (0 until rowIndex).sumOf { gridView.renderedRowHeights[it] } + rowIndex * gridView.spacing
				
				children.add(node.apply {
					layoutX = posX + component.posX
					layoutY = posY + component.posY
				})
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy