@@ -5,6 +5,7 @@ import javafx.geometry.Pos
55import javafx.scene.control.Label
66import javafx.scene.layout.Priority
77import javafx.scene.paint.Color
8+ import javafx.scene.text.Font
89import javafx.scene.text.TextAlignment
910import sc.api.plugins.ITeam
1011import sc.api.plugins.Team
@@ -14,6 +15,41 @@ import sc.gui.model.GameModel
1415import sc.gui.strings
1516import tornadofx.*
1617
18+ fun decodeXmlEntities (toDecode : String ): String {
19+ // if ('&' !in toDecode) return toDecode
20+ // Replace potentially bad characters
21+ return toDecode.replace(" <" , " <" )
22+ .replace(" >" , " >" )
23+ .replace(" &" , " &" )
24+ .replace(" &" , " &" )
25+ .replace(" "" , " \" " )
26+ }
27+
28+ fun playerLabel (game : GameModel , team : Team ) =
29+ Label ().apply {
30+ // Add string to display for team including teamStats.
31+ textProperty().bind(
32+ game.gameState.stringBinding { state ->
33+ state?.teamStats(team)?.takeUnless { it.isEmpty() }?.let { stats ->
34+ stats.joinToString(
35+ " \n " ,
36+ " ${decodeXmlEntities(game.playerNames[team.index])} (${strings[" color.${team.color} " ]} )\n "
37+ ) { stat ->
38+ " ${stat.label} ${stat.icon?.let { if (stat.value > 0 ) it.repeat(stat.value) else " -" } ? : stat.value} "
39+ }
40+ }
41+ })
42+ // Handle theming
43+ textFillProperty().bind(AppModel .darkMode.objectBinding {
44+ if (it == true )
45+ Color .hsb(Color .valueOf(team.color).hue, .4 , 1.0 )
46+ else
47+ Color .hsb(Color .valueOf(team.color).hue, .8 , .6 )
48+ })
49+ font = Font (AppStyle .fontSizeBig.value)
50+
51+ }
52+
1753class StatusBinding (private val game : GameModel ): StringBinding() {
1854 init {
1955 bind(game.gameStarted, game.currentTeam, game.gameResult, game.playerNames, game.atLatestTurn)
@@ -23,11 +59,11 @@ class StatusBinding(private val game: GameModel): StringBinding() {
2359 if (game.gameStarted.value && game.atLatestTurn.value || game.gameResult.value != null )
2460 game.gameResult.takeIf { game.atLatestTurn.value }?.get()?.let { gameResult ->
2561 """
26- ${gameResult.win?.winner?.let { " ${it.displayName} hat gewonnen!" } ? : " Unentschieden" }
27- ${gameResult.win?.reason?.message?.replace(" brig" , " übrig" ).orEmpty()}
62+ ${gameResult.win?.winner?.let { " ${decodeXmlEntities( it.displayName) } hat gewonnen!" } ? : " Unentschieden" }
63+ ${decodeXmlEntities( gameResult.win?.reason?.message?.replace(" brig" , " übrig" ).orEmpty() )}
2864 """ .trimIndent().trim(' \n ' )
29- } ? : " ${game.currentTeam.value.displayName} am Zug"
30- else game.playerNames.joinToString(" vs " )
65+ } ? : " ${decodeXmlEntities( game.currentTeam.value.displayName) } am Zug"
66+ else game.playerNames.map { decodeXmlEntities(it) }. joinToString(" vs " )
3167
3268 val ITeam .displayName
3369 get() = index.let { game.playerNames.getOrNull(it) ? : " Spieler ${it + 1 } " }
@@ -38,15 +74,22 @@ class ScoreBinding(private val game: GameModel): StringBinding() {
3874 bind(game.gameStarted, game.gameState)
3975 }
4076
41- override fun computeValue (): String =
42- if (game.gameStarted.value)
43- " Runde ${game.getCurrentRound()} - " +
44- game.gameState.value?.run {
45- Team .values().sortedBy { it != startTeam }.joinToString(" : " ) {
46- getPointsForTeam(it).first().toString()
47- }
48- }
49- else " Drücke auf Start" .takeUnless { game.gameOver.value && game.atLatestTurn.value }.orEmpty()
77+ /* *
78+ * A ScoreBinding should have the following computed String value:
79+ * Runde X - Punkte Team 1 : Punkte Team 2
80+ * This point order is inverted if the startTeam is Team.TWO.
81+ * This is only used for the finals.
82+ */
83+ override fun computeValue (): String {
84+ if (game.gameStarted.value) {
85+ return " Runde ${(game.currentTurn.get() + 1 ) / 2 } - " +
86+ game.gameState.value?.getPointsForTeam(Team .ONE )?.first().toString() +
87+ " : " +
88+ game.gameState.value?.getPointsForTeam(Team .TWO )?.first().toString()
89+ } else {
90+ return " Drücke auf Start" .takeUnless { game.gameOver.value && game.atLatestTurn.value }.orEmpty()
91+ }
92+ }
5093}
5194
5295class StatusView : View () {
@@ -55,13 +98,15 @@ class StatusView: View() {
5598 override val root = hbox {
5699 useMaxWidth = true
57100 alignment = Pos .CENTER
58- add(playerLabel(Team .ONE ))
101+ // Moved to PlayerOne/TwoView
102+ // add(playerLabel(Team.ONE))
59103 vbox(alignment = Pos .CENTER ) {
60104 this .spacing = AppStyle .fontSizeUnscaled.value
61105 runLater {
62106 prefWidthProperty().bind(scene.widthProperty().divide(2 ))
63107 hgrow = Priority .ALWAYS
64- maxWidth = AppStyle .fontSizeRegular.value * 60
108+ maxWidth = AppStyle .fontSizeRegular.value * 90
109+ prefHeightProperty().bind(scene.heightProperty().divide(6 ))
65110 }
66111 addClass(AppStyle .statusLabel)
67112 label(StatusBinding (game)) {
@@ -70,7 +115,8 @@ class StatusView: View() {
70115 }
71116 label(ScoreBinding (game))
72117 }
73- add(playerLabel(Team .TWO ))
118+ // Moved to PlayerOne/TwoView
119+ // add(playerLabel(Team.TWO))
74120
75121 // runLater {
76122 // scene.root.apply {
0 commit comments