diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt index 67fc7f25..7e34a1d6 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt @@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.editor.asset.component import com.bartlomiejpluta.base.editor.asset.model.Asset import com.bartlomiejpluta.base.editor.asset.model.AssetCategory import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset import com.bartlomiejpluta.base.editor.image.asset.ImageAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset @@ -70,6 +71,7 @@ class AssetTreeCell(renameAsset: (asset: Asset, name: String) -> Asset, deleteAs is TileSetAsset -> FontIcon("fa-th") is ImageAsset -> FontIcon("fa-image") is EntitySet -> FontIcon("fa-male") + is FontAsset -> FontIcon("fa-font") else -> null } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt index c2b32db7..0b9072b0 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt @@ -31,12 +31,17 @@ class AssetsListView : View() { menuitem("Import Entity Set...") { mainController.importEntitySet() } } + private val fonts = AssetCategory("Fonts").apply { + menuitem("Import Font...") { mainController.importFont() } + } + private val rootItem = AssetCategory( name = "Project", items = observableListOf( maps, tileSets, images, - entitySet + entitySet, + fonts ) ) @@ -48,6 +53,7 @@ class AssetsListView : View() { Bindings.bindContent(tileSets.items, it.tileSets) Bindings.bindContent(images.items, it.images) Bindings.bindContent(entitySet.items, it.entitySets) + Bindings.bindContent(fonts.items, it.fonts) root.root.expandAll() } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/build/project/DefaultProjectAssembler.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/build/project/DefaultProjectAssembler.kt index 105c637a..2c466730 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/build/project/DefaultProjectAssembler.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/build/project/DefaultProjectAssembler.kt @@ -27,6 +27,7 @@ class DefaultProjectAssembler : ProjectAssembler { packager.pack(project.tileSetsDirectory, targetJar, "BOOT-INF/classes/project/tilesets") packager.pack(project.imagesDirectory, targetJar, "BOOT-INF/classes/project/images") packager.pack(project.entitySetsDirectory, targetJar, "BOOT-INF/classes/project/entsets") + packager.pack(project.fontsDirectory, targetJar, "BOOT-INF/classes/project/fonts") packager.copy(project.projectFile, targetJar, "BOOT-INF/classes/project") } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/component/SingleFileChooserField.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/component/SingleFileChooserField.kt new file mode 100644 index 00000000..2d47f642 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/component/SingleFileChooserField.kt @@ -0,0 +1,61 @@ +package com.bartlomiejpluta.base.editor.common.component + +import javafx.beans.property.ObjectProperty +import javafx.beans.property.SimpleObjectProperty +import javafx.beans.property.SimpleStringProperty +import javafx.scene.layout.HBox +import tornadofx.* +import java.io.File + +class SingleFileChooserField( + private val fileProperty: ObjectProperty = SimpleObjectProperty(), + var type: Type = Type.FILE, + var validationContext: ValidationContext? = null, + op: SingleFileChooserField.() -> Unit = {} +) : HBox() { + private val filePath = SimpleStringProperty() + private var openDialog: (() -> List) = { chooseFile("File Location", emptyArray()) } + + fun dialogFormat(op: () -> List) { + this.openDialog = op + } + + init { + textfield(filePath) { + trimWhitespace() + + validationContext?.addValidator(this, filePath) { + if (it.isNullOrBlank()) { + error("Field is required") + } + + val file = File(it!!) + when { + !file.exists() -> error("Provide valid path to the ${type.name.toLowerCase()}") + type == Type.FILE && file.isDirectory -> error("Expected file, but directory is provided") + type == Type.DIRECTORY && file.isFile -> error("Expected directory, but file is provided") + else -> null + } + } + } + + button("Choose") { + action { + filePath.value = openDialog().getOrNull(0)?.absolutePath + } + } + + filePath.addListener { _, _, value -> + value?.let { + fileProperty.value = File(it) + } + } + + op(this) + } + + enum class Type { + FILE, + DIRECTORY + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/asset/FontAsset.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/asset/FontAsset.kt new file mode 100644 index 00000000..a0a4689b --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/asset/FontAsset.kt @@ -0,0 +1,7 @@ +package com.bartlomiejpluta.base.editor.gui.font.asset + +import com.bartlomiejpluta.base.editor.asset.model.Asset +import com.bartlomiejpluta.base.editor.project.model.Project + +class FontAsset(project: Project, uid: String, source: String, name: String) : + Asset(project.fontsDirectoryProperty, uid, source, name) \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/asset/FontAssetData.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/asset/FontAssetData.kt new file mode 100644 index 00000000..19e3e1c7 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/asset/FontAssetData.kt @@ -0,0 +1,15 @@ +package com.bartlomiejpluta.base.editor.gui.font.asset + +import javafx.beans.property.SimpleObjectProperty +import javafx.beans.property.SimpleStringProperty +import tornadofx.getValue +import tornadofx.setValue +import java.io.File + +class FontAssetData { + val nameProperty = SimpleStringProperty() + var name by nameProperty + + val fileProperty = SimpleObjectProperty() + var file by fileProperty +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/view/importing/ImportFontFragment.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/view/importing/ImportFontFragment.kt new file mode 100644 index 00000000..ea8a1191 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/view/importing/ImportFontFragment.kt @@ -0,0 +1,55 @@ +package com.bartlomiejpluta.base.editor.gui.font.view.importing + +import com.bartlomiejpluta.base.editor.common.component.SingleFileChooserField +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData +import com.bartlomiejpluta.base.editor.gui.font.viewmodel.FontAssetDataVM +import javafx.stage.FileChooser +import tornadofx.* + +class ImportFontFragment : Fragment("Import Font") { + private val dataVM = find() + + private var onCompleteConsumer: ((FontAssetData) -> Unit)? = null + + fun onComplete(consumer: (FontAssetData) -> Unit) { + this.onCompleteConsumer = consumer + } + + override val root = form { + fieldset("Import Font") { + field("Font Name") { + textfield(dataVM.nameProperty) { + requestFocus() + required() + trimWhitespace() + } + } + + field("Font File") { + this += SingleFileChooserField(dataVM.fileProperty) { + type = SingleFileChooserField.Type.FILE + validationContext = dataVM.validationContext + + dialogFormat { + chooseFile("Font File Location", arrayOf(FileChooser.ExtensionFilter("TTF File", "*.ttf"))) + } + } + } + } + + buttonbar { + button("Ok") { + action { + if (dataVM.commit()) { + onCompleteConsumer?.let { it(dataVM.item) } + close() + } + } + } + + button("Cancel") { + action { close() } + } + } + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/viewmodel/FontAssetDataVM.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/viewmodel/FontAssetDataVM.kt new file mode 100644 index 00000000..1e068602 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/gui/font/viewmodel/FontAssetDataVM.kt @@ -0,0 +1,14 @@ +package com.bartlomiejpluta.base.editor.gui.font.viewmodel + +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData +import tornadofx.ItemViewModel +import tornadofx.getValue +import tornadofx.setValue + +class FontAssetDataVM : ItemViewModel(FontAssetData()) { + val nameProperty = bind(FontAssetData::nameProperty) + var name by nameProperty + + val fileProperty = bind(FontAssetData::fileProperty) + var file by fileProperty +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt index 6b30d610..113f3f57 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt @@ -9,6 +9,8 @@ import com.bartlomiejpluta.base.editor.entityset.view.importing.ImportEntitySetF import com.bartlomiejpluta.base.editor.entityset.viewmodel.EntitySetAssetDataVM import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent import com.bartlomiejpluta.base.editor.file.model.FileNode +import com.bartlomiejpluta.base.editor.gui.font.view.importing.ImportFontFragment +import com.bartlomiejpluta.base.editor.gui.font.viewmodel.FontAssetDataVM import com.bartlomiejpluta.base.editor.image.view.importing.ImportImageFragment import com.bartlomiejpluta.base.editor.image.viewmodel.ImageAssetDataVM import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset @@ -167,6 +169,20 @@ class MainController : Controller() { } } + fun importFont() { + val vm = FontAssetDataVM() + val scope = Scope() + setInScope(vm, scope) + + find(scope).apply { + onComplete { + projectContext.importFont(it) + } + + openModal(block = true, resizable = false) + } + } + fun closeScript(fsNode: FileNode) { openItems.entries.firstOrNull { (_, item) -> item is Code && item.fileNode.absolutePath == fsNode.absolutePath }?.key?.let { openItems.remove(it) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt index f8d2170b..e91ad7fb 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt @@ -7,6 +7,8 @@ import com.bartlomiejpluta.base.editor.code.service.JavaClassService import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet import com.bartlomiejpluta.base.editor.entityset.asset.EntitySetAssetData import com.bartlomiejpluta.base.editor.file.model.FileNode +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData import com.bartlomiejpluta.base.editor.image.asset.ImageAsset import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset @@ -177,6 +179,19 @@ class DefaultProjectContext : ProjectContext { } } + override fun importFont(data: FontAssetData) { + project?.let { + UID.next(it.fonts.map(Asset::uid)).let { uid -> + val source = "$uid.${data.file.extension}" + val targetFile = File(it.fontsDirectory, source) + data.file.copyTo(targetFile) + it.fonts += FontAsset(it, uid, source, data.name) + + save() + } + } + } + override fun deleteAsset(asset: Asset) { project?.let { it.assetLists.firstOrNull { assets -> assets.remove(asset) } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt index dd249e11..35f51b45 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt @@ -4,6 +4,7 @@ import com.bartlomiejpluta.base.editor.asset.model.Asset import com.bartlomiejpluta.base.editor.code.model.Code import com.bartlomiejpluta.base.editor.entityset.asset.EntitySetAssetData import com.bartlomiejpluta.base.editor.file.model.FileNode +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData import com.bartlomiejpluta.base.editor.image.asset.ImageAsset import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData import com.bartlomiejpluta.base.editor.map.model.map.GameMap @@ -35,6 +36,8 @@ interface ProjectContext { fun importEntitySet(data: EntitySetAssetData) + fun importFont(data: FontAssetData) + fun deleteAsset(asset: Asset) fun loadScript(fileNode: FileNode): Code fun saveScript(code: Code) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt index 1ae49120..df33123d 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt @@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.project.model import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet import com.bartlomiejpluta.base.editor.file.model.FileSystemNode +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset import com.bartlomiejpluta.base.editor.image.asset.ImageAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset @@ -30,8 +31,9 @@ class Project { val tileSets = observableListOf() val images = observableListOf() val entitySets = observableListOf() + val fonts = observableListOf() - val assetLists = listOf(maps, tileSets, images, entitySets) + val assetLists = listOf(maps, tileSets, images, entitySets, fonts) val mapsDirectoryProperty = SimpleObjectProperty() var mapsDirectory by mapsDirectoryProperty @@ -49,6 +51,10 @@ class Project { var entitySetsDirectory by entitySetsDirectoryProperty private set + val fontsDirectoryProperty = SimpleObjectProperty() + var fontsDirectory by fontsDirectoryProperty + private set + val codeDirectoryProperty = SimpleObjectProperty() var codeDirectory by codeDirectoryProperty private set @@ -83,6 +89,7 @@ class Project { tileSetsDirectory = File(it, TILE_SETS_DIR) imagesDirectory = File(it, IMAGES_DIR) entitySetsDirectory = File(it, ENTITY_SETS_DIR) + fontsDirectory = File(it, FONTS_DIR) codeDirectory = File(it, CODE_DIR) buildDirectory = File(it, BUILD_DIR) buildClassesDirectory = File(it, BUILD_CLASSES_DIR) @@ -98,6 +105,7 @@ class Project { tileSetsDirectory?.mkdirs() imagesDirectory?.mkdirs() entitySetsDirectory?.mkdirs() + fontsDirectory?.mkdirs() codeDirectory?.mkdirs() } @@ -109,6 +117,7 @@ class Project { const val TILE_SETS_DIR = "tilesets" const val IMAGES_DIR = "images" const val ENTITY_SETS_DIR = "entsets" + const val FONTS_DIR = "fonts" const val CODE_DIR = "code" const val BUILD_DIR = "build" const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes" diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt index 98be3627..9f331203 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.editor.project.serial import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset import com.bartlomiejpluta.base.editor.image.asset.ImageAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.project.model.Project @@ -21,6 +22,7 @@ class ProtobufProjectDeserializer : ProjectDeserializer { project.tileSets.addAll(proto.tileSetsList.map { deserializeTileSet(project, it) }) project.images.addAll(proto.imagesList.map { deserializeImage(project, it) }) project.entitySets.addAll(proto.entitySetsList.map { deserializeEntitySet(project, it) }) + project.fonts.addAll(proto.fontsList.map { deserializeFont(project, it) }) return project } @@ -55,4 +57,11 @@ class ProtobufProjectDeserializer : ProjectDeserializer { rows = entitySetAsset.rows, columns = entitySetAsset.columns ) -} \ No newline at end of file + + private fun deserializeFont(project: Project, fontAsset: ProjectProto.FontAsset) = FontAsset( + project = project, + uid = fontAsset.uid, + source = fontAsset.source, + name = fontAsset.name + ) +} diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt index faa5ce9e..cd306e78 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.editor.project.serial import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet +import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset import com.bartlomiejpluta.base.editor.image.asset.ImageAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.project.model.Project @@ -20,6 +21,7 @@ class ProtobufProjectSerializer : ProjectSerializer { proto.addAllTileSets(item.tileSets.map(this::serializeTileSet)) proto.addAllImages(item.images.map(this::serializeImage)) proto.addAllEntitySets(item.entitySets.map(this::serializeEntitySet)) + proto.addAllFonts(item.fonts.map(this::serializeFont)) proto.build().writeTo(output) } @@ -50,4 +52,10 @@ class ProtobufProjectSerializer : ProjectSerializer { .setRows(entitySet.rows) .setColumns(entitySet.columns) .build() -} \ No newline at end of file + + private fun serializeFont(font: FontAsset) = ProjectProto.FontAsset.newBuilder() + .setUid(font.uid) + .setSource(font.source) + .setName(font.name) + .build() +} diff --git a/proto/src/main/proto/project.proto b/proto/src/main/proto/project.proto index fcec3660..b74c686a 100644 --- a/proto/src/main/proto/project.proto +++ b/proto/src/main/proto/project.proto @@ -10,6 +10,7 @@ message Project { repeated TileSetAsset tileSets = 4; repeated ImageAsset images = 5; repeated EntitySetAsset entitySets = 6; + repeated FontAsset fonts = 7; } message GameMapAsset { @@ -38,4 +39,10 @@ message EntitySetAsset { required string name = 3; required uint32 rows = 4; required uint32 columns = 5; +} + +message FontAsset { + required string uid = 1; + required string source = 2; + required string name = 3; } \ No newline at end of file