Add markers to timeline

This commit is contained in:
johni0702
2015-11-08 11:25:26 +01:00
parent dfd133d84f
commit 14941c15bb
3 changed files with 153 additions and 154 deletions

View File

@@ -1,182 +1,179 @@
package com.replaymod.replay.gui.overlay; package com.replaymod.replay.gui.overlay;
import de.johni0702.replaystudio.data.Marker;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.timelines.GuiTimeline;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.MouseUtils; import de.johni0702.minecraft.gui.GuiRenderer;
import net.minecraft.client.Minecraft; import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.element.advanced.AbstractGuiTimeline;
import de.johni0702.minecraft.gui.function.Draggable;
import de.johni0702.replaystudio.data.Marker;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.I18n;
import net.minecraft.util.MathHelper;
import org.lwjgl.util.Point; import org.lwjgl.util.Point;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
import java.awt.*; public class GuiMarkerTimeline extends AbstractGuiTimeline<GuiMarkerTimeline> implements Draggable {
protected static final int TEXTURE_MARKER_X = 109;
public class GuiMarkerTimeline extends GuiTimeline { protected static final int TEXTURE_MARKER_Y = 20;
private static final int KEYFRAME_MARKER_X = 109; protected static final int TEXTURE_MARKER_SELECTED_X = 114;
private static final int KEYFRAME_MARKER_Y = 20; protected static final int TEXTURE_MARKER_SELECTED_Y = 20;
protected static final int MARKER_SIZE = 5;
private final ReplayHandler replayHandler; private final ReplayHandler replayHandler;
private ReadableDimension lastSize;
private Marker selectedMarker; private Marker selectedMarker;
private Marker clickedMarker; private int draggingStartX;
private long clickTime; private int draggingTimeDelta;
private boolean dragging; private boolean dragging;
private long lastClickTime;
public GuiMarkerTimeline(ReplayHandler replayHandler, int positionX, int positionY, int width, int height) { public GuiMarkerTimeline(ReplayHandler replayHandler) {
super(positionX, positionY, width, height);
this.replayHandler = replayHandler; this.replayHandler = replayHandler;
this.showMarkers = false;
} }
@Override @Override
public boolean mouseClick(Minecraft mc, int mouseX, int mouseY, int button) { protected GuiMarkerTimeline getThis() {
if(!enabled) return false; return this;
}
long time = getTimeAt(mouseX, mouseY); @Override
if(time == -1) { public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
return false; lastSize = size;
super.draw(renderer, size, renderInfo);
drawMarkers(renderer, size);
}
protected void drawMarkers(GuiRenderer renderer, ReadableDimension size) {
renderer.bindTexture(ReplayMod.TEXTURE);
for (Marker marker : replayHandler.getMarkers()) {
drawMarker(renderer, size, marker);
}
}
protected void drawMarker(GuiRenderer renderer, ReadableDimension size, Marker marker) {
int visibleLength = (int) (getLength() * getZoom());
int markerPos = MathHelper.clamp_int(marker.getTime(), getOffset(), getOffset() + visibleLength);
double positionInVisible = markerPos - getOffset();
double fractionOfVisible = positionInVisible / visibleLength;
int markerX = (int) (BORDER_LEFT + fractionOfVisible * (size.getWidth() - BORDER_LEFT - BORDER_RIGHT));
int textureX, textureY;
if (marker.equals(selectedMarker)) {
textureX = TEXTURE_MARKER_SELECTED_X;
textureY = TEXTURE_MARKER_SELECTED_Y;
} else {
textureX = TEXTURE_MARKER_X;
textureY = TEXTURE_MARKER_Y;
}
renderer.drawTexturedRect(markerX - 2, size.getHeight() - BORDER_BOTTOM - MARKER_SIZE,
textureX, textureY, MARKER_SIZE, MARKER_SIZE);
}
/**
* Returns the marker which the mouse is at.
* @param mouseX X coordinate of the mouse
* @param mouseY Y coordinate of the mouse
* @return The marker or {@code null} if the mouse isn't on a marker
*/
protected Marker getMarkerAt(int mouseX, int mouseY) {
if (lastSize == null) {
return null;
}
Point mouse = new Point(mouseX, mouseY);
getContainer().convertFor(this, mouse);
mouseX = mouse.getX();
mouseY = mouse.getY();
if (mouseX < 0 || mouseY < lastSize.getHeight() - BORDER_BOTTOM - MARKER_SIZE
|| mouseX > lastSize.getWidth() || mouseY > lastSize.getHeight() - BORDER_BOTTOM) {
return null;
} }
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width)); int visibleLength = (int) (getLength() * getZoom());
int contentWidth = lastSize.getWidth() - BORDER_LEFT - BORDER_RIGHT;
Marker closest = null; for (Marker marker : replayHandler.getMarkers()) {
if(mouseY >= positionY + BORDER_TOP + 10) { int markerPos = MathHelper.clamp_int(marker.getTime(), getOffset(), getOffset() + visibleLength);
long distance = tolerance; double positionInVisible = markerPos - getOffset();
for (Marker m : replayHandler.getMarkers()) { double fractionOfVisible = positionInVisible / visibleLength;
long d = Math.abs(m.getTime() - time); int markerX = (int) (BORDER_LEFT + fractionOfVisible * contentWidth);
if (d <= distance) { if (Math.abs(markerX - mouseX) < 3) {
closest = m; return marker;
distance = d;
}
} }
} }
return null;
}
//left mouse button @Override
if(button == 0) { public boolean mouseClick(ReadablePoint position, int button) {
if(closest == null) { //if no keyframe clicked, jump in time Marker marker = getMarkerAt(position.getX(), position.getY());
replayHandler.doJump((int) getTimeAt(mouseX, mouseY), true); if (marker != null) {
} else { if (button == 0) { // Left click
selectedMarker = closest; long now = System.currentTimeMillis();
// If we clicked on a key frame, then continue monitoring the mouse for movements selectedMarker = marker;
long currentTime = System.currentTimeMillis(); if (Math.abs(lastClickTime - now) > 500) { // Single click
if(currentTime - clickTime < 500) { // if double clicked then open GUI instead draggingStartX = position.getX();
// mc.displayGuiScreen(GuiEditKeyframe.create(closest)); draggingTimeDelta = marker.getTime() - getTimeAt(position.getX(), position.getY());
// TODO Edit Gui } else { // Double click
this.clickedMarker = null; // TODO: Open Edit GUI
} else {
this.clickedMarker = closest;
this.dragging = false;
} }
this.clickTime = currentTime; lastClickTime = now;
} } else if (button == 1) { // Right click
selectedMarker = null;
} else if(button == 1) {
if(closest != null) {
//Jump to clicked Marker Keyframe (explicitly force to jump to this position)
replayHandler.setTargetPosition(new AdvancedPosition( replayHandler.setTargetPosition(new AdvancedPosition(
closest.getX(), closest.getY(), closest.getZ(), marker.getX(), marker.getY(), marker.getZ(),
closest.getPitch(), closest.getYaw(), closest.getRoll() marker.getPitch(), marker.getYaw(), marker.getRoll()
)); ));
replayHandler.doJump(marker.getTime(), false);
//perform the jump, telling the Overlay not to override the last position value
replayHandler.doJump(closest.getTime(), false);
} }
return true;
} }
return super.mouseClick(position, button);
return isHovering(mouseX, mouseY);
} }
@Override @Override
public void mouseDrag(Minecraft mc, int mouseX, int mouseY, int button) { public boolean mouseDrag(ReadablePoint position, int button, long timeSinceLastCall) {
if(!enabled) return; if (selectedMarker != null) {
long time = getTimeAt(mouseX, mouseY); int diff = position.getX() - draggingStartX;
if (time != -1) { if (Math.abs(diff) > MARKER_SIZE) {
if (clickedMarker != null) { dragging = true;
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width)); }
if (dragging) {
if (dragging || Math.abs(clickedMarker.getTime() - time) > tolerance) { int timeAt = getTimeAt(position.getX(), position.getY());
clickedMarker.setTime((int) time); if (timeAt != -1) {
dragging = true; selectedMarker.setTime(draggingTimeDelta + timeAt);
} }
return true;
} }
} }
return false;
} }
@Override @Override
public void mouseRelease(Minecraft mc, int mouseX, int mouseY, int button) { public boolean mouseRelease(ReadablePoint position, int button) {
mouseDrag(mc, mouseX, mouseY, button); if (selectedMarker != null) {
clickedMarker = null; mouseDrag(position, button, 0);
if (dragging) { if (dragging) {
replayHandler.saveMarkers(); dragging = false;
dragging = false; replayHandler.saveMarkers();
return true;
}
} }
return false;
} }
@Override @Override
public void draw(Minecraft mc, int mouseX, int mouseY) { protected String getTooltipText(RenderInfo renderInfo) {
super.draw(mc, mouseX, mouseY); Marker marker = getMarkerAt(renderInfo.mouseX, renderInfo.mouseY);
if (marker != null) {
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT; return marker.getName() != null ? marker.getName() : I18n.format("replaymod.gui.ingame.unnamedmarker");
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 (Marker marker : replayHandler.getMarkers()) {
drawMarker(marker, bodyWidth, leftTime, rightTime, segmentLength);
} }
return super.getTooltipText(renderInfo);
} }
}
private int getMarkerX(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 (Marker marker : replayHandler.getMarkers()) {
int markerX = getMarkerX(marker.getTime(), leftTime, bodyWidth, segmentLength);
if(MouseUtils.isMouseWithinBounds(markerX - 2, this.positionY + BORDER_TOP + 10 + 1, 5, 5)) {
Point mouse = MouseUtils.getMousePos();
String markerName = marker.getName();
if(markerName == null || markerName.isEmpty()) 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 drawMarker(Marker marker, int bodyWidth, long leftTime, long rightTime, double segmentLength) {
if (marker.getTime() <= rightTime && marker.getTime() >= leftTime) {
int textureX = KEYFRAME_MARKER_X;
int textureY = KEYFRAME_MARKER_Y;
int y = positionY+10;
int keyframeX = getMarkerX(marker.getTime(), leftTime, bodyWidth, segmentLength);
if (selectedMarker == marker) {
textureX += 5;
}
rect(keyframeX - 2, y + BORDER_TOP, textureX, textureY, 5, 5);
}
}
}

View File

@@ -9,7 +9,6 @@ import de.johni0702.minecraft.gui.container.AbstractGuiOverlay;
import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.element.GuiSlider; import de.johni0702.minecraft.gui.element.GuiSlider;
import de.johni0702.minecraft.gui.element.GuiTexturedButton; import de.johni0702.minecraft.gui.element.GuiTexturedButton;
import de.johni0702.minecraft.gui.element.advanced.GuiTimeline;
import de.johni0702.minecraft.gui.element.advanced.IGuiTimeline; import de.johni0702.minecraft.gui.element.advanced.IGuiTimeline;
import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout;
@@ -26,19 +25,12 @@ import static com.replaymod.core.ReplayMod.TEXTURE_SIZE;
public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> { public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
private final ReplayHandler replayHandler;
public final GuiPanel topPanel = new GuiPanel(this) public final GuiPanel topPanel = new GuiPanel(this)
.setLayout(new HorizontalLayout(HorizontalLayout.Alignment.LEFT).setSpacing(5)); .setLayout(new HorizontalLayout(HorizontalLayout.Alignment.LEFT).setSpacing(5));
public final GuiTexturedButton playPauseButton = new GuiTexturedButton().setSize(20, 20) public final GuiTexturedButton playPauseButton = new GuiTexturedButton().setSize(20, 20)
.setTexture(ReplayMod.TEXTURE, TEXTURE_SIZE); .setTexture(ReplayMod.TEXTURE, TEXTURE_SIZE);
public final GuiSlider speedSlider = new GuiSlider().setSize(100, 20).setSteps(37); // 0.0 is not included public final GuiSlider speedSlider = new GuiSlider().setSize(100, 20).setSteps(37); // 0.0 is not included
public final GuiTimeline timeline = new GuiTimeline(){ public final GuiMarkerTimeline timeline;
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
setCursorPosition(replayHandler.getReplaySender().currentTimeStamp());
super.draw(renderer, size, renderInfo);
}
}.setSize(Integer.MAX_VALUE, 20);
/** /**
* This is not used by the replay module itself but may be used by other modules/extras to show * This is not used by the replay module itself but may be used by other modules/extras to show
@@ -48,7 +40,13 @@ public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
.setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(5)); .setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(5));
public GuiReplayOverlay(final ReplayHandler replayHandler) { public GuiReplayOverlay(final ReplayHandler replayHandler) {
this.replayHandler = replayHandler; timeline = new GuiMarkerTimeline(replayHandler){
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
setCursorPosition(replayHandler.getReplaySender().currentTimeStamp());
super.draw(renderer, size, renderInfo);
}
}.setSize(Integer.MAX_VALUE, 20);
topPanel.addElements(null, playPauseButton, speedSlider, timeline); topPanel.addElements(null, playPauseButton, speedSlider, timeline);
setLayout(new CustomLayout<GuiReplayOverlay>() { setLayout(new CustomLayout<GuiReplayOverlay>() {

View File

@@ -68,15 +68,19 @@ public abstract class AbstractGuiTimeline<T extends AbstractGuiTimeline<T>> exte
setTooltip(new GuiTooltip(){ setTooltip(new GuiTooltip(){
@Override @Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) { public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
int ms = getTimeAt(renderInfo.mouseX, renderInfo.mouseY); setText(getTooltipText(renderInfo));
int s = ms / 1000 % 60;
int m = ms / 1000 / 60;
setText(String.format("%02d:%02d", m, s));
super.draw(renderer, size, renderInfo); super.draw(renderer, size, renderInfo);
} }
}.setText("00:00")); }.setText("00:00"));
} }
protected String getTooltipText(RenderInfo renderInfo) {
int ms = getTimeAt(renderInfo.mouseX, renderInfo.mouseY);
int s = ms / 1000 % 60;
int m = ms / 1000 / 60;
return String.format("%02d:%02d", m, s);
}
@Override @Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) { public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
this.size = size; this.size = size;