13bb0bdMerge branch 1.11-staging into 1.11.2-staging5257a41Merge branch 1.10.2 into 1.11689f897Merge branch 1.9.4 into 1.10.20aed9c3Merge branch 1.8.9 into 1.9.4f36ebf1Merge branch 1.8 into 1.8.908170b3Downgrade FG to 2.1 because FG 2.2 is 1.9+ only41d2547Update translations00e999fFix replay not being closed when opened via URI scheme handler (fixes #92)767ea29Fix book gui not being suppressed during replay (fixes #90)5b04edbHide ReplayMod app entry from menus on Linux6aff99dFix livelock during netty write to embedded channel (fixes #85)703805fFix infinite loop in mc.scheduledTasks (fixes #86)7a4440cUpdate ReplayStudio0b9c56cFix resource packs not working after first time jumping back in time933ee5f[Compat] Fix camera entity with BetterSprinting prior to 2.0.0 (fixes #78)83b1090Fix hotbar being visible while spectating player (fixes #83)5c73117[Compat] Fix invisible entities with Orange's 1.7 Animations (fixes #78)4704b29Replace the RenderPlayer hook (used subclassing) with a mixin (fixes #79)0c226b0Fix path at end of replay resulting in constant reloading (fixes #56)1b9b13eRename render success sound to all lowercase (required for 1.11) (fixes #66)c2000b3Fix only front-facing chunks visible for ODS rendering (fixes #67)aafeeccFix initial login gui not closing on success (fixes #68)9292addUse percent-encoding for replay file names (fixes #71)8499c0fFix name of invis armor stand with CustomNameVisible not rendering (fixes #72)b9ea572Try to handle invalid ffmpeg arguments more gracefully (fixes #77)a2f8c88Fix compression packets being recorded (fixes #80)19629c3Replace usages of System.out with loggerfe1d9b8Stop Forge from allowing the mod to load on other MC versions (fixes #82)d56fa9bUpdate ReplayStudio/MCProtocolLib (Fixes missing ARMOR_STAND MobType)7c719e0Update ReplayStudio/MCProtocolLib (Fixes missing ARMOR_STAND MobType)1a1e96cFix server with RM installed refusing clients without RM (fixes #76)35eb9caReplace usage of FMLLog with the mod logger
481 lines
22 KiB
Java
481 lines
22 KiB
Java
package com.replaymod.online.gui;
|
|
|
|
import com.google.common.base.Optional;
|
|
import com.google.common.base.Supplier;
|
|
import com.google.common.primitives.Ints;
|
|
import com.google.common.util.concurrent.FutureCallback;
|
|
import com.google.common.util.concurrent.Futures;
|
|
import com.mojang.realmsclient.gui.ChatFormatting;
|
|
import com.replaymod.core.utils.Utils;
|
|
import com.replaymod.online.ReplayModOnline;
|
|
import com.replaymod.online.api.ApiClient;
|
|
import com.replaymod.online.api.ApiException;
|
|
import com.replaymod.online.api.replay.SearchQuery;
|
|
import com.replaymod.online.api.replay.holders.Category;
|
|
import com.replaymod.online.api.replay.holders.FileInfo;
|
|
import com.replaymod.online.api.replay.holders.FileRating;
|
|
import com.replaymod.online.api.replay.holders.Rating;
|
|
import com.replaymod.online.api.replay.pagination.DownloadedFilePagination;
|
|
import com.replaymod.online.api.replay.pagination.FavoritedFilePagination;
|
|
import com.replaymod.online.api.replay.pagination.Pagination;
|
|
import com.replaymod.online.api.replay.pagination.SearchPagination;
|
|
import com.replaymod.replaystudio.replay.ReplayMetaData;
|
|
import com.replaymod.replaystudio.studio.ReplayStudio;
|
|
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
|
|
import de.johni0702.minecraft.gui.container.GuiContainer;
|
|
import de.johni0702.minecraft.gui.container.GuiPanel;
|
|
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
import de.johni0702.minecraft.gui.element.GuiButton;
|
|
import de.johni0702.minecraft.gui.element.GuiImage;
|
|
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
import de.johni0702.minecraft.gui.element.GuiTooltip;
|
|
import de.johni0702.minecraft.gui.element.IGuiButton;
|
|
import de.johni0702.minecraft.gui.element.advanced.GuiResourceLoadingList;
|
|
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
|
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
|
import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
|
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
|
|
import de.johni0702.minecraft.gui.utils.Colors;
|
|
import de.johni0702.minecraft.gui.utils.Consumer;
|
|
import org.apache.logging.log4j.util.Strings;
|
|
import org.lwjgl.util.Dimension;
|
|
import org.lwjgl.util.ReadableDimension;
|
|
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.IOException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.HashSet;
|
|
import java.util.Set;
|
|
|
|
import static com.replaymod.online.ReplayModOnline.LOGGER;
|
|
|
|
public class GuiReplayCenter extends GuiScreen {
|
|
private final ReplayModOnline mod;
|
|
private final ApiClient apiClient;
|
|
|
|
private GuiButton makeCategory(String name) {
|
|
return new GuiButton().setI18nLabel("replaymod.gui.center.top." + name).setSize(75, 20);
|
|
}
|
|
|
|
public final GuiButton categoryRecent = makeCategory("recent").onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
show(new SearchPagination(apiClient,
|
|
new SearchQuery(false, null, null, null, null, null, null, null, null, null)));
|
|
categoryRecent.setDisabled();
|
|
}
|
|
});
|
|
|
|
public final GuiButton categoryBest = makeCategory("best").onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
show(new SearchPagination(apiClient,
|
|
new SearchQuery(true, null, null, null, null, null, null, null, null, null)));
|
|
categoryBest.setDisabled();
|
|
}
|
|
});
|
|
|
|
public final GuiButton categoryDownloaded = makeCategory("downloaded").onClick(new Runnable()
|
|
|
|
{
|
|
@Override
|
|
public void run() {
|
|
show(new DownloadedFilePagination(mod));
|
|
categoryDownloaded.setDisabled();
|
|
}
|
|
});
|
|
|
|
public final GuiButton categoryFavorited = makeCategory("favorited").onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
show(new FavoritedFilePagination(apiClient));
|
|
categoryFavorited.setDisabled();
|
|
}
|
|
});
|
|
|
|
public final GuiButton categorySearch = makeCategory("search").onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
searchPopup.open();
|
|
}
|
|
});
|
|
|
|
public final GuiPanel categories = new GuiPanel(this).setLayout(new HorizontalLayout().setSpacing(5))
|
|
.addElements(null, categoryRecent, categoryBest, categoryDownloaded, categoryFavorited, categorySearch);
|
|
|
|
public final GuiResourceLoadingList<GuiReplayEntry> list = new GuiResourceLoadingList<GuiReplayEntry>(this).onSelectionChanged(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
GuiReplayEntry selected = list.getSelected();
|
|
replayButtonPanel.forEach(IGuiButton.class).setEnabled(selected != null);
|
|
replayButtonPanel.forEach(IGuiButton.class).setTooltip(null);
|
|
if (selected != null) {
|
|
int replayId = selected.fileInfo.getId();
|
|
boolean favorited = favoritedReplays.contains(replayId);
|
|
boolean liked = likedReplays.contains(replayId);
|
|
boolean disliked = dislikedReplays.contains(replayId);
|
|
|
|
loadButton.setI18nLabel(selected.downloaded ? "replaymod.gui.load" : "replaymod.gui.download");
|
|
if (selected.incompatible) {
|
|
loadButton.setDisabled();
|
|
}
|
|
|
|
favoriteButton.setI18nLabel("replaymod.gui.center." + (favorited ? "unfavorite" : "favorite"));
|
|
// Only allow button usage for either unfavorite or favorite after they've actually downloaded it
|
|
favoriteButton.setEnabled(favorited || selected.downloaded);
|
|
if (favoriteButton.isEnabled()) {
|
|
favoriteButton.setTooltip(null);
|
|
} else {
|
|
favoriteButton.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.center.downloadrequired"));
|
|
}
|
|
|
|
// Similar for like/dislike buttons
|
|
likeButton.setEnabled(selected.downloaded);
|
|
dislikeButton.setEnabled(selected.downloaded);
|
|
if (likeButton.isEnabled()) {
|
|
likeButton.setTooltip(null);
|
|
dislikeButton.setTooltip(null);
|
|
} else {
|
|
likeButton.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.center.downloadrequired"));
|
|
dislikeButton.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.center.downloadrequired"));
|
|
}
|
|
likeButton.setI18nLabel("replaymod.gui." + (liked ? "removelike" : "like"));
|
|
dislikeButton.setI18nLabel("replaymod.gui." + (disliked ? "removedislike" : "dislike"));
|
|
}
|
|
}
|
|
}).onLoad(new Consumer<Consumer<Supplier<GuiReplayEntry>>>() {
|
|
@Override
|
|
public void consume(Consumer<Supplier<GuiReplayEntry>> obj) {
|
|
// Do not load any replays until the user has selected the category they'd like to view
|
|
}
|
|
}).setDrawShadow(true).setDrawSlider(true);
|
|
|
|
public final GuiButton loadButton = new GuiButton().onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
FileInfo fileInfo = list.getSelected().fileInfo;
|
|
mod.startReplay(fileInfo.getId(), fileInfo.getName(), GuiReplayCenter.this);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}).setSize(95, 20).setI18nLabel("replaymod.gui.download").setDisabled();
|
|
|
|
public final GuiButton favoriteButton = new GuiButton().onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
int replayId = list.getSelected().fileInfo.getId();
|
|
boolean favorited = favoritedReplays.contains(replayId);
|
|
apiClient.favFile(replayId, !favorited);
|
|
reloadFavorited();
|
|
list.onSelectionChanged();
|
|
} catch (IOException | ApiException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}).setSize(95, 20).setI18nLabel("replaymod.gui.center.favorite").setDisabled();
|
|
|
|
public final GuiButton likeButton = new GuiButton().onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
int replayId = list.getSelected().fileInfo.getId();
|
|
boolean liked = likedReplays.contains(replayId);
|
|
apiClient.rateFile(replayId, liked ? Rating.RatingType.NEUTRAL : Rating.RatingType.LIKE);
|
|
reloadRated();
|
|
list.onSelectionChanged();
|
|
} catch (IOException | ApiException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}).setSize(95, 20).setI18nLabel("replaymod.gui.like").setDisabled();
|
|
|
|
public final GuiButton dislikeButton = new GuiButton().onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
int replayId = list.getSelected().fileInfo.getId();
|
|
boolean disliked = dislikedReplays.contains(replayId);
|
|
apiClient.rateFile(replayId, disliked ? Rating.RatingType.NEUTRAL : Rating.RatingType.DISLIKE);
|
|
reloadRated();
|
|
list.onSelectionChanged();
|
|
} catch (IOException | ApiException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}).setSize(95, 20).setI18nLabel("replaymod.gui.dislike").setDisabled();
|
|
|
|
public final GuiButton logoutButton = new GuiButton().onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
Futures.addCallback(GuiYesNoPopup.open(GuiReplayCenter.this,
|
|
new GuiLabel().setI18nText("replaymod.gui.center.logoutcallback").setColor(Colors.BLACK))
|
|
.setYesI18nLabel("replaymod.gui.logout").setNoI18nLabel("replaymod.gui.cancel")
|
|
.getFuture(), new FutureCallback<Boolean>() {
|
|
@Override
|
|
public void onSuccess(Boolean result) {
|
|
if (result) {
|
|
apiClient.logout();
|
|
getMinecraft().displayGuiScreen(null);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onFailure(Throwable t) {
|
|
t.printStackTrace();
|
|
}
|
|
});
|
|
}
|
|
}).setSize(195, 20).setI18nLabel("replaymod.gui.logout");
|
|
|
|
public final GuiButton mainMenuButton = new GuiButton().onClick(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
getMinecraft().displayGuiScreen(null);
|
|
}
|
|
}).setSize(195, 20).setI18nLabel("replaymod.gui.mainmenu");
|
|
|
|
public final GuiReplayCenterSearch searchPopup;
|
|
|
|
public final GuiPanel replayButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
|
.addElements(null, loadButton, favoriteButton, likeButton, dislikeButton);
|
|
public final GuiPanel generalButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
|
.addElements(null, logoutButton, mainMenuButton);
|
|
public final GuiPanel buttonPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(5))
|
|
.addElements(null, replayButtonPanel, generalButtonPanel);
|
|
|
|
private volatile Set<Integer> favoritedReplays = Collections.emptySet();
|
|
private volatile Set<Integer> likedReplays = Collections.emptySet();
|
|
private volatile Set<Integer> dislikedReplays = Collections.emptySet();
|
|
|
|
public GuiReplayCenter(ReplayModOnline mod) {
|
|
this.mod = mod;
|
|
this.apiClient = mod.getApiClient();
|
|
this.searchPopup = new GuiReplayCenterSearch(this, apiClient);
|
|
|
|
setTitle(new GuiLabel().setI18nText("replaymod.gui.replaycenter"));
|
|
|
|
setLayout(new CustomLayout<GuiScreen>() {
|
|
@Override
|
|
protected void layout(GuiScreen container, int width, int height) {
|
|
pos(buttonPanel, width / 2 - width(buttonPanel) / 2, height - 10 - height(buttonPanel));
|
|
|
|
pos(list, 0, 50);
|
|
size(list, width, y(buttonPanel) - 10 - y(list));
|
|
|
|
pos(categories, width / 2 - width(categories) / 2, y(list) - 7 - height(categories));
|
|
}
|
|
});
|
|
}
|
|
|
|
private void reloadFavorited() {
|
|
try {
|
|
favoritedReplays = new HashSet<>(Ints.asList(apiClient.getFavorites()));
|
|
} catch (IOException | ApiException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private void reloadRated() {
|
|
try {
|
|
Set<Integer> liked = new HashSet<>(), disliked = new HashSet<>();
|
|
for (FileRating rating : apiClient.getRatedFiles()) {
|
|
(rating.isRatingPositive() ? liked : disliked).add(rating.getFile());
|
|
}
|
|
this.likedReplays = liked;
|
|
this.dislikedReplays = disliked;
|
|
} catch (IOException | ApiException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public void show(final Pagination pagination) {
|
|
list.setOffsetY(0);
|
|
list.onLoad(new Consumer<Consumer<Supplier<GuiReplayEntry>>>() {
|
|
@Override
|
|
public void consume(Consumer<Supplier<GuiReplayEntry>> obj) {
|
|
if (pagination.getLoadedPages() < 0) {
|
|
pagination.fetchPage();
|
|
}
|
|
|
|
reloadFavorited();
|
|
reloadRated();
|
|
|
|
int i = 0;
|
|
for (final FileInfo fileInfo : pagination.getFiles()) {
|
|
if (Thread.interrupted()) return;
|
|
try {
|
|
// Make sure that to int[] conversion doesn't have to occur in main thread
|
|
final BufferedImage theThumb;
|
|
if (fileInfo.hasThumbnail()) {
|
|
BufferedImage buf = apiClient.downloadThumbnail(fileInfo.getId());
|
|
// This is the same way minecraft calls this method, we cache the result and hand
|
|
// minecraft a BufferedImage with way simpler logic using the precomputed values
|
|
final int[] theIntArray = buf.getRGB(0, 0, buf.getWidth(), buf.getHeight(), null, 0, buf.getWidth());
|
|
theThumb = new BufferedImage(buf.getWidth(), buf.getHeight(), BufferedImage.TYPE_INT_ARGB) {
|
|
@Override
|
|
public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) {
|
|
System.arraycopy(theIntArray, 0, rgbArray, 0, theIntArray.length);
|
|
return null; // Minecraft doesn't use the return value
|
|
}
|
|
};
|
|
} else {
|
|
theThumb = null;
|
|
}
|
|
|
|
final int sortId = i++;
|
|
final boolean downloaded = mod.hasDownloaded(fileInfo.getId());
|
|
obj.consume(new Supplier<GuiReplayEntry>() {
|
|
@Override
|
|
public GuiReplayEntry get() {
|
|
return new GuiReplayEntry(fileInfo, theThumb, sortId, downloaded);
|
|
}
|
|
});
|
|
} catch (Exception e) {
|
|
LOGGER.error("Could not load Replay File {}", fileInfo.getId(), e);
|
|
}
|
|
}
|
|
}
|
|
}).load();
|
|
|
|
categories.forEach(IGuiButton.class).setEnabled();
|
|
}
|
|
|
|
@Override
|
|
protected GuiReplayCenter getThis() {
|
|
return this;
|
|
}
|
|
|
|
private final GuiImage defaultThumbnail = new GuiImage().setTexture(Utils.DEFAULT_THUMBNAIL);
|
|
public class GuiReplayEntry extends AbstractGuiContainer<GuiReplayEntry> implements Comparable<GuiReplayEntry> {
|
|
public final FileInfo fileInfo;
|
|
public final GuiLabel name = new GuiLabel();
|
|
public final GuiLabel author = new GuiLabel();
|
|
public final GuiLabel date = new GuiLabel().setColor(Colors.LIGHT_GRAY);
|
|
public final GuiLabel server = new GuiLabel().setColor(Colors.LIGHT_GRAY);
|
|
public final GuiLabel version = new GuiLabel().setColor(Colors.RED);
|
|
public final GuiLabel category = new GuiLabel().setColor(Colors.GREY);
|
|
public final GuiPanel stats = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(3));
|
|
public final GuiLabel favorites = new GuiLabel(stats).setColor(Colors.ORANGE);
|
|
public final GuiLabel likes = new GuiLabel(stats).setColor(Colors.GREEN);
|
|
public final GuiLabel dislikes = new GuiLabel(stats).setColor(Colors.RED);
|
|
public final GuiPanel infoPanel = new GuiPanel(this).setLayout(new CustomLayout<GuiPanel>() {
|
|
@Override
|
|
protected void layout(GuiPanel container, int width, int height) {
|
|
pos(name, 0, 0);
|
|
pos(author, 0, height(name) + 2);
|
|
pos(server, 0, y(author) + height(author) + 3);
|
|
pos(category, 0, y(server) + height(server) + 3);
|
|
|
|
pos(date, width - width(date), y(author));
|
|
pos(version, width - width(version), y(server));
|
|
pos(stats, width - width(stats), y(category));
|
|
}
|
|
}).addElements(null, name, author, date, server, version, category, stats);
|
|
public final GuiImage thumbnail;
|
|
public final GuiLabel duration = new GuiLabel();
|
|
public final GuiPanel durationPanel = new GuiPanel().setBackgroundColor(Colors.HALF_TRANSPARENT)
|
|
.addElements(null, duration).setLayout(new CustomLayout<GuiPanel>() {
|
|
@Override
|
|
protected void layout(GuiPanel container, int width, int height) {
|
|
pos(duration, 2, 2);
|
|
}
|
|
|
|
@Override
|
|
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
|
ReadableDimension dimension = duration.calcMinSize();
|
|
return new Dimension(dimension.getWidth() + 2, dimension.getHeight() + 2);
|
|
}
|
|
});
|
|
public final GuiLabel downloads = new GuiLabel();
|
|
public final GuiPanel downloadsPanel = new GuiPanel().setBackgroundColor(Colors.HALF_TRANSPARENT)
|
|
.addElements(null, downloads).setLayout(new CustomLayout<GuiPanel>() {
|
|
@Override
|
|
protected void layout(GuiPanel container, int width, int height) {
|
|
pos(downloads, 2, 2);
|
|
}
|
|
|
|
@Override
|
|
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
|
ReadableDimension dimension = downloads.calcMinSize();
|
|
return new Dimension(dimension.getWidth() + 2, dimension.getHeight() + 2);
|
|
}
|
|
});
|
|
|
|
private final long dateMillis;
|
|
private final int sortId;
|
|
private final boolean downloaded;
|
|
private final boolean incompatible;
|
|
|
|
public GuiReplayEntry(FileInfo fileInfo, BufferedImage thumbImage, int sortId, boolean downloaded) {
|
|
this.fileInfo = fileInfo;
|
|
this.sortId = sortId;
|
|
this.downloaded = downloaded;
|
|
ReplayMetaData metaData = fileInfo.getMetadata();
|
|
|
|
name.setText(ChatFormatting.UNDERLINE + Utils.fileNameToReplayName(fileInfo.getName()));
|
|
author.setI18nText("replaymod.gui.center.author",
|
|
"" + ChatFormatting.GRAY + ChatFormatting.ITALIC, fileInfo.getOwner());
|
|
if (Strings.isEmpty(metaData.getServerName())) {
|
|
server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED);
|
|
} else {
|
|
server.setText(metaData.getServerName());
|
|
}
|
|
incompatible = !new ReplayStudio().isCompatible(fileInfo.getMetadata().getFileFormatVersion());
|
|
if (incompatible) {
|
|
version.setText("Minecraft " + fileInfo.getMetadata().getMcVersion());
|
|
}
|
|
dateMillis = metaData.getDate();
|
|
date.setText(new SimpleDateFormat().format(new Date(dateMillis)));
|
|
if (thumbImage == null) {
|
|
thumbnail = new GuiImage(defaultThumbnail);
|
|
addElements(null, thumbnail);
|
|
} else {
|
|
thumbnail = new GuiImage(this).setTexture(thumbImage);
|
|
}
|
|
thumbnail.setSize(45 * 16 / 9, 45);
|
|
duration.setText(Utils.convertSecondsToShortString(metaData.getDuration() / 1000));
|
|
downloads.setText(fileInfo.getDownloads() + " ⬇");
|
|
favorites.setText("⭑" + fileInfo.getFavorites());
|
|
likes.setText("⬆" + fileInfo.getRatings().getPositive());
|
|
dislikes.setText("⬇" + fileInfo.getRatings().getNegative());
|
|
category.setText(ChatFormatting.ITALIC + Optional.fromNullable(Category.fromId(fileInfo.getCategory()))
|
|
.or(Category.MISCELLANEOUS).toNiceString());
|
|
addElements(null, durationPanel, downloadsPanel);
|
|
|
|
setLayout(new CustomLayout<GuiReplayEntry>() {
|
|
@Override
|
|
protected void layout(GuiReplayEntry container, int width, int height) {
|
|
pos(thumbnail, 0, 0);
|
|
x(durationPanel, width(thumbnail) - width(durationPanel));
|
|
y(durationPanel, height(thumbnail) - height(durationPanel));
|
|
x(downloadsPanel, width(thumbnail) - width(downloadsPanel));
|
|
y(downloadsPanel, height(thumbnail) - height(durationPanel) - height(downloadsPanel));
|
|
|
|
pos(infoPanel, width(thumbnail) + 5, 0);
|
|
size(infoPanel, width - width(thumbnail) - 5, height(thumbnail));
|
|
}
|
|
|
|
@Override
|
|
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
|
return new org.lwjgl.util.Dimension(300, thumbnail.getMinSize().getHeight());
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
protected GuiReplayEntry getThis() {
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(GuiReplayEntry o) {
|
|
return Integer.compare(sortId, o.sortId);
|
|
}
|
|
}
|
|
}
|