From 901b175efeec2770b8cd6e24c5e993fcb955fcc5 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 8 Jul 2015 04:46:44 +0200 Subject: [PATCH] Created GuiMarkerTimeline to display Markers again Created helper methods in ReplayHandler to provide information about MarkerKeyframes --- .../{ => timelines}/GuiKeyframeTimeline.java | 33 +--- .../elements/timelines/GuiMarkerTimeline.java | 182 ++++++++++++++++++ .../elements/{ => timelines}/GuiTimeline.java | 3 +- .../gui/overlay/GuiReplayOverlay.java | 9 +- .../replaymod/holders/MarkerKeyframe.java | 2 +- .../replaymod/replay/ReplayHandler.java | 10 +- 6 files changed, 205 insertions(+), 34 deletions(-) rename src/main/java/eu/crushedpixel/replaymod/gui/elements/{ => timelines}/GuiKeyframeTimeline.java (88%) create mode 100644 src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiMarkerTimeline.java rename src/main/java/eu/crushedpixel/replaymod/gui/elements/{ => timelines}/GuiTimeline.java (98%) diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/elements/GuiKeyframeTimeline.java b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiKeyframeTimeline.java similarity index 88% rename from src/main/java/eu/crushedpixel/replaymod/gui/elements/GuiKeyframeTimeline.java rename to src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiKeyframeTimeline.java index 6e0150ed..b1b36345 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/elements/GuiKeyframeTimeline.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiKeyframeTimeline.java @@ -1,4 +1,4 @@ -package eu.crushedpixel.replaymod.gui.elements; +package eu.crushedpixel.replaymod.gui.elements.timelines; import eu.crushedpixel.replaymod.gui.GuiEditKeyframe; import eu.crushedpixel.replaymod.holders.Keyframe; @@ -65,9 +65,7 @@ public class GuiKeyframeTimeline extends GuiTimeline { this.dragging = false; } } else { // If we didn't then just update the cursor - if(this.placeKeyframes) { //only if it's the keyframe timeline - ReplayHandler.setRealTimelineCursor((int) time); - } + ReplayHandler.setRealTimelineCursor((int) time); this.dragging = true; } this.clickTime = currentTime; @@ -89,7 +87,7 @@ public class GuiKeyframeTimeline extends GuiTimeline { ReplayHandler.getTimeKeyframes().sort(); dragging = true; } - } else if (dragging && placeKeyframes) { + } else if (dragging) { ReplayHandler.setRealTimelineCursor((int) time); } } @@ -127,15 +125,12 @@ public class GuiKeyframeTimeline extends GuiTimeline { while(iterator.hasNext()) { Keyframe kf2 = iterator.next(); + if(kf.getValue().getSpectatedEntityID() + .equals(kf2.getValue().getSpectatedEntityID())) { - if(kf2.getValue() instanceof Position) { - if(kf.getValue().getSpectatedEntityID() - .equals(kf2.getValue().getSpectatedEntityID())) { - - nextSpectatorKeyframeRealTime = kf2.getRealTimestamp(); - } - break; + nextSpectatorKeyframeRealTime = kf2.getRealTimestamp(); } + break; } int i2 = iterator.previousIndex(); @@ -174,20 +169,6 @@ public class GuiKeyframeTimeline extends GuiTimeline { return (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth); } - @Override - public void drawOverlay(Minecraft mc, int mouseX, int mouseY) { - boolean drawn = false; - - int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT; - - long leftTime = Math.round(timeStart * timelineLength); - double segmentLength = timelineLength * zoom; - - if(!drawn) { - super.drawOverlay(mc, mouseX, mouseY); - } - } - private void drawKeyframe(Keyframe kf, int bodyWidth, long leftTime, long rightTime, double segmentLength) { if (kf.getRealTimestamp() <= rightTime && kf.getRealTimestamp() >= leftTime) { int textureX; diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiMarkerTimeline.java b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiMarkerTimeline.java new file mode 100644 index 00000000..4c20f8fd --- /dev/null +++ b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiMarkerTimeline.java @@ -0,0 +1,182 @@ +package eu.crushedpixel.replaymod.gui.elements.timelines; + +import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.holders.MarkerKeyframe; +import eu.crushedpixel.replaymod.replay.ReplayHandler; +import eu.crushedpixel.replaymod.utils.MouseUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import org.lwjgl.util.Point; + +import java.awt.*; + +public class GuiMarkerTimeline extends GuiTimeline { + private static final int KEYFRAME_MARKER_X = 109; + private static final int KEYFRAME_MARKER_Y = 20; + + private MarkerKeyframe clickedKeyFrame; + private long clickTime; + private boolean dragging; + + public GuiMarkerTimeline(int positionX, int positionY, int width, boolean showMarkers) { + super(positionX, positionY, width); + this.showMarkers = showMarkers; + } + + @Override + public void mouseClick(Minecraft mc, int mouseX, int mouseY, int button) { + if(!enabled) return; + + //left mouse button + if(button == 0) { + long time = getTimeAt(mouseX, mouseY); + if(time == -1) { + return; + } + + int tolerance = (int) (2 * Math.round(zoom * timelineLength / width)); + + MarkerKeyframe closest = null; + if(mouseY >= positionY + BORDER_TOP + 10) { + closest = ReplayHandler.getClosestMarkerForRealTime((int) time, tolerance); + } + + ReplayHandler.selectMarkerKeyframe(closest); + + if(closest == null) { //if no keyframe clicked, jump in time + ReplayMod.overlay.performJump(getTimeAt(mouseX, mouseY)); + } else { + // If we clicked on a key frame, then continue monitoring the mouse for movements + long currentTime = System.currentTimeMillis(); + if(closest != null) { + if(currentTime - clickTime < 500) { // if double clicked then open GUI instead + //TODO: Make Marker Name editable + this.clickedKeyFrame = null; + } else { + this.clickedKeyFrame = closest; + this.dragging = false; + } + } else { // If we didn't then just update the cursor + this.dragging = true; + } + this.clickTime = currentTime; + } + + } else if(button == 1) { + + long time = getTimeAt(mouseX, mouseY); + if(time == -1) { + return; + } + + int tolerance = (int) (2 * Math.round(zoom * timelineLength / width)); + + MarkerKeyframe closest = null; + if(mouseY >= positionY + BORDER_TOP + 10) { + closest = ReplayHandler.getClosestMarkerForRealTime((int) time, tolerance); + } + + if(closest != null) { + //Jump to clicked Marker Keyframe + ReplayHandler.setLastPosition(closest.getPosition()); + ReplayMod.replaySender.jumpToTime(closest.getRealTimestamp()); + } + } + } + + @Override + public void mouseDrag(Minecraft mc, int mouseX, int mouseY, int button) { + if(!enabled) return; + long time = getTimeAt(mouseX, mouseY); + if (time != -1) { + if (clickedKeyFrame != null) { + int tolerance = (int) (2 * Math.round(zoom * timelineLength / width)); + + if (dragging || Math.abs(clickedKeyFrame.getRealTimestamp() - time) > tolerance) { + clickedKeyFrame.setRealTimestamp((int) time); + dragging = true; + } + } + } + } + + @Override + public void mouseRelease(Minecraft mc, int mouseX, int mouseY, int button) { + mouseDrag(mc, mouseX, mouseY, button); + clickedKeyFrame = null; + dragging = false; + } + + @Override + public void draw(Minecraft mc, int mouseX, int mouseY) { + super.draw(mc, mouseX, mouseY); + + int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT; + + long leftTime = Math.round(timeStart * timelineLength); + long rightTime = Math.round((timeStart + zoom) * timelineLength); + + double segmentLength = timelineLength * zoom; + + drawTimelineCursor(leftTime, rightTime, bodyWidth); + + //Draw Keyframe logos + for (MarkerKeyframe kf : ReplayHandler.getMarkers()) { + if (kf != null && !kf.equals(ReplayHandler.getSelectedMarkerKeyframe())) + drawKeyframe(kf, bodyWidth, leftTime, rightTime, segmentLength); + } + + if(ReplayHandler.getSelectedMarkerKeyframe() != null) { + drawKeyframe(ReplayHandler.getSelectedMarkerKeyframe(), bodyWidth, leftTime, rightTime, segmentLength); + } + } + + private int getKeyframeX(int timestamp, long leftTime, int bodyWidth, double segmentLength) { + long positionInSegment = timestamp - leftTime; + double fractionOfSegment = positionInSegment / segmentLength; + return (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth); + } + + @Override + public void drawOverlay(Minecraft mc, int mouseX, int mouseY) { + boolean drawn = false; + + int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT; + + long leftTime = Math.round(timeStart * timelineLength); + double segmentLength = timelineLength * zoom; + + for(MarkerKeyframe marker : ReplayHandler.getMarkers()) { + int keyframeX = getKeyframeX(marker.getRealTimestamp(), leftTime, bodyWidth, segmentLength); + + if(MouseUtils.isMouseWithinBounds(keyframeX - 2, this.positionY + BORDER_TOP + 10 + 1, 5, 5)) { + Point mouse = MouseUtils.getMousePos(); + String markerName = marker.getName(); + if(markerName == null) markerName = I18n.format("replaymod.gui.ingame.unnamedmarker"); + ReplayMod.tooltipRenderer.drawTooltip(mouse.getX(), mouse.getY(), markerName, null, Color.WHITE); + + drawn = true; + } + } + + if(!drawn) { + super.drawOverlay(mc, mouseX, mouseY); + } + } + + private void drawKeyframe(MarkerKeyframe kf, int bodyWidth, long leftTime, long rightTime, double segmentLength) { + if (kf.getRealTimestamp() <= rightTime && kf.getRealTimestamp() >= leftTime) { + int textureX = KEYFRAME_MARKER_X; + int textureY = KEYFRAME_MARKER_Y; + int y = positionY+10; + + int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength); + + if (ReplayHandler.isSelected(kf)) { + textureX += 5; + } + + rect(keyframeX - 2, y + BORDER_TOP, textureX, textureY, 5, 5); + } + } +} \ No newline at end of file diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/elements/GuiTimeline.java b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiTimeline.java similarity index 98% rename from src/main/java/eu/crushedpixel/replaymod/gui/elements/GuiTimeline.java rename to src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiTimeline.java index 571c9edc..b09698f4 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/elements/GuiTimeline.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiTimeline.java @@ -1,6 +1,7 @@ -package eu.crushedpixel.replaymod.gui.elements; +package eu.crushedpixel.replaymod.gui.elements.timelines; import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.gui.elements.GuiElement; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Gui; import net.minecraft.client.renderer.GlStateManager; diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java b/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java index 1eac1617..5af6fc2a 100755 --- a/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java @@ -7,6 +7,8 @@ import eu.crushedpixel.replaymod.gui.GuiMouseInput; import eu.crushedpixel.replaymod.gui.GuiRenderSettings; import eu.crushedpixel.replaymod.gui.GuiReplaySpeedSlider; import eu.crushedpixel.replaymod.gui.elements.*; +import eu.crushedpixel.replaymod.gui.elements.timelines.GuiKeyframeTimeline; +import eu.crushedpixel.replaymod.gui.elements.timelines.GuiMarkerTimeline; import eu.crushedpixel.replaymod.holders.Keyframe; import eu.crushedpixel.replaymod.holders.Position; import eu.crushedpixel.replaymod.holders.TimestampValue; @@ -232,10 +234,7 @@ public class GuiReplayOverlay extends Gui { } }, "replaymod.gui.ingame.menu.zoomout"); - //TODO: GuiMarkerKeyframeTimeline - private final GuiKeyframeTimeline timeline = new GuiKeyframeTimeline(TIMELINE_X, TOP_ROW - 1, WIDTH - 14 - TIMELINE_X, false, false, false) { - - }; + private final GuiMarkerTimeline timeline = new GuiMarkerTimeline(TIMELINE_X, TOP_ROW - 1, WIDTH - 14 - TIMELINE_X, false); private final GuiKeyframeTimeline timelineReal = new GuiKeyframeTimeline(TIMELINE_REAL_X, BOTTOM_ROW - 1, TIMELINE_REAL_WIDTH, true, true, true); { @@ -339,7 +338,7 @@ public class GuiReplayOverlay extends Gui { } } - private void performJump(long timelineTime) { + public void performJump(long timelineTime) { if (timelineTime != -1) { // Click on timeline //When hurrying, no Timeline jumping etc. is possible if(!ReplayMod.replaySender.isHurrying()) { diff --git a/src/main/java/eu/crushedpixel/replaymod/holders/MarkerKeyframe.java b/src/main/java/eu/crushedpixel/replaymod/holders/MarkerKeyframe.java index 654fd65a..29dec7df 100644 --- a/src/main/java/eu/crushedpixel/replaymod/holders/MarkerKeyframe.java +++ b/src/main/java/eu/crushedpixel/replaymod/holders/MarkerKeyframe.java @@ -5,7 +5,7 @@ import lombok.Data; @Data @AllArgsConstructor -public final class MarkerKeyframe { +public class MarkerKeyframe { private int realTimestamp; private Position position; diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java index 700e8c33..88e25287 100755 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java @@ -390,6 +390,12 @@ public class ReplayHandler { selectedKeyframe = kf; } + public static boolean isSelected(MarkerKeyframe kf) { + return kf == selectedMarkerKeyframe; + } + + public static void selectMarkerKeyframe(MarkerKeyframe kf) { selectedMarkerKeyframe = kf; } + public static boolean isInReplay() { return inReplay; } @@ -456,7 +462,7 @@ public class ReplayHandler { ReplayMod.overlay.resetUI(true); } catch(Exception e) { e.printStackTrace(); - // TODO: Fix exceptionsudo + // TODO: Fix exception } //Load lighting and trigger update @@ -544,6 +550,8 @@ public class ReplayHandler { return selectedKeyframe; } + public static MarkerKeyframe getSelectedMarkerKeyframe() { return selectedMarkerKeyframe; } + public static int getRealTimelineCursor() { return realTimelinePosition; }