1/*
2 * Copyright 2010-2013, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stefano Ceccherini, stefano.ceccherini@gmail.com
7 *		Siarzhuk Zharski, zharik@gmx.li
8 */
9
10
11#include "Colors.h"
12
13#include <ctype.h>
14#include <stdio.h>
15#include <strings.h>
16
17#include <Application.h>
18#include <Catalog.h>
19#include <Resources.h>
20
21
22#undef B_TRANSLATION_CONTEXT
23#define B_TRANSLATION_CONTEXT "Terminal colors scheme"
24
25
26// Standard colors
27const rgb_color kBlack = { 0, 0, 0, 255 };
28const rgb_color kGreen = { 0, 255, 0, 255 };
29const rgb_color kWhite = { 255, 255, 255, 255 };
30const rgb_color kYellow = { 255, 255, 0, 255 };
31
32
33const struct color_scheme kColorSchemeDefault = {
34	B_TRANSLATE("Default"),
35	kBlack,
36	kWhite,
37	kWhite,
38	kBlack,
39	kWhite,
40	kBlack
41};
42
43const struct color_scheme kColorSchemeBlue = {
44	B_TRANSLATE("Blue"),
45	kYellow,
46	{ 0, 0, 139, 255 },
47	kBlack,
48	kYellow,
49	kBlack,
50	{ 0, 139, 139, 255 },
51};
52
53const struct color_scheme kColorSchemeMidnight = {
54	B_TRANSLATE("Midnight"),
55	kWhite,
56	kBlack,
57	kBlack,
58	kWhite,
59	kBlack,
60	kWhite
61};
62
63const struct color_scheme kColorSchemeProfessional = {
64	B_TRANSLATE("Professional"),
65	kWhite,
66	{ 8, 8, 8, 255 },
67	{ 50, 50, 50, 255 },
68	kWhite,
69	kWhite,
70	{ 50, 50, 50, 255 },
71};
72
73const struct color_scheme kColorSchemeRetro = {
74	B_TRANSLATE("Retro"),
75	kGreen,
76	kBlack,
77	kBlack,
78	kGreen,
79	kBlack,
80	kGreen
81};
82
83const struct color_scheme kColorSchemeSlate = {
84	B_TRANSLATE("Slate"),
85	kWhite,
86	{ 20, 20, 28, 255 },
87	{ 70, 70, 70, 255 },
88	{ 255, 200, 0, 255 },
89	kWhite,
90	{ 70, 70, 70, 255 },
91};
92
93const struct color_scheme kColorSchemeSolarizedDark = {
94	B_TRANSLATE("Solarized Dark"),
95	{ 119, 137, 139, 255 },
96	{ 0, 36, 45, 255 },
97	{ 0, 46, 57, 255 },
98	{ 120, 137, 139, 255 },
99	{ 136, 151, 151, 255 },
100	{ 0, 46, 57, 255 },
101};
102
103const struct color_scheme kColorSchemeSolarizedLight = {
104	B_TRANSLATE("Solarized Light"),
105	{ 90, 112, 120, 255 },
106	{ 253, 244, 223, 255 },
107	{ 236, 228, 207, 255 },
108	{ 90, 112, 120, 255 },
109	{ 78, 99, 106, 255 },
110	{ 236, 228, 207, 255 },
111};
112
113struct color_scheme gCustomColorScheme = {
114	B_TRANSLATE("Custom")
115};
116
117const color_scheme* gPredefinedColorSchemes[] = {
118	&kColorSchemeDefault,
119	&kColorSchemeBlue,
120	&kColorSchemeMidnight,
121	&kColorSchemeProfessional,
122	&kColorSchemeRetro,
123	&kColorSchemeSlate,
124	&kColorSchemeSolarizedDark,
125	&kColorSchemeSolarizedLight,
126	&gCustomColorScheme,
127	NULL
128};
129
130
131bool
132color_scheme::operator==(const color_scheme& scheme)
133{
134	return text_fore_color == scheme.text_fore_color
135		&& text_back_color == scheme.text_back_color
136		&& cursor_fore_color == scheme.cursor_fore_color
137		&& cursor_back_color == scheme.cursor_back_color
138		&& select_fore_color == scheme.select_fore_color
139		&& select_back_color == scheme.select_back_color;
140}
141
142// #pragma mark XColorsTable implementation
143
144XColorsTable gXColorsTable;
145
146
147XColorsTable::XColorsTable()
148		:
149		fTable(NULL),
150		fCount(0)
151{
152}
153
154
155XColorsTable::~XColorsTable()
156{
157	// fTable as result of LoadResource call and owned
158	// by BApplication so no need to free it explicitly
159	fTable = NULL;
160	fCount = 0;
161}
162
163
164status_t
165XColorsTable::LookUpColor(const char* name, rgb_color* color)
166{
167	if (name == NULL || color == NULL)
168		return B_BAD_DATA;
169
170	// first check for 'rgb:xxx/xxx/xxx'-encoded color names
171	const char magic[5] = "rgb:";
172	if (strncasecmp(name, magic, sizeof(magic) - 1) == 0) {
173		int r = 0, g = 0, b = 0;
174		if (sscanf(&name[4], "%x/%x/%x", &r, &g, &b) == 3) {
175			color->set_to(0xFF & r, 0xFF & g, 0xFF & b);
176			return B_OK;
177		}
178		// else - let the chance lookup in rgb.txt table. Is it reasonable??
179	}
180
181	// for non-'rgb:xxx/xxx/xxx'-encoded - search the X11 rgb table
182	if (fTable == NULL) {
183		status_t result = _LoadXColorsTable();
184		if (result != B_OK)
185			return result;
186	}
187
188	// use binary search to lookup color name hash in table
189	int left  = -1;
190	int right = fCount;
191	uint32 hash = _HashName(name);
192	while ((right - left) > 1) {
193		int i = (left + right) / 2;
194		((fTable[i].hash < hash) ? left : right) = i;
195	}
196
197	if (fTable[right].hash == hash) {
198		*color = fTable[right].color;
199		return B_OK;
200	}
201
202	return B_NAME_NOT_FOUND;
203}
204
205
206status_t
207XColorsTable::_LoadXColorsTable()
208{
209	BResources* res = BApplication::AppResources();
210	if (res == NULL)
211		return B_ERROR;
212
213	size_t size = 0;
214	fTable = (_XColorEntry*)res->LoadResource(B_RAW_TYPE, "XColorsTable", &size);
215	if (fTable == NULL || size < sizeof(_XColorEntry)) {
216		fTable = NULL;
217		return B_ENTRY_NOT_FOUND;
218	}
219
220	fCount = size / sizeof(_XColorEntry);
221	return B_OK;
222}
223
224
225uint32
226XColorsTable::_HashName(const char* name)
227{
228	uint32 hash = 0;
229	uint32 g = 0;
230
231	// Using modified P.J.Weinberger hash algorithm
232	// Spaces are purged out, characters are upper-cased
233	// 'E' replaced with 'A' (to join 'grey' and 'gray' variations)
234	for (const char* p = name; *p; p++) {
235		int ch = toupper(*p);
236		switch (ch) {
237		case ' ':
238			break;
239		case 'E':
240			ch = 'A';
241		default:
242			hash = (hash << 4) + (ch & 0xFF);
243			g = hash & 0xf0000000;
244			if (g != 0) {
245				hash ^= g >> 24;
246				hash ^= g;
247			}
248			break;
249		}
250	}
251
252	return hash;
253}
254