PandaLib/pandalib-chat/src/main/java/fr/pandacube/lib/chat/ChatFilledLine.java

209 lines
6.2 KiB
Java

package fr.pandacube.lib.chat;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.format.TextColor;
import org.jetbrains.annotations.NotNull;
import fr.pandacube.lib.chat.Chat.FormatableChat;
/**
* Builder for a {@link Chat} component for filling a chat line, with decoration and eventual aligned text.
*/
public class ChatFilledLine implements ComponentLike {
/**
* Builder for a filled line with the provided left-aligned text.
* @param text the text to align ont the left.
* @return a new {@link ChatFilledLine} builder.
*/
public static ChatFilledLine leftText(ComponentLike text) {
return new ChatFilledLine(text, Alignment.LEFT);
}
/**
* Builder for a filled line with the provided right-aligned text.
* @param text the text to align ont the right.
* @return a new {@link ChatFilledLine} builder.
*/
public static ChatFilledLine rightText(ComponentLike text) {
return new ChatFilledLine(text, Alignment.RIGHT);
}
/**
* Builder for a filled line with the provided centered text.
* @param text the text to center.
* @return a new {@link ChatFilledLine} builder.
*/
public static ChatFilledLine centerText(ComponentLike text) {
return new ChatFilledLine(text, Alignment.CENTER);
}
/**
* Builder for a filled line with no text.
* @return a new {@link ChatFilledLine} builder.
*/
public static ChatFilledLine filled() {
return new ChatFilledLine(null, Alignment.NONE);
}
private final ComponentLike text;
private final Alignment alignment;
private char decorationChar = ChatConfig.decorationChar;
private TextColor decorationColor = ChatConfig.decorationColor;
private boolean decorationBold = false;
private int nbSide = ChatConfig.nbCharMargin;
private boolean spacesAroundText = false;
private boolean console = false;
private Integer maxWidth = null;
private ChatFilledLine(ComponentLike text, Alignment alignment) {
this.text = text;
this.alignment = alignment;
}
/**
* Sets the decoration char.
* @param decoChar the character that will fill the line.
* @return this.
*/
public ChatFilledLine decoChar(char decoChar) {
decorationChar = decoChar;
return this;
}
/**
* Sets the decoration color.
* @param decoColor the color of the characters filling the line.
* @return this.
*/
public ChatFilledLine decoColor(TextColor decoColor) {
decorationColor = decoColor;
return this;
}
/**
* Sets the decoration in bold.
* @return this.
*/
public ChatFilledLine decoBold() {
decorationBold = true;
return this;
}
/**
* Sets the number of side character when the text is aligned left or right.
* @param nbSide the number of character that will separate the border from the side of the text.
* @return this.
*/
public ChatFilledLine nbSide(int nbSide) {
this.nbSide = nbSide;
return this;
}
/**
* Adds spaces around the text.
* @return this.
*/
public ChatFilledLine spacesAroundText() {
spacesAroundText = true;
return this;
}
/**
* Configure if the line will be rendered on console or not.
* @param console true for console, false for game UI.
* @return this.
*/
public ChatFilledLine console(boolean console) {
this.console = console;
return this;
}
/**
* Configure the width of the line.
* @param maxWidth the width to consider when rendering the line. In pixel for game UI rendering, n character for
* console rendering.
* @return this.
*/
public ChatFilledLine maxWidth(int maxWidth) {
this.maxWidth = maxWidth;
return this;
}
/**
* Renders this line to a {@link FormatableChat}.
* @return a new {@link FormatableChat} built by this {@link ChatFilledLine}.
*/
public FormatableChat toChat() {
int maxWidth = (this.maxWidth != null)
? this.maxWidth
: console ? ChatUtil.CONSOLE_NB_CHAR_DEFAULT : ChatUtil.DEFAULT_CHAT_WIDTH;
if (alignment == Alignment.NONE) {
int count = maxWidth / ChatUtil.charW(decorationChar, console, decorationBold);
return Chat.text(ChatUtil.repeatedChar(decorationChar, count)).color(decorationColor).bold(decorationBold);
}
ComponentLike text = spacesAroundText
? Chat.text(" ").then(this.text).thenText(" ")
: this.text;
int textWidth = ChatUtil.componentWidth(text.asComponent(), console);
if (textWidth > maxWidth)
return (FormatableChat) text;
int repeatedCharWidth = ChatUtil.charW(decorationChar, console, decorationBold);
int nbCharLeft = 0, nbCharRight = 0;
switch (alignment) {
case CENTER -> {
nbCharLeft = nbCharRight = (maxWidth - textWidth) / 2 / repeatedCharWidth;
if (nbCharLeft == 0)
return (FormatableChat) text;
}
case LEFT, RIGHT -> {
int remWidth = textWidth + nbSide * repeatedCharWidth;
if (remWidth > maxWidth)
return (FormatableChat) text;
boolean left = alignment == Alignment.LEFT;
int nbOtherSide = (maxWidth - remWidth) / repeatedCharWidth;
nbCharLeft = left ? nbSide : nbOtherSide;
nbCharRight = left ? nbOtherSide : nbSide;
}
}
Chat d = Chat.chat()
.then(Chat.text(ChatUtil.repeatedChar(decorationChar, nbCharLeft)).color(decorationColor).bold(decorationBold))
.then(text);
if (decorationChar != ' ')
d.then(Chat.text(ChatUtil.repeatedChar(decorationChar, nbCharRight)).color(decorationColor).bold(decorationBold));
return (FormatableChat) d;
}
@Override
public @NotNull Component asComponent() {
return toChat().asComponent();
}
private enum Alignment {
LEFT,
CENTER,
RIGHT,
NONE
}
}