diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/DepthState.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/DepthState.java index db364ef4c..135ee97aa 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/DepthState.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/DepthState.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.timeline; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.types.CLIPACTIONS; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.MATRIX; @@ -64,6 +65,8 @@ public class DepthState { public Frame frame; + public PlaceObjectTypeTag placeObjectTag; + public long instanceId; public boolean motionTween = false; @@ -96,6 +99,7 @@ public class DepthState { ratio = obj.ratio; clipDepth = obj.clipDepth; time = obj.time; + placeObjectTag = obj.placeObjectTag; if (sameInstance) { time++; instanceId = obj.instanceId; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 8cef1db13..38e63e4f4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -257,11 +257,12 @@ public class Timeline { newFrameNeeded = true; PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; int depth = po.getDepth(); - if (!frame.layers.containsKey(depth)) { - frame.layers.put(depth, new DepthState(swf, frame)); + DepthState fl = frame.layers.get(depth); + if (fl == null) { + frame.layers.put(depth, fl = new DepthState(swf, frame)); } frame.layersChanged = true; - DepthState fl = frame.layers.get(depth); + fl.placeObjectTag = po; int characterId = po.getCharacterId(); if (characterId != -1) { fl.characterId = characterId; @@ -314,7 +315,7 @@ public class Timeline { fl.clipActions = po.getClipActions(); fl.clipDepth = po.getClipDepth(); } - fl.key = true; + fl.key = characterId != -1; } else if (t instanceof RemoveTag) { newFrameNeeded = true; RemoveTag r = (RemoveTag) t; @@ -342,8 +343,7 @@ public class Timeline { maxDepth = getMaxDepthInternal(); - // todo: enable again after TweenDetector.detectRanges implemented - //detectTweens(); + detectTweens(); calculateMaxDepthFrames(); createASPackages(); @@ -355,10 +355,6 @@ public class Timeline { initialized = true; } - private boolean compare(int a, int b, int c, int tolerance) { - return Math.abs((b - a) - (c - b)) < tolerance; - } - private void detectTweens() { for (int d = 1; d <= maxDepth; d++) { int characterId = -1; @@ -366,26 +362,31 @@ public class Timeline { for (int f = 0; f <= frames.size(); f++) { DepthState ds = f >= frames.size() ? null : frames.get(f).layers.get(d); - if (f < frames.size() && ds != null && ds.characterId == characterId && ds.characterId != -1) { + if (ds != null && characterId != -1 && ds.characterId == characterId) { len++; } else { if (characterId != -1) { - List matrices = new ArrayList<>(); + int startPos = f - len; + List matrices = new ArrayList<>(len); for (int k = 0; k < len; k++) { - matrices.add(frames.get(f - len + k).layers.get(d).matrix); + matrices.add(frames.get(startPos + k).layers.get(d)); } + List ranges = TweenDetector.detectRanges(matrices); for (TweenRange r : ranges) { for (int t = r.startPosition; t <= r.endPosition; t++) { - DepthState layer = frames.get(f - len + t).layers.get(d); + DepthState layer = frames.get(startPos + t).layers.get(d); layer.motionTween = true; layer.key = false; } - frames.get(r.startPosition).layers.get(d).key = true; + + frames.get(startPos + r.startPosition).layers.get(d).key = true; } } + len = 1; } + characterId = ds == null ? -1 : ds.characterId; } } @@ -396,7 +397,7 @@ public class Timeline { for (int d = 1; d <= maxDepth; d++) { for (int f = frames.size() - 1; f >= 0; f--) { if (frames.get(f).layers.get(d) != null) { - depthMaxFrame.put(d, f + 1); + depthMaxFrame.put(d, f); break; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/TweenDetector.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/TweenDetector.java index f3db91696..1b597a17e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/TweenDetector.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/TweenDetector.java @@ -1,22 +1,23 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.timeline; -import com.jpexs.decompiler.flash.types.MATRIX; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -27,11 +28,15 @@ import java.util.List; */ public class TweenDetector { - public static List detectRanges(List matrices) { + public static List detectRanges(List depthStates) { //TODO: make this working :-( - return new ArrayList<>(); + if (depthStates.size() < 2 || depthStates.get(0).placeObjectTag == depthStates.get(1).placeObjectTag) { + return new ArrayList<>(); + } + + return new ArrayList<>(Arrays.asList(new TweenRange(0, depthStates.size() - 1))); /* - + List ret = new ArrayList<>(); double tolerance = 1; int min = 3; @@ -44,20 +49,20 @@ public class TweenDetector { List scaleY=new ArrayList<>(); List rotateSkew0=new ArrayList<>(); List rotateSkew1=new ArrayList<>(); - - + + Set ms=new HashSet(); ms.addAll(matrices); if(ms.size()==1){ return new ArrayList<>(); } - - + + for(MATRIX n:matrices){ //... - } - - for (; startpos + i <= matrices.size() + 1; i++) { + } + + for (; startpos + i <= matrices.size() + 1; i++) { double errTranslateX = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(translateX, startpos, i); double errTranslateY = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(translateY, startpos, i); double errScaleX = startpos + i > matrices.size() ? Double.MAX_VALUE : getErrorLevel(scaleX, startpos, i); @@ -71,7 +76,7 @@ public class TweenDetector { i = min - 1; continue; } - ret.add(new TweenRange(startpos, startpos+i-1-1)); + ret.add(new TweenRange(startpos, startpos+i-1-1)); startpos = startpos + i -1; i = min - 1; last = null; diff --git a/src/com/jpexs/decompiler/flash/gui/timeline/TimelineBodyPanel.java b/src/com/jpexs/decompiler/flash/gui/timeline/TimelineBodyPanel.java index fc70ef31c..b74b3fd0b 100644 --- a/src/com/jpexs/decompiler/flash/gui/timeline/TimelineBodyPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/timeline/TimelineBodyPanel.java @@ -35,6 +35,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.List; +import java.util.Map; import javax.swing.JPanel; import org.pushingpixels.substance.api.ColorSchemeAssociationKind; import org.pushingpixels.substance.api.ComponentState; @@ -50,13 +51,11 @@ public class TimelineBodyPanel extends JPanel implements MouseListener, KeyListe private final Timeline timeline; - public static final Color motionTweenColor = new Color(0x59, 0xfe, 0x7c); + public static final Color shapeTweenColor = new Color(0x59, 0xfe, 0x7c); - public static final Color shapeTweenColor = new Color(0xd1, 0xac, 0xf1); + public static final Color motionTweenColor = new Color(0xd1, 0xac, 0xf1); //public static final Color frameColor = new Color(0xbd, 0xd8, 0xfc); - //public static final Color emptyFrameColor = Color.white; - //public static final Color emptyFrameSecondColor = new Color(0xea, 0xf2, 0xfc); public static final Color borderColor = Color.black; public static final Color emptyBorderColor = new Color(0xbd, 0xd8, 0xfc); @@ -80,6 +79,11 @@ public class TimelineBodyPanel extends JPanel implements MouseListener, KeyListe public Point cursor = null; + private enum BlockType { + + EMPTY, NORMAL, MOTION_TWEEN, SHAPE_TWEEN + } + public static Color getEmptyFrameColor() { return SubstanceColorUtilities.getLighterColor(getControlColor(), 0.7); } @@ -137,10 +141,12 @@ public class TimelineBodyPanel extends JPanel implements MouseListener, KeyListe g.setColor(TimelinePanel.getBackgroundColor()); g.fillRect(0, 0, getWidth(), getHeight()); Rectangle clip = g.getClipBounds(); - int start_f = clip.x / TimelinePanel.FRAME_WIDTH; - int start_d = clip.y / TimelinePanel.FRAME_HEIGHT; - int end_f = (clip.x + clip.width) / TimelinePanel.FRAME_WIDTH; - int end_d = (clip.y + clip.height) / TimelinePanel.FRAME_HEIGHT; + int frameWidth = TimelinePanel.FRAME_WIDTH; + int frameHeight = TimelinePanel.FRAME_HEIGHT; + int start_f = clip.x / frameWidth; + int start_d = clip.y / frameHeight; + int end_f = (clip.x + clip.width) / frameWidth; + int end_d = (clip.y + clip.height) / frameHeight; int max_d = timeline.getMaxDepth(); if (max_d < end_d) { @@ -155,219 +161,158 @@ public class TimelineBodyPanel extends JPanel implements MouseListener, KeyListe return; } - boolean keyfound[] = new boolean[end_d - start_d + 1]; - + // draw background for (int f = start_f; f <= end_f; f++) { + g.setColor((f + 1) % 5 == 0 ? getEmptyFrameSecondColor() : getEmptyFrameColor()); + g.fillRect(f * frameWidth, start_d * frameHeight, frameWidth, (end_d - start_d + 1) * frameHeight); + g.setColor(emptyBorderColor); for (int d = start_d; d <= end_d; d++) { - DepthState fl = timeline.getFrame(f).layers.get(d); - if (fl == null) { - if ((f + 1) % 5 == 0) { - g.setColor(getEmptyFrameSecondColor()); - } else { - g.setColor(getEmptyFrameColor()); - } - g.fillRect(f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - g.setColor(emptyBorderColor); - g.drawRect(f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - } + g.drawRect(f * frameWidth, d * frameHeight, frameWidth, frameHeight); } } + + // draw selected cell + if (cursor != null) { + g.setColor(getSelectedColor()); + g.fillRect(cursor.x * frameWidth + 1, cursor.y * frameHeight + 1, frameWidth - 1, frameHeight - 1); + } + + g.setColor(aColor); + g.setFont(getFont().deriveFont(fontSize)); + int awidth = g.getFontMetrics().stringWidth("a"); for (int f = start_f; f <= end_f; f++) { - for (int d = start_d; d <= end_d; d++) { + if (!timeline.getFrame(f).actions.isEmpty()) { + g.drawString("a", f * frameWidth + frameWidth / 2 - awidth / 2, frameHeight / 2 + fontSize / 2); + } + } + + Map depthMaxFrames = timeline.getDepthMaxFrame(); + for (int d = start_d; d <= end_d; d++) { + int maxFrame = depthMaxFrames.containsKey(d) ? depthMaxFrames.get(d) : -1; + if (maxFrame < 0) { + continue; + } + + int end_f2 = Math.min(end_f, maxFrame); + int start_f2 = Math.min(start_f, end_f2); + + // find the start frame number of the current block + DepthState dsStart = timeline.getFrame(start_f2).layers.get(d); + for (; start_f2 >= 1; start_f2--) { + DepthState ds = timeline.getFrame(start_f2 - 1).layers.get(d); + if (((dsStart == null) != (ds == null)) + || (ds != null && dsStart.characterId != ds.characterId)) { + break; + } + } + + for (int f = start_f2; f <= end_f2; f++) { DepthState fl = timeline.getFrame(f).layers.get(d); boolean motionTween = fl == null ? false : fl.motionTween; - DepthState flNext = null; - if (f < max_f) { - flNext = timeline.getFrame(f + 1).layers.get(d); - } - DepthState flPrev = null; - if (f > 0) { - flPrev = timeline.getFrame(f - 1).layers.get(d); - } + DepthState flNext = f < max_f ? timeline.getFrame(f + 1).layers.get(d) : null; + DepthState flPrev = f > 0 ? timeline.getFrame(f - 1).layers.get(d) : null; CharacterTag cht = fl == null ? null : timeline.swf.getCharacter(fl.characterId); boolean shapeTween = cht != null && (cht instanceof MorphShapeTag); - boolean motionTweenStart = (!motionTween) && (flNext != null && flNext.motionTween); - boolean motionTweenEnd = (!motionTween) && (flPrev != null && flPrev.motionTween); + boolean motionTweenStart = !motionTween && (flNext != null && flNext.motionTween); + boolean motionTweenEnd = !motionTween && (flPrev != null && flPrev.motionTween); //boolean shapeTweenStart = shapeTween && (flPrev == null || flPrev.characterId != fl.characterId); //boolean shapeTweenEnd = shapeTween && (flNext == null || flNext.characterId != fl.characterId); - if (motionTweenStart || motionTweenEnd) { - motionTween = true; - } - boolean selected = false; - if (cursor != null) { - if (f == cursor.x && d == cursor.y) { - selected = true; - } - } - if (selected) { - //if (!(fl != null && (flNext == null || flNext.key))) { - g.setColor(getSelectedColor()); - g.fillRect(f * TimelinePanel.FRAME_WIDTH + 1, d * TimelinePanel.FRAME_HEIGHT + 1, TimelinePanel.FRAME_WIDTH - 1, TimelinePanel.FRAME_HEIGHT - 1); - //} - } - + /*if (motionTweenStart || motionTweenEnd) { + motionTween = true; + }*/ + int draw_f = f; + int num_frames = 1; + Color backColor; + BlockType blockType; if (fl == null) { - - if (timeline.getDepthMaxFrame().containsKey(d) && f < timeline.getDepthMaxFrame().get(d)) { - int draw_f = f; - - DepthState prev_ds = f < 1 ? null : timeline.getFrame(f - 1).layers.get(d); - - if (f == 0 || prev_ds != null) { - draw_f = f; - keyfound[d - start_d] = true; - } else if (!keyfound[d - start_d]) { - for (; draw_f >= 0; draw_f--) { - if (timeline.getFrame(draw_f).layers.get(d) != null) { - if (timeline.getFrame(draw_f).layers.get(d).characterId != -1) { - break; - } - } - } - } else { - continue; - } - int num_frames = 1; - for (int i = draw_f + 1; i < timeline.getFrameCount(); i++) { - if (timeline.getFrame(i).layers.get(d) != null) { - if (timeline.getFrame(i).layers.get(d).characterId != -1) { - break; - } - } - num_frames++; - } - g.setColor(getEmptyFrameColor()); - g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - g.setColor(borderColor); - g.drawRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - - if (selected) { - g.setColor(getSelectedColor()); - g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - } - - g.setColor(keyColor); - g.drawOval(draw_f * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT * 3 / 4 - TimelinePanel.FRAME_WIDTH / 2 / 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_WIDTH / 2); - - if (num_frames > 1) { - if (cursor != null && cursor.y == d && cursor.x == f + num_frames - 1) { - g.setColor(getSelectedColor()); - g.fillRect((f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + 1, d * TimelinePanel.FRAME_HEIGHT + 1, TimelinePanel.FRAME_WIDTH - 1, TimelinePanel.FRAME_HEIGHT - 1); - } - - g.setColor(stopColor); - g.fillRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2); - g.setColor(stopBorderColor); - g.drawRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2); - - g.setColor(borderLinesColor); - for (int n = draw_f + 1; n < draw_f + num_frames; n++) { - g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + borderLinesLength); - g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - borderLinesLength); - } - } - } - - if (d == 0) { - if (!timeline.getFrame(f).actions.isEmpty()) { - g.setColor(aColor); - g.setFont(getFont().deriveFont(fontSize)); - int awidth = g.getFontMetrics().stringWidth("a"); - g.drawString("a", f * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2 - awidth / 2, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 + fontSize / 2); - } - } - continue; - } else { - - int draw_f = 0; - if (fl.key) { - draw_f = f; - keyfound[d - start_d] = true; - } else if (!keyfound[d - start_d]) { - for (int k = f - 1; k >= 0; k--) { - fl = timeline.getFrame(k).layers.get(d); - if (fl == null) { - break; - } - if (fl.key) { - keyfound[d - start_d] = true; - draw_f = k; - break; - } - } - } else { - continue; - } - int num_frames = 1; - for (int n = draw_f + 1; n < timeline.getFrameCount(); n++) { - fl = timeline.getFrame(n).layers.get(d); - if (fl == null) { - break; - } - if (fl.key) { + for (; f + 1 < timeline.getFrameCount(); f++) { + fl = timeline.getFrame(f + 1).layers.get(d); + if (fl != null && fl.characterId != -1) { break; } + num_frames++; } - g.setColor(getFrameColor()); - g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - if (motionTween) { - g.setColor(motionTweenColor); - g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - } - if (shapeTween) { - g.setColor(shapeTweenColor); - g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - } - - if (selected) { - g.setColor(getSelectedColor()); - g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - } - - g.setColor(borderColor); - g.drawRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT); - //} - if ((motionTween || shapeTween)) { - g.drawLine(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT * 3 / 4, - draw_f * TimelinePanel.FRAME_WIDTH + num_frames * TimelinePanel.FRAME_WIDTH - TimelinePanel.FRAME_WIDTH / 2, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT * 3 / 4 - ); - } - g.setColor(keyColor); - g.fillOval(draw_f * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT * 3 / 4 - TimelinePanel.FRAME_WIDTH / 2 / 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_WIDTH / 2); - if ((motionTween || shapeTween)) { - g.fillOval((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT * 3 / 4 - TimelinePanel.FRAME_WIDTH / 2 / 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_WIDTH / 2); - } - - if (num_frames > 1) { - if (cursor != null && cursor.y == d && cursor.x == f + num_frames - 1) { - g.setColor(getSelectedColor()); - g.fillRect((f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + 1, d * TimelinePanel.FRAME_HEIGHT + 1, TimelinePanel.FRAME_WIDTH - 1, TimelinePanel.FRAME_HEIGHT - 1); + backColor = getEmptyFrameColor(); + blockType = BlockType.EMPTY; + } else { + for (; f + 1 < timeline.getFrameCount(); f++) { + fl = timeline.getFrame(f + 1).layers.get(d); + if (fl == null || fl.key) { + break; } - if (!(motionTween || shapeTween)) { - g.setColor(stopColor); - g.fillRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2); - g.setColor(stopBorderColor); - g.drawRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2); - } - g.setColor(borderLinesColor); - for (int n = draw_f + 1; n < draw_f + num_frames; n++) { - g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + borderLinesLength); - g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - borderLinesLength); - } + num_frames++; } + + backColor = shapeTween ? shapeTweenColor : motionTween ? motionTweenColor : getFrameColor(); + blockType = shapeTween ? BlockType.SHAPE_TWEEN : motionTween ? BlockType.MOTION_TWEEN : BlockType.NORMAL; } + + drawBlock(g, backColor, d, draw_f, num_frames, blockType); } } if (cursor != null && cursor.x >= start_f && cursor.x <= end_f) { g.setColor(TimelinePanel.selectedBorderColor); - g.drawLine(cursor.x * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2, 0, cursor.x * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2, getHeight()); + g.drawLine(cursor.x * frameWidth + frameWidth / 2, 0, cursor.x * frameWidth + frameWidth / 2, getHeight()); + } + } + + private void drawBlock(Graphics2D g, Color backColor, int depth, int frame, int num_frames, BlockType blockType) { + int frameWidth = TimelinePanel.FRAME_WIDTH; + int frameHeight = TimelinePanel.FRAME_HEIGHT; + + g.setColor(backColor); + g.fillRect(frame * frameWidth, depth * frameHeight, num_frames * frameWidth, frameHeight); + g.setColor(borderColor); + g.drawRect(frame * frameWidth, depth * frameHeight, num_frames * frameWidth, frameHeight); + + boolean selected = false; + if (cursor != null && frame <= cursor.x && (frame + num_frames) > cursor.x && depth == cursor.y) { + selected = true; + } + + if (selected) { + g.setColor(getSelectedColor()); + g.fillRect(cursor.x * frameWidth + 1, depth * frameHeight + 1, frameWidth - 1, frameHeight - 1); + } + + boolean isTween = blockType == BlockType.MOTION_TWEEN || blockType == BlockType.SHAPE_TWEEN; + + g.setColor(keyColor); + if (isTween) { + g.drawLine(frame * frameWidth, depth * frameHeight + frameHeight * 3 / 4, + frame * frameWidth + num_frames * frameWidth - frameWidth / 2, depth * frameHeight + frameHeight * 3 / 4 + ); + } + + if (blockType == BlockType.EMPTY) { + g.drawOval(frame * frameWidth + frameWidth / 4, depth * frameHeight + frameHeight * 3 / 4 - frameWidth / 2 / 2, frameWidth / 2, frameWidth / 2); + } else { + g.fillOval(frame * frameWidth + frameWidth / 4, depth * frameHeight + frameHeight * 3 / 4 - frameWidth / 2 / 2, frameWidth / 2, frameWidth / 2); + } + + if (num_frames > 1) { + int endFrame = frame + num_frames - 1; + if (isTween) { + g.fillOval(endFrame * frameWidth + frameWidth / 4, depth * frameHeight + frameHeight * 3 / 4 - frameWidth / 2 / 2, frameWidth / 2, frameWidth / 2); + } else { + g.setColor(stopColor); + g.fillRect(endFrame * frameWidth + frameWidth / 4, depth * frameHeight + frameHeight / 2 - 2, frameWidth / 2, frameHeight / 2); + g.setColor(stopBorderColor); + g.drawRect(endFrame * frameWidth + frameWidth / 4, depth * frameHeight + frameHeight / 2 - 2, frameWidth / 2, frameHeight / 2); + } + + g.setColor(borderLinesColor); + for (int n = frame + 1; n < frame + num_frames; n++) { + g.drawLine(n * frameWidth, depth * frameHeight + 1, n * frameWidth, depth * frameHeight + borderLinesLength); + g.drawLine(n * frameWidth, depth * frameHeight + frameHeight - 1, n * frameWidth, depth * frameHeight + frameHeight - borderLinesLength); + } } }