Pagination changes and cleanup.

Refactored PaginationBox to be abstract. Implementations can generate individual components as needed now.
Add lots of Component usage to schematic list, help listings, etc.
Fix a few schematic and file resolution issues.
This commit is contained in:
wizjany
2019-04-28 01:12:05 -04:00
parent 62353a46db
commit b3053f19ce
17 changed files with 307 additions and 202 deletions

View File

@ -19,47 +19,75 @@
package com.sk89q.worldedit.util.formatting.component;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
public class CommandListBox extends MessageBox {
import java.util.List;
private boolean first = true;
public class CommandListBox extends PaginationBox {
private List<CommandEntry> commands = Lists.newArrayList();
/**
* Create a new box.
*
* @param title the title
*/
public CommandListBox(String title) {
super(title, new TextComponentProducer());
public CommandListBox(String title, String pageCommand) {
super(title, pageCommand);
}
public CommandListBox appendCommand(String alias, Component description) {
return appendCommand(alias, description, null);
@Override
public Component getComponent(int number) {
return commands.get(number).createComponent();
}
public CommandListBox appendCommand(String alias, String description, String insertion) {
return appendCommand(alias, TextComponent.of(description), insertion);
@Override
public int getComponentsSize() {
return commands.size();
}
public CommandListBox appendCommand(String alias, Component description, String insertion) {
if (!first) {
getContents().newline();
public void appendCommand(String alias, Component description) {
appendCommand(alias, description, null);
}
public void appendCommand(String alias, String description, String insertion) {
appendCommand(alias, TextComponent.of(description), insertion);
}
public void appendCommand(String alias, Component description, String insertion) {
commands.add(new CommandEntry(alias, description, insertion));
}
private static class CommandEntry {
private final String alias;
private final Component description;
private final String insertion;
CommandEntry(String alias, Component description, String insertion) {
this.alias = alias;
this.description = description;
this.insertion = insertion;
}
TextComponent commandName = TextComponent.of(alias, TextColor.GOLD);
if (insertion != null) {
commandName = commandName
.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, insertion))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select")));
}
getContents().append(commandName.append(TextComponent.of(": ")));
getContents().append(description);
first = false;
return this;
}
Component createComponent() {
TextComponentProducer line = new TextComponentProducer();
line.append(SubtleFormat.wrap("? ")
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "//help " + insertion))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help"))));
TextComponent command = TextComponent.of(alias, TextColor.GOLD);
if (insertion == null) {
line.append(command);
} else {
line.append(command
.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, insertion))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select"))));
}
return line.append(TextComponent.of(": ")).append(description).create();
}
}
}

View File

@ -44,7 +44,7 @@ public class CommandUsageBox extends TextComponentProducer {
* @param commands the commands to describe
* @param commandString the commands that were used, such as "/we" or "/brush sphere"
*/
public CommandUsageBox(List<Command> commands, String commandString) {
public CommandUsageBox(List<Command> commands, String commandString) throws InvalidComponentException {
this(commands, commandString, null);
}
@ -55,7 +55,7 @@ public class CommandUsageBox extends TextComponentProducer {
* @param commandString the commands that were used, such as "/we" or "/brush sphere"
* @param parameters list of parameters to use
*/
public CommandUsageBox(List<Command> commands, String commandString, @Nullable CommandParameters parameters) {
public CommandUsageBox(List<Command> commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException {
checkNotNull(commands);
checkNotNull(commandString);
Map<String, Command> subCommands = getSubCommands(Iterables.getLast(commands));
@ -66,8 +66,9 @@ public class CommandUsageBox extends TextComponentProducer {
}
}
private void attachSubcommandUsage(Map<String, Command> dispatcher, String commandString, @Nullable CommandParameters parameters) {
CommandListBox box = new CommandListBox("Subcommands");
private void attachSubcommandUsage(Map<String, Command> dispatcher, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException {
CommandListBox box = new CommandListBox(commandString.isEmpty() ? "Help" : "Subcommands:" + commandString,
"//help %page%" + (commandString.isEmpty() ? "" : " " + commandString));
String prefix = !commandString.isEmpty() ? commandString + " " : "";
List<Command> list = dispatcher.values().stream()
@ -80,7 +81,7 @@ public class CommandUsageBox extends TextComponentProducer {
}
}
append(box.create());
append(box.create(1));
}
private void attachCommandUsage(List<Command> commands, String commandString) {

View File

@ -21,9 +21,12 @@ package com.sk89q.worldedit.util.formatting.component;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
/**
* Makes for a box with a border above and below.
@ -40,28 +43,38 @@ public class MessageBox extends TextComponentProducer {
public MessageBox(String title, TextComponentProducer contents) {
checkNotNull(title);
int leftOver = GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - title.length() - 2;
int leftSide = (int) Math.floor(leftOver * 1.0/3);
int rightSide = (int) Math.floor(leftOver * 2.0/3);
if (leftSide > 0) {
append(TextComponent.of(createBorder(leftSide), TextColor.YELLOW));
}
append(Component.space());
append(title);
append(Component.space());
if (rightSide > 0) {
append(TextComponent.of(createBorder(rightSide), TextColor.YELLOW));
}
newline();
append(centerAndBorder(TextComponent.of(title))).newline();
this.contents = contents;
}
private String createBorder(int count) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < count; i++) {
builder.append("-");
protected Component centerAndBorder(TextComponent text) {
TextComponentProducer line = new TextComponentProducer();
int leftOver = GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - getLength(text);
int side = (int) Math.floor(leftOver / 2.0);
if (side > 0) {
if (side > 1) {
line.append(createBorder(side - 1));
}
line.append(Component.space());
}
return builder.toString();
line.append(text);
if (side > 0) {
line.append(Component.space());
if (side > 1) {
line.append(createBorder(side - 1));
}
}
return line.create();
}
private static int getLength(TextComponent text) {
return text.content().length() + text.children().stream().filter(c -> c instanceof TextComponent)
.mapToInt(c -> getLength((TextComponent) c)).sum();
}
private TextComponent createBorder(int count) {
return TextComponent.of(Strings.repeat("-", count),
TextColor.YELLOW, Sets.newHashSet(TextDecoration.STRIKETHROUGH));
}
/**

View File

@ -25,14 +25,14 @@ import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import javax.annotation.Nullable;
import java.util.List;
public class PaginationBox extends MessageBox {
public abstract class PaginationBox extends MessageBox {
public static final int IDEAL_ROWS_FOR_PLAYER = 8;
private static final int IDEAL_ROWS_FOR_PLAYER = 8;
private String pageCommand;
private List<TextComponent> components;
private int componentsPerPage = IDEAL_ROWS_FOR_PLAYER;
/**
@ -40,30 +40,30 @@ public class PaginationBox extends MessageBox {
*
* @param title The title
*/
public PaginationBox(String title) {
protected PaginationBox(String title) {
this(title, null);
}
/**
* Sets the components to create pages for.
*
* @param components The components
*/
public void setComponents(List<TextComponent> components) {
this.components = components;
}
public abstract Component getComponent(int number);
public abstract int getComponentsSize();
public void setComponentsPerPage(int componentsPerPage) {
this.componentsPerPage = componentsPerPage;
}
public void formatForConsole() {
this.pageCommand = null;
this.componentsPerPage = 20;
}
/**
* Creates a Paginated component
*
* @param title The title
* @param pageCommand The command to run to switch page, with %page% representing page number
*/
public PaginationBox(String title, String pageCommand) {
protected PaginationBox(String title, @Nullable String pageCommand) {
super(title, new TextComponentProducer());
if (pageCommand != null && !pageCommand.contains("%page%")) {
@ -72,48 +72,76 @@ public class PaginationBox extends MessageBox {
this.pageCommand = pageCommand;
}
public TextComponent create(int page) throws InvalidComponentException {
if (components == null) {
throw new IllegalStateException("You must provide components before creating.");
}
if (page == 1 && components.isEmpty()) {
public Component create(int page) throws InvalidComponentException {
if (page == 1 && getComponentsSize() == 0) {
return getContents().reset().append("There's nothing to see here").create();
}
int pageCount = (int) Math.ceil(components.size() / (double) componentsPerPage);
int pageCount = (int) Math.ceil(getComponentsSize() / (double) componentsPerPage);
if (page < 1 || page > pageCount) {
throw new InvalidComponentException("Invalid page number.");
}
getContents().reset();
for (int i = (page - 1) * componentsPerPage; i < Math.min(page * componentsPerPage, components.size()); i++) {
getContents().append(components.get(i)).newline();
final int lastComp = Math.min(page * componentsPerPage, getComponentsSize());
for (int i = (page - 1) * componentsPerPage; i < lastComp; i++) {
getContents().append(getComponent(i));
if (i + 1 != lastComp) {
getContents().newline();
}
}
if (pageCount == 1) {
return super.create();
}
getContents().newline();
TextComponent pageNumberComponent = TextComponent.of("Page ", TextColor.YELLOW)
.append(TextComponent.of(String.valueOf(page), TextColor.GOLD))
.append(TextComponent.of(" of "))
.append(TextComponent.of(String.valueOf(pageCount), TextColor.GOLD));
if (pageCommand != null) {
TextComponentProducer navProducer = new TextComponentProducer();
if (page > 1) {
TextComponent prevComponent = TextComponent.of("<<< ", TextColor.GOLD)
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page - 1))))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate")));
getContents().append(prevComponent);
navProducer.append(prevComponent);
}
getContents().append(pageNumberComponent);
navProducer.append(pageNumberComponent);
if (page < pageCount) {
TextComponent nextComponent = TextComponent.of(" >>>", TextColor.GOLD)
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page + 1))))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate")));
getContents().append(nextComponent);
navProducer.append(nextComponent);
}
getContents().append(centerAndBorder(navProducer.create()));
} else {
getContents().append(pageNumberComponent);
getContents().append(centerAndBorder(pageNumberComponent));
}
return TextComponent.of("").append(Component.newline()).append(super.create());
return super.create();
}
@Override
public TextComponent create() {
throw new IllegalStateException("Pagination components must be created with a page");
}
public static PaginationBox fromStrings(String header, @Nullable String pageCommand, List<String> lines) {
return new ListPaginationBox(header, pageCommand, lines);
}
private static class ListPaginationBox extends PaginationBox {
private final List<String> lines;
ListPaginationBox(String header, String pageCommand, List<String> lines) {
super(header, pageCommand);
this.lines = lines;
}
@Override
public Component getComponent(int number) {
return TextComponent.of(lines.get(number));
}
@Override
public int getComponentsSize() {
return lines.size();
}
}
}

View File

@ -0,0 +1,56 @@
package com.sk89q.worldedit.util.formatting.component;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import java.io.File;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
public class SchematicPaginationBox extends PaginationBox {
private final String prefix;
private final File[] files;
public SchematicPaginationBox(String rootDir, File[] files, String pageCommand) {
super("Available schematics", pageCommand);
this.prefix = rootDir == null ? "" : rootDir;
this.files = files;
}
@Override
public Component getComponent(int number) {
checkArgument(number < files.length - 1 && number >= 0);
File file = files[number];
Multimap<String, ClipboardFormat> exts = ClipboardFormats.getFileExtensionMap();
String format = exts.get(Files.getFileExtension(file.getName()))
.stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown");
boolean inRoot = file.getParentFile().getName().equals(prefix);
String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1];
return TextComponent.builder()
.content("")
.append(TextComponent.of("[L]")
.color(TextColor.GOLD)
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem load " + path))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load"))))
.append(Component.space())
.append(TextComponent.of(path)
.color(TextColor.DARK_GREEN)
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format))))
.build();
}
@Override
public int getComponentsSize() {
return files.length;
}
}