Skip to content
67 changes: 67 additions & 0 deletions assets/data/editors/layouts/stage/animEditScreen.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<window width="660" height="320" title="${translate('win-title', null, [button.animData.name])}">
<set name="MARGIN" value="20" />
<set name="XOFFSET" value="35" />
<set name="YOFFSET" value="40" />
<set name="TO" value="64" />

<exec>
function col(c:Int) {
return MARGIN + (200 + XOFFSET) * c;
}
</exec>

<title name="title" x="MARGIN" y="YOFFSET + 6" text="${translate('anim-title')}"/>

<!-- Alot of terms have already been translated in other places, so they get reused for consistency -->
<section>
<set name="curY" value="title.y + TO"/>
<textbox name="animID" label="${translate('characterAnim.name', 'characterEditor.')}" text="${button.animData.name}" x="col(0)" y="curY" width="120"/>
<stepper name="animFPS" label="${translate('characterAnim.fps', 'characterEditor.')}" value="button.animData.fps" x="last.x + last.bWidth + XOFFSET - 20" y="curY" width="100" precision="2" min="1"/>
<textbox name="animPrefix" label="${translate('characterAnim.anim', 'characterEditor.')}" text="${button.animData.anim}" x="col(1)" y="curY" width="190"/>
<checkbox name="useFrameLabel" value="button.animData.label" x="last.x + last.bWidth + MARGIN" y="curY + 6"/>
<label name="labelText" text="${translate('label')}" x="last.x + last.width + MARGIN - 15" size="15"/>
</section>

<section>
<set name="curY" value="animID.y + animID.bHeight + YOFFSET"/>
<dropdown name="animType" label="${translate('animType', 'stageElementEditScreen.')}" value="button.animData.animType" x="col(0)" y="curY" width="180">
<item label="${translate('animType.none', 'stageElementEditScreen.')}" value="0" />
<item label="${translate('animType.beat', 'stageElementEditScreen.')}" value="1" />
<item label="${translate('animType.loop', 'stageElementEditScreen.')}" value="2" />
</dropdown>
<textbox name="animIndices" label="${translate('characterAnim.indices', 'characterEditor.')}" text="${CoolUtil.formatNumberRange(button.animData.indices, ', ')}" x="col(1)" y="curY" width="200"/>
<stepper name="offsetX" value="button.animData.x" x="col(2)" y="curY" width="100" precision="1"/>
<stepper name="offsetY" value="button.animData.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" width="100" precision="1"/>
<label name="offsets" text="${translate('offsets')}" x="offsetX.x" y="offsetX.y" size="15"/>
</section>

<section>
<set name="curY" value="self.winHeight - YOFFSET"/>
<checkbox name="loop" text="${translate('characterAnim.looping', 'characterEditor.')}" value="button.animData.loop" x="col(0)" y="curY"/>
<checkbox name="forcedPlay" text="${translate('forcePlay')}" value="CoolUtil.getDefault(button.animData.forced, false)" x="last.x + last.field.width + XOFFSET" y="curY"/>
</section>

<exec>
var prevText:String = animID.label.text;
function onUpdate() {
if (animID.label.text != prevText)
self.winTitle = self.titleSpr.text = translate('win-title', null, [animID.label.text]);
prevText = animID.label.text;

labelText.y = (useFrameLabel.y + (useFrameLabel.height / 2)) - (labelText.height / 2);
}

function onSave() {
button.animData.name = animID.label.text;
button.animData.animType = animType.value;
button.animData.anim = animPrefix.label.text;
button.animData.fps = animFPS.value;
button.animData.x = offsetX.value; button.animData.y = offsetY.value;
button.animData.loop = loop.checked;
button.animData.forced = forcedPlay.checked;
button.animData.indices = CoolUtil.parseNumberRange(animIndices.label.text);
button.animData.label = useFrameLabel.checked;
button.updateDisplay();
}
</exec>
</window>
134 changes: 103 additions & 31 deletions assets/data/editors/layouts/stage/spriteEditScreen.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@

<exec>
function col(c:Int) {
return 20 + (200 + XOFFSET) * c;
return MARGIN + (200 + XOFFSET) * c;
}

if(sprite.animateAtlas == null) {
previewSprite = new FunkinSprite(50, self.winHeight - 100);
previewSprite = new FunkinSprite(MARGIN, self.winHeight - (100 + MARGIN));
previewSprite.frame = sprite.frame;

self.add(previewSprite);
}

