alphabet editor stuff

i still need a way to add spritesheets
This commit is contained in:
SrtHero278
2025-08-10 11:32:36 -07:00
parent 9757b002bd
commit 689eda7114
5 changed files with 227 additions and 88 deletions
+1
View File
@@ -488,6 +488,7 @@
<str id="newGlyph">New Glyph</str> <str id="newGlyph">New Glyph</str>
<str id="editGlyph">Edit Glyph</str> <str id="editGlyph">Edit Glyph</str>
<str id="deleteGlyph">Delete Glyph</str> <str id="deleteGlyph">Delete Glyph</str>
<str id="deleteCurGlyph">Delete Current Glyph</str>
</group> </group>
<str id="topBar.offset">Offsets</str> <str id="topBar.offset">Offsets</str>
+104 -22
View File
@@ -43,6 +43,11 @@ class AlphabetEditor extends UIState {
public var queueReorder:Bool = false; public var queueReorder:Bool = false;
public var componentList:UIButtonList<ComponentButton>; public var componentList:UIButtonList<ComponentButton>;
public var glyphCreateWindow:UISliceSprite;
public var glyphChar:UITextBox;
public var confirmGlyph:UIButton;
public var deleteGlyph:UIButton;
public var infoWindow:GlyphInfoWindow; public var infoWindow:GlyphInfoWindow;
public var curSelectedComponent:AlphabetComponent = null; public var curSelectedComponent:AlphabetComponent = null;
public var curSelectedData:AlphabetLetterData = null; public var curSelectedData:AlphabetLetterData = null;
@@ -83,13 +88,18 @@ class AlphabetEditor extends UIState {
{ {
label: translate("topBar.edit"), label: translate("topBar.edit"),
childs: [ childs: [
{ // TODO: add redo and undo
/*{
label: translate("edit.undo"), label: translate("edit.undo"),
// TODO: add undo onSelect: null
}, },
{ {
label: translate("edit.redo"), label: translate("edit.redo"),
// TODO: add redo onSelect: null
},*/
{
label: translate("glyph.deleteCurGlyph"),
}, },
{ {
label: "Edit Main Data", // TODO: add translations label: "Edit Main Data", // TODO: add translations
@@ -97,23 +107,6 @@ class AlphabetEditor extends UIState {
} }
] ]
}, },
{
label: translate("topBar.glyph"),
childs: [
{
label: translate("glyph.newGlyph"),
//onSelect: _glyph_new
},
{
label: translate("glyph.editGlyph"),
//onSelect: _glyph_edit
},
{
label: translate("glyph.deleteGlyph"),
//onSelect: _glyph_delete
}
]
},
{ {
label: translate("topBar.view"), label: translate("topBar.view"),
childs: [ childs: [
@@ -188,6 +181,67 @@ class AlphabetEditor extends UIState {
brokenWarning.color = 0xFFFF6969; brokenWarning.color = 0xFFFF6969;
add(brokenWarning); add(brokenWarning);
glyphCreateWindow = new UISliceSprite(FlxG.width - 15, topMenuSpr.bHeight + 15, 200, 150, "editors/ui/context-bg");
glyphCreateWindow.x -= glyphCreateWindow.bWidth;
uiGroup.add(glyphCreateWindow);
glyphChar = new UITextBox(glyphCreateWindow.x + 15, glyphCreateWindow.y + 15, "", glyphCreateWindow.bWidth - 30);
glyphCreateWindow.members.push(glyphChar);
confirmGlyph = new UIButton(glyphChar.x, glyphChar.y + glyphChar.bHeight + 15, translate("glyph.newGlyph"), function() {
if (deleteGlyph.selectable) {
curLetter = tape.manualLetters.indexOf(lastChar) + charsForDefault.length;
changeLetter(0);
} else {
tape.manualLetters.push(lastChar);
tape.text = "";
for (def in charsForDefault)
tape.text += def[Std.int(Math.floor(defaultTmr) % def.length)] + " ";
tape.text += tape.manualLetters.join(" ");
for (i in 0...tape.fastGetData(lastChar).components.length) {
var anim = bigLetter.text + i;
bigLetter.animation.remove(anim);
tape.animation.remove(anim);
}
tape.letterData.set(lastChar, {
isDefault: false,
advance: Math.NaN,
advanceEmpty: true,
components: [],
startIndex: 0
});
curLetter = tape.manualLetters.length - 1 + charsForDefault.length;
changeLetter(0);
}
}, glyphChar.bWidth);
confirmGlyph.selectable = false;
glyphCreateWindow.members.push(confirmGlyph);
deleteGlyph = new UIButton(glyphChar.x, confirmGlyph.y + confirmGlyph.bHeight + 5, translate("glyph.deleteGlyph"), function() {
final charIdx = tape.manualLetters.indexOf(lastChar);
tape.manualLetters.splice(charIdx, 1);
tape.text = "";
for (def in charsForDefault)
tape.text += def[Std.int(Math.floor(defaultTmr) % def.length)] + " ";
tape.text += tape.manualLetters.join(" ");
for (i in 0...tape.fastGetData(lastChar).components.length) {
var anim = bigLetter.text + i;
bigLetter.animation.remove(anim);
tape.animation.remove(anim);
}
tape.letterData.remove(lastChar);
changeLetter((curLetter >= charIdx + charsForDefault.length) ? -1 : 0);
}, glyphChar.bWidth);
deleteGlyph.color = FlxColor.RED;
deleteGlyph.selectable = false;
glyphCreateWindow.members.push(deleteGlyph);
infoWindow = new GlyphInfoWindow(); infoWindow = new GlyphInfoWindow();
uiGroup.add(infoWindow); uiGroup.add(infoWindow);
@@ -247,8 +301,29 @@ class AlphabetEditor extends UIState {
} }
} }
var lastChar:String = "";
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
super.update(elapsed); super.update(elapsed);
if (glyphChar.label.text != lastChar) {
if (glyphChar.label.text == "") {
lastChar = "";
confirmGlyph.selectable = false;
deleteGlyph.selectable = false;
confirmGlyph.field.text = translate("glyph.newGlyph");
} else {
glyphChar.label.text = lastChar = switch (tape.forceCase) {
case UPPER: glyphChar.label.text.charAt(glyphChar.label.text.length - 1).toUpperCase();
case LOWER: glyphChar.label.text.charAt(glyphChar.label.text.length - 1).toLowerCase();
case NONE: glyphChar.label.text.charAt(glyphChar.label.text.length - 1);
};
confirmGlyph.selectable = true;
deleteGlyph.selectable = tape.manualLetters.contains(lastChar);
confirmGlyph.field.text = translate(deleteGlyph.selectable ? "glyph.editGlyph" : "glyph.newGlyph");
}
}
if (queueReorder) { if (queueReorder) {
queueReorder = false; queueReorder = false;
var outlines = []; var outlines = [];
@@ -344,6 +419,7 @@ class AlphabetEditor extends UIState {
curLetter = CoolUtil.positiveModuloInt(curLetter + inc, tape.manualLetters.length + charsForDefault.length); curLetter = CoolUtil.positiveModuloInt(curLetter + inc, tape.manualLetters.length + charsForDefault.length);
targetX = FlxG.width * 0.5 - tape.defaultAdvance * (0.5 + curLetter * 2); targetX = FlxG.width * 0.5 - tape.defaultAdvance * (0.5 + curLetter * 2);
bigLetter.text = (curLetter < charsForDefault.length) ? charsForDefault[curLetter][0] : tape.manualLetters[curLetter - charsForDefault.length]; bigLetter.text = (curLetter < charsForDefault.length) ? charsForDefault[curLetter][0] : tape.manualLetters[curLetter - charsForDefault.length];
glyphChar.label.text = bigLetter.text;
bigLetter.updateHitbox(); bigLetter.updateHitbox();
bigLetter.screenCenter(); bigLetter.screenCenter();
@@ -396,11 +472,17 @@ class AlphabetEditor extends UIState {
changeLetter(1); changeLetter(1);
} }
function buildAlphabet() {
var tempPrettyPrint = true;
var xmlThingYea:String = "<!DOCTYPE codename-engine-alphabet-font>\n" + Printer.print(tape.buildXML(), tempPrettyPrint);
return tempPrettyPrint ? xmlThingYea : xmlThingYea.replace("\n", "");
}
function _file_save(_) { function _file_save(_) {
#if sys #if sys
CoolUtil.safeSaveFile( CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/data/alphabet/${__typeface}.xml', '${Paths.getAssetsRoot()}/data/alphabet/${__typeface}.xml',
""//alphabet.buildXML() buildAlphabet()
); );
#else #else
_file_saveas(_); _file_saveas(_);
@@ -408,7 +490,7 @@ class AlphabetEditor extends UIState {
} }
function _file_saveas(_) { function _file_saveas(_) {
openSubState(new SaveSubstate(""/*alphabet.buildXML()*/, { openSubState(new SaveSubstate(buildAlphabet(), {
defaultSaveFile: '${__typeface}.xml' defaultSaveFile: '${__typeface}.xml'
})); }));
} }
@@ -43,14 +43,11 @@ class AlphabetIconOption extends TextOption {
var spritesheet = null; var spritesheet = null;
for (node in xml.elements()) { for (node in xml.elements()) {
if (node.nodeName == "spritesheet") { if (node.nodeName == "spritesheet") {
spritesheet = node.firstChild().nodeValue; spritesheet = node.firstChild().nodeValue.trim();
break; break;
} }
} }
var useColorOffsets = xml.get("useColorOffsets").getDefault("false") == "true";
// todo fix crash if invalid spritesheet; // todo fix crash if invalid spritesheet;
iconSpr = new FlxSprite(); iconSpr = new FlxSprite();
@@ -64,7 +61,7 @@ class AlphabetIconOption extends TextOption {
} }
} }
iconSpr.frame = frameToUse; iconSpr.frame = frameToUse;
if (useColorOffsets) { if (xml.get("colorMode") == "offsets") {
iconSpr.colorTransform.color = -1; iconSpr.colorTransform.color = -1;
} }
iconSpr.setPosition(90 - iconSpr.width - 20, (__text.height - iconSpr.height) / 2); iconSpr.setPosition(90 - iconSpr.width - 20, (__text.height - iconSpr.height) / 2);
@@ -60,7 +60,7 @@ class GlyphInfoWindow extends UIWindow {
xBox = new UINumericStepper(prefixBox.x, prefixBox.y + prefixBox.bHeight + itemMargin + labelOffset, 0, 1, 2, null, null, 80); xBox = new UINumericStepper(prefixBox.x, prefixBox.y + prefixBox.bHeight + itemMargin + labelOffset, 0, 1, 2, null, null, 80);
xBox.onChange = valueSet.bind(xBox, function(val) { // kinda dumb but blame cne ui xBox.onChange = valueSet.bind(xBox, function(val) { // kinda dumb but blame cne ui
compon.x = val; compon.x = -val;
}); });
members.push(xBox); members.push(xBox);
@@ -121,7 +121,7 @@ class GlyphInfoWindow extends UIWindow {
members.push(colorModeDrop); members.push(colorModeDrop);
addLabelOn(colorModeDrop, "Color Mode"); addLabelOn(colorModeDrop, "Color Mode");
outlineCheck = new UICheckbox(colorModeDrop.x + colorModeDrop.bWidth + itemMargin * 2, colorModeDrop.y + 4, "Use Outline?"); outlineCheck = new UICheckbox(colorModeDrop.x + colorModeDrop.bWidth + itemMargin * 2, colorModeDrop.y + 10, "Use Outline?");
outlineCheck.onChecked = function(val) { outlineCheck.onChecked = function(val) {
targetPercent = val ? 1 : 0; targetPercent = val ? 1 : 0;
@@ -156,10 +156,12 @@ class GlyphInfoWindow extends UIWindow {
}; };
data.components.insert(AlphabetEditor.instance.outlineIdx, newOutline); data.components.insert(AlphabetEditor.instance.outlineIdx, newOutline);
++AlphabetEditor.instance.outlineIdx;
++data.startIndex; ++data.startIndex;
} else { } else {
compon.outIndex = null; compon.outIndex = null;
data.components.splice(AlphabetEditor.instance.outlineIdx - 1, 1); data.components.splice(AlphabetEditor.instance.outlineIdx - 1, 1);
--AlphabetEditor.instance.outlineIdx;
--data.startIndex; --data.startIndex;
} }
} }
@@ -254,7 +256,7 @@ class GlyphInfoWindow extends UIWindow {
} }
prefixBox.label.text = com.anim; prefixBox.label.text = com.anim;
xBox.value = com.x; xBox.value = -com.x;
yBox.value = com.y; yBox.value = com.y;
scaleXBox.value = com.scaleX; scaleXBox.value = com.scaleX;
scaleYBox.value = com.scaleY; scaleYBox.value = com.scaleY;
@@ -277,11 +279,11 @@ class GlyphInfoWindow extends UIWindow {
targetPercent = 1; targetPercent = 1;
} }
for (item in members) { for (item in [prefixBox, scaleXBox, scaleYBox, angleBox, flipXBox, flipYBox])
if (item is UISprite) item.selectable = true;
cast(item, UISprite).selectable = true; for (item in [xBox, yBox, colorModeDrop, outlineCheck, outlineBox, outlineXBox, outlineYBox])
} item.selectable = !data.isDefault;
colorModeDrop.dropButton.selectable = true; colorModeDrop.dropButton.selectable = colorModeDrop.selectable;
} }
function valueSet(item:UINumericStepper, func:Dynamic, text:String) { function valueSet(item:UINumericStepper, func:Dynamic, text:String) {
+99 -42
View File
@@ -163,7 +163,7 @@ class Alphabet extends FlxSprite {
}; };
var manualLetters:Array<String> = []; var manualLetters:Array<String> = [];
var failedLetters:Array<String> = []; var failedLetters:Array<String> = [];
var failedOutlines:Array<String> = []; var sheets:Array<String> = [];
public var renderMode:AlphabetRenderMode = DEFAULT; public var renderMode:AlphabetRenderMode = DEFAULT;
@@ -321,7 +321,7 @@ class Alphabet extends FlxSprite {
if (!isOnScreen(camera)) { if (!isOnScreen(camera)) {
frameOffset.y -= offsetY; frameOffset.y -= offsetY;
frameOffset.x -= offsetX; frameOffset.x -= offsetX;
break; continue;
} }
if (__component.hasColorMode) if (__component.hasColorMode)
@@ -436,10 +436,8 @@ class Alphabet extends FlxSprite {
if (anim == null) if (anim == null)
return defaultAdvance; return defaultAdvance;
if (data.advanceEmpty && !data.isDefault) { if (data.advanceEmpty && !data.isDefault)
data.advanceEmpty = false;
data.advance = frames.frames[anim.frames[0]].sourceSize.x; data.advance = frames.frames[anim.frames[0]].sourceSize.x;
}
return (data.isDefault) ? frames.frames[anim.frames[0]].sourceSize.x : data.advance; return (data.isDefault) ? frames.frames[anim.frames[0]].sourceSize.x : data.advance;
} }
@@ -514,28 +512,17 @@ class Alphabet extends FlxSprite {
return animation.getByName(name); return animation.getByName(name);
} }
/*function getLetterOutline(char:String, component:AlphabetComponent, index:Int) {
var name = char + "Outline" + Std.string(index);
if (failedOutlines.contains(name)) return null;
if (animation.exists(name)) return animation.getByName(name);
animation.addByPrefix(name, component.outline.anim, fps);
if (!animation.exists(name)) {
failedOutlines.push(name);
return null;
}
return animation.getByName(name);
}*/
function checkNode(node:Xml):Void { function checkNode(node:Xml):Void {
switch (node.nodeName) { switch (node.nodeName) {
case "spritesheet": case "spritesheet":
final sheet = node.firstChild().nodeValue.trim();
if (frames == null) if (frames == null)
frames = Paths.getFrames(node.firstChild().nodeValue); frames = Paths.getFrames(sheet);
else { else {
for (frame in Paths.getFrames(node.firstChild().nodeValue).frames) for (frame in Paths.getFrames(sheet).frames)
frames.pushFrame(frame); frames.pushFrame(frame);
} }
sheets.push(sheet);
case "defaultAnim": case "defaultAnim":
var idx = ["UPPER", "LOWER"].indexOf(node.get("casing").toUpperCase()) + 1; var idx = ["UPPER", "LOWER"].indexOf(node.get("casing").toUpperCase()) + 1;
@@ -549,7 +536,7 @@ class Alphabet extends FlxSprite {
advance: 0.0, advance: 0.0,
advanceEmpty: true, advanceEmpty: true,
components: [{ components: [{
anim: node.firstChild().nodeValue, anim: node.firstChild().nodeValue.trim(),
x: 0.0, x: 0.0,
y: 0.0, y: 0.0,
@@ -705,7 +692,7 @@ class Alphabet extends FlxSprite {
components.push({ components.push({
outIndex: (node.get("hasOutline") == "true") ? 0 : null, outIndex: (node.get("hasOutline") == "true") ? 0 : null,
anim: node.firstChild().nodeValue, anim: node.firstChild().nodeValue.trim(),
x: xOff, x: xOff,
y: yOff, y: yOff,
@@ -766,6 +753,8 @@ class Alphabet extends FlxSprite {
v[2] = []; v[2] = [];
v; v;
} }
sheets = [];
manualLetters = [];
failedLetters = [" "]; failedLetters = [" "];
defaultAdvance = Std.parseFloat(xml.get("advance")).getDefaultFloat(40.0); defaultAdvance = Std.parseFloat(xml.get("advance")).getDefaultFloat(40.0);
@@ -781,34 +770,102 @@ class Alphabet extends FlxSprite {
checkNode(node); checkNode(node);
} }
private static var alphabetProperties:Array<String> = ["fps", "advance", "lineGap", "forceCasing", "useColorOffsets", "antialiasing"]; private static var alphabetProperties:Array<String> = ["fps", "advance", "lineGap", "forceCasing", "colorMode", "antialiasing"];
private static var componentProperties:Array<String> = ["name", "anim", "x", "y", "scaleX", "scaleY", "angle", "offsetX", "offsetY", "flipX", "flipY"]; private static var componentProperties:Array<String> = ["char", "advance", "anim", "x", "y", "scaleX", "scaleY", "flipX", "flipY", "angle", "colorMode", "hasOutline", "outline", "outlineX", "outlineY"];
public function buildXML():Xml { public function buildXML():Xml {
var xml = Xml.createElement("alphabet"); var xml = Xml.createElement("alphabetFont");
xml.set("fps", Std.string(fps)); xml.set("fps", Std.string(fps));
xml.set("advance", Std.string(defaultAdvance)); xml.set("advance", Std.string(defaultAdvance));
xml.set("lineGap", Std.string(lineGap)); xml.set("lineGap", Std.string(lineGap));
xml.set("forceCasing", ["none", "upper", "lower"][forceCase]); xml.set("forceCasing", ["none", "upper", "lower"][forceCase]);
xml.set("useColorOffsets", ["tint", "offsets", "none"][colorMode]); xml.set("colorMode", ["tint", "offsets", "none"][colorMode]);
xml.set("antialiasing", antialiasing ? "true" : "false"); xml.set("antialiasing", antialiasing ? "true" : "false");
xml.attributeOrder = alphabetProperties; xml.attributeOrder = alphabetProperties;
/*for (component in components) { for (sheet in sheets) {
var componentXml = Xml.createElement("component"); var sheetNode = Xml.createElement("spritesheet");
componentXml.attributeOrder = componentProperties; sheetNode.addChild(Xml.createPCData(sheet));
componentXml.set("name", component.name); xml.addChild(sheetNode);
componentXml.set("anim", component.anim); }
componentXml.set("x", Std.string(component.x));
componentXml.set("y", Std.string(component.y)); for (i in 0...3) {
if(component.scaleX != 1) componentXml.set("scaleX", Std.string(component.scaleX)); if (defaults[i] == null) continue;
if(component.scaleY != 1) componentXml.set("scaleY", Std.string(component.scaleY));
if(component.angle != 0) componentXml.set("angle", Std.string(component.angle)); var compon = defaults[i].components[0];
if(component.offsetX != 0) componentXml.set("offsetX", Std.string(component.offsetX)); var node = Xml.createElement("defaultAnim");
if(component.offsetY != 0) componentXml.set("offsetY", Std.string(component.offsetY)); node.addChild(Xml.createPCData(compon.anim));
xml.addChild(componentXml); if (i != 0)
}*/ node.set("casing", ["upper", "lower"][i - 1]);
if (compon.scaleX != 1.0 || compon.scaleY != 1.0) {
node.set("scaleX", Std.string(compon.scaleX));
node.set("scaleY", Std.string(compon.scaleY));
}
if (compon.flipX || compon.flipY) {
node.set("flipX", Std.string(compon.flipX));
node.set("flipY", Std.string(compon.flipY));
}
if (compon.angle != 0.0)
node.set("angle", Std.string(compon.angle));
node.attributeOrder = componentProperties;
xml.addChild(node);
}
for (let in manualLetters) {
var data = fastGetData(let);
var node = Xml.createElement(data.components.length - data.startIndex > 1 ? "composite" : "anim");
node.set("char", let);
if (!data.advanceEmpty)
node.set("advance", Std.string(data.advance));
for (i in data.startIndex...data.components.length) {
var compon = data.components[i];
var cNode:Xml = node;
if (data.components.length - data.startIndex > 1) {
cNode = Xml.createElement("component");
cNode.set("anim", compon.anim);
node.addChild(cNode);
} else
cNode.addChild(Xml.createPCData(compon.anim));
if (compon.x != 0.0 || compon.y != 0.0) {
cNode.set("x", Std.string(-compon.x));
cNode.set("y", Std.string(compon.y));
}
if (compon.scaleX != 1.0 || compon.scaleY != 1.0) {
cNode.set("scaleX", Std.string(compon.scaleX));
cNode.set("scaleY", Std.string(compon.scaleY));
}
if (compon.flipX || compon.flipY) {
cNode.set("flipX", Std.string(compon.flipX));
cNode.set("flipY", Std.string(compon.flipY));
}
if (compon.angle != 0.0)
cNode.set("angle", Std.string(compon.angle));
if (compon.hasColorMode)
cNode.set("colorMode", ["tint", "offsets", "none"][compon.colorMode]);
if (compon.outIndex != null) {
var outline = data.components[compon.outIndex];
cNode.set("hasOutline", "true");
cNode.set("outline", outline.anim);
if (outline.x != 0.0 || outline.y != 0.0) {
cNode.set("outlineX", Std.string(outline.x));
cNode.set("outlineY", Std.string(outline.y));
}
}
cNode.attributeOrder = componentProperties;
}
node.attributeOrder = componentProperties;
xml.addChild(node);
}
return xml; return xml;
} }
@@ -828,9 +885,9 @@ class Alphabet extends FlxSprite {
this.letterData = from.letterData; this.letterData = from.letterData;
this.defaults = from.defaults; this.defaults = from.defaults;
this.loaded = from.loaded; this.loaded = from.loaded;
this.sheets = from.sheets;
this.manualLetters = from.manualLetters; this.manualLetters = from.manualLetters;
this.failedLetters = from.failedLetters; this.failedLetters = from.failedLetters;
this.failedOutlines = from.failedOutlines;
} }
override function destroy():Void { override function destroy():Void {
@@ -843,7 +900,7 @@ class Alphabet extends FlxSprite {
defaults = null; defaults = null;
manualLetters = null; manualLetters = null;
failedLetters = null; failedLetters = null;
failedOutlines = null; sheets = null;
super.destroy(); super.destroy();
} }