Added: Simple editor - add/remove frames in buttons

This commit is contained in:
Jindra Petřík
2025-05-17 17:03:59 +02:00
parent 5fecb497b4
commit b8c67a2bc3
10 changed files with 441 additions and 139 deletions

View File

@@ -270,7 +270,7 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer {
layer.filters = r.filterList;
layer.matrix = r.placeMatrix;
layer.characterId = r.characterId;
layer.depth = r.placeDepth;
layer.depth = r.placeDepth;
if (r.placeDepth > maxDepth) {
maxDepth = r.placeDepth;
@@ -278,15 +278,28 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer {
if (r.buttonStateUp) {
frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, frameUp, false));
frameUp.layers.get(r.placeDepth).key = true;
}
if (r.buttonStateDown) {
frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, frameDown, false));
}
if (r.buttonStateOver) {
frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, frameOver, false));
if (!r.buttonStateUp) {
frameOver.layers.get(r.placeDepth).key = true;
}
}
if (r.buttonStateDown) {
frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, frameDown, false));
if (!r.buttonStateOver) {
frameDown.layers.get(r.placeDepth).key = true;
}
}
if (r.buttonStateHitTest) {
frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, frameHit, false));
if (!r.buttonStateDown) {
frameHit.layers.get(r.placeDepth).key = true;
}
}
}

View File

@@ -264,14 +264,23 @@ public class DefineButtonTag extends ButtonTag implements ASMSourceContainer {
if (r.buttonStateUp) {
frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, frameUp, false));
}
if (r.buttonStateDown) {
frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, frameDown, false));
}
if (r.buttonStateOver) {
frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, frameOver, false));
if (!r.buttonStateUp) {
frameOver.layers.get(r.placeDepth).key = true;
}
}
if (r.buttonStateDown) {
frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, frameDown, false));
if (!r.buttonStateOver) {
frameDown.layers.get(r.placeDepth).key = true;
}
}
if (r.buttonStateHitTest) {
frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, frameHit, false));
if (!r.buttonStateDown) {
frameDown.layers.get(r.placeDepth).key = true;
}
}
}

View File