function animTypeToString(animType:AnimType) {
return ["none", "beat", "loop"][animType];
}
if (getEx('anims') == null)
setEx('anims', sprite.animDatas.copy());
</exec>

<title name="title" x="20" y="30 + 16" text="${translate('sprite-title')}" />
Expand All @@ -25,7 +31,7 @@
<textbox name="nameTextBox" label="${translate('nameID')}" value="button.getName()" x="col(0)" y="curY" width="200" height="32" />
<textbox name="spriteTextBox" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" />
<stepper name="alphaStepper" label="Alpha" value="sprite.alpha" x="spriteTextBox.x + spriteTextBox.bWidth + XOFFSET" y="curY" precision="2" step="0.01" width="100" />
<label name="imageFile" text="${translate('imageFile')}" x="spriteTextBox.x" y="spriteTextBox.y - 14" size="15" />
<label name="imageFile" text="${translate('imageFile', [stage.spritesParentFolder])}" x="spriteTextBox.x" y="spriteTextBox.y - 14" size="15" />
</section>

<section> <!-- ROW 2 -->
Expand Down Expand Up @@ -64,8 +70,6 @@
<checkbox name="antialiasingCheckbox" text="${translate('antialiasing')}" value="sprite.antialiasing" x="col(0)" y="curY" />
<radio for="memoryCheck" name="highMemoryRadio" text="${translate('highMemory')}" value="getEx('highMemory')" x="col(1)" y="curY" />
<radio for="memoryCheck" name="lowMemoryRadio" text="${translate('lowMemory')}" value="getEx('lowMemory')" x="col(2)" y="curY" />

<!-- TODO: Animation list -->
</section>

<section> <!-- RIGHT SIDE -->
Expand All @@ -77,30 +81,39 @@
<camSpacing value="0" />

<code>
buttonlist.addButton.exists = false;
</code>

<!-- <code>
import funkin.editors.extra.PropertyButton;
//import funkin.backend.utils.XMLUtil.AnimData;
import funkin.editors.stage.elements.StageSpriteAnimButton;

var buttonList = buttonlist; // important for now, since it gets reset after the code is run

var width = buttonList.buttonSize.x;
var height = buttonList.buttonSize.y;

inline function addAnimBtn(animData:AnimData) {
var animButton = new StageSpriteAnimButton(animData, buttonList, width, height, width / 5, width / 3);
animButton.spriteXML = xml;
buttonList.add(animButton);
}

buttonList.addButton.callback = function() {
buttonList.add(new PropertyButton("newProperty", "valueHere", buttonList, width, height, 150, 220, 25));
final dummyAnim = {
name: TranslationUtil.translate('characterEditor.characterAnim.defaultAnimName'),
anim: translate('defaultAnimPrefix'),
fps: 24,
loop: false,
animType: animType.value,
x: 0,
y: 0,
indices: [],
label: false
};
addAnimBtn(dummyAnim);
}

//var defaultAttribs = Stage.DEFAULT_ATTRIBUTES;
//for (i in stage.stageXML.attributes()) {
// trace(i, defaultAttribs);
// if (!defaultAttribs.contains(i))
// buttonList.add(new PropertyButton(i, stage.stageXML.get(i), buttonList, width, height, 150, 220, 25));
//}
for(key =&gt; val in stage.extra)
buttonList.add(new PropertyButton(key, val, buttonList, width, height, 150, 220, 25));
</code> -->
for (animData in getEx('anims')) {
if (animData.name == 'idle' &amp;&amp; animData.anim == null) continue; // Skips dummy animation added by XMLUtil.loadSpriteFromXML
addAnimBtn(animData);
}
</code>
</buttonlist>

<text text="${translate('tipCustomProperties')}" x="col(2) - 60" y="self.winHeight - 50" size="15" />
Expand All @@ -111,35 +124,61 @@

<section if="previewSprite != null">
<title name="previewTitle" x="20" y="self.winHeight - 150" text="${translate('transformPreview')}" size="15" />
</section>
</section>

<exec>
var prevText = spriteTextBox.label.text;
var prevID = nameTextBox.label.text;
var spriteExists = true;
var ratio = sprite.width / sprite.height;

spriteTextBox.onChange = function(text) {
var newSprite = stage.spritesParentFolder + text;
var animated = Paths.framesExists(newSprite, true);
spriteExists = ( animated || Assets.exists(Paths.image(newSprite)) );

if (text != prevText &amp;&amp; spriteExists) {
if (animated) previewSprite.frames = Paths.getFrames(newSprite, previewSprite.animateSettings);
else previewSprite.loadGraphic(Paths.image(newSprite));
previewSprite.updateHitbox();

ratio = previewSprite.width / previewSprite.height;
previewSprite.colorTransform.__identity();
} else if (!spriteExists) {
previewSprite.colorTransform.color = 0xFFEF0202;
}
prevText = text;
}

function onUpdate() {
if (nameTextBox.label.text != prevID)
self.winTitle = self.titleSpr.text = translate('win-sprite-title', [nameTextBox.label.text]);
prevID = nameTextBox.label.text;

if(previewSprite == null) return;
previewSprite.color = 0xFFFFFFFF; // TODO: Color Wheel
previewSprite.skew.x = skewXStepper.value;
previewSprite.skew.y = skewYStepper.value;
previewSprite.angle = angleStepper.value;
previewSprite.alpha = alphaStepper.value;
previewSprite.antialiasing = antialiasingCheckbox.checked;
var ratio = sprite.width / sprite.height;
previewSprite.setGraphicSize(50 * scaleXStepper.value * ratio, 50 * scaleYStepper.value);
previewSprite.setGraphicSize(85 * scaleXStepper.value * ratio, 85 * scaleYStepper.value);
previewSprite.updateHitbox();
}

function onSave() {
sprite.name = nameTextBox.label.text;
setEx("imageFile", spriteTextBox.label.text);

setEx("highMemory", highMemoryRadio.checked);
setEx("lowMemory", lowMemoryRadio.checked);

//sprite.x = xStepper.value;
//sprite.y = yStepper.value;
//sprite.zoomFactor = zoomFactorStepper.value;
//sprite.antialiasing = antialiasingCheckbox.checked;
sprite.x = xStepper.value;
sprite.y = yStepper.value;
sprite.zoomFactor = zoomFactorStepper.value;
sprite.antialiasing = antialiasingCheckbox.checked;
//sprite.color = colorWheel.color;
//sprite.spriteAnimType = animType.value;
sprite.spriteAnimType = animTypeToString(animType.value);
sprite.angle = angleStepper.value;
sprite.alpha = alphaStepper.value;

Expand Down Expand Up @@ -171,15 +210,48 @@
button.xml.set("x", xStepper.value);
button.xml.set("y", yStepper.value);
button.xml.set("zoom", zoomFactorStepper.value);
button.xml.set("type", animType.key);
button.xml.set("type", animTypeToString(animType.value));
button.xml.set("antialiasing", antialiasingCheckbox.checked);
button.xml.set("angle", angleStepper.value);
button.xml.set("alpha", alphaStepper.value);

getEx('anims').clear();
var allowedAnims:Array&lt;String&gt; = [for (b in animations.buttons.members) b.animData.name];
for (node in button.xml.elementsNamed('anim')) if (!allowedAnims.contains( node.get('name') ))
button.xml.removeChild(node);

for (i in 0...animations.buttons.length) {
var actualChildren:Array&lt;Xml&gt; = button.xml.children.filter((f) -&gt; f.nodeType == 0);
if (i &gt; actualChildren.length - 1) {
var newAnim = Xml.createElement('anim');
button.xml.addChild(newAnim);
actualChildren.push(newAnim);
//trace("added new at " + i + ": " + newAnim);
}

final animData:AnimData = animations.buttons.members[i].animData;
final animNode:Xml = actualChildren[i];
//trace(animNode + "(" + i + ") before");
animNode.set("name", animData.name);
animNode.set("type", animTypeToString(animData.animType)); // XMLAnimType is abstract of int, the code is treating it as just int
animNode.set("anim", animData.anim);
animNode.set("fps", animData.fps);
animNode.set("x", animData.x);
animNode.set("y", animData.y);
animNode.set("loop", animData.loop);
animNode.set("forced", CoolUtil.getDefault(animData.forced, false));
animNode.set("indices", CoolUtil.formatNumberRange(animData.indices));
animNode.set("label", animData.label);
//trace(animNode + "(" + i + ")");
getEx('anims').set(animData.name, animData);
}

saveXY(sprite.scrollFactor, "scroll", scrollXStepper, scrollYStepper);
saveXY(sprite.scale, "scale", scaleXStepper, scaleYStepper);
saveXY(sprite.skew, "skew", skewXStepper, skewYStepper);
XMLUtil.loadSpriteFromXML(sprite, button.xml, stage.spritesParentFolder);
button.updateInfo();
setEx('node', button.xml);
}
</exec>
</window>
17 changes: 15 additions & 2 deletions assets/languages/en/Editors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,9 @@
<str id="title">Stage Info</str>
<str id="stageName">Stage Name</str>
<str id="spritePath">Sprite Path\n(Needs Refresh)</str>
<str id="startCamPos">Start Camera Position (X, Y)</str>
<str id="startCamPos">Start Camera Position\n(X, Y)</str>
<str id="zoom">Zoom</str>
<str id="customAttributes">Custom Attributes</str>
</group>

<group name="StageElementEditScreen" prefix="stageElementEditScreen.">
Expand All @@ -607,7 +608,7 @@

<str id="elementName">Element Name</str>
<str id="nameID">Name Identifier</str>
<str id="imageFile">Image File (WIP: needs reload)\nIn (${stage.spritesParentFolder})</str>
<str id="imageFile">Image File\n(in "{0}")</str>
<str id="scroll">Scroll {0}</str>
<str id="scale">Scale {0}</str>
<str id="camera">Camera {0}</str>
Expand All @@ -623,6 +624,7 @@
<str id="lowMemory">Low Memory</str>
<str id="attributes">Attributes</str>
<str id="transformPreview">Transform Preview:</str>
<str id="animations">Animations</str>

<str id="animType">Animation Type</str>
<group name="AnimTypeDropdown" prefix="animType.">
Expand All @@ -631,6 +633,8 @@
<str id="loop">LOOP</str>
</group>
<str id="tipCustomProperties">Tip: To access custom properties,\nHold Shift when clicking edit</str>

<str id="defaultAnimPrefix">Name on Anim Data</str>
</group>

<group name="StageXMLEditScreen" prefix="stageXMLEditScreen.">
Expand All @@ -645,6 +649,7 @@
<group name="StageElement" prefix="stageElement.">
<str id="scale">Scale: {0}, {1}</str>
<str id="scroll">Scroll: {0}, {1}</str>
<str id="unknown">Unknown Sprite:\n{0}</str>
</group>

<group name="StageSprites" prefix="stageSprites.">
Expand All @@ -654,6 +659,14 @@
<str id="character">Character</str>
<str id="warnings.not-implemented">Creating a box isnt implemented yet!</str>
</group>

<group name="StageAnimEdit" prefix="stageSpriteAnimEditScreen.">
<str id="win-title">Editing "{0}" Anim</str>
<str id="anim-title">Anim Data</str>
<str id="label">Use Frame Labels?</str>
<str id="offsets">Offset (X, Y)</str>
<str id="forcePlay">Forced Playing?</str>
</group>
</group>

<!-- PlayTesting and SaveWarning are almost the same but with some small differences -->
Expand Down
6 changes: 4 additions & 2 deletions assets/languages/es/Editors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@
<str id="title">Info. del Escenario</str>
<str id="stageName">Nombre del Escenario</str>
<str id="spritePath">Ubicación de Imágenes\n(Necesita Refrescar)</str>
<str id="startCamPos">Posición inicial de la cámara (X, Y)</str>
<str id="startCamPos">Posición inicial de la cámara\n(X, Y)</str>
<str id="zoom">Zoom</str>
</group>

Expand All @@ -566,7 +566,7 @@

<str id="elementName">Nombre del Elemento</str>
<str id="nameID">Identificador de Nombre</str>
<str id="imageFile">Imagen (WIP: necesita refrescar)\nEn (${stage.spritesParentFolder})</str>
<str id="imageFile">Imagen\n(en "{0}")</str>
<str id="scroll">Desplazamiento {0}</str>
<str id="scale">Tamaño {0}</str>
<str id="camera">Cámara {0}</str>
Expand All @@ -580,6 +580,7 @@
<str id="lowMemory">Baja Memoria</str>
<str id="attributes">Atributos</str>
<str id="transformPreview">Preview:</str>
<str id="animations">Animaciónes</str>

<str id="animType">Tipo de Animación</str>
<group name="AnimTypeDropdown" prefix="animType.">
Expand All @@ -602,6 +603,7 @@
<group name="StageElement" prefix="stageElement.">
<str id="scale">Tamaño: {0}, {1}</str>
<str id="scroll">Desplazamiento: {0}, {1}</str>
<str id="unknown">Sprite Desconocido:\n{0}</str>
</group>

<group name="StageSprites" prefix="stageSprites.">
Expand Down
Loading