1 /**
2  * Consoleur: a package for interaction with character-oriented terminal emulators
3  *
4  * Copyright: Maxim Freck, 2017.
5  * Authors:   Maxim Freck <maxim@freck.pp.ru>
6  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  */
8 module consoleur.style.posix;
9 version(Posix) {
10 
11 /// Color list
12 enum Color: uint
13 {
14 	//default 8 colors
15 	black = 0,
16 	maroon,
17 	green,
18 	olive,
19 	navy,
20 	purple,
21 	teal,
22 	silver,
23 
24 	//light 8 colors
25 	grey = 8,
26 	red,
27 	lime,
28 	yellow,
29 	blue,
30 	fuchsia,
31 	aqua,
32 	white,
33 
34 	grayscale1 = 232,
35 	grayscale2,
36 	grayscale3,
37 	grayscale4,
38 	grayscale5,
39 	grayscale6,
40 	grayscale7,
41 	grayscale8,
42 	grayscale9,
43 	grayscale10,
44 	grayscale11,
45 	grayscale12,
46 	grayscale13,
47 	grayscale14,
48 	grayscale15,
49 	grayscale16,
50 	grayscale17,
51 	grayscale18,
52 	grayscale19,
53 	grayscale20,
54 	grayscale21,
55 	grayscale22,
56 	grayscale23,
57 	grayscale24
58 }
59 
60 /// Font styles
61 enum Style: uint {
62 	none        = 0,
63 	bold        = 0b00000000_00000000_00000000_00000001,
64 	italic      = 0b00000000_00000000_00000000_00000010,
65 	underline   = 0b00000000_00000000_00000000_00000100,
66 	blink       = 0b00000000_00000000_00000000_00001000,
67 	inverted    = 0b00000000_00000000_00000000_00010000,
68 	linethrough = 0b00000000_00000000_00000000_00100000,
69 }
70 
71 
72 private Style style;
73 private uint fgColor = Color.white;
74 private uint bgColor = Color.black;
75 
76 /*******
77  * Sets default colors
78  */
79 void setDefaultColors() @safe
80 {
81 	import std.stdio: write;
82 	write("\x1b[39m\x1b[49m");
83 }
84 
85 /*******
86  * Sets foreground color
87  * Returns: true in case of success, otherwise false
88  *
89  * Params:
90  *  c = The color (0-7 — default colors, 8-15 — bright colors)
91  */
92 bool setFg(Color c) @safe
93 {
94 	import std.stdio: writef;
95 
96 	if (c > 15) return false;
97 	fgColor = c;
98 
99 	if (c > 7) {
100 		writef("\033[%u;1m", c+30-8);
101 	} else {
102 		writef("\033[%um", c+30);
103 	}
104 
105 	return true;
106 }
107 
108 /*******
109  * Sets background color
110  * Returns: true in case of success, otherwise false
111  *
112  * Params:
113  *  c = The color (0-7 — default colors, 8-15 — bright colors)
114  */
115 bool setBg(Color c) @safe
116 {
117 	import std.stdio: writef;
118 
119 	if (c > 15) return false;
120 	bgColor = c;
121 
122 	if (c > 7) {
123 		writef("\x1b[%u;1m", c+40-8);
124 	} else {
125 		writef("\x1b[%um", c+40);
126 	}
127 
128 	return true;
129 }
130 
131 /*******
132  * Sets terminal colors
133  * Returns: true in case of success, otherwise false
134  *
135  * Params:
136  *  fgC = The foreground color
137  *  bgC = The background color
138  */
139 bool setColors(Color fgC, Color bgC) @safe
140 {
141 	return (setFg(fgC) && setBg(bgC));
142 }
143 
144 
145 /*******
146  * Sets foreground color in a 256 color mode
147  * Returns: true in case of success, otherwise false
148  *
149  * Params:
150  *  c = The color
151  */
152 bool setFg256(uint c) @safe
153 {
154 	import std.stdio: writef;
155 
156 	if (c > 255) return false;
157 
158 	fgColor = c;
159 	writef("\x1b[38;05;%um", c);
160 
161 	return true;
162 }
163 
164 /*******
165  * Sets background color in a 256 color mode
166  * Returns: true in case of success, otherwise false
167  *
168  * Params:
169  *  c = The color
170  */
171 bool setBg256(uint c) @safe
172 {
173 	import std.stdio: writef;
174 
175 	if (c > 255) return false;
176 
177 	bgColor = c;
178 	writef("\x1b[48;05;%um", c);
179 
180 	return true;
181 }
182 
183 /*******
184  * Sets colors in a 256 color mode
185  * Returns: true in case of success, otherwise false
186  *
187  * Params:
188  *  fgC = The foreground color
189  *  bgC = The background color
190  */
191 bool setColors256(int fgC, int bgC) @safe
192 {
193 	return (setFg256(fgC) && setBg256(bgC));
194 }
195 
196 /*******
197  * Sets foreground color in a TrueColor mode
198  * Returns: true in case of success, otherwise false
199  *
200  * Params:
201  *  c = The color
202  */
203 bool setFg24bit(uint c) @safe
204 {
205 	import std.stdio: writef;
206 
207 	fgColor = c;
208 	writef("\x1b[38;2;%u;%u;%um", c.r, c.g, c.b);
209 
210 	return true;
211 }
212 
213 /*******
214  * Sets background color in a TrueColor mode
215  * Returns: true in case of success, otherwise false
216  *
217  * Params:
218  *  c = The color
219  */
220 bool setBg24bit(uint c) @safe
221 {
222 	import std.stdio: writef;
223 
224 	bgColor = c;
225 	writef("\x1b[48;2;%u;%u;%um", c.r, c.g, c.b);
226 
227 	return true;
228 }
229 
230 /*******
231  * Sets colors in a TrueColor mode
232  * Returns: true in case of success, otherwise false
233  *
234  * Params:
235  *  fgC = The foreground color
236  *  bgC = The background color
237  */
238 void setColors24bit(int fgC, int bgC) @safe
239 {
240 	setFg24bit(fgC);
241 	setBg24bit(bgC);
242 }
243 
244 
245 /*******
246  * Builds color code for a TrueColor functions
247  * Returns: uint representing the color code
248  *
249  * Params:
250  *  r = red component
251  *  g = green component
252  *  b = blue component
253  */
254 pragma(inline) nothrow uint rgb(uint r, uint g, uint b) @safe @nogc
255 {
256 	return ((r & 0xff) << 24 | (g & 0xff) << 16 | (b & 0xff) << 8);
257 }
258 
259 pragma(inline) private nothrow uint r(uint src) @safe @nogc
260 {
261 	return (src & 0xff000000) >> 24;
262 }
263 
264 pragma(inline) private nothrow uint g(uint src) @safe @nogc
265 {
266 	return (src & 0x00ff0000) >> 16;
267 }
268 
269 pragma(inline) private nothrow uint b(uint src) @safe @nogc
270 {
271 	return (src & 0x0000ff00) >> 8;
272 }
273 
274 
275 /*******
276  * Sets text styles (see enum Style)
277  *
278  * Params:
279  *  s = The style
280  */
281 void setStyle(Style s)
282 {
283 	import std.stdio: write;
284 	string esc;
285 
286 	if (s == style) return;
287 
288 	esc.check(s, Style.bold, "\x1b[1m", "\x1b[22m");
289 	esc.check(s, Style.italic, "\x1b[3m", "\x1b[23m");
290 	esc.check(s, Style.underline, "\x1b[4m", "\x1b[24m");
291 	esc.check(s, Style.blink, "\x1b[5m", "\x1b[25m");
292 	esc.check(s, Style.inverted, "\x1b[7m", "\x1b[27m");
293 	esc.check(s, Style.linethrough, "\x1b[9m", "\x1b[29m");
294 
295 	style = s;
296 
297 	write(esc);
298 }
299 
300 pragma(inline) private void check(ref string str, Style s, Style st, string on, string off) @safe
301 {
302 	if ( (s & st) && !(style & st)) {
303 		str ~= on;
304 		style |= st;
305 	} else if (!(s & st) && (style & st)) {
306 		str ~=off;
307 		style &= ~st;
308 	}
309 }
310 
311 }