@@ -35,6 +35,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -278,7 +279,7 @@ public abstract class ButtonTag extends DrawableTag implements Timelined {
break;
}
}
if (addIfNotExists) {
BUTTONRECORD newRecord = new BUTTONRECORD(swf, this);
switch (frame) {
@@ -295,12 +296,52 @@ public abstract class ButtonTag extends DrawableTag implements Timelined {
newRecord.buttonStateHitTest = true;
break;
}
newRecord.placeDepth = depth;
getRecords().add(newRecord);
return newRecord;
}
return null;
}
public void packRecords() {
List<BUTTONRECORD> records = new ArrayList<>();
for (int i = records.size() - 1; i >= 0; i--) {
BUTTONRECORD rec = records.get(i);
if (rec.isEmpty()) {
records.remove(i);
}
}
}
public Set<Integer> getEmptyFrames() {
Set<Integer> ret = new LinkedHashSet<>();
ret.add(FRAME_UP);
ret.add(FRAME_OVER);
ret.add(FRAME_DOWN);
ret.add(FRAME_HITTEST);
for (BUTTONRECORD rec : getRecords()) {
if (rec.buttonStateUp) {
ret.remove(FRAME_UP);
}
if (rec.buttonStateOver) {
ret.remove(FRAME_OVER);
}
if (rec.buttonStateDown) {
ret.remove(FRAME_DOWN);
}
if (rec.buttonStateHitTest) {
ret.remove(FRAME_HITTEST);
}
}
return ret;
}
public boolean isFrameEmpty(int frame) {
return true;
}
public void setRecordFromPlaceObject(int frame, PlaceObjectTypeTag placeTag) {
BUTTONRECORD selectedRecord = null;

View File

@@ -84,6 +84,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -144,6 +145,11 @@ public class Timeline {
* Map of depth to maximum frame.
*/
private final Map<Integer, Integer> depthMaxFrame = new HashMap<>();
/**
* Map of depth to maximum frame including buttons
*/
private final Map<Integer, Integer> depthMaxFrameButtons = new HashMap<>();
/**
* List of all ASMSources.
@@ -283,6 +289,16 @@ public class Timeline {
ensureInitialized();
return depthMaxFrame;
}
/**
* Gets map of depth to max frame including buttons
*
* @return Map of depth to max frame
*/
public Map<Integer, Integer> getDepthMaxFrameButtons() {
ensureInitialized();
return depthMaxFrameButtons;
}
/**
* Gets map of soundStream id to SoundStreamFrameRanges.
@@ -325,6 +341,7 @@ public class Timeline {
initialized = false;
frames.clear();
depthMaxFrame.clear();
depthMaxFrameButtons.clear();
asmSources.clear();
asmSourceContainers.clear();
actionFrames.clear();
@@ -725,14 +742,31 @@ public class Timeline {
*/
private synchronized void calculateMaxDepthFrames() {
depthMaxFrame.clear();
depthMaxFrameButtons.clear();
for (int d = 0; d <= maxDepth; d++) {
for (int f = frames.size() - 1; f >= 0; f--) {
if (frames.get(f).layers.get(d) != null) {
depthMaxFrame.put(d, f);
depthMaxFrame.put(d, f);
break;
}
}
}
if (timelined instanceof ButtonTag) {
ButtonTag button = (ButtonTag) timelined;
Set<Integer> emptyFrames = button.getEmptyFrames();
for (int d = 0; d <= maxDepth; d++) {
for (int f = frames.size() - 1; f >= 0; f--) {
if (frames.get(f).layers.get(d) != null) {
if (!emptyFrames.contains(f)) {
depthMaxFrameButtons.put(d, f);
break;
}
}
}
}
}
}
/**

View File

@@ -33,6 +33,7 @@ import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFArray;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.filters.FILTER;
import com.jpexs.helpers.Helper;
import java.io.Serializable;
import java.util.List;
@@ -52,12 +53,14 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh
/**
* Has blend mode?
*
* @since SWF 8
*/
public boolean buttonHasBlendMode;
/**
* Has filter list?
*
* @since SWF 8
*/
public boolean buttonHasFilterList;
@@ -146,6 +149,7 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh
/**
* Constructor.
*
* @param swf SWF
* @param tag Button tag
*/
@@ -154,6 +158,26 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh
this.tag = tag;
}
public BUTTONRECORD(BUTTONRECORD source) {
this.buttonHasBlendMode = source.buttonHasBlendMode;
this.buttonHasFilterList = source.buttonHasFilterList;
this.buttonStateHitTest =source. buttonStateHitTest;
this.buttonStateDown = source.buttonStateDown;
this.buttonStateOver = source.buttonStateOver;
this.buttonStateUp = source.buttonStateUp;
this.characterId = source.characterId;
this.placeDepth = source.placeDepth;
this.placeMatrix = new MATRIX(source.placeMatrix);
this.colorTransform = source.colorTransform == null ? null : new CXFORMWITHALPHA(source.colorTransform);
this.filterList = Helper.deepCopy(source.filterList);
this.blendMode = source.blendMode;
this.swf = source.swf;
this.tag = source.tag;
this.modified = source.modified;
}
/**
* Constructor.
*/
@@ -179,6 +203,7 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh
/**
* Sets the modified flag.
*
* @param value Modified flag
*/
public void setModified(boolean value) {
@@ -211,20 +236,69 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh
this.characterId = characterId;
}
/**
* Enables/disables specific frame
*
* @param frame Frame
* @param value Value
*/
public void setFrame(int frame, boolean value) {
switch (frame) {
case ButtonTag.FRAME_UP:
buttonStateUp = value;
break;
case ButtonTag.FRAME_OVER:
buttonStateOver = value;
break;
case ButtonTag.FRAME_DOWN:
buttonStateDown = value;
break;
case ButtonTag.FRAME_HITTEST:
buttonStateHitTest = value;
break;
}
}
/**
* Has frame
*
* @param frame Frame
* @return True if has
*/
public boolean hasFrame(int frame) {
switch (frame) {
case ButtonTag.FRAME_UP:
return buttonStateUp;
case ButtonTag.FRAME_OVER:
return buttonStateOver;
case ButtonTag.FRAME_DOWN:
return buttonStateDown;
case ButtonTag.FRAME_HITTEST:
return buttonStateHitTest;
}
return false;
}
/**
* Imports placeObject to this BUTTONRECORD
*
* @param placeObject Place tag
*/
public void fromPlaceObject(PlaceObjectTypeTag placeObject) {
placeDepth = placeObject.getDepth();
characterId = placeObject.getCharacterId();
ColorTransform importedColorTrans = placeObject.getColorTransform();
colorTransform = importedColorTrans == null ? null : new CXFORMWITHALPHA(placeObject.getColorTransform());
ColorTransform importedColorTrans = placeObject.getColorTransform();
colorTransform = importedColorTrans == null ? new CXFORMWITHALPHA() : new CXFORMWITHALPHA(placeObject.getColorTransform());
placeMatrix = placeObject.getMatrix();
blendMode = placeObject.getBlendMode();
buttonHasBlendMode = blendMode > 0;
filterList = placeObject.getFilters();
buttonHasFilterList = filterList != null && !filterList.isEmpty();
}
/**
* Converts this BUTTONRECORD to a place tag.
*
* @return Place tag
*/
public PlaceObject3Tag toPlaceObject() {
@@ -260,4 +334,20 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh
}
return placeTag;
}
public boolean isEmpty() {
if (buttonStateUp) {
return false;
}
if (buttonStateOver) {
return false;
}
if (buttonStateDown) {
return false;
}
if (buttonStateHitTest) {
return false;
}
return true;
}
}