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="editGlyph">Edit Glyph</str>
<str id="deleteGlyph">Delete Glyph</str>
<str id="deleteCurGlyph">Delete Current Glyph</str>
</group>
<str id="topBar.offset">Offsets</str>
+105 -23
View File
@@ -43,6 +43,11 @@ class AlphabetEditor extends UIState {
public var queueReorder:Bool = false;
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 curSelectedComponent:AlphabetComponent = null;
public var curSelectedData:AlphabetLetterData = null;
@@ -83,13 +88,18 @@ class AlphabetEditor extends UIState {
{
label: translate("topBar.edit"),
childs: [
{
// TODO: add redo and undo
/*{
label: translate("edit.undo"),
// TODO: add undo
onSelect: null
},
{
label: translate("edit.redo"),
// TODO: add redo
onSelect: null
},*/
{
label: translate("glyph.deleteCurGlyph"),
},
{
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"),
childs: [
@@ -188,6 +181,67 @@ class AlphabetEditor extends UIState {
brokenWarning.color = 0xFFFF6969;
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();
uiGroup.add(infoWindow);
@@ -208,7 +262,7 @@ class AlphabetEditor extends UIState {
scaleX: 1,
scaleY: 1,
flipX: false,
flipY: false,
@@ -247,8 +301,29 @@ class AlphabetEditor extends UIState {
}
}
var lastChar:String = "";
public override function update(elapsed:Float) {
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) {
queueReorder = false;
var outlines = [];
@@ -344,6 +419,7 @@ class AlphabetEditor extends UIState {
curLetter = CoolUtil.positiveModuloInt(curLetter + inc, tape.manualLetters.length + charsForDefault.length);
targetX = FlxG.width * 0.5 - tape.defaultAdvance * (0.5 + curLetter * 2);
bigLetter.text = (curLetter < charsForDefault.length) ? charsForDefault[curLetter][0] : tape.manualLetters[curLetter - charsForDefault.length];
glyphChar.label.text = bigLetter.text;
bigLetter.updateHitbox();
bigLetter.screenCenter();
@@ -396,11 +472,17 @@ class AlphabetEditor extends UIState {
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(_) {
#if sys
CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/data/alphabet/${__typeface}.xml',
""//alphabet.buildXML()
buildAlphabet()
);
#else
_file_saveas(_);
@@ -408,7 +490,7 @@ class AlphabetEditor extends UIState {
}
function _file_saveas(_) {
openSubState(new SaveSubstate(""/*alphabet.buildXML()*/, {
openSubState(new SaveSubstate(buildAlphabet(), {
defaultSaveFile: '${__typeface}.xml'
}));
}
@@ -43,14 +43,11 @@ class AlphabetIconOption extends TextOption {
var spritesheet = null;
for (node in xml.elements()) {
if (node.nodeName == "spritesheet") {
spritesheet = node.firstChild().nodeValue;
spritesheet = node.firstChild().nodeValue.trim();
break;
}
}
var useColorOffsets = xml.get("useColorOffsets").getDefault("false") == "true";
// todo fix crash if invalid spritesheet;
iconSpr = new FlxSprite();
@@ -64,7 +61,7 @@ class AlphabetIconOption extends TextOption {
}
}
iconSpr.frame = frameToUse;
if (useColorOffsets) {
if (xml.get("colorMode") == "offsets") {
iconSpr.colorTransform.color = -1;
}
iconSpr.setPosition(90 - iconSpr.width - 20, (__text.height - iconSpr.height) / 2);
@@ -10,7 +10,7 @@ class GlyphInfoWindow extends UIWindow {
public var scaleYBox:UINumericStepper;
public var angleBox:UINumericStepper;
public var colorModeDrop:UIDropDown;
public var flipXBox:UICheckbox;
public var flipYBox:UICheckbox;
@@ -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.onChange = valueSet.bind(xBox, function(val) { // kinda dumb but blame cne ui
compon.x = val;
compon.x = -val;
});
members.push(xBox);
@@ -121,7 +121,7 @@ class GlyphInfoWindow extends UIWindow {
members.push(colorModeDrop);
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) {
targetPercent = val ? 1 : 0;
@@ -147,7 +147,7 @@ class GlyphInfoWindow extends UIWindow {
angle: compon.angle,
cos: compon.cos,
sin: compon.sin,
flipX: compon.flipX,
flipY: compon.flipY,
@@ -156,15 +156,17 @@ class GlyphInfoWindow extends UIWindow {
};
data.components.insert(AlphabetEditor.instance.outlineIdx, newOutline);
++AlphabetEditor.instance.outlineIdx;
++data.startIndex;
} else {
compon.outIndex = null;
data.components.splice(AlphabetEditor.instance.outlineIdx - 1, 1);
--AlphabetEditor.instance.outlineIdx;
--data.startIndex;
}
}
members.push(outlineCheck);
flipXBox = new UICheckbox(outlineCheck.x, outlineCheck.y - outlineCheck.height - 8, "Flip X?");
flipXBox.onChecked = function(check:Bool) {
compon.flipX = check;
@@ -254,7 +256,7 @@ class GlyphInfoWindow extends UIWindow {
}
prefixBox.label.text = com.anim;
xBox.value = com.x;
xBox.value = -com.x;
yBox.value = com.y;
scaleXBox.value = com.scaleX;
scaleYBox.value = com.scaleY;
@@ -276,12 +278,12 @@ class GlyphInfoWindow extends UIWindow {
outlineYBox.value = out.y;
targetPercent = 1;
}
for (item in members) {
if (item is UISprite)
cast(item, UISprite).selectable = true;
}
colorModeDrop.dropButton.selectable = true;
for (item in [prefixBox, scaleXBox, scaleYBox, angleBox, flipXBox, flipYBox])
item.selectable = true;
for (item in [xBox, yBox, colorModeDrop, outlineCheck, outlineBox, outlineXBox, outlineYBox])
item.selectable = !data.isDefault;
colorModeDrop.dropButton.selectable = colorModeDrop.selectable;
}
function valueSet(item:UINumericStepper, func:Dynamic, text:String) {
+105 -48
View File
@@ -36,7 +36,7 @@ final class AlphabetComponent {
public var cos:Float;
public var scaleX:Float;
public var scaleY:Float;
public var flipX:Bool;
public var flipY:Bool;
@@ -163,7 +163,7 @@ class Alphabet extends FlxSprite {
};
var manualLetters:Array<String> = [];
var failedLetters:Array<String> = [];
var failedOutlines:Array<String> = [];
var sheets:Array<String> = [];
public var renderMode:AlphabetRenderMode = DEFAULT;
@@ -321,7 +321,7 @@ class Alphabet extends FlxSprite {
if (!isOnScreen(camera)) {
frameOffset.y -= offsetY;
frameOffset.x -= offsetX;
break;
continue;
}
if (__component.hasColorMode)
@@ -436,10 +436,8 @@ class Alphabet extends FlxSprite {
if (anim == null)
return defaultAdvance;
if (data.advanceEmpty && !data.isDefault) {
data.advanceEmpty = false;
if (data.advanceEmpty && !data.isDefault)
data.advance = frames.frames[anim.frames[0]].sourceSize.x;
}
return (data.isDefault) ? frames.frames[anim.frames[0]].sourceSize.x : data.advance;
}
@@ -514,28 +512,17 @@ class Alphabet extends FlxSprite {
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 {
switch (node.nodeName) {
case "spritesheet":
final sheet = node.firstChild().nodeValue.trim();
if (frames == null)
frames = Paths.getFrames(node.firstChild().nodeValue);
frames = Paths.getFrames(sheet);
else {
for (frame in Paths.getFrames(node.firstChild().nodeValue).frames)
for (frame in Paths.getFrames(sheet).frames)
frames.pushFrame(frame);
}
sheets.push(sheet);
case "defaultAnim":
var idx = ["UPPER", "LOWER"].indexOf(node.get("casing").toUpperCase()) + 1;
@@ -549,7 +536,7 @@ class Alphabet extends FlxSprite {
advance: 0.0,
advanceEmpty: true,
components: [{
anim: node.firstChild().nodeValue,
anim: node.firstChild().nodeValue.trim(),
x: 0.0,
y: 0.0,
@@ -560,7 +547,7 @@ class Alphabet extends FlxSprite {
angle: angle,
cos: angleCos,
sin: angleSin,
flipX: node.get("flipX") == "true",
flipY: node.get("flipY") == "true",
@@ -616,7 +603,7 @@ class Alphabet extends FlxSprite {
angle: angle,
cos: angleCos,
sin: angleSin,
flipX: xFlip,
flipY: yFlip,
@@ -639,7 +626,7 @@ class Alphabet extends FlxSprite {
angle: angle,
cos: angleCos,
sin: angleSin,
flipX: xFlip,
flipY: yFlip,
@@ -673,7 +660,7 @@ class Alphabet extends FlxSprite {
var xScale:Float = Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0);
var yScale:Float = Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0);
var advance:Float = Std.parseFloat(node.get("advance"));
var xFlip = node.get("flipX") == "true";
var yFlip = node.get("flipY") == "true";
@@ -694,7 +681,7 @@ class Alphabet extends FlxSprite {
angle: angle,
cos: angleCos,
sin: angleSin,
flipX: xFlip,
flipY: yFlip,
@@ -705,7 +692,7 @@ class Alphabet extends FlxSprite {
components.push({
outIndex: (node.get("hasOutline") == "true") ? 0 : null,
anim: node.firstChild().nodeValue,
anim: node.firstChild().nodeValue.trim(),
x: xOff,
y: yOff,
@@ -766,6 +753,8 @@ class Alphabet extends FlxSprite {
v[2] = [];
v;
}
sheets = [];
manualLetters = [];
failedLetters = [" "];
defaultAdvance = Std.parseFloat(xml.get("advance")).getDefaultFloat(40.0);
@@ -781,34 +770,102 @@ class Alphabet extends FlxSprite {
checkNode(node);
}
private static var alphabetProperties:Array<String> = ["fps", "advance", "lineGap", "forceCasing", "useColorOffsets", "antialiasing"];
private static var componentProperties:Array<String> = ["name", "anim", "x", "y", "scaleX", "scaleY", "angle", "offsetX", "offsetY", "flipX", "flipY"];
private static var alphabetProperties:Array<String> = ["fps", "advance", "lineGap", "forceCasing", "colorMode", "antialiasing"];
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 {
var xml = Xml.createElement("alphabet");
var xml = Xml.createElement("alphabetFont");
xml.set("fps", Std.string(fps));
xml.set("advance", Std.string(defaultAdvance));
xml.set("lineGap", Std.string(lineGap));
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.attributeOrder = alphabetProperties;
/*for (component in components) {
var componentXml = Xml.createElement("component");
componentXml.attributeOrder = componentProperties;
componentXml.set("name", component.name);
componentXml.set("anim", component.anim);
componentXml.set("x", Std.string(component.x));
componentXml.set("y", Std.string(component.y));
if(component.scaleX != 1) componentXml.set("scaleX", Std.string(component.scaleX));
if(component.scaleY != 1) componentXml.set("scaleY", Std.string(component.scaleY));
if(component.angle != 0) componentXml.set("angle", Std.string(component.angle));
if(component.offsetX != 0) componentXml.set("offsetX", Std.string(component.offsetX));
if(component.offsetY != 0) componentXml.set("offsetY", Std.string(component.offsetY));
xml.addChild(componentXml);
}*/
for (sheet in sheets) {
var sheetNode = Xml.createElement("spritesheet");
sheetNode.addChild(Xml.createPCData(sheet));
xml.addChild(sheetNode);
}
for (i in 0...3) {
if (defaults[i] == null) continue;
var compon = defaults[i].components[0];
var node = Xml.createElement("defaultAnim");
node.addChild(Xml.createPCData(compon.anim));
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;
}
@@ -828,9 +885,9 @@ class Alphabet extends FlxSprite {
this.letterData = from.letterData;
this.defaults = from.defaults;
this.loaded = from.loaded;
this.sheets = from.sheets;
this.manualLetters = from.manualLetters;
this.failedLetters = from.failedLetters;
this.failedOutlines = from.failedOutlines;
}
override function destroy():Void {
@@ -843,7 +900,7 @@ class Alphabet extends FlxSprite {
defaults = null;
manualLetters = null;
failedLetters = null;
failedOutlines = null;
sheets = null;
super.destroy();
}