/*
 * 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 <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2010-2020 Martin Berglund
 */
package com.googlecode.lanterna.graphics;

import com.googlecode.lanterna.SGR;
import com.googlecode.lanterna.TextColor;
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.gui2.table.Table;

import java.util.*;

Very basic implementation of Theme that allows you to quickly define a theme in code. It is a very simple implementation that doesn't implement any intelligent fallback based on class hierarchy or package names. If a particular class has not been defined with an explicit override, it will get the default theme style definition.
Author:Martin
/** * Very basic implementation of {@link Theme} that allows you to quickly define a theme in code. It is a very simple * implementation that doesn't implement any intelligent fallback based on class hierarchy or package names. If a * particular class has not been defined with an explicit override, it will get the default theme style definition. * * @author Martin */
public class SimpleTheme implements Theme {
Helper method that will quickly setup a new theme with some sensible component overrides.
Params:
  • activeIsBold – Should focused components also use bold SGR style?
  • baseForeground – The base foreground color of the theme
  • baseBackground – The base background color of the theme
  • editableForeground – Foreground color for editable components, or editable areas of components
  • editableBackground – Background color for editable components, or editable areas of components
  • selectedForeground – Foreground color for the selection marker when a component has multiple selection states
  • selectedBackground – Background color for the selection marker when a component has multiple selection states
  • guiBackground – Background color of the GUI, if this theme is assigned to the TextGUI
Returns:Assembled SimpleTheme using the parameters from above
/** * Helper method that will quickly setup a new theme with some sensible component overrides. * @param activeIsBold Should focused components also use bold SGR style? * @param baseForeground The base foreground color of the theme * @param baseBackground The base background color of the theme * @param editableForeground Foreground color for editable components, or editable areas of components * @param editableBackground Background color for editable components, or editable areas of components * @param selectedForeground Foreground color for the selection marker when a component has multiple selection states * @param selectedBackground Background color for the selection marker when a component has multiple selection states * @param guiBackground Background color of the GUI, if this theme is assigned to the {@link TextGUI} * @return Assembled {@link SimpleTheme} using the parameters from above */
public static SimpleTheme makeTheme( boolean activeIsBold, TextColor baseForeground, TextColor baseBackground, TextColor editableForeground, TextColor editableBackground, TextColor selectedForeground, TextColor selectedBackground, TextColor guiBackground) { SGR[] activeStyle = activeIsBold ? new SGR[]{SGR.BOLD} : new SGR[0]; SimpleTheme theme = new SimpleTheme(baseForeground, baseBackground); theme.getDefaultDefinition().setSelected(baseBackground, baseForeground, activeStyle); theme.getDefaultDefinition().setActive(selectedForeground, selectedBackground, activeStyle); theme.addOverride(AbstractBorder.class, baseForeground, baseBackground) .setSelected(baseForeground, baseBackground, activeStyle); theme.addOverride(AbstractListBox.class, baseForeground, baseBackground) .setSelected(selectedForeground, selectedBackground, activeStyle); theme.addOverride(Button.class, baseForeground, baseBackground) .setActive(selectedForeground, selectedBackground, activeStyle) .setSelected(selectedForeground, selectedBackground, activeStyle); theme.addOverride(CheckBox.class, baseForeground, baseBackground) .setActive(selectedForeground, selectedBackground, activeStyle) .setPreLight(selectedForeground, selectedBackground, activeStyle) .setSelected(selectedForeground, selectedBackground, activeStyle); theme.addOverride(CheckBoxList.class, baseForeground, baseBackground) .setActive(selectedForeground, selectedBackground, activeStyle); theme.addOverride(ComboBox.class, baseForeground, baseBackground) .setActive(editableForeground, editableBackground, activeStyle) .setPreLight(editableForeground, editableBackground); theme.addOverride(DefaultWindowDecorationRenderer.class, baseForeground, baseBackground) .setActive(baseForeground, baseBackground, activeStyle); theme.addOverride(GUIBackdrop.class, baseForeground, guiBackground); theme.addOverride(RadioBoxList.class, baseForeground, baseBackground) .setActive(selectedForeground, selectedBackground, activeStyle); theme.addOverride(Table.class, baseForeground, baseBackground) .setActive(editableForeground, editableBackground, activeStyle) .setSelected(baseForeground, baseBackground); theme.addOverride(TextBox.class, editableForeground, editableBackground) .setActive(editableForeground, editableBackground, activeStyle) .setSelected(editableForeground, editableBackground, activeStyle); theme.setWindowPostRenderer(new WindowShadowRenderer()); return theme; } private final Definition defaultDefinition; private final Map<Class<?>, Definition> overrideDefinitions; private WindowPostRenderer windowPostRenderer; private WindowDecorationRenderer windowDecorationRenderer;
Creates a new SimpleTheme object that uses the supplied constructor arguments as the default style
Params:
  • foreground – Color to use as the foreground unless overridden
  • background – Color to use as the background unless overridden
  • styles – Extra SGR styles to apply unless overridden
/** * Creates a new {@link SimpleTheme} object that uses the supplied constructor arguments as the default style * @param foreground Color to use as the foreground unless overridden * @param background Color to use as the background unless overridden * @param styles Extra SGR styles to apply unless overridden */
public SimpleTheme(TextColor foreground, TextColor background, SGR... styles) { this.defaultDefinition = new Definition(new DefaultMutableThemeStyle(foreground, background, styles)); this.overrideDefinitions = new HashMap<Class<?>, Definition>(); this.windowPostRenderer = null; this.windowDecorationRenderer = null; } @Override public synchronized Definition getDefaultDefinition() { return defaultDefinition; } @Override public synchronized Definition getDefinition(Class<?> clazz) { Definition definition = overrideDefinitions.get(clazz); if(definition == null) { return getDefaultDefinition(); } return definition; }
Adds an override for a particular class, or overwrites a previously defined override.
Params:
  • clazz – Class to override the theme for
  • foreground – Color to use as the foreground color for this override style
  • background – Color to use as the background color for this override style
  • styles – SGR styles to apply for this override
Returns:The newly created Definition that corresponds to this override.
/** * Adds an override for a particular class, or overwrites a previously defined override. * @param clazz Class to override the theme for * @param foreground Color to use as the foreground color for this override style * @param background Color to use as the background color for this override style * @param styles SGR styles to apply for this override * @return The newly created {@link Definition} that corresponds to this override. */
public synchronized Definition addOverride(Class<?> clazz, TextColor foreground, TextColor background, SGR... styles) { Definition definition = new Definition(new DefaultMutableThemeStyle(foreground, background, styles)); overrideDefinitions.put(clazz, definition); return definition; } @Override public synchronized WindowPostRenderer getWindowPostRenderer() { return windowPostRenderer; }
Changes the WindowPostRenderer this theme will return. If called with null, the theme returns no post renderer and the GUI system will use whatever is the default.
Params:
  • windowPostRenderer – Post-renderer to use along with this theme, or null to remove
Returns:Itself
/** * Changes the {@link WindowPostRenderer} this theme will return. If called with {@code null}, the theme returns no * post renderer and the GUI system will use whatever is the default. * @param windowPostRenderer Post-renderer to use along with this theme, or {@code null} to remove * @return Itself */
public synchronized SimpleTheme setWindowPostRenderer(WindowPostRenderer windowPostRenderer) { this.windowPostRenderer = windowPostRenderer; return this; } @Override public synchronized WindowDecorationRenderer getWindowDecorationRenderer() { return windowDecorationRenderer; }
Changes the WindowDecorationRenderer this theme will return. If called with null, the theme returns no decoration renderer and the GUI system will use whatever is the default.
Params:
  • windowDecorationRenderer – Decoration renderer to use along with this theme, or null to remove
Returns:Itself
/** * Changes the {@link WindowDecorationRenderer} this theme will return. If called with {@code null}, the theme * returns no decoration renderer and the GUI system will use whatever is the default. * @param windowDecorationRenderer Decoration renderer to use along with this theme, or {@code null} to remove * @return Itself */
public synchronized SimpleTheme setWindowDecorationRenderer(WindowDecorationRenderer windowDecorationRenderer) { this.windowDecorationRenderer = windowDecorationRenderer; return this; } public interface RendererProvider<T extends Component> { ComponentRenderer<T> getRenderer(Class<T> type); }
Internal class inside SimpleTheme used to allow basic editing of the default style and the optional overrides.
/** * Internal class inside {@link SimpleTheme} used to allow basic editing of the default style and the optional * overrides. */
public static class Definition implements ThemeDefinition { private final ThemeStyle normal; private ThemeStyle preLight; private ThemeStyle selected; private ThemeStyle active; private ThemeStyle insensitive; private final Map<String, ThemeStyle> customStyles; private final Properties properties; private final Map<String, Character> characterMap; private final Map<Class<?>, RendererProvider<?>> componentRendererMap; private boolean cursorVisible; private Definition(ThemeStyle normal) { this.normal = normal; this.preLight = null; this.selected = null; this.active = null; this.insensitive = null; this.customStyles = new HashMap<String, ThemeStyle>(); this.properties = new Properties(); this.characterMap = new HashMap<String, Character>(); this.componentRendererMap = new HashMap<Class<?>, RendererProvider<?>>(); this.cursorVisible = true; } @Override public synchronized ThemeStyle getNormal() { return normal; } @Override public synchronized ThemeStyle getPreLight() { if(preLight == null) { return normal; } return preLight; }
Sets the theme definition style "prelight"
Params:
  • foreground – Foreground color for this style
  • background – Background color for this style
  • styles – SGR styles to use
Returns:Itself
/** * Sets the theme definition style "prelight" * @param foreground Foreground color for this style * @param background Background color for this style * @param styles SGR styles to use * @return Itself */
public synchronized Definition setPreLight(TextColor foreground, TextColor background, SGR... styles) { this.preLight = new DefaultMutableThemeStyle(foreground, background, styles); return this; } @Override public synchronized ThemeStyle getSelected() { if(selected == null) { return normal; } return selected; }
Sets the theme definition style "selected"
Params:
  • foreground – Foreground color for this style
  • background – Background color for this style
  • styles – SGR styles to use
Returns:Itself
/** * Sets the theme definition style "selected" * @param foreground Foreground color for this style * @param background Background color for this style * @param styles SGR styles to use * @return Itself */
public synchronized Definition setSelected(TextColor foreground, TextColor background, SGR... styles) { this.selected = new DefaultMutableThemeStyle(foreground, background, styles); return this; } @Override public synchronized ThemeStyle getActive() { if(active == null) { return normal; } return active; }
Sets the theme definition style "active"
Params:
  • foreground – Foreground color for this style
  • background – Background color for this style
  • styles – SGR styles to use
Returns:Itself
/** * Sets the theme definition style "active" * @param foreground Foreground color for this style * @param background Background color for this style * @param styles SGR styles to use * @return Itself */
public synchronized Definition setActive(TextColor foreground, TextColor background, SGR... styles) { this.active = new DefaultMutableThemeStyle(foreground, background, styles); return this; } @Override public synchronized ThemeStyle getInsensitive() { if(insensitive == null) { return normal; } return insensitive; }
Sets the theme definition style "insensitive"
Params:
  • foreground – Foreground color for this style
  • background – Background color for this style
  • styles – SGR styles to use
Returns:Itself
/** * Sets the theme definition style "insensitive" * @param foreground Foreground color for this style * @param background Background color for this style * @param styles SGR styles to use * @return Itself */
public synchronized Definition setInsensitive(TextColor foreground, TextColor background, SGR... styles) { this.insensitive = new DefaultMutableThemeStyle(foreground, background, styles); return this; } @Override public synchronized ThemeStyle getCustom(String name) { return customStyles.get(name); } @Override public synchronized ThemeStyle getCustom(String name, ThemeStyle defaultValue) { ThemeStyle themeStyle = customStyles.get(name); if(themeStyle == null) { return defaultValue; } return themeStyle; }
Adds a custom definition style to the theme using the supplied name. This will be returned using the matching call to getCustom(String).
Params:
  • name – Name of the custom style
  • foreground – Foreground color for this style
  • background – Background color for this style
  • styles – SGR styles to use
Returns:Itself
/** * Adds a custom definition style to the theme using the supplied name. This will be returned using the matching * call to {@link Definition#getCustom(String)}. * @param name Name of the custom style * @param foreground Foreground color for this style * @param background Background color for this style * @param styles SGR styles to use * @return Itself */
public synchronized Definition setCustom(String name, TextColor foreground, TextColor background, SGR... styles) { customStyles.put(name, new DefaultMutableThemeStyle(foreground, background, styles)); return this; } @Override public synchronized boolean getBooleanProperty(String name, boolean defaultValue) { return Boolean.parseBoolean(properties.getProperty(name, Boolean.toString(defaultValue))); }
Attaches a boolean value property to this SimpleTheme that will be returned if calling getBooleanProperty(String, boolean) with the same name.
Params:
  • name – Name of the property
  • value – Value to attach to the property name
Returns:Itself
/** * Attaches a boolean value property to this {@link SimpleTheme} that will be returned if calling * {@link Definition#getBooleanProperty(String, boolean)} with the same name. * @param name Name of the property * @param value Value to attach to the property name * @return Itself */
public synchronized Definition setBooleanProperty(String name, boolean value) { properties.setProperty(name, Boolean.toString(value)); return this; } @Override public synchronized boolean isCursorVisible() { return cursorVisible; }
Sets the value that suggests if the cursor should be visible or not (it's still up to the component renderer if it's going to honour this or not).
Params:
  • cursorVisible – If true then this theme definition would like the text cursor to be displayed, false if not.
Returns:Itself
/** * Sets the value that suggests if the cursor should be visible or not (it's still up to the component renderer * if it's going to honour this or not). * @param cursorVisible If {@code true} then this theme definition would like the text cursor to be displayed, * {@code false} if not. * @return Itself */
public synchronized Definition setCursorVisible(boolean cursorVisible) { this.cursorVisible = cursorVisible; return this; } @Override public synchronized char getCharacter(String name, char fallback) { Character character = characterMap.get(name); if(character == null) { return fallback; } return character; }
Stores a character value in this definition under a specific name. This is used to customize the appearance of certain components. It is returned with call to getCharacter(String, char) with the same name.
Params:
  • name – Symbolic name for the character
  • character – Character to attach to the symbolic name
Returns:Itself
/** * Stores a character value in this definition under a specific name. This is used to customize the appearance * of certain components. It is returned with call to {@link Definition#getCharacter(String, char)} with the * same name. * @param name Symbolic name for the character * @param character Character to attach to the symbolic name * @return Itself */
public synchronized Definition setCharacter(String name, char character) { characterMap.put(name, character); return this; } @SuppressWarnings("unchecked") @Override public synchronized <T extends Component> ComponentRenderer<T> getRenderer(Class<T> type) { RendererProvider<T> rendererProvider = (RendererProvider<T>)componentRendererMap.get(type); if(rendererProvider == null) { return null; } return rendererProvider.getRenderer(type); }
Registered a callback to get a custom ComponentRenderer for a particular class. Use this to make a certain component (built-in or external) to use a custom renderer.
Params:
Type parameters:
  • <T> – Type of class
Returns:Itself
/** * Registered a callback to get a custom {@link ComponentRenderer} for a particular class. Use this to make a * certain component (built-in or external) to use a custom renderer. * @param type Class for which to invoke the callback and return the {@link ComponentRenderer} * @param rendererProvider Callback to invoke when getting a {@link ComponentRenderer} * @param <T> Type of class * @return Itself */
public synchronized <T extends Component> Definition setRenderer(Class<T> type, RendererProvider<T> rendererProvider) { if(rendererProvider == null) { componentRendererMap.remove(type); } else { componentRendererMap.put(type, rendererProvider); } return this; } } }