diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java index ea183cdb..4490df11 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java @@ -20,38 +20,10 @@ public abstract class BaseComponent BaseComponent parent; /** - * The color of this component and any child components (unless overridden) + * The component's style. */ - private ChatColor color; - /** - * The font of this component and any child components (unless overridden) - */ - private String font; - /** - * Whether this component and any child components (unless overridden) is - * bold - */ - private Boolean bold; - /** - * Whether this component and any child components (unless overridden) is - * italic - */ - private Boolean italic; - /** - * Whether this component and any child components (unless overridden) is - * underlined - */ - private Boolean underlined; - /** - * Whether this component and any child components (unless overridden) is - * strikethrough - */ - private Boolean strikethrough; - /** - * Whether this component and any child components (unless overridden) is - * obfuscated - */ - private Boolean obfuscated; + @Getter + private ComponentStyle style = new ComponentStyle(); /** * The text to insert into the chat when this component (and child * components) are clicked while pressing the shift key @@ -153,31 +125,31 @@ public abstract class BaseComponent } if ( retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL ) { - if ( replace || color == null ) + if ( replace || !style.hasColor() ) { setColor( component.getColorRaw() ); } - if ( replace || font == null ) + if ( replace || !style.hasFont() ) { setFont( component.getFontRaw() ); } - if ( replace || bold == null ) + if ( replace || style.isBoldRaw() == null ) { setBold( component.isBoldRaw() ); } - if ( replace || italic == null ) + if ( replace || style.isItalicRaw() == null ) { setItalic( component.isItalicRaw() ); } - if ( replace || underlined == null ) + if ( replace || style.isUnderlinedRaw() == null ) { setUnderlined( component.isUnderlinedRaw() ); } - if ( replace || strikethrough == null ) + if ( replace || style.isStrikethroughRaw() == null ) { setStrikethrough( component.isStrikethroughRaw() ); } - if ( replace || obfuscated == null ) + if ( replace || style.isObfuscatedRaw() == null ) { setObfuscated( component.isObfuscatedRaw() ); } @@ -266,6 +238,29 @@ public abstract class BaseComponent return builder.toString(); } + /** + * Set the {@link ComponentStyle} for this component. + *
+ * Unlike {@link #applyStyle(ComponentStyle)}, this method will overwrite + * all style values on this component. + * + * @param style the style to set, or null to set all style values to default + */ + public void setStyle(ComponentStyle style) + { + this.style = ( style != null ) ? style.clone() : new ComponentStyle(); + } + + /** + * Set this component's color. + * + * @param color the component color, or null to use the default + */ + public void setColor(ChatColor color) + { + this.style.setColor( color ); + } + /** * Returns the color of this component. This uses the parent's color if this * component doesn't have one. {@link net.md_5.bungee.api.ChatColor#WHITE} @@ -275,7 +270,7 @@ public abstract class BaseComponent */ public ChatColor getColor() { - if ( color == null ) + if ( !style.hasColor() ) { if ( parent == null ) { @@ -283,7 +278,7 @@ public abstract class BaseComponent } return parent.getColor(); } - return color; + return style.getColor(); } /** @@ -294,7 +289,17 @@ public abstract class BaseComponent */ public ChatColor getColorRaw() { - return color; + return style.getColor(); + } + + /** + * Set this component's font. + * + * @param font the font to set, or null to use the default + */ + public void setFont(String font) + { + this.style.setFont( font ); } /** @@ -305,7 +310,7 @@ public abstract class BaseComponent */ public String getFont() { - if ( font == null ) + if ( !style.hasFont() ) { if ( parent == null ) { @@ -313,7 +318,7 @@ public abstract class BaseComponent } return parent.getFont(); } - return font; + return style.getFont(); } /** @@ -324,7 +329,17 @@ public abstract class BaseComponent */ public String getFontRaw() { - return font; + return style.getFont(); + } + + /** + * Set whether or not this component is bold. + * + * @param bold the new bold state, or null to use the default + */ + public void setBold(Boolean bold) + { + this.style.setBold( bold ); } /** @@ -336,11 +351,11 @@ public abstract class BaseComponent */ public boolean isBold() { - if ( bold == null ) + if ( style.isBoldRaw() == null ) { return parent != null && parent.isBold(); } - return bold; + return style.isBold(); } /** @@ -351,7 +366,17 @@ public abstract class BaseComponent */ public Boolean isBoldRaw() { - return bold; + return style.isBoldRaw(); + } + + /** + * Set whether or not this component is italic. + * + * @param italic the new italic state, or null to use the default + */ + public void setItalic(Boolean italic) + { + this.style.setItalic( italic ); } /** @@ -363,11 +388,11 @@ public abstract class BaseComponent */ public boolean isItalic() { - if ( italic == null ) + if ( style.isItalicRaw() == null ) { return parent != null && parent.isItalic(); } - return italic; + return style.isItalic(); } /** @@ -378,7 +403,17 @@ public abstract class BaseComponent */ public Boolean isItalicRaw() { - return italic; + return style.isItalicRaw(); + } + + /** + * Set whether or not this component is underlined. + * + * @param underlined the new underlined state, or null to use the default + */ + public void setUnderlined(Boolean underlined) + { + this.style.setUnderlined( underlined ); } /** @@ -390,11 +425,11 @@ public abstract class BaseComponent */ public boolean isUnderlined() { - if ( underlined == null ) + if ( style.isUnderlinedRaw() == null ) { return parent != null && parent.isUnderlined(); } - return underlined; + return style.isUnderlined(); } /** @@ -405,7 +440,18 @@ public abstract class BaseComponent */ public Boolean isUnderlinedRaw() { - return underlined; + return style.isUnderlinedRaw(); + } + + /** + * Set whether or not this component is strikethrough. + * + * @param strikethrough the new strikethrough state, or null to use the + * default + */ + public void setStrikethrough(Boolean strikethrough) + { + this.style.setStrikethrough( strikethrough ); } /** @@ -417,11 +463,11 @@ public abstract class BaseComponent */ public boolean isStrikethrough() { - if ( strikethrough == null ) + if ( style.isStrikethroughRaw() == null ) { return parent != null && parent.isStrikethrough(); } - return strikethrough; + return style.isStrikethrough(); } /** @@ -432,7 +478,17 @@ public abstract class BaseComponent */ public Boolean isStrikethroughRaw() { - return strikethrough; + return style.isStrikethroughRaw(); + } + + /** + * Set whether or not this component is obfuscated. + * + * @param obfuscated the new obfuscated state, or null to use the default + */ + public void setObfuscated(Boolean obfuscated) + { + this.style.setObfuscated( obfuscated ); } /** @@ -444,11 +500,11 @@ public abstract class BaseComponent */ public boolean isObfuscated() { - if ( obfuscated == null ) + if ( style.isObfuscatedRaw() == null ) { return parent != null && parent.isObfuscated(); } - return obfuscated; + return style.isObfuscated(); } /** @@ -459,7 +515,48 @@ public abstract class BaseComponent */ public Boolean isObfuscatedRaw() { - return obfuscated; + return style.isObfuscatedRaw(); + } + + /** + * Apply the style from the given {@link ComponentStyle} to this component. + *
+ * Any style values that have been explicitly set in the style will be
+ * applied to this component. If a value is not set in the style, it will
+ * not override the style set in this component.
+ *
+ * @param style the style to apply
+ */
+ public void applyStyle(ComponentStyle style)
+ {
+ if ( style.hasColor() )
+ {
+ setColor( style.getColor() );
+ }
+ if ( style.hasFont() )
+ {
+ setFont( style.getFont() );
+ }
+ if ( style.isBoldRaw() != null )
+ {
+ setBold( style.isBoldRaw() );
+ }
+ if ( style.isItalicRaw() != null )
+ {
+ setItalic( style.isItalicRaw() );
+ }
+ if ( style.isUnderlinedRaw() != null )
+ {
+ setUnderlined( style.isUnderlinedRaw() );
+ }
+ if ( style.isStrikethroughRaw() != null )
+ {
+ setStrikethrough( style.isStrikethroughRaw() );
+ }
+ if ( style.isObfuscatedRaw() != null )
+ {
+ setObfuscated( style.isObfuscatedRaw() );
+ }
}
public void setExtra(List
+ * ComponentStyleBuilder simplifies creating component styles by allowing the
+ * use of a chainable builder.
+ *
+ * ComponentStyle style = ComponentStyle.builder()
+ * .color(ChatColor.RED)
+ * .font("custom:font")
+ * .bold(true).italic(true).create();
+ *
+ * BaseComponent component = new ComponentBuilder("Hello world").style(style).create();
+ * // Or it can be used directly on a component
+ * TextComponent text = new TextComponent("Hello world");
+ * text.applyStyle(style);
+ *
+ *
+ * @see ComponentStyle#builder()
+ * @see ComponentStyle#builder(ComponentStyle)
+ */
+public final class ComponentStyleBuilder
+{
+
+ private ChatColor color;
+ private String font;
+ private Boolean bold, italic, underlined, strikethrough, obfuscated;
+
+ /**
+ * Set the style color.
+ *
+ * @param color the color to set, or null to use the default
+ * @return this ComponentStyleBuilder for chaining
+ */
+ public ComponentStyleBuilder color(ChatColor color)
+ {
+ this.color = color;
+ return this;
+ }
+
+ /**
+ * Set the style font.
+ *
+ * @param font the font key to set, or null to use the default
+ * @return this ComponentStyleBuilder for chaining
+ */
+ public ComponentStyleBuilder font(String font)
+ {
+ this.font = font;
+ return this;
+ }
+
+ /**
+ * Set the style's bold property.
+ *
+ * @param bold the bold value to set, or null to use the default
+ * @return this ComponentStyleBuilder for chaining
+ */
+ public ComponentStyleBuilder bold(Boolean bold)
+ {
+ this.bold = bold;
+ return this;
+ }
+
+ /**
+ * Set the style's italic property.
+ *
+ * @param italic the italic value to set, or null to use the default
+ * @return this ComponentStyleBuilder for chaining
+ */
+ public ComponentStyleBuilder italic(Boolean italic)
+ {
+ this.italic = italic;
+ return this;
+ }
+
+ /**
+ * Set the style's underlined property.
+ *
+ * @param underlined the underlined value to set, or null to use the default
+ * @return this ComponentStyleBuilder for chaining
+ */
+ public ComponentStyleBuilder underlined(Boolean underlined)
+ {
+ this.underlined = underlined;
+ return this;
+ }
+
+ /**
+ * Set the style's strikethrough property.
+ *
+ * @param strikethrough the strikethrough value to set, or null to use the
+ * default
+ * @return this ComponentStyleBuilder for chaining
+ */
+ public ComponentStyleBuilder strikethrough(Boolean strikethrough)
+ {
+ this.strikethrough = strikethrough;
+ return this;
+ }
+
+ /**
+ * Set the style's obfuscated property.
+ *
+ * @param obfuscated the obfuscated value to set, or null to use the default
+ * @return this ComponentStyleBuilder for chaining
+ */
+ public ComponentStyleBuilder obfuscated(Boolean obfuscated)
+ {
+ this.obfuscated = obfuscated;
+ return this;
+ }
+
+ /**
+ * Build the {@link ComponentStyle} using the values set in this builder.
+ *
+ * @return the created ComponentStyle
+ */
+ public ComponentStyle build()
+ {
+ return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated );
+ }
+}
diff --git a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
index b7e85f1f..86bb0cb5 100644
--- a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
+++ b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java
@@ -4,72 +4,25 @@ import com.google.common.base.Preconditions;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Locale;
-import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
+import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.hover.content.Content;
public class BaseComponentSerializer
{
- private static boolean getAsBoolean(JsonElement el)
- {
- if ( el.isJsonPrimitive() )
- {
- JsonPrimitive primitive = (JsonPrimitive) el;
-
- if ( primitive.isBoolean() )
- {
- return primitive.getAsBoolean();
- }
-
- if ( primitive.isNumber() )
- {
- Number number = primitive.getAsNumber();
- if ( number instanceof Byte )
- {
- return number.byteValue() != 0;
- }
- }
- }
-
- return false;
- }
-
protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context)
{
- if ( object.has( "bold" ) )
- {
- component.setBold( getAsBoolean( object.get( "bold" ) ) );
- }
- if ( object.has( "italic" ) )
- {
- component.setItalic( getAsBoolean( object.get( "italic" ) ) );
- }
- if ( object.has( "underlined" ) )
- {
- component.setUnderlined( getAsBoolean( object.get( "underlined" ) ) );
- }
- if ( object.has( "strikethrough" ) )
- {
- component.setStrikethrough( getAsBoolean( object.get( "strikethrough" ) ) );
- }
- if ( object.has( "obfuscated" ) )
- {
- component.setObfuscated( getAsBoolean( object.get( "obfuscated" ) ) );
- }
- if ( object.has( "color" ) )
- {
- component.setColor( ChatColor.of( object.get( "color" ).getAsString() ) );
- }
+ component.applyStyle( context.deserialize( object, ComponentStyle.class ) );
+
if ( object.has( "insertion" ) )
{
component.setInsertion( object.get( "insertion" ).getAsString() );
@@ -131,10 +84,6 @@ public class BaseComponentSerializer
}
}
- if ( object.has( "font" ) )
- {
- component.setFont( object.get( "font" ).getAsString() );
- }
if ( object.has( "extra" ) )
{
component.setExtra( Arrays.asList( context.