319 lines
12 KiB
Scala
319 lines
12 KiB
Scala
package fmon.builder
|
|
|
|
import java.io._
|
|
|
|
import javafx.application.Application
|
|
import javafx.fxml.FXML
|
|
import javafx.fxml.FXMLLoader
|
|
import javafx.fxml.JavaFXBuilderFactory
|
|
import javafx.scene.{control => jfxsc, layout => jfxsl, Parent, Scene}
|
|
import javafx.stage.Stage
|
|
|
|
import scalafx.Includes._
|
|
import scalafx.beans.property._
|
|
import scalafx.collections.ObservableBuffer
|
|
import scalafx.scene.control._
|
|
import scalafx.scene.image.ImageView
|
|
import scalafx.scene.input.MouseEvent
|
|
import scalafx.scene.paint.Color
|
|
import scalafx.scene.layout._
|
|
|
|
import fmon.Config
|
|
import fmon.draw.tile.{AutoTile, AutoTilePalette}
|
|
import fmon.util.YamlHelper
|
|
import fmon.world.{Tileset, TileInfo, TilesetToken}
|
|
|
|
class ObsTileset(name_ : String) {
|
|
val name = new StringProperty(this, "name", name_)
|
|
val a1 = new ObjectProperty[File](this, "a1", null)
|
|
val a2 = new ObjectProperty[File](this, "a2", null)
|
|
val a3 = new ObjectProperty[File](this, "a3", null)
|
|
val a4 = new ObjectProperty[File](this, "a4", null)
|
|
val a5 = new ObjectProperty[File](this, "a5", null)
|
|
|
|
val b = new ObjectProperty[File](this, "b", null)
|
|
val c = new ObjectProperty[File](this, "c", null)
|
|
|
|
val a1Size = new IntegerProperty(this, "a1size", 0)
|
|
val a2Size = new IntegerProperty(this, "a2size", 0)
|
|
val a3Size = new IntegerProperty(this, "a3size", 0)
|
|
val a4Size = new IntegerProperty(this, "a4size", 0)
|
|
val a5Size = new IntegerProperty(this, "a5size", 0)
|
|
val bSize = new IntegerProperty(this, "bsize", 0)
|
|
val cSize = new IntegerProperty(this, "csize", 0)
|
|
|
|
val tileInfo = ObservableBuffer[TileInfo]()
|
|
|
|
def toToken = {
|
|
def nm(file: File) = if (file != null) file.getName else null
|
|
println(tileInfo.size)
|
|
TilesetToken(name(), nm(a1()), nm(a2()), nm(a3()), nm(a4()), nm(a5()), nm(b()), nm(c()), IndexedSeq(tileInfo: _*))
|
|
}
|
|
|
|
override def toString = name()
|
|
}
|
|
|
|
class TilesetBuilder extends Savable {
|
|
@FXML var tilesetList: jfxsc.ListView[ObsTileset] = _
|
|
|
|
@FXML var nameField: jfxsc.TextField = _
|
|
@FXML var a1Chooser: jfxsc.ComboBox[File] = _
|
|
@FXML var a2Chooser: jfxsc.ComboBox[File] = _
|
|
@FXML var a3Chooser: jfxsc.ComboBox[File] = _
|
|
@FXML var a4Chooser: jfxsc.ComboBox[File] = _
|
|
@FXML var a5Chooser: jfxsc.ComboBox[File] = _
|
|
@FXML var bChooser: jfxsc.ComboBox[File] = _
|
|
@FXML var cChooser: jfxsc.ComboBox[File] = _
|
|
|
|
@FXML var tileView: jfxsl.TilePane = _
|
|
|
|
@FXML var doesPassNorth: jfxsc.CheckBox = _
|
|
@FXML var doesPassEast: jfxsc.CheckBox = _
|
|
@FXML var doesPassSouth: jfxsc.CheckBox = _
|
|
@FXML var doesPassWest: jfxsc.CheckBox = _
|
|
@FXML var isCounter: jfxsc.CheckBox = _
|
|
|
|
val tilesets = ObservableBuffer[ObsTileset]()
|
|
|
|
var a1Palette = IndexedSeq[AutoTile]()
|
|
var a2Palette = IndexedSeq[AutoTile]()
|
|
var a3Palette = IndexedSeq[AutoTile]()
|
|
var a4Palette = IndexedSeq[AutoTile]()
|
|
var a5Palette = IndexedSeq[AutoTile]()
|
|
var bPalette = IndexedSeq[AutoTile]()
|
|
var cPalette = IndexedSeq[AutoTile]()
|
|
|
|
val resourceDir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Resources\tilesets")
|
|
val files = resourceDir.listFiles()
|
|
val filenames = files.map(f => (f.getName(), f)).toMap
|
|
|
|
var currTileIndex = 0
|
|
|
|
def currTileset = getSelected(tilesetList)
|
|
|
|
@FXML
|
|
def initialize(): Unit = {
|
|
tilesetList.items = tilesets
|
|
tilesetList.selectionModel().selectedIndex.onChange(selectionChange)
|
|
a1Chooser.converter = FilenameConverter
|
|
a2Chooser.converter = FilenameConverter
|
|
a3Chooser.converter = FilenameConverter
|
|
a4Chooser.converter = FilenameConverter
|
|
a5Chooser.converter = FilenameConverter
|
|
bChooser.converter = FilenameConverter
|
|
cChooser.converter = FilenameConverter
|
|
|
|
a1Chooser.items() ++= null +: files.filter(f => f.getName.endsWith("A1.png"))
|
|
a2Chooser.items() ++= null +: files.filter(f => f.getName.endsWith("A2.png"))
|
|
a3Chooser.items() ++= null +: files.filter(f => f.getName.endsWith("A3.png"))
|
|
a4Chooser.items() ++= null +: files.filter(f => f.getName.endsWith("A4.png"))
|
|
a5Chooser.items() ++= null +: files.filter(f => f.getName.endsWith("A5.png"))
|
|
bChooser.items() ++= null +: files.filter(f => f.getName.endsWith("B.png"))
|
|
cChooser.items() ++= null +: files.filter(f => f.getName.endsWith("C.png"))
|
|
|
|
println(files.size)
|
|
}
|
|
|
|
def addTileset(): Unit = {
|
|
tilesets += new ObsTileset("Tileset")
|
|
tilesetList.selectionModel().selectLast()
|
|
}
|
|
|
|
def selectionChange(): Unit = {
|
|
val ts = getSelected(tilesetList)
|
|
nameField.text = ts.name()
|
|
|
|
def safeSelect(box: ComboBox[File], file: File) = {
|
|
box.selectionModel().clearSelection()
|
|
box.selectionModel().select(file)
|
|
}
|
|
|
|
safeSelect(a1Chooser, ts.a1())
|
|
safeSelect(a2Chooser, ts.a2())
|
|
safeSelect(a3Chooser, ts.a3())
|
|
safeSelect(a4Chooser, ts.a4())
|
|
safeSelect(a5Chooser, ts.a5())
|
|
safeSelect(bChooser, ts.b())
|
|
safeSelect(cChooser, ts.c())
|
|
|
|
}
|
|
|
|
def setName(): Unit = {
|
|
getSelected(tilesetList).name.value = nameField.text()
|
|
tilesetList.refresh()
|
|
}
|
|
|
|
def setA1(): Unit = {
|
|
currTileset.a1.value = getSelected(a1Chooser)
|
|
a1Palette = if (getSelected(a1Chooser) == null) IndexedSeq() else AutoTilePalette.a2(getSelected(a1Chooser), Config.tileSize).tiles
|
|
if (a1Palette.size != currTileset.a1Size()) {
|
|
currTileset.tileInfo.removeRange(0, currTileset.a1Size())
|
|
currTileset.a1Size() = a1Palette.size
|
|
val info = a1Palette.map(_ => allPassInfo)
|
|
currTileset.tileInfo.insert(0, info : _*)
|
|
}
|
|
updateTileView()
|
|
}
|
|
|
|
def setA2(): Unit = {
|
|
currTileset.a2.value = getSelected(a2Chooser)
|
|
a2Palette = if (getSelected(a2Chooser) == null) IndexedSeq() else AutoTilePalette.a2(getSelected(a2Chooser), Config.tileSize).tiles
|
|
if (a2Palette.size != currTileset.a2Size()) {
|
|
val priorSize = currTileset.a2Size()
|
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a2Size())
|
|
currTileset.a2Size() = a1Palette.size
|
|
val info = a2Palette.map(_ => allPassInfo)
|
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
|
}
|
|
updateTileView()
|
|
}
|
|
|
|
def setA3(): Unit = {
|
|
currTileset.a3.value = getSelected(a3Chooser)
|
|
a3Palette = if (getSelected(a3Chooser) == null) IndexedSeq() else AutoTilePalette.a3(getSelected(a3Chooser), Config.tileSize).tiles
|
|
if (a3Palette.size != currTileset.a3Size()) {
|
|
val priorSize = currTileset.a1Size() + currTileset.a2Size()
|
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a3Size())
|
|
currTileset.a3Size() = a1Palette.size
|
|
val info = a3Palette.map(_ => allPassInfo)
|
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
|
}
|
|
updateTileView()
|
|
}
|
|
|
|
def setA4(): Unit = {
|
|
currTileset.a4.value = getSelected(a4Chooser)
|
|
a4Palette = if (getSelected(a4Chooser) == null) IndexedSeq() else AutoTilePalette.a4(getSelected(a4Chooser), Config.tileSize).tiles
|
|
if (a4Palette.size != currTileset.a4Size()) {
|
|
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size()
|
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a4Size())
|
|
currTileset.a4Size() = a4Palette.size
|
|
val info = a4Palette.map(_ => allPassInfo)
|
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
|
}
|
|
updateTileView()
|
|
}
|
|
|
|
def setA5(): Unit = {
|
|
currTileset.a5.value = getSelected(a5Chooser)
|
|
a5Palette = if (getSelected(a5Chooser) == null) IndexedSeq() else AutoTilePalette.basic(getSelected(a5Chooser), Config.tileSize).tiles
|
|
if (a5Palette.size != currTileset.a5Size()) {
|
|
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size() + currTileset.a4Size()
|
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.a5Size())
|
|
currTileset.a5Size() = a5Palette.size
|
|
val info = a5Palette.map(_ => allPassInfo)
|
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
|
}
|
|
updateTileView()
|
|
}
|
|
|
|
def setB(): Unit = {
|
|
currTileset.b.value = getSelected(bChooser)
|
|
bPalette = if (getSelected(bChooser) == null) IndexedSeq() else AutoTilePalette.partitioned(getSelected(bChooser), 2, Config.tileSize).tiles
|
|
if (bPalette.size != currTileset.bSize()) {
|
|
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size() + currTileset.a4Size() + currTileset.a5Size()
|
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.bSize())
|
|
currTileset.bSize() = bPalette.size
|
|
val info = bPalette.map(_ => allPassInfo)
|
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
|
}
|
|
updateTileView()
|
|
}
|
|
|
|
def setC(): Unit = {
|
|
currTileset.c.value = getSelected(cChooser)
|
|
cPalette = if (getSelected(cChooser) == null) IndexedSeq() else AutoTilePalette.partitioned(getSelected(cChooser), 2, Config.tileSize).tiles
|
|
if (cPalette.size != currTileset.cSize()) {
|
|
val priorSize = currTileset.a1Size() + currTileset.a2Size() + currTileset.a3Size() + currTileset.a4Size() + currTileset.a5Size() + currTileset.bSize()
|
|
currTileset.tileInfo.removeRange(priorSize, priorSize + currTileset.cSize())
|
|
currTileset.cSize() = cPalette.size
|
|
val info = cPalette.map(_ => allPassInfo)
|
|
currTileset.tileInfo.insert(priorSize, info : _*)
|
|
}
|
|
updateTileView()
|
|
}
|
|
|
|
def updateTileView(): Unit = {
|
|
tileView.children.clear()
|
|
val tiles = a1Palette ++ a2Palette ++ a3Palette ++ a4Palette ++ a5Palette ++ bPalette ++ cPalette
|
|
tileView.children ++= tiles.zipWithIndex.map{case (t, i) => new ImageView(t.icon.croppedImage()){
|
|
handleEvent(MouseEvent.Any) {
|
|
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
|
currTileIndex = i
|
|
setTile(currTileset.tileInfo(i))
|
|
}
|
|
}
|
|
}.delegate}
|
|
}
|
|
|
|
def setTile(info: TileInfo): Unit = {
|
|
doesPassNorth.selected = info.doesPassNorth
|
|
doesPassEast.selected = info.doesPassEast
|
|
doesPassSouth.selected = info.doesPassSouth
|
|
doesPassWest.selected = info.doesPassWest
|
|
isCounter.selected = info.isCounter
|
|
}
|
|
|
|
def updateTile(): Unit = {
|
|
currTileset.tileInfo(currTileIndex) = TileInfo(
|
|
doesPassNorth.selected(),
|
|
doesPassEast.selected(),
|
|
doesPassSouth.selected(),
|
|
doesPassWest.selected(),
|
|
isCounter.selected())
|
|
}
|
|
|
|
def saveTo(file: File): Unit = {
|
|
val tileSeq = tilesets.map(a => a.toToken)
|
|
YamlHelper.writeSeq(new FileOutputStream(file), tileSeq)
|
|
}
|
|
|
|
def openFrom(file: File): Unit = {
|
|
def f(name: String) = if (name != null) new File(resourceDir, name) else null
|
|
|
|
val tokens = YamlHelper.extractSeq[TilesetToken](new FileInputStream(file))
|
|
tilesets.clear()
|
|
tilesets ++= tokens.map(t=> {
|
|
val ts = new ObsTileset(t.name)
|
|
ts.a1.value = f(t.a1)
|
|
ts.a2.value = f(t.a2)
|
|
ts.a3.value = f(t.a3)
|
|
ts.a4.value = f(t.a4)
|
|
ts.a5.value = f(t.a5)
|
|
ts.b.value = f(t.b)
|
|
ts.c.value = f(t.c)
|
|
// TODO : Individual sizes
|
|
ts.tileInfo ++= t.info
|
|
ts
|
|
})
|
|
tilesetList.refresh()
|
|
}
|
|
|
|
private def allPassInfo = TileInfo(true, true, true, true, false)
|
|
}
|
|
|
|
object TilesetBuilder {
|
|
class TBA extends Application {
|
|
override def start(primaryStage: Stage): Unit = {
|
|
val frameLoader = new FXMLLoader(getClass.getResource("App.fxml"))
|
|
val root: Parent = frameLoader.load()
|
|
val controller = frameLoader.getController[App]()
|
|
|
|
val builderLoader = new FXMLLoader(getClass.getResource("TilesetBuilder.fxml"))
|
|
val builder: Parent = builderLoader.load()
|
|
val builderController = builderLoader.getController[TilesetBuilder]()
|
|
|
|
controller.pane.children = builder
|
|
controller.builder = builderController
|
|
|
|
val scene: Scene = new Scene(root)
|
|
primaryStage.setScene(scene)
|
|
primaryStage.show()
|
|
}
|
|
}
|
|
|
|
def main(args: Array[String]): Unit = {
|
|
Application.launch(classOf[TBA], args: _*)
|
|
}
|
|
|
|
} |