diff --git a/Assets/common/icons.png b/Assets/common/icons.png index 1fb496e9..9c6c4fdf 100644 Binary files a/Assets/common/icons.png and b/Assets/common/icons.png differ diff --git a/Assets/common/icons2x.png b/Assets/common/icons2x.png index 2b822dc9..e733ef49 100644 Binary files a/Assets/common/icons2x.png and b/Assets/common/icons2x.png differ diff --git a/Sources/arm/Context.hx b/Sources/arm/Context.hx index d78c9d0b..5aac7a0b 100644 --- a/Sources/arm/Context.hx +++ b/Sources/arm/Context.hx @@ -11,6 +11,7 @@ import iron.data.MaterialData; import arm.data.MaterialSlot; import arm.data.LayerSlot; import arm.data.BrushSlot; +import arm.data.FontSlot; import arm.util.UVUtil; import arm.util.RenderUtil; import arm.util.ParticleUtil; @@ -30,6 +31,7 @@ class Context { public static var layer: LayerSlot; public static var layerIsMask = false; // Mask selected for active layer public static var brush: BrushSlot; + public static var font: FontSlot; public static var texture: TAsset = null; public static var object: Object; public static var paintObject: MeshObject; @@ -116,7 +118,6 @@ class Context { public static var textToolImage: Image = null; public static var textToolText: String; - public static var textToolHandle = new Handle(); public static var particleMaterial: MaterialData = null; public static var layerFilter = 0; @@ -284,6 +285,20 @@ class Context { UINodes.inst.hwnd.redraws = 2; } + public static function selectFont(i: Int) { + if (Project.fonts.length <= i) return; + setFont(Project.fonts[i]); + } + + public static function setFont(f: FontSlot) { + if (Project.fonts.indexOf(f) == -1) return; + font = f; + RenderUtil.makeTextPreview(); + RenderUtil.makeDecalPreview(); + UISidebar.inst.hwnd2.redraws = 2; + UIView2D.inst.hwnd.redraws = 2; + } + public static function setLayer(l: LayerSlot, isMask = false) { if (l == layer && layerIsMask == isMask) return; layer = l; diff --git a/Sources/arm/Enums.hx b/Sources/arm/Enums.hx index d2c5d5ee..083d992c 100644 --- a/Sources/arm/Enums.hx +++ b/Sources/arm/Enums.hx @@ -183,6 +183,7 @@ package arm; @:enum abstract View2DType(Int) from Int to Int { var View2DLayer = 0; var View2DAsset = 1; + var View2DFont = 2; } @:enum abstract BorderSide(Int) from Int to Int { diff --git a/Sources/arm/Project.hx b/Sources/arm/Project.hx index cdf3b51e..6d448119 100644 --- a/Sources/arm/Project.hx +++ b/Sources/arm/Project.hx @@ -20,6 +20,7 @@ import arm.ui.UIBox; import arm.ui.UINodes; import arm.data.LayerSlot; import arm.data.BrushSlot; +import arm.data.FontSlot; import arm.data.MaterialSlot; import arm.node.MaterialParser; import arm.io.ImportAsset; @@ -43,6 +44,7 @@ class Project { public static var materialsScene: Array = null; public static var brushes: Array = null; public static var layers: Array = null; + public static var fonts: Array = null; public static var paintObjects: Array = null; public static var assetMap = new Map(); // kha.Image | kha.Font #if arm_world @@ -209,6 +211,8 @@ class Project { Context.material = materials[0]; brushes = [new BrushSlot()]; Context.brush = brushes[0]; + fonts = [new FontSlot("default.ttf", App.font)]; + Context.font = fonts[0]; History.reset(); diff --git a/Sources/arm/data/FontSlot.hx b/Sources/arm/data/FontSlot.hx new file mode 100644 index 00000000..017a229a --- /dev/null +++ b/Sources/arm/data/FontSlot.hx @@ -0,0 +1,21 @@ +package arm.data; + +import haxe.Json; +import kha.Image; +import kha.Blob; +import zui.Nodes; +import iron.data.Data; + +class FontSlot { + public var image: Image = null; // 200px + public var previewReady = false; + public var id = 0; + public var font: kha.Font; + public var name: String; + + public function new(name: String, font: kha.Font) { + for (slot in Project.fonts) if (slot.id >= id) id = slot.id + 1; + this.name = name; + this.font = font; + } +} diff --git a/Sources/arm/io/ImportFont.hx b/Sources/arm/io/ImportFont.hx index 6499855c..19187699 100644 --- a/Sources/arm/io/ImportFont.hx +++ b/Sources/arm/io/ImportFont.hx @@ -3,18 +3,26 @@ package arm.io; import kha.Font; import iron.data.Data; import arm.sys.Path; +import arm.ui.UISidebar; +import arm.data.FontSlot; +import arm.util.RenderUtil; class ImportFont { - public static var fontList = ["default.ttf"]; - public static var fontMap = new Map(); - public static function run(path: String) { Data.getFont(path, function(font: Font) { var ar = path.split(Path.sep); var name = ar[ar.length - 1]; - fontList.push(name); - fontMap.set(name, font); + Context.font = new FontSlot(name, font); + Project.fonts.push(Context.font); + + function makeFontPreview(_) { + RenderUtil.makeFontPreview(); + iron.App.removeRender(makeFontPreview); + } + iron.App.notifyOnRender(makeFontPreview); + + UISidebar.inst.hwnd2.redraws = 2; }); } } diff --git a/Sources/arm/ui/TabFonts.hx b/Sources/arm/ui/TabFonts.hx index 70ff869a..b9468385 100644 --- a/Sources/arm/ui/TabFonts.hx +++ b/Sources/arm/ui/TabFonts.hx @@ -2,6 +2,7 @@ package arm.ui; import zui.Zui; import zui.Id; +import iron.system.Time; import arm.io.ImportFont; class TabFonts { @@ -10,13 +11,80 @@ class TabFonts { public static function draw() { var ui = UISidebar.inst.ui; if (ui.tab(UISidebar.inst.htab2, tr("Fonts"))) { - ui.row([1 / 4]); + ui.row([1 / 4, 1 / 4]); if (ui.button(tr("Import"))) Project.importAsset("ttf"); if (ui.isHovered) ui.tooltip(tr("Import font file") + ' (${Config.keymap.file_import_assets})'); - for (f in ImportFont.fontList) { - ui.text(f); + if (ui.button(tr("2D View"))) { + UISidebar.inst.show2DView(View2DFont); + } + + var slotw = Std.int(51 * ui.SCALE()); + var num = Std.int(UISidebar.inst.windowW / slotw); + + for (row in 0...Std.int(Math.ceil(Project.fonts.length / num))) { + ui.row([for (i in 0...num) 1 / num]); + + ui._x += 2; + if (row > 0) ui._y += 6; + + for (j in 0...num) { + var imgw = Std.int(50 * ui.SCALE()); + var i = j + row * num; + if (i >= Project.fonts.length) { + @:privateAccess ui.endElement(imgw); + continue; + } + var img = Project.fonts[i].image; + + if (Context.font == Project.fonts[i]) { + // ui.fill(1, -2, img.width + 3, img.height + 3, ui.t.HIGHLIGHT_COL); // TODO + var off = row % 2 == 1 ? 1 : 0; + var w = 50; + if (Config.raw.window_scale > 1) w += Std.int(Config.raw.window_scale * 2); + ui.fill(-1, -2, w + 3, 2, ui.t.HIGHLIGHT_COL); + ui.fill(-1, w - off, w + 3, 2 + off, ui.t.HIGHLIGHT_COL); + ui.fill(-1, -2, 2, w + 3, ui.t.HIGHLIGHT_COL); + ui.fill(w + 1, -2, 2, w + 4, ui.t.HIGHLIGHT_COL); + } + + var tile = ui.SCALE() > 1 ? 100 : 50; + var state = State.Idle; + if (Project.fonts[i].previewReady) { + // ui.g.pipeline = UIView2D.inst.pipe; // L8 + // #if kha_opengl + // ui.currentWindow.texture.g4.setPipeline(UIView2D.inst.pipe); + // #end + // ui.currentWindow.texture.g4.setInt(UIView2D.inst.channelLocation, 1); + state = ui.image(img); + // ui.g.pipeline = null; + } + else { + state = ui.image(Res.get("icons.k"), -1, null, tile * 6, tile, tile, tile); + } + + if (state == State.Started) { + if (Context.font != Project.fonts[i]) Context.selectFont(i); + if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(View2DFont); + Context.selectTime = Time.time(); + } + if (ui.isHovered && ui.inputReleasedR) { + var add = Project.fonts.length > 1 ? 1 : 0; + UIMenu.draw(function(ui: Zui) { + ui.text(Project.fonts[i].name, Right, ui.t.HIGHLIGHT_COL); + + if (Project.fonts.length > 1 && ui.button(tr("Delete"), Left)) { + Context.selectFont(i == 0 ? 1 : 0); + Project.fonts.splice(i, 1); + UISidebar.inst.hwnd2.redraws = 2; + } + }, 1 + add); + } + if (ui.isHovered && img != null) ui.tooltipImage(img); + } + + ui._y += 6; } } } diff --git a/Sources/arm/ui/TabLayers.hx b/Sources/arm/ui/TabLayers.hx index 95fd756c..dce4b9a5 100644 --- a/Sources/arm/ui/TabLayers.hx +++ b/Sources/arm/ui/TabLayers.hx @@ -32,7 +32,7 @@ class TabLayers { Layers.newLayer(); History.newLayer(); } - if (ui.button(tr("2D View"))) UISidebar.inst.show2DView(); + if (ui.button(tr("2D View"))) UISidebar.inst.show2DView(View2DLayer); else if (ui.isHovered) ui.tooltip(tr("Show 2D View") + ' (${Config.keymap.toggle_node_editor})'); var ar = [tr("All")]; @@ -163,7 +163,7 @@ class TabLayers { } if (state == State.Started) { Context.setLayer(l); - if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(); + if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(View2DLayer); Context.selectTime = Time.time(); if (l.getChildren() == null) { var mouse = Input.getMouse(); @@ -225,7 +225,7 @@ class TabLayers { } if (state == State.Started) { Context.setLayer(l, true); - if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(); + if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(View2DLayer); Context.selectTime = Time.time(); var mouse = Input.getMouse(); App.dragOffX = -(mouse.x - uix - ui._windowX - 3); @@ -242,7 +242,7 @@ class TabLayers { if (state == State.Started) { Context.setLayer(l); - if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(); + if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(View2DLayer); Context.selectTime = Time.time(); } diff --git a/Sources/arm/ui/TabTextures.hx b/Sources/arm/ui/TabTextures.hx index 5fcd7f42..3dd946e5 100644 --- a/Sources/arm/ui/TabTextures.hx +++ b/Sources/arm/ui/TabTextures.hx @@ -23,7 +23,7 @@ class TabTextures { } if (ui.isHovered) ui.tooltip(tr("Import texture file") + ' (${Config.keymap.file_import_assets})'); - if (ui.button(tr("2D View"))) UISidebar.inst.show2DView(1); + if (ui.button(tr("2D View"))) UISidebar.inst.show2DView(View2DAsset); if (Project.assets.length > 0) { @@ -56,7 +56,7 @@ class TabTextures { App.dragAsset = asset; Context.texture = asset; - if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(1); + if (Time.time() - Context.selectTime < 0.25) UISidebar.inst.show2DView(View2DAsset); Context.selectTime = Time.time(); UIView2D.inst.hwnd.redraws = 2; } diff --git a/Sources/arm/ui/UIHeader.hx b/Sources/arm/ui/UIHeader.hx index 0fe4a3b5..400f2805 100644 --- a/Sources/arm/ui/UIHeader.hx +++ b/Sources/arm/ui/UIHeader.hx @@ -214,11 +214,10 @@ class UIHeader { } } if (Context.tool == ToolText) { - ui.combo(Context.textToolHandle, ImportFont.fontList, tr("Font")); var h = Id.handle(); h.text = Context.textToolText; Context.textToolText = ui.textInput(h, ""); - if (h.changed || Context.textToolHandle.changed) { + if (h.changed) { ui.g.end(); RenderUtil.makeTextPreview(); RenderUtil.makeDecalPreview(); diff --git a/Sources/arm/ui/UISidebar.hx b/Sources/arm/ui/UISidebar.hx index d1231047..ed95336a 100644 --- a/Sources/arm/ui/UISidebar.hx +++ b/Sources/arm/ui/UISidebar.hx @@ -21,6 +21,7 @@ import arm.util.ViewportUtil; import arm.util.UVUtil; import arm.data.LayerSlot; import arm.data.BrushSlot; +import arm.data.FontSlot; import arm.data.MaterialSlot; import arm.io.ImportFont; import arm.io.ExportTexture; @@ -88,6 +89,12 @@ class UISidebar { Context.parseBrushInputs(); } + if (Project.fonts == null) { + Project.fonts = []; + Project.fonts.push(new FontSlot("default.ttf", App.font)); + Context.font = Project.fonts[0]; + } + if (Project.layers == null) { Project.layers = []; Project.layers.push(new LayerSlot()); @@ -221,7 +228,7 @@ class UISidebar { Context.setLayer(Project.layers[i]); } else if (Operator.shortcut(Config.keymap.toggle_2d_view)) { - show2DView(); + show2DView(View2DLayer); } else if (Operator.shortcut(Config.keymap.toggle_node_editor)) { UINodes.inst.canvasType == CanvasMaterial ? showMaterialNodes() : showBrushNodes(); @@ -838,7 +845,7 @@ class UISidebar { App.resize(); } - public function show2DView(type = 0) { + public function show2DView(type: View2DType) { // Clear input state as ui receives input events even when not drawn @:privateAccess UIView2D.inst.ui.endInput(); if (UIView2D.inst.type != type) UIView2D.inst.show = true; diff --git a/Sources/arm/ui/UIView2D.hx b/Sources/arm/ui/UIView2D.hx index aaa44675..cde60446 100644 --- a/Sources/arm/ui/UIView2D.hx +++ b/Sources/arm/ui/UIView2D.hx @@ -11,6 +11,7 @@ import zui.Zui; import zui.Id; import iron.system.Input; import arm.util.UVUtil; +import arm.util.RenderUtil; import arm.render.RenderPathPaint; import arm.Enums; @@ -84,6 +85,9 @@ class UIView2D { // Ensure UV map is drawn if (uvmapShow) UVUtil.cacheUVMap(); + // Ensure font image is drawn + if (Context.font.image == null) RenderUtil.makeFontPreview(); + ui.begin(g); wh = iron.App.h(); if (UINodes.inst.show) { @@ -121,9 +125,13 @@ class UIView2D { texType == TexNormal ? 5 : 0; } - else { // View2DAsset + else if (type == View2DAsset) { tex = UISidebar.inst.getImage(Context.texture); } + else { // View2DFont + tex = Context.font.image; + tw = tex.width; + } var th = tw; if (tex != null) { @@ -184,7 +192,7 @@ class UIView2D { h.text = l.name; l.name = ui.textInput(h, "", Right); } - else { + else if (type == View2DAsset) { var asset = Context.texture; if (asset != null) { var assetNames = Project.assetNames; @@ -194,6 +202,10 @@ class UIView2D { assetNames[i] = asset.name; } } + else { // View2DFont + h.text = Context.font.name; + Context.font.name = ui.textInput(h, "", Right); + } if (h.changed) UISidebar.inst.hwnd.redraws = 2; ui.t.ACCENT_COL = ACCENT_COL; diff --git a/Sources/arm/util/RenderUtil.hx b/Sources/arm/util/RenderUtil.hx index 402b4157..2b6dbbc5 100644 --- a/Sources/arm/util/RenderUtil.hx +++ b/Sources/arm/util/RenderUtil.hx @@ -95,6 +95,9 @@ class RenderUtil { } public static function makeDecalPreview() { + var current = @:privateAccess kha.graphics4.Graphics2.current; + if (current != null) current.end(); + if (Context.decalImage == null) { Context.decalImage = Image.createRenderTarget(RenderUtil.decalPreviewSize, RenderUtil.decalPreviewSize); } @@ -153,11 +156,16 @@ class RenderUtil { MaterialParser.parseMeshMaterial(); Context.ddirty = 0; + + if (current != null) current.begin(false); } public static function makeTextPreview() { + var current = @:privateAccess kha.graphics4.Graphics2.current; + if (current != null) current.end(); + var text = Context.textToolText; - var font = getTextToolFont(); + var font = Context.font.font; var fontSize = 200; var textW = Std.int(font.width(fontSize, text)); var textH = Std.int(font.height(fontSize)); @@ -177,12 +185,33 @@ class RenderUtil { g2.color = 0xffffffff; g2.drawString(text, texW / 2 - textW / 2, texW / 2 - textH / 2); g2.end(); + + if (current != null) current.begin(false); } - static function getTextToolFont(): Font { - var fontName = ImportFont.fontList[Context.textToolHandle.position]; - if (fontName == "default.ttf") return arm.ui.UISidebar.inst.ui.ops.font; - return ImportFont.fontMap.get(fontName); + public static function makeFontPreview() { + var current = @:privateAccess kha.graphics4.Graphics2.current; + if (current != null) current.end(); + + var text = "Abg"; + var font = Context.font.font; + var fontSize = 120; + var textW = Std.int(font.width(fontSize, text)) + 8; + var textH = Std.int(font.height(fontSize)) + 8; + if (Context.font.image == null) { + // Context.font.image = Image.createRenderTarget(200, 200, TextureFormat.L8); + Context.font.image = Image.createRenderTarget(200, 200, TextureFormat.RGBA32); + } + var g2 = Context.font.image.g2; + g2.begin(true, 0x00000000); + g2.font = font; + g2.fontSize = fontSize; + g2.color = 0xffffffff; + g2.drawString(text, 200 / 2 - textW / 2, 200 / 2 - textH / 2); + g2.end(); + Context.font.previewReady = true; + + if (current != null) current.begin(false); } public static function makeBrushPreview() {