From: Niki Roo Date: Thu, 6 Jul 2017 20:16:02 +0000 (+0200) Subject: Version 2.0.0: update sources X-Git-Url: http://git.nikiroo.be/?p=jvcard.git;a=commitdiff_plain;h=f06c81000632cfb5f525ca458f719338f55f9f66 Version 2.0.0: update sources - use latest nikiroo-utils - use new scripts for build and dependencies handling - not a lot of differences, but much less confusion for me --- diff --git a/VERSION b/VERSION index 336c367..227cea2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0-dev +2.0.0 diff --git a/lanterna/2016-02-26 - 10:25 lanterna-master.zip b/lanterna/2016-02-26 - 10:25 lanterna-master.zip deleted file mode 100644 index bb45a36..0000000 Binary files a/lanterna/2016-02-26 - 10:25 lanterna-master.zip and /dev/null differ diff --git a/lanterna/lanterna-2.1.9-javadoc.jar b/lanterna/lanterna-2.1.9-javadoc.jar deleted file mode 100644 index b423ae0..0000000 Binary files a/lanterna/lanterna-2.1.9-javadoc.jar and /dev/null differ diff --git a/lanterna/lanterna-2.1.9-sources.jar b/lanterna/lanterna-2.1.9-sources.jar deleted file mode 100644 index 410521f..0000000 Binary files a/lanterna/lanterna-2.1.9-sources.jar and /dev/null differ diff --git a/lanterna/lanterna-2.1.9.jar b/lanterna/lanterna-2.1.9.jar deleted file mode 100644 index 5c6fa5f..0000000 Binary files a/lanterna/lanterna-2.1.9.jar and /dev/null differ diff --git a/lanterna/lanterna-3.0.0-beta2-javadoc.jar b/lanterna/lanterna-3.0.0-beta2-javadoc.jar deleted file mode 100644 index e8258ec..0000000 Binary files a/lanterna/lanterna-3.0.0-beta2-javadoc.jar and /dev/null differ diff --git a/lanterna/lanterna-3.0.0-beta2-sources.jar b/lanterna/lanterna-3.0.0-beta2-sources.jar deleted file mode 100644 index d81b3c1..0000000 Binary files a/lanterna/lanterna-3.0.0-beta2-sources.jar and /dev/null differ diff --git a/lanterna/lanterna-3.0.0-beta2.jar b/lanterna/lanterna-3.0.0-beta2.jar deleted file mode 100644 index 9d11a43..0000000 Binary files a/lanterna/lanterna-3.0.0-beta2.jar and /dev/null differ diff --git a/lanterna/2016-02-29 - 16:20 lanterna-master.zip b/libs/lanterna-2016.02.26-snapshot-sources.jar similarity index 72% rename from lanterna/2016-02-29 - 16:20 lanterna-master.zip rename to libs/lanterna-2016.02.26-snapshot-sources.jar index 55f0f8e..a7c28e5 100644 Binary files a/lanterna/2016-02-29 - 16:20 lanterna-master.zip and b/libs/lanterna-2016.02.26-snapshot-sources.jar differ diff --git a/libs/nikiroo-utils-2.0.0-sources.jar b/libs/nikiroo-utils-2.0.0-sources.jar new file mode 100644 index 0000000..26cad68 Binary files /dev/null and b/libs/nikiroo-utils-2.0.0-sources.jar differ diff --git a/src/be/nikiroo/jvcard/BaseClass.java b/src/be/nikiroo/jvcard/BaseClass.java index 9323376..9533321 100644 --- a/src/be/nikiroo/jvcard/BaseClass.java +++ b/src/be/nikiroo/jvcard/BaseClass.java @@ -10,7 +10,7 @@ import java.util.LinkedList; import java.util.List; import java.util.ListIterator; -import be.nikiroo.jvcard.resources.StringUtils; +import be.nikiroo.utils.StringUtils; /** * This class is basically a List with a parent and a "dirty" state check. It @@ -30,7 +30,7 @@ import be.nikiroo.jvcard.resources.StringUtils; *

* * @author niki - * + * * @param * the type of the child elements */ @@ -275,7 +275,7 @@ public abstract class BaseClass> implements List { public String getContentState(boolean self) { StringBuilder builder = new StringBuilder(); buildContentStateRaw(builder, self); - return StringUtils.getHash(builder.toString()); + return StringUtils.getMd5Hash(builder.toString()); } /** diff --git a/src/be/nikiroo/jvcard/Contact.java b/src/be/nikiroo/jvcard/Contact.java index d75d338..93bd809 100644 --- a/src/be/nikiroo/jvcard/Contact.java +++ b/src/be/nikiroo/jvcard/Contact.java @@ -11,7 +11,7 @@ import java.util.UUID; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.parsers.Parser; -import be.nikiroo.jvcard.resources.StringUtils; +import be.nikiroo.utils.StringUtils; /** * A contact is the information that represent a contact person or organisation. diff --git a/src/be/nikiroo/jvcard/launcher/Main.java b/src/be/nikiroo/jvcard/launcher/Main.java index 54238c8..d893e10 100644 --- a/src/be/nikiroo/jvcard/launcher/Main.java +++ b/src/be/nikiroo/jvcard/launcher/Main.java @@ -1,7 +1,9 @@ package be.nikiroo.jvcard.launcher; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Field; import java.net.Socket; import java.nio.charset.Charset; @@ -19,14 +21,15 @@ import be.nikiroo.jvcard.launcher.Optional.NotSupportedException; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.remote.Command; import be.nikiroo.jvcard.remote.SimpleSocket; -import be.nikiroo.jvcard.resources.Bundles; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.bundles.ColorBundle; -import be.nikiroo.jvcard.resources.bundles.DisplayBundle; -import be.nikiroo.jvcard.resources.bundles.RemoteBundle; -import be.nikiroo.jvcard.resources.bundles.TransBundle; -import be.nikiroo.jvcard.resources.enums.DisplayOption; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.DisplayBundle; +import be.nikiroo.jvcard.resources.DisplayOption; +import be.nikiroo.jvcard.resources.RemoteBundle; +import be.nikiroo.jvcard.resources.StringId; +import be.nikiroo.jvcard.resources.TransBundle; +import be.nikiroo.utils.ImageUtils; +import be.nikiroo.utils.StringUtils; +import be.nikiroo.utils.Version; +import be.nikiroo.utils.resources.Bundles; /** * This class contains the runnable Main method. It will parse the user supplied @@ -34,11 +37,10 @@ import be.nikiroo.jvcard.resources.enums.StringId; * a MainWindow. * * @author niki - * + * */ public class Main { static public final String APPLICATION_TITLE = "jVcard"; - static public final String APPLICATION_VERSION = "1.1-dev"; static private final int ERR_NO_FILE = 1; static private final int ERR_SYNTAX = 2; @@ -273,11 +275,11 @@ public class Main { } new TransBundle().updateFile(dir); // default locale - for (String lang : TransBundle.getKnownLanguages()) { + for (String lang : new TransBundle().getKnownLanguages()) { new TransBundle(lang).updateFile(dir); } - new ColorBundle().updateFile(dir); + // new UIColors().updateFile(dir); new DisplayBundle().updateFile(dir); new RemoteBundle().updateFile(dir); } catch (IOException e) { @@ -336,7 +338,16 @@ public class Main { .toLowerCase(); } - String b64 = StringUtils.fromImage(f); + String b64; + InputStream in = null; + try { + in = new FileInputStream(f); + b64 = ImageUtils.toBase64(in); + } finally { + if (in != null) { + in.close(); + } + } // remove previous photos: for (Data photo = contact @@ -377,7 +388,7 @@ public class Main { System.out.println("Saving " + f); try { ImageIO.write( - StringUtils.toImage(photo.getValue()), + ImageUtils.fromBase64(photo.getValue()), "png", f); } catch (IOException e) { System.err.println(trans( @@ -413,7 +424,8 @@ public class Main { break; } case HELP: { - System.out.println(APPLICATION_TITLE + " " + APPLICATION_VERSION); + System.out.println(APPLICATION_TITLE + " " + + Version.getCurrentVersion()); System.out.println(); System.out.println(trans(StringId.CLI_HELP)); diff --git a/src/be/nikiroo/jvcard/remote/Server.java b/src/be/nikiroo/jvcard/remote/Server.java index ac29e97..30c404c 100644 --- a/src/be/nikiroo/jvcard/remote/Server.java +++ b/src/be/nikiroo/jvcard/remote/Server.java @@ -18,9 +18,9 @@ import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.parsers.Vcard21Parser; import be.nikiroo.jvcard.remote.SimpleSocket.BlockAppendable; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.bundles.RemoteBundle; -import be.nikiroo.jvcard.resources.enums.RemotingOption; +import be.nikiroo.jvcard.resources.RemoteBundle; +import be.nikiroo.jvcard.resources.RemotingOption; +import be.nikiroo.utils.StringUtils; /** * This class implements a small server that can listen for requests to @@ -34,7 +34,7 @@ import be.nikiroo.jvcard.resources.enums.RemotingOption; *

* * @author niki - * + * */ public class Server implements Runnable { private ServerSocket ss; diff --git a/src/be/nikiroo/jvcard/remote/Sync.java b/src/be/nikiroo/jvcard/remote/Sync.java index a1e5e24..4b7a18b 100644 --- a/src/be/nikiroo/jvcard/remote/Sync.java +++ b/src/be/nikiroo/jvcard/remote/Sync.java @@ -25,16 +25,16 @@ import be.nikiroo.jvcard.launcher.CardResult.MergeCallback; import be.nikiroo.jvcard.parsers.Format; import be.nikiroo.jvcard.parsers.Vcard21Parser; import be.nikiroo.jvcard.remote.SimpleSocket.BlockAppendable; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.bundles.RemoteBundle; -import be.nikiroo.jvcard.resources.enums.RemotingOption; +import be.nikiroo.jvcard.resources.RemoteBundle; +import be.nikiroo.jvcard.resources.RemotingOption; +import be.nikiroo.utils.StringUtils; /** * This class will synchronise {@link Card}s between a local instance an a * remote jVCard server. * * @author niki - * + * */ public class Sync { /** The time in ms after which we declare that 2 timestamps are different */ @@ -523,7 +523,7 @@ public class Sync { * * @param dir * the cache to use - * + * * @return the cached {@link File} */ private File getCache(File dir) { diff --git a/src/be/nikiroo/jvcard/resources/Bundles.java b/src/be/nikiroo/jvcard/resources/Bundles.java deleted file mode 100644 index 04b6f70..0000000 --- a/src/be/nikiroo/jvcard/resources/Bundles.java +++ /dev/null @@ -1,407 +0,0 @@ -package be.nikiroo.jvcard.resources; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.lang.reflect.Field; -import java.util.Locale; -import java.util.ResourceBundle; - -/** - * This class help you get UTF-8 bundles for this application. - * - * @author niki - * - */ -public class Bundles { - /** - * The configuration directory where we try to get the .properties - * in priority, or NULL to get the information from the compiled resources. - */ - static private String confDir = getConfDir(); - - /** - * The type of configuration information the associated {@link Bundle} will - * convey. - * - * @author niki - * - */ - public enum Target { - colors, display, jvcard, remote, resources - } - - /** - * Return the configuration directory where to try to find the - * .properties files in priority. - * - * @return the configuration directory - */ - static private String getConfDir() { - // Do not override user-supplied config directory (see --help) - if (Bundles.confDir != null) - return Bundles.confDir; - - try { - ResourceBundle bundle = ResourceBundle.getBundle(Bundles.class - .getPackage().getName() + "." + "jvcard", - Locale.getDefault(), new FixedResourceBundleControl(null)); - - String configDir = bundle.getString("CONFIG_DIR"); - if (configDir != null && configDir.trim().length() > 0) - return configDir; - } catch (Exception e) { - } - - return null; - } - - /** - * Set the primary configuration directory to look for .properties - * files in. - * - * All {@link ResourceBundle}s returned by this class after that point will - * respect this new directory. - * - * @param confDir - * the new directory - */ - static public void setDirectory(String confDir) { - Bundles.confDir = confDir; - } - - /** - * Get the primary configuration directory to look for .properties - * files in. - * - * @return the directory - */ - static public String getDirectory() { - return Bundles.confDir; - } - - /** - * This class encapsulate a {@link ResourceBundle} in UTF-8. It only allows - * to retrieve values associated to an enumeration, and allows some - * additional methods. - * - * @author niki - * - * @param - * the enum to use to get values out of this class - */ - public class Bundle> { - private Class type; - protected Target name; - protected ResourceBundle map; - - /** - * Create a new {@link Bundles} of the given name. - * - * @param type - * a runtime instance of the class of E - * - * @param name - * the name of the {@link Bundles} - */ - protected Bundle(Class type, Target name) { - this.type = type; - this.name = name; - this.map = getBundle(name); - } - - /** - * Return the value associated to the given id as a {@link String}. - * - * @param mame - * the id of the value to get - * - * @return the associated value - */ - public String getString(E id) { - if (map.containsKey(id.name())) { - return map.getString(id.name()).trim(); - } - - return ""; - } - - /** - * Return the value associated to the given id as a {@link Boolean}. - * - * @param mame - * the id of the value to get - * - * @return the associated value - */ - public Boolean getBoolean(E id) { - String str = getString(id); - if (str != null && str.length() > 0) { - if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("on") - || str.equalsIgnoreCase("yes")) - return true; - if (str.equalsIgnoreCase("false") - || str.equalsIgnoreCase("off") - || str.equalsIgnoreCase("no")) - return false; - - } - - return null; - } - - /** - * Return the value associated to the given id as a {@link boolean}. - * - * @param mame - * the id of the value to get - * @param def - * the default value when it is not present in the config - * file or if it is not a boolean value - * - * @return the associated value - */ - public boolean getBoolean(E id, boolean def) { - Boolean b = getBoolean(id); - if (b != null) - return b; - - return def; - } - - /** - * Return the value associated to the given id as an {@link Integer}. - * - * @param mame - * the id of the value to get - * - * @return the associated value - */ - public Integer getInteger(E id) { - try { - return Integer.parseInt(getString(id)); - } catch (Exception e) { - } - - return null; - } - - /** - * Return the value associated to the given id as a {@link int}. - * - * @param mame - * the id of the value to get - * @param def - * the default value when it is not present in the config - * file or if it is not a int value - * - * @return the associated value - */ - public int getInteger(E id, int def) { - Integer i = getInteger(id); - if (i != null) - return i; - - return def; - } - - /** - * Create/update the .properties file. Will use the most likely - * candidate as base if the file does not already exists and this - * resource is translatable (for instance, "en_US" will use "en" as a - * base if the resource is a translation file). - * - * @param path - * the path where the .properties files are - * - * @throws IOException - * in case of IO errors - */ - public void updateFile(String path) throws IOException { - File file = getUpdateFile(path); - - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(file), "UTF-8")); - - writeHeader(writer); - writer.write("\n"); - writer.write("\n"); - - for (Field field : type.getDeclaredFields()) { - Meta meta = field.getAnnotation(Meta.class); - if (meta != null) { - E id = E.valueOf(type, field.getName()); - String info = getMetaInfo(meta); - - if (info != null) { - writer.write(info); - writer.write("\n"); - } - - writeValue(writer, id); - } - } - - writer.close(); - } - - /** - * Return formated, display-able information from the {@link Meta} field - * given. Each line will always starts with a "#" character. - * - * @param meta - * the {@link Meta} field - * - * @return the information to display or NULL if none - */ - protected String getMetaInfo(Meta meta) { - String what = meta.what(); - String where = meta.where(); - String format = meta.format(); - String info = meta.info(); - - int opt = what.length() + where.length() + format.length(); - if (opt + info.length() == 0) - return null; - - StringBuilder builder = new StringBuilder(); - builder.append("# "); - - if (opt > 0) { - builder.append("("); - if (what.length() > 0) { - builder.append("WHAT: " + what); - if (where.length() + format.length() > 0) - builder.append(", "); - } - - if (where.length() > 0) { - builder.append("WHERE: " + where); - if (format.length() > 0) - builder.append(", "); - } - - if (format.length() > 0) { - builder.append("FORMAT: " + format); - } - - builder.append(")"); - if (info.length() > 0) { - builder.append("\n# "); - } - } - - builder.append(info); - - return builder.toString(); - } - - /** - * Write the header found in the configuration .properties file - * of this {@link Bundles}. - * - * @param writer - * the {@link Writer} to write the header in - * - * @throws IOException - * in case of IO error - */ - protected void writeHeader(Writer writer) throws IOException { - writer.write("# " + name + "\n"); - writer.write("#\n"); - } - - /** - * Write the given id to the config file, i.e., - * "MY_ID = my_curent_value" followed by a new line - * - * @param writer - * the {@link Writer} to write into - * @param id - * the id to write - * - * @throws IOException - * in case of IO error - */ - protected void writeValue(Writer writer, E id) throws IOException { - writeValue(writer, id.name(), getString(id)); - } - - /** - * Write the given data to the config file, i.e., - * "MY_ID = my_curent_value" followed by a new line - * - * @param writer - * the {@link Writer} to write into - * @param id - * the id to write - * @param value - * the id's value - * - * @throws IOException - * in case of IO error - */ - protected void writeValue(Writer writer, String id, String value) - throws IOException { - writer.write(id); - writer.write(" = "); - - String[] lines = value.replaceAll("\\\t", "\\\\\\t").split("\n"); - for (int i = 0; i < lines.length; i++) { - writer.write(lines[i]); - if (i < lines.length - 1) { - writer.write("\\n\\"); - } - writer.write("\n"); - } - } - - /** - * Return the non-localised bundle of the given name. - * - * @param name - * the name of the bundle to load - * - * @return the bundle - */ - protected ResourceBundle getBundle(Target name) { - return ResourceBundle.getBundle(Bundles.class.getPackage() - .getName() + "." + name.name(), - new FixedResourceBundleControl(confDir)); - } - - /** - * Return the localised bundle of the given name and {@link Locale}. - * - * @param name - * the name of the bundle to load - * @param locale - * the {@link Locale} to use - * - * @return the localised bundle - */ - protected ResourceBundle getBundle(Target name, Locale locale) { - return ResourceBundle.getBundle(Bundles.class.getPackage() - .getName() + "." + name.name(), locale, - new FixedResourceBundleControl(confDir)); - } - - /** - * Return the source file for this {@link Bundles} from the given path. - * - * @param path - * the path where the .properties files are - * - * @return the source {@link File} - * - * @throws IOException - * in case of IO errors - */ - protected File getUpdateFile(String path) { - return new File(path, name.name() + ".properties"); - } - } -} diff --git a/src/be/nikiroo/jvcard/resources/ColorBundle.java b/src/be/nikiroo/jvcard/resources/ColorBundle.java new file mode 100644 index 0000000..4fcef5e --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/ColorBundle.java @@ -0,0 +1,71 @@ +package be.nikiroo.jvcard.resources; + +import java.io.IOException; +import java.io.Writer; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import be.nikiroo.utils.resources.Bundle; + +/** + * All colour information must come from here. + *

+ * TODO: delete this class, and think about a better way to get BG/FG colours... + * + * @author niki + */ +public class ColorBundle extends Bundle { + public ColorBundle() { + super(ColorOption.class, Target.colors, null); + } + + @Override + protected void writeHeader(Writer writer) throws IOException { + ColorOption.writeHeader(writer); + } + + @Override + protected void writeValue(Writer writer, ColorOption id) throws IOException { + String name = id.name() + "_FG"; + String value = ""; + if (containsKey(name)) + value = getString(name).trim(); + + writeValue(writer, name, value); + + name = id.name() + "_BG"; + value = ""; + if (containsKey(name)) + value = getString(name).trim(); + + writeValue(writer, name, value); + } + + @Override + protected void resetMap(ResourceBundle bundle) { + // this.map.clear(); + + if (bundle != null) { + for (ColorOption field : type.getEnumConstants()) { + try { + // String value = bundle.getString(field.name()); + // this.map.put(field.name(), value == null ? null : + // value.trim()); + setString(field.name() + "_FG", + bundle.getString(field.name() + "_FG")); + setString(field.name() + "_BG", + bundle.getString(field.name() + "_BG")); + } catch (MissingResourceException e) { + } + } + } + } + + @Override + public String getStringX(ColorOption id, String suffix) { + String key = id.name() + + (suffix == null ? "" : "_" + suffix.toUpperCase()); + + return getString(key); + } +} diff --git a/src/be/nikiroo/jvcard/resources/enums/ColorOption.java b/src/be/nikiroo/jvcard/resources/ColorOption.java similarity index 55% rename from src/be/nikiroo/jvcard/resources/enums/ColorOption.java rename to src/be/nikiroo/jvcard/resources/ColorOption.java index d8816e0..40b5a2b 100644 --- a/src/be/nikiroo/jvcard/resources/enums/ColorOption.java +++ b/src/be/nikiroo/jvcard/resources/ColorOption.java @@ -1,62 +1,62 @@ -package be.nikiroo.jvcard.resources.enums; +package be.nikiroo.jvcard.resources; import java.io.IOException; import java.io.Writer; -import be.nikiroo.jvcard.resources.Meta; -import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.utils.resources.Meta; +import be.nikiroo.utils.resources.Meta.Format; /** * Represent an element that can be coloured (foreground/background colours). * * @author niki - * + * */ public enum ColorOption { - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) DEFAULT, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) TITLE_MAIN, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) TITLE_VARIABLE, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) TITLE_COUNT, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) ACTION_KEY, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) ACTION_DESC, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) LINE_MESSAGE, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) LINE_MESSAGE_ERR, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) LINE_MESSAGE_QUESTION, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) LINE_MESSAGE_ANS, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) CONTACT_LINE, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) CONTACT_LINE_SEPARATOR, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) CONTACT_LINE_SELECTED, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) CONTACT_LINE_SEPARATOR_SELECTED, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) CONTACT_LINE_DIRTY, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) CONTACT_LINE_DIRTY_SELECTED, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) VIEW_CONTACT_NAME, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) VIEW_CONTACT_NORMAL, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) VIEW_CONTACT_HIGHLIGHT, // - @Meta(what = "", where = "", format = "colour", info = "") + @Meta(format = Format.COLOR) VIEW_CONTACT_NOTES_TITLE, // ; diff --git a/src/be/nikiroo/jvcard/resources/bundles/DisplayBundle.java b/src/be/nikiroo/jvcard/resources/DisplayBundle.java similarity index 53% rename from src/be/nikiroo/jvcard/resources/bundles/DisplayBundle.java rename to src/be/nikiroo/jvcard/resources/DisplayBundle.java index df34639..7a26071 100644 --- a/src/be/nikiroo/jvcard/resources/bundles/DisplayBundle.java +++ b/src/be/nikiroo/jvcard/resources/DisplayBundle.java @@ -1,12 +1,9 @@ -package be.nikiroo.jvcard.resources.bundles; +package be.nikiroo.jvcard.resources; import java.io.IOException; import java.io.Writer; -import be.nikiroo.jvcard.resources.Bundles; -import be.nikiroo.jvcard.resources.Bundles.Bundle; -import be.nikiroo.jvcard.resources.Bundles.Target; -import be.nikiroo.jvcard.resources.enums.DisplayOption; +import be.nikiroo.utils.resources.Bundle; /** * This class manages the display configuration of the application. @@ -16,7 +13,7 @@ import be.nikiroo.jvcard.resources.enums.DisplayOption; */ public class DisplayBundle extends Bundle { public DisplayBundle() { - new Bundles().super(DisplayOption.class, Target.display); + super(DisplayOption.class, Target.display, null); } @Override diff --git a/src/be/nikiroo/jvcard/resources/enums/DisplayOption.java b/src/be/nikiroo/jvcard/resources/DisplayOption.java similarity index 79% rename from src/be/nikiroo/jvcard/resources/enums/DisplayOption.java rename to src/be/nikiroo/jvcard/resources/DisplayOption.java index 24efa45..a5dc5ed 100644 --- a/src/be/nikiroo/jvcard/resources/enums/DisplayOption.java +++ b/src/be/nikiroo/jvcard/resources/DisplayOption.java @@ -1,21 +1,21 @@ -package be.nikiroo.jvcard.resources.enums; +package be.nikiroo.jvcard.resources; import java.io.IOException; import java.io.Writer; -import be.nikiroo.jvcard.resources.Bundles.Bundle; -import be.nikiroo.jvcard.resources.Meta; +import be.nikiroo.utils.resources.Meta; + public enum DisplayOption { - @Meta(what = "", where = "", format = "coma-separated list of CLF", info = "The format of each line in the contact list") + @Meta( info = "comma-separated list of CLF", description = "The format of each line in the contact list") CONTACT_LIST_FORMAT, // - @Meta(what = "", where = "", format = "CDIF", info = "The list of details to show in View Contact mode") + @Meta( info = "CDIF", description = "The list of details to show in View Contact mode") CONTACT_DETAILS_INFO, // - @Meta(what = "", where = "", format = "Integer or nothing for auto", info = "The size of the details' labels") + @Meta( info = "Integer or nothing for auto", description = "The size of the details' labels") CONTACT_DETAILS_LABEL_WIDTH, // - @Meta(what = "", where = "", format = "CLF", info = "The default value of FN if it is not present") + @Meta( info = "CLF", description = "The default value of FN if it is not present") CONTACT_DETAILS_DEFAULT_FN, // - @Meta(what = "", where = "", format = "TRUE or FALSE", info = "TRUE to force all FNs to be recreated from CONTACT_DETAILS_DEFAULT_FN") + @Meta(info = "TRUE or FALSE", description = "TRUE to force all FNs to be recreated from CONTACT_DETAILS_DEFAULT_FN") CONTACT_DETAILS_SHOW_COMPUTED_FN, // ; diff --git a/src/be/nikiroo/jvcard/resources/FixedResourceBundleControl.java b/src/be/nikiroo/jvcard/resources/FixedResourceBundleControl.java deleted file mode 100644 index 25832a2..0000000 --- a/src/be/nikiroo/jvcard/resources/FixedResourceBundleControl.java +++ /dev/null @@ -1,93 +0,0 @@ -package be.nikiroo.jvcard.resources; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLConnection; -import java.util.Locale; -import java.util.PropertyResourceBundle; -import java.util.ResourceBundle; -import java.util.ResourceBundle.Control; - -/** - * Fixed ResourceBundle.Control class. It will use UTF-8 for the files to load. - * - * Also support an option to first check into the given path before looking into - * the resources. - * - * @author niki - * - */ -class FixedResourceBundleControl extends Control { - private String outsideWorld = null; - - /** - * Create a new {@link FixedResourceBundleControl}. - * - * @param outsideWorld - * NULL if you are only interested into the resources, a path to - * first check into it before looking at the actual resources - */ - public FixedResourceBundleControl(String outsideWorld) { - this.outsideWorld = outsideWorld; - } - - @Override - public ResourceBundle newBundle(String baseName, Locale locale, - String format, ClassLoader loader, boolean reload) - throws IllegalAccessException, InstantiationException, IOException { - // The below is a copy of the default implementation. - String bundleName = toBundleName(baseName, locale); - String resourceName = toResourceName(bundleName, "properties"); - - ResourceBundle bundle = null; - InputStream stream = null; - if (reload) { - URL url = loader.getResource(resourceName); - if (url != null) { - URLConnection connection = url.openConnection(); - if (connection != null) { - connection.setUseCaches(false); - stream = connection.getInputStream(); - } - } - } else { - // New code to support outside resources: - if (outsideWorld != null) { - String pkg = this.getClass().getPackage().getName(); - pkg = pkg.replaceAll("\\.", File.separator) + File.separator; - - if (resourceName.startsWith(pkg)) { - try { - String file = outsideWorld + File.separator - + resourceName.substring(pkg.length()); - stream = new FileInputStream(file); - } catch (Exception e) { - // file not in priority directory, - // fallback to default resource - } - } - } - - if (stream == null) - stream = loader.getResourceAsStream(resourceName); - // - } - if (stream != null) { - try { - // This line is changed to make it to read properties files - // as UTF-8. - // How can someone use an archaic encoding such as ISO 8859-1 by - // *DEFAULT* is beyond me... - bundle = new PropertyResourceBundle(new InputStreamReader( - stream, "UTF-8")); - } finally { - stream.close(); - } - } - return bundle; - } -} \ No newline at end of file diff --git a/src/be/nikiroo/jvcard/resources/Meta.java b/src/be/nikiroo/jvcard/resources/Meta.java deleted file mode 100644 index 769d132..0000000 --- a/src/be/nikiroo/jvcard/resources/Meta.java +++ /dev/null @@ -1,47 +0,0 @@ -package be.nikiroo.jvcard.resources; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation used to give some information about the translation keys, so the - * translation .properties file can be created programmatically. - * - * @author niki - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Meta { - /** - * What kind of item this key represent (a Key, a Label text, a format to - * use for something else...). - * - * @return what it is - */ - String what(); - - /** - * Where in the application will this key appear (in the action keys, in a - * menu, in a message...). - * - * @return where it is - */ - String where(); - - /** - * What format should/must this key be in. - * - * @return the format it is in - */ - String format(); - - /** - * Free info text to help translate. - * - * @return some info - */ - String info(); -} diff --git a/src/be/nikiroo/jvcard/resources/bundles/RemoteBundle.java b/src/be/nikiroo/jvcard/resources/RemoteBundle.java similarity index 53% rename from src/be/nikiroo/jvcard/resources/bundles/RemoteBundle.java rename to src/be/nikiroo/jvcard/resources/RemoteBundle.java index 0d27bf3..7a193ee 100644 --- a/src/be/nikiroo/jvcard/resources/bundles/RemoteBundle.java +++ b/src/be/nikiroo/jvcard/resources/RemoteBundle.java @@ -1,12 +1,9 @@ -package be.nikiroo.jvcard.resources.bundles; +package be.nikiroo.jvcard.resources; import java.io.IOException; import java.io.Writer; -import be.nikiroo.jvcard.resources.Bundles; -import be.nikiroo.jvcard.resources.Bundles.Bundle; -import be.nikiroo.jvcard.resources.Bundles.Target; -import be.nikiroo.jvcard.resources.enums.RemotingOption; +import be.nikiroo.utils.resources.Bundle; /** * This class manages the display configuration of the application. @@ -16,7 +13,7 @@ import be.nikiroo.jvcard.resources.enums.RemotingOption; */ public class RemoteBundle extends Bundle { public RemoteBundle() { - new Bundles().super(RemotingOption.class, Target.remote); + super(RemotingOption.class, Target.remote, null); } @Override diff --git a/src/be/nikiroo/jvcard/resources/enums/RemotingOption.java b/src/be/nikiroo/jvcard/resources/RemotingOption.java similarity index 53% rename from src/be/nikiroo/jvcard/resources/enums/RemotingOption.java rename to src/be/nikiroo/jvcard/resources/RemotingOption.java index f0b274b..b281482 100644 --- a/src/be/nikiroo/jvcard/resources/enums/RemotingOption.java +++ b/src/be/nikiroo/jvcard/resources/RemotingOption.java @@ -1,18 +1,18 @@ -package be.nikiroo.jvcard.resources.enums; +package be.nikiroo.jvcard.resources; import java.io.IOException; import java.io.Writer; -import be.nikiroo.jvcard.resources.Meta; -import be.nikiroo.jvcard.resources.Bundles.Bundle; +import be.nikiroo.utils.resources.Meta; +import be.nikiroo.utils.resources.Meta.Format; public enum RemotingOption { - @Meta(what = "", where = "Server", format = "directory", info = "when starting as a jVCard remote server, where to look for data") + @Meta(format = Format.DIRECTORY, description = "when starting as a jVCard remote server, where to look for data") SERVER_DATA_PATH, // - @Meta(what = "", where = "Client", format = "directory", info = "when loading \"jvcard://\" links, where to save cache files") + @Meta(format = Format.DIRECTORY, description = "when loading \"jvcard://\" links, where to save cache files") CLIENT_CACHE_DIR, // - @Meta(what = "", where = "Client", format = "TRUE or FALSE", info = "Automatically synchronise remote cards") + @Meta(format = Format.BOOLEAN, description = "Automatically synchronise remote cards") CLIENT_AUTO_SYNC, // ; diff --git a/src/be/nikiroo/jvcard/resources/ResourceList.java b/src/be/nikiroo/jvcard/resources/ResourceList.java deleted file mode 100644 index 6f87c93..0000000 --- a/src/be/nikiroo/jvcard/resources/ResourceList.java +++ /dev/null @@ -1,123 +0,0 @@ -package be.nikiroo.jvcard.resources; - -// code copied from from: -// http://forums.devx.com/showthread.php?t=153784, -// via: -// http://stackoverflow.com/questions/3923129/get-a-list-of-resources-from-classpath-directory - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; - -/** - * list resources available from the classpath @ * - */ -public class ResourceList { - - /** - * for all elements of java.class.path get a Collection of resources Pattern - * pattern = Pattern.compile(".*"); gets all resources - * - * @param pattern - * the pattern to match - * @return the resources in the order they are found - */ - public static Collection getResources(final Pattern pattern) { - final ArrayList retval = new ArrayList(); - final String classPath = System.getProperty("java.class.path", "."); - final String[] classPathElements = classPath.split(System - .getProperty("path.separator")); - for (final String element : classPathElements) { - retval.addAll(getResources(element, pattern)); - } - return retval; - } - - private static Collection getResources(final String element, - final Pattern pattern) { - final ArrayList retval = new ArrayList(); - final File file = new File(element); - if (file.isDirectory()) { - retval.addAll(getResourcesFromDirectory(file, pattern)); - } else { - retval.addAll(getResourcesFromJarFile(file, pattern)); - } - return retval; - } - - private static Collection getResourcesFromJarFile(final File file, - final Pattern pattern) { - final ArrayList retval = new ArrayList(); - ZipFile zf; - try { - zf = new ZipFile(file); - } catch (final ZipException e) { - throw new Error(e); - } catch (final IOException e) { - throw new Error(e); - } - final Enumeration e = zf.entries(); - while (e.hasMoreElements()) { - final ZipEntry ze = (ZipEntry) e.nextElement(); - final String fileName = ze.getName(); - final boolean accept = pattern.matcher(fileName).matches(); - if (accept) { - retval.add(fileName); - } - } - try { - zf.close(); - } catch (final IOException e1) { - throw new Error(e1); - } - return retval; - } - - private static Collection getResourcesFromDirectory( - final File directory, final Pattern pattern) { - final ArrayList retval = new ArrayList(); - final File[] fileList = directory.listFiles(); - for (final File file : fileList) { - if (file.isDirectory()) { - retval.addAll(getResourcesFromDirectory(file, pattern)); - } else { - try { - final String fileName = file.getCanonicalPath(); - final boolean accept = pattern.matcher(fileName).matches(); - if (accept) { - retval.add(fileName); - } - } catch (final IOException e) { - throw new Error(e); - } - } - } - return retval; - } - - /** - * list the resources that match args[0] - * - * @param args - * args[0] is the pattern to match, or list all resources if - * there are no args - */ - public static void main(final String[] args) { - Pattern pattern; - if (args.length < 1) { - pattern = Pattern.compile(".*"); - } else { - pattern = Pattern.compile(args[0]); - } - final Collection list = ResourceList.getResources(pattern); - for (final String name : list) { - System.out.println(name); - } - } -} diff --git a/src/be/nikiroo/jvcard/resources/StringId.java b/src/be/nikiroo/jvcard/resources/StringId.java new file mode 100644 index 0000000..fbbb158 --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/StringId.java @@ -0,0 +1,128 @@ +package be.nikiroo.jvcard.resources; + +import be.nikiroo.utils.resources.Meta; + + +/** + * The enum representing textual information to be translated to the user as a + * key. + * + * Note that each key that should be translated MUST be annotated with a + * {@link Meta} annotation. + * + * @author niki + * + */ +public enum StringId { + DUMMY, // <-- TODO : remove + NULL, // Special usage, no annotations so it is not visible in + // .properties files + @Meta( info = "MUST BE 3 chars long", description = "Tab key") + KEY_TAB, // keys + @Meta( info = "MUST BE 3 chars long", description = "Enter key") + KEY_ENTER, // + @Meta( description = "Go back to previous screen") + KEY_ACTION_BACK, // + @Meta( description = "Get help text") + KEY_ACTION_HELP, // + @Meta( description = "View the selected card") + KEY_ACTION_VIEW_CARD, // + @Meta( description = "View the selected contact") + KEY_ACTION_VIEW_CONTACT, // + @Meta( description = "Edit the contact") + KEY_ACTION_EDIT_CONTACT, // + @Meta( description = "Edit the contact in RAW mode") + KEY_ACTION_EDIT_CONTACT_RAW, // + @Meta( description = "Edit the RAW field") + KEY_ACTION_EDIT_FIELD, // + @Meta( description = "Save the whole card") + KEY_ACTION_SAVE_CARD, // + @Meta( description = "Delete the selected element") + KEY_ACTION_DELETE, // + @Meta( description = "Filter the displayed contacts") + KEY_ACTION_SEARCH, // + @Meta( info = "we could use: ' ', ┃, │...", description = "Field separator") + DEAULT_FIELD_SEPARATOR, // MainContentList + @Meta( description = "Invert the photo's colours") + KEY_ACTION_INVERT, // + @Meta( description = "Show the photo in 'fullscreen'") + KEY_ACTION_FULLSCREEN, // + @Meta( description = "Switch between the available display formats") + KEY_ACTION_SWITCH_FORMAT, // multi-usage + @Meta( description = "Add a new contact/field") + KEY_ACTION_ADD, // + @Meta( description = "New contact") + ASK_USER_CONTACT_NAME, // + @Meta( info = "%s = contact name", description = "Delete contact") + CONFIRM_USER_DELETE_CONTACT, // + @Meta( info = "%s = contact name", description = "cannot delete a contact") + ERR_CANNOT_DELETE_CONTACT, // + @Meta( description = "The Help message header line") + CLI_HELP, // + @Meta( description = "The Help message line before explaining the different modes") + CLI_HELP_MODES, // + @Meta( description = "The Help message line for help usage") + CLI_HELP_MODE_HELP, // + @Meta( description = "The Help message line for contact manager usage") + CLI_HELP_MODE_CONTACT_MANAGER, // + @Meta( description = "The Help message line for contact manager usage") + CLI_HELP_MODE_I18N, // + @Meta( description = "The Help message line for jVCard server usage") + CLI_HELP_MODE_SERVER, // + @Meta( description = "The Help message line for --load-photo usage") + CLI_HELP_MODE_LOAD_PHOTO, // + @Meta( description = "The Help message line for --save-photo usage") + CLI_HELP_MODE_SAVE_PHOTO, // + @Meta( description = "The Help message line for config save usage") + CLI_HELP_MODE_SAVE_CONFIG, // + @Meta( description = "The Help message line before the list of options") + CLI_HELP_OPTIONS, // + @Meta( description = "The Help message line for: --") + CLI_HELP_DD, // + @Meta( description = "The Help message line for: --") + CLI_HELP_LANG, // + @Meta( description = "The Help message line for: --") + CLI_HELP_GUI, // + @Meta( description = "The Help message line for: --") + CLI_HELP_TUI, // + @Meta( description = "The Help message line for: --") + CLI_HELP_NOUTF_OPTION, // + @Meta( description = "The Help message line for: --") + CLI_HELP_CONFIG, // + @Meta( description = "The Help message footer about files and jvcard:// links") + CLI_HELP_FOOTER, // + @Meta( info = "%s = the error", description = "Syntax error: SOME TEXT") + CLI_SERR, // + @Meta( description = "More than one mode given") + CLI_SERR_MODES, // + @Meta( description = "--lang is required") + CLI_SERR_NOLANG, // + @Meta( description = "The dir is required") + CLI_SERR_NODIR, // + @Meta( description = "The port is required") + CLI_SERR_NOPORT, // + @Meta( description = "The format is required") + CLI_SERR_NOFORMAT, // + @Meta( info = "%s = bad port", description = "The port is not valid") + CLI_SERR_BADPORT, // + @Meta( info = "%s = mode", description = "Card files are not supported in mode %s") + CLI_SERR_CANNOT_CARDS, // + @Meta( info = "%s = the error", description = "Error: SOME TEXT") + CLI_ERR, // + @Meta( description = "No files given") + CLI_ERR_NOFILES, // + @Meta( info = "%s = dir", description = "Cannot create conf dir %s") + CLI_ERR_CANNOT_CREATE_CONFDIR, // + @Meta( description = "Remoting not available") + CLI_ERR_NO_REMOTING, // + @Meta( description = "TUI not available") + CLI_ERR_NO_TUI, // + @Meta( info = "%s = dir", description = "Cannot create/update language in dir %s") + CLI_ERR_CANNOT_CREATE_LANG, // + @Meta( info = "%s = card", description = "Cannot open card %s") + CLI_ERR_CANNOT_OPEN, // + @Meta(info = "%s = contact FN", description = "Cannot save photo of contact %s") + CLI_ERR_CANNOT_SAVE_PHOTO, // + @Meta( description = "Cannot start the program with the given cards") + CLI_ERR_CANNOT_START, // +}; diff --git a/src/be/nikiroo/jvcard/resources/StringUtils.java b/src/be/nikiroo/jvcard/resources/StringUtils.java deleted file mode 100644 index a838af9..0000000 --- a/src/be/nikiroo/jvcard/resources/StringUtils.java +++ /dev/null @@ -1,512 +0,0 @@ -package be.nikiroo.jvcard.resources; - -import java.awt.Image; -import java.awt.geom.AffineTransform; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.text.Normalizer; -import java.text.Normalizer.Form; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.regex.Pattern; - -import javax.imageio.ImageIO; -import javax.xml.bind.DatatypeConverter; - -import com.googlecode.lanterna.gui2.LinearLayout.Alignment; - -public class StringUtils { - static private Pattern marks = Pattern - .compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+"); - - /** - * Fix the size of the given {@link String} either with space-padding or by - * shortening it. - * - * @param text - * the {@link String} to fix - * @param width - * the size of the resulting {@link String} or -1 for a noop - * - * @return the resulting {@link String} of size size - */ - static public String padString(String text, int width) { - return padString(text, width, true, Alignment.Beginning); - } - - /** - * Fix the size of the given {@link String} either with space-padding or by - * optionally shortening it. - * - * @param text - * the {@link String} to fix - * @param width - * the size of the resulting {@link String} if the text fits or - * if cut is TRUE or -1 for a noop - * @param cut - * cut the {@link String} shorter if needed - * @param align - * align the {@link String} in this position if we have enough - * space - * - * @return the resulting {@link String} of size size minimum - */ - static public String padString(String text, int width, boolean cut, - Alignment align) { - - if (width >= 0) { - if (text == null) - text = ""; - - int diff = width - text.length(); - - if (diff < 0) { - if (cut) - text = text.substring(0, width); - } else if (diff > 0) { - if (diff < 2 && align != Alignment.End) - align = Alignment.Beginning; - - switch (align) { - case Beginning: - text = text + new String(new char[diff]).replace('\0', ' '); - break; - case End: - text = new String(new char[diff]).replace('\0', ' ') + text; - break; - case Center: - case Fill: - default: - int pad1 = (diff) / 2; - int pad2 = (diff + 1) / 2; - text = new String(new char[pad1]).replace('\0', ' ') + text - + new String(new char[pad2]).replace('\0', ' '); - break; - } - } - } - - return text; - } - - /** - * Sanitise the given input to make it more Terminal-friendly by removing - * combining characters. - * - * @param input - * the input to sanitise - * @param allowUnicode - * allow Unicode or only allow ASCII Latin characters - * - * @return the sanitised {@link String} - */ - static public String sanitize(String input, boolean allowUnicode) { - return sanitize(input, allowUnicode, !allowUnicode); - } - - /** - * Sanitise the given input to make it more Terminal-friendly by removing - * combining characters. - * - * @param input - * the input to sanitise - * @param allowUnicode - * allow Unicode or only allow ASCII Latin characters - * @param removeAllAccents - * TRUE to replace all accentuated characters by their non - * accentuated counter-parts - * - * @return the sanitised {@link String} - */ - static public String sanitize(String input, boolean allowUnicode, - boolean removeAllAccents) { - - if (removeAllAccents) { - input = Normalizer.normalize(input, Form.NFKD); - input = marks.matcher(input).replaceAll(""); - } - - input = Normalizer.normalize(input, Form.NFKC); - - if (!allowUnicode) { - StringBuilder builder = new StringBuilder(); - for (int index = 0; index < input.length(); index++) { - char car = input.charAt(index); - // displayable chars in ASCII are in the range 32<->255, - // except DEL (127) - if (car >= 32 && car <= 255 && car != 127) { - builder.append(car); - } - } - input = builder.toString(); - } - - return input; - } - - /** - * Convert between time in milliseconds to {@link String} in a "static" way - * (to exchange data over the wire, for instance). - * - * @param time - * the time in milliseconds - * - * @return the time as a {@link String} - */ - static public String fromTime(long time) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - return sdf.format(new Date(time)); - } - - /** - * Convert between time as a {@link String} to milliseconds in a "static" - * way (to exchange data over the wire, for instance). - * - * @param time - * the time as a {@link String} - * - * @return the time in milliseconds - */ - static public long toTime(String display) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - try { - return sdf.parse(display).getTime(); - } catch (ParseException e) { - return -1; - } - } - - /** - * Convert the given {@link Image} object into a Base64 representation of - * the same {@link Image}. object. - * - * @param image - * the {@link Image} object to convert - * - * @return the Base64 representation - * - * @throws IOException - * in case of IO error - */ - static public String fromImage(BufferedImage image) throws IOException { - String imageString = null; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - ImageIO.write(image, "jpeg", out); - byte[] imageBytes = out.toByteArray(); - - imageString = DatatypeConverter.printBase64Binary(imageBytes); - - out.close(); - - return imageString; - } - - /** - * Convert the given {@link File} image into a Base64 representation of the - * same {@link File}. - * - * @param file - * the {@link File} image to convert - * - * @return the Base64 representation - * - * @throws IOException - * in case of IO error - */ - static public String fromImage(File file) throws IOException { - String fileString = null; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - byte[] buf = new byte[8192]; - InputStream in = new FileInputStream(file); - - int c = 0; - while ((c = in.read(buf, 0, buf.length)) > 0) { - out.write(buf, 0, c); - } - out.flush(); - in.close(); - - fileString = DatatypeConverter.printBase64Binary(out.toByteArray()); - out.close(); - - return fileString; - } - - /** - * Convert the given Base64 representation of an image into an {@link Image} - * object. - * - * @param b64data - * the {@link Image} in Base64 format - * - * @return the {@link Image} object - * - * @throws IOException - * in case of IO error - */ - static public BufferedImage toImage(String b64data) throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream( - DatatypeConverter.parseBase64Binary(b64data)); - - int orientation; - try { - orientation = getExifTransorm(in); - } catch (Exception e) { - // no EXIF transform, ok - orientation = -1; - } - - in.reset(); - BufferedImage image = ImageIO.read(in); - - // Note: this code has been found on internet; - // thank you anonymous coder. - int width = image.getWidth(); - int height = image.getHeight(); - AffineTransform affineTransform = new AffineTransform(); - - switch (orientation) { - case 1: - break; - case 2: // Flip X - affineTransform.scale(-1.0, 1.0); - affineTransform.translate(-width, 0); - break; - case 3: // PI rotation - affineTransform.translate(width, height); - affineTransform.rotate(Math.PI); - break; - case 4: // Flip Y - affineTransform.scale(1.0, -1.0); - affineTransform.translate(0, -height); - break; - case 5: // - PI/2 and Flip X - affineTransform.rotate(-Math.PI / 2); - affineTransform.scale(-1.0, 1.0); - break; - case 6: // -PI/2 and -width - affineTransform.translate(height, 0); - affineTransform.rotate(Math.PI / 2); - break; - case 7: // PI/2 and Flip - affineTransform.scale(-1.0, 1.0); - affineTransform.translate(-height, 0); - affineTransform.translate(0, width); - affineTransform.rotate(3 * Math.PI / 2); - break; - case 8: // PI / 2 - affineTransform.translate(0, width); - affineTransform.rotate(3 * Math.PI / 2); - break; - default: - affineTransform = null; - break; - } - - if (affineTransform != null) { - AffineTransformOp affineTransformOp = new AffineTransformOp( - affineTransform, AffineTransformOp.TYPE_BILINEAR); - - BufferedImage transformedImage = new BufferedImage(height, width, - image.getType()); - transformedImage = affineTransformOp - .filter(image, transformedImage); - - image = transformedImage; - } - // - - return image; - } - - /** - * Return a hash of the given {@link String}. - * - * @param input - * the input data - * - * @return the hash - */ - static public String getHash(String input) { - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(input.getBytes()); - byte byteData[] = md.digest(); - - StringBuffer hexString = new StringBuffer(); - for (int i = 0; i < byteData.length; i++) { - String hex = Integer.toHexString(0xff & byteData[i]); - if (hex.length() == 1) - hexString.append('0'); - hexString.append(hex); - } - - return hexString.toString(); - } catch (NoSuchAlgorithmException e) { - // all JVM most probably have an MD5 implementation, but even if - // not, returning the input is "correct", if inefficient and - // unsecure - return input; - } - } - - /** - * Return the EXIF transformation flag of this image if any. - * - *

- * Note: this code has been found on internet; thank you anonymous coder. - *

- * - * @param in - * the data {@link InputStream} - * - * @return the transformation flag if any - * - * @throws IOException - * in case of IO error - */ - static private int getExifTransorm(InputStream in) throws IOException { - int[] exif_data = new int[100]; - int set_flag = 0; - int is_motorola = 0; - - /* Read File head, check for JPEG SOI + Exif APP1 */ - for (int i = 0; i < 4; i++) - exif_data[i] = in.read(); - - if (exif_data[0] != 0xFF || exif_data[1] != 0xD8 - || exif_data[2] != 0xFF || exif_data[3] != 0xE1) - return -2; - - /* Get the marker parameter length count */ - int length = (in.read() << 8 | in.read()); - - /* Length includes itself, so must be at least 2 */ - /* Following Exif data length must be at least 6 */ - if (length < 8) - return -1; - length -= 8; - /* Read Exif head, check for "Exif" */ - for (int i = 0; i < 6; i++) - exif_data[i] = in.read(); - - if (exif_data[0] != 0x45 || exif_data[1] != 0x78 - || exif_data[2] != 0x69 || exif_data[3] != 0x66 - || exif_data[4] != 0 || exif_data[5] != 0) - return -1; - - /* Read Exif body */ - length = length > exif_data.length ? exif_data.length : length; - for (int i = 0; i < length; i++) - exif_data[i] = in.read(); - - if (length < 12) - return -1; /* Length of an IFD entry */ - - /* Discover byte order */ - if (exif_data[0] == 0x49 && exif_data[1] == 0x49) - is_motorola = 0; - else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D) - is_motorola = 1; - else - return -1; - - /* Check Tag Mark */ - if (is_motorola == 1) { - if (exif_data[2] != 0) - return -1; - if (exif_data[3] != 0x2A) - return -1; - } else { - if (exif_data[3] != 0) - return -1; - if (exif_data[2] != 0x2A) - return -1; - } - - /* Get first IFD offset (offset to IFD0) */ - int offset; - if (is_motorola == 1) { - if (exif_data[4] != 0) - return -1; - if (exif_data[5] != 0) - return -1; - offset = exif_data[6]; - offset <<= 8; - offset += exif_data[7]; - } else { - if (exif_data[7] != 0) - return -1; - if (exif_data[6] != 0) - return -1; - offset = exif_data[5]; - offset <<= 8; - offset += exif_data[4]; - } - if (offset > length - 2) - return -1; /* check end of data segment */ - - /* Get the number of directory entries contained in this IFD */ - int number_of_tags; - if (is_motorola == 1) { - number_of_tags = exif_data[offset]; - number_of_tags <<= 8; - number_of_tags += exif_data[offset + 1]; - } else { - number_of_tags = exif_data[offset + 1]; - number_of_tags <<= 8; - number_of_tags += exif_data[offset]; - } - if (number_of_tags == 0) - return -1; - offset += 2; - - /* Search for Orientation Tag in IFD0 */ - for (;;) { - if (offset > length - 12) - return -1; /* check end of data segment */ - /* Get Tag number */ - int tagnum; - if (is_motorola == 1) { - tagnum = exif_data[offset]; - tagnum <<= 8; - tagnum += exif_data[offset + 1]; - } else { - tagnum = exif_data[offset + 1]; - tagnum <<= 8; - tagnum += exif_data[offset]; - } - if (tagnum == 0x0112) - break; /* found Orientation Tag */ - if (--number_of_tags == 0) - return -1; - offset += 12; - } - - /* Get the Orientation value */ - if (is_motorola == 1) { - if (exif_data[offset + 8] != 0) - return -1; - set_flag = exif_data[offset + 9]; - } else { - if (exif_data[offset + 9] != 0) - return -1; - set_flag = exif_data[offset + 8]; - } - if (set_flag > 8) - return -1; - - return set_flag; - } -} diff --git a/src/be/nikiroo/jvcard/resources/Target.java b/src/be/nikiroo/jvcard/resources/Target.java new file mode 100644 index 0000000..ebde93f --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/Target.java @@ -0,0 +1,12 @@ +package be.nikiroo.jvcard.resources; + +/** + * The type of configuration information the associated {@link Bundle} will + * convey. + * + * @author niki + * + */ +public enum Target { + colors, display, jvcard, remote, resources +} \ No newline at end of file diff --git a/src/be/nikiroo/jvcard/resources/TransBundle.java b/src/be/nikiroo/jvcard/resources/TransBundle.java new file mode 100644 index 0000000..6a875ac --- /dev/null +++ b/src/be/nikiroo/jvcard/resources/TransBundle.java @@ -0,0 +1,31 @@ +package be.nikiroo.jvcard.resources; + + +/** + * This class manages the translation of {@link TransBundle.StringId}s into + * user-understandable text. + * + * @author niki + * + */ +public class TransBundle extends + be.nikiroo.utils.resources.TransBundle { + + /** + * Create a translation service with the default language. + */ + public TransBundle() { + super(StringId.class, Target.resources); + } + + /** + * Create a translation service for the given language. (Will fall back to + * the default one i not found.) + * + * @param language + * the language to use + */ + public TransBundle(String language) { + super(StringId.class, Target.resources, language); + } +} diff --git a/src/be/nikiroo/jvcard/resources/bundles/ColorBundle.java b/src/be/nikiroo/jvcard/resources/bundles/ColorBundle.java deleted file mode 100644 index 25accfe..0000000 --- a/src/be/nikiroo/jvcard/resources/bundles/ColorBundle.java +++ /dev/null @@ -1,43 +0,0 @@ -package be.nikiroo.jvcard.resources.bundles; - -import java.io.IOException; -import java.io.Writer; - -import be.nikiroo.jvcard.resources.Bundles; -import be.nikiroo.jvcard.resources.Bundles.Bundle; -import be.nikiroo.jvcard.resources.Bundles.Target; -import be.nikiroo.jvcard.resources.enums.ColorOption; - -/** - * All colour information must come from here. - * - * @author niki - * - */ -public class ColorBundle extends Bundle { - public ColorBundle() { - new Bundles().super(ColorOption.class, Target.colors); - } - - @Override - protected void writeHeader(Writer writer) throws IOException { - ColorOption.writeHeader(writer); - } - - @Override - protected void writeValue(Writer writer, ColorOption id) throws IOException { - String name = id.name() + "_FG"; - String value = ""; - if (map.containsKey(name)) - value = map.getString(name).trim(); - - writeValue(writer, name, value); - - name = id.name() + "_BG"; - value = ""; - if (map.containsKey(name)) - value = map.getString(name).trim(); - - writeValue(writer, name, value); - } -} diff --git a/src/be/nikiroo/jvcard/resources/bundles/TransBundle.java b/src/be/nikiroo/jvcard/resources/bundles/TransBundle.java deleted file mode 100644 index 5acd704..0000000 --- a/src/be/nikiroo/jvcard/resources/bundles/TransBundle.java +++ /dev/null @@ -1,230 +0,0 @@ -package be.nikiroo.jvcard.resources.bundles; - -import java.io.File; -import java.io.IOException; -import java.io.Writer; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.regex.Pattern; - -import be.nikiroo.jvcard.resources.Bundles; -import be.nikiroo.jvcard.resources.Bundles.Bundle; -import be.nikiroo.jvcard.resources.Bundles.Target; -import be.nikiroo.jvcard.resources.ResourceList; -import be.nikiroo.jvcard.resources.enums.StringId; - -/** - * This class manages the translation of {@link TransBundle.StringId}s into - * user-understandable text. - * - * @author niki - * - */ -public class TransBundle extends Bundle { - private boolean utf = true; - private Locale locale; - private boolean defaultLocale = false; - - /** - * Create a translation service with the default language. - */ - public TransBundle() { - new Bundles().super(StringId.class, Target.resources); - setLanguage(null); - } - - /** - * Create a translation service for the given language. (Will fall back to - * the default one i not found.) - * - * @param language - * the language to use - */ - public TransBundle(String language) { - new Bundles().super(StringId.class, Target.resources); - - setLanguage(language); - } - - /** - * Translate the given {@link StringId} into user text. - * - * @param stringId - * the ID to translate - * @param values - * the values to insert instead of the place holders in the - * translation - * - * @return the translated text with the given value where required - */ - public String getString(StringId stringId, Object... values) { - StringId id = stringId; - String result = ""; - - if (!isUnicode()) { - try { - id = StringId.valueOf(stringId.name() + "_NOUTF"); - } catch (IllegalArgumentException iae) { - // no special _NOUTF version found - } - } - - if (id == StringId.NULL) { - result = ""; - } else if (id == StringId.DUMMY) { - result = "[dummy]"; - } else if (map.containsKey(id.name())) { - result = map.getString(id.name()); - } else { - result = id.toString(); - } - - if (values != null && values.length > 0) - return String.format(locale, result, values); - else - return result; - } - - /** - * Check if unicode characters should be used. - * - * @return TRUE to allow unicode - */ - public boolean isUnicode() { - return utf; - } - - /** - * Allow or disallow unicode characters in the program. - * - * @param utf - * TRUE to allow unuciode, FALSE to only allow ASCII characters - */ - public void setUnicode(boolean utf) { - this.utf = utf; - } - - /** - * Initialise the translation mappings for the given language. - * - * @param language - * the language to initialise, in the form "en-GB" or "fr" for - * instance - */ - private void setLanguage(String language) { - defaultLocale = (language == null || language.length() == 0); - locale = getLocaleFor(language); - map = getBundle(Target.resources, locale); - } - - @Override - public String getString(StringId id) { - return getString(id, (Object[]) null); - } - - @Override - protected File getUpdateFile(String path) { - String code = locale.toString(); - File file = null; - if (!defaultLocale && code.length() > 0) { - file = new File(path, name.name() + "_" + code + ".properties"); - } else { - // Default properties file: - file = new File(path, name.name() + ".properties"); - } - - return file; - } - - @Override - protected void writeHeader(Writer writer) throws IOException { - String code = locale.toString(); - String name = locale.getDisplayCountry(locale); - - if (name.length() == 0) - name = locale.getDisplayLanguage(locale); - if (name.length() == 0) - name = "default"; - - if (code.length() > 0) { - name = name + " (" + code + ")"; - } - - StringId.writeHeader(writer, name); - } - - @Override - protected void writeValue(Writer writer, StringId id) throws IOException { - super.writeValue(writer, id); - - String name = id.name() + "_NOUTF"; - if (map.containsKey(name)) { - String value = map.getString(name).trim(); - writeValue(writer, name, value); - } - } - - /** - * Return the {@link Locale} representing the given language. - * - * @param language - * the language to initialise, in the form "en-GB" or "fr" for - * instance - * - * @return the corresponding {@link Locale} or the default {@link Locale} if - * it is not known - */ - static private Locale getLocaleFor(String language) { - Locale locale; - - if (language == null) { - locale = Locale.getDefault(); - } else { - language = language.replaceAll("_", "-"); - String lang = language; - String country = null; - if (language.contains("-")) { - lang = language.split("-")[0]; - country = language.split("-")[1]; - } - - if (country != null) - locale = new Locale(lang, country); - else - locale = new Locale(lang); - } - - return locale; - } - - /** - * Return all the languages known by the program. - * - * @return the known language codes - */ - static public List getKnownLanguages() { - List resources = new LinkedList(); - - String regex = ".*" + Target.resources.name() - + "[_a-zA-Za]*\\.properties$"; - - for (String res : ResourceList.getResources(Pattern.compile(regex))) { - String resource = res; - int index = resource.lastIndexOf('/'); - if (index >= 0 && index < (resource.length() - 1)) - resource = resource.substring(index + 1); - if (resource.startsWith(Target.resources.name())) { - resource = resource.substring(0, resource.length() - - ".properties".length()); - resource = resource.substring(Target.resources.name().length()); - if (resource.startsWith("_")) { - resource = resource.substring(1); - resources.add(resource); - } - } - } - - return resources; - } -} diff --git a/src/be/nikiroo/jvcard/resources/display.properties b/src/be/nikiroo/jvcard/resources/display.properties index eb7408d..d23688e 100644 --- a/src/be/nikiroo/jvcard/resources/display.properties +++ b/src/be/nikiroo/jvcard/resources/display.properties @@ -35,7 +35,7 @@ # -# (FORMAT: coma-separated list of CLF) +# (FORMAT: comma-separated list of CLF) # The format of each line in the contact list CONTACT_LIST_FORMAT = NICKNAME@10|FN@+|EMAIL@30|PHOTO@x,N@[0]@20|N@[1]@+|EMAIL@40 # (FORMAT: CDIF) diff --git a/src/be/nikiroo/jvcard/resources/enums/StringId.java b/src/be/nikiroo/jvcard/resources/enums/StringId.java deleted file mode 100644 index ced8bfc..0000000 --- a/src/be/nikiroo/jvcard/resources/enums/StringId.java +++ /dev/null @@ -1,156 +0,0 @@ -package be.nikiroo.jvcard.resources.enums; - -import java.io.IOException; -import java.io.Writer; - -import be.nikiroo.jvcard.resources.Bundles.Bundle; -import be.nikiroo.jvcard.resources.Meta; - -/** - * The enum representing textual information to be translated to the user as a - * key. - * - * Note that each key that should be translated MUST be annotated with a - * {@link Meta} annotation. - * - * @author niki - * - */ -public enum StringId { - DUMMY, // <-- TODO : remove - NULL, // Special usage, no annotations so it is not visible in - // .properties files - @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Tab key") - KEY_TAB, // keys - @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Enter key") - KEY_ENTER, // - @Meta(what = "Action key", where = "All screens except the first (KEY_ACTION_QUIT)", format = "", info = "Go back to previous screen") - KEY_ACTION_BACK, // - @Meta(what = "Action key", where = "MainWindow", format = "", info = "Get help text") - KEY_ACTION_HELP, // - @Meta(what = "Action key", where = "FileList", format = "", info = "View the selected card") - KEY_ACTION_VIEW_CARD, // - @Meta(what = "Action key", where = "ContactList", format = "", info = "View the selected contact") - KEY_ACTION_VIEW_CONTACT, // - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Edit the contact") - KEY_ACTION_EDIT_CONTACT, // - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Edit the contact in RAW mode") - KEY_ACTION_EDIT_CONTACT_RAW, // - @Meta(what = "Action key", where = "ContactDetailsRaw", format = "", info = "Edit the RAW field") - KEY_ACTION_EDIT_FIELD, // - @Meta(what = "Action key", where = "ContactList", format = "", info = "Save the whole card") - KEY_ACTION_SAVE_CARD, // - @Meta(what = "", where = "ContactList/ContactDetailsRaw", format = "", info = "Delete the selected element") - KEY_ACTION_DELETE, // - @Meta(what = "Action key", where = "ContactList", format = "", info = "Filter the displayed contacts") - KEY_ACTION_SEARCH, // - @Meta(what = "", where = "", format = "we could use: ' ', ┃, │...", info = "Field separator") - DEAULT_FIELD_SEPARATOR, // MainContentList - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Invert the photo's colours") - KEY_ACTION_INVERT, // - @Meta(what = "Action key", where = "ContactDetails", format = "", info = "Show the photo in 'fullscreen'") - KEY_ACTION_FULLSCREEN, // - @Meta(what = "Action key", where = "ContactList, ContactDetails, ContactDetailsRaw", format = "", info = "Switch between the available display formats") - KEY_ACTION_SWITCH_FORMAT, // multi-usage - @Meta(what = "Action key", where = "Contact list, Edit Contact", format = "", info = "Add a new contact/field") - KEY_ACTION_ADD, // - @Meta(what = "User question: TEXT", where = "Contact list", format = "", info = "New contact") - ASK_USER_CONTACT_NAME, // - @Meta(what = "User question: [Y|N]", where = "Contact list", format = "%s = contact name", info = "Delete contact") - CONFIRM_USER_DELETE_CONTACT, // - @Meta(what = "Error", where = "Contact list", format = "%s = contact name", info = "cannot delete a contact") - ERR_CANNOT_DELETE_CONTACT, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message header line") - CLI_HELP, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line before explaining the different modes") - CLI_HELP_MODES, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for help usage") - CLI_HELP_MODE_HELP, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for contact manager usage") - CLI_HELP_MODE_CONTACT_MANAGER, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for contact manager usage") - CLI_HELP_MODE_I18N, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for jVCard server usage") - CLI_HELP_MODE_SERVER, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for --load-photo usage") - CLI_HELP_MODE_LOAD_PHOTO, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for --save-photo usage") - CLI_HELP_MODE_SAVE_PHOTO, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for config save usage") - CLI_HELP_MODE_SAVE_CONFIG, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line before the list of options") - CLI_HELP_OPTIONS, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for: --") - CLI_HELP_DD, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for: --") - CLI_HELP_LANG, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for: --") - CLI_HELP_GUI, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for: --") - CLI_HELP_TUI, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for: --") - CLI_HELP_NOUTF_OPTION, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message line for: --") - CLI_HELP_CONFIG, // - @Meta(what = "CLI --help", where = "", format = "", info = "The Help message footer about files and jvcard:// links") - CLI_HELP_FOOTER, // - @Meta(what = "CLI ERROR", where = "", format = "%s = the error", info = "Syntax error: SOME TEXT") - CLI_SERR, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "More than one mode given") - CLI_SERR_MODES, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "--lang is required") - CLI_SERR_NOLANG, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "The dir is required") - CLI_SERR_NODIR, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "The port is required") - CLI_SERR_NOPORT, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "The format is required") - CLI_SERR_NOFORMAT, // - @Meta(what = "CLI ERROR", where = "", format = "%s = bad port", info = "The port is not valid") - CLI_SERR_BADPORT, // - @Meta(what = "CLI ERROR", where = "", format = "%s = mode", info = "Card files are not supported in mode %s") - CLI_SERR_CANNOT_CARDS, // - @Meta(what = "CLI ERROR", where = "", format = "%s = the error", info = "Error: SOME TEXT") - CLI_ERR, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "No files given") - CLI_ERR_NOFILES, // - @Meta(what = "CLI ERROR", where = "", format = "%s = dir", info = "Cannot create conf dir %s") - CLI_ERR_CANNOT_CREATE_CONFDIR, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "Remoting not available") - CLI_ERR_NO_REMOTING, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "TUI not available") - CLI_ERR_NO_TUI, // - @Meta(what = "CLI ERROR", where = "", format = "%s = dir", info = "Cannot create/update language in dir %s") - CLI_ERR_CANNOT_CREATE_LANG, // - @Meta(what = "CLI ERROR", where = "", format = "%s = card", info = "Cannot open card %s") - CLI_ERR_CANNOT_OPEN, // - @Meta(what = "CLI ERROR", where = "", format = "%s = contact FN", info = "Cannot save photo of contact %s") - CLI_ERR_CANNOT_SAVE_PHOTO, // - @Meta(what = "CLI ERROR", where = "", format = "", info = "Cannot start the program with the given cards") - CLI_ERR_CANNOT_START, // - - ; - - /** - * Write the header found in the configuration .properties file of - * this {@link Bundle}. - * - * @param writer - * the {@link Writer} to write the header in - * @param name - * the file name - * - * @throws IOException - * in case of IO error - */ - static public void writeHeader(Writer writer, String name) - throws IOException { - writer.write("# " + name + " translation file (UTF-8)\n"); - writer.write("# \n"); - writer.write("# Note that any key can be doubled with a _NOUTF suffix\n"); - writer.write("# to use when the flag --noutf is passed\n"); - writer.write("# \n"); - writer.write("# Also, the comments always refer to the key below them.\n"); - writer.write("# \n"); - } -}; diff --git a/src/be/nikiroo/jvcard/tui/ImageText.java b/src/be/nikiroo/jvcard/tui/ImageText.java deleted file mode 100644 index 5945b82..0000000 --- a/src/be/nikiroo/jvcard/tui/ImageText.java +++ /dev/null @@ -1,483 +0,0 @@ -package be.nikiroo.jvcard.tui; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.awt.image.ImageObserver; - -import com.googlecode.lanterna.TerminalSize; - -/** - * This class converts an {@link Image} into a textual representation that can - * be displayed to the user in a TUI. - * - * @author niki - * - */ -public class ImageText { - private Image image; - private TerminalSize size; - private String text; - private boolean ready; - private Mode mode; - private boolean invert; - - /** - * Th rendering modes supported by this {@link ImageText} to convert - * {@link Image}s into text. - * - * @author niki - * - */ - public enum Mode { - /** - * Use 5 different "colours" which are actually Unicode - * {@link Character}s representing - *
    - *
  • space (blank)
  • - *
  • low shade (░)
  • - *
  • medium shade (▒)
  • - *
  • high shade (▓)
  • - *
  • full block (█)
  • - *
- */ - DITHERING, - /** - * Use "block" Unicode {@link Character}s up to quarter blocks, thus in - * effect doubling the resolution both in vertical and horizontal space. - * Note that since 2 {@link Character}s next to each other are square, - * we will use 4 blocks per 2 blocks for w/h resolution. - */ - DOUBLE_RESOLUTION, - /** - * Use {@link Character}s from both {@link Mode#DOUBLE_RESOLUTION} and - * {@link Mode#DITHERING}. - */ - DOUBLE_DITHERING, - /** - * Only use ASCII {@link Character}s. - */ - ASCII, - } - - /** - * Create a new {@link ImageText} with the given parameters. Defaults to - * {@link Mode#DOUBLE_DITHERING} and no colour inversion. - * - * @param image - * the source {@link Image} - * @param size - * the final text size to target - */ - public ImageText(Image image, TerminalSize size) { - this(image, size, Mode.DOUBLE_DITHERING, false); - } - - /** - * Create a new {@link ImageText} with the given parameters. - * - * @param image - * the source {@link Image} - * @param size - * the final text size to target - * @param mode - * the mode of conversion - * @param invert - * TRUE to invert colours rendering - */ - public ImageText(Image image, TerminalSize size, Mode mode, boolean invert) { - setImage(image); - setSize(size); - setMode(mode); - setColorInvert(invert); - } - - /** - * Change the source {@link Image}. - * - * @param image - * the new {@link Image} - */ - public void setImage(Image image) { - this.text = null; - this.ready = false; - this.image = image; - } - - /** - * Change the target size of this {@link ImageText}. - * - * @param size - * the new size - */ - public void setSize(TerminalSize size) { - this.text = null; - this.ready = false; - this.size = size; - } - - /** - * Change the image-to-text mode. - * - * @param mode - * the new {@link Mode} - */ - public void setMode(Mode mode) { - this.mode = mode; - this.text = null; - this.ready = false; - } - - /** - * Set the colour-invert mode. - * - * @param invert - * TRUE to inverse the colours - */ - public void setColorInvert(boolean invert) { - this.invert = invert; - this.text = null; - this.ready = false; - } - - /** - * Check if the colours are inverted. - * - * @return TRUE if the colours are inverted - */ - public boolean isColorInvert() { - return invert; - } - - /** - * Return the textual representation of the included {@link Image}. - * - * @return the {@link String} representation - */ - public String getText() { - if (text == null) { - if (image == null || size == null || size.getColumns() == 0 - || size.getRows() == 0) - return ""; - - int mult = 1; - if (mode == Mode.DOUBLE_RESOLUTION || mode == Mode.DOUBLE_DITHERING) - mult = 2; - - int w = size.getColumns() * mult; - int h = size.getRows() * mult; - - BufferedImage buff = new BufferedImage(w, h, - BufferedImage.TYPE_INT_ARGB); - - Graphics gfx = buff.getGraphics(); - - TerminalSize srcSize = getSize(image); - srcSize = new TerminalSize(srcSize.getColumns() * 2, - srcSize.getRows()); - int x = 0; - int y = 0; - - if (srcSize.getColumns() < srcSize.getRows()) { - double ratio = (double) size.getColumns() - / (double) size.getRows(); - ratio *= (double) srcSize.getRows() - / (double) srcSize.getColumns(); - - h = (int) Math.round(ratio * h); - y = (buff.getHeight() - h) / 2; - } else { - double ratio = (double) size.getRows() - / (double) size.getColumns(); - ratio *= (double) srcSize.getColumns() - / (double) srcSize.getRows(); - - w = (int) Math.round(ratio * w); - x = (buff.getWidth() - w) / 2; - } - - if (gfx.drawImage(image, x, y, w, h, new ImageObserver() { - @Override - public boolean imageUpdate(Image img, int infoflags, int x, - int y, int width, int height) { - ImageText.this.ready = true; - return true; - } - })) { - ready = true; - } - - while (!ready) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - } - - gfx.dispose(); - - StringBuilder builder = new StringBuilder(); - - for (int row = 0; row < buff.getHeight(); row += mult) { - if (row > 0) - builder.append('\n'); - - for (int col = 0; col < buff.getWidth(); col += mult) { - if (mult == 1) { - char car = ' '; - float brightness = getBrightness(buff.getRGB(col, row)); - if (mode == Mode.DITHERING) - car = getDitheringChar(brightness, " ░▒▓█"); - if (mode == Mode.ASCII) - car = getDitheringChar(brightness, " .-+=o8#"); - - builder.append(car); - } else if (mult == 2) { - builder.append(getBlockChar( // - buff.getRGB(col, row),// - buff.getRGB(col + 1, row),// - buff.getRGB(col, row + 1),// - buff.getRGB(col + 1, row + 1),// - mode == Mode.DOUBLE_DITHERING// - )); - } - } - } - - text = builder.toString(); - } - - return text; - } - - @Override - public String toString() { - return getText(); - } - - /** - * Return the size of the given {@link Image}. - * - * @param img - * the image to measure - * - * @return the size - */ - static private TerminalSize getSize(Image img) { - TerminalSize size = null; - while (size == null) { - int w = img.getWidth(null); - int h = img.getHeight(null); - if (w > -1 && h > -1) { - size = new TerminalSize(w, h); - } else { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - } - } - - return size; - } - - /** - * Return the {@link Character} corresponding to the given brightness level - * from the evenly-separated given {@link Character}s. - * - * @param brightness - * the brightness level - * @param cars - * the {@link Character}s to choose from, from less bright to - * most bright; MUST contain at least one - * {@link Character} - * - * @return the {@link Character} to use - */ - private char getDitheringChar(float brightness, String cars) { - int index = Math.round(brightness * (cars.length() - 1)); - return cars.charAt(index); - } - - /** - * Return the {@link Character} corresponding to the 4 given colours in - * {@link Mode#DOUBLE_RESOLUTION} or {@link Mode#DOUBLE_DITHERING} mode. - * - * @param upperleft - * the upper left colour - * @param upperright - * the upper right colour - * @param lowerleft - * the lower left colour - * @param lowerright - * the lower right colour - * @param dithering - * TRUE to use {@link Mode#DOUBLE_DITHERING}, FALSE for - * {@link Mode#DOUBLE_RESOLUTION} - * - * @return the {@link Character} to use - */ - private char getBlockChar(int upperleft, int upperright, int lowerleft, - int lowerright, boolean dithering) { - int choice = 0; - if (getBrightness(upperleft) > 0.5f) - choice += 1; - if (getBrightness(upperright) > 0.5f) - choice += 2; - if (getBrightness(lowerleft) > 0.5f) - choice += 4; - if (getBrightness(lowerright) > 0.5f) - choice += 8; - - switch (choice) { - case 0: - return ' '; - case 1: - return '▘'; - case 2: - return '▝'; - case 3: - return '▀'; - case 4: - return '▖'; - case 5: - return '▌'; - case 6: - return '▞'; - case 7: - return '▛'; - case 8: - return '▗'; - case 9: - return '▚'; - case 10: - return '▐'; - case 11: - return '▜'; - case 12: - return '▄'; - case 13: - return '▙'; - case 14: - return '▟'; - case 15: - if (dithering) { - float avg = 0; - avg += getBrightness(upperleft); - avg += getBrightness(upperright); - avg += getBrightness(lowerleft); - avg += getBrightness(lowerright); - avg /= 4; - - return getDitheringChar(avg, " ░▒▓█"); - } else { - return '█'; - } - } - - return ' '; - } - - /** - * Temporary array used so not to create a lot of new ones. - */ - private float[] tmp = new float[4]; - - /** - * Return the brightness value to use from the given ARGB colour. - * - * @param argb - * the argb colour - * - * @return the brightness to sue for computations - */ - private float getBrightness(int argb) { - if (invert) - return 1 - rgb2hsb(argb, tmp)[2]; - return rgb2hsb(argb, tmp)[2]; - } - - /** - * Convert the given ARGB colour in HSL/HSB, either into the supplied array - * or into a new one if array is NULL. - * - *

- * ARGB pixels are given in 0xAARRGGBB format, while the returned array will - * contain Hue, Saturation, Lightness/Brightness, Alpha, in this order. H, - * S, L and A are all ranging from 0 to 1 (indeed, H is in 1/360th). - *

- * pixel - * - * @param argb - * the ARGB colour pixel to convert - * @param array - * the array to convert into or NULL to create a new one - * - * @return the array containing the HSL/HSB converted colour - */ - static float[] rgb2hsb(int argb, float[] array) { - int a, r, g, b; - a = ((argb & 0xff000000) >> 24); - r = ((argb & 0x00ff0000) >> 16); - g = ((argb & 0x0000ff00) >> 8); - b = ((argb & 0x000000ff)); - - if (array == null) - array = new float[4]; - Color.RGBtoHSB(r, g, b, array); - - array[3] = a; - - return array; - - // // other implementation: - // - // float a, r, g, b; - // a = ((argb & 0xff000000) >> 24) / 255.0f; - // r = ((argb & 0x00ff0000) >> 16) / 255.0f; - // g = ((argb & 0x0000ff00) >> 8) / 255.0f; - // b = ((argb & 0x000000ff)) / 255.0f; - // - // float rgbMin, rgbMax; - // rgbMin = Math.min(r, Math.min(g, b)); - // rgbMax = Math.max(r, Math.max(g, b)); - // - // float l; - // l = (rgbMin + rgbMax) / 2; - // - // float s; - // if (rgbMin == rgbMax) { - // s = 0; - // } else { - // if (l <= 0.5) { - // s = (rgbMax - rgbMin) / (rgbMax + rgbMin); - // } else { - // s = (rgbMax - rgbMin) / (2.0f - rgbMax - rgbMin); - // } - // } - // - // float h; - // if (r > g && r > b) { - // h = (g - b) / (rgbMax - rgbMin); - // } else if (g > b) { - // h = 2.0f + (b - r) / (rgbMax - rgbMin); - // } else { - // h = 4.0f + (r - g) / (rgbMax - rgbMin); - // } - // h /= 6; // from 0 to 1 - // - // return new float[] { h, s, l, a }; - // - // // // natural mode: - // // - // // int aa = (int) Math.round(100 * a); - // // int hh = (int) (360 * h); - // // if (hh < 0) - // // hh += 360; - // // int ss = (int) Math.round(100 * s); - // // int ll = (int) Math.round(100 * l); - // // - // // return new int[] { hh, ss, ll, aa }; - } -} diff --git a/src/be/nikiroo/jvcard/tui/ImageTextControl.java b/src/be/nikiroo/jvcard/tui/ImageTextControl.java index dc05482..22621a3 100644 --- a/src/be/nikiroo/jvcard/tui/ImageTextControl.java +++ b/src/be/nikiroo/jvcard/tui/ImageTextControl.java @@ -1,9 +1,11 @@ package be.nikiroo.jvcard.tui; +import java.awt.Dimension; import java.awt.Image; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.tui.ImageText.Mode; +import be.nikiroo.utils.ImageText; +import be.nikiroo.utils.ImageText.Mode; import com.googlecode.lanterna.TerminalSize; import com.googlecode.lanterna.gui2.BorderLayout; @@ -14,7 +16,7 @@ import com.googlecode.lanterna.gui2.TextBox; * A {@link Panel} containing an {@link ImageText} rendering. * * @author niki - * + * */ public class ImageTextControl extends Panel { private ImageText image; @@ -44,7 +46,8 @@ public class ImageTextControl extends Panel { this.setLayoutManager(new BorderLayout()); setSize(size); - setImage(new ImageText(image, size, mode, false)); + setImage(new ImageText(image, new Dimension(size.getColumns(), + size.getRows()), mode, false)); } /** @@ -80,7 +83,7 @@ public class ImageTextControl extends Panel { @Override public synchronized Panel setSize(TerminalSize size) { if (image != null) - image.setSize(size); + image.setSize(new Dimension(size.getColumns(), size.getRows())); super.setSize(size); diff --git a/src/be/nikiroo/jvcard/tui/KeyAction.java b/src/be/nikiroo/jvcard/tui/KeyAction.java index bd91ba7..9a56cd9 100644 --- a/src/be/nikiroo/jvcard/tui/KeyAction.java +++ b/src/be/nikiroo/jvcard/tui/KeyAction.java @@ -6,7 +6,7 @@ import be.nikiroo.jvcard.Card; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.StringId; import com.googlecode.lanterna.input.KeyStroke; import com.googlecode.lanterna.input.KeyType; diff --git a/src/be/nikiroo/jvcard/tui/MainWindow.java b/src/be/nikiroo/jvcard/tui/MainWindow.java index a87b7ba..39560a4 100644 --- a/src/be/nikiroo/jvcard/tui/MainWindow.java +++ b/src/be/nikiroo/jvcard/tui/MainWindow.java @@ -7,14 +7,15 @@ import java.util.LinkedList; import java.util.List; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.enums.ColorOption; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.ColorOption; +import be.nikiroo.jvcard.resources.StringId; import be.nikiroo.jvcard.tui.KeyAction.Mode; import be.nikiroo.jvcard.tui.panes.ContactDetails; import be.nikiroo.jvcard.tui.panes.ContactDetailsRaw; import be.nikiroo.jvcard.tui.panes.ContactList; import be.nikiroo.jvcard.tui.panes.MainContent; +import be.nikiroo.utils.StringUtils; +import be.nikiroo.utils.Version; import com.googlecode.lanterna.TerminalSize; import com.googlecode.lanterna.gui2.BasicWindow; @@ -54,7 +55,7 @@ public class MainWindow extends BasicWindow { * Information about a question to ask the user and its answer. * * @author niki - * + * */ private class UserQuestion { private boolean oneKeyAnswer; @@ -404,7 +405,7 @@ public class MainWindow extends BasicWindow { */ private void setTitle() { String prefix = " " + Main.APPLICATION_TITLE + " (version " - + Main.APPLICATION_VERSION + ")"; + + Version.getCurrentVersion() + ")"; String title = null; int count = -1; @@ -605,8 +606,6 @@ public class MainWindow extends BasicWindow { * * @param key * the key that was pressed - * @param answer - * the answer given for this key * * @return if the window handled the input */ @@ -641,12 +640,11 @@ public class MainWindow extends BasicWindow { /** * Handle the input in case of "normal" (not "ask for answer") mode. * - * @param key - * the key that was pressed + * @param action + * the key that was pressed and the action to take * @param answer * the answer given for this key * - * @return if the window handled the input */ private void handleAction(KeyAction action, String answer) { MainContent content = getContent(); diff --git a/src/be/nikiroo/jvcard/tui/UiColors.java b/src/be/nikiroo/jvcard/tui/UiColors.java index 7d951c8..a851d4e 100644 --- a/src/be/nikiroo/jvcard/tui/UiColors.java +++ b/src/be/nikiroo/jvcard/tui/UiColors.java @@ -3,13 +3,16 @@ package be.nikiroo.jvcard.tui; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.Writer; import java.util.HashMap; import java.util.Map; import java.util.MissingResourceException; import java.util.Properties; -import be.nikiroo.jvcard.resources.bundles.ColorBundle; -import be.nikiroo.jvcard.resources.enums.ColorOption; +import be.nikiroo.jvcard.resources.ColorBundle; +import be.nikiroo.jvcard.resources.ColorOption; +import be.nikiroo.jvcard.resources.Target; +import be.nikiroo.utils.resources.Bundle; import com.googlecode.lanterna.TextColor; import com.googlecode.lanterna.graphics.PropertiesTheme; @@ -23,14 +26,15 @@ import com.googlecode.lanterna.gui2.Label; * @author niki * */ -public class UiColors extends ColorBundle { +public class UiColors { static private Object lock = new Object(); static private UiColors instance = null; private Map colorMap = null; + private ColorBundle bundle; private UiColors() { - super(); + bundle = new ColorBundle(); colorMap = new HashMap(); } @@ -128,7 +132,7 @@ public class UiColors extends ColorBundle { if (!getInstance().colorMap.containsKey(el.name() + "_BG")) { String value = null; try { - value = getInstance().map.getString(el.name() + "_BG"); + value = getInstance().bundle.getStringX(el, "BG"); } catch (MissingResourceException mre) { value = null; } @@ -151,7 +155,7 @@ public class UiColors extends ColorBundle { if (!getInstance().colorMap.containsKey(el.name() + "_FG")) { String value = null; try { - value = getInstance().map.getString(el.name() + "_FG"); + value = getInstance().bundle.getStringX(el, "FG"); } catch (MissingResourceException mre) { value = null; } diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java b/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java index a221f6b..9bab007 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactDetails.java @@ -7,16 +7,17 @@ import java.util.List; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.TypeInfo; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.bundles.DisplayBundle; -import be.nikiroo.jvcard.resources.enums.ColorOption; -import be.nikiroo.jvcard.resources.enums.DisplayOption; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.ColorOption; +import be.nikiroo.jvcard.resources.DisplayBundle; +import be.nikiroo.jvcard.resources.DisplayOption; +import be.nikiroo.jvcard.resources.StringId; import be.nikiroo.jvcard.tui.ImageTextControl; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; import be.nikiroo.jvcard.tui.UiColors; +import be.nikiroo.utils.ImageUtils; +import be.nikiroo.utils.StringUtils; import com.googlecode.lanterna.TerminalSize; import com.googlecode.lanterna.gui2.BorderLayout; @@ -189,7 +190,7 @@ public class ContactDetails extends MainContent { && encoding.getValue().equalsIgnoreCase("b")) { try { - image = StringUtils.toImage(photo.getValue()); + image = ImageUtils.fromBase64(photo.getValue()); } catch (Exception e) { System.err.println("Cannot parse image for contact: " + contact.getPreferredDataValue("UID")); diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java index c29ba00..2b8e842 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactDetailsRaw.java @@ -7,13 +7,13 @@ import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.TypeInfo; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.enums.ColorOption; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.ColorOption; +import be.nikiroo.jvcard.resources.StringId; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; import be.nikiroo.jvcard.tui.TuiLauncher; +import be.nikiroo.utils.StringUtils; import com.googlecode.lanterna.gui2.MultiWindowTextGUI; import com.googlecode.lanterna.gui2.dialogs.ActionListDialogBuilder; diff --git a/src/be/nikiroo/jvcard/tui/panes/ContactList.java b/src/be/nikiroo/jvcard/tui/panes/ContactList.java index 20d4944..dc89fcd 100644 --- a/src/be/nikiroo/jvcard/tui/panes/ContactList.java +++ b/src/be/nikiroo/jvcard/tui/panes/ContactList.java @@ -8,10 +8,10 @@ import be.nikiroo.jvcard.Card; import be.nikiroo.jvcard.Contact; import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.resources.bundles.DisplayBundle; -import be.nikiroo.jvcard.resources.enums.DisplayOption; -import be.nikiroo.jvcard.resources.enums.ColorOption; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.ColorOption; +import be.nikiroo.jvcard.resources.DisplayBundle; +import be.nikiroo.jvcard.resources.DisplayOption; +import be.nikiroo.jvcard.resources.StringId; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; diff --git a/src/be/nikiroo/jvcard/tui/panes/FileList.java b/src/be/nikiroo/jvcard/tui/panes/FileList.java index da589aa..1172378 100644 --- a/src/be/nikiroo/jvcard/tui/panes/FileList.java +++ b/src/be/nikiroo/jvcard/tui/panes/FileList.java @@ -11,12 +11,12 @@ import be.nikiroo.jvcard.launcher.CardResult; import be.nikiroo.jvcard.launcher.CardResult.MergeCallback; import be.nikiroo.jvcard.launcher.Main; import be.nikiroo.jvcard.parsers.Format; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.enums.ColorOption; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.ColorOption; +import be.nikiroo.jvcard.resources.StringId; import be.nikiroo.jvcard.tui.KeyAction; import be.nikiroo.jvcard.tui.KeyAction.DataType; import be.nikiroo.jvcard.tui.KeyAction.Mode; +import be.nikiroo.utils.StringUtils; import com.googlecode.lanterna.input.KeyType; diff --git a/src/be/nikiroo/jvcard/tui/panes/MainContentList.java b/src/be/nikiroo/jvcard/tui/panes/MainContentList.java index 9e5f8ec..1b0eb1b 100644 --- a/src/be/nikiroo/jvcard/tui/panes/MainContentList.java +++ b/src/be/nikiroo/jvcard/tui/panes/MainContentList.java @@ -4,10 +4,10 @@ import java.util.LinkedList; import java.util.List; import be.nikiroo.jvcard.launcher.Main; -import be.nikiroo.jvcard.resources.StringUtils; -import be.nikiroo.jvcard.resources.enums.ColorOption; -import be.nikiroo.jvcard.resources.enums.StringId; +import be.nikiroo.jvcard.resources.ColorOption; +import be.nikiroo.jvcard.resources.StringId; import be.nikiroo.jvcard.tui.UiColors; +import be.nikiroo.utils.StringUtils; import com.googlecode.lanterna.TextColor; import com.googlecode.lanterna.gui2.AbstractListBox.ListItemRenderer; diff --git a/src/com/googlecode/lanterna/CJKUtils.java b/src/com/googlecode/lanterna/CJKUtils.java deleted file mode 100644 index a611618..0000000 --- a/src/com/googlecode/lanterna/CJKUtils.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna; - -/** - * Utilities class for analyzing and working with CJK (Chinese, Japanese, Korean) characters. The main purpose of this - * class is to assist in figuring out how many terminal columns a character (and in extension, a String) takes up. The - * main issue is that while most latin (and latin-related) character can be trusted to consume one column in the - * terminal, CJK characters tends to take two, partly due to the square nature of the characters but mostly due to the - * fact that they require most space to distinguish. - * - * @author Martin - * @see TerminalTextUtils - * @deprecated Use {@code TerminalTextUtils} instead - */ -public class CJKUtils { - private CJKUtils() { - } - - /** - * Given a character, is this character considered to be a CJK character? - * Shamelessly stolen from - * StackOverflow - * where it was contributed by user Rakesh N - * @param c Character to test - * @return {@code true} if the character is a CJK character - * @deprecated Use {@code TerminalTextUtils.isCharJCK(c)} instead - * @see TerminalTextUtils#isCharCJK(char) - */ - @Deprecated - public static boolean isCharCJK(final char c) { - return TerminalTextUtils.isCharCJK(c); - } - - /** - * @deprecated Call {@code getColumnWidth(s)} instead - */ - @Deprecated - public static int getTrueWidth(String s) { - return TerminalTextUtils.getColumnWidth(s); - } - - /** - * Given a string, returns how many columns this string would need to occupy in a terminal, taking into account that - * CJK characters takes up two columns. - * @param s String to check length - * @return Number of actual terminal columns the string would occupy - * @deprecated Use {@code TerminalTextUtils.getColumnWidth(s)} instead - * @see TerminalTextUtils#getColumnWidth(String) - */ - @Deprecated - public static int getColumnWidth(String s) { - return TerminalTextUtils.getColumnIndex(s, s.length()); - } - - /** - * Given a string and a character index inside that string, find out what the column index of that character would - * be if printed in a terminal. If the string only contains non-CJK characters then the returned value will be same - * as {@code stringCharacterIndex}, but if there are CJK characters the value will be different due to CJK - * characters taking up two columns in width. If the character at the index in the string is a CJK character itself, - * the returned value will be the index of the left-side of character. - * @param s String to translate the index from - * @param stringCharacterIndex Index within the string to get the terminal column index of - * @return Index of the character inside the String at {@code stringCharacterIndex} when it has been writted to a - * terminal - * @throws StringIndexOutOfBoundsException if the index given is outside the String length or negative - * @deprecated Use {@code TerminalTextUtils.getColumnIndex(s, stringCharacterIndex)} instead - * @see TerminalTextUtils#getColumnIndex(String, int) - */ - @Deprecated - public static int getColumnIndex(String s, int stringCharacterIndex) throws StringIndexOutOfBoundsException { - return TerminalTextUtils.getColumnIndex(s, stringCharacterIndex); - } - - /** - * This method does the reverse of getColumnIndex, given a String and imagining it has been printed out to the - * top-left corner of a terminal, in the column specified by {@code columnIndex}, what is the index of that - * character in the string. If the string contains no CJK characters, this will always be the same as - * {@code columnIndex}. If the index specified is the right column of a CJK character, the index is the same as if - * the column was the left column. So calling {@code getStringCharacterIndex("英", 0)} and - * {@code getStringCharacterIndex("英", 1)} will both return 0. - * @param s String to translate the index to - * @param columnIndex Column index of the string written to a terminal - * @return The index in the string of the character in terminal column {@code columnIndex} - * @deprecated Use {@code TerminalTextUtils.getStringCharacterIndex(s, columnIndex} instead - * @see TerminalTextUtils#getStringCharacterIndex(String, int) - */ - @Deprecated - public static int getStringCharacterIndex(String s, int columnIndex) { - return TerminalTextUtils.getStringCharacterIndex(s, columnIndex); - } - - /** - * Given a string that may or may not contain CJK characters, returns the substring which will fit inside - * availableColumnSpace columns. This method does not handle special cases like tab or new-line. - *

- * Calling this method is the same as calling {@code fitString(string, 0, availableColumnSpace)}. - * @param string The string to fit inside the availableColumnSpace - * @param availableColumnSpace Number of columns to fit the string inside - * @return The whole or part of the input string which will fit inside the supplied availableColumnSpace - * @deprecated Use {@code TerminalTextUtils.fitString(string, availableColumnSpace)} instead - * @see TerminalTextUtils#fitString(String, int) - */ - @Deprecated - public static String fitString(String string, int availableColumnSpace) { - return TerminalTextUtils.fitString(string, availableColumnSpace); - } - - /** - * Given a string that may or may not contain CJK characters, returns the substring which will fit inside - * availableColumnSpace columns. This method does not handle special cases like tab or new-line. - *

- * This overload has a {@code fromColumn} parameter that specified where inside the string to start fitting. Please - * notice that {@code fromColumn} is not a character index inside the string, but a column index as if the string - * has been printed from the left-most side of the terminal. So if the string is "日本語", fromColumn set to 1 will - * not starting counting from the second character ("本") in the string but from the CJK filler character belonging - * to "日". If you want to count from a particular character index inside the string, please pass in a substring - * and use fromColumn set to 0. - * @param string The string to fit inside the availableColumnSpace - * @param fromColumn From what column of the input string to start fitting (see description above!) - * @param availableColumnSpace Number of columns to fit the string inside - * @return The whole or part of the input string which will fit inside the supplied availableColumnSpace - * @deprecated Use {@code TerminalTextUtils.fitString(string, fromColumn, availableColumnSpace)} instead - * @see TerminalTextUtils#fitString(String, int, int) - */ - @Deprecated - public static String fitString(String string, int fromColumn, int availableColumnSpace) { - return TerminalTextUtils.fitString(string, fromColumn, availableColumnSpace); - } -} diff --git a/src/com/googlecode/lanterna/SGR.java b/src/com/googlecode/lanterna/SGR.java deleted file mode 100644 index 815072d..0000000 --- a/src/com/googlecode/lanterna/SGR.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.googlecode.lanterna; - -/** - * SGR - Select Graphic Rendition, changes the state of the terminal as to what kind of text to print after this - * command. When working with the Terminal interface, its keeping a state of which SGR codes are active, so activating - * one of these codes will make it apply to all text until you explicitly deactivate it. When you work with Screen and - * GUI systems, usually the SGR is a property of an independent character and won't affect others. - */ -public enum SGR { - /** - * Bold text mode. Please note that on some terminal implementations, instead of (or in addition to) making the text - * bold, it will draw the text in a slightly different color - */ - BOLD, - - /** - * Reverse text mode, will flip the foreground and background colors while active - */ - REVERSE, - - /** - * Draws a horizontal line under the text. Not widely supported. - */ - UNDERLINE, - - /** - * Text will blink on the screen by alternating the foreground color between the real foreground color and the - * background color. Not widely supported. - */ - BLINK, - - /** - * Draws a border around the text. Rarely supported. - */ - BORDERED, - - /** - * I have no idea, exotic extension, please send me a reference screen shots! - */ - FRAKTUR, - - /** - * Draws a horizontal line through the text. Rarely supported. - */ - CROSSED_OUT, - - /** - * Draws a circle around the text. Rarely supported. - */ - CIRCLED, - ; -} diff --git a/src/com/googlecode/lanterna/Symbols.java b/src/com/googlecode/lanterna/Symbols.java deleted file mode 100644 index ab4e010..0000000 --- a/src/com/googlecode/lanterna/Symbols.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * 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-2015 Martin - */ - -package com.googlecode.lanterna; - -/** - * Some text graphics, taken from http://en.wikipedia.org/wiki/Codepage_437 but converted to its UTF-8 counterpart. - * This class it mostly here to help out with building text GUIs when you don't have a handy Unicode chart available. - * Previously this class was known as ACS, which was taken from ncurses (meaning "Alternative Character Set"). - * @author martin - */ -public class Symbols { - private Symbols() {} - - /** - * ☺ - */ - public static final char FACE_WHITE = 0x263A; - /** - * ☻ - */ - public static final char FACE_BLACK = 0x263B; - /** - * ♥ - */ - public static final char HEART = 0x2665; - /** - * ♣ - */ - public static final char CLUB = 0x2663; - /** - * ♦ - */ - public static final char DIAMOND = 0x2666; - /** - * ♠ - */ - public static final char SPADES = 0x2660; - /** - * • - */ - public static final char BULLET = 0x2022; - /** - * ◘ - */ - public static final char INVERSE_BULLET = 0x25d8; - /** - * ○ - */ - public static final char WHITE_CIRCLE = 0x25cb; - /** - * ◙ - */ - public static final char INVERSE_WHITE_CIRCLE = 0x25d9; - - /** - * ■ - */ - public static final char SOLID_SQUARE = 0x25A0; - /** - * ▪ - */ - public static final char SOLID_SQUARE_SMALL = 0x25AA; - /** - * □ - */ - public static final char OUTLINED_SQUARE = 0x25A1; - /** - * ▫ - */ - public static final char OUTLINED_SQUARE_SMALL = 0x25AB; - - /** - * ♀ - */ - public static final char FEMALE = 0x2640; - /** - * ♂ - */ - public static final char MALE = 0x2642; - - /** - * ↑ - */ - public static final char ARROW_UP = 0x2191; - /** - * ↓ - */ - public static final char ARROW_DOWN = 0x2193; - /** - * → - */ - public static final char ARROW_RIGHT = 0x2192; - /** - * ← - */ - public static final char ARROW_LEFT = 0x2190; - - /** - * █ - */ - public static final char BLOCK_SOLID = 0x2588; - /** - * ▓ - */ - public static final char BLOCK_DENSE = 0x2593; - /** - * ▒ - */ - public static final char BLOCK_MIDDLE = 0x2592; - /** - * ░ - */ - public static final char BLOCK_SPARSE = 0x2591; - - /** - * ⏴ - */ - public static final char TRIANGLE_RIGHT_POINTING_MEDIUM_BLACK = 0x23F4; - /** - * ⏵ - */ - public static final char TRIANGLE_LEFT_POINTING_MEDIUM_BLACK = 0x23F5; - /** - * ⏶ - */ - public static final char TRIANGLE_UP_POINTING_MEDIUM_BLACK = 0x23F6; - /** - * ⏷ - */ - public static final char TRIANGLE_DOWN_POINTING_MEDIUM_BLACK = 0x23F7; - - - /** - * ─ - */ - public static final char SINGLE_LINE_HORIZONTAL = 0x2500; - /** - * ━ - */ - public static final char BOLD_SINGLE_LINE_HORIZONTAL = 0x2501; - /** - * ╾ - */ - public static final char BOLD_TO_NORMAL_SINGLE_LINE_HORIZONTAL = 0x257E; - /** - * ╼ - */ - public static final char BOLD_FROM_NORMAL_SINGLE_LINE_HORIZONTAL = 0x257C; - /** - * ═ - */ - public static final char DOUBLE_LINE_HORIZONTAL = 0x2550; - /** - * │ - */ - public static final char SINGLE_LINE_VERTICAL = 0x2502; - /** - * ┃ - */ - public static final char BOLD_SINGLE_LINE_VERTICAL = 0x2503; - /** - * ╿ - */ - public static final char BOLD_TO_NORMAL_SINGLE_LINE_VERTICAL = 0x257F; - /** - * ╽ - */ - public static final char BOLD_FROM_NORMAL_SINGLE_LINE_VERTICAL = 0x257D; - /** - * ║ - */ - public static final char DOUBLE_LINE_VERTICAL = 0x2551; - - /** - * ┌ - */ - public static final char SINGLE_LINE_TOP_LEFT_CORNER = 0x250C; - /** - * ╔ - */ - public static final char DOUBLE_LINE_TOP_LEFT_CORNER = 0x2554; - /** - * ┐ - */ - public static final char SINGLE_LINE_TOP_RIGHT_CORNER = 0x2510; - /** - * ╗ - */ - public static final char DOUBLE_LINE_TOP_RIGHT_CORNER = 0x2557; - - /** - * └ - */ - public static final char SINGLE_LINE_BOTTOM_LEFT_CORNER = 0x2514; - /** - * ╚ - */ - public static final char DOUBLE_LINE_BOTTOM_LEFT_CORNER = 0x255A; - /** - * ┘ - */ - public static final char SINGLE_LINE_BOTTOM_RIGHT_CORNER = 0x2518; - /** - * ╝ - */ - public static final char DOUBLE_LINE_BOTTOM_RIGHT_CORNER = 0x255D; - - /** - * ┼ - */ - public static final char SINGLE_LINE_CROSS = 0x253C; - /** - * ╬ - */ - public static final char DOUBLE_LINE_CROSS = 0x256C; - /** - * ╪ - */ - public static final char DOUBLE_LINE_HORIZONTAL_SINGLE_LINE_CROSS = 0x256A; - /** - * ╫ - */ - public static final char DOUBLE_LINE_VERTICAL_SINGLE_LINE_CROSS = 0x256B; - - /** - * ┴ - */ - public static final char SINGLE_LINE_T_UP = 0x2534; - /** - * ┬ - */ - public static final char SINGLE_LINE_T_DOWN = 0x252C; - /** - * ├ - */ - public static final char SINGLE_LINE_T_RIGHT = 0x251c; - /** - * ┤ - */ - public static final char SINGLE_LINE_T_LEFT = 0x2524; - - /** - * ╨ - */ - public static final char SINGLE_LINE_T_DOUBLE_UP = 0x2568; - /** - * ╥ - */ - public static final char SINGLE_LINE_T_DOUBLE_DOWN = 0x2565; - /** - * ╞ - */ - public static final char SINGLE_LINE_T_DOUBLE_RIGHT = 0x255E; - /** - * ╡ - */ - public static final char SINGLE_LINE_T_DOUBLE_LEFT = 0x2561; - - /** - * ╩ - */ - public static final char DOUBLE_LINE_T_UP = 0x2569; - /** - * ╦ - */ - public static final char DOUBLE_LINE_T_DOWN = 0x2566; - /** - * ╠ - */ - public static final char DOUBLE_LINE_T_RIGHT = 0x2560; - /** - * ╣ - */ - public static final char DOUBLE_LINE_T_LEFT = 0x2563; - - /** - * ╧ - */ - public static final char DOUBLE_LINE_T_SINGLE_UP = 0x2567; - /** - * ╤ - */ - public static final char DOUBLE_LINE_T_SINGLE_DOWN = 0x2564; - /** - * ╟ - */ - public static final char DOUBLE_LINE_T_SINGLE_RIGHT = 0x255F; - /** - * ╢ - */ - public static final char DOUBLE_LINE_T_SINGLE_LEFT = 0x2562; -} diff --git a/src/com/googlecode/lanterna/TerminalPosition.java b/src/com/googlecode/lanterna/TerminalPosition.java deleted file mode 100644 index 3dd5813..0000000 --- a/src/com/googlecode/lanterna/TerminalPosition.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna; - -/** - * A 2-d position in 'terminal space'. Please note that the coordinates are 0-indexed, meaning 0x0 is the top left - * corner of the terminal. This object is immutable so you cannot change it after it has been created. Instead, you - * can easily create modified 'clones' by using the 'with' methods. - * - * @author Martin - */ -public class TerminalPosition { - - /** - * Constant for the top-left corner (0x0) - */ - public static final TerminalPosition TOP_LEFT_CORNER = new TerminalPosition(0, 0); - /** - * Constant for the 1x1 position (one offset in both directions from top-left) - */ - public static final TerminalPosition OFFSET_1x1 = new TerminalPosition(1, 1); - - private final int row; - private final int column; - - /** - * Creates a new TerminalPosition object, which represents a location on the screen. There is no check to verify - * that the position you specified is within the size of the current terminal and you can specify negative positions - * as well. - * - * @param column Column of the location, or the "x" coordinate, zero indexed (the first column is 0) - * @param row Row of the location, or the "y" coordinate, zero indexed (the first row is 0) - */ - public TerminalPosition(int column, int row) { - this.row = row; - this.column = column; - } - - /** - * Returns the index of the column this position is representing, zero indexed (the first column has index 0). - * @return Index of the column this position has - */ - public int getColumn() { - return column; - } - - /** - * Returns the index of the row this position is representing, zero indexed (the first row has index 0) - * @return Index of the row this position has - */ - public int getRow() { - return row; - } - - /** - * Creates a new TerminalPosition object representing a position with the same column index as this but with a - * supplied row index. - * @param row Index of the row for the new position - * @return A TerminalPosition object with the same column as this but with a specified row index - */ - public TerminalPosition withRow(int row) { - if(row == 0 && this.column == 0) { - return TOP_LEFT_CORNER; - } - return new TerminalPosition(this.column, row); - } - - /** - * Creates a new TerminalPosition object representing a position with the same row index as this but with a - * supplied column index. - * @param column Index of the column for the new position - * @return A TerminalPosition object with the same row as this but with a specified column index - */ - public TerminalPosition withColumn(int column) { - if(column == 0 && this.row == 0) { - return TOP_LEFT_CORNER; - } - return new TerminalPosition(column, this.row); - } - - /** - * Creates a new TerminalPosition object representing a position on the same row, but with a column offset by a - * supplied value. Calling this method with delta 0 will return this, calling it with a positive delta will return - * a terminal position delta number of columns to the right and for negative numbers the same to the left. - * @param delta Column offset - * @return New terminal position based off this one but with an applied offset - */ - public TerminalPosition withRelativeColumn(int delta) { - if(delta == 0) { - return this; - } - return withColumn(column + delta); - } - - /** - * Creates a new TerminalPosition object representing a position on the same column, but with a row offset by a - * supplied value. Calling this method with delta 0 will return this, calling it with a positive delta will return - * a terminal position delta number of rows to the down and for negative numbers the same up. - * @param delta Row offset - * @return New terminal position based off this one but with an applied offset - */ - public TerminalPosition withRelativeRow(int delta) { - if(delta == 0) { - return this; - } - return withRow(row + delta); - } - - /** - * Creates a new TerminalPosition object that is 'translated' by an amount of rows and columns specified by another - * TerminalPosition. Same as calling - * withRelativeRow(translate.getRow()).withRelativeColumn(translate.getColumn()) - * @param translate How many columns and rows to translate - * @return New TerminalPosition that is the result of the original with added translation - */ - public TerminalPosition withRelative(TerminalPosition translate) { - return withRelative(translate.getColumn(), translate.getRow()); - } - - /** - * Creates a new TerminalPosition object that is 'translated' by an amount of rows and columns specified by the two - * parameters. Same as calling - * withRelativeRow(deltaRow).withRelativeColumn(deltaColumn) - * @param deltaColumn How many columns to move from the current position in the new TerminalPosition - * @param deltaRow How many rows to move from the current position in the new TerminalPosition - * @return New TerminalPosition that is the result of the original position with added translation - */ - public TerminalPosition withRelative(int deltaColumn, int deltaRow) { - return withRelativeRow(deltaRow).withRelativeColumn(deltaColumn); - } - - @Override - public String toString() { - return "[" + column + ":" + row + "]"; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 23 * hash + this.row; - hash = 23 * hash + this.column; - return hash; - } - - public boolean equals(int columnIndex, int rowIndex) { - return this.column == columnIndex && - this.row == rowIndex; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final TerminalPosition other = (TerminalPosition) obj; - return this.row == other.row && this.column == other.column; - } -} diff --git a/src/com/googlecode/lanterna/TerminalSize.java b/src/com/googlecode/lanterna/TerminalSize.java deleted file mode 100644 index 0de7134..0000000 --- a/src/com/googlecode/lanterna/TerminalSize.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna; - -/** - * Terminal dimensions in 2-d space, measured in number of rows and columns. This class is immutable and cannot change - * its internal state after creation. - * - * @author Martin - */ -public class TerminalSize { - public static final TerminalSize ZERO = new TerminalSize(0, 0); - public static final TerminalSize ONE = new TerminalSize(1, 1); - - private final int columns; - private final int rows; - - /** - * Creates a new terminal size representation with a given width (columns) and height (rows) - * @param columns Width, in number of columns - * @param rows Height, in number of columns - */ - public TerminalSize(int columns, int rows) { - if (columns < 0) { - throw new IllegalArgumentException("TerminalSize.columns cannot be less than 0!"); - } - if (rows < 0) { - throw new IllegalArgumentException("TerminalSize.rows cannot be less than 0!"); - } - this.columns = columns; - this.rows = rows; - } - - /** - * @return Returns the width of this size representation, in number of columns - */ - public int getColumns() { - return columns; - } - - /** - * Creates a new size based on this size, but with a different width - * @param columns Width of the new size, in columns - * @return New size based on this one, but with a new width - */ - public TerminalSize withColumns(int columns) { - if(this.columns == columns) { - return this; - } - if(columns == 0 && this.rows == 0) { - return ZERO; - } - return new TerminalSize(columns, this.rows); - } - - - /** - * @return Returns the height of this size representation, in number of rows - */ - public int getRows() { - return rows; - } - - /** - * Creates a new size based on this size, but with a different height - * @param rows Height of the new size, in rows - * @return New size based on this one, but with a new height - */ - public TerminalSize withRows(int rows) { - if(this.rows == rows) { - return this; - } - if(rows == 0 && this.columns == 0) { - return ZERO; - } - return new TerminalSize(this.columns, rows); - } - - /** - * Creates a new TerminalSize object representing a size with the same number of rows, but with a column size offset by a - * supplied value. Calling this method with delta 0 will return this, calling it with a positive delta will return - * a terminal size delta number of columns wider and for negative numbers shorter. - * @param delta Column offset - * @return New terminal size based off this one but with an applied transformation - */ - public TerminalSize withRelativeColumns(int delta) { - if(delta == 0) { - return this; - } - return withColumns(columns + delta); - } - - /** - * Creates a new TerminalSize object representing a size with the same number of columns, but with a row size offset by a - * supplied value. Calling this method with delta 0 will return this, calling it with a positive delta will return - * a terminal size delta number of rows longer and for negative numbers shorter. - * @param delta Row offset - * @return New terminal size based off this one but with an applied transformation - */ - public TerminalSize withRelativeRows(int delta) { - if(delta == 0) { - return this; - } - return withRows(rows + delta); - } - - /** - * Creates a new TerminalSize object representing a size based on this object's size but with a delta applied. - * This is the same as calling - * withRelativeColumns(delta.getColumns()).withRelativeRows(delta.getRows()) - * @param delta Column and row offset - * @return New terminal size based off this one but with an applied resize - */ - public TerminalSize withRelative(TerminalSize delta) { - return withRelative(delta.getColumns(), delta.getRows()); - } - - /** - * Creates a new TerminalSize object representing a size based on this object's size but with a delta applied. - * This is the same as calling - * withRelativeColumns(deltaColumns).withRelativeRows(deltaRows) - * @param deltaColumns How many extra columns the new TerminalSize will have (negative values are allowed) - * @param deltaRows How many extra rows the new TerminalSize will have (negative values are allowed) - * @return New terminal size based off this one but with an applied resize - */ - public TerminalSize withRelative(int deltaColumns, int deltaRows) { - return withRelativeRows(deltaRows).withRelativeColumns(deltaColumns); - } - - /** - * Takes a different TerminalSize and returns a new TerminalSize that has the largest dimensions of the two, - * measured separately. So calling 3x5 on a 5x3 will return 5x5. - * @param other Other TerminalSize to compare with - * @return TerminalSize that combines the maximum width between the two and the maximum height - */ - public TerminalSize max(TerminalSize other) { - return withColumns(Math.max(columns, other.columns)) - .withRows(Math.max(rows, other.rows)); - } - - /** - * Takes a different TerminalSize and returns a new TerminalSize that has the smallest dimensions of the two, - * measured separately. So calling 3x5 on a 5x3 will return 3x3. - * @param other Other TerminalSize to compare with - * @return TerminalSize that combines the minimum width between the two and the minimum height - */ - public TerminalSize min(TerminalSize other) { - return withColumns(Math.min(columns, other.columns)) - .withRows(Math.min(rows, other.rows)); - } - - /** - * Returns itself if it is equal to the supplied size, otherwise the supplied size. You can use this if you have a - * size field which is frequently recalculated but often resolves to the same size; it will keep the same object - * in memory instead of swapping it out every cycle. - * @param size Size you want to return - * @return Itself if this size equals the size passed in, otherwise the size passed in - */ - public TerminalSize with(TerminalSize size) { - if(equals(size)) { - return this; - } - return size; - } - - @Override - public String toString() { - return "{" + columns + "x" + rows + "}"; - } - - @Override - public boolean equals(Object obj) { - if(this == obj) { - return true; - } - if (!(obj instanceof TerminalSize)) { - return false; - } - - TerminalSize other = (TerminalSize) obj; - return columns == other.columns - && rows == other.rows; - } - - @Override - public int hashCode() { - int hash = 5; - hash = 53 * hash + this.columns; - hash = 53 * hash + this.rows; - return hash; - } -} diff --git a/src/com/googlecode/lanterna/TerminalTextUtils.java b/src/com/googlecode/lanterna/TerminalTextUtils.java deleted file mode 100644 index 53fe735..0000000 --- a/src/com/googlecode/lanterna/TerminalTextUtils.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * This class contains a number of utility methods for analyzing characters and strings in a terminal context. The main - * purpose is to make it easier to work with text that may or may not contain double-width text characters, such as CJK - * (Chinese, Japanese, Korean) and other special symbols. This class assumes those are all double-width and in case the - * terminal (-emulator) chooses to draw them (somehow) as single-column then all the calculations in this class will be - * wrong. It seems safe to assume what this class considers double-width really is taking up two columns though. - * - * @author Martin - */ -public class TerminalTextUtils { - private TerminalTextUtils() { - } - - /** - * Given a character, is this character considered to be a CJK character? - * Shamelessly stolen from - * StackOverflow - * where it was contributed by user Rakesh N - * @param c Character to test - * @return {@code true} if the character is a CJK character - * - */ - public static boolean isCharCJK(final char c) { - Character.UnicodeBlock unicodeBlock = Character.UnicodeBlock.of(c); - return (unicodeBlock == Character.UnicodeBlock.HIRAGANA) - || (unicodeBlock == Character.UnicodeBlock.KATAKANA) - || (unicodeBlock == Character.UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS) - || (unicodeBlock == Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO) - || (unicodeBlock == Character.UnicodeBlock.HANGUL_JAMO) - || (unicodeBlock == Character.UnicodeBlock.HANGUL_SYLLABLES) - || (unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) - || (unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A) - || (unicodeBlock == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B) - || (unicodeBlock == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS) - || (unicodeBlock == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS) - || (unicodeBlock == Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT) - || (unicodeBlock == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION) - || (unicodeBlock == Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS) - || (unicodeBlock == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS && c < 0xFF61); //The magic number here is the separating index between full-width and half-width - } - - /** - * Checks if a character is expected to be taking up two columns if printed to a terminal. This will generally be - * {@code true} for CJK (Chinese, Japanese and Korean) characters. - * @param c Character to test if it's double-width when printed to a terminal - * @return {@code true} if this character is expected to be taking up two columns when printed to the terminal, - * otherwise {@code false} - */ - public static boolean isCharDoubleWidth(final char c) { - return isCharCJK(c); - } - - /** - * @deprecated Call {@code getColumnWidth(s)} instead - */ - @Deprecated - public static int getTrueWidth(String s) { - return getColumnWidth(s); - } - - /** - * Given a string, returns how many columns this string would need to occupy in a terminal, taking into account that - * CJK characters takes up two columns. - * @param s String to check length - * @return Number of actual terminal columns the string would occupy - */ - public static int getColumnWidth(String s) { - return getColumnIndex(s, s.length()); - } - - /** - * Given a string and a character index inside that string, find out what the column index of that character would - * be if printed in a terminal. If the string only contains non-CJK characters then the returned value will be same - * as {@code stringCharacterIndex}, but if there are CJK characters the value will be different due to CJK - * characters taking up two columns in width. If the character at the index in the string is a CJK character itself, - * the returned value will be the index of the left-side of character. - * @param s String to translate the index from - * @param stringCharacterIndex Index within the string to get the terminal column index of - * @return Index of the character inside the String at {@code stringCharacterIndex} when it has been writted to a - * terminal - * @throws StringIndexOutOfBoundsException if the index given is outside the String length or negative - */ - public static int getColumnIndex(String s, int stringCharacterIndex) throws StringIndexOutOfBoundsException { - int index = 0; - for(int i = 0; i < stringCharacterIndex; i++) { - if(isCharCJK(s.charAt(i))) { - index++; - } - index++; - } - return index; - } - - /** - * This method does the reverse of getColumnIndex, given a String and imagining it has been printed out to the - * top-left corner of a terminal, in the column specified by {@code columnIndex}, what is the index of that - * character in the string. If the string contains no CJK characters, this will always be the same as - * {@code columnIndex}. If the index specified is the right column of a CJK character, the index is the same as if - * the column was the left column. So calling {@code getStringCharacterIndex("英", 0)} and - * {@code getStringCharacterIndex("英", 1)} will both return 0. - * @param s String to translate the index to - * @param columnIndex Column index of the string written to a terminal - * @return The index in the string of the character in terminal column {@code columnIndex} - */ - public static int getStringCharacterIndex(String s, int columnIndex) { - int index = 0; - int counter = 0; - while(counter < columnIndex) { - if(isCharCJK(s.charAt(index++))) { - counter++; - if(counter == columnIndex) { - return index - 1; - } - } - counter++; - } - return index; - } - - /** - * Given a string that may or may not contain CJK characters, returns the substring which will fit inside - * availableColumnSpace columns. This method does not handle special cases like tab or new-line. - *

- * Calling this method is the same as calling {@code fitString(string, 0, availableColumnSpace)}. - * @param string The string to fit inside the availableColumnSpace - * @param availableColumnSpace Number of columns to fit the string inside - * @return The whole or part of the input string which will fit inside the supplied availableColumnSpace - */ - public static String fitString(String string, int availableColumnSpace) { - return fitString(string, 0, availableColumnSpace); - } - - /** - * Given a string that may or may not contain CJK characters, returns the substring which will fit inside - * availableColumnSpace columns. This method does not handle special cases like tab or new-line. - *

- * This overload has a {@code fromColumn} parameter that specified where inside the string to start fitting. Please - * notice that {@code fromColumn} is not a character index inside the string, but a column index as if the string - * has been printed from the left-most side of the terminal. So if the string is "日本語", fromColumn set to 1 will - * not starting counting from the second character ("本") in the string but from the CJK filler character belonging - * to "日". If you want to count from a particular character index inside the string, please pass in a substring - * and use fromColumn set to 0. - * @param string The string to fit inside the availableColumnSpace - * @param fromColumn From what column of the input string to start fitting (see description above!) - * @param availableColumnSpace Number of columns to fit the string inside - * @return The whole or part of the input string which will fit inside the supplied availableColumnSpace - */ - public static String fitString(String string, int fromColumn, int availableColumnSpace) { - if(availableColumnSpace <= 0) { - return ""; - } - - StringBuilder bob = new StringBuilder(); - int column = 0; - int index = 0; - while(index < string.length() && column < fromColumn) { - char c = string.charAt(index++); - column += TerminalTextUtils.isCharCJK(c) ? 2 : 1; - } - if(column > fromColumn) { - bob.append(" "); - availableColumnSpace--; - } - - while(availableColumnSpace > 0 && index < string.length()) { - char c = string.charAt(index++); - availableColumnSpace -= TerminalTextUtils.isCharCJK(c) ? 2 : 1; - if(availableColumnSpace < 0) { - bob.append(' '); - } - else { - bob.append(c); - } - } - return bob.toString(); - } - - /** - * This method will calculate word wrappings given a number of lines of text and how wide the text can be printed. - * The result is a list of new rows where word-wrapping was applied. - * @param maxWidth Maximum number of columns that can be used before word-wrapping is applied, if <= 0 then the - * lines will be returned unchanged - * @param lines Input text - * @return The input text word-wrapped at {@code maxWidth}; this may contain more rows than the input text - */ - public static List getWordWrappedText(int maxWidth, String... lines) { - //Bounds checking - if(maxWidth <= 0) { - return Arrays.asList(lines); - } - - List result = new ArrayList(); - LinkedList linesToBeWrapped = new LinkedList(Arrays.asList(lines)); - while(!linesToBeWrapped.isEmpty()) { - String row = linesToBeWrapped.removeFirst(); - int rowWidth = getColumnWidth(row); - if(rowWidth <= maxWidth) { - result.add(row); - } - else { - //Now search in reverse and find the first possible line-break - final int characterIndexMax = getStringCharacterIndex(row, maxWidth); - int characterIndex = characterIndexMax; - while(characterIndex >= 0 && - !Character.isSpaceChar(row.charAt(characterIndex)) && - !isCharCJK(row.charAt(characterIndex))) { - characterIndex--; - } - // right *after* a CJK is also a "nice" spot to break the line! - if (characterIndex >= 0 && characterIndex < characterIndexMax && - isCharCJK(row.charAt(characterIndex))) { - characterIndex++; // with these conditions it fits! - } - - if(characterIndex < 0) { - //Failed! There was no 'nice' place to cut so just cut it at maxWidth - characterIndex = Math.max(characterIndexMax, 1); // at least 1 char - result.add(row.substring(0, characterIndex)); - linesToBeWrapped.addFirst(row.substring(characterIndex)); - } - else { - // characterIndex == 0 only happens, if either - // - first char is CJK and maxWidth==1 or - // - first char is whitespace - // either way: put it in row before break to prevent infinite loop. - characterIndex = Math.max( characterIndex, 1); // at least 1 char - - //Ok, split the row, add it to the result and continue processing the second half on a new line - result.add(row.substring(0, characterIndex)); - while(characterIndex < row.length() && - Character.isSpaceChar(row.charAt(characterIndex))) { - characterIndex++; - }; - if (characterIndex < row.length()) { // only if rest contains non-whitespace - linesToBeWrapped.addFirst(row.substring(characterIndex)); - } - } - } - } - return result; - } -} diff --git a/src/com/googlecode/lanterna/TextCharacter.java b/src/com/googlecode/lanterna/TextCharacter.java deleted file mode 100644 index b3762d7..0000000 --- a/src/com/googlecode/lanterna/TextCharacter.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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-2015 Martin - */ -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) { - - 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 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); - } - - @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 + '}'; - } -} diff --git a/src/com/googlecode/lanterna/TextColor.java b/src/com/googlecode/lanterna/TextColor.java deleted file mode 100644 index 3a2ea70..0000000 --- a/src/com/googlecode/lanterna/TextColor.java +++ /dev/null @@ -1,585 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna; - - -import java.awt.*; - -/** - * This is an abstract base class for terminal color definitions. Since there are different ways of specifying terminal - * colors, all with a different range of adoptions, this makes it possible to program an API against an implementation- - * agnostic color definition. Please remember when using colors that not all terminals and terminal emulators supports - * them. The 24-bit color mode is very unsupported, for example, and even the default Linux terminal doesn't support - * the 256-color indexed mode. - * - * @author Martin - */ -public interface TextColor { - /** - * Returns the byte sequence in between CSI and character 'm' that is used to enable this color as the foreground - * color on an ANSI-compatible terminal. - * @return Byte array out data to output in between of CSI and 'm' - */ - byte[] getForegroundSGRSequence(); - - /** - * Returns the byte sequence in between CSI and character 'm' that is used to enable this color as the background - * color on an ANSI-compatible terminal. - * @return Byte array out data to output in between of CSI and 'm' - */ - byte[] getBackgroundSGRSequence(); - - /** - * Converts this color to an AWT color object, assuming a standard VGA palette. - * @return TextColor as an AWT Color - */ - Color toColor(); - - /** - * This class represent classic ANSI colors that are likely to be very compatible with most terminal - * implementations. It is limited to 8 colors (plus the 'default' color) but as a norm, using bold mode (SGR code) - * will slightly alter the color, giving it a bit brighter tone, so in total this will give you 16 (+1) colors. - *

- * For more information, see http://en.wikipedia.org/wiki/File:Ansi.png - */ - enum ANSI implements TextColor { - BLACK((byte)0, 0, 0, 0), - RED((byte)1, 170, 0, 0), - GREEN((byte)2, 0, 170, 0), - YELLOW((byte)3, 170, 85, 0), - BLUE((byte)4, 0, 0, 170), - MAGENTA((byte)5, 170, 0, 170), - CYAN((byte)6, 0, 170, 170), - WHITE((byte)7, 170, 170, 170), - DEFAULT((byte)9, 0, 0, 0); - - private final byte index; - private final Color color; - - ANSI(byte index, int red, int green, int blue) { - this.index = index; - this.color = new Color(red, green, blue); - } - - @Override - public byte[] getForegroundSGRSequence() { - return new byte[] { (byte)'3', (byte)(48 + index)}; //48 is ascii code for '0' - } - - @Override - public byte[] getBackgroundSGRSequence() { - return new byte[] { (byte)'4', (byte)(48 + index)}; //48 is ascii code for '0' - } - - @Override - public Color toColor() { - return color; - } - } - - /** - * This class represents a color expressed in the indexed XTerm 256 color extension, where each color is defined in a - * lookup-table. All in all, there are 256 codes, but in order to know which one to know you either need to have the - * table at hand, or you can use the two static helper methods which can help you convert from three 8-bit - * RGB values to the closest approximate indexed color number. If you are interested, the 256 index values are - * actually divided like this:
- * 0 .. 15 - System colors, same as ANSI, but the actual rendered color depends on the terminal emulators color scheme
- * 16 .. 231 - Forms a 6x6x6 RGB color cube
- * 232 .. 255 - A gray scale ramp (without black and white endpoints)
- *

- * Support for indexed colors is somewhat widely adopted, not as much as the ANSI colors (TextColor.ANSI) but more - * than the RGB (TextColor.RGB). - *

- * For more details on this, please see - * this commit message to Konsole. - */ - class Indexed implements TextColor { - private static final byte[][] COLOR_TABLE = new byte[][] { - //These are the standard 16-color VGA palette entries - {(byte)0,(byte)0,(byte)0 }, - {(byte)170,(byte)0,(byte)0 }, - {(byte)0,(byte)170,(byte)0 }, - {(byte)170,(byte)85,(byte)0 }, - {(byte)0,(byte)0,(byte)170 }, - {(byte)170,(byte)0,(byte)170 }, - {(byte)0,(byte)170,(byte)170 }, - {(byte)170,(byte)170,(byte)170 }, - {(byte)85,(byte)85,(byte)85 }, - {(byte)255,(byte)85,(byte)85 }, - {(byte)85,(byte)255,(byte)85 }, - {(byte)255,(byte)255,(byte)85 }, - {(byte)85,(byte)85,(byte)255 }, - {(byte)255,(byte)85,(byte)255 }, - {(byte)85,(byte)255,(byte)255 }, - {(byte)255,(byte)255,(byte)255 }, - - //Starting 6x6x6 RGB color cube from 16 - {(byte)0x00,(byte)0x00,(byte)0x00 }, - {(byte)0x00,(byte)0x00,(byte)0x5f }, - {(byte)0x00,(byte)0x00,(byte)0x87 }, - {(byte)0x00,(byte)0x00,(byte)0xaf }, - {(byte)0x00,(byte)0x00,(byte)0xd7 }, - {(byte)0x00,(byte)0x00,(byte)0xff }, - {(byte)0x00,(byte)0x5f,(byte)0x00 }, - {(byte)0x00,(byte)0x5f,(byte)0x5f }, - {(byte)0x00,(byte)0x5f,(byte)0x87 }, - {(byte)0x00,(byte)0x5f,(byte)0xaf }, - {(byte)0x00,(byte)0x5f,(byte)0xd7 }, - {(byte)0x00,(byte)0x5f,(byte)0xff }, - {(byte)0x00,(byte)0x87,(byte)0x00 }, - {(byte)0x00,(byte)0x87,(byte)0x5f }, - {(byte)0x00,(byte)0x87,(byte)0x87 }, - {(byte)0x00,(byte)0x87,(byte)0xaf }, - {(byte)0x00,(byte)0x87,(byte)0xd7 }, - {(byte)0x00,(byte)0x87,(byte)0xff }, - {(byte)0x00,(byte)0xaf,(byte)0x00 }, - {(byte)0x00,(byte)0xaf,(byte)0x5f }, - {(byte)0x00,(byte)0xaf,(byte)0x87 }, - {(byte)0x00,(byte)0xaf,(byte)0xaf }, - {(byte)0x00,(byte)0xaf,(byte)0xd7 }, - {(byte)0x00,(byte)0xaf,(byte)0xff }, - {(byte)0x00,(byte)0xd7,(byte)0x00 }, - {(byte)0x00,(byte)0xd7,(byte)0x5f }, - {(byte)0x00,(byte)0xd7,(byte)0x87 }, - {(byte)0x00,(byte)0xd7,(byte)0xaf }, - {(byte)0x00,(byte)0xd7,(byte)0xd7 }, - {(byte)0x00,(byte)0xd7,(byte)0xff }, - {(byte)0x00,(byte)0xff,(byte)0x00 }, - {(byte)0x00,(byte)0xff,(byte)0x5f }, - {(byte)0x00,(byte)0xff,(byte)0x87 }, - {(byte)0x00,(byte)0xff,(byte)0xaf }, - {(byte)0x00,(byte)0xff,(byte)0xd7 }, - {(byte)0x00,(byte)0xff,(byte)0xff }, - {(byte)0x5f,(byte)0x00,(byte)0x00 }, - {(byte)0x5f,(byte)0x00,(byte)0x5f }, - {(byte)0x5f,(byte)0x00,(byte)0x87 }, - {(byte)0x5f,(byte)0x00,(byte)0xaf }, - {(byte)0x5f,(byte)0x00,(byte)0xd7 }, - {(byte)0x5f,(byte)0x00,(byte)0xff }, - {(byte)0x5f,(byte)0x5f,(byte)0x00 }, - {(byte)0x5f,(byte)0x5f,(byte)0x5f }, - {(byte)0x5f,(byte)0x5f,(byte)0x87 }, - {(byte)0x5f,(byte)0x5f,(byte)0xaf }, - {(byte)0x5f,(byte)0x5f,(byte)0xd7 }, - {(byte)0x5f,(byte)0x5f,(byte)0xff }, - {(byte)0x5f,(byte)0x87,(byte)0x00 }, - {(byte)0x5f,(byte)0x87,(byte)0x5f }, - {(byte)0x5f,(byte)0x87,(byte)0x87 }, - {(byte)0x5f,(byte)0x87,(byte)0xaf }, - {(byte)0x5f,(byte)0x87,(byte)0xd7 }, - {(byte)0x5f,(byte)0x87,(byte)0xff }, - {(byte)0x5f,(byte)0xaf,(byte)0x00 }, - {(byte)0x5f,(byte)0xaf,(byte)0x5f }, - {(byte)0x5f,(byte)0xaf,(byte)0x87 }, - {(byte)0x5f,(byte)0xaf,(byte)0xaf }, - {(byte)0x5f,(byte)0xaf,(byte)0xd7 }, - {(byte)0x5f,(byte)0xaf,(byte)0xff }, - {(byte)0x5f,(byte)0xd7,(byte)0x00 }, - {(byte)0x5f,(byte)0xd7,(byte)0x5f }, - {(byte)0x5f,(byte)0xd7,(byte)0x87 }, - {(byte)0x5f,(byte)0xd7,(byte)0xaf }, - {(byte)0x5f,(byte)0xd7,(byte)0xd7 }, - {(byte)0x5f,(byte)0xd7,(byte)0xff }, - {(byte)0x5f,(byte)0xff,(byte)0x00 }, - {(byte)0x5f,(byte)0xff,(byte)0x5f }, - {(byte)0x5f,(byte)0xff,(byte)0x87 }, - {(byte)0x5f,(byte)0xff,(byte)0xaf }, - {(byte)0x5f,(byte)0xff,(byte)0xd7 }, - {(byte)0x5f,(byte)0xff,(byte)0xff }, - {(byte)0x87,(byte)0x00,(byte)0x00 }, - {(byte)0x87,(byte)0x00,(byte)0x5f }, - {(byte)0x87,(byte)0x00,(byte)0x87 }, - {(byte)0x87,(byte)0x00,(byte)0xaf }, - {(byte)0x87,(byte)0x00,(byte)0xd7 }, - {(byte)0x87,(byte)0x00,(byte)0xff }, - {(byte)0x87,(byte)0x5f,(byte)0x00 }, - {(byte)0x87,(byte)0x5f,(byte)0x5f }, - {(byte)0x87,(byte)0x5f,(byte)0x87 }, - {(byte)0x87,(byte)0x5f,(byte)0xaf }, - {(byte)0x87,(byte)0x5f,(byte)0xd7 }, - {(byte)0x87,(byte)0x5f,(byte)0xff }, - {(byte)0x87,(byte)0x87,(byte)0x00 }, - {(byte)0x87,(byte)0x87,(byte)0x5f }, - {(byte)0x87,(byte)0x87,(byte)0x87 }, - {(byte)0x87,(byte)0x87,(byte)0xaf }, - {(byte)0x87,(byte)0x87,(byte)0xd7 }, - {(byte)0x87,(byte)0x87,(byte)0xff }, - {(byte)0x87,(byte)0xaf,(byte)0x00 }, - {(byte)0x87,(byte)0xaf,(byte)0x5f }, - {(byte)0x87,(byte)0xaf,(byte)0x87 }, - {(byte)0x87,(byte)0xaf,(byte)0xaf }, - {(byte)0x87,(byte)0xaf,(byte)0xd7 }, - {(byte)0x87,(byte)0xaf,(byte)0xff }, - {(byte)0x87,(byte)0xd7,(byte)0x00 }, - {(byte)0x87,(byte)0xd7,(byte)0x5f }, - {(byte)0x87,(byte)0xd7,(byte)0x87 }, - {(byte)0x87,(byte)0xd7,(byte)0xaf }, - {(byte)0x87,(byte)0xd7,(byte)0xd7 }, - {(byte)0x87,(byte)0xd7,(byte)0xff }, - {(byte)0x87,(byte)0xff,(byte)0x00 }, - {(byte)0x87,(byte)0xff,(byte)0x5f }, - {(byte)0x87,(byte)0xff,(byte)0x87 }, - {(byte)0x87,(byte)0xff,(byte)0xaf }, - {(byte)0x87,(byte)0xff,(byte)0xd7 }, - {(byte)0x87,(byte)0xff,(byte)0xff }, - {(byte)0xaf,(byte)0x00,(byte)0x00 }, - {(byte)0xaf,(byte)0x00,(byte)0x5f }, - {(byte)0xaf,(byte)0x00,(byte)0x87 }, - {(byte)0xaf,(byte)0x00,(byte)0xaf }, - {(byte)0xaf,(byte)0x00,(byte)0xd7 }, - {(byte)0xaf,(byte)0x00,(byte)0xff }, - {(byte)0xaf,(byte)0x5f,(byte)0x00 }, - {(byte)0xaf,(byte)0x5f,(byte)0x5f }, - {(byte)0xaf,(byte)0x5f,(byte)0x87 }, - {(byte)0xaf,(byte)0x5f,(byte)0xaf }, - {(byte)0xaf,(byte)0x5f,(byte)0xd7 }, - {(byte)0xaf,(byte)0x5f,(byte)0xff }, - {(byte)0xaf,(byte)0x87,(byte)0x00 }, - {(byte)0xaf,(byte)0x87,(byte)0x5f }, - {(byte)0xaf,(byte)0x87,(byte)0x87 }, - {(byte)0xaf,(byte)0x87,(byte)0xaf }, - {(byte)0xaf,(byte)0x87,(byte)0xd7 }, - {(byte)0xaf,(byte)0x87,(byte)0xff }, - {(byte)0xaf,(byte)0xaf,(byte)0x00 }, - {(byte)0xaf,(byte)0xaf,(byte)0x5f }, - {(byte)0xaf,(byte)0xaf,(byte)0x87 }, - {(byte)0xaf,(byte)0xaf,(byte)0xaf }, - {(byte)0xaf,(byte)0xaf,(byte)0xd7 }, - {(byte)0xaf,(byte)0xaf,(byte)0xff }, - {(byte)0xaf,(byte)0xd7,(byte)0x00 }, - {(byte)0xaf,(byte)0xd7,(byte)0x5f }, - {(byte)0xaf,(byte)0xd7,(byte)0x87 }, - {(byte)0xaf,(byte)0xd7,(byte)0xaf }, - {(byte)0xaf,(byte)0xd7,(byte)0xd7 }, - {(byte)0xaf,(byte)0xd7,(byte)0xff }, - {(byte)0xaf,(byte)0xff,(byte)0x00 }, - {(byte)0xaf,(byte)0xff,(byte)0x5f }, - {(byte)0xaf,(byte)0xff,(byte)0x87 }, - {(byte)0xaf,(byte)0xff,(byte)0xaf }, - {(byte)0xaf,(byte)0xff,(byte)0xd7 }, - {(byte)0xaf,(byte)0xff,(byte)0xff }, - {(byte)0xd7,(byte)0x00,(byte)0x00 }, - {(byte)0xd7,(byte)0x00,(byte)0x5f }, - {(byte)0xd7,(byte)0x00,(byte)0x87 }, - {(byte)0xd7,(byte)0x00,(byte)0xaf }, - {(byte)0xd7,(byte)0x00,(byte)0xd7 }, - {(byte)0xd7,(byte)0x00,(byte)0xff }, - {(byte)0xd7,(byte)0x5f,(byte)0x00 }, - {(byte)0xd7,(byte)0x5f,(byte)0x5f }, - {(byte)0xd7,(byte)0x5f,(byte)0x87 }, - {(byte)0xd7,(byte)0x5f,(byte)0xaf }, - {(byte)0xd7,(byte)0x5f,(byte)0xd7 }, - {(byte)0xd7,(byte)0x5f,(byte)0xff }, - {(byte)0xd7,(byte)0x87,(byte)0x00 }, - {(byte)0xd7,(byte)0x87,(byte)0x5f }, - {(byte)0xd7,(byte)0x87,(byte)0x87 }, - {(byte)0xd7,(byte)0x87,(byte)0xaf }, - {(byte)0xd7,(byte)0x87,(byte)0xd7 }, - {(byte)0xd7,(byte)0x87,(byte)0xff }, - {(byte)0xd7,(byte)0xaf,(byte)0x00 }, - {(byte)0xd7,(byte)0xaf,(byte)0x5f }, - {(byte)0xd7,(byte)0xaf,(byte)0x87 }, - {(byte)0xd7,(byte)0xaf,(byte)0xaf }, - {(byte)0xd7,(byte)0xaf,(byte)0xd7 }, - {(byte)0xd7,(byte)0xaf,(byte)0xff }, - {(byte)0xd7,(byte)0xd7,(byte)0x00 }, - {(byte)0xd7,(byte)0xd7,(byte)0x5f }, - {(byte)0xd7,(byte)0xd7,(byte)0x87 }, - {(byte)0xd7,(byte)0xd7,(byte)0xaf }, - {(byte)0xd7,(byte)0xd7,(byte)0xd7 }, - {(byte)0xd7,(byte)0xd7,(byte)0xff }, - {(byte)0xd7,(byte)0xff,(byte)0x00 }, - {(byte)0xd7,(byte)0xff,(byte)0x5f }, - {(byte)0xd7,(byte)0xff,(byte)0x87 }, - {(byte)0xd7,(byte)0xff,(byte)0xaf }, - {(byte)0xd7,(byte)0xff,(byte)0xd7 }, - {(byte)0xd7,(byte)0xff,(byte)0xff }, - {(byte)0xff,(byte)0x00,(byte)0x00 }, - {(byte)0xff,(byte)0x00,(byte)0x5f }, - {(byte)0xff,(byte)0x00,(byte)0x87 }, - {(byte)0xff,(byte)0x00,(byte)0xaf }, - {(byte)0xff,(byte)0x00,(byte)0xd7 }, - {(byte)0xff,(byte)0x00,(byte)0xff }, - {(byte)0xff,(byte)0x5f,(byte)0x00 }, - {(byte)0xff,(byte)0x5f,(byte)0x5f }, - {(byte)0xff,(byte)0x5f,(byte)0x87 }, - {(byte)0xff,(byte)0x5f,(byte)0xaf }, - {(byte)0xff,(byte)0x5f,(byte)0xd7 }, - {(byte)0xff,(byte)0x5f,(byte)0xff }, - {(byte)0xff,(byte)0x87,(byte)0x00 }, - {(byte)0xff,(byte)0x87,(byte)0x5f }, - {(byte)0xff,(byte)0x87,(byte)0x87 }, - {(byte)0xff,(byte)0x87,(byte)0xaf }, - {(byte)0xff,(byte)0x87,(byte)0xd7 }, - {(byte)0xff,(byte)0x87,(byte)0xff }, - {(byte)0xff,(byte)0xaf,(byte)0x00 }, - {(byte)0xff,(byte)0xaf,(byte)0x5f }, - {(byte)0xff,(byte)0xaf,(byte)0x87 }, - {(byte)0xff,(byte)0xaf,(byte)0xaf }, - {(byte)0xff,(byte)0xaf,(byte)0xd7 }, - {(byte)0xff,(byte)0xaf,(byte)0xff }, - {(byte)0xff,(byte)0xd7,(byte)0x00 }, - {(byte)0xff,(byte)0xd7,(byte)0x5f }, - {(byte)0xff,(byte)0xd7,(byte)0x87 }, - {(byte)0xff,(byte)0xd7,(byte)0xaf }, - {(byte)0xff,(byte)0xd7,(byte)0xd7 }, - {(byte)0xff,(byte)0xd7,(byte)0xff }, - {(byte)0xff,(byte)0xff,(byte)0x00 }, - {(byte)0xff,(byte)0xff,(byte)0x5f }, - {(byte)0xff,(byte)0xff,(byte)0x87 }, - {(byte)0xff,(byte)0xff,(byte)0xaf }, - {(byte)0xff,(byte)0xff,(byte)0xd7 }, - {(byte)0xff,(byte)0xff,(byte)0xff }, - - //Grey-scale ramp from 232 - {(byte)0x08,(byte)0x08,(byte)0x08 }, - {(byte)0x12,(byte)0x12,(byte)0x12 }, - {(byte)0x1c,(byte)0x1c,(byte)0x1c }, - {(byte)0x26,(byte)0x26,(byte)0x26 }, - {(byte)0x30,(byte)0x30,(byte)0x30 }, - {(byte)0x3a,(byte)0x3a,(byte)0x3a }, - {(byte)0x44,(byte)0x44,(byte)0x44 }, - {(byte)0x4e,(byte)0x4e,(byte)0x4e }, - {(byte)0x58,(byte)0x58,(byte)0x58 }, - {(byte)0x62,(byte)0x62,(byte)0x62 }, - {(byte)0x6c,(byte)0x6c,(byte)0x6c }, - {(byte)0x76,(byte)0x76,(byte)0x76 }, - {(byte)0x80,(byte)0x80,(byte)0x80 }, - {(byte)0x8a,(byte)0x8a,(byte)0x8a }, - {(byte)0x94,(byte)0x94,(byte)0x94 }, - {(byte)0x9e,(byte)0x9e,(byte)0x9e }, - {(byte)0xa8,(byte)0xa8,(byte)0xa8 }, - {(byte)0xb2,(byte)0xb2,(byte)0xb2 }, - {(byte)0xbc,(byte)0xbc,(byte)0xbc }, - {(byte)0xc6,(byte)0xc6,(byte)0xc6 }, - {(byte)0xd0,(byte)0xd0,(byte)0xd0 }, - {(byte)0xda,(byte)0xda,(byte)0xda }, - {(byte)0xe4,(byte)0xe4,(byte)0xe4 }, - {(byte)0xee,(byte)0xee,(byte)0xee } - }; - - private final int colorIndex; - private final Color awtColor; - - /** - * Creates a new TextColor using the XTerm 256 color indexed mode, with the specified index value. You must - * choose a value between 0 and 255. - * @param colorIndex Index value to use for this color. - */ - public Indexed(int colorIndex) { - if(colorIndex > 255 || colorIndex < 0) { - throw new IllegalArgumentException("Cannot create a Color.Indexed with a color index of " + colorIndex + - ", must be in the range of 0-255"); - } - this.colorIndex = colorIndex; - this.awtColor = new Color(COLOR_TABLE[colorIndex][0] & 0x000000ff, - COLOR_TABLE[colorIndex][1] & 0x000000ff, - COLOR_TABLE[colorIndex][2] & 0x000000ff); - } - - @Override - public byte[] getForegroundSGRSequence() { - return ("38;5;" + colorIndex).getBytes(); - } - - @Override - public byte[] getBackgroundSGRSequence() { - return ("48;5;" + colorIndex).getBytes(); - } - - @Override - public Color toColor() { - return awtColor; - } - - @Override - public String toString() { - return "{IndexedColor:" + colorIndex + "}"; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 43 * hash + this.colorIndex; - return hash; - } - - @Override - public boolean equals(Object obj) { - if(obj == null) { - return false; - } - if(getClass() != obj.getClass()) { - return false; - } - final Indexed other = (Indexed) obj; - return this.colorIndex == other.colorIndex; - } - - /** - * Picks out a color approximated from the supplied RGB components - * @param red Red intensity, from 0 to 255 - * @param green Red intensity, from 0 to 255 - * @param blue Red intensity, from 0 to 255 - * @return Nearest color from the 6x6x6 RGB color cube or from the 24 entries grey-scale ramp (whichever is closest) - */ - public static Indexed fromRGB(int red, int green, int blue) { - if(red < 0 || red > 255) { - throw new IllegalArgumentException("fromRGB: red is outside of valid range (0-255)"); - } - if(green < 0 || green > 255) { - throw new IllegalArgumentException("fromRGB: green is outside of valid range (0-255)"); - } - if(blue < 0 || blue > 255) { - throw new IllegalArgumentException("fromRGB: blue is outside of valid range (0-255)"); - } - - int rescaledRed = (int)(((double)red / 255.0) * 5.0); - int rescaledGreen = (int)(((double)green / 255.0) * 5.0); - int rescaledBlue = (int)(((double)blue / 255.0) * 5.0); - - int index = rescaledBlue + (6 * rescaledGreen) + (36 * rescaledRed) + 16; - Indexed fromColorCube = new Indexed(index); - Indexed fromGreyRamp = fromGreyRamp((red + green + blue) / 3); - - //Now figure out which one is closest - Color colored = fromColorCube.toColor(); - Color grey = fromGreyRamp.toColor(); - int coloredDistance = ((red - colored.getRed()) * (red - colored.getRed())) + - ((green - colored.getGreen()) * (green - colored.getGreen())) + - ((blue - colored.getBlue()) * (blue - colored.getBlue())); - int greyDistance = ((red - grey.getRed()) * (red - grey.getRed())) + - ((green - grey.getGreen()) * (green - grey.getGreen())) + - ((blue - grey.getBlue()) * (blue - grey.getBlue())); - if(coloredDistance < greyDistance) { - return fromColorCube; - } - else { - return fromGreyRamp; - } - } - - /** - * Picks out a color from the grey-scale ramp area of the color index. - * @param intensity Intensity, 0 - 255 - * @return Indexed color from the grey-scale ramp which is the best match for the supplied intensity - */ - private static Indexed fromGreyRamp(int intensity) { - int rescaled = (int)(((double)intensity / 255.0) * 23.0) + 232; - return new Indexed(rescaled); - } - } - - /** - * This class can be used to specify a color in 24-bit color space (RGB with 8-bit resolution per color). Please be - * aware that only a few terminal support 24-bit color control codes, please avoid using this class unless you know - * all users will have compatible terminals. For details, please see - * - * this commit log. Behavior on terminals that don't support these codes is undefined. - */ - class RGB implements TextColor { - private final Color color; - - /** - * This class can be used to specify a color in 24-bit color space (RGB with 8-bit resolution per color). Please be - * aware that only a few terminal support 24-bit color control codes, please avoid using this class unless you know - * all users will have compatible terminals. For details, please see - * - * this commit log. Behavior on terminals that don't support these codes is undefined. - * - * @param r Red intensity, from 0 to 255 - * @param g Green intensity, from 0 to 255 - * @param b Blue intensity, from 0 to 255 - */ - public RGB(int r, int g, int b) { - if(r < 0 || r > 255) { - throw new IllegalArgumentException("RGB: r is outside of valid range (0-255)"); - } - if(g < 0 || g > 255) { - throw new IllegalArgumentException("RGB: g is outside of valid range (0-255)"); - } - if(b < 0 || b > 255) { - throw new IllegalArgumentException("RGB: b is outside of valid range (0-255)"); - } - this.color = new Color(r, g, b); - } - - @Override - public byte[] getForegroundSGRSequence() { - return ("38;2;" + getRed() + ";" + getGreen() + ";" + getBlue()).getBytes(); - } - - @Override - public byte[] getBackgroundSGRSequence() { - return ("48;2;" + getRed() + ";" + getGreen() + ";" + getBlue()).getBytes(); - } - - @Override - public Color toColor() { - return color; - } - - /** - * @return Red intensity of this color, from 0 to 255 - */ - public int getRed() { - return color.getRed(); - } - - /** - * @return Green intensity of this color, from 0 to 255 - */ - public int getGreen() { - return color.getGreen(); - } - - /** - * @return Blue intensity of this color, from 0 to 255 - */ - public int getBlue() { - return color.getBlue(); - } - - @Override - public String toString() { - return "{RGB:" + getRed() + "," + getGreen() + "," + getBlue() + "}"; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 29 * hash + color.hashCode(); - return hash; - } - - @SuppressWarnings("SimplifiableIfStatement") - @Override - public boolean equals(Object obj) { - if(obj == null) { - return false; - } - if(getClass() != obj.getClass()) { - return false; - } - final RGB other = (RGB) obj; - return color.equals(other.color); - } - } -} diff --git a/src/com/googlecode/lanterna/bundle/BundleLocator.java b/src/com/googlecode/lanterna/bundle/BundleLocator.java deleted file mode 100644 index 9df44de..0000000 --- a/src/com/googlecode/lanterna/bundle/BundleLocator.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.googlecode.lanterna.bundle; - -import java.security.PrivilegedAction; -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.ResourceBundle; - -/** - * This class permits to deal easily with bundles. - * @author silveryocha - */ -public abstract class BundleLocator { - - private final String bundleName; - private static final ClassLoader loader = BundleLocator.class.getClassLoader(); - - /** - * Hidden constructor. - * @param bundleName the name of the bundle. - */ - protected BundleLocator(final String bundleName) { - this.bundleName = bundleName; - } - - /** - * Method that centralizes the way to get the value associated to a bundle key. - * @param locale the locale. - * @param key the key searched for. - * @param parameters the parameters to apply to the value associated to the key. - * @return the formatted value associated to the given key. Empty string if no value exists for - * the given key. - */ - protected String getBundleKeyValue(Locale locale, String key, Object... parameters) { - String value = null; - try { - value = getBundle(locale).getString(key); - } catch (Exception ignore) { - } - return value != null ? MessageFormat.format(value, parameters) : null; - } - - /** - * Gets the right bundle.
- * A cache is handled as well as the concurrent accesses. - * @param locale the locale. - * @return the instance of the bundle. - */ - private ResourceBundle getBundle(Locale locale) { - return ResourceBundle.getBundle(bundleName, locale, loader); - } -} diff --git a/src/com/googlecode/lanterna/bundle/LocalizedUIBundle.java b/src/com/googlecode/lanterna/bundle/LocalizedUIBundle.java deleted file mode 100644 index a1021af..0000000 --- a/src/com/googlecode/lanterna/bundle/LocalizedUIBundle.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.googlecode.lanterna.bundle; - -import java.util.Locale; - -/** - * This class permits to get easily localized strings about the UI. - * @author silveryocha - */ -public class LocalizedUIBundle extends BundleLocator { - - private static final LocalizedUIBundle MY_BUNDLE = new LocalizedUIBundle("multilang.lanterna-ui"); - - public static String get(String key, String... parameters) { - return get(Locale.getDefault(), key, parameters); - } - - public static String get(Locale locale, String key, String... parameters) { - return MY_BUNDLE.getBundleKeyValue(locale, key, (Object[])parameters); - } - - private LocalizedUIBundle(final String bundleName) { - super(bundleName); - } -} diff --git a/src/com/googlecode/lanterna/graphics/AbstractTextGraphics.java b/src/com/googlecode/lanterna/graphics/AbstractTextGraphics.java deleted file mode 100644 index e44aa0f..0000000 --- a/src/com/googlecode/lanterna/graphics/AbstractTextGraphics.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.*; -import com.googlecode.lanterna.screen.TabBehaviour; - -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; - -/** - * This class hold the default logic for drawing the basic text graphic as exposed by TextGraphic. All implementations - * rely on a setCharacter method being implemented in subclasses. - * @author Martin - */ -public abstract class AbstractTextGraphics implements TextGraphics { - protected TextColor foregroundColor; - protected TextColor backgroundColor; - protected TabBehaviour tabBehaviour; - protected final EnumSet activeModifiers; - private final ShapeRenderer shapeRenderer; - - protected AbstractTextGraphics() { - this.activeModifiers = EnumSet.noneOf(SGR.class); - this.tabBehaviour = TabBehaviour.ALIGN_TO_COLUMN_4; - this.foregroundColor = TextColor.ANSI.DEFAULT; - this.backgroundColor = TextColor.ANSI.DEFAULT; - this.shapeRenderer = new DefaultShapeRenderer(new DefaultShapeRenderer.Callback() { - @Override - public void onPoint(int column, int row, TextCharacter character) { - setCharacter(column, row, character); - } - }); - } - - @Override - public TextColor getBackgroundColor() { - return backgroundColor; - } - - @Override - public TextGraphics setBackgroundColor(final TextColor backgroundColor) { - this.backgroundColor = backgroundColor; - return this; - } - - @Override - public TextColor getForegroundColor() { - return foregroundColor; - } - - @Override - public TextGraphics setForegroundColor(final TextColor foregroundColor) { - this.foregroundColor = foregroundColor; - return this; - } - - @Override - public TextGraphics enableModifiers(SGR... modifiers) { - enableModifiers(Arrays.asList(modifiers)); - return this; - } - - private void enableModifiers(Collection modifiers) { - this.activeModifiers.addAll(modifiers); - } - - @Override - public TextGraphics disableModifiers(SGR... modifiers) { - disableModifiers(Arrays.asList(modifiers)); - return this; - } - - private void disableModifiers(Collection modifiers) { - this.activeModifiers.removeAll(modifiers); - } - - @Override - public synchronized TextGraphics setModifiers(EnumSet modifiers) { - activeModifiers.clear(); - activeModifiers.addAll(modifiers); - return this; - } - - @Override - public TextGraphics clearModifiers() { - this.activeModifiers.clear(); - return this; - } - - @Override - public EnumSet getActiveModifiers() { - return activeModifiers; - } - - @Override - public TabBehaviour getTabBehaviour() { - return tabBehaviour; - } - - @Override - public TextGraphics setTabBehaviour(TabBehaviour tabBehaviour) { - if(tabBehaviour != null) { - this.tabBehaviour = tabBehaviour; - } - return this; - } - - @Override - public TextGraphics fill(char c) { - fillRectangle(TerminalPosition.TOP_LEFT_CORNER, getSize(), c); - return this; - } - - @Override - public TextGraphics setCharacter(int column, int row, char character) { - return setCharacter(column, row, newTextCharacter(character)); - } - - @Override - public TextGraphics setCharacter(TerminalPosition position, TextCharacter textCharacter) { - setCharacter(position.getColumn(), position.getRow(), textCharacter); - return this; - } - - @Override - public TextGraphics setCharacter(TerminalPosition position, char character) { - return setCharacter(position.getColumn(), position.getRow(), character); - } - - @Override - public TextGraphics drawLine(TerminalPosition fromPosition, TerminalPosition toPoint, char character) { - return drawLine(fromPosition, toPoint, newTextCharacter(character)); - } - - @Override - public TextGraphics drawLine(TerminalPosition fromPoint, TerminalPosition toPoint, TextCharacter character) { - shapeRenderer.drawLine(fromPoint, toPoint, character); - return this; - } - - @Override - public TextGraphics drawLine(int fromX, int fromY, int toX, int toY, char character) { - return drawLine(fromX, fromY, toX, toY, newTextCharacter(character)); - } - - @Override - public TextGraphics drawLine(int fromX, int fromY, int toX, int toY, TextCharacter character) { - return drawLine(new TerminalPosition(fromX, fromY), new TerminalPosition(toX, toY), character); - } - - @Override - public TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character) { - return drawTriangle(p1, p2, p3, newTextCharacter(character)); - } - - @Override - public TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - shapeRenderer.drawTriangle(p1, p2, p3, character); - return this; - } - - @Override - public TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character) { - return fillTriangle(p1, p2, p3, newTextCharacter(character)); - } - - @Override - public TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - shapeRenderer.fillTriangle(p1, p2, p3, character); - return this; - } - - @Override - public TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, char character) { - return drawRectangle(topLeft, size, newTextCharacter(character)); - } - - @Override - public TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - shapeRenderer.drawRectangle(topLeft, size, character); - return this; - } - - @Override - public TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, char character) { - return fillRectangle(topLeft, size, newTextCharacter(character)); - } - - @Override - public TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - shapeRenderer.fillRectangle(topLeft, size, character); - return this; - } - - @Override - public TextGraphics drawImage(TerminalPosition topLeft, TextImage image) { - return drawImage(topLeft, image, TerminalPosition.TOP_LEFT_CORNER, image.getSize()); - } - - @Override - public TextGraphics drawImage( - TerminalPosition topLeft, - TextImage image, - TerminalPosition sourceImageTopLeft, - TerminalSize sourceImageSize) { - - // If the source image position is negative, offset the whole image - if(sourceImageTopLeft.getColumn() < 0) { - topLeft = topLeft.withRelativeColumn(-sourceImageTopLeft.getColumn()); - sourceImageSize = sourceImageSize.withRelativeColumns(sourceImageTopLeft.getColumn()); - sourceImageTopLeft = sourceImageTopLeft.withColumn(0); - } - if(sourceImageTopLeft.getRow() < 0) { - topLeft = topLeft.withRelativeRow(-sourceImageTopLeft.getRow()); - sourceImageSize = sourceImageSize.withRelativeRows(sourceImageTopLeft.getRow()); - sourceImageTopLeft = sourceImageTopLeft.withRow(0); - } - - // cropping specified image-subrectangle to the image itself: - int fromRow = Math.max(sourceImageTopLeft.getRow(), 0); - int untilRow = Math.min(sourceImageTopLeft.getRow() + sourceImageSize.getRows(), image.getSize().getRows()); - int fromColumn = Math.max(sourceImageTopLeft.getColumn(), 0); - int untilColumn = Math.min(sourceImageTopLeft.getColumn() + sourceImageSize.getColumns(), image.getSize().getColumns()); - - // difference between position in image and position on target: - int diffRow = topLeft.getRow() - sourceImageTopLeft.getRow(); - int diffColumn = topLeft.getColumn() - sourceImageTopLeft.getColumn(); - - // top/left-crop at target(TextGraphics) rectangle: (only matters, if topLeft has a negative coordinate) - fromRow = Math.max(fromRow, -diffRow); - fromColumn = Math.max(fromColumn, -diffColumn); - - // bot/right-crop at target(TextGraphics) rectangle: (only matters, if topLeft has a negative coordinate) - untilRow = Math.min(untilRow, getSize().getRows() - diffRow); - untilColumn = Math.min(untilColumn, getSize().getColumns() - diffColumn); - - if (fromRow >= untilRow || fromColumn >= untilColumn) { - return this; - } - for (int row = fromRow; row < untilRow; row++) { - for (int column = fromColumn; column < untilColumn; column++) { - setCharacter(column + diffColumn, row + diffRow, image.getCharacterAt(column, row)); - } - } - return this; - } - - @Override - public TextGraphics putString(int column, int row, String string) { - if(string.contains("\n")) { - string = string.substring(0, string.indexOf("\n")); - } - if(string.contains("\r")) { - string = string.substring(0, string.indexOf("\r")); - } - string = tabBehaviour.replaceTabs(string, column); - int offset = 0; - for(int i = 0; i < string.length(); i++) { - char character = string.charAt(i); - setCharacter( - column + offset, - row, - new TextCharacter( - character, - foregroundColor, - backgroundColor, - activeModifiers.clone())); - - if(TerminalTextUtils.isCharCJK(character)) { - //CJK characters are twice the normal characters in width, so next character position is two columns forward - offset += 2; - } - else { - //For "normal" characters we advance to the next column - offset += 1; - } - } - return this; - } - - @Override - public TextGraphics putString(TerminalPosition position, String string) { - putString(position.getColumn(), position.getRow(), string); - return this; - } - - @Override - public TextGraphics putString(int column, int row, String string, SGR extraModifier, SGR... optionalExtraModifiers) {clearModifiers(); - return putString(column, row, string, EnumSet.of(extraModifier, optionalExtraModifiers)); - } - - @Override - public TextGraphics putString(int column, int row, String string, Collection extraModifiers) { - extraModifiers.removeAll(activeModifiers); - enableModifiers(extraModifiers); - putString(column, row, string); - disableModifiers(extraModifiers); - return this; - } - - @Override - public TextGraphics putString(TerminalPosition position, String string, SGR extraModifier, SGR... optionalExtraModifiers) { - putString(position.getColumn(), position.getRow(), string, extraModifier, optionalExtraModifiers); - return this; - } - - @Override - public TextCharacter getCharacter(TerminalPosition position) { - return getCharacter(position.getColumn(), position.getRow()); - } - - @Override - public TextGraphics newTextGraphics(TerminalPosition topLeftCorner, TerminalSize size) throws IllegalArgumentException { - TerminalSize writableArea = getSize(); - if(topLeftCorner.getColumn() + size.getColumns() <= 0 || - topLeftCorner.getColumn() >= writableArea.getColumns() || - topLeftCorner.getRow() + size.getRows() <= 0 || - topLeftCorner.getRow() >= writableArea.getRows()) { - //The area selected is completely outside of this TextGraphics, so we can return a "null" object that doesn't - //do anything because it is impossible to change anything anyway - return new NullTextGraphics(size); - } - return new SubTextGraphics(this, topLeftCorner, size); - } - - private TextCharacter newTextCharacter(char character) { - return new TextCharacter(character, foregroundColor, backgroundColor, activeModifiers); - } -} diff --git a/src/com/googlecode/lanterna/graphics/BasicTextImage.java b/src/com/googlecode/lanterna/graphics/BasicTextImage.java deleted file mode 100644 index 29ffd38..0000000 --- a/src/com/googlecode/lanterna/graphics/BasicTextImage.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import java.util.Arrays; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.TextCharacter; -import com.googlecode.lanterna.TextColor; - -/** - * Simple implementation of TextImage that keeps the content as a two-dimensional TextCharacter array. Copy operations - * between two BasicTextImage classes are semi-optimized by using System.arraycopy instead of iterating over each - * character and copying them over one by one. - * @author martin - */ -public class BasicTextImage implements TextImage { - private final TerminalSize size; - private final TextCharacter[][] buffer; - - /** - * Creates a new BasicTextImage with the specified size and fills it initially with space characters using the - * default foreground and background color - * @param columns Size of the image in number of columns - * @param rows Size of the image in number of rows - */ - public BasicTextImage(int columns, int rows) { - this(new TerminalSize(columns, rows)); - } - - /** - * Creates a new BasicTextImage with the specified size and fills it initially with space characters using the - * default foreground and background color - * @param size Size to make the image - */ - public BasicTextImage(TerminalSize size) { - this(size, new TextCharacter(' ', TextColor.ANSI.DEFAULT, TextColor.ANSI.DEFAULT)); - } - - /** - * Creates a new BasicTextImage with a given size and a TextCharacter to initially fill it with - * @param size Size of the image - * @param initialContent What character to set as the initial content - */ - public BasicTextImage(TerminalSize size, TextCharacter initialContent) { - this(size, new TextCharacter[0][], initialContent); - } - - /** - * Creates a new BasicTextImage by copying a region of a two-dimensional array of TextCharacter:s. If the area to be - * copied to larger than the source array, a filler character is used. - * @param size Size to create the new BasicTextImage as (and size to copy from the array) - * @param toCopy Array to copy initial data from - * @param initialContent Filler character to use if the source array is smaller than the requested size - */ - private BasicTextImage(TerminalSize size, TextCharacter[][] toCopy, TextCharacter initialContent) { - if(size == null || toCopy == null || initialContent == null) { - throw new IllegalArgumentException("Cannot create BasicTextImage with null " + - (size == null ? "size" : (toCopy == null ? "toCopy" : "filler"))); - } - this.size = size; - - int rows = size.getRows(); - int columns = size.getColumns(); - buffer = new TextCharacter[rows][]; - for(int y = 0; y < rows; y++) { - buffer[y] = new TextCharacter[columns]; - for(int x = 0; x < columns; x++) { - if(y < toCopy.length && x < toCopy[y].length) { - buffer[y][x] = toCopy[y][x]; - } - else { - buffer[y][x] = initialContent; - } - } - } - } - - @Override - public TerminalSize getSize() { - return size; - } - - @Override - public void setAll(TextCharacter character) { - if(character == null) { - throw new IllegalArgumentException("Cannot call BasicTextImage.setAll(..) with null character"); - } - for(TextCharacter[] line : buffer) { - Arrays.fill(line, character); - } - } - - @Override - public BasicTextImage resize(TerminalSize newSize, TextCharacter filler) { - if(newSize == null || filler == null) { - throw new IllegalArgumentException("Cannot resize BasicTextImage with null " + - (newSize == null ? "newSize" : "filler")); - } - if(newSize.getRows() == buffer.length && - (buffer.length == 0 || newSize.getColumns() == buffer[0].length)) { - return this; - } - return new BasicTextImage(newSize, buffer, filler); - } - - @Override - public void setCharacterAt(TerminalPosition position, TextCharacter character) { - if(position == null) { - throw new IllegalArgumentException("Cannot call BasicTextImage.setCharacterAt(..) with null position"); - } - setCharacterAt(position.getColumn(), position.getRow(), character); - } - - @Override - public void setCharacterAt(int column, int row, TextCharacter character) { - if(character == null) { - throw new IllegalArgumentException("Cannot call BasicTextImage.setCharacterAt(..) with null character"); - } - if(column < 0 || row < 0 || row >= buffer.length || column >= buffer[0].length) { - return; - } - - buffer[row][column] = character; - } - - @Override - public TextCharacter getCharacterAt(TerminalPosition position) { - if(position == null) { - throw new IllegalArgumentException("Cannot call BasicTextImage.getCharacterAt(..) with null position"); - } - return getCharacterAt(position.getColumn(), position.getRow()); - } - - @Override - public TextCharacter getCharacterAt(int column, int row) { - if(column < 0 || row < 0 || row >= buffer.length || column >= buffer[0].length) { - return null; - } - - return buffer[row][column]; - } - - @Override - public void copyTo(TextImage destination) { - copyTo(destination, 0, buffer.length, 0, buffer[0].length, 0, 0); - } - - @Override - public void copyTo( - TextImage destination, - int startRowIndex, - int rows, - int startColumnIndex, - int columns, - int destinationRowOffset, - int destinationColumnOffset) { - - // If the source image position is negative, offset the whole image - if(startColumnIndex < 0) { - destinationColumnOffset += -startColumnIndex; - columns += startColumnIndex; - startColumnIndex = 0; - } - if(startRowIndex < 0) { - startRowIndex += -startRowIndex; - rows = startRowIndex; - startRowIndex = 0; - } - - // If the destination offset is negative, adjust the source start indexes - if(destinationColumnOffset < 0) { - startColumnIndex -= destinationColumnOffset; - columns += destinationColumnOffset; - destinationColumnOffset = 0; - } - if(destinationRowOffset < 0) { - startRowIndex -= destinationRowOffset; - rows += destinationRowOffset; - destinationRowOffset = 0; - } - - //Make sure we can't copy more than is available - columns = Math.min(buffer[0].length - startColumnIndex, columns); - rows = Math.min(buffer.length - startRowIndex, rows); - - //Adjust target lengths as well - columns = Math.min(destination.getSize().getColumns() - destinationColumnOffset, columns); - rows = Math.min(destination.getSize().getRows() - destinationRowOffset, rows); - - if(columns <= 0 || rows <= 0) { - return; - } - - TerminalSize destinationSize = destination.getSize(); - if(destination instanceof BasicTextImage) { - int targetRow = destinationRowOffset; - for(int y = startRowIndex; y < startRowIndex + rows && targetRow < destinationSize.getRows(); y++) { - System.arraycopy(buffer[y], startColumnIndex, ((BasicTextImage)destination).buffer[targetRow++], destinationColumnOffset, columns); - } - } - else { - //Manually copy character by character - for(int y = startRowIndex; y < startRowIndex + rows; y++) { - for(int x = startColumnIndex; x < startColumnIndex + columns; x++) { - destination.setCharacterAt( - x - startColumnIndex + destinationColumnOffset, - y - startRowIndex + destinationRowOffset, - buffer[y][x]); - } - } - } - } - - @Override - public TextGraphics newTextGraphics() { - return new AbstractTextGraphics() { - @Override - public TextGraphics setCharacter(int columnIndex, int rowIndex, TextCharacter textCharacter) { - BasicTextImage.this.setCharacterAt(columnIndex, rowIndex, textCharacter); - return this; - } - - @Override - public TextCharacter getCharacter(int column, int row) { - return BasicTextImage.this.getCharacterAt(column, row); - } - - @Override - public TerminalSize getSize() { - return size; - } - }; - } - - private TextCharacter[] newBlankLine() { - TextCharacter[] line = new TextCharacter[size.getColumns()]; - Arrays.fill(line, TextCharacter.DEFAULT_CHARACTER); - return line; - } - - @Override - public void scrollLines(int firstLine, int lastLine, int distance) { - if (firstLine < 0) { firstLine = 0; } - if (lastLine >= size.getRows()) { lastLine = size.getRows() - 1; } - if (firstLine < lastLine) { - if (distance > 0) { - // scrolling up: start with first line as target: - int curLine = firstLine; - // copy lines from further "below": - for (; curLine <= lastLine - distance; curLine++) { - buffer[curLine] = buffer[curLine+distance]; - } - // blank out the remaining lines: - for (; curLine <= lastLine; curLine++) { - buffer[curLine] = newBlankLine(); - } - } - else if (distance < 0) { - // scrolling down: start with last line as target: - int curLine = lastLine; distance = -distance; - // copy lines from further "above": - for (; curLine >= firstLine + distance; curLine--) { - buffer[curLine] = buffer[curLine-distance]; - } - // blank out the remaining lines: - for (; curLine >= firstLine; curLine--) { - buffer[curLine] = newBlankLine(); - } - } /* else: distance == 0 => no-op */ - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(size.getRows()*(size.getColumns()+1)+50); - sb.append('{').append(size.getColumns()).append('x').append(size.getRows()).append('}').append('\n'); - for (TextCharacter[] line : buffer) { - for (TextCharacter tc : line) { - sb.append(tc.getCharacter()); - } - sb.append('\n'); - } - return sb.toString(); - } -} diff --git a/src/com/googlecode/lanterna/graphics/DefaultShapeRenderer.java b/src/com/googlecode/lanterna/graphics/DefaultShapeRenderer.java deleted file mode 100644 index 0908b3a..0000000 --- a/src/com/googlecode/lanterna/graphics/DefaultShapeRenderer.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.TextCharacter; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * Default implementation of ShapeRenderer. This class (and the interface) is mostly here to make the code cleaner in - * {@code AbstractTextGraphics}. - * @author Martin - */ -class DefaultShapeRenderer implements ShapeRenderer { - interface Callback { - void onPoint(int column, int row, TextCharacter character); - } - - private final Callback callback; - - DefaultShapeRenderer(Callback callback) { - this.callback = callback; - } - - @Override - public void drawLine(TerminalPosition p1, TerminalPosition p2, TextCharacter character) { - //http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm - //Implementation from Graphics Programming Black Book by Michael Abrash - //Available at http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/graphics-programming-black-book-r1698 - if(p1.getRow() > p2.getRow()) { - TerminalPosition temp = p1; - p1 = p2; - p2 = temp; - } - int deltaX = p2.getColumn() - p1.getColumn(); - int deltaY = p2.getRow() - p1.getRow(); - if(deltaX > 0) { - if(deltaX > deltaY) { - drawLine0(p1, deltaX, deltaY, true, character); - } - else { - drawLine1(p1, deltaX, deltaY, true, character); - } - } - else { - deltaX = Math.abs(deltaX); - if(deltaX > deltaY) { - drawLine0(p1, deltaX, deltaY, false, character); - } - else { - drawLine1(p1, deltaX, deltaY, false, character); - } - } - } - - private void drawLine0(TerminalPosition start, int deltaX, int deltaY, boolean leftToRight, TextCharacter character) { - int x = start.getColumn(); - int y = start.getRow(); - int deltaYx2 = deltaY * 2; - int deltaYx2MinusDeltaXx2 = deltaYx2 - (deltaX * 2); - int errorTerm = deltaYx2 - deltaX; - callback.onPoint(x, y, character); - while(deltaX-- > 0) { - if(errorTerm >= 0) { - y++; - errorTerm += deltaYx2MinusDeltaXx2; - } - else { - errorTerm += deltaYx2; - } - x += leftToRight ? 1 : -1; - callback.onPoint(x, y, character); - } - } - - private void drawLine1(TerminalPosition start, int deltaX, int deltaY, boolean leftToRight, TextCharacter character) { - int x = start.getColumn(); - int y = start.getRow(); - int deltaXx2 = deltaX * 2; - int deltaXx2MinusDeltaYx2 = deltaXx2 - (deltaY * 2); - int errorTerm = deltaXx2 - deltaY; - callback.onPoint(x, y, character); - while(deltaY-- > 0) { - if(errorTerm >= 0) { - x += leftToRight ? 1 : -1; - errorTerm += deltaXx2MinusDeltaYx2; - } - else { - errorTerm += deltaXx2; - } - y++; - callback.onPoint(x, y, character); - } - } - - @Override - public void drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - drawLine(p1, p2, character); - drawLine(p2, p3, character); - drawLine(p3, p1, character); - } - - @Override - public void drawRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - TerminalPosition topRight = topLeft.withRelativeColumn(size.getColumns() - 1); - TerminalPosition bottomRight = topRight.withRelativeRow(size.getRows() - 1); - TerminalPosition bottomLeft = topLeft.withRelativeRow(size.getRows() - 1); - drawLine(topLeft, topRight, character); - drawLine(topRight, bottomRight, character); - drawLine(bottomRight, bottomLeft, character); - drawLine(bottomLeft, topLeft, character); - } - - @Override - public void fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - //I've used the algorithm described here: - //http://www-users.mat.uni.torun.pl/~wrona/3d_tutor/tri_fillers.html - TerminalPosition[] points = new TerminalPosition[]{p1, p2, p3}; - Arrays.sort(points, new Comparator() { - @Override - public int compare(TerminalPosition o1, TerminalPosition o2) { - return (o1.getRow() < o2.getRow()) ? -1 : ((o1.getRow() == o2.getRow()) ? 0 : 1); - } - }); - - float dx1, dx2, dx3; - if (points[1].getRow() - points[0].getRow() > 0) { - dx1 = (float)(points[1].getColumn() - points[0].getColumn()) / (float)(points[1].getRow() - points[0].getRow()); - } - else { - dx1 = 0; - } - if (points[2].getRow() - points[0].getRow() > 0) { - dx2 = (float)(points[2].getColumn() - points[0].getColumn()) / (float)(points[2].getRow() - points[0].getRow()); - } - else { - dx2 = 0; - } - if (points[2].getRow() - points[1].getRow() > 0) { - dx3 = (float)(points[2].getColumn() - points[1].getColumn()) / (float)(points[2].getRow() - points[1].getRow()); - } - else { - dx3 = 0; - } - - float startX, startY, endX; - startX = endX = points[0].getColumn(); - startY = points[0].getRow(); - if (dx1 > dx2) { - for (; startY <= points[1].getRow(); startY++, startX += dx2, endX += dx1) { - drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character); - } - endX = points[1].getColumn(); - for (; startY <= points[2].getRow(); startY++, startX += dx2, endX += dx3) { - drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character); - } - } else { - for (; startY <= points[1].getRow(); startY++, startX += dx1, endX += dx2) { - drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character); - } - startX = points[1].getColumn(); - startY = points[1].getRow(); - for (; startY <= points[2].getRow(); startY++, startX += dx3, endX += dx2) { - drawLine(new TerminalPosition((int)startX, (int)startY), new TerminalPosition((int)endX, (int)startY), character); - } - } - } - - @Override - public void fillRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - for(int y = 0; y < size.getRows(); y++) { - for(int x = 0; x < size.getColumns(); x++) { - callback.onPoint(topLeft.getColumn() + x, topLeft.getRow() + y, character); - } - } - } -} diff --git a/src/com/googlecode/lanterna/graphics/DoublePrintingTextGraphics.java b/src/com/googlecode/lanterna/graphics/DoublePrintingTextGraphics.java deleted file mode 100644 index 37e2029..0000000 --- a/src/com/googlecode/lanterna/graphics/DoublePrintingTextGraphics.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.TextCharacter; -import com.googlecode.lanterna.TerminalSize; - -/** - * This TextGraphics implementation wraps another TextGraphics and forwards all operations to it, but with a few - * differences. First of all, each individual character being printed is printed twice. Secondly, if you call - * {@code getSize()}, it will return a size that has half the width of the underlying TextGraphics. This presents the - * writable view as somewhat squared, since normally terminal characters are twice as tall as wide. You can see some - * examples of how this looks by running the Triangle test in {@code com.googlecode.lanterna.screen.ScreenTriangleTest} - * and compare it when running with the --square parameter and without. - */ -public class DoublePrintingTextGraphics extends AbstractTextGraphics { - private final TextGraphics underlyingTextGraphics; - - /** - * Creates a new {@code DoublePrintingTextGraphics} on top of a supplied {@code TextGraphics} - * @param underlyingTextGraphics backend {@code TextGraphics} to forward all the calls to - */ - public DoublePrintingTextGraphics(TextGraphics underlyingTextGraphics) { - this.underlyingTextGraphics = underlyingTextGraphics; - } - - @Override - public TextGraphics setCharacter(int columnIndex, int rowIndex, TextCharacter textCharacter) { - columnIndex = columnIndex * 2; - underlyingTextGraphics.setCharacter(columnIndex, rowIndex, textCharacter); - underlyingTextGraphics.setCharacter(columnIndex + 1, rowIndex, textCharacter); - return this; - } - - @Override - public TextCharacter getCharacter(int columnIndex, int rowIndex) { - columnIndex = columnIndex * 2; - return underlyingTextGraphics.getCharacter(columnIndex, rowIndex); - - } - - @Override - public TerminalSize getSize() { - TerminalSize size = underlyingTextGraphics.getSize(); - return size.withColumns(size.getColumns() / 2); - } -} diff --git a/src/com/googlecode/lanterna/graphics/ImmutableThemedTextGraphics.java b/src/com/googlecode/lanterna/graphics/ImmutableThemedTextGraphics.java deleted file mode 100644 index a5b12da..0000000 --- a/src/com/googlecode/lanterna/graphics/ImmutableThemedTextGraphics.java +++ /dev/null @@ -1,293 +0,0 @@ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.*; -import com.googlecode.lanterna.screen.TabBehaviour; - -import java.util.Collection; -import java.util.EnumSet; - -/** - * Implementation of ThemedTextGraphics that wraps a TextGraphics that all calls are delegated to, except for the - * method from ThemedTextGraphics which are handled. The theme is set at construction time, but you can create a clone - * of this object with a different theme. - * @author Martin - */ -public class ImmutableThemedTextGraphics implements ThemedTextGraphics { - private final TextGraphics backend; - private final Theme theme; - - /** - * Creates a new {@code ImmutableThemedTextGraphics} with a specified backend for all drawing operations and a - * theme. - * @param backend Backend to send all drawing operations to - * @param theme Theme to be associated with this object - */ - public ImmutableThemedTextGraphics(TextGraphics backend, Theme theme) { - this.backend = backend; - this.theme = theme; - } - - /** - * Returns a new {@code ImmutableThemedTextGraphics} that targets the same backend but with another theme - * @param theme Theme the new {@code ImmutableThemedTextGraphics} is using - * @return New {@code ImmutableThemedTextGraphics} object that uses the same backend as this object - */ - public ImmutableThemedTextGraphics withTheme(Theme theme) { - return new ImmutableThemedTextGraphics(backend, theme); - } - - /** - * Returns the underlying {@code TextGraphics} that is handling all drawing operations - * @return Underlying {@code TextGraphics} that is handling all drawing operations - */ - public TextGraphics getUnderlyingTextGraphics() { - return backend; - } - - /** - * Returns the theme associated with this {@code ImmutableThemedTextGraphics} - * @return The theme associated with this {@code ImmutableThemedTextGraphics} - */ - public Theme getTheme() { - return theme; - } - - @Override - public ThemeDefinition getThemeDefinition(Class clazz) { - return theme.getDefinition(clazz); - } - - @Override - public ImmutableThemedTextGraphics applyThemeStyle(ThemeStyle themeStyle) { - setForegroundColor(themeStyle.getForeground()); - setBackgroundColor(themeStyle.getBackground()); - setModifiers(themeStyle.getSGRs()); - return this; - } - - @Override - public TerminalSize getSize() { - return backend.getSize(); - } - - @Override - public ImmutableThemedTextGraphics newTextGraphics(TerminalPosition topLeftCorner, TerminalSize size) throws IllegalArgumentException { - return new ImmutableThemedTextGraphics(backend.newTextGraphics(topLeftCorner, size), theme); - } - - @Override - public TextColor getBackgroundColor() { - return backend.getBackgroundColor(); - } - - @Override - public ImmutableThemedTextGraphics setBackgroundColor(TextColor backgroundColor) { - backend.setBackgroundColor(backgroundColor); - return this; - } - - @Override - public TextColor getForegroundColor() { - return backend.getForegroundColor(); - } - - @Override - public ImmutableThemedTextGraphics setForegroundColor(TextColor foregroundColor) { - backend.setForegroundColor(foregroundColor); - return this; - } - - @Override - public ImmutableThemedTextGraphics enableModifiers(SGR... modifiers) { - backend.enableModifiers(modifiers); - return this; - } - - @Override - public ImmutableThemedTextGraphics disableModifiers(SGR... modifiers) { - backend.disableModifiers(modifiers); - return this; - } - - @Override - public ImmutableThemedTextGraphics setModifiers(EnumSet modifiers) { - backend.setModifiers(modifiers); - return this; - } - - @Override - public ImmutableThemedTextGraphics clearModifiers() { - backend.clearModifiers(); - return this; - } - - @Override - public EnumSet getActiveModifiers() { - return backend.getActiveModifiers(); - } - - @Override - public TabBehaviour getTabBehaviour() { - return backend.getTabBehaviour(); - } - - @Override - public ImmutableThemedTextGraphics setTabBehaviour(TabBehaviour tabBehaviour) { - backend.setTabBehaviour(tabBehaviour); - return this; - } - - @Override - public ImmutableThemedTextGraphics fill(char c) { - backend.fill(c); - return this; - } - - @Override - public TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, char character) { - backend.fillRectangle(topLeft, size, character); - return this; - } - - @Override - public TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - backend.fillRectangle(topLeft, size, character); - return this; - } - - @Override - public TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, char character) { - backend.drawRectangle(topLeft, size, character); - return this; - } - - @Override - public TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - backend.drawRectangle(topLeft, size, character); - return this; - } - - @Override - public TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character) { - backend.fillTriangle(p1, p2, p3, character); - return this; - } - - @Override - public TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - backend.fillTriangle(p1, p2, p3, character); - return this; - } - - @Override - public TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character) { - backend.drawTriangle(p1, p2, p3, character); - return this; - } - - @Override - public TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - backend.drawTriangle(p1, p2, p3, character); - return this; - } - - @Override - public TextGraphics drawLine(TerminalPosition fromPoint, TerminalPosition toPoint, char character) { - backend.drawLine(fromPoint, toPoint, character); - return this; - } - - @Override - public TextGraphics drawLine(TerminalPosition fromPoint, TerminalPosition toPoint, TextCharacter character) { - backend.drawLine(fromPoint, toPoint, character); - return this; - } - - @Override - public TextGraphics drawLine(int fromX, int fromY, int toX, int toY, char character) { - backend.drawLine(fromX, fromY, toX, toY, character); - return this; - } - - @Override - public TextGraphics drawLine(int fromX, int fromY, int toX, int toY, TextCharacter character) { - backend.drawLine(fromX, fromY, toX, toY, character); - return this; - } - - @Override - public TextGraphics drawImage(TerminalPosition topLeft, TextImage image) { - backend.drawImage(topLeft, image); - return this; - } - - @Override - public TextGraphics drawImage(TerminalPosition topLeft, TextImage image, TerminalPosition sourceImageTopLeft, TerminalSize sourceImageSize) { - backend.drawImage(topLeft, image, sourceImageTopLeft, sourceImageSize); - return this; - } - - @Override - public TextGraphics setCharacter(TerminalPosition position, char character) { - backend.setCharacter(position, character); - return this; - } - - @Override - public TextGraphics setCharacter(TerminalPosition position, TextCharacter character) { - backend.setCharacter(position, character); - return this; - } - - @Override - public TextGraphics setCharacter(int column, int row, char character) { - backend.setCharacter(column, row, character); - return this; - } - - @Override - public TextGraphics setCharacter(int column, int row, TextCharacter character) { - backend.setCharacter(column, row, character); - return this; - } - - @Override - public ImmutableThemedTextGraphics putString(int column, int row, String string) { - backend.putString(column, row, string); - return this; - } - - @Override - public ImmutableThemedTextGraphics putString(TerminalPosition position, String string) { - backend.putString(position, string); - return this; - } - - @Override - public ImmutableThemedTextGraphics putString(int column, int row, String string, SGR extraModifier, SGR... optionalExtraModifiers) { - backend.putString(column, row, string, extraModifier, optionalExtraModifiers); - return this; - } - - @Override - public ImmutableThemedTextGraphics putString(TerminalPosition position, String string, SGR extraModifier, SGR... optionalExtraModifiers) { - backend.putString(position, string, extraModifier, optionalExtraModifiers); - return this; - } - - @Override - public TextGraphics putString(int column, int row, String string, Collection extraModifiers) { - backend.putString(column, row, string, extraModifiers); - return this; - } - - @Override - public TextCharacter getCharacter(TerminalPosition position) { - return backend.getCharacter(position); - } - - @Override - public TextCharacter getCharacter(int column, int row) { - return backend.getCharacter(column, row); - } -} diff --git a/src/com/googlecode/lanterna/graphics/NullTextGraphics.java b/src/com/googlecode/lanterna/graphics/NullTextGraphics.java deleted file mode 100644 index 0e73695..0000000 --- a/src/com/googlecode/lanterna/graphics/NullTextGraphics.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.*; -import com.googlecode.lanterna.screen.TabBehaviour; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; - -/** - * TextGraphics implementation that does nothing, but has a pre-defined size - * @author martin - */ -class NullTextGraphics implements TextGraphics { - private final TerminalSize size; - private TextColor foregroundColor; - private TextColor backgroundColor; - private TabBehaviour tabBehaviour; - private final EnumSet activeModifiers; - - /** - * Creates a new {@code NullTextGraphics} that will return the specified size value if asked how big it is but other - * than that ignore all other calls. - * @param size The size to report - */ - public NullTextGraphics(TerminalSize size) { - this.size = size; - this.foregroundColor = TextColor.ANSI.DEFAULT; - this.backgroundColor = TextColor.ANSI.DEFAULT; - this.tabBehaviour = TabBehaviour.ALIGN_TO_COLUMN_4; - this.activeModifiers = EnumSet.noneOf(SGR.class); - } - - @Override - public TerminalSize getSize() { - return size; - } - - @Override - public TextGraphics newTextGraphics(TerminalPosition topLeftCorner, TerminalSize size) throws IllegalArgumentException { - return this; - } - - @Override - public TextColor getBackgroundColor() { - return backgroundColor; - } - - @Override - public TextGraphics setBackgroundColor(TextColor backgroundColor) { - this.backgroundColor = backgroundColor; - return this; - } - - @Override - public TextColor getForegroundColor() { - return foregroundColor; - } - - @Override - public TextGraphics setForegroundColor(TextColor foregroundColor) { - this.foregroundColor = foregroundColor; - return this; - } - - @Override - public TextGraphics enableModifiers(SGR... modifiers) { - activeModifiers.addAll(Arrays.asList(modifiers)); - return this; - } - - @Override - public TextGraphics disableModifiers(SGR... modifiers) { - activeModifiers.removeAll(Arrays.asList(modifiers)); - return this; - } - - @Override - public TextGraphics setModifiers(EnumSet modifiers) { - clearModifiers(); - activeModifiers.addAll(modifiers); - return this; - } - - @Override - public TextGraphics clearModifiers() { - activeModifiers.clear(); - return this; - } - - @Override - public EnumSet getActiveModifiers() { - return EnumSet.copyOf(activeModifiers); - } - - @Override - public TabBehaviour getTabBehaviour() { - return tabBehaviour; - } - - @Override - public TextGraphics setTabBehaviour(TabBehaviour tabBehaviour) { - this.tabBehaviour = tabBehaviour; - return this; - } - - @Override - public TextGraphics fill(char c) { - return this; - } - - @Override - public TextGraphics setCharacter(int column, int row, char character) { - return this; - } - - @Override - public TextGraphics setCharacter(int column, int row, TextCharacter character) { - return this; - } - - @Override - public TextGraphics setCharacter(TerminalPosition position, char character) { - return this; - } - - @Override - public TextGraphics setCharacter(TerminalPosition position, TextCharacter character) { - return this; - } - - @Override - public TextGraphics drawLine(TerminalPosition fromPoint, TerminalPosition toPoint, char character) { - return this; - } - - @Override - public TextGraphics drawLine(TerminalPosition fromPoint, TerminalPosition toPoint, TextCharacter character) { - return this; - } - - @Override - public TextGraphics drawLine(int fromX, int fromY, int toX, int toY, char character) { - return this; - } - - @Override - public TextGraphics drawLine(int fromX, int fromY, int toX, int toY, TextCharacter character) { - return this; - } - - @Override - public TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character) { - return this; - } - - @Override - public TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - return this; - } - - @Override - public TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character) { - return this; - } - - @Override - public TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character) { - return this; - } - - @Override - public TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, char character) { - return this; - } - - @Override - public TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - return this; - } - - @Override - public TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, char character) { - return this; - } - - @Override - public TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character) { - return this; - } - - @Override - public TextGraphics drawImage(TerminalPosition topLeft, TextImage image) { - return this; - } - - @Override - public TextGraphics drawImage(TerminalPosition topLeft, TextImage image, TerminalPosition sourceImageTopLeft, TerminalSize sourceImageSize) { - return this; - } - - @Override - public TextGraphics putString(int column, int row, String string) { - return this; - } - - @Override - public TextGraphics putString(TerminalPosition position, String string) { - return this; - } - - @Override - public TextGraphics putString(int column, int row, String string, SGR extraModifier, SGR... optionalExtraModifiers) { - return this; - } - - @Override - public TextGraphics putString(TerminalPosition position, String string, SGR extraModifier, SGR... optionalExtraModifiers) { - return this; - } - - @Override - public TextGraphics putString(int column, int row, String string, Collection extraModifiers) { - return this; - } - - @Override - public TextCharacter getCharacter(int column, int row) { - return null; - } - - @Override - public TextCharacter getCharacter(TerminalPosition position) { - return null; - } -} diff --git a/src/com/googlecode/lanterna/graphics/PropertiesTheme.java b/src/com/googlecode/lanterna/graphics/PropertiesTheme.java deleted file mode 100644 index 9ac8a60..0000000 --- a/src/com/googlecode/lanterna/graphics/PropertiesTheme.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.SGR; -import com.googlecode.lanterna.TextColor; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * This implementation of Theme reads its definitions from a {@code Properties} object. - * @author Martin - */ -public final class PropertiesTheme implements Theme { - private static final String STYLE_NORMAL = ""; - private static final String STYLE_PRELIGHT = "PRELIGHT"; - private static final String STYLE_SELECTED = "SELECTED"; - private static final String STYLE_ACTIVE = "ACTIVE"; - private static final String STYLE_INSENSITIVE = "INSENSITIVE"; - - private static final Pattern STYLE_FORMAT = Pattern.compile("([a-zA-Z]+)(\\[([a-zA-Z0-9-_]+)\\])?"); - private static final Pattern INDEXED_COLOR = Pattern.compile("#[0-9]{1,3}"); - private static final Pattern RGB_COLOR = Pattern.compile("#[0-9a-fA-F]{6}"); - - private final ThemeTreeNode rootNode; - - /** - * Creates a new {@code PropertiesTheme} that is initialized by the properties value - * @param properties Properties to initialize this theme with - */ - public PropertiesTheme(Properties properties) { - rootNode = new ThemeTreeNode(); - rootNode.foregroundMap.put(STYLE_NORMAL, TextColor.ANSI.WHITE); - rootNode.backgroundMap.put(STYLE_NORMAL, TextColor.ANSI.BLACK); - - for(String key: properties.stringPropertyNames()) { - String definition = getDefinition(key); - ThemeTreeNode node = getNode(definition); - node.apply(getStyle(key), properties.getProperty(key)); - } - } - - private ThemeTreeNode getNode(String definition) { - ThemeTreeNode parentNode; - if(definition.equals("")) { - return rootNode; - } - else if(definition.contains(".")) { - String parent = definition.substring(0, definition.lastIndexOf(".")); - parentNode = getNode(parent); - definition = definition.substring(definition.lastIndexOf(".") + 1); - } - else { - parentNode = rootNode; - } - if(!parentNode.childMap.containsKey(definition)) { - parentNode.childMap.put(definition, new ThemeTreeNode()); - } - return parentNode.childMap.get(definition); - } - - private String getDefinition(String propertyName) { - if(!propertyName.contains(".")) { - return ""; - } - else { - return propertyName.substring(0, propertyName.lastIndexOf(".")); - } - } - - private String getStyle(String propertyName) { - if(!propertyName.contains(".")) { - return propertyName; - } - else { - return propertyName.substring(propertyName.lastIndexOf(".") + 1); - } - } - - @Override - public ThemeDefinition getDefaultDefinition() { - return new DefinitionImpl(Collections.singletonList(rootNode)); - } - - @Override - public ThemeDefinition getDefinition(Class clazz) { - String name = clazz.getName(); - List path = new ArrayList(); - ThemeTreeNode currentNode = rootNode; - while(!name.equals("")) { - path.add(currentNode); - String nextNodeName = name; - if(nextNodeName.contains(".")) { - nextNodeName = nextNodeName.substring(0, name.indexOf(".")); - name = name.substring(name.indexOf(".") + 1); - } - if(currentNode.childMap.containsKey(nextNodeName)) { - currentNode = currentNode.childMap.get(nextNodeName); - } - else { - break; - } - } - return new DefinitionImpl(path); - } - - - private class DefinitionImpl implements ThemeDefinition { - final List path; - - DefinitionImpl(List path) { - this.path = path; - } - - @Override - public ThemeStyle getNormal() { - return new StyleImpl(path, STYLE_NORMAL); - } - - @Override - public ThemeStyle getPreLight() { - return new StyleImpl(path, STYLE_PRELIGHT); - } - - @Override - public ThemeStyle getSelected() { - return new StyleImpl(path, STYLE_SELECTED); - } - - @Override - public ThemeStyle getActive() { - return new StyleImpl(path, STYLE_ACTIVE); - } - - @Override - public ThemeStyle getInsensitive() { - return new StyleImpl(path, STYLE_INSENSITIVE); - } - - @Override - public ThemeStyle getCustom(String name) { - ThemeTreeNode lastElement = path.get(path.size() - 1); - if(lastElement.sgrMap.containsKey(name) || - lastElement.foregroundMap.containsKey(name) || - lastElement.backgroundMap.containsKey(name)) { - return new StyleImpl(path, name); - } - // If there was no custom style with this name, just return the normal one - return getNormal(); - } - - @Override - public char getCharacter(String name, char fallback) { - Character character = path.get(path.size() - 1).characterMap.get(name); - if(character == null) { - return fallback; - } - return character; - } - - @Override - public String getRenderer() { - return path.get(path.size() - 1).renderer; - } - } - - private class StyleImpl implements ThemeStyle { - private final List path; - private final String name; - - private StyleImpl(List path, String name) { - this.path = path; - this.name = name; - } - - @Override - public TextColor getForeground() { - ListIterator iterator = path.listIterator(path.size()); - while(iterator.hasPrevious()) { - ThemeTreeNode node = iterator.previous(); - if(node.foregroundMap.containsKey(name)) { - return node.foregroundMap.get(name); - } - } - if(!name.equals(STYLE_NORMAL)) { - return new StyleImpl(path, STYLE_NORMAL).getForeground(); - } - return TextColor.ANSI.WHITE; - } - - @Override - public TextColor getBackground() { - ListIterator iterator = path.listIterator(path.size()); - while(iterator.hasPrevious()) { - ThemeTreeNode node = iterator.previous(); - if(node.backgroundMap.containsKey(name)) { - return node.backgroundMap.get(name); - } - } - if(!name.equals(STYLE_NORMAL)) { - return new StyleImpl(path, STYLE_NORMAL).getBackground(); - } - return TextColor.ANSI.BLACK; - } - - @Override - public EnumSet getSGRs() { - ListIterator iterator = path.listIterator(path.size()); - while(iterator.hasPrevious()) { - ThemeTreeNode node = iterator.previous(); - if(node.sgrMap.containsKey(name)) { - return node.sgrMap.get(name); - } - } - if(!name.equals(STYLE_NORMAL)) { - return new StyleImpl(path, STYLE_NORMAL).getSGRs(); - } - return EnumSet.noneOf(SGR.class); - } - } - - private static class ThemeTreeNode { - private final Map childMap; - private final Map foregroundMap; - private final Map backgroundMap; - private final Map> sgrMap; - private final Map characterMap; - private String renderer; - - private ThemeTreeNode() { - childMap = new HashMap(); - foregroundMap = new HashMap(); - backgroundMap = new HashMap(); - sgrMap = new HashMap>(); - characterMap = new HashMap(); - renderer = null; - } - - public void apply(String style, String value) { - value = value.trim(); - Matcher matcher = STYLE_FORMAT.matcher(style); - if(!matcher.matches()) { - throw new IllegalArgumentException("Unknown style declaration: " + style); - } - String styleComponent = matcher.group(1); - String group = matcher.groupCount() > 2 ? matcher.group(3) : null; - if(styleComponent.toLowerCase().trim().equals("foreground")) { - foregroundMap.put(getCategory(group), parseValue(value)); - } - else if(styleComponent.toLowerCase().trim().equals("background")) { - backgroundMap.put(getCategory(group), parseValue(value)); - } - else if(styleComponent.toLowerCase().trim().equals("sgr")) { - sgrMap.put(getCategory(group), parseSGR(value)); - } - else if(styleComponent.toLowerCase().trim().equals("char")) { - characterMap.put(getCategory(group), value.isEmpty() ? null : value.charAt(0)); - } - else if(styleComponent.toLowerCase().trim().equals("renderer")) { - renderer = value.trim().isEmpty() ? null : value.trim(); - } - else { - throw new IllegalArgumentException("Unknown style component \"" + styleComponent + "\" in style \"" + style + "\""); - } - } - - private TextColor parseValue(String value) { - value = value.trim(); - if(RGB_COLOR.matcher(value).matches()) { - int r = Integer.parseInt(value.substring(1, 3), 16); - int g = Integer.parseInt(value.substring(3, 5), 16); - int b = Integer.parseInt(value.substring(5, 7), 16); - return new TextColor.RGB(r, g, b); - } - else if(INDEXED_COLOR.matcher(value).matches()) { - int index = Integer.parseInt(value.substring(1)); - return new TextColor.Indexed(index); - } - try { - return TextColor.ANSI.valueOf(value.toUpperCase()); - } - catch(IllegalArgumentException e) { - throw new IllegalArgumentException("Unknown color definition \"" + value + "\"", e); - } - } - - private EnumSet parseSGR(String value) { - value = value.trim(); - String[] sgrEntries = value.split(","); - EnumSet sgrSet = EnumSet.noneOf(SGR.class); - for(String entry: sgrEntries) { - entry = entry.trim().toUpperCase(); - if(!entry.isEmpty()) { - try { - sgrSet.add(SGR.valueOf(entry)); - } - catch(IllegalArgumentException e) { - throw new IllegalArgumentException("Unknown SGR code \"" + entry + "\"", e); - } - } - } - return sgrSet; - } - - private String getCategory(String group) { - if(group == null) { - return STYLE_NORMAL; - } - for(String style: Arrays.asList(STYLE_ACTIVE, STYLE_INSENSITIVE, STYLE_PRELIGHT, STYLE_NORMAL, STYLE_SELECTED)) { - if(group.toUpperCase().equals(style)) { - return style; - } - } - return group; - } - } -} diff --git a/src/com/googlecode/lanterna/graphics/Scrollable.java b/src/com/googlecode/lanterna/graphics/Scrollable.java deleted file mode 100644 index e59129f..0000000 --- a/src/com/googlecode/lanterna/graphics/Scrollable.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.googlecode.lanterna.graphics; - -import java.io.IOException; - -/** - * Describes an area that can be 'scrolled', by moving a range of lines up or down. Certain terminals will implement - * this through extensions and are much faster than if lanterna tries to manually erase and re-print the text. - * - * @author Andreas - */ -public interface Scrollable { - /** - * Scroll a range of lines of this Scrollable according to given distance. - * - * If scroll-range is empty (firstLine > lastLine || distance == 0) then - * this method does nothing. - * - * Lines that are scrolled away from are cleared. - * - * If absolute value of distance is equal or greater than number of lines - * in range, then all lines within the range will be cleared. - * - * @param firstLine first line of the range to be scrolled (top line is 0) - * @param lastLine last (inclusive) line of the range to be scrolled - * @param distance if > 0: move lines up, else if < 0: move lines down. - */ - void scrollLines(int firstLine, int lastLine, int distance) throws IOException; -} diff --git a/src/com/googlecode/lanterna/graphics/ShapeRenderer.java b/src/com/googlecode/lanterna/graphics/ShapeRenderer.java deleted file mode 100644 index 206effd..0000000 --- a/src/com/googlecode/lanterna/graphics/ShapeRenderer.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.TextCharacter; - -/** - * This package private interface exposes methods for translating abstract lines, triangles and rectangles to discreet - * points on a grid. - * @author Martin - */ -interface ShapeRenderer { - void drawLine(TerminalPosition p1, TerminalPosition p2, TextCharacter character); - void drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character); - void drawRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character); - void fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character); - void fillRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character); -} diff --git a/src/com/googlecode/lanterna/graphics/SubTextGraphics.java b/src/com/googlecode/lanterna/graphics/SubTextGraphics.java deleted file mode 100644 index c3ef0fd..0000000 --- a/src/com/googlecode/lanterna/graphics/SubTextGraphics.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.TextCharacter; -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; - -/** - * This implementation of TextGraphics will take a 'proper' object and composite a view on top of it, by using a - * top-left position and a size. Any attempts to put text outside of this area will be dropped. - * @author Martin - */ -class SubTextGraphics extends AbstractTextGraphics { - private final TextGraphics underlyingTextGraphics; - private final TerminalPosition topLeft; - private final TerminalSize writableAreaSize; - - SubTextGraphics(TextGraphics underlyingTextGraphics, TerminalPosition topLeft, TerminalSize writableAreaSize) { - this.underlyingTextGraphics = underlyingTextGraphics; - this.topLeft = topLeft; - this.writableAreaSize = writableAreaSize; - } - - private TerminalPosition project(int column, int row) { - return topLeft.withRelative(column, row); - } - - @Override - public TextGraphics setCharacter(int columnIndex, int rowIndex, TextCharacter textCharacter) { - TerminalSize writableArea = getSize(); - if(columnIndex < 0 || columnIndex >= writableArea.getColumns() || - rowIndex < 0 || rowIndex >= writableArea.getRows()) { - return this; - } - TerminalPosition projectedPosition = project(columnIndex, rowIndex); - underlyingTextGraphics.setCharacter(projectedPosition, textCharacter); - return this; - } - - @Override - public TerminalSize getSize() { - return writableAreaSize; - } - - @Override - public TextCharacter getCharacter(int column, int row) { - TerminalPosition projectedPosition = project(column, row); - return underlyingTextGraphics.getCharacter(projectedPosition.getColumn(), projectedPosition.getRow()); - } -} diff --git a/src/com/googlecode/lanterna/graphics/TextGraphics.java b/src/com/googlecode/lanterna/graphics/TextGraphics.java deleted file mode 100644 index 0ad0f93..0000000 --- a/src/com/googlecode/lanterna/graphics/TextGraphics.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.*; -import com.googlecode.lanterna.screen.TabBehaviour; - -import java.util.Collection; -import java.util.EnumSet; - -/** - * This interface exposes functionality to 'draw' text graphics on a section of the terminal. It has several - * implementation for the different levels, including one for Terminal, one for Screen and one which is used by the - * TextGUI system to draw components. They are all very similar and has a lot of graphics functionality in - * AbstractTextGraphics. - *

- * The basic concept behind a TextGraphics implementation is that it keeps a state on four things: - *

    - *
  • Foreground color
  • - *
  • Background color
  • - *
  • Modifiers
  • - *
  • Tab-expanding behaviour
  • - *
- * These call all be altered through ordinary set* methods, but some will be altered as the result of performing one of - * the 'drawing' operations. See the documentation to each method for further information (for example, putString). - *

- * Don't hold on to your TextGraphics objects for too long; ideally create them and let them be GC:ed when you are done - * with them. The reason is that not all implementations will handle the underlying terminal changing size. - * @author Martin - */ -public interface TextGraphics { - /** - * Returns the size of the area that this text graphic can write to. Any attempts of placing characters outside of - * this area will be silently ignored. - * @return Size of the writable area that this TextGraphics can write too - */ - TerminalSize getSize(); - - /** - * Creates a new TextGraphics of the same type as this one, using the same underlying subsystem. Using this method, - * you need to specify a section of the current TextGraphics valid area that this new TextGraphic shall be - * restricted to. If you call newTextGraphics(TerminalPosition.TOP_LEFT_CORNER, textGraphics.getSize()) - * then the resulting object will be identical to this one, but having a separated state for colors, position and - * modifiers. - * @param topLeftCorner Position of this TextGraphics's writable area that is to become the top-left corner (0x0) of - * the new TextGraphics - * @param size How large area, counted from the topLeftCorner, the new TextGraphics can write to. This cannot be - * larger than the current TextGraphics's writable area (adjusted by topLeftCorner) - * @return A new TextGraphics with the same underlying subsystem, that can write to only the specified area - * @throws java.lang.IllegalArgumentException If the size the of new TextGraphics exceeds the dimensions of this - * TextGraphics in any way. - */ - TextGraphics newTextGraphics(TerminalPosition topLeftCorner, TerminalSize size) throws IllegalArgumentException; - - /** - * Returns the current background color - * @return Current background color - */ - TextColor getBackgroundColor(); - - /** - * Updates the current background color - * @param backgroundColor New background color - * @return Itself - */ - TextGraphics setBackgroundColor(TextColor backgroundColor); - - /** - * Returns the current foreground color - * @return Current foreground color - */ - TextColor getForegroundColor(); - - /** - * Updates the current foreground color - * @param foregroundColor New foreground color - * @return Itself - */ - TextGraphics setForegroundColor(TextColor foregroundColor); - - /** - * Adds zero or more modifiers to the set of currently active modifiers - * @param modifiers Modifiers to add to the set of currently active modifiers - * @return Itself - */ - TextGraphics enableModifiers(SGR... modifiers); - - /** - * Removes zero or more modifiers from the set of currently active modifiers - * @param modifiers Modifiers to remove from the set of currently active modifiers - * @return Itself - */ - TextGraphics disableModifiers(SGR... modifiers); - - /** - * Sets the active modifiers to exactly the set passed in to this method. Any previous state of which modifiers are - * enabled doesn't matter. - * @param modifiers Modifiers to set as active - * @return Itself - */ - TextGraphics setModifiers(EnumSet modifiers); - - /** - * Removes all active modifiers - * @return Itself - */ - TextGraphics clearModifiers(); - - /** - * Returns all the SGR codes that are currently active in the TextGraphic - * @return Currently active SGR modifiers - */ - EnumSet getActiveModifiers(); - - /** - * Retrieves the current tab behaviour, which is what the TextGraphics will use when expanding \t characters to - * spaces. - * @return Current behaviour in use for expanding tab to spaces - */ - TabBehaviour getTabBehaviour(); - - /** - * Sets the behaviour to use when expanding tab characters (\t) to spaces - * @param tabBehaviour Behaviour to use when expanding tabs to spaces - */ - TextGraphics setTabBehaviour(TabBehaviour tabBehaviour); - - /** - * Fills the entire writable area with a single character, using current foreground color, background color and modifiers. - * @param c Character to fill the writable area with - */ - TextGraphics fill(char c); - - /** - * Sets the character at the current position to the specified value - * @param column column of the location to set the character - * @param row row of the location to set the character - * @param character Character to set at the current position - * @return Itself - */ - TextGraphics setCharacter(int column, int row, char character); - - /** - * Sets the character at the current position to the specified value, without using the current colors and modifiers - * of this TextGraphics. - * @param column column of the location to set the character - * @param row row of the location to set the character - * @param character Character data to set at the current position - * @return Itself - */ - TextGraphics setCharacter(int column, int row, TextCharacter character); - - /** - * Sets the character at the current position to the specified value - * @param position position of the location to set the character - * @param character Character to set at the current position - * @return Itself - */ - TextGraphics setCharacter(TerminalPosition position, char character); - - /** - * Sets the character at the current position to the specified value, without using the current colors and modifiers - * of this TextGraphics. - * @param position position of the location to set the character - * @param character Character data to set at the current position - * @return Itself - */ - TextGraphics setCharacter(TerminalPosition position, TextCharacter character); - - /** - * Draws a line from a specified position to a specified position, using a supplied character. The current - * foreground color, background color and modifiers will be applied. - * @param fromPoint From where to draw the line - * @param toPoint Where to draw the line - * @param character Character to use for the line - * @return Itself - */ - TextGraphics drawLine(TerminalPosition fromPoint, TerminalPosition toPoint, char character); - - /** - * Draws a line from a specified position to a specified position, using a supplied TextCharacter. The current - * foreground color, background color and modifiers of this TextGraphics will not be used and will not be modified - * by this call. - * @param fromPoint From where to draw the line - * @param toPoint Where to draw the line - * @param character Character data to use for the line, including character, colors and modifiers - * @return Itself - */ - TextGraphics drawLine(TerminalPosition fromPoint, TerminalPosition toPoint, TextCharacter character); - - /** - * Draws a line from a specified position to a specified position, using a supplied character. The current - * foreground color, background color and modifiers will be applied. - * @param fromX Column of the starting position to draw the line from (inclusive) - * @param fromY Row of the starting position to draw the line from (inclusive) - * @param toX Column of the end position to draw the line to (inclusive) - * @param toY Row of the end position to draw the line to (inclusive) - * @param character Character to use for the line - * @return Itself - */ - TextGraphics drawLine(int fromX, int fromY, int toX, int toY, char character); - - /** - * Draws a line from a specified position to a specified position, using a supplied character. The current - * foreground color, background color and modifiers of this TextGraphics will not be used and will not be modified - * by this call. - * @param fromX Column of the starting position to draw the line from (inclusive) - * @param fromY Row of the starting position to draw the line from (inclusive) - * @param toX Column of the end position to draw the line to (inclusive) - * @param toY Row of the end position to draw the line to (inclusive) - * @param character Character data to use for the line, including character, colors and modifiers - * @return Itself - */ - TextGraphics drawLine(int fromX, int fromY, int toX, int toY, TextCharacter character); - - /** - * Draws the outline of a triangle on the screen, using a supplied character. The triangle will begin at p1, go - * through p2 and then p3 and then back to p1. The current foreground color, background color and modifiers will be - * applied. - * @param p1 First point on the screen of the triangle - * @param p2 Second point on the screen of the triangle - * @param p3 Third point on the screen of the triangle - * @param character What character to use when drawing the lines of the triangle - */ - TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character); - - /** - * Draws the outline of a triangle on the screen, using a supplied character. The triangle will begin at p1, go - * through p2 and then p3 and then back to p1. The current foreground color, background color and modifiers of this - * TextGraphics will not be used and will not be modified by this call. - * @param p1 First point on the screen of the triangle - * @param p2 Second point on the screen of the triangle - * @param p3 Third point on the screen of the triangle - * @param character What character data to use when drawing the lines of the triangle - */ - TextGraphics drawTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character); - - /** - * Draws a filled triangle, using a supplied character. The triangle will begin at p1, go - * through p2 and then p3 and then back to p1. The current foreground color, background color and modifiers will be - * applied. - * @param p1 First point on the screen of the triangle - * @param p2 Second point on the screen of the triangle - * @param p3 Third point on the screen of the triangle - * @param character What character to use when drawing the triangle - */ - TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, char character); - - /** - * Draws a filled triangle, using a supplied character. The triangle will begin at p1, go - * through p2 and then p3 and then back to p1. The current foreground color, background color and modifiers of this - * TextGraphics will not be used and will not be modified by this call. - * @param p1 First point on the screen of the triangle - * @param p2 Second point on the screen of the triangle - * @param p3 Third point on the screen of the triangle - * @param character What character data to use when drawing the triangle - */ - TextGraphics fillTriangle(TerminalPosition p1, TerminalPosition p2, TerminalPosition p3, TextCharacter character); - - /** - * Draws the outline of a rectangle with a particular character (and the currently active colors and - * modifiers). The topLeft coordinate is inclusive. - *

- * For example, calling drawRectangle with size being the size of the terminal and top-left value being the terminal's - * top-left (0x0) corner will draw a border around the terminal. - *

- * The current foreground color, background color and modifiers will be applied. - * @param topLeft Coordinates of the top-left position of the rectangle - * @param size Size (in columns and rows) of the area to draw - * @param character What character to use when drawing the outline of the rectangle - */ - TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, char character); - - /** - * Draws the outline of a rectangle with a particular TextCharacter, ignoring the current colors and modifiers of - * this TextGraphics. - *

- * For example, calling drawRectangle with size being the size of the terminal and top-left value being the terminal's - * top-left (0x0) corner will draw a border around the terminal. - *

- * The current foreground color, background color and modifiers will not be modified by this call. - * @param topLeft Coordinates of the top-left position of the rectangle - * @param size Size (in columns and rows) of the area to draw - * @param character What character data to use when drawing the outline of the rectangle - */ - TextGraphics drawRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character); - - /** - * Takes a rectangle and fills it with a particular character (and the currently active colors and - * modifiers). The topLeft coordinate is inclusive. - *

- * For example, calling fillRectangle with size being the size of the terminal and top-left value being the terminal's - * top-left (0x0) corner will fill the entire terminal with this character. - *

- * The current foreground color, background color and modifiers will be applied. - * @param topLeft Coordinates of the top-left position of the rectangle - * @param size Size (in columns and rows) of the area to draw - * @param character What character to use when filling the rectangle - */ - TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, char character); - - /** - * Takes a rectangle and fills it using a particular TextCharacter, ignoring the current colors and modifiers of - * this TextGraphics. The topLeft coordinate is inclusive. - *

- * For example, calling fillRectangle with size being the size of the terminal and top-left value being the terminal's - * top-left (0x0) corner will fill the entire terminal with this character. - *

- * The current foreground color, background color and modifiers will not be modified by this call. - * @param topLeft Coordinates of the top-left position of the rectangle - * @param size Size (in columns and rows) of the area to draw - * @param character What character data to use when filling the rectangle - */ - TextGraphics fillRectangle(TerminalPosition topLeft, TerminalSize size, TextCharacter character); - - /** - * Takes a TextImage and draws it on the surface this TextGraphics is targeting, given the coordinates on the target - * that is specifying where the top-left corner of the image should be drawn. This is equivalent of calling - * {@code drawImage(topLeft, image, TerminalPosition.TOP_LEFT_CORNER, image.getSize()}. - * @param topLeft Position of the top-left corner of the image on the target - * @param image Image to draw - * @return Itself - */ - TextGraphics drawImage(TerminalPosition topLeft, TextImage image); - - /** - * Takes a TextImage and draws it on the surface this TextGraphics is targeting, given the coordinates on the target - * that is specifying where the top-left corner of the image should be drawn. This overload will only draw a portion - * of the image to the target, as specified by the two last parameters. - * @param topLeft Position of the top-left corner of the image on the target - * @param image Image to draw - * @param sourceImageTopLeft Position of the top-left corner in the source image to draw at the topLeft position on - * the target - * @param sourceImageSize How much of the source image to draw on the target, counted from the sourceImageTopLeft - * position - * @return Itself - */ - TextGraphics drawImage(TerminalPosition topLeft, TextImage image, TerminalPosition sourceImageTopLeft, TerminalSize sourceImageSize); - - /** - * Puts a string on the screen at the specified position with the current colors and modifiers. If the string - * contains newlines (\r and/or \n), the method will stop at the character before that; you have to manage - * multi-line strings yourself! The current foreground color, background color and modifiers will be applied. - * @param column What column to put the string at - * @param row What row to put the string at - * @param string String to put on the screen - * @return Itself - */ - TextGraphics putString(int column, int row, String string); - - /** - * Shortcut to calling: - *

-     *  putString(position.getColumn(), position.getRow(), string);
-     * 
- * @param position Position to put the string at - * @param string String to put on the screen - * @return Itself - */ - TextGraphics putString(TerminalPosition position, String string); - - /** - * Puts a string on the screen at the specified position with the current colors and modifiers. If the string - * contains newlines (\r and/or \n), the method will stop at the character before that; you have to manage - * multi-line strings yourself! If you supplied any extra modifiers, they will be applied when writing the string - * as well but not recorded into the state of the TextGraphics object. - * @param column What column to put the string at - * @param row What row to put the string at - * @param string String to put on the screen - * @param extraModifier Modifier to apply to the string - * @param optionalExtraModifiers Optional extra modifiers to apply to the string - * @return Itself - */ - TextGraphics putString(int column, int row, String string, SGR extraModifier, SGR... optionalExtraModifiers); - - /** - * Shortcut to calling: - *
-     *  putString(position.getColumn(), position.getRow(), string, modifiers, optionalExtraModifiers);
-     * 
- * @param position Position to put the string at - * @param string String to put on the screen - * @param extraModifier Modifier to apply to the string - * @param optionalExtraModifiers Optional extra modifiers to apply to the string - * @return Itself - */ - TextGraphics putString(TerminalPosition position, String string, SGR extraModifier, SGR... optionalExtraModifiers); - - /** - * Puts a string on the screen at the specified position with the current colors and modifiers. If the string - * contains newlines (\r and/or \n), the method will stop at the character before that; you have to manage - * multi-line strings yourself! If you supplied any extra modifiers, they will be applied when writing the string - * as well but not recorded into the state of the TextGraphics object. - * @param column What column to put the string at - * @param row What row to put the string at - * @param string String to put on the screen - * @param extraModifiers Modifier to apply to the string - * @return Itself - */ - TextGraphics putString(int column, int row, String string, Collection extraModifiers); - - /** - * Returns the character at the specific position in the terminal. May return {@code null} if the TextGraphics - * implementation doesn't support it or doesn't know what the character is. - * @param position Position to return the character for - * @return The text character at the specified position or {@code null} if not available - */ - TextCharacter getCharacter(TerminalPosition position); - - /** - * Returns the character at the specific position in the terminal. May return {@code null} if the TextGraphics - * implementation doesn't support it or doesn't know what the character is. - * @param column Column to return the character for - * @param row Row to return the character for - * @return The text character at the specified position or {@code null} if not available - */ - TextCharacter getCharacter(int column, int row); -} diff --git a/src/com/googlecode/lanterna/graphics/TextImage.java b/src/com/googlecode/lanterna/graphics/TextImage.java deleted file mode 100644 index a20bc50..0000000 --- a/src/com/googlecode/lanterna/graphics/TextImage.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.TextCharacter; - -/** - * An 'image' build up of text characters with color and style information. These are completely in memory and not - * visible anyway, but can be used when drawing with a TextGraphics objects. - * @author martin - */ -public interface TextImage extends Scrollable { - /** - * Returns the dimensions of this TextImage, in columns and rows - * @return Size of this TextImage - */ - TerminalSize getSize(); - - /** - * Returns the character stored at a particular position in this image - * @param position Coordinates of the character - * @return TextCharacter stored at the specified position - */ - TextCharacter getCharacterAt(TerminalPosition position); - - /** - * Returns the character stored at a particular position in this image - * @param column Column coordinate of the character - * @param row Row coordinate of the character - * @return TextCharacter stored at the specified position - */ - TextCharacter getCharacterAt(int column, int row); - - /** - * Sets the character at a specific position in the image to a particular TextCharacter. If the position is outside - * of the image's size, this method does nothing. - * @param position Coordinates of the character - * @param character What TextCharacter to assign at the specified position - */ - void setCharacterAt(TerminalPosition position, TextCharacter character); - - /** - * Sets the character at a specific position in the image to a particular TextCharacter. If the position is outside - * of the image's size, this method does nothing. - * @param column Column coordinate of the character - * @param row Row coordinate of the character - * @param character What TextCharacter to assign at the specified position - */ - void setCharacterAt(int column, int row, TextCharacter character); - - /** - * Sets the text image content to one specified character (including color and style) - * @param character The character to fill the image with - */ - void setAll(TextCharacter character); - - /** - * Creates a TextGraphics object that targets this TextImage for all its drawing operations. - * @return TextGraphics object for this TextImage - */ - TextGraphics newTextGraphics(); - - /** - * Returns a copy of this image resized to a new size and using a specified filler character if the new size is - * larger than the old and we need to fill in empty areas. The copy will be independent from the one this method is - * invoked on, so modifying one will not affect the other. - * @param newSize Size of the new image - * @param filler Filler character to use on the new areas when enlarging the image (is not used when shrinking) - * @return Copy of this image, but resized - */ - TextImage resize(TerminalSize newSize, TextCharacter filler); - - - /** - * Copies this TextImage's content to another TextImage. If the destination TextImage is larger than this - * ScreenBuffer, the areas outside of the area that is written to will be untouched. - * @param destination TextImage to copy to - */ - void copyTo(TextImage destination); - - /** - * Copies this TextImage's content to another TextImage. If the destination TextImage is larger than this - * TextImage, the areas outside of the area that is written to will be untouched. - * @param destination TextImage to copy to - * @param startRowIndex Which row in this image to copy from - * @param rows How many rows to copy - * @param startColumnIndex Which column in this image to copy from - * @param columns How many columns to copy - * @param destinationRowOffset Offset (in number of rows) in the target image where we want to first copied row to be - * @param destinationColumnOffset Offset (in number of columns) in the target image where we want to first copied column to be - */ - void copyTo( - TextImage destination, - int startRowIndex, - int rows, - int startColumnIndex, - int columns, - int destinationRowOffset, - int destinationColumnOffset); - - /** - * Scroll a range of lines of this TextImage according to given distance. - * - * TextImage implementations of this method do not throw IOException. - */ - @Override - void scrollLines(int firstLine, int lastLine, int distance); -} diff --git a/src/com/googlecode/lanterna/graphics/Theme.java b/src/com/googlecode/lanterna/graphics/Theme.java deleted file mode 100644 index 16dbcee..0000000 --- a/src/com/googlecode/lanterna/graphics/Theme.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -/** - * The main theme interface, from which you can retrieve theme definitions - * @author Martin - */ -public interface Theme { - /** - * Returns what this theme considers to be the default definition - * @return The default theme definition - */ - ThemeDefinition getDefaultDefinition(); - - /** - * Returns the theme definition associated with this class. The implementation of Theme should ensure that this - * call never returns {@code null}, it should always give back a valid value (falling back to the default is nothing - * else can be used). - * @param clazz Class to get the theme definition for - * @return The ThemeDefinition for the class passed in - */ - ThemeDefinition getDefinition(Class clazz); -} diff --git a/src/com/googlecode/lanterna/graphics/ThemeDefinition.java b/src/com/googlecode/lanterna/graphics/ThemeDefinition.java deleted file mode 100644 index 3efa92c..0000000 --- a/src/com/googlecode/lanterna/graphics/ThemeDefinition.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -/** - * A ThemeDefinition contains a collection of ThemeStyle:s, which defines on a lower level which colors and SGRs to - * apply if you want to draw according to the theme. The different style names are directly inspired from GTK 2. You can - * also fetch character definitions which are stored inside of the theme, for example if you want to draw a border and - * make the characters that make up the border customizable. - * - * @author Martin - */ -public interface ThemeDefinition { - /** - * The normal style of the definition, which can be considered the default to be used. - * @return ThemeStyle representation for the normal style - */ - ThemeStyle getNormal(); - - /** - * The pre-light style of this definition, which can be used when a component has input focus but isn't active or - * selected, similar to mouse-hoovering in modern GUIs - * @return ThemeStyle representation for the pre-light style - */ - ThemeStyle getPreLight(); - - /** - * The "selected" style of this definition, which can used when a component has been actively selected in some way. - * @return ThemeStyle representation for the selected style - */ - ThemeStyle getSelected(); - - /** - * The "active" style of this definition, which can be used when a component is being directly interacted with - * @return ThemeStyle representation for the active style - */ - ThemeStyle getActive(); - - /** - * The insensitive style of this definition, which can be used when a component has been disabled or in some other - * way isn't able to be interacted with. - * @return ThemeStyle representation for the insensitive style - */ - ThemeStyle getInsensitive(); - - /** - * Retrieves a custom ThemeStyle, if one is available by this name. Will return null if no such style could be found - * within this ThemeDefinition. You can use this if you need more categories than the ones available above. - * @param name Name of the style to look up - * @return The ThemeStyle associated with the name, or {@code null} if there was no such style - */ - ThemeStyle getCustom(String name); - - /** - * Retrieves a character from this theme definition by the specified name. This method cannot return {@code null} so - * you need to give a fallback in case the definition didn't have any character by this name. - * @param name Name of the character to look up - * @param fallback Character to return if there was no character by the name supplied in this definition - * @return The character from this definition by the name entered, or {@code fallback} if the definition didn't have - * any character defined with this name - */ - char getCharacter(String name, char fallback); - - /** - * Returns the class name of the ComponentRenderer attached to this definition. If none is declared, it will return - * {@code null} instead of going up in the hierarchy, unlike the other methods of this interface. - * @return Full name of the renderer class or {@code null} - */ - String getRenderer(); -} diff --git a/src/com/googlecode/lanterna/graphics/ThemeStyle.java b/src/com/googlecode/lanterna/graphics/ThemeStyle.java deleted file mode 100644 index 99d85ee..0000000 --- a/src/com/googlecode/lanterna/graphics/ThemeStyle.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -import com.googlecode.lanterna.SGR; -import com.googlecode.lanterna.TextColor; - -import java.util.EnumSet; - -/** - * ThemeStyle is the lowest entry in the theme hierarchy, containing the actual colors and SGRs to use. - * @author Martin - */ -public interface ThemeStyle { - TextColor getForeground(); - TextColor getBackground(); - EnumSet getSGRs(); -} diff --git a/src/com/googlecode/lanterna/graphics/ThemedTextGraphics.java b/src/com/googlecode/lanterna/graphics/ThemedTextGraphics.java deleted file mode 100644 index 593e0e6..0000000 --- a/src/com/googlecode/lanterna/graphics/ThemedTextGraphics.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.graphics; - -/** - * Expanded TextGraphics that adds methods to interact with themes - * @author Martin - */ -public interface ThemedTextGraphics extends TextGraphics { - /** - * Returns the {@code Theme} object active on this {@code ThemedTextGraphics} - * @return Active {@code Theme} object - */ - Theme getTheme(); - - /** - * Retrieves the ThemeDefinition associated with the class parameter passed in. The implementation should make sure - * that there is always a fallback available if there's no direct definition for this class; the method should never - * return null. - * @param clazz Class to search ThemeDefinition for - * @return ThemeDefinition that was resolved for this class - */ - ThemeDefinition getThemeDefinition(Class clazz); - - /** - * Takes a ThemeStyle as applies it to this TextGraphics. This will effectively set the foreground color, the - * background color and all the SGRs. - * @param themeStyle ThemeStyle to apply - * @return Itself - */ - ThemedTextGraphics applyThemeStyle(ThemeStyle themeStyle); -} diff --git a/src/com/googlecode/lanterna/gui2/AbsoluteLayout.java b/src/com/googlecode/lanterna/gui2/AbsoluteLayout.java deleted file mode 100644 index 02ce7d9..0000000 --- a/src/com/googlecode/lanterna/gui2/AbsoluteLayout.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalSize; -import java.util.List; - -/** - * Layout manager that places components where they are manually specified to be and sizes them to the size they are - * manually assigned to. When using the AbsoluteLayout, please use setPosition(..) and setSize(..) manually on each - * component to choose where to place them. Components that have not had their position and size explicitly set will - * not be visible. - * - * @author martin - */ -public class AbsoluteLayout implements LayoutManager { - @Override - public TerminalSize getPreferredSize(List components) { - TerminalSize size = TerminalSize.ZERO; - for(Component component: components) { - size = size.max( - new TerminalSize( - component.getPosition().getColumn() + component.getSize().getColumns(), - component.getPosition().getRow() + component.getSize().getRows())); - - } - return size; - } - - @Override - public void doLayout(TerminalSize area, List components) { - //Do nothing - } - - @Override - public boolean hasChanged() { - return false; - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractBasePane.java b/src/com/googlecode/lanterna/gui2/AbstractBasePane.java deleted file mode 100644 index 0cd47bb..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractBasePane.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.input.KeyStroke; -import com.googlecode.lanterna.input.KeyType; -import com.googlecode.lanterna.input.MouseAction; - -/** - * This abstract implementation of {@code BasePane} has the common code shared by all different concrete - * implementations. - */ -public abstract class AbstractBasePane implements BasePane { - protected final ContentHolder contentHolder; - protected InteractableLookupMap interactableLookupMap; - private Interactable focusedInteractable; - private boolean invalid; - private boolean strictFocusChange; - private boolean enableDirectionBasedMovements; - - protected AbstractBasePane() { - this.contentHolder = new ContentHolder(); - this.interactableLookupMap = new InteractableLookupMap(new TerminalSize(80, 25)); - this.invalid = false; - this.strictFocusChange = false; - this.enableDirectionBasedMovements = true; - } - - @Override - public boolean isInvalid() { - return invalid || contentHolder.isInvalid(); - } - - @Override - public void invalidate() { - invalid = true; - - //Propagate - contentHolder.invalidate(); - } - - @Override - public void draw(TextGUIGraphics graphics) { - graphics.applyThemeStyle(graphics.getThemeDefinition(Window.class).getNormal()); - graphics.fill(' '); - contentHolder.draw(graphics); - - if(!interactableLookupMap.getSize().equals(graphics.getSize())) { - interactableLookupMap = new InteractableLookupMap(graphics.getSize()); - } else { - interactableLookupMap.reset(); - } - contentHolder.updateLookupMap(interactableLookupMap); - //interactableLookupMap.debug(); - invalid = false; - } - - @Override - public boolean handleInput(KeyStroke key) { - if(key.getKeyType() == KeyType.MouseEvent) { - MouseAction mouseAction = (MouseAction)key; - TerminalPosition localCoordinates = fromGlobal(mouseAction.getPosition()); - Interactable interactable = interactableLookupMap.getInteractableAt(localCoordinates); - interactable.handleInput(key); - } - else if(focusedInteractable != null) { - Interactable next = null; - Interactable.FocusChangeDirection direction = Interactable.FocusChangeDirection.TELEPORT; //Default - Interactable.Result result = focusedInteractable.handleInput(key); - if(!enableDirectionBasedMovements) { - if(result == Interactable.Result.MOVE_FOCUS_DOWN || result == Interactable.Result.MOVE_FOCUS_RIGHT) { - result = Interactable.Result.MOVE_FOCUS_NEXT; - } - else if(result == Interactable.Result.MOVE_FOCUS_UP || result == Interactable.Result.MOVE_FOCUS_LEFT) { - result = Interactable.Result.MOVE_FOCUS_PREVIOUS; - } - } - switch (result) { - case HANDLED: - return true; - case UNHANDLED: - //Filter the event recursively through all parent containers until we hit null; give the containers - //a chance to absorb the event - Container parent = focusedInteractable.getParent(); - while(parent != null) { - if(parent.handleInput(key)) { - return true; - } - parent = parent.getParent(); - } - return false; - case MOVE_FOCUS_NEXT: - next = contentHolder.nextFocus(focusedInteractable); - if(next == null) { - next = contentHolder.nextFocus(null); - } - direction = Interactable.FocusChangeDirection.NEXT; - break; - case MOVE_FOCUS_PREVIOUS: - next = contentHolder.previousFocus(focusedInteractable); - if(next == null) { - next = contentHolder.previousFocus(null); - } - direction = Interactable.FocusChangeDirection.PREVIOUS; - break; - case MOVE_FOCUS_DOWN: - next = interactableLookupMap.findNextDown(focusedInteractable); - direction = Interactable.FocusChangeDirection.DOWN; - if(next == null && !strictFocusChange) { - next = contentHolder.nextFocus(focusedInteractable); - direction = Interactable.FocusChangeDirection.NEXT; - } - break; - case MOVE_FOCUS_LEFT: - next = interactableLookupMap.findNextLeft(focusedInteractable); - direction = Interactable.FocusChangeDirection.LEFT; - break; - case MOVE_FOCUS_RIGHT: - next = interactableLookupMap.findNextRight(focusedInteractable); - direction = Interactable.FocusChangeDirection.RIGHT; - break; - case MOVE_FOCUS_UP: - next = interactableLookupMap.findNextUp(focusedInteractable); - direction = Interactable.FocusChangeDirection.UP; - if(next == null && !strictFocusChange) { - next = contentHolder.previousFocus(focusedInteractable); - direction = Interactable.FocusChangeDirection.PREVIOUS; - } - break; - } - if(next != null) { - setFocusedInteractable(next, direction); - } - return true; - } - return false; - } - - @Override - public Component getComponent() { - return contentHolder.getComponent(); - } - - @Override - public void setComponent(Component component) { - contentHolder.setComponent(component); - } - - @Override - public Interactable getFocusedInteractable() { - return focusedInteractable; - } - - @Override - public TerminalPosition getCursorPosition() { - if(focusedInteractable == null) { - return null; - } - TerminalPosition position = focusedInteractable.getCursorLocation(); - if(position == null) { - return null; - } - //Don't allow the component to set the cursor outside of its own boundaries - if(position.getColumn() < 0 || - position.getRow() < 0 || - position.getColumn() >= focusedInteractable.getSize().getColumns() || - position.getRow() >= focusedInteractable.getSize().getRows()) { - return null; - } - return focusedInteractable.toBasePane(position); - } - - @Override - public void setFocusedInteractable(Interactable toFocus) { - setFocusedInteractable(toFocus, - toFocus != null ? - Interactable.FocusChangeDirection.TELEPORT : Interactable.FocusChangeDirection.RESET); - } - - protected void setFocusedInteractable(Interactable toFocus, Interactable.FocusChangeDirection direction) { - if(focusedInteractable == toFocus) { - return; - } - if(focusedInteractable != null) { - focusedInteractable.onLeaveFocus(direction, focusedInteractable); - } - Interactable previous = focusedInteractable; - focusedInteractable = toFocus; - if(toFocus != null) { - toFocus.onEnterFocus(direction, previous); - } - invalidate(); - } - - @Override - public void setStrictFocusChange(boolean strictFocusChange) { - this.strictFocusChange = strictFocusChange; - } - - @Override - public void setEnableDirectionBasedMovements(boolean enableDirectionBasedMovements) { - this.enableDirectionBasedMovements = enableDirectionBasedMovements; - } - - protected class ContentHolder extends AbstractComposite { - @Override - public void setComponent(Component component) { - if(getComponent() == component) { - return; - } - setFocusedInteractable(null); - super.setComponent(component); - if(focusedInteractable == null && component instanceof Interactable) { - setFocusedInteractable((Interactable)component); - } - else if(focusedInteractable == null && component instanceof Container) { - setFocusedInteractable(((Container)component).nextFocus(null)); - } - } - - public boolean removeComponent(Component component) { - boolean removed = super.removeComponent(component); - if (removed) { - focusedInteractable = null; - } - return removed; - } - - @Override - public TextGUI getTextGUI() { - return AbstractBasePane.this.getTextGUI(); - } - - @Override - protected ComponentRenderer createDefaultRenderer() { - return new ComponentRenderer() { - @Override - public TerminalSize getPreferredSize(Container component) { - Component subComponent = getComponent(); - if(subComponent == null) { - return TerminalSize.ZERO; - } - return subComponent.getPreferredSize(); - } - - @Override - public void drawComponent(TextGUIGraphics graphics, Container component) { - Component subComponent = getComponent(); - if(subComponent == null) { - return; - } - subComponent.draw(graphics); - } - }; - } - - @Override - public TerminalPosition toGlobal(TerminalPosition position) { - return AbstractBasePane.this.toGlobal(position); - } - - @Override - public TerminalPosition toBasePane(TerminalPosition position) { - return position; - } - - @Override - public BasePane getBasePane() { - return AbstractBasePane.this; - } - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractBorder.java b/src/com/googlecode/lanterna/gui2/AbstractBorder.java deleted file mode 100644 index 09f8f36..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractBorder.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; - -/** - * Abstract implementation of {@code Border} interface that has some of the methods filled out. If you want to create - * your own {@code Border} implementation, should should probably extend from this. - * @author Martin - */ -public abstract class AbstractBorder extends AbstractComposite implements Border { - @Override - public void setComponent(Component component) { - super.setComponent(component); - if(component != null) { - component.setPosition(TerminalPosition.TOP_LEFT_CORNER); - } - } - - @Override - public BorderRenderer getRenderer() { - return (BorderRenderer)super.getRenderer(); - } - - @Override - public Border setSize(TerminalSize size) { - super.setSize(size); - getComponent().setSize(getWrappedComponentSize(size)); - return self(); - } - - @Override - public LayoutData getLayoutData() { - return getComponent().getLayoutData(); - } - - @Override - public Border setLayoutData(LayoutData ld) { - getComponent().setLayoutData(ld); - return this; - } - - @Override - public TerminalPosition toBasePane(TerminalPosition position) { - return super.toBasePane(position).withRelative(getWrappedComponentTopLeftOffset()); - } - - @Override - public TerminalPosition toGlobal(TerminalPosition position) { - return super.toGlobal(position).withRelative(getWrappedComponentTopLeftOffset()); - } - - private TerminalPosition getWrappedComponentTopLeftOffset() { - return getRenderer().getWrappedComponentTopLeftOffset(); - } - - private TerminalSize getWrappedComponentSize(TerminalSize borderSize) { - return getRenderer().getWrappedComponentSize(borderSize); - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractComponent.java b/src/com/googlecode/lanterna/gui2/AbstractComponent.java deleted file mode 100644 index fb7c1e7..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractComponent.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; - -/** - * AbstractComponent provides some good default behaviour for a {@code Component}, all components in Lanterna extends - * from this class in some way. If you want to write your own component that isn't interactable or theme:able, you - * probably want to extend from this class. - *

- * The way you want to declare your new {@code Component} is to pass in itself as the generic parameter, like this: - *

- * {@code
- *     public class MyComponent extends AbstractComponent {
- *         ...
- *     }
- * }
- * 
- * This was, the component renderer will be correctly setup type-wise and you will need to do fewer typecastings when - * you implement the drawing method your new component. - * - * @author Martin - * @param Should always be itself, this value will be used for the {@code ComponentRenderer} declaration - */ -public abstract class AbstractComponent implements Component { - private ComponentRenderer renderer; - private Container parent; - private TerminalSize size; - private TerminalSize explicitPreferredSize; //This is keeping the value set by the user (if setPreferredSize() is used) - private TerminalPosition position; - private LayoutData layoutData; - private boolean invalid; - - /** - * Default constructor - */ - public AbstractComponent() { - size = TerminalSize.ZERO; - position = TerminalPosition.TOP_LEFT_CORNER; - explicitPreferredSize = null; - layoutData = null; - invalid = true; - parent = null; - renderer = null; //Will be set on the first call to getRenderer() - } - - /** - * When you create a custom component, you need to implement this method and return a Renderer which is responsible - * for taking care of sizing the component, rendering it and choosing where to place the cursor (if Interactable). - * This value is intended to be overridden by custom themes. - * @return Renderer to use when sizing and drawing this component - */ - protected abstract ComponentRenderer createDefaultRenderer(); - - /** - * This will attempt to dynamically construct a {@code ComponentRenderer} class from a string, assumed to be passed - * in from a theme. This makes it possible to create themes that supplies their own {@code ComponentRenderers} that - * can even replace the ones built into lanterna and used for the bundled components. - * - * @param className Fully qualified name of the {@code ComponentRenderer} we want to instatiate - * @return {@code null} if {@code className} was null, otherwise the {@code ComponentRenderer} instance - * @throws RuntimeException If there were any problems instatiating the class - */ - @SuppressWarnings("unchecked") - protected ComponentRenderer getRendererFromTheme(String className) { - if(className == null) { - return null; - } - try { - return (ComponentRenderer)Class.forName(className).newInstance(); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - - /** - * Takes a {@code Runnable} and immediately executes it if this is called on the designated GUI thread, otherwise - * schedules it for later invocation. - * @param runnable {@code Runnable} to execute on the GUI thread - */ - protected void runOnGUIThreadIfExistsOtherwiseRunDirect(Runnable runnable) { - if(getTextGUI() != null && getTextGUI().getGUIThread() != null) { - getTextGUI().getGUIThread().invokeLater(runnable); - } - else { - runnable.run(); - } - } - - /** - * Explicitly sets the {@code ComponentRenderer} to be used when drawing this component. - * @param renderer {@code ComponentRenderer} to be used when drawing this component - * @return Itself - */ - public T setRenderer(ComponentRenderer renderer) { - this.renderer = renderer; - return self(); - } - - @Override - public synchronized ComponentRenderer getRenderer() { - if(renderer == null) { - renderer = createDefaultRenderer(); - if(renderer == null) { - throw new IllegalStateException(getClass() + " returns a null default renderer"); - } - } - return renderer; - } - - @Override - public void invalidate() { - invalid = true; - } - - @Override - public synchronized T setSize(TerminalSize size) { - this.size = size; - return self(); - } - - @Override - public TerminalSize getSize() { - return size; - } - - @Override - public final TerminalSize getPreferredSize() { - if(explicitPreferredSize != null) { - return explicitPreferredSize; - } - else { - return calculatePreferredSize(); - } - } - - @Override - public final synchronized T setPreferredSize(TerminalSize explicitPreferredSize) { - this.explicitPreferredSize = explicitPreferredSize; - return self(); - } - - /** - * Invokes the component renderer's size calculation logic and returns the result. This value represents the - * preferred size and isn't necessarily what it will eventually be assigned later on. - * @return Size that the component renderer believes the component should be - */ - protected synchronized TerminalSize calculatePreferredSize() { - return getRenderer().getPreferredSize(self()); - } - - @Override - public synchronized T setPosition(TerminalPosition position) { - this.position = position; - return self(); - } - - @Override - public TerminalPosition getPosition() { - return position; - } - - @Override - public boolean isInvalid() { - return invalid; - } - - @Override - public final synchronized void draw(final TextGUIGraphics graphics) { - if(getRenderer() == null) { - ComponentRenderer renderer = getRendererFromTheme(graphics.getThemeDefinition(getClass()).getRenderer()); - if(renderer == null) { - renderer = createDefaultRenderer(); - if(renderer == null) { - throw new IllegalStateException(getClass() + " returned a null default renderer"); - } - } - setRenderer(renderer); - } - //Delegate drawing the component to the renderer - setSize(graphics.getSize()); - onBeforeDrawing(); - getRenderer().drawComponent(graphics, self()); - onAfterDrawing(graphics); - invalid = false; - } - - /** - * This method is called just before the component's renderer is invoked for the drawing operation. You can use this - * hook to do some last-minute adjustments to the component, as an alternative to coding it into the renderer - * itself. The component should have the correct size and position at this point, if you call {@code getSize()} and - * {@code getPosition()}. - */ - protected void onBeforeDrawing() { - //No operation by default - } - - /** - * This method is called immediately after the component's renderer has finished the drawing operation. You can use - * this hook to do some post-processing if you need, as an alternative to coding it into the renderer. The - * {@code TextGUIGraphics} supplied is the same that was fed into the renderer. - * @param graphics Graphics object you can use to manipulate the appearance of the component - */ - protected void onAfterDrawing(TextGUIGraphics graphics) { - //No operation by default - } - - @Override - public synchronized T setLayoutData(LayoutData data) { - if(layoutData != data) { - layoutData = data; - invalidate(); - } - return self(); - } - - @Override - public LayoutData getLayoutData() { - return layoutData; - } - - @Override - public Container getParent() { - return parent; - } - - @Override - public boolean hasParent(Container parent) { - if(this.parent == null) { - return false; - } - Container recursiveParent = this.parent; - while(recursiveParent != null) { - if(recursiveParent == parent) { - return true; - } - recursiveParent = recursiveParent.getParent(); - } - return false; - } - - @Override - public TextGUI getTextGUI() { - if(parent == null) { - return null; - } - return parent.getTextGUI(); - } - - @Override - public boolean isInside(Container container) { - Component test = this; - while(test.getParent() != null) { - if(test.getParent() == container) { - return true; - } - test = test.getParent(); - } - return false; - } - - @Override - public BasePane getBasePane() { - if(parent == null) { - return null; - } - return parent.getBasePane(); - } - - @Override - public TerminalPosition toBasePane(TerminalPosition position) { - Container parent = getParent(); - if(parent == null) { - return null; - } - return parent.toBasePane(getPosition().withRelative(position)); - } - - @Override - public TerminalPosition toGlobal(TerminalPosition position) { - Container parent = getParent(); - if(parent == null) { - return null; - } - return parent.toGlobal(getPosition().withRelative(position)); - } - - @Override - public synchronized Border withBorder(Border border) { - border.setComponent(this); - return border; - } - - @Override - public synchronized T addTo(Panel panel) { - panel.addComponent(this); - return self(); - } - - @Override - public synchronized void onAdded(Container container) { - parent = container; - } - - @Override - public synchronized void onRemoved(Container container) { - parent = null; - } - - /** - * This is a little hack to avoid doing typecasts all over the place when having to return {@code T}. Credit to - * avl42 for this one! - * @return Itself, but as type T - */ - @SuppressWarnings("unchecked") - protected T self() { - return (T)this; - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractComposite.java b/src/com/googlecode/lanterna/gui2/AbstractComposite.java deleted file mode 100644 index 325d8b5..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractComposite.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.input.KeyStroke; - -import java.util.Collection; -import java.util.Collections; - -/** - * This abstract implementation contains common code for the different {@code Composite} implementations. A - * {@code Composite} component is one that encapsulates a single component, like borders. Because of this, a - * {@code Composite} can be seen as a special case of a {@code Container} and indeed this abstract class does in fact - * implement the {@code Container} interface as well, to make the composites easier to work with internally. - * @author martin - * @param Should always be itself, see {@code AbstractComponent} - */ -public abstract class AbstractComposite extends AbstractComponent implements Composite, Container { - - private Component component; - - /** - * Default constructor - */ - public AbstractComposite() { - component = null; - } - - @Override - public void setComponent(Component component) { - Component oldComponent = this.component; - if(oldComponent == component) { - return; - } - if(oldComponent != null) { - removeComponent(oldComponent); - } - if(component != null) { - this.component = component; - component.onAdded(this); - component.setPosition(TerminalPosition.TOP_LEFT_CORNER); - invalidate(); - } - } - - @Override - public Component getComponent() { - return component; - } - - @Override - public int getChildCount() { - return component != null ? 1 : 0; - } - - @Override - public Collection getChildren() { - if(component != null) { - return Collections.singletonList(component); - } - else { - return Collections.emptyList(); - } - } - - @Override - public boolean containsComponent(Component component) { - return component != null && component.hasParent(this); - } - - @Override - public boolean removeComponent(Component component) { - if(this.component == component) { - this.component = null; - component.onRemoved(this); - invalidate(); - return true; - } - return false; - } - - @Override - public boolean isInvalid() { - return component != null && component.isInvalid(); - } - - @Override - public void invalidate() { - super.invalidate(); - - //Propagate - if(component != null) { - component.invalidate(); - } - } - - @Override - public Interactable nextFocus(Interactable fromThis) { - if(fromThis == null && getComponent() instanceof Interactable) { - return (Interactable)getComponent(); - } - else if(getComponent() instanceof Container) { - return ((Container)getComponent()).nextFocus(fromThis); - } - return null; - } - - @Override - public Interactable previousFocus(Interactable fromThis) { - if(fromThis == null && getComponent() instanceof Interactable) { - return (Interactable)getComponent(); - } - else if(getComponent() instanceof Container) { - return ((Container)getComponent()).previousFocus(fromThis); - } - return null; - } - - @Override - public boolean handleInput(KeyStroke key) { - return false; - } - - @Override - public void updateLookupMap(InteractableLookupMap interactableLookupMap) { - if(getComponent() instanceof Container) { - ((Container)getComponent()).updateLookupMap(interactableLookupMap); - } - else if(getComponent() instanceof Interactable) { - interactableLookupMap.add((Interactable)getComponent()); - } - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractInteractableComponent.java b/src/com/googlecode/lanterna/gui2/AbstractInteractableComponent.java deleted file mode 100644 index db43899..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractInteractableComponent.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.input.KeyStroke; - -/** - * Default implementation of Interactable that extends from AbstractComponent. If you want to write your own component - * that is interactable, i.e. can receive keyboard (and mouse) input, you probably want to extend from this class as - * it contains some common implementations of the methods from {@code Interactable} interface - * @param Should always be itself, see {@code AbstractComponent} - * @author Martin - */ -public abstract class AbstractInteractableComponent> extends AbstractComponent implements Interactable { - - private InputFilter inputFilter; - private boolean inFocus; - - /** - * Default constructor - */ - protected AbstractInteractableComponent() { - inputFilter = null; - inFocus = false; - } - - @Override - public T takeFocus() { - BasePane basePane = getBasePane(); - if(basePane != null) { - basePane.setFocusedInteractable(this); - } - return self(); - } - - /** - * {@inheritDoc} - *

- * This method is final in {@code AbstractInteractableComponent}, please override {@code afterEnterFocus} instead - */ - @Override - public final void onEnterFocus(FocusChangeDirection direction, Interactable previouslyInFocus) { - inFocus = true; - afterEnterFocus(direction, previouslyInFocus); - } - - /** - * Called by {@code AbstractInteractableComponent} automatically after this component has received input focus. You - * can override this method if you need to trigger some action based on this. - * @param direction How focus was transferred, keep in mind this is from the previous component's point of view so - * if this parameter has value DOWN, focus came in from above - * @param previouslyInFocus Which interactable component had focus previously - */ - @SuppressWarnings("EmptyMethod") - protected void afterEnterFocus(FocusChangeDirection direction, Interactable previouslyInFocus) { - //By default no action - } - - /** - * {@inheritDoc} - *

- * This method is final in {@code AbstractInteractableComponent}, please override {@code afterLeaveFocus} instead - */ - @Override - public final void onLeaveFocus(FocusChangeDirection direction, Interactable nextInFocus) { - inFocus = false; - afterLeaveFocus(direction, nextInFocus); - } - - /** - * Called by {@code AbstractInteractableComponent} automatically after this component has lost input focus. You - * can override this method if you need to trigger some action based on this. - * @param direction How focus was transferred, keep in mind this is from the this component's point of view so - * if this parameter has value DOWN, focus is moving down to a component below - * @param nextInFocus Which interactable component is going to receive focus - */ - @SuppressWarnings("EmptyMethod") - protected void afterLeaveFocus(FocusChangeDirection direction, Interactable nextInFocus) { - //By default no action - } - - @Override - protected abstract InteractableRenderer createDefaultRenderer(); - - @Override - public InteractableRenderer getRenderer() { - return (InteractableRenderer)super.getRenderer(); - } - - @Override - public boolean isFocused() { - return inFocus; - } - - @Override - public final synchronized Result handleInput(KeyStroke keyStroke) { - if(inputFilter == null || inputFilter.onInput(this, keyStroke)) { - return handleKeyStroke(keyStroke); - } - else { - return Result.UNHANDLED; - } - } - - /** - * This method can be overridden to handle various user input (mostly from the keyboard) when this component is in - * focus. The input method from the interface, {@code handleInput(..)} is final in - * {@code AbstractInteractableComponent} to ensure the input filter is properly handled. If the filter decides that - * this event should be processed, it will call this method. - * @param keyStroke What input was entered by the user - * @return Result of processing the key-stroke - */ - protected Result handleKeyStroke(KeyStroke keyStroke) { - // Skip the keystroke if ctrl, alt or shift was down - if(!keyStroke.isAltDown() && !keyStroke.isCtrlDown() && !keyStroke.isShiftDown()) { - switch(keyStroke.getKeyType()) { - case ArrowDown: - return Result.MOVE_FOCUS_DOWN; - case ArrowLeft: - return Result.MOVE_FOCUS_LEFT; - case ArrowRight: - return Result.MOVE_FOCUS_RIGHT; - case ArrowUp: - return Result.MOVE_FOCUS_UP; - case Tab: - return Result.MOVE_FOCUS_NEXT; - case ReverseTab: - return Result.MOVE_FOCUS_PREVIOUS; - case MouseEvent: - getBasePane().setFocusedInteractable(this); - return Result.HANDLED; - default: - } - } - return Result.UNHANDLED; - } - - @Override - public TerminalPosition getCursorLocation() { - return getRenderer().getCursorLocation(self()); - } - - @Override - public InputFilter getInputFilter() { - return inputFilter; - } - - @Override - public synchronized T setInputFilter(InputFilter inputFilter) { - this.inputFilter = inputFilter; - return self(); - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractListBox.java b/src/com/googlecode/lanterna/gui2/AbstractListBox.java deleted file mode 100644 index d4f1417..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractListBox.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalTextUtils; -import com.googlecode.lanterna.Symbols; -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.input.KeyStroke; - -import java.util.ArrayList; -import java.util.List; - -/** - * Base class for several list box implementations, this will handle things like list of items and the scrollbar. - * @param Should always be itself, see {@code AbstractComponent} - * @param Type of items this list box contains - * @author Martin - */ -public abstract class AbstractListBox> extends AbstractInteractableComponent { - private final List items; - private int selectedIndex; - private ListItemRenderer listItemRenderer; - - /** - * This constructor sets up the component so it has no preferred size but will ask to be as big as the list is. If - * the GUI cannot accommodate this size, scrolling and a vertical scrollbar will be used. - */ - protected AbstractListBox() { - this(null); - } - - /** - * This constructor sets up the component with a preferred size that is will always request, no matter what items - * are in the list box. If there are more items than the size can contain, scrolling and a vertical scrollbar will - * be used. Calling this constructor with a {@code null} value has the same effect as calling the default - * constructor. - * - * @param size Preferred size that the list should be asking for instead of invoking the preferred size calculation, - * or if set to {@code null} will ask to be big enough to display all items. - */ - protected AbstractListBox(TerminalSize size) { - this.items = new ArrayList(); - this.selectedIndex = -1; - setPreferredSize(size); - setListItemRenderer(createDefaultListItemRenderer()); - } - - @Override - protected InteractableRenderer createDefaultRenderer() { - return new DefaultListBoxRenderer(); - } - - /** - * Method that constructs the {@code ListItemRenderer} that this list box should use to draw the elements of the - * list box. This can be overridden to supply a custom renderer. Note that this is not the renderer used for the - * entire list box but for each item, called one by one. - * @return {@code ListItemRenderer} to use when drawing the items in the list - */ - protected ListItemRenderer createDefaultListItemRenderer() { - return new ListItemRenderer(); - } - - ListItemRenderer getListItemRenderer() { - return listItemRenderer; - } - - /** - * This method overrides the {@code ListItemRenderer} that is used to draw each element in the list box. Note that - * this is not the renderer used for the entire list box but for each item, called one by one. - * @param listItemRenderer New renderer to use when drawing the items in the list box - * @return Itself - */ - public synchronized T setListItemRenderer(ListItemRenderer listItemRenderer) { - if(listItemRenderer == null) { - listItemRenderer = createDefaultListItemRenderer(); - if(listItemRenderer == null) { - throw new IllegalStateException("createDefaultListItemRenderer returned null"); - } - } - this.listItemRenderer = listItemRenderer; - return self(); - } - - @Override - public synchronized Result handleKeyStroke(KeyStroke keyStroke) { - try { - switch(keyStroke.getKeyType()) { - case Tab: - return Result.MOVE_FOCUS_NEXT; - - case ReverseTab: - return Result.MOVE_FOCUS_PREVIOUS; - - case ArrowRight: - return Result.MOVE_FOCUS_RIGHT; - - case ArrowLeft: - return Result.MOVE_FOCUS_LEFT; - - case ArrowDown: - if(items.isEmpty() || selectedIndex == items.size() - 1) { - return Result.MOVE_FOCUS_DOWN; - } - selectedIndex++; - return Result.HANDLED; - - case ArrowUp: - if(items.isEmpty() || selectedIndex == 0) { - return Result.MOVE_FOCUS_UP; - } - selectedIndex--; - return Result.HANDLED; - - case Home: - selectedIndex = 0; - return Result.HANDLED; - - case End: - selectedIndex = items.size() - 1; - return Result.HANDLED; - - case PageUp: - if(getSize() != null) { - setSelectedIndex(getSelectedIndex() - getSize().getRows()); - } - return Result.HANDLED; - - case PageDown: - if(getSize() != null) { - setSelectedIndex(getSelectedIndex() + getSize().getRows()); - } - return Result.HANDLED; - - default: - } - return Result.UNHANDLED; - } - finally { - invalidate(); - } - } - - @Override - protected synchronized void afterEnterFocus(FocusChangeDirection direction, Interactable previouslyInFocus) { - if(items.isEmpty()) { - return; - } - - if(direction == FocusChangeDirection.DOWN) { - selectedIndex = 0; - } - else if(direction == FocusChangeDirection.UP) { - selectedIndex = items.size() - 1; - } - } - - /** - * Adds one more item to the list box, at the end. - * @param item Item to add to the list box - * @return Itself - */ - public synchronized T addItem(V item) { - if(item == null) { - return self(); - } - - items.add(item); - if(selectedIndex == -1) { - selectedIndex = 0; - } - invalidate(); - return self(); - } - - /** - * Removes all items from the list box - * @return Itself - */ - public synchronized T clearItems() { - items.clear(); - selectedIndex = -1; - invalidate(); - return self(); - } - - /** - * Looks for the particular item in the list and returns the index within the list (starting from zero) of that item - * if it is found, or -1 otherwise - * @param item What item to search for in the list box - * @return Index of the item in the list box or -1 if the list box does not contain the item - */ - public synchronized int indexOf(V item) { - return items.indexOf(item); - } - - /** - * Retrieves the item at the specified index in the list box - * @param index Index of the item to fetch - * @return The item at the specified index - * @throws IndexOutOfBoundsException If the index is less than zero or equals/greater than the number of items in - * the list box - */ - public synchronized V getItemAt(int index) { - return items.get(index); - } - - /** - * Checks if the list box has no items - * @return {@code true} if the list box has no items, {@code false} otherwise - */ - public synchronized boolean isEmpty() { - return items.isEmpty(); - } - - /** - * Returns the number of items currently in the list box - * @return Number of items in the list box - */ - public synchronized int getItemCount() { - return items.size(); - } - - /** - * Returns a copy of the items in the list box as a {@code List} - * @return Copy of all the items in this list box - */ - public synchronized List getItems() { - return new ArrayList(items); - } - - /** - * Sets which item in the list box that is currently selected. Please note that in this context, selected simply - * means it is the item that currently has input focus. This is not to be confused with list box implementations - * such as {@code CheckBoxList} where individual items have a certain checked/unchecked state. - * @param index Index of the item that should be currently selected - * @return Itself - */ - public synchronized T setSelectedIndex(int index) { - selectedIndex = index; - if(selectedIndex < 0) { - selectedIndex = 0; - } - if(selectedIndex > items.size() - 1) { - selectedIndex = items.size() - 1; - } - invalidate(); - return self(); - } - - /** - * Returns the index of the currently selected item in the list box. Please note that in this context, selected - * simply means it is the item that currently has input focus. This is not to be confused with list box - * implementations such as {@code CheckBoxList} where individual items have a certain checked/unchecked state. - * @return The index of the currently selected row in the list box, or -1 if there are no items - */ - public int getSelectedIndex() { - return selectedIndex; - } - - /** - * Returns the currently selected item in the list box. Please note that in this context, selected - * simply means it is the item that currently has input focus. This is not to be confused with list box - * implementations such as {@code CheckBoxList} where individual items have a certain checked/unchecked state. - * @return The currently selected item in the list box, or {@code null} if there are no items - */ - public synchronized V getSelectedItem() { - if (selectedIndex == -1) { - return null; - } else { - return items.get(selectedIndex); - } - } - - /** - * The default renderer for {@code AbstractListBox} and all its subclasses. - * @param Type of the items the list box this renderer is for - * @param Type of list box - */ - public static class DefaultListBoxRenderer> implements InteractableRenderer { - private int scrollTopIndex; - - /** - * Default constructor - */ - public DefaultListBoxRenderer() { - this.scrollTopIndex = 0; - } - - @Override - public TerminalPosition getCursorLocation(T listBox) { - int selectedIndex = listBox.getSelectedIndex(); - int columnAccordingToRenderer = listBox.getListItemRenderer().getHotSpotPositionOnLine(selectedIndex); - if(columnAccordingToRenderer == -1) { - return null; - } - return new TerminalPosition(columnAccordingToRenderer, selectedIndex - scrollTopIndex); - } - - @Override - public TerminalSize getPreferredSize(T listBox) { - int maxWidth = 5; //Set it to something... - int index = 0; - for (V item : listBox.getItems()) { - String itemString = listBox.getListItemRenderer().getLabel(listBox, index++, item); - int stringLengthInColumns = TerminalTextUtils.getColumnWidth(itemString); - if (stringLengthInColumns > maxWidth) { - maxWidth = stringLengthInColumns; - } - } - return new TerminalSize(maxWidth + 1, listBox.getItemCount()); - } - - @Override - public void drawComponent(TextGUIGraphics graphics, T listBox) { - //update the page size, used for page up and page down keys - int componentHeight = graphics.getSize().getRows(); - int componentWidth = graphics.getSize().getColumns(); - int selectedIndex = listBox.getSelectedIndex(); - List items = listBox.getItems(); - ListItemRenderer listItemRenderer = listBox.getListItemRenderer(); - - if(selectedIndex != -1) { - if(selectedIndex < scrollTopIndex) - scrollTopIndex = selectedIndex; - else if(selectedIndex >= componentHeight + scrollTopIndex) - scrollTopIndex = selectedIndex - componentHeight + 1; - } - - //Do we need to recalculate the scroll position? - //This code would be triggered by resizing the window when the scroll - //position is at the bottom - if(items.size() > componentHeight && - items.size() - scrollTopIndex < componentHeight) { - scrollTopIndex = items.size() - componentHeight; - } - - graphics.applyThemeStyle(graphics.getThemeDefinition(AbstractListBox.class).getNormal()); - graphics.fill(' '); - - TerminalSize itemSize = graphics.getSize().withRows(1); - for(int i = scrollTopIndex; i < items.size(); i++) { - if(i - scrollTopIndex >= componentHeight) { - break; - } - listItemRenderer.drawItem( - graphics.newTextGraphics(new TerminalPosition(0, i - scrollTopIndex), itemSize), - listBox, - i, - items.get(i), - selectedIndex == i, - listBox.isFocused()); - } - - graphics.applyThemeStyle(graphics.getThemeDefinition(AbstractListBox.class).getNormal()); - if(items.size() > componentHeight) { - graphics.putString(componentWidth - 1, 0, Symbols.ARROW_UP + ""); - - graphics.applyThemeStyle(graphics.getThemeDefinition(AbstractListBox.class).getInsensitive()); - for(int i = 1; i < componentHeight - 1; i++) - graphics.putString(componentWidth - 1, i, Symbols.BLOCK_MIDDLE + ""); - - graphics.applyThemeStyle(graphics.getThemeDefinition(AbstractListBox.class).getNormal()); - graphics.putString(componentWidth - 1, componentHeight - 1, Symbols.ARROW_DOWN + ""); - - //Finally print the 'tick' - int scrollableSize = items.size() - componentHeight; - double position = (double)scrollTopIndex / ((double)scrollableSize); - int tickPosition = (int)(((double) componentHeight - 3.0) * position); - graphics.applyThemeStyle(graphics.getThemeDefinition(AbstractListBox.class).getInsensitive()); - graphics.putString(componentWidth - 1, 1 + tickPosition, " "); - } - } - } - - /** - * The default list item renderer class, this can be extended and customized it needed. The instance which is - * assigned to the list box will be called once per item in the list when the list box is drawn. - * @param Type of the items in the list box - * @param Type of the list box class itself - */ - public static class ListItemRenderer> { - /** - * Returns where on the line to place the text terminal cursor for a currently selected item. By default this - * will return 0, meaning the first character of the selected line. If you extend {@code ListItemRenderer} you - * can change this by returning a different number. Returning -1 will cause lanterna to hide the cursor. - * @param selectedIndex Which item is currently selected - * @return Index of the character in the string we want to place the terminal cursor on, or -1 to hide it - */ - public int getHotSpotPositionOnLine(int selectedIndex) { - return 0; - } - - /** - * Given a list box, an index of an item within that list box and what the item is, this method should return - * what to draw for that item. The default implementation is to return whatever {@code toString()} returns when - * called on the item. - * @param listBox List box the item belongs to - * @param index Index of the item - * @param item The item itself - * @return String to draw for this item - */ - public String getLabel(T listBox, int index, V item) { - return item != null ? item.toString() : ""; - } - - /** - * This is the main drawing method for a single list box item, it applies the current theme to setup the colors - * and then calls {@code getLabel(..)} and draws the result using the supplied {@code TextGUIGraphics}. The - * graphics object is created just for this item and is restricted so that it can only draw on the area this - * item is occupying. The top-left corner (0x0) should be the starting point when drawing the item. - * @param graphics Graphics object to draw with - * @param listBox List box we are drawing an item from - * @param index Index of the item we are drawing - * @param item The item we are drawing - * @param selected Will be set to {@code true} if the item is currently selected, otherwise {@code false}, but - * please notice what context 'selected' refers to here (see {@code setSelectedIndex}) - * @param focused Will be set to {@code true} if the list box currently has input focus, otherwise {@code false} - */ - public void drawItem(TextGUIGraphics graphics, T listBox, int index, V item, boolean selected, boolean focused) { - if(selected && focused) { - graphics.applyThemeStyle(graphics.getThemeDefinition(AbstractListBox.class).getSelected()); - } - else { - graphics.applyThemeStyle(graphics.getThemeDefinition(AbstractListBox.class).getNormal()); - } - String label = getLabel(listBox, index, item); - label = TerminalTextUtils.fitString(label, graphics.getSize().getColumns()); - graphics.putString(0, 0, label); - } - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractTextGUI.java b/src/com/googlecode/lanterna/gui2/AbstractTextGUI.java deleted file mode 100644 index f517faf..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractTextGUI.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.graphics.PropertiesTheme; -import com.googlecode.lanterna.graphics.Theme; -import com.googlecode.lanterna.input.KeyStroke; -import com.googlecode.lanterna.input.KeyType; -import com.googlecode.lanterna.screen.Screen; - -import java.io.EOFException; -import java.io.FileInputStream; - -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * This abstract implementation of TextGUI contains some basic management of the underlying Screen and other common code - * that can be shared between different implementations. - * @author Martin - */ -public abstract class AbstractTextGUI implements TextGUI { - - private final Screen screen; - private final List listeners; - private boolean blockingIO; - private boolean dirty; - private TextGUIThread textGUIThread; - private Theme guiTheme; - - /** - * Constructor for {@code AbstractTextGUI} that requires a {@code Screen} and a factory for creating the GUI thread - * @param textGUIThreadFactory Factory class to use for creating the {@code TextGUIThread} class - * @param screen What underlying {@code Screen} to use for this text GUI - */ - protected AbstractTextGUI(TextGUIThreadFactory textGUIThreadFactory, Screen screen) { - if(screen == null) { - throw new IllegalArgumentException("Creating a TextGUI requires an underlying Screen"); - } - this.screen = screen; - this.listeners = new CopyOnWriteArrayList(); - this.blockingIO = false; - this.dirty = false; - this.guiTheme = new PropertiesTheme(loadDefaultThemeProperties()); - this.textGUIThread = textGUIThreadFactory.createTextGUIThread(this); - } - - private static Properties loadDefaultThemeProperties() { - Properties properties = new Properties(); - try { - ClassLoader classLoader = AbstractTextGUI.class.getClassLoader(); - InputStream resourceAsStream = classLoader.getResourceAsStream("default-theme.properties"); - if(resourceAsStream == null) { - resourceAsStream = new FileInputStream("src/main/resources/default-theme.properties"); - } - properties.load(resourceAsStream); - resourceAsStream.close(); - return properties; - } - catch(IOException e) { - return properties; - } - } - - /** - * Reads one key from the input queue, blocking or non-blocking depending on if blocking I/O has been enabled. To - * enable blocking I/O (disabled by default), use {@code setBlockingIO(true)}. - * @return One piece of user input as a {@code KeyStroke} or {@code null} if blocking I/O is disabled and there was - * no input waiting - * @throws IOException In case of an I/O error while reading input - */ - protected KeyStroke readKeyStroke() throws IOException { - return blockingIO ? screen.readInput() : pollInput(); - } - - /** - * Polls the underlying input queue for user input, returning either a {@code KeyStroke} or {@code null} - * @return {@code KeyStroke} representing the user input or {@code null} if there was none - * @throws IOException In case of an I/O error while reading input - */ - protected KeyStroke pollInput() throws IOException { - return screen.pollInput(); - } - - @Override - public synchronized boolean processInput() throws IOException { - boolean gotInput = false; - KeyStroke keyStroke = readKeyStroke(); - if(keyStroke != null) { - gotInput = true; - do { - if (keyStroke.getKeyType() == KeyType.EOF) { - throw new EOFException(); - } - boolean handled = handleInput(keyStroke); - if(!handled) { - handled = fireUnhandledKeyStroke(keyStroke); - } - dirty = handled || dirty; - keyStroke = pollInput(); - } while(keyStroke != null); - } - return gotInput; - } - - @Override - public void setTheme(Theme theme) { - this.guiTheme = theme; - } - - @Override - public synchronized void updateScreen() throws IOException { - screen.doResizeIfNecessary(); - drawGUI(new TextGUIGraphics(this, screen.newTextGraphics(), guiTheme)); - screen.setCursorPosition(getCursorPosition()); - screen.refresh(); - dirty = false; - } - - @Override - public boolean isPendingUpdate() { - return screen.doResizeIfNecessary() != null || dirty; - } - - @Override - public TextGUIThread getGUIThread() { - return textGUIThread; - } - - @Override - public void addListener(Listener listener) { - listeners.add(listener); - } - - @Override - public void removeListener(Listener listener) { - listeners.remove(listener); - } - - /** - * Enables blocking I/O, causing calls to {@code readKeyStroke()} to block until there is input available. Notice - * that you can still poll for input using {@code pollInput()}. - * @param blockingIO Set this to {@code true} if blocking I/O should be enabled, otherwise {@code false} - */ - public void setBlockingIO(boolean blockingIO) { - this.blockingIO = blockingIO; - } - - /** - * Checks if blocking I/O is enabled or not - * @return {@code true} if blocking I/O is enabled, otherwise {@code false} - */ - public boolean isBlockingIO() { - return blockingIO; - } - - /** - * This method should be called when there was user input that wasn't handled by the GUI. It will fire the - * {@code onUnhandledKeyStroke(..)} method on any registered listener. - * @param keyStroke The {@code KeyStroke} that wasn't handled by the GUI - * @return {@code true} if at least one of the listeners handled the key stroke, this will signal to the GUI that it - * needs to be redrawn again. - */ - protected final boolean fireUnhandledKeyStroke(KeyStroke keyStroke) { - boolean handled = false; - for(Listener listener: listeners) { - handled = listener.onUnhandledKeyStroke(this, keyStroke) || handled; - } - return handled; - } - - /** - * Marks the whole text GUI as invalid and that it needs to be redrawn at next opportunity - */ - protected void invalidate() { - dirty = true; - } - - /** - * Draws the entire GUI using a {@code TextGUIGraphics} object - * @param graphics Graphics object to draw using - */ - protected abstract void drawGUI(TextGUIGraphics graphics); - - /** - * Top-level method for drilling in to the GUI and figuring out, in global coordinates, where to place the text - * cursor on the screen at this time. - * @return Where to place the text cursor, or {@code null} if the cursor should be hidden - */ - protected abstract TerminalPosition getCursorPosition(); - - /** - * This method should take the user input and feed it to the focused component for handling. - * @param key {@code KeyStroke} representing the user input - * @return {@code true} if the input was recognized and handled by the GUI, indicating that the GUI should be redrawn - */ - protected abstract boolean handleInput(KeyStroke key); -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractTextGUIThread.java b/src/com/googlecode/lanterna/gui2/AbstractTextGUIThread.java deleted file mode 100644 index f4a0016..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractTextGUIThread.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.googlecode.lanterna.gui2; - -import java.io.IOException; -import java.util.Queue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Created by martin on 20/06/15. - */ -public abstract class AbstractTextGUIThread implements TextGUIThread { - - protected final TextGUI textGUI; - protected final Queue customTasks; - protected ExceptionHandler exceptionHandler; - - public AbstractTextGUIThread(TextGUI textGUI) { - this.exceptionHandler = new ExceptionHandler() { - @Override - public boolean onIOException(IOException e) { - e.printStackTrace(); - return true; - } - - @Override - public boolean onRuntimeException(RuntimeException e) { - e.printStackTrace(); - return true; - } - }; - this.textGUI = textGUI; - this.customTasks = new LinkedBlockingQueue(); - } - - @Override - public void invokeLater(Runnable runnable) throws IllegalStateException { - customTasks.add(runnable); - } - - @Override - public void setExceptionHandler(ExceptionHandler exceptionHandler) { - if(exceptionHandler == null) { - throw new IllegalArgumentException("Cannot call setExceptionHandler(null)"); - } - this.exceptionHandler = exceptionHandler; - } - - @Override - public synchronized boolean processEventsAndUpdate() throws IOException { - if(getThread() != Thread.currentThread()) { - throw new IllegalStateException("Calling processEventAndUpdate outside of GUI thread"); - } - textGUI.processInput(); - while(!customTasks.isEmpty()) { - Runnable r = customTasks.poll(); - if(r != null) { - r.run(); - } - } - if(textGUI.isPendingUpdate()) { - textGUI.updateScreen(); - return true; - } - return false; - } - - @Override - public void invokeAndWait(final Runnable runnable) throws IllegalStateException, InterruptedException { - if(Thread.currentThread() == getThread()) { - runnable.run(); - } - else { - final CountDownLatch countDownLatch = new CountDownLatch(1); - invokeLater(new Runnable() { - @Override - public void run() { - try { - runnable.run(); - } - finally { - countDownLatch.countDown(); - } - } - }); - countDownLatch.await(); - } - } -} diff --git a/src/com/googlecode/lanterna/gui2/AbstractWindow.java b/src/com/googlecode/lanterna/gui2/AbstractWindow.java deleted file mode 100644 index 4e55f3d..0000000 --- a/src/com/googlecode/lanterna/gui2/AbstractWindow.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.input.KeyStroke; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.input.KeyType; - -import java.util.*; - -/** - * Abstract Window has most of the code requiring for a window to function, all concrete window implementations extends - * from this in one way or another. You can define your own window by extending from this, as an alternative to building - * up the GUI externally by constructing a {@code BasicWindow} and adding components to it. - * @author Martin - */ -public abstract class AbstractWindow extends AbstractBasePane implements Window { - private String title; - private WindowBasedTextGUI textGUI; - private boolean visible; - private TerminalSize lastKnownSize; - private TerminalSize lastKnownDecoratedSize; - private TerminalPosition lastKnownPosition; - private TerminalPosition contentOffset; - private Set hints; - private boolean closeWindowWithEscape; - - /** - * Default constructor, this creates a window with no title - */ - public AbstractWindow() { - this(""); - } - - /** - * Creates a window with a specific title that will (probably) be drawn in the window decorations - * @param title Title of this window - */ - public AbstractWindow(String title) { - super(); - this.title = title; - this.textGUI = null; - this.visible = true; - this.lastKnownPosition = null; - this.lastKnownSize = null; - this.lastKnownDecoratedSize = null; - this.closeWindowWithEscape = false; - - this.hints = new HashSet(); - } - - /** - * Setting this property to {@code true} will cause pressing the ESC key to close the window. This used to be the - * default behaviour of lanterna 3 during the development cycle but is not longer the case. You are encouraged to - * put proper buttons or other kind of components to clearly mark to the user how to close the window instead of - * magically taking ESC, but sometimes it can be useful (when doing testing, for example) to enable this mode. - * @param closeWindowWithEscape If {@code true}, this window will self-close if you press ESC key - */ - public void setCloseWindowWithEscape(boolean closeWindowWithEscape) { - this.closeWindowWithEscape = closeWindowWithEscape; - } - - @Override - public void setTextGUI(WindowBasedTextGUI textGUI) { - //This is kind of stupid check, but might cause it to blow up on people using the library incorrectly instead of - //just causing weird behaviour - if(this.textGUI != null && textGUI != null) { - throw new UnsupportedOperationException("Are you calling setTextGUI yourself? Please read the documentation" - + " in that case (this could also be a bug in Lanterna, please report it if you are sure you are " - + "not calling Window.setTextGUI(..) from your code)"); - } - this.textGUI = textGUI; - } - - @Override - public WindowBasedTextGUI getTextGUI() { - return textGUI; - } - - /** - * Alters the title of the window to the supplied string - * @param title New title of the window - */ - public void setTitle(String title) { - this.title = title; - invalidate(); - } - - @Override - public String getTitle() { - return title; - } - - @Override - public boolean isVisible() { - return visible; - } - - @Override - public void setVisible(boolean visible) { - this.visible = visible; - } - @Override - public void draw(TextGUIGraphics graphics) { - if(!graphics.getSize().equals(lastKnownSize)) { - getComponent().invalidate(); - } - setSize(graphics.getSize(), false); - super.draw(graphics); - } - - @Override - public boolean handleInput(KeyStroke key) { - boolean handled = super.handleInput(key); - if(!handled && closeWindowWithEscape && key.getKeyType() == KeyType.Escape) { - close(); - return true; - } - return handled; - } - - @Override - public TerminalPosition toGlobal(TerminalPosition localPosition) { - if(localPosition == null) { - return null; - } - return lastKnownPosition.withRelative(contentOffset.withRelative(localPosition)); - } - - @Override - public TerminalPosition fromGlobal(TerminalPosition globalPosition) { - if(globalPosition == null) { - return null; - } - return globalPosition.withRelative( - -lastKnownPosition.getColumn() - contentOffset.getColumn(), - -lastKnownPosition.getRow() - contentOffset.getRow()); - } - - @Override - public TerminalSize getPreferredSize() { - return contentHolder.getPreferredSize(); - } - - @Override - public void setHints(Collection hints) { - this.hints = new HashSet(hints); - invalidate(); - } - - @Override - public Set getHints() { - return Collections.unmodifiableSet(hints); - } - - @Override - public final TerminalPosition getPosition() { - return lastKnownPosition; - } - - @Override - public final void setPosition(TerminalPosition topLeft) { - this.lastKnownPosition = topLeft; - } - - @Override - public final TerminalSize getSize() { - return lastKnownSize; - } - - @Override - public void setSize(TerminalSize size) { - setSize(size, true); - } - - private void setSize(TerminalSize size, boolean invalidate) { - this.lastKnownSize = size; - if(invalidate) { - invalidate(); - } - } - - @Override - public final TerminalSize getDecoratedSize() { - return lastKnownDecoratedSize; - } - - @Override - public final void setDecoratedSize(TerminalSize decoratedSize) { - this.lastKnownDecoratedSize = decoratedSize; - } - - @Override - public void setContentOffset(TerminalPosition offset) { - this.contentOffset = offset; - } - - @Override - public void close() { - if(textGUI != null) { - textGUI.removeWindow(this); - } - setComponent(null); - } - - @Override - public void waitUntilClosed() { - WindowBasedTextGUI textGUI = getTextGUI(); - if(textGUI != null) { - textGUI.waitForWindowToClose(this); - } - } -} diff --git a/src/com/googlecode/lanterna/gui2/ActionListBox.java b/src/com/googlecode/lanterna/gui2/ActionListBox.java deleted file mode 100644 index a805b6e..0000000 --- a/src/com/googlecode/lanterna/gui2/ActionListBox.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.input.KeyStroke; -import com.googlecode.lanterna.input.KeyType; - -/** - * This class is a list box implementation that displays a number of items that has actions associated with them. You - * can activate this action by pressing the Enter or Space keys on the keyboard and the action associated with the - * currently selected item will fire. - * @author Martin - */ -public class ActionListBox extends AbstractListBox { - - /** - * Default constructor, creates an {@code ActionListBox} with no pre-defined size that will request to be big enough - * to display all items - */ - public ActionListBox() { - this(null); - } - - /** - * Creates a new {@code ActionListBox} with a pre-set size. If the items don't fit in within this size, scrollbars - * will be used to accommodate. Calling {@code new ActionListBox(null)} has the same effect as calling - * {@code new ActionListBox()}. - * @param preferredSize - */ - public ActionListBox(TerminalSize preferredSize) { - super(preferredSize); - } - - /** - * {@inheritDoc} - * - * The label of the item in the list box will be the result of calling {@code .toString()} on the runnable, which - * might not be what you want to have unless you explicitly declare it. Consider using - * {@code addItem(String label, Runnable action} instead, if you want to just set the label easily without having - * to override {@code .toString()}. - * - * @param object Runnable to execute when the action was selected and fired in the list - * @return Itself - */ - @Override - public ActionListBox addItem(Runnable object) { - return super.addItem(object); - } - - /** - * Adds a new item to the list, which is displayed in the list using a supplied label. - * @param label Label to use in the list for the new item - * @param action Runnable to invoke when this action is selected and then triggered - * @return Itself - */ - public ActionListBox addItem(final String label, final Runnable action) { - return addItem(new Runnable() { - @Override - public void run() { - action.run(); - } - - @Override - public String toString() { - return label; - } - }); - } - - @Override - public TerminalPosition getCursorLocation() { - return null; - } - - @Override - public Result handleKeyStroke(KeyStroke keyStroke) { - Object selectedItem = getSelectedItem(); - if(selectedItem != null && - (keyStroke.getKeyType() == KeyType.Enter || - (keyStroke.getKeyType() == KeyType.Character && keyStroke.getCharacter() == ' '))) { - - ((Runnable)selectedItem).run(); - return Result.HANDLED; - } - return super.handleKeyStroke(keyStroke); - } -} diff --git a/src/com/googlecode/lanterna/gui2/AnimatedLabel.java b/src/com/googlecode/lanterna/gui2/AnimatedLabel.java deleted file mode 100644 index 60e6021..0000000 --- a/src/com/googlecode/lanterna/gui2/AnimatedLabel.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalSize; - -import java.lang.ref.WeakReference; -import java.util.*; - -/** - * This is a special label that contains not just a single text to display but a number of frames that are cycled - * through. The class will manage a timer on its own and ensure the label is updated and redrawn. There is a static - * helper method available to create the classic "spinning bar": {@code createClassicSpinningLine()} - */ -public class AnimatedLabel extends Label { - private static Timer TIMER = null; - private static final WeakHashMap SCHEDULED_TASKS = new WeakHashMap(); - - /** - * Creates a classic spinning bar which can be used to signal to the user that an operation in is process. - * @return {@code AnimatedLabel} instance which is setup to show a spinning bar - */ - public static AnimatedLabel createClassicSpinningLine() { - return createClassicSpinningLine(150); - } - - /** - * Creates a classic spinning bar which can be used to signal to the user that an operation in is process. - * @param speed Delay in between each frame - * @return {@code AnimatedLabel} instance which is setup to show a spinning bar - */ - public static AnimatedLabel createClassicSpinningLine(int speed) { - AnimatedLabel animatedLabel = new AnimatedLabel("-"); - animatedLabel.addFrame("\\"); - animatedLabel.addFrame("|"); - animatedLabel.addFrame("/"); - animatedLabel.startAnimation(speed); - return animatedLabel; - } - - private final List frames; - private TerminalSize combinedMaximumPreferredSize; - private int currentFrame; - - /** - * Creates a new animated label, initially set to one frame. You will need to add more frames and call - * {@code startAnimation()} for this to start moving. - * - * @param firstFrameText The content of the label at the first frame - */ - public AnimatedLabel(String firstFrameText) { - super(firstFrameText); - frames = new ArrayList(); - currentFrame = 0; - combinedMaximumPreferredSize = TerminalSize.ZERO; - - String[] lines = splitIntoMultipleLines(firstFrameText); - frames.add(lines); - ensurePreferredSize(lines); - } - - /** - * Adds one more frame at the end of the list of frames - * @param text Text to use for the label at this frame - */ - public synchronized void addFrame(String text) { - String[] lines = splitIntoMultipleLines(text); - frames.add(lines); - ensurePreferredSize(lines); - } - - private void ensurePreferredSize(String[] lines) { - combinedMaximumPreferredSize = combinedMaximumPreferredSize.max(getBounds(lines, combinedMaximumPreferredSize)); - } - - /** - * Advances the animated label to the next frame. You normally don't need to call this manually as it will be done - * by the animation thread. - */ - public synchronized void nextFrame() { - currentFrame++; - if(currentFrame >= frames.size()) { - currentFrame = 0; - } - super.setLines(frames.get(currentFrame)); - invalidate(); - } - - @Override - public void onRemoved(Container container) { - stopAnimation(); - } - - /** - * Starts the animation thread which will periodically call {@code nextFrame()} at the interval specified by the - * {@code millisecondsPerFrame} parameter. After all frames have been cycled through, it will start over from the - * first frame again. - * @param millisecondsPerFrame The interval in between every frame - */ - public synchronized void startAnimation(long millisecondsPerFrame) { - if(TIMER == null) { - TIMER = new Timer("AnimatedLabel"); - } - AnimationTimerTask animationTimerTask = new AnimationTimerTask(this); - SCHEDULED_TASKS.put(this, animationTimerTask); - TIMER.scheduleAtFixedRate(animationTimerTask, millisecondsPerFrame, millisecondsPerFrame); - } - - /** - * Halts the animation thread and the label will stop at whatever was the current frame at the time when this was - * called - */ - public synchronized void stopAnimation() { - removeTaskFromTimer(this); - } - - private static synchronized void removeTaskFromTimer(AnimatedLabel animatedLabel) { - SCHEDULED_TASKS.get(animatedLabel).cancel(); - SCHEDULED_TASKS.remove(animatedLabel); - canCloseTimer(); - } - - private static synchronized void canCloseTimer() { - if(SCHEDULED_TASKS.isEmpty()) { - TIMER.cancel(); - TIMER = null; - } - } - - private static class AnimationTimerTask extends TimerTask { - private final WeakReference labelRef; - - private AnimationTimerTask(AnimatedLabel label) { - this.labelRef = new WeakReference(label); - } - - @Override - public void run() { - AnimatedLabel animatedLabel = labelRef.get(); - if(animatedLabel == null) { - cancel(); - canCloseTimer(); - } - else { - if(animatedLabel.getBasePane() == null) { - animatedLabel.stopAnimation(); - } - else { - animatedLabel.nextFrame(); - } - } - } - } -} diff --git a/src/com/googlecode/lanterna/gui2/AsynchronousTextGUIThread.java b/src/com/googlecode/lanterna/gui2/AsynchronousTextGUIThread.java deleted file mode 100644 index 67efa01..0000000 --- a/src/com/googlecode/lanterna/gui2/AsynchronousTextGUIThread.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.googlecode.lanterna.gui2; - -/** - * Extended interface of TextGUIThread for implementations that uses a separate thread for all GUI event processing and - * updating. - * - * @author Martin - */ -public interface AsynchronousTextGUIThread extends TextGUIThread { - /** - * Starts the AsynchronousTextGUIThread, typically meaning that the event processing loop will start. - */ - void start(); - - /** - * Requests that the AsynchronousTextGUIThread stops, typically meaning that the event processing loop will exit - */ - void stop(); - - /** - * Blocks until the GUI loop has stopped - * @throws InterruptedException In case this thread was interrupted while waiting for the GUI thread to exit - */ - void waitForStop() throws InterruptedException; - - /** - * Returns the current status of this GUI thread - * @return Current status of the GUI thread - */ - State getState(); - - /** - * Enum representing the states of the GUI thread life-cycle - */ - enum State { - /** - * The instance has been created but not yet started - */ - CREATED, - /** - * The thread has started an is running - */ - STARTED, - /** - * The thread is trying to stop but is still running - */ - STOPPING, - /** - * The thread has stopped - */ - STOPPED, - ; - } -} diff --git a/src/com/googlecode/lanterna/gui2/BasePane.java b/src/com/googlecode/lanterna/gui2/BasePane.java deleted file mode 100644 index 1f3c10e..0000000 --- a/src/com/googlecode/lanterna/gui2/BasePane.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.input.KeyStroke; - -/** - * BasePane is the base container in a Text GUI. A text gui may have several base panes, although they are - * always independent. One common example of this is a multi-window system where each window is a base pane. Think of - * the base pane as a root container, the ultimate parent of all components added to a GUI. When you use - * {@code MultiWindowTextGUI}, the background space behind the windows is a {@code BasePane} too, just like each of the - * windows. They are all drawn separately and composited together. Every {@code BasePane} has a single component that - * is drawn over the entire area the {@code BasePane} is occupying, it's very likely you want to set this component to - * be a container of some sort, probably a {@code Panel}, that can host multiple child components. - * - * @see Panel - * @author Martin - */ -public interface BasePane extends Composite { - - /** - * Returns the TextGUI this BasePane belongs to or {@code null} if none. One example of when this method returns - * {@code null} is when calling it on a Window that hasn't been displayed yet. - * @return The TextGUI this BasePane belongs to - */ - TextGUI getTextGUI(); - - /** - * Called by the GUI system (or something imitating the GUI system) to draw the root container. The TextGUIGraphics - * object should be used to perform the drawing operations. - * @param graphics TextGraphics object to draw with - */ - void draw(TextGUIGraphics graphics); - - /** - * Checks if this root container (i.e. any of its child components) has signaled that what it's currently displaying - * is out of date and needs re-drawing. - * @return {@code true} if the container's content is invalid and needs redrawing, {@code false} otherwise - */ - boolean isInvalid(); - - /** - * Invalidates the whole root container (including all of its child components) which will cause them all to be - * recalculated (for containers) and redrawn. - */ - void invalidate(); - - /** - * Called by the GUI system to delegate a keyboard input event. The root container will decide what to do with this - * input, usually sending it to one of its sub-components, but if it isn't able to find any handler for this input - * it should return {@code false} so that the GUI system can take further decisions on what to do with it. - * @param key Keyboard input - * @return {@code true} If the root container could handle the input, false otherwise - */ - boolean handleInput(KeyStroke key); - - /** - * Returns the component that is the content of the BasePane. This is probably the root of a hierarchy of nested - * Panels but it could also be a single component. - * @return Component which is the content of this BasePane - */ - @Override - Component getComponent(); - - /** - * Sets the top-level component inside this BasePane. If you want it to contain only one component, you can set it - * directly, but for more complicated GUIs you probably want to create a hierarchy of panels and set the first one - * here. - * @param component Component which this BasePane is using as it's content - */ - @Override - void setComponent(Component component); - - /** - * Returns the component in the root container that currently has input focus. There can only be one component at a - * time being in focus. - * @return Interactable component that is currently in receiving input focus - */ - Interactable getFocusedInteractable(); - - /** - * Sets the component currently in focus within this root container, or sets no component in focus if {@code null} - * is passed in. - * @param interactable Interactable to focus, or {@code null} to clear focus - */ - void setFocusedInteractable(Interactable interactable); - - /** - * Returns the position of where to put the terminal cursor according to this root container. This is typically - * derived from which component has focus, or {@code null} if no component has focus or if the root container doesn't - * want the cursor to be visible. Note that the coordinates are in local coordinate space, relative to the top-left - * corner of the root container. You can use your TextGUI implementation to translate these to global coordinates. - * @return Local position of where to place the cursor, or {@code null} if the cursor shouldn't be visible - */ - TerminalPosition getCursorPosition(); - - /** - * Returns a position in a root container's local coordinate space to global coordinates - * @param localPosition The local position to translate - * @return The local position translated to global coordinates - */ - TerminalPosition toGlobal(TerminalPosition localPosition); - - /** - * Returns a position expressed in global coordinates, i.e. row and column offset from the top-left corner of the - * terminal into a position relative to the top-left corner of the base pane. Calling - * {@code fromGlobal(toGlobal(..))} should return the exact same position. - * @param position Position expressed in global coordinates to translate to local coordinates of this BasePane - * @return The global coordinates expressed as local coordinates - */ - TerminalPosition fromGlobal(TerminalPosition position); - - /** - * If set to true, up/down array keys will not translate to next/previous if there are no more components - * above/below. - * @param strictFocusChange Will not allow relaxed navigation if set to {@code true} - */ - void setStrictFocusChange(boolean strictFocusChange); - - /** - * If set to false, using the keyboard arrows keys will have the same effect as using the tab and reverse tab. - * Lanterna will map arrow down and arrow right to tab, going to the next component, and array up and array left to - * reverse tab, going to the previous component. If set to true, Lanterna will search for the next component - * starting at the cursor position in the general direction of the arrow. By default this is enabled. - *

- * In Lanterna 2, direction based movements were not available. - * @param enableDirectionBasedMovements Should direction based focus movements be enabled? - */ - void setEnableDirectionBasedMovements(boolean enableDirectionBasedMovements); -} diff --git a/src/com/googlecode/lanterna/gui2/BasicWindow.java b/src/com/googlecode/lanterna/gui2/BasicWindow.java deleted file mode 100644 index f5bdd91..0000000 --- a/src/com/googlecode/lanterna/gui2/BasicWindow.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -/** - * Simple AbstractWindow implementation that you can use as a building block when creating new windows without having - * to create new classes. - * - * @author Martin - */ -public class BasicWindow extends AbstractWindow { - - /** - * Default constructor, creates a new window with no title - */ - public BasicWindow() { - super(); - } - - /** - * This constructor creates a window with a specific title, that is (probably) going to be displayed in the window - * decoration - * @param title Title of the window - */ - public BasicWindow(String title) { - super(title); - } -} diff --git a/src/com/googlecode/lanterna/gui2/Border.java b/src/com/googlecode/lanterna/gui2/Border.java deleted file mode 100644 index fe53226..0000000 --- a/src/com/googlecode/lanterna/gui2/Border.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; - -/** - * Main interface for different border classes, with additional methods to help lanterna figure out the size and offset - * of components wrapped by borders. - * @author Martin - */ -public interface Border extends Container, Composite { - interface BorderRenderer extends ComponentRenderer { - /** - * How large is the offset from the top left corner of the border to the top left corner of the wrapped component? - * @return Position of the wrapped components top left position, relative to the top left corner of the border - */ - TerminalPosition getWrappedComponentTopLeftOffset(); - - /** - * Given a total size of the border composite and it's wrapped component, how large would the actual wrapped - * component be? - * @param borderSize Size to calculate for, this should be the total size of the border and the inner component - * @return Size of the inner component if the total size of inner + border is borderSize - */ - TerminalSize getWrappedComponentSize(TerminalSize borderSize); - } -} diff --git a/src/com/googlecode/lanterna/gui2/BorderLayout.java b/src/com/googlecode/lanterna/gui2/BorderLayout.java deleted file mode 100644 index 446774c..0000000 --- a/src/com/googlecode/lanterna/gui2/BorderLayout.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; - -import java.util.*; - -/** - * BorderLayout imitates the BorderLayout class from AWT, allowing you to add a center component with optional - * components around it in top, bottom, left and right locations. The edge components will be sized at their preferred - * size and the center component will take up whatever remains. - * @author martin - */ -public class BorderLayout implements LayoutManager { - - /** - * This type is what you use as the layout data for components added to a panel using {@code BorderLayout} for its - * layout manager. This values specified where inside the panel the component should be added. - */ - public enum Location implements LayoutData { - /** - * The component with this value as its layout data will occupy the center space, whatever is remaining after - * the other components (if any) have allocated their space. - */ - CENTER, - /** - * The component with this value as its layout data will occupy the left side of the container, attempting to - * allocate the preferred width of the component and at least the preferred height, but could be more depending - * on the other components added. - */ - LEFT, - /** - * The component with this value as its layout data will occupy the right side of the container, attempting to - * allocate the preferred width of the component and at least the preferred height, but could be more depending - * on the other components added. - */ - RIGHT, - /** - * The component with this value as its layout data will occupy the top side of the container, attempting to - * allocate the preferred height of the component and at least the preferred width, but could be more depending - * on the other components added. - */ - TOP, - /** - * The component with this value as its layout data will occupy the bottom side of the container, attempting to - * allocate the preferred height of the component and at least the preferred width, but could be more depending - * on the other components added. - */ - BOTTOM, - ; - } - - //When components don't have a location, we'll assign an available location based on this order - private static final List AUTO_ASSIGN_ORDER = Collections.unmodifiableList(Arrays.asList( - Location.CENTER, - Location.TOP, - Location.BOTTOM, - Location.LEFT, - Location.RIGHT)); - - @Override - public TerminalSize getPreferredSize(List components) { - EnumMap layout = makeLookupMap(components); - int preferredHeight = - (layout.containsKey(Location.TOP) ? layout.get(Location.TOP).getPreferredSize().getRows() : 0) - + - Math.max( - layout.containsKey(Location.LEFT) ? layout.get(Location.LEFT).getPreferredSize().getRows() : 0, - Math.max( - layout.containsKey(Location.CENTER) ? layout.get(Location.CENTER).getPreferredSize().getRows() : 0, - layout.containsKey(Location.RIGHT) ? layout.get(Location.RIGHT).getPreferredSize().getRows() : 0)) - + - (layout.containsKey(Location.BOTTOM) ? layout.get(Location.BOTTOM).getPreferredSize().getRows() : 0); - - int preferredWidth = - Math.max( - (layout.containsKey(Location.LEFT) ? layout.get(Location.LEFT).getPreferredSize().getColumns() : 0) + - (layout.containsKey(Location.CENTER) ? layout.get(Location.CENTER).getPreferredSize().getColumns() : 0) + - (layout.containsKey(Location.RIGHT) ? layout.get(Location.RIGHT).getPreferredSize().getColumns() : 0), - Math.max( - layout.containsKey(Location.TOP) ? layout.get(Location.TOP).getPreferredSize().getColumns() : 0, - layout.containsKey(Location.BOTTOM) ? layout.get(Location.BOTTOM).getPreferredSize().getColumns() : 0)); - return new TerminalSize(preferredWidth, preferredHeight); - } - - @Override - public void doLayout(TerminalSize area, List components) { - EnumMap layout = makeLookupMap(components); - int availableHorizontalSpace = area.getColumns(); - int availableVerticalSpace = area.getRows(); - - //We'll need this later on - int topComponentHeight = 0; - int leftComponentWidth = 0; - - //First allocate the top - if(layout.containsKey(Location.TOP)) { - Component topComponent = layout.get(Location.TOP); - topComponentHeight = Math.min(topComponent.getPreferredSize().getRows(), availableVerticalSpace); - topComponent.setPosition(TerminalPosition.TOP_LEFT_CORNER); - topComponent.setSize(new TerminalSize(availableHorizontalSpace, topComponentHeight)); - availableVerticalSpace -= topComponentHeight; - } - - //Next allocate the bottom - if(layout.containsKey(Location.BOTTOM)) { - Component bottomComponent = layout.get(Location.BOTTOM); - int bottomComponentHeight = Math.min(bottomComponent.getPreferredSize().getRows(), availableVerticalSpace); - bottomComponent.setPosition(new TerminalPosition(0, area.getRows() - bottomComponentHeight)); - bottomComponent.setSize(new TerminalSize(availableHorizontalSpace, bottomComponentHeight)); - availableVerticalSpace -= bottomComponentHeight; - } - - //Now divide the remaining space between LEFT, CENTER and RIGHT - if(layout.containsKey(Location.LEFT)) { - Component leftComponent = layout.get(Location.LEFT); - leftComponentWidth = Math.min(leftComponent.getPreferredSize().getColumns(), availableHorizontalSpace); - leftComponent.setPosition(new TerminalPosition(0, topComponentHeight)); - leftComponent.setSize(new TerminalSize(leftComponentWidth, availableVerticalSpace)); - availableHorizontalSpace -= leftComponentWidth; - } - if(layout.containsKey(Location.RIGHT)) { - Component rightComponent = layout.get(Location.RIGHT); - int rightComponentWidth = Math.min(rightComponent.getPreferredSize().getColumns(), availableHorizontalSpace); - rightComponent.setPosition(new TerminalPosition(area.getColumns() - rightComponentWidth, topComponentHeight)); - rightComponent.setSize(new TerminalSize(rightComponentWidth, availableVerticalSpace)); - availableHorizontalSpace -= rightComponentWidth; - } - if(layout.containsKey(Location.CENTER)) { - Component centerComponent = layout.get(Location.CENTER); - centerComponent.setPosition(new TerminalPosition(leftComponentWidth, topComponentHeight)); - centerComponent.setSize(new TerminalSize(availableHorizontalSpace, availableVerticalSpace)); - } - - //Set the remaining components to 0x0 - for(Component component: components) { - if(!layout.values().contains(component)) { - component.setPosition(TerminalPosition.TOP_LEFT_CORNER); - component.setSize(TerminalSize.ZERO); - } - } - } - - private EnumMap makeLookupMap(List components) { - EnumMap map = new EnumMap(Location.class); - List unassignedComponents = new ArrayList(); - for(Component component: components) { - if(component.getLayoutData() instanceof Location) { - map.put((Location)component.getLayoutData(), component); - } - else { - unassignedComponents.add(component); - } - } - //Try to assign components to available locations - for(Component component: unassignedComponents) { - for(Location location: AUTO_ASSIGN_ORDER) { - if(!map.containsKey(location)) { - map.put(location, component); - break; - } - } - } - return map; - } - - @Override - public boolean hasChanged() { - //No internal state - return false; - } -} diff --git a/src/com/googlecode/lanterna/gui2/Borders.java b/src/com/googlecode/lanterna/gui2/Borders.java deleted file mode 100644 index 7e01900..0000000 --- a/src/com/googlecode/lanterna/gui2/Borders.java +++ /dev/null @@ -1,600 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.*; -import com.googlecode.lanterna.graphics.TextGraphics; - -import java.util.Arrays; -import java.util.List; - -/** - * This class containers a couple of border implementation and utility methods for instantiating them. It also contains - * a utility method for joining border line graphics together with adjacent lines so they blend in together: - * {@code joinLinesWithFrame(..)}. - * @author Martin - */ -public class Borders { - private Borders() { - } - - //Different ways to draw the border - private enum BorderStyle { - Solid, - Bevel, - ReverseBevel, - } - - /** - * Creates a {@code Border} that is drawn as a solid color single line surrounding the wrapped component - * @return New solid color single line {@code Border} - */ - public static Border singleLine() { - return singleLine(""); - } - - /** - * Creates a {@code Border} that is drawn as a solid color single line surrounding the wrapped component with a - * title string normally drawn at the top-left side - * @param title The title to draw on the border - * @return New solid color single line {@code Border} with a title - */ - public static Border singleLine(String title) { - return new SingleLine(title, BorderStyle.Solid); - } - - /** - * Creates a {@code Border} that is drawn as a bevel color single line surrounding the wrapped component - * @return New bevel color single line {@code Border} - */ - public static Border singleLineBevel() { - return singleLineBevel(""); - } - - /** - * Creates a {@code Border} that is drawn as a bevel color single line surrounding the wrapped component with a - * title string normally drawn at the top-left side - * @param title The title to draw on the border - * @return New bevel color single line {@code Border} with a title - */ - public static Border singleLineBevel(String title) { - return new SingleLine(title, BorderStyle.Bevel); - } - - /** - * Creates a {@code Border} that is drawn as a reverse bevel color single line surrounding the wrapped component - * @return New reverse bevel color single line {@code Border} - */ - public static Border singleLineReverseBevel() { - return singleLineReverseBevel(""); - } - - /** - * Creates a {@code Border} that is drawn as a reverse bevel color single line surrounding the wrapped component - * with a title string normally drawn at the top-left side - * @param title The title to draw on the border - * @return New reverse bevel color single line {@code Border} with a title - */ - public static Border singleLineReverseBevel(String title) { - return new SingleLine(title, BorderStyle.ReverseBevel); - } - - /** - * Creates a {@code Border} that is drawn as a solid color double line surrounding the wrapped component - * @return New solid color double line {@code Border} - */ - public static Border doubleLine() { - return doubleLine(""); - } - - /** - * Creates a {@code Border} that is drawn as a solid color double line surrounding the wrapped component with a - * title string normally drawn at the top-left side - * @param title The title to draw on the border - * @return New solid color double line {@code Border} with a title - */ - public static Border doubleLine(String title) { - return new DoubleLine(title, BorderStyle.Solid); - } - - /** - * Creates a {@code Border} that is drawn as a bevel color double line surrounding the wrapped component - * @return New bevel color double line {@code Border} - */ - public static Border doubleLineBevel() { - return doubleLineBevel(""); - } - - /** - * Creates a {@code Border} that is drawn as a bevel color double line surrounding the wrapped component with a - * title string normally drawn at the top-left side - * @param title The title to draw on the border - * @return New bevel color double line {@code Border} with a title - */ - public static Border doubleLineBevel(String title) { - return new DoubleLine(title, BorderStyle.Bevel); - } - - /** - * Creates a {@code Border} that is drawn as a reverse bevel color double line surrounding the wrapped component - * @return New reverse bevel color double line {@code Border} - */ - public static Border doubleLineReverseBevel() { - return doubleLineReverseBevel(""); - } - - /** - * Creates a {@code Border} that is drawn as a reverse bevel color double line surrounding the wrapped component - * with a title string normally drawn at the top-left side - * @param title The title to draw on the border - * @return New reverse bevel color double line {@code Border} with a title - */ - public static Border doubleLineReverseBevel(String title) { - return new DoubleLine(title, BorderStyle.ReverseBevel); - } - - private static abstract class StandardBorder extends AbstractBorder { - private final String title; - protected final BorderStyle borderStyle; - - protected StandardBorder(String title, BorderStyle borderStyle) { - if (title == null) { - throw new IllegalArgumentException("Cannot create a border with null title"); - } - this.borderStyle = borderStyle; - this.title = title; - } - - public String getTitle() { - return title; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "{" + title + "}"; - } - } - - private static abstract class AbstractBorderRenderer implements Border.BorderRenderer { - private final BorderStyle borderStyle; - - protected AbstractBorderRenderer(BorderStyle borderStyle) { - this.borderStyle = borderStyle; - } - - @Override - public TerminalSize getPreferredSize(Border component) { - StandardBorder border = (StandardBorder)component; - Component wrappedComponent = border.getComponent(); - TerminalSize preferredSize; - if (wrappedComponent == null) { - preferredSize = TerminalSize.ZERO; - } else { - preferredSize = wrappedComponent.getPreferredSize(); - } - preferredSize = preferredSize.withRelativeColumns(2).withRelativeRows(2); - String borderTitle = border.getTitle(); - return preferredSize.max(new TerminalSize((borderTitle.isEmpty() ? 2 : TerminalTextUtils.getColumnWidth(borderTitle) + 4), 2)); - } - - @Override - public TerminalPosition getWrappedComponentTopLeftOffset() { - return TerminalPosition.OFFSET_1x1; - } - - @Override - public TerminalSize getWrappedComponentSize(TerminalSize borderSize) { - return borderSize - .withRelativeColumns(-Math.min(2, borderSize.getColumns())) - .withRelativeRows(-Math.min(2, borderSize.getRows())); - } - - @Override - public void drawComponent(TextGUIGraphics graphics, Border component) { - StandardBorder border = (StandardBorder)component; - Component wrappedComponent = border.getComponent(); - if(wrappedComponent == null) { - return; - } - TerminalSize drawableArea = graphics.getSize(); - - char horizontalLine = getHorizontalLine(graphics); - char verticalLine = getVerticalLine(graphics); - char bottomLeftCorner = getBottomLeftCorner(graphics); - char topLeftCorner = getTopLeftCorner(graphics); - char bottomRightCorner = getBottomRightCorner(graphics); - char topRightCorner = getTopRightCorner(graphics); - - if(borderStyle == BorderStyle.Bevel) { - graphics.applyThemeStyle(graphics.getThemeDefinition(StandardBorder.class).getPreLight()); - } - else { - graphics.applyThemeStyle(graphics.getThemeDefinition(StandardBorder.class).getNormal()); - } - graphics.setCharacter(0, drawableArea.getRows() - 1, bottomLeftCorner); - if(drawableArea.getRows() > 2) { - graphics.drawLine(new TerminalPosition(0, drawableArea.getRows() - 2), new TerminalPosition(0, 1), verticalLine); - } - graphics.setCharacter(0, 0, topLeftCorner); - if(drawableArea.getColumns() > 2) { - graphics.drawLine(new TerminalPosition(1, 0), new TerminalPosition(drawableArea.getColumns() - 2, 0), horizontalLine); - } - - if(borderStyle == BorderStyle.ReverseBevel) { - graphics.applyThemeStyle(graphics.getThemeDefinition(StandardBorder.class).getPreLight()); - } - else { - graphics.applyThemeStyle(graphics.getThemeDefinition(StandardBorder.class).getNormal()); - } - graphics.setCharacter(drawableArea.getColumns() - 1, 0, topRightCorner); - if(drawableArea.getRows() > 2) { - graphics.drawLine(new TerminalPosition(drawableArea.getColumns() - 1, 1), - new TerminalPosition(drawableArea.getColumns() - 1, drawableArea.getRows() - 2), - verticalLine); - } - graphics.setCharacter(drawableArea.getColumns() - 1, drawableArea.getRows() - 1, bottomRightCorner); - if(drawableArea.getColumns() > 2) { - graphics.drawLine(new TerminalPosition(1, drawableArea.getRows() - 1), - new TerminalPosition(drawableArea.getColumns() - 2, drawableArea.getRows() - 1), - horizontalLine); - } - - if(drawableArea.getColumns() >= TerminalTextUtils.getColumnWidth(border.getTitle()) + 4) { - graphics.putString(2, 0, border.getTitle()); - } - - wrappedComponent.draw(graphics.newTextGraphics(getWrappedComponentTopLeftOffset(), getWrappedComponentSize(drawableArea))); - - - joinLinesWithFrame(graphics); - } - - protected abstract char getHorizontalLine(TextGUIGraphics graphics); - protected abstract char getVerticalLine(TextGUIGraphics graphics); - protected abstract char getBottomLeftCorner(TextGUIGraphics graphics); - protected abstract char getTopLeftCorner(TextGUIGraphics graphics); - protected abstract char getBottomRightCorner(TextGUIGraphics graphics); - protected abstract char getTopRightCorner(TextGUIGraphics graphics); - } - - /** - * This method will attempt to join line drawing characters with the outermost bottom and top rows and left and - * right columns. For example, if a vertical left border character is ║ and the character immediately to the right - * of it is ─, then the border character will be updated to ╟ to join the two together. Please note that this method - * will only join the outer border columns and rows. - * @param graphics Graphics to use when inspecting and joining characters - */ - public static void joinLinesWithFrame(TextGraphics graphics) { - TerminalSize drawableArea = graphics.getSize(); - if(drawableArea.getRows() <= 2 || drawableArea.getColumns() <= 2) { - //Too small - return; - } - - int upperRow = 0; - int lowerRow = drawableArea.getRows() - 1; - int leftRow = 0; - int rightRow = drawableArea.getColumns() - 1; - - List junctionFromBelowSingle = Arrays.asList( - Symbols.SINGLE_LINE_VERTICAL, - Symbols.BOLD_FROM_NORMAL_SINGLE_LINE_VERTICAL, - Symbols.SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_HORIZONTAL_SINGLE_LINE_CROSS, - Symbols.SINGLE_LINE_BOTTOM_LEFT_CORNER, - Symbols.SINGLE_LINE_BOTTOM_RIGHT_CORNER, - Symbols.SINGLE_LINE_T_LEFT, - Symbols.SINGLE_LINE_T_RIGHT, - Symbols.SINGLE_LINE_T_UP, - Symbols.SINGLE_LINE_T_DOUBLE_LEFT, - Symbols.SINGLE_LINE_T_DOUBLE_RIGHT, - Symbols.DOUBLE_LINE_T_SINGLE_UP); - List junctionFromBelowDouble = Arrays.asList( - Symbols.DOUBLE_LINE_VERTICAL, - Symbols.DOUBLE_LINE_CROSS, - Symbols.DOUBLE_LINE_VERTICAL_SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_BOTTOM_LEFT_CORNER, - Symbols.DOUBLE_LINE_BOTTOM_RIGHT_CORNER, - Symbols.DOUBLE_LINE_T_LEFT, - Symbols.DOUBLE_LINE_T_RIGHT, - Symbols.DOUBLE_LINE_T_UP, - Symbols.DOUBLE_LINE_T_SINGLE_LEFT, - Symbols.DOUBLE_LINE_T_SINGLE_RIGHT, - Symbols.SINGLE_LINE_T_DOUBLE_UP); - List junctionFromAboveSingle = Arrays.asList( - Symbols.SINGLE_LINE_VERTICAL, - Symbols.BOLD_TO_NORMAL_SINGLE_LINE_VERTICAL, - Symbols.SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_HORIZONTAL_SINGLE_LINE_CROSS, - Symbols.SINGLE_LINE_TOP_LEFT_CORNER, - Symbols.SINGLE_LINE_TOP_RIGHT_CORNER, - Symbols.SINGLE_LINE_T_LEFT, - Symbols.SINGLE_LINE_T_RIGHT, - Symbols.SINGLE_LINE_T_DOWN, - Symbols.SINGLE_LINE_T_DOUBLE_LEFT, - Symbols.SINGLE_LINE_T_DOUBLE_RIGHT, - Symbols.DOUBLE_LINE_T_SINGLE_DOWN); - List junctionFromAboveDouble = Arrays.asList( - Symbols.DOUBLE_LINE_VERTICAL, - Symbols.DOUBLE_LINE_CROSS, - Symbols.DOUBLE_LINE_VERTICAL_SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_TOP_LEFT_CORNER, - Symbols.DOUBLE_LINE_TOP_RIGHT_CORNER, - Symbols.DOUBLE_LINE_T_LEFT, - Symbols.DOUBLE_LINE_T_RIGHT, - Symbols.DOUBLE_LINE_T_DOWN, - Symbols.DOUBLE_LINE_T_SINGLE_LEFT, - Symbols.DOUBLE_LINE_T_SINGLE_RIGHT, - Symbols.SINGLE_LINE_T_DOUBLE_DOWN); - List junctionFromLeftSingle = Arrays.asList( - Symbols.SINGLE_LINE_HORIZONTAL, - Symbols.BOLD_TO_NORMAL_SINGLE_LINE_HORIZONTAL, - Symbols.SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_VERTICAL_SINGLE_LINE_CROSS, - Symbols.SINGLE_LINE_BOTTOM_LEFT_CORNER, - Symbols.SINGLE_LINE_TOP_LEFT_CORNER, - Symbols.SINGLE_LINE_T_UP, - Symbols.SINGLE_LINE_T_DOWN, - Symbols.SINGLE_LINE_T_RIGHT, - Symbols.SINGLE_LINE_T_DOUBLE_UP, - Symbols.SINGLE_LINE_T_DOUBLE_DOWN, - Symbols.DOUBLE_LINE_T_SINGLE_RIGHT); - List junctionFromLeftDouble = Arrays.asList( - Symbols.DOUBLE_LINE_HORIZONTAL, - Symbols.DOUBLE_LINE_CROSS, - Symbols.DOUBLE_LINE_HORIZONTAL_SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_BOTTOM_LEFT_CORNER, - Symbols.DOUBLE_LINE_TOP_LEFT_CORNER, - Symbols.DOUBLE_LINE_T_UP, - Symbols.DOUBLE_LINE_T_DOWN, - Symbols.DOUBLE_LINE_T_RIGHT, - Symbols.DOUBLE_LINE_T_SINGLE_UP, - Symbols.DOUBLE_LINE_T_SINGLE_DOWN, - Symbols.SINGLE_LINE_T_DOUBLE_RIGHT); - List junctionFromRightSingle = Arrays.asList( - Symbols.SINGLE_LINE_HORIZONTAL, - Symbols.BOLD_FROM_NORMAL_SINGLE_LINE_HORIZONTAL, - Symbols.SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_VERTICAL_SINGLE_LINE_CROSS, - Symbols.SINGLE_LINE_BOTTOM_RIGHT_CORNER, - Symbols.SINGLE_LINE_TOP_RIGHT_CORNER, - Symbols.SINGLE_LINE_T_UP, - Symbols.SINGLE_LINE_T_DOWN, - Symbols.SINGLE_LINE_T_LEFT, - Symbols.SINGLE_LINE_T_DOUBLE_UP, - Symbols.SINGLE_LINE_T_DOUBLE_DOWN, - Symbols.DOUBLE_LINE_T_SINGLE_LEFT); - List junctionFromRightDouble = Arrays.asList( - Symbols.DOUBLE_LINE_HORIZONTAL, - Symbols.DOUBLE_LINE_CROSS, - Symbols.DOUBLE_LINE_HORIZONTAL_SINGLE_LINE_CROSS, - Symbols.DOUBLE_LINE_BOTTOM_RIGHT_CORNER, - Symbols.DOUBLE_LINE_TOP_RIGHT_CORNER, - Symbols.DOUBLE_LINE_T_UP, - Symbols.DOUBLE_LINE_T_DOWN, - Symbols.DOUBLE_LINE_T_LEFT, - Symbols.DOUBLE_LINE_T_SINGLE_UP, - Symbols.DOUBLE_LINE_T_SINGLE_DOWN, - Symbols.SINGLE_LINE_T_DOUBLE_LEFT); - - //Go horizontally and check vertical neighbours if it's possible to extend lines into the border - for(int column = 1; column < drawableArea.getColumns() - 1; column++) { - //Check first row - TextCharacter borderCharacter = graphics.getCharacter(column, upperRow); - if(borderCharacter == null) { - continue; - } - TextCharacter neighbourCharacter = graphics.getCharacter(column, upperRow + 1); - if(neighbourCharacter != null) { - char neighbour = neighbourCharacter.getCharacter(); - if(borderCharacter.getCharacter() == Symbols.SINGLE_LINE_HORIZONTAL) { - if(junctionFromBelowSingle.contains(neighbour)) { - graphics.setCharacter(column, upperRow, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_DOWN)); - } - else if(junctionFromBelowDouble.contains(neighbour)) { - graphics.setCharacter(column, upperRow, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_DOUBLE_DOWN)); - } - } - else if(borderCharacter.getCharacter() == Symbols.DOUBLE_LINE_HORIZONTAL) { - if(junctionFromBelowSingle.contains(neighbour)) { - graphics.setCharacter(column, upperRow, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_SINGLE_DOWN)); - } - else if(junctionFromBelowDouble.contains(neighbour)) { - graphics.setCharacter(column, upperRow, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_DOWN)); - } - } - } - - //Check last row - borderCharacter = graphics.getCharacter(column, lowerRow); - if(borderCharacter == null) { - continue; - } - neighbourCharacter = graphics.getCharacter(column, lowerRow - 1); - if(neighbourCharacter != null) { - char neighbour = neighbourCharacter.getCharacter(); - if(borderCharacter.getCharacter() == Symbols.SINGLE_LINE_HORIZONTAL) { - if(junctionFromAboveSingle.contains(neighbour)) { - graphics.setCharacter(column, lowerRow, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_UP)); - } - else if(junctionFromAboveDouble.contains(neighbour)) { - graphics.setCharacter(column, lowerRow, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_DOUBLE_UP)); - } - } - else if(borderCharacter.getCharacter() == Symbols.DOUBLE_LINE_HORIZONTAL) { - if(junctionFromAboveSingle.contains(neighbour)) { - graphics.setCharacter(column, lowerRow, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_SINGLE_UP)); - } - else if(junctionFromAboveDouble.contains(neighbour)) { - graphics.setCharacter(column, lowerRow, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_UP)); - } - } - } - } - - //Go vertically and check horizontal neighbours if it's possible to extend lines into the border - for(int row = 1; row < drawableArea.getRows() - 1; row++) { - //Check first column - TextCharacter borderCharacter = graphics.getCharacter(leftRow, row); - if(borderCharacter == null) { - continue; - } - TextCharacter neighbourCharacter = graphics.getCharacter(leftRow + 1, row); - if(neighbourCharacter != null) { - char neighbour = neighbourCharacter.getCharacter(); - if(borderCharacter.getCharacter() == Symbols.SINGLE_LINE_VERTICAL) { - if(junctionFromRightSingle.contains(neighbour)) { - graphics.setCharacter(leftRow, row, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_RIGHT)); - } - else if(junctionFromRightDouble.contains(neighbour)) { - graphics.setCharacter(leftRow, row, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_DOUBLE_RIGHT)); - } - } - else if(borderCharacter.getCharacter() == Symbols.DOUBLE_LINE_VERTICAL) { - if(junctionFromRightSingle.contains(neighbour)) { - graphics.setCharacter(leftRow, row, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_SINGLE_RIGHT)); - } - else if(junctionFromRightDouble.contains(neighbour)) { - graphics.setCharacter(leftRow, row, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_RIGHT)); - } - } - } - - //Check last column - borderCharacter = graphics.getCharacter(rightRow, row); - if(borderCharacter == null) { - continue; - } - neighbourCharacter = graphics.getCharacter(rightRow - 1, row); - if(neighbourCharacter != null) { - char neighbour = neighbourCharacter.getCharacter(); - if(borderCharacter.getCharacter() == Symbols.SINGLE_LINE_VERTICAL) { - if(junctionFromLeftSingle.contains(neighbour)) { - graphics.setCharacter(rightRow, row, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_LEFT)); - } - else if(junctionFromLeftDouble.contains(neighbour)) { - graphics.setCharacter(rightRow, row, borderCharacter.withCharacter(Symbols.SINGLE_LINE_T_DOUBLE_LEFT)); - } - } - else if(borderCharacter.getCharacter() == Symbols.DOUBLE_LINE_VERTICAL) { - if(junctionFromLeftSingle.contains(neighbour)) { - graphics.setCharacter(rightRow, row, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_SINGLE_LEFT)); - } - else if(junctionFromLeftDouble.contains(neighbour)) { - graphics.setCharacter(rightRow, row, borderCharacter.withCharacter(Symbols.DOUBLE_LINE_T_LEFT)); - } - } - } - } - } - - private static class SingleLine extends StandardBorder { - private SingleLine(String title, BorderStyle borderStyle) { - super(title, borderStyle); - } - - @Override - protected BorderRenderer createDefaultRenderer() { - return new SingleLineRenderer(borderStyle); - } - } - - private static class SingleLineRenderer extends AbstractBorderRenderer { - public SingleLineRenderer(BorderStyle borderStyle) { - super(borderStyle); - } - - @Override - protected char getTopRightCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(SingleLineRenderer.class).getCharacter("TOP_RIGHT_CORNER", Symbols.SINGLE_LINE_TOP_RIGHT_CORNER); - } - - @Override - protected char getBottomRightCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(SingleLineRenderer.class).getCharacter("BOTTOM_RIGHT_CORNER", Symbols.SINGLE_LINE_BOTTOM_RIGHT_CORNER); - } - - @Override - protected char getTopLeftCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(SingleLineRenderer.class).getCharacter("TOP_LEFT_CORNER", Symbols.SINGLE_LINE_TOP_LEFT_CORNER); - } - - @Override - protected char getBottomLeftCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(SingleLineRenderer.class).getCharacter("BOTTOM_LEFT_CORNER", Symbols.SINGLE_LINE_BOTTOM_LEFT_CORNER); - } - - @Override - protected char getVerticalLine(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(SingleLineRenderer.class).getCharacter("VERTICAL_LINE", Symbols.SINGLE_LINE_VERTICAL); - } - - @Override - protected char getHorizontalLine(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(SingleLineRenderer.class).getCharacter("HORIZONTAL_LINE", Symbols.SINGLE_LINE_HORIZONTAL); - } - } - - private static class DoubleLine extends StandardBorder { - private DoubleLine(String title, BorderStyle borderStyle) { - super(title, borderStyle); - } - - @Override - protected BorderRenderer createDefaultRenderer() { - return new DoubleLineRenderer(borderStyle); - } - } - - private static class DoubleLineRenderer extends AbstractBorderRenderer { - public DoubleLineRenderer(BorderStyle borderStyle) { - super(borderStyle); - } - - @Override - protected char getTopRightCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(DoubleLine.class).getCharacter("TOP_RIGHT_CORNER", Symbols.DOUBLE_LINE_TOP_RIGHT_CORNER); - } - - @Override - protected char getBottomRightCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(DoubleLine.class).getCharacter("BOTTOM_RIGHT_CORNER", Symbols.DOUBLE_LINE_BOTTOM_RIGHT_CORNER); - } - - @Override - protected char getTopLeftCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(DoubleLine.class).getCharacter("TOP_LEFT_CORNER", Symbols.DOUBLE_LINE_TOP_LEFT_CORNER); - } - - @Override - protected char getBottomLeftCorner(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(DoubleLine.class).getCharacter("BOTTOM_LEFT_CORNER", Symbols.DOUBLE_LINE_BOTTOM_LEFT_CORNER); - } - - @Override - protected char getVerticalLine(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(DoubleLine.class).getCharacter("VERTICAL_LINE", Symbols.DOUBLE_LINE_VERTICAL); - } - - @Override - protected char getHorizontalLine(TextGUIGraphics graphics) { - return graphics.getThemeDefinition(DoubleLine.class).getCharacter("HORIZONTAL_LINE", Symbols.DOUBLE_LINE_HORIZONTAL); - } - } -} diff --git a/src/com/googlecode/lanterna/gui2/Button.java b/src/com/googlecode/lanterna/gui2/Button.java deleted file mode 100644 index 8ce43fd..0000000 --- a/src/com/googlecode/lanterna/gui2/Button.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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-2015 Martin - */ -package com.googlecode.lanterna.gui2; - -import com.googlecode.lanterna.TerminalTextUtils; -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import com.googlecode.lanterna.graphics.ThemeDefinition; -import com.googlecode.lanterna.input.KeyStroke; -import com.googlecode.lanterna.input.KeyType; - -/** - * Simple labeled button with an optional action attached to it, you trigger the action by pressing the Enter key on the - * keyboard when the component is in focus. - * @author Martin - */ -public class Button extends AbstractInteractableComponent