package com.ubergeek42.weechat;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class ColorScheme {
public static final int OPT_FG = 0;
public static final int OPT_BG = 1;
static ColorScheme currentColorScheme;
public static ColorScheme get() {
if (currentColorScheme == null) currentColorScheme = new ColorScheme();
return currentColorScheme;
}
public static void set(ColorScheme cs) {
currentColorScheme = cs;
}
// the following 3 are loaded from constants and then, as needed,
// populated from the properties file
// extended colors do not get to be loaded
private int basic[];
private int[][] options = new int[44][2];
private int def[] = new int[2];
// the following are used by Color.java and UI
public int[] chat_time;
public int[] chat_highlight;
public int[] chat_nick_prefix;
public int[] chat_nick_suffix;
public int[] chat_prefix_more;
public int[] chat_read_marker;
public int[] defaul;
public int[] chat_inactive_buffer;
private final static int[] INVALID = new int[]{-1, -1};
////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////// constructors /////////
////////////////////////////////////////////////////////////////////////////////////////////////
public ColorScheme() {
basic = BASIC.clone();
def[0] = BASIC[7];
def[1] = BASIC[0];
loadDefaultOptions();
setUsedFields();
}
public ColorScheme(Properties p) {
// load color0 to color16
basic = new int[BASIC.length];
for (int i = 0; i < basic.length; i++) basic[i] = getPropertyInt(p, "color" + i, BASIC[i]);
// load default & default_bg
def[0] = getPropertyInt(p, "DEFAULT", basic[7]);
def[1] = getPropertyInt(p, "DEFAULT_BG", basic[0]);
loadDefaultOptions();
loadOptionsFromProperties(p);
setUsedFields();
}
private void setUsedFields() {
chat_time = getOptionColor("chat_time");
chat_highlight = getOptionColor("chat_highlight");
chat_nick_prefix = getOptionColor("chat_nick_prefix");
chat_nick_suffix = getOptionColor("chat_nick_suffix");
chat_prefix_more = getOptionColor("chat_prefix_more");
chat_read_marker = getOptionColor("chat_read_marker");
defaul = getOptionColor("default");
chat_inactive_buffer = getOptionColor("chat_inactive_buffer");
}
// will crash if string is not found!
private int[] getOptionColor(String opt) {
return getOptionColor(OPTIONS.get(opt));
}
////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////// public methods ///////
////////////////////////////////////////////////////////////////////////////////////////////////
/** get a pair of colors that fulfil a certain role. see OPTIONS_RAW
** returns {-1, -1} if not found */
public int[] getOptionColor(int i) {
if (i < 0 || i >= options.length) return INVALID;
return options[i];
}
////////////////////////////////////////////////////////////////////////////////////////////////
/** get a basic or an extended color. made possible by extended only starting at 16
** returns -1 if not found */
public int getColor(int i) {
if (i < 0) return -1;
if (i < basic.length) return basic[i];
if (i < EXTENDED.length) return EXTENDED[i];
return -1;
}
////////////////////////////////////////////////////////////////////////////////////////////////
/** get "weechat color" from a set of standard (STD) colors used in weechat
** ctrl-f "weechat color" in https://weechat.org/files/doc/devel/weechat_dev.en.html
** returns -1 if not found */
public int getWeechatColor(int i) {
if (i == 0) return defaul[OPT_FG];
if (i < 0 || i >= WEECHAT_COLORS_TO_BASIC_COLORS.length) return -1;
return getColor(WEECHAT_COLORS_TO_BASIC_COLORS[i]);
}
////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////// private static final ///
////////////////////////////////////////////////////////////////////////////////////////////////
private final static int BASIC[] = new int[]{
0x000000, // Black
0x800000, // Light Red
0x008000, // Light Green
0x808000, // Light Yellow(Brown)
0x000080, // Light Blue
0x800080, // Light Magenta
0x008080, // Light Cyan
0xC0C0C0, // Light Gray
0x808080, // Gray
0xFF0000, // Red
0x00FF00, // Green
0xFFFF00, // Yellow
0x0000FF, // Blue
0xFF00FF, // Magenta
0x00FFFF, // Cyan
0xFFFFFF // White
};
// Extended terminal colors, from colortest.vim:
// http://www.vim.org/scripts/script.php?script_id=1349
private final static int EXTENDED[] = new int[256];
static {
int base[] = new int[]{0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF};
for (int i = 16; i < 232; i++) {
int j = i - 16;
EXTENDED[i] = (base[(j / 36) % 6]) << 16 | (base[(j / 6) % 6] << 8 | (base[j % 6]));
}
for (int i = 232; i < 256; i++) {
int j = 8 + i * 10;
EXTENDED[i] = j << 16 | j << 8 | j;
}
}
private final static int WEECHAT_COLORS_TO_BASIC_COLORS[] = new int[] {
0, // Default (handled in a special way)
0, // Black
8, // Dark Gray
9, // Red
1, // Light Red
10, // Green
2, // Light Green
3, // Brown
11, // Yellow
12, // Blue
4, // Light Blue
13, // Magenta
5, // Light Magenta
14, // Cyan
6, // Light Cyan
7, // Gray
15, // White
};
// default weechat options: id, fg, bg, name
// fg and bg stand for basic colors; can be -1 for no color and -2/-3 for default/default bg
private static final Object[] OPTIONS_RAW = new Object[]{
12, -1, "separator", // 0
-2, -3, "chat", // 1
-2, -1, "chat_time", // 2
3, -1, "chat_time_delimiters", // 3
11, -1, "chat_prefix_error", // 4
13, -1, "chat_prefix_network", // 5
15, -1, "chat_prefix_action", // 6
2, -1, "chat_prefix_join", // 7
1, -1, "chat_prefix_quit", // 8
5, -1, "chat_prefix_more", // 9
10, -1, "chat_prefix_suffix", // 10
15, -1, "chat_buffer", // 11
3, -1, "chat_server", // 12
15, -1, "chat_channel", // 13
6, -1, "chat_nick", // 14
15, -1, "chat_nick_self", // 15
14, -1, "chat_nick_other", // 16
-1, -1, null, // 17
-1, -1, null, // 18
-1, -1, null, // 19
-1, -1, null, // 20
-1, -1, null, // 21
-1, -1, null, // 22
-1, -1, null, // 23
-1, -1, null, // 24
-1, -1, null, // 25
-1, -1, null, // 26
14, -1, "chat_host", // 27
10, -1, "chat_delimiters", // 28
11, 13, "chat_highlight", // 29
13, -2, "chat_read_marker", // 30
11, 5, "chat_text_found", // 31
14, -1, "chat_value", // 32
3, -1, "chat_prefix_buffer", // 33
9, -1, "chat_tags", // 34
8, -1, "chat_inactive_window", // 35
8, -1, "chat_inactive_buffer", // 36
8, -1, "chat_prefix_buffer_inactive_buffer", // 37
8, -1, "chat_nick_offline", // 38
-2, 8, "chat_nick_offline_highlight", // 39
10, -1, "chat_nick_prefix", // 40
10, -1, "chat_nick_suffix", // 41
11, 13, "emphasis", // 42
14, -1, "chat_day_change" // 43
};
// option name -> id (size 44!!)
private static final HashMap<String, Integer> OPTIONS = new HashMap<>();
static {
for (int i = 0; i < OPTIONS_RAW.length/3; i++) {
String option = (String) OPTIONS_RAW[i*3 + 2];
if (option != null) OPTIONS.put(option, i);
}
OPTIONS.put("default", 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////// options ////
////////////////////////////////////////////////////////////////////////////////////////////////
// this loads stuff from "basic" and "def"/"def_bg". see OPTIONS_RAW
private void loadDefaultOptions() {
for (int i = 0; i < options.length; i++) {
int fg = (int) OPTIONS_RAW[i*3], bg = (int) OPTIONS_RAW[i*3 + 1];
options[i] = new int[]{getBasicColorOrDefaultFgBg(fg), getBasicColorOrDefaultFgBg(bg)};
}
}
private void loadOptionsFromProperties(Properties p) {
for (Map.Entry<String, Integer> option : OPTIONS.entrySet()) {
int fg = getPropertyInt(p, option.getKey(), -2);
int bg = getPropertyInt(p, option.getKey() + "_bg", -2);
if (fg != -2) options[option.getValue()][OPT_FG] = fg;
if (bg != -2) options[option.getValue()][OPT_BG] = bg;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////// helpers ////
////////////////////////////////////////////////////////////////////////////////////////////////
private int getPropertyInt(Properties p, String key, int d) {
try {return Integer.decode(p.getProperty(key));}
catch (Exception e) {return d;}
}
private int getBasicColorOrDefaultFgBg(int i) {
if (i == -3) return def[1];
if (i == -2) return def[0];
if (i < 0 || i >= basic.length) return -1;
return basic[i];
}
}