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