com.googlecode.lanterna.TextCharacter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lanterna Show documentation
Show all versions of lanterna Show documentation
Java library for creating text-based terminal GUIs
/*
* This file is part of lanterna (http://code.google.com/p/lanterna/).
*
* lanterna is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Copyright (C) 2010-2017 Martin Berglund
*/
package com.googlecode.lanterna;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
/**
* Represents a single character with additional metadata such as colors and modifiers. This class is immutable and
* cannot be modified after creation.
* @author Martin
*/
public class TextCharacter {
private static EnumSet toEnumSet(SGR... modifiers) {
if(modifiers.length == 0) {
return EnumSet.noneOf(SGR.class);
}
else {
return EnumSet.copyOf(Arrays.asList(modifiers));
}
}
public static final TextCharacter DEFAULT_CHARACTER = new TextCharacter(' ', TextColor.ANSI.DEFAULT, TextColor.ANSI.DEFAULT);
private final char character;
private final TextColor foregroundColor;
private final TextColor backgroundColor;
private final EnumSet modifiers; //This isn't immutable, but we should treat it as such and not expose it!
/**
* Creates a {@code ScreenCharacter} based on a supplied character, with default colors and no extra modifiers.
* @param character Physical character to use
*/
public TextCharacter(char character) {
this(character, TextColor.ANSI.DEFAULT, TextColor.ANSI.DEFAULT);
}
/**
* Copies another {@code ScreenCharacter}
* @param character screenCharacter to copy from
*/
public TextCharacter(TextCharacter character) {
this(character.getCharacter(),
character.getForegroundColor(),
character.getBackgroundColor(),
character.getModifiers().toArray(new SGR[character.getModifiers().size()]));
}
/**
* Creates a new {@code ScreenCharacter} based on a physical character, color information and optional modifiers.
* @param character Physical character to refer to
* @param foregroundColor Foreground color the character has
* @param backgroundColor Background color the character has
* @param styles Optional list of modifiers to apply when drawing the character
*/
@SuppressWarnings("WeakerAccess")
public TextCharacter(
char character,
TextColor foregroundColor,
TextColor backgroundColor,
SGR... styles) {
this(character,
foregroundColor,
backgroundColor,
toEnumSet(styles));
}
/**
* Creates a new {@code ScreenCharacter} based on a physical character, color information and a set of modifiers.
* @param character Physical character to refer to
* @param foregroundColor Foreground color the character has
* @param backgroundColor Background color the character has
* @param modifiers Set of modifiers to apply when drawing the character
*/
public TextCharacter(
char character,
TextColor foregroundColor,
TextColor backgroundColor,
EnumSet modifiers) {
// Don't allow creating a TextCharacter containing a control character
// For backward-compatibility, do allow tab for now
// TODO: In lanterna 3.1, don't allow tab
if(TerminalTextUtils.isControlCharacter(character) && character != '\t') {
throw new IllegalArgumentException("Cannot create a TextCharacter from a control character (0x" + Integer.toHexString(character) + ")");
}
if(foregroundColor == null) {
foregroundColor = TextColor.ANSI.DEFAULT;
}
if(backgroundColor == null) {
backgroundColor = TextColor.ANSI.DEFAULT;
}
this.character = character;
this.foregroundColor = foregroundColor;
this.backgroundColor = backgroundColor;
this.modifiers = EnumSet.copyOf(modifiers);
}
/**
* The actual character this TextCharacter represents
* @return character of the TextCharacter
*/
public char getCharacter() {
return character;
}
/**
* Foreground color specified for this TextCharacter
* @return Foreground color of this TextCharacter
*/
public TextColor getForegroundColor() {
return foregroundColor;
}
/**
* Background color specified for this TextCharacter
* @return Background color of this TextCharacter
*/
public TextColor getBackgroundColor() {
return backgroundColor;
}
/**
* Returns a set of all active modifiers on this TextCharacter
* @return Set of active SGR codes
*/
public EnumSet getModifiers() {
return EnumSet.copyOf(modifiers);
}
/**
* Returns true if this TextCharacter has the bold modifier active
* @return {@code true} if this TextCharacter has the bold modifier active
*/
public boolean isBold() {
return modifiers.contains(SGR.BOLD);
}
/**
* Returns true if this TextCharacter has the reverse modifier active
* @return {@code true} if this TextCharacter has the reverse modifier active
*/
public boolean isReversed() {
return modifiers.contains(SGR.REVERSE);
}
/**
* Returns true if this TextCharacter has the underline modifier active
* @return {@code true} if this TextCharacter has the underline modifier active
*/
public boolean isUnderlined() {
return modifiers.contains(SGR.UNDERLINE);
}
/**
* Returns true if this TextCharacter has the blink modifier active
* @return {@code true} if this TextCharacter has the blink modifier active
*/
public boolean isBlinking() {
return modifiers.contains(SGR.BLINK);
}
/**
* Returns true if this TextCharacter has the bordered modifier active
* @return {@code true} if this TextCharacter has the bordered modifier active
*/
public boolean isBordered() {
return modifiers.contains(SGR.BORDERED);
}
/**
* Returns true if this TextCharacter has the crossed-out modifier active
* @return {@code true} if this TextCharacter has the crossed-out modifier active
*/
public boolean isCrossedOut() {
return modifiers.contains(SGR.CROSSED_OUT);
}
/**
* Returns true if this TextCharacter has the italic modifier active
* @return {@code true} if this TextCharacter has the italic modifier active
*/
public boolean isItalic() {
return modifiers.contains(SGR.ITALIC);
}
/**
* Returns a new TextCharacter with the same colors and modifiers but a different underlying character
* @param character Character the copy should have
* @return Copy of this TextCharacter with different underlying character
*/
@SuppressWarnings("SameParameterValue")
public TextCharacter withCharacter(char character) {
if(this.character == character) {
return this;
}
return new TextCharacter(character, foregroundColor, backgroundColor, modifiers);
}
/**
* Returns a copy of this TextCharacter with a specified foreground color
* @param foregroundColor Foreground color the copy should have
* @return Copy of the TextCharacter with a different foreground color
*/
public TextCharacter withForegroundColor(TextColor foregroundColor) {
if(this.foregroundColor == foregroundColor || this.foregroundColor.equals(foregroundColor)) {
return this;
}
return new TextCharacter(character, foregroundColor, backgroundColor, modifiers);
}
/**
* Returns a copy of this TextCharacter with a specified background color
* @param backgroundColor Background color the copy should have
* @return Copy of the TextCharacter with a different background color
*/
public TextCharacter withBackgroundColor(TextColor backgroundColor) {
if(this.backgroundColor == backgroundColor || this.backgroundColor.equals(backgroundColor)) {
return this;
}
return new TextCharacter(character, foregroundColor, backgroundColor, modifiers);
}
/**
* Returns a copy of this TextCharacter with specified list of SGR modifiers. None of the currently active SGR codes
* will be carried over to the copy, only those in the passed in value.
* @param modifiers SGR modifiers the copy should have
* @return Copy of the TextCharacter with a different set of SGR modifiers
*/
public TextCharacter withModifiers(Collection modifiers) {
EnumSet newSet = EnumSet.copyOf(modifiers);
if(modifiers.equals(newSet)) {
return this;
}
return new TextCharacter(character, foregroundColor, backgroundColor, newSet);
}
/**
* Returns a copy of this TextCharacter with an additional SGR modifier. All of the currently active SGR codes
* will be carried over to the copy, in addition to the one specified.
* @param modifier SGR modifiers the copy should have in additional to all currently present
* @return Copy of the TextCharacter with a new SGR modifier
*/
public TextCharacter withModifier(SGR modifier) {
if(modifiers.contains(modifier)) {
return this;
}
EnumSet newSet = EnumSet.copyOf(this.modifiers);
newSet.add(modifier);
return new TextCharacter(character, foregroundColor, backgroundColor, newSet);
}
/**
* Returns a copy of this TextCharacter with an SGR modifier removed. All of the currently active SGR codes
* will be carried over to the copy, except for the one specified. If the current TextCharacter doesn't have the
* SGR specified, it will return itself.
* @param modifier SGR modifiers the copy should not have
* @return Copy of the TextCharacter without the SGR modifier
*/
public TextCharacter withoutModifier(SGR modifier) {
if(!modifiers.contains(modifier)) {
return this;
}
EnumSet newSet = EnumSet.copyOf(this.modifiers);
newSet.remove(modifier);
return new TextCharacter(character, foregroundColor, backgroundColor, newSet);
}
public boolean isDoubleWidth() {
return TerminalTextUtils.isCharDoubleWidth(character);
}
@SuppressWarnings("SimplifiableIfStatement")
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(getClass() != obj.getClass()) {
return false;
}
final TextCharacter other = (TextCharacter) obj;
if(this.character != other.character) {
return false;
}
if(this.foregroundColor != other.foregroundColor && (this.foregroundColor == null || !this.foregroundColor.equals(other.foregroundColor))) {
return false;
}
if(this.backgroundColor != other.backgroundColor && (this.backgroundColor == null || !this.backgroundColor.equals(other.backgroundColor))) {
return false;
}
return !(this.modifiers != other.modifiers && (this.modifiers == null || !this.modifiers.equals(other.modifiers)));
}
@Override
public int hashCode() {
int hash = 7;
hash = 37 * hash + this.character;
hash = 37 * hash + (this.foregroundColor != null ? this.foregroundColor.hashCode() : 0);
hash = 37 * hash + (this.backgroundColor != null ? this.backgroundColor.hashCode() : 0);
hash = 37 * hash + (this.modifiers != null ? this.modifiers.hashCode() : 0);
return hash;
}
@Override
public String toString() {
return "TextCharacter{" + "character=" + character + ", foregroundColor=" + foregroundColor + ", backgroundColor=" + backgroundColor + ", modifiers=" + modifiers + '}';
}
}