diff --git a/assets/data/editors/layouts/stage/animEditScreen.xml b/assets/data/editors/layouts/stage/animEditScreen.xml new file mode 100644 index 0000000000..39c3303ca5 --- /dev/null +++ b/assets/data/editors/layouts/stage/animEditScreen.xml @@ -0,0 +1,67 @@ + + + + + + + + function col(c:Int) { + return MARGIN + (200 + XOFFSET) * c; + } + + + + + <!-- 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> \ No newline at end of file diff --git a/assets/data/editors/layouts/stage/spriteEditScreen.xml b/assets/data/editors/layouts/stage/spriteEditScreen.xml index de6e70bb27..80bb4d26f7 100644 --- a/assets/data/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/data/editors/layouts/stage/spriteEditScreen.xml @@ -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')}" /> @@ -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 --> @@ -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 --> @@ -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 => 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' && 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" /> @@ -111,10 +124,37 @@ <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 && 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; @@ -122,11 +162,10 @@ 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); @@ -134,12 +173,12 @@ 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; @@ -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<String> = [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<Xml> = button.xml.children.filter((f) -> f.nodeType == 0); + if (i > 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> \ No newline at end of file diff --git a/assets/languages/en/Editors.xml b/assets/languages/en/Editors.xml index c36b63b5e1..aa8bf81cf8 100644 --- a/assets/languages/en/Editors.xml +++ b/assets/languages/en/Editors.xml @@ -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."> @@ -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> @@ -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."> @@ -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."> @@ -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."> @@ -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 --> diff --git a/assets/languages/es/Editors.xml b/assets/languages/es/Editors.xml index f8f23dd52d..8e4da69a0f 100644 --- a/assets/languages/es/Editors.xml +++ b/assets/languages/es/Editors.xml @@ -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> @@ -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> @@ -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."> @@ -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."> diff --git a/assets/languages/it/Editors.xml b/assets/languages/it/Editors.xml index 90853b8587..d0968dc16a 100644 --- a/assets/languages/it/Editors.xml +++ b/assets/languages/it/Editors.xml @@ -561,7 +561,7 @@ <str id="title">Informazioni Palcoscenico</str> <str id="stageName">Nome Palcoscenico</str> <str id="spritePath">Percorso file Sprite\n(E' necessario ricaricare la pagina)</str> - <str id="startCamPos">Posizioni iniziali della Telecamera (X, Y)</str> + <str id="startCamPos">Posizioni iniziali della Telecamera\n(X, Y)</str> <str id="zoom">Zoom</str> </group> @@ -576,7 +576,7 @@ <str id="elementName">Nome Elemento</str> <str id="nameID">Nome Identificatore</str> - <str id="imageFile">File Immagine (WIP: reload necessario)\nIn (${stage.spritesParentFolder})</str> + <str id="imageFile">File Immagine\n(in "{0}")</str> <str id="scroll">Scorrimento {0}</str> <str id="scale">Scala {0}</str> <str id="camera">Teleamera {0}</str> diff --git a/assets/languages/pl/Editors.xml b/assets/languages/pl/Editors.xml index 694e66c3d9..86ff120c14 100644 --- a/assets/languages/pl/Editors.xml +++ b/assets/languages/pl/Editors.xml @@ -568,7 +568,7 @@ <str id="title">Info Sceny</str> <str id="stageName">Nazwa Sceny</str> <str id="spritePath">Ścieżka Plikowa Sprite'a\n(Wymaga Odświeżenia)</str> - <str id="startCamPos">Pozycja Startowa Kamery (X, Y)</str> + <str id="startCamPos">Pozycja Startowa Kamery\n(X, Y)</str> <str id="zoom">Przybliżenie</str> </group> @@ -583,7 +583,7 @@ <str id="elementName">Nazwa Elementu</str> <str id="nameID">Nazwa Identyfikatora</str> - <str id="imageFile">Plik Obrazu (W TRACKIE PRACY: wymaga odświeżenia)\nIn (${stage.spritesParentFolder})</str> + <str id="imageFile">Plik Obrazu\n(in "{0}")</str> <str id="scroll">Przewijanie {0}</str> <str id="scale">Skala {0}</str> <str id="camera">Kamera {0}</str> diff --git a/assets/languages/pt/Editors.xml b/assets/languages/pt/Editors.xml index aa718df294..2d0a05208d 100644 --- a/assets/languages/pt/Editors.xml +++ b/assets/languages/pt/Editors.xml @@ -588,7 +588,7 @@ <str id="title">Info. do Cenário</str> <str id="stageName">Nome do Cenário</str> <str id="spritePath">Caminho do Sprite\n(Requer Recarregamento)</str> - <str id="startCamPos">Posição inicial da Câmara (X, Y)</str> + <str id="startCamPos">Posição inicial da Câmara\n(X, Y)</str> <str id="zoom">Zoom</str> <str id="customAttributes">Atributos Especiais</str> </group> @@ -604,7 +604,7 @@ <str id="elementName">Nome do Elemento</str> <str id="nameID">Nome Identificador</str> - <str id="imageFile">Imagem (WIP: precisa recarregar)\nEm (${stage.spritesParentFolder})</str> + <str id="imageFile">Imagem\n(em "{0}")</str> <str id="scroll">Scroll {0}</str> <!-- it's "scroll" here because "deslocamento" is too big --> <str id="scale">Tamanho {0}</str> <str id="camera">Câmara {0}</str> @@ -629,6 +629,8 @@ <str id="loop">REPETIR</str> </group> <str id="tipCustomProperties">Dica: Para aceder a mais dados,\nSegure em Shift quando Editar</str> + + <str id="defaultAnimPrefix">Nome em Dados de Animação</str> </group> <group name="StageXMLEditScreen" prefix="stageXMLEditScreen."> @@ -643,6 +645,7 @@ <group name="StageElement" prefix="stageElement."> <str id="scale">Tamanho: {0}, {1}</str> <str id="scroll">Deslocamento: {0}, {1}</str> + <str id="unknown">Sprite Desconhecido:\n{0}</str> </group> <group name="StageSprites" prefix="stageSprites."> @@ -652,6 +655,14 @@ <str id="character">Personagem</str> <str id="warnings.not-implemented">Criar caixas ainda não foi implementado!</str> </group> + + <group name="StageAnimEdit" prefix="stageSpriteAnimEditScreen."> + <str id="win-title">A Editar a Animação "{0}"</str> + <str id="anim-title">Dados da Animação</str> + <str id="label">Usar Rótulos\nde Quadro?</str> + <str id="offsets">Posições (X, Y)</str> + <str id="forcePlay">Reprodução Forçada?</str> + </group> </group> <group name="PlayTesting" prefix="playtesting."> diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 8b54a2c695..89c2a33473 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -260,6 +260,7 @@ class StageEditor extends UIState { stageSpritesWindow.add(button); } else if(sprite == null) { var basic = new FlxBasic(); // prevent awkward layering + basic.exists = false; insert(i, basic); var button = new StageUnknownButton(0,0, basic, xml); stageSpritesWindow.add(button); @@ -308,8 +309,8 @@ class StageEditor extends UIState { sprite.extra.set(exID("type"), node.name); sprite.extra.set(exID("imageFile"), '${node.getAtt("sprite").getDefault(sprite.name)}'); sprite.extra.set(exID("parentNode"), parent); - sprite.extra.set(exID("highMemory"), parent.name == "highMemory"); - sprite.extra.set(exID("lowMemory"), parent.name == "lowMemory"); + sprite.extra.set(exID("highMemory"), parent.name == "high-memory"); + sprite.extra.set(exID("lowMemory"), parent.name == "low-memory"); //sprite.active = false; } if(sprite is StageCharPos) @@ -374,6 +375,7 @@ class StageEditor extends UIState { } char.name = charName; char.debugMode = true; + char.useRenderTexture = true; // Play first anim, and make it the last frame var animToPlay = char.getAnimOrder()[0]; char.playAnim(animToPlay, true, NONE); @@ -392,8 +394,8 @@ class StageEditor extends UIState { char.extra.set(exID("camY"), charPos.camyoffset); char.extra.set(exID("parentNode"), parent); - char.extra.set(exID("highMemory"), parent.name == "highMemory"); - char.extra.set(exID("lowMemory"), parent.name == "lowMemory"); + char.extra.set(exID("highMemory"), parent.name == "high-memory"); + char.extra.set(exID("lowMemory"), parent.name == "low-memory"); chars.push(char); stage.applyCharStuff(char, charPos.name, 0); @@ -668,6 +670,8 @@ class StageEditor extends UIState { saveToXml(spriteXML, "color", sprite.color.toWebString(), "#FFFFFF"); // TODO: save custom parameters //saveToXml(spriteXML, "flipX", sprite.flipX, false); + if (node.hasNode.anim) for (animNode in node.nodes.anim) + spriteXML.addChild(animNode.x); newNode = spriteXML; } else if(button is StageCharacterButton) { var button:StageCharacterButton = cast button; diff --git a/source/funkin/editors/stage/elements/StageSolidButton.hx b/source/funkin/editors/stage/elements/StageSolidButton.hx index 6ded6d26e8..49ffd1925b 100644 --- a/source/funkin/editors/stage/elements/StageSolidButton.hx +++ b/source/funkin/editors/stage/elements/StageSolidButton.hx @@ -8,6 +8,7 @@ class StageSolidButton extends StageSpriteButton { public function new(x:Float,y:Float, sprite:FunkinSprite, xml:Access) { super(x,y, sprite, xml); color = 0xFFD9FF50; + hasAdvancedEdit = false; } public override function onEdit() { diff --git a/source/funkin/editors/stage/elements/StageSpriteAnimButton.hx b/source/funkin/editors/stage/elements/StageSpriteAnimButton.hx new file mode 100644 index 0000000000..651b736da5 --- /dev/null +++ b/source/funkin/editors/stage/elements/StageSpriteAnimButton.hx @@ -0,0 +1,99 @@ +package funkin.editors.stage.elements; + +import funkin.backend.utils.XMLUtil.AnimData; +import haxe.xml.Access; +import funkin.editors.extra.PropertyButton; + +class StageSpriteAnimButton extends PropertyButton +{ + public var fpsStepper:UINumericStepper; + public var editButton:UIButton; + public var editIcon:FlxSprite; + @:unreflective private var __initialized:Bool = false; + + public var spriteXML:Access; + public var animData(default, null):AnimData; + + public function new(anim:AnimData, parent, width:Int = 280, height:Int = 35, nameWidth:Int = 100, valueWidth:Int = 135, inputHeight:Int = 25) + { + super("", "", parent, width, height, nameWidth, valueWidth, inputHeight); + animData = anim; + propertyText.onChange = (text) -> animData.name = text; + valueText.onChange = (text) -> animData.anim = text; + + var editSize = height - 5 * 2; + editButton = new UIButton(deleteButton.x - deleteButton.bWidth - 5, 5, null, openAnimEdit, editSize, editSize); + editButton.frames = Paths.getFrames("editors/ui/grayscale-button"); + editButton.color = 0xFFFF5B0F; + editButton.autoAlpha = false; + members.insert(members.indexOf(deleteButton), editButton); + + editIcon = new FlxSprite(editButton.x + 8, editButton.y + 10).loadGraphic(Paths.image('editors/stage/edit-button'), true, 16, 16); + editIcon.animation.add("advanced", [1]); + editIcon.animation.play("advanced"); + editIcon.antialiasing = false; + members.insert(members.indexOf(editButton) + 1, editIcon); + + fpsStepper = new UINumericStepper(valueText.x + valueText.bWidth + 15, 5, 0, 1, 2, 0, null, Math.round(width / 4), 25); + fpsStepper.onChange = (text) -> + { + @:privateAccess fpsStepper.__onChange(text); + animData.fps = fpsStepper.value; + }; + members.insert(members.indexOf(deleteButton), fpsStepper); + + __initialized = true; + updateDisplay(); + } + + public function openAnimEdit() + { + final parent = (FlxG.state.subState is UISoftcodedWindow) ? FlxG.state.subState : FlxG.state; + parent.openSubState(new SpriteAnimEditScreen(spriteXML, this, null)); + } + + public override function updatePos() + { + super.updatePos(); + if (!__initialized) return; + + fpsStepper.follow(this, valueText.x + valueText.bWidth, bHeight/2 - (fpsStepper.bHeight/2)); + editButton.follow(this, deleteButton.x - deleteButton.bWidth - 5, bHeight/2 - (editButton.bHeight/2)); + editIcon.follow(editButton, editButton.bWidth / 2 - editIcon.width / 2, editButton.bHeight / 2 - editIcon.height / 2); + } + + public inline function updateDisplay() + { + propertyText.label.text = animData.name; + valueText.label.text = animData.anim; + fpsStepper.value = animData.fps; + } +} + +class SpriteAnimEditScreen extends UISoftcodedWindow +{ + public var saveCallback:Void->Void; + public var parentButton:StageSpriteAnimButton; + public var xml:Access; + + inline function translate(id:String, prefix:String = "stageSpriteAnimEditScreen.", ?args:Array<Dynamic>) + return TU.translate(prefix + id, args); + + public function new(xml:Access, parentButton:StageSpriteAnimButton, saveCallback:Void->Void) { + this.saveCallback = saveCallback; + this.parentButton = parentButton; + this.xml = xml; + super("layouts/stage/animEditScreen", [ + "stage" => StageEditor.instance.stage, + "xml" => xml, + "exID" => StageEditor.exID, + "translate" => translate, + "button" => parentButton + ]); + } + + override function saveData() { + super.saveData(); + if(saveCallback != null) saveCallback(); + } +} \ No newline at end of file diff --git a/source/funkin/editors/stage/elements/StageUnknownButton.hx b/source/funkin/editors/stage/elements/StageUnknownButton.hx index a3fb09492a..6c0e5a623c 100644 --- a/source/funkin/editors/stage/elements/StageUnknownButton.hx +++ b/source/funkin/editors/stage/elements/StageUnknownButton.hx @@ -8,12 +8,13 @@ class StageUnknownButton extends StageElementButton { public var lowMemory:Bool = false; public var highMemory:Bool = false; public var basic:FlxBasic; + var dummy:FunkinSprite; // to allow it to be saved public function new(x:Float,y:Float, basic:FlxBasic, xml:Access) { this.basic = basic; - super(x,y, xml); + super(x, y, xml); - if(xml.x.parent != null) { + if (xml.x.parent != null) { lowMemory = xml.x.parent.nodeName == "low-memory"; highMemory = xml.x.parent.nodeName == "high-memory"; } @@ -27,8 +28,12 @@ class StageUnknownButton extends StageElementButton { members.remove(visibilityIcon); setEditAdvanced(); - updateInfo(); + + dummy = new FunkinSprite(); + dummy.extra.set(StageEditor.exID("lowMemory"), lowMemory); + dummy.extra.set(StageEditor.exID("highMemory"), highMemory); + dummy.extra.set(StageEditor.exID("button"), this); } public override function update(elapsed:Float) { @@ -40,11 +45,7 @@ class StageUnknownButton extends StageElementButton { } public override function getSprite():FunkinSprite { - var sprite = new FunkinSprite(); // to allow it to be saved - sprite.extra.set(StageEditor.exID("lowMemory"), lowMemory); - sprite.extra.set(StageEditor.exID("highMemory"), highMemory); - sprite.extra.set(StageEditor.exID("button"), this); - return sprite; + return dummy; } public override function canRender() { @@ -58,10 +59,12 @@ class StageUnknownButton extends StageElementButton { FlxG.state.openSubState(new StageUnknownEditScreen(this)); } - //public override function onEdit() { - // UIState.state.displayNotification(new UIBaseNotification("Editing a character isnt implemented yet!", 2, BOTTOM_LEFT)); - // CoolUtil.playMenuSFX(WARNING, 0.45); - //} + public override function onDelete() { + basic.destroy(); + dummy.destroy(); + xml.x.parent.removeChild(xml.x); + StageEditor.instance.stageSpritesWindow.remove(this); + } public override function onVisiblityToggle() { }