From 30ebfe96bd264d9541bbb22795ee5be53cdaf98b Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Fri, 10 Jul 2015 03:36:57 +0200 Subject: [PATCH] Allowed GuiTimeline instances to have any height (instead of fixed 22px height) and updated draw() method accordingly Added HSV noise to GuiTimeline's textures to somewhat hide the repeating body texture Implemented GuiTimeline in GuiObjectManager's GuiObjectKeyframeTimeline Added asInt() method to TimestampValue, to avoid int casts of value field --- .../replaymod/gui/GuiObjectManager.java | 166 ++++++++---------- .../timelines/GuiKeyframeTimeline.java | 4 +- .../elements/timelines/GuiMarkerTimeline.java | 4 +- .../gui/elements/timelines/GuiTimeline.java | 73 ++++++-- .../gui/overlay/GuiReplayOverlay.java | 4 +- .../replaymod/holders/TimestampValue.java | 4 + .../resources/assets/replaymod/replay_gui.png | Bin 7260 -> 8398 bytes 7 files changed, 146 insertions(+), 109 deletions(-) diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiObjectManager.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiObjectManager.java index 59d8681b..cf66238f 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiObjectManager.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiObjectManager.java @@ -3,12 +3,12 @@ package eu.crushedpixel.replaymod.gui; import eu.crushedpixel.replaymod.assets.CustomImageObject; import eu.crushedpixel.replaymod.assets.ReplayAsset; import eu.crushedpixel.replaymod.gui.elements.*; +import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener; +import eu.crushedpixel.replaymod.gui.elements.timelines.GuiTimeline; import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay; import eu.crushedpixel.replaymod.interpolation.KeyframeList; import eu.crushedpixel.replaymod.replay.ReplayHandler; import eu.crushedpixel.replaymod.utils.MouseUtils; -import lombok.Getter; -import lombok.Setter; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; @@ -44,7 +44,7 @@ public class GuiObjectManager extends GuiScreen { private GuiTexturedButton zoomInButton, zoomOutButton; private ComposedElement anchorInputs, positionInputs, scaleInputs, orientationInputs, opacityInputs, numberInputs; - private ComposedElement allElements; + private ComposedElement disableElements, allElements; private static final int KEYFRAME_BUTTON_X = 80; private static final int KEYFRAME_BUTTON_Y = 40; @@ -57,11 +57,11 @@ public class GuiObjectManager extends GuiScreen { private GuiTexturedButton normal = new GuiTexturedButton(0, x, y, 20, 20, GuiReplayOverlay.replay_gui, KEYFRAME_BUTTON_X, KEYFRAME_BUTTON_Y, GuiReplayOverlay.TEXTURE_SIZE, GuiReplayOverlay.TEXTURE_SIZE, new Runnable() { - @Override - public void run() { - addKeyframe(line); - } - }, + @Override + public void run() { + addKeyframe(line); + } + }, null); private GuiTexturedButton selected = new GuiTexturedButton(0, x, y, 20, 20, @@ -84,6 +84,12 @@ public class GuiObjectManager extends GuiScreen { return normal; } } + + @Override + public void setEnabled(boolean enabled) { + selected.setEnabled(enabled); + normal.setEnabled(enabled); + } }; } @@ -128,7 +134,7 @@ public class GuiObjectManager extends GuiScreen { objectList = new GuiEntryList(fontRendererObj, 0, 0, 0, 0); objectList.setEmptyMessage(I18n.format("replaymod.gui.objects.empty")); - + addButton = new GuiAdvancedButton(0, 0, 0, 20, I18n.format("replaymod.gui.add"), new Runnable() { @Override public void run() { @@ -147,6 +153,18 @@ public class GuiObjectManager extends GuiScreen { nameInput.hint = I18n.format("replaymod.gui.objects.properties.name"); keyframeLists = new KeyframeList[5]; + + objectList.addSelectionListener(new SelectionListener() { + @Override + public void onSelectionChanged(int selectionIndex) { + CustomImageObject selectedObject = objectList.getElement(selectionIndex); + if(selectedObject != null) { + disableElements.setEnabled(true); + } else { + disableElements.setEnabled(false); + } + } + }); } String[] labelStrings = new String[] { @@ -165,6 +183,7 @@ public class GuiObjectManager extends GuiScreen { } } + disableElements = new ComposedElement(); allElements = new ComposedElement(); int inputWidth = 40; @@ -194,30 +213,34 @@ public class GuiObjectManager extends GuiScreen { child.addPart(button); child.addPart(label); - allElements.addPart(child); + disableElements.addPart(child); } - int timelineX = anchorZInput.xPosition + anchorZInput.width + 5; - int timelineY = anchorZInput.yPosition; + int timelineX = anchorZInput.xPosition + anchorZInput.width + 5 - 1; + int timelineY = anchorZInput.yPosition - 1; - int timelineWidth = this.width-10-timelineX; - int timelineHeight = this.height-10-10-timelineY; + int timelineWidth = this.width-10-timelineX + 2; + int timelineHeight = this.height-10-10-timelineY + 2; objectKeyframeTimeline = new GuiObjectKeyframeTimeline(timelineX, timelineY, timelineWidth, timelineHeight, keyframeLists); - allElements.addPart(objectKeyframeTimeline); + disableElements.addPart(objectKeyframeTimeline); - timelineScrollbar = new GuiScrollbar(timelineX, this.height-15, timelineWidth-19) { + timelineScrollbar = new GuiScrollbar(timelineX, this.height-15, timelineWidth-21) { @Override public void dragged() { - objectKeyframeTimeline.setLeftPosition((float)sliderPosition); + objectKeyframeTimeline.timeStart = (float)sliderPosition; } }; - allElements.addPart(timelineScrollbar); + + timelineScrollbar.size = objectKeyframeTimeline.zoom; + timelineScrollbar.sliderPosition = objectKeyframeTimeline.timeStart; + + disableElements.addPart(timelineScrollbar); zoomInButton = GuiReplayOverlay.texturedButton(width - 28, this.height-15, 40, 20, 9, new Runnable() { @Override public void run() { - objectKeyframeTimeline.setZoomScale(Math.max(0.025f, objectKeyframeTimeline.getZoomScale() - ZOOM_STEPS)); + objectKeyframeTimeline.zoom = Math.max(0.025f, objectKeyframeTimeline.zoom - ZOOM_STEPS); } }, "replaymod.gui.ingame.menu.zoomin"); @@ -225,13 +248,13 @@ public class GuiObjectManager extends GuiScreen { @Override public void run() { - objectKeyframeTimeline.setZoomScale(Math.min(1f, objectKeyframeTimeline.getZoomScale() + ZOOM_STEPS)); - objectKeyframeTimeline.setLeftPosition(Math.min(objectKeyframeTimeline.getLeftPos(), 1f - objectKeyframeTimeline.getZoomScale())); + objectKeyframeTimeline.zoom = Math.min(1f, objectKeyframeTimeline.zoom + ZOOM_STEPS); + objectKeyframeTimeline.timeStart = Math.min(objectKeyframeTimeline.timeStart, 1f - objectKeyframeTimeline.zoom); } }, "replaymod.gui.ingame.menu.zoomout"); - allElements.addPart(zoomInButton); - allElements.addPart(zoomOutButton); + disableElements.addPart(zoomInButton); + disableElements.addPart(zoomOutButton); objectList.xPosition = 11; objectList.yPosition = 11; @@ -246,7 +269,7 @@ public class GuiObjectManager extends GuiScreen { nameInput.yPosition = objectList.yPosition; nameInput.width = objectList.width; - allElements.addPart(nameInput); + disableElements.addPart(nameInput); dropdownLabel.positionX = (width/2)+5; int strWidth = fontRendererObj.getStringWidth(I18n.format("replaymod.gui.assets.filechooser")+": "); @@ -256,8 +279,8 @@ public class GuiObjectManager extends GuiScreen { dropdownLabel.positionY = assetDropdown.yPosition + 6; assetDropdown.width = (objectList.width-strWidth-5); - allElements.addPart(dropdownLabel); - allElements.addPart(assetDropdown); + disableElements.addPart(dropdownLabel); + disableElements.addPart(assetDropdown); addButton.xPosition = nameInput.xPosition; addButton.width = removeButton.width = nameInput.width/2 - 2; @@ -267,6 +290,10 @@ public class GuiObjectManager extends GuiScreen { allElements.addPart(addButton); allElements.addPart(removeButton); + allElements.addPart(disableElements); + + objectList.setSelectionIndex(objectList.getSelectionIndex()); // trigger an event for the SelectionListener + initialized = true; } @@ -313,93 +340,50 @@ public class GuiObjectManager extends GuiScreen { super.mouseReleased(mouseX, mouseY, mouseButton); } - public class GuiObjectKeyframeTimeline implements GuiElement { + public class GuiObjectKeyframeTimeline extends GuiTimeline { private KeyframeList[] keyframeLists; public int x, y, width, height; - @Getter @Setter - private int timestamp; - - @Getter @Setter - private float zoomScale; - - @Getter @Setter - private float leftPos; - - private int timelineLength = 10 * 60 * 1000; + private boolean dragging = false; public GuiObjectKeyframeTimeline(int x, int y, int width, int height, KeyframeList... keyframeLists) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; + super(x, y, width, height); this.keyframeLists = keyframeLists; - } - public void setLeftPosition(float leftPos) { - this.leftPos = leftPos; - } - - private boolean enabled = true; - - @Override - public void draw(Minecraft mc, int mouseX, int mouseY) { - drawRect(this.x - 1, this.y - 1, this.x + this.width + 1, this.y + this.height + 1, -6250336); - drawRect(this.x, this.y, this.x + this.width, this.y + this.height, -16777216); - - int count = keyframeLists.length; - int i = 0; - for(KeyframeList list : keyframeLists) { - int yPos = (int)(((float)i/count)*(height+2)); - int h = (int)(1f/count)*(height+2); - - if(i < count) - drawHorizontalLine(x, x+width, y+yPos+h-1, -6250336); - i++; - } - } - - @Override - public void drawOverlay(Minecraft mc, int mouseX, int mouseY) { - - } - - @Override - public boolean isHovering(int mouseX, int mouseY) { - return false; + this.zoom = 0.1; + this.timelineLength = 10 * 60 * 1000; + this.showMarkers = true; } @Override public void mouseClick(Minecraft mc, int mouseX, int mouseY, int button) { - + if(!enabled) return; + super.mouseClick(mc, mouseX, mouseY, button); + int time = (int) getTimeAt(mouseX, mouseY); + if(time != -1) { + cursorPosition = time; + dragging = true; + } } @Override public void mouseDrag(Minecraft mc, int mouseX, int mouseY, int button) { - + if(!enabled) return; + super.mouseDrag(mc, mouseX, mouseY, button); + if(dragging) { + int time = (int) getTimeAt(mouseX, mouseY); + if(time != -1) cursorPosition = time; + } } @Override public void mouseRelease(Minecraft mc, int mouseX, int mouseY, int button) { - - } - - @Override - public void buttonPressed(Minecraft mc, int mouseX, int mouseY, char key, int keyCode) { - - } - - @Override - public void tick(Minecraft mc) { - - } - - @Override - public void setEnabled(boolean enabled) { - this.enabled = enabled; + if(!enabled) return; + super.mouseRelease(mc, mouseX, mouseY, button); + this.dragging = false; } } } diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiKeyframeTimeline.java b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiKeyframeTimeline.java index b1b36345..534d62df 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiKeyframeTimeline.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiKeyframeTimeline.java @@ -23,9 +23,9 @@ public class GuiKeyframeTimeline extends GuiTimeline { private boolean timeKeyframes; private boolean placeKeyframes; - public GuiKeyframeTimeline(int positionX, int positionY, int width, boolean showMarkers, + public GuiKeyframeTimeline(int positionX, int positionY, int width, int height, boolean showMarkers, boolean showPlaceKeyframes, boolean showTimeKeyframes) { - super(positionX, positionY, width); + super(positionX, positionY, width, height); this.showMarkers = showMarkers; this.timeKeyframes = showTimeKeyframes; this.placeKeyframes = showPlaceKeyframes; 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 index 4c20f8fd..9eaa82a4 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiMarkerTimeline.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiMarkerTimeline.java @@ -18,8 +18,8 @@ public class GuiMarkerTimeline extends GuiTimeline { private long clickTime; private boolean dragging; - public GuiMarkerTimeline(int positionX, int positionY, int width, boolean showMarkers) { - super(positionX, positionY, width); + public GuiMarkerTimeline(int positionX, int positionY, int width, int height, boolean showMarkers) { + super(positionX, positionY, width, height); this.showMarkers = showMarkers; } diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiTimeline.java b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiTimeline.java index b09698f4..c2169ca5 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiTimeline.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/elements/timelines/GuiTimeline.java @@ -16,10 +16,10 @@ import static org.lwjgl.opengl.GL11.glEnable; public class GuiTimeline extends Gui implements GuiElement { protected static final int TEXTURE_WIDTH = 64; + protected static final int TEXTURE_HEIGHT = 22; protected static final int BORDER_TOP = 4; protected static final int BORDER_BOTTOM = 3; - protected static final int HEIGHT = 22; protected static final int TEXTURE_X = 64; protected static final int TEXTURE_Y = 106; @@ -57,13 +57,15 @@ public class GuiTimeline extends Gui implements GuiElement { protected final int positionX; protected final int positionY; protected final int width; + protected final int height; protected boolean enabled = true; - public GuiTimeline(int positionX, int positionY, int width) { + public GuiTimeline(int positionX, int positionY, int width, int height) { this.positionX = positionX; this.positionY = positionY; this.width = width; + this.height = height; } /** @@ -76,7 +78,7 @@ public class GuiTimeline extends Gui implements GuiElement { int left = positionX + BORDER_LEFT; int right = positionX + width - BORDER_RIGHT; int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT; - if (mouseX >= left && mouseX <= right && mouseY >= positionY && mouseY <= positionY + HEIGHT) { + if (mouseX >= left && mouseX <= right && mouseY >= positionY && mouseY <= positionY + height) { double segmentLength = timelineLength * zoom; double segmentTime = segmentLength * (mouseX - left) / bodyWidth; return Math.round(timeStart * timelineLength + segmentTime); @@ -96,14 +98,48 @@ public class GuiTimeline extends Gui implements GuiElement { int BORDER_LEFT = GuiTimeline.BORDER_LEFT + 1; int BODY_WIDTH = GuiTimeline.BODY_WIDTH - 1; - // Left border - rect(positionX, positionY, TEXTURE_X, TEXTURE_Y, BORDER_LEFT, HEIGHT); - // Body - for (int i = bodyLeft; i < bodyRight; i += BODY_WIDTH) { - rect(i, positionY, TEXTURE_X + BORDER_LEFT, TEXTURE_Y, Math.min(BODY_WIDTH, bodyRight - i), HEIGHT); + /* + // Upper left border + rect(positionX, positionY, TEXTURE_X, TEXTURE_Y, BORDER_LEFT, BORDER_TOP); + + // Lower left border + rect(positionX, positionY+height-BORDER_BOTTOM, TEXTURE_X, TEXTURE_Y+TEXTURE_HEIGHT-BORDER_BOTTOM, BORDER_LEFT, BORDER_BOTTOM); + */ + + boolean leftRightDrawn = false; + + for (int i = positionX; i < bodyRight; i += BODY_WIDTH) { + int textureX = leftRightDrawn ? TEXTURE_X+BORDER_LEFT : TEXTURE_X; + + // Upper border + rect(i, positionY, textureX, TEXTURE_Y, Math.min(BODY_WIDTH, bodyRight - i), BORDER_TOP); + + int remaining = height-BORDER_TOP-BORDER_BOTTOM; + int y = positionY + BORDER_TOP; + while(remaining > 0) { + int toDraw = Math.min(remaining, TEXTURE_HEIGHT - BORDER_TOP - BORDER_BOTTOM); + rect(i, y, textureX, TEXTURE_Y+BORDER_TOP, Math.min(BODY_WIDTH, bodyRight - i), Math.min(TEXTURE_HEIGHT-BORDER_TOP-BORDER_BOTTOM, toDraw)); + + // Right border + if(!leftRightDrawn) { + rect(bodyLeft+bodyWidth, y, TEXTURE_X+TEXTURE_WIDTH-BORDER_RIGHT, TEXTURE_Y+BORDER_TOP, BORDER_RIGHT, Math.min(TEXTURE_HEIGHT-BORDER_TOP-BORDER_BOTTOM, toDraw)); + } + + y += toDraw; + remaining -= toDraw; + } + + // Lower border + rect(i, positionY+height-BORDER_BOTTOM, textureX, TEXTURE_Y+TEXTURE_HEIGHT-BORDER_BOTTOM, Math.min(BODY_WIDTH, bodyRight - i), BORDER_BOTTOM); + + leftRightDrawn = true; } - // Right border - rect(bodyRight, positionY, TEXTURE_X + BORDER_LEFT + BODY_WIDTH, TEXTURE_Y, BORDER_RIGHT, HEIGHT); + + // Upper right corner + rect(bodyLeft+bodyWidth, positionY, TEXTURE_X+TEXTURE_WIDTH-BORDER_RIGHT, TEXTURE_Y, BORDER_RIGHT, BORDER_TOP); + + // Lower right corner + rect(bodyLeft+bodyWidth, positionY+height-BORDER_BOTTOM, TEXTURE_X+TEXTURE_WIDTH-BORDER_RIGHT, TEXTURE_Y+TEXTURE_HEIGHT-BORDER_BOTTOM, BORDER_RIGHT, BORDER_BOTTOM); } long leftTime = Math.round(timeStart * timelineLength); @@ -111,7 +147,7 @@ public class GuiTimeline extends Gui implements GuiElement { // Draw markers if (showMarkers) { - int markerY = positionY + HEIGHT - BORDER_BOTTOM; + int markerY = positionY + height - BORDER_BOTTOM; MarkerType mt = MarkerType.getMarkerType(zoom, timelineLength); // Small markers @@ -152,7 +188,20 @@ public class GuiTimeline extends Gui implements GuiElement { double fractionOfSegment = positionInSegment / (zoom * timelineLength); int cursorX = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth); - rect(cursorX - 2, positionY + BORDER_TOP, 84, 20, 5, 16); + rect(cursorX - 2, positionY + BORDER_TOP-1, 84, 20, 5, 4); + + + int remaining = height-BORDER_TOP-BORDER_BOTTOM-3; + int y = positionY + BORDER_TOP-1 + 4; + while(remaining > 0) { + int toDraw = Math.min(remaining, 11); + + rect(cursorX - 2, y, 84, 24, 5, toDraw); + + y += toDraw; + remaining -= toDraw; + } + } } 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 86f23825..752d5112 100755 --- a/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java @@ -234,9 +234,9 @@ public class GuiReplayOverlay extends Gui { }, "replaymod.gui.ingame.menu.zoomout"); - private final GuiMarkerTimeline timeline = new GuiMarkerTimeline(TIMELINE_X, TOP_ROW - 1, WIDTH - 14 - TIMELINE_X, false); + private final GuiMarkerTimeline timeline = new GuiMarkerTimeline(TIMELINE_X, TOP_ROW - 1, WIDTH - 14 - TIMELINE_X, 22, false); - private final GuiKeyframeTimeline timelineReal = new GuiKeyframeTimeline(TIMELINE_REAL_X, BOTTOM_ROW - 1, TIMELINE_REAL_WIDTH, true, true, true); + private final GuiKeyframeTimeline timelineReal = new GuiKeyframeTimeline(TIMELINE_REAL_X, BOTTOM_ROW - 1, TIMELINE_REAL_WIDTH, 22, true, true, true); { timelineReal.timelineLength = 10 * 60 * 1000; } diff --git a/src/main/java/eu/crushedpixel/replaymod/holders/TimestampValue.java b/src/main/java/eu/crushedpixel/replaymod/holders/TimestampValue.java index 4456393d..f76b051d 100644 --- a/src/main/java/eu/crushedpixel/replaymod/holders/TimestampValue.java +++ b/src/main/java/eu/crushedpixel/replaymod/holders/TimestampValue.java @@ -12,6 +12,10 @@ public class TimestampValue implements KeyframeValue { @Interpolate public double value; + public int asInt() { + return (int)value; + } + @Override public TimestampValue newInstance() { return new TimestampValue(); diff --git a/src/main/resources/assets/replaymod/replay_gui.png b/src/main/resources/assets/replaymod/replay_gui.png index ece10558ea861d38324e7dd6e60e00cd8667c1d2..fc3d539a4d4159a8b222ff159735a9baf72d77b8 100755 GIT binary patch literal 8398 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 OKwVkqWxXOK=KleDt3u)c literal 7260 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 W5QoVh3lshW0<_ij)k;-tKKu{!)Az;z