1 /*
2     This file is part of Konsole, KDE's terminal.
3 
4     Copyright (C) 2007, 2013 by Robert Knight <robertknight@gmail.com>
5     Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
6 
7     Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
8 
9     This program is free software: you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22     02110-1301  USA.
23 */
24 
25 #ifndef CHARACTERCOLOR_H
26 #define CHARACTERCOLOR_H
27 
28 // Qt
29 #include <QColor>
30 
31 /**
32  * An entry in a terminal display's color palette.
33  *
34  * A color palette is an array of 16 ColorEntry instances which map
35  * system color indexes (from 0 to 15) into actual colors.
36  *
37  * Each entry can be set as bold, in which case any text
38  * drawn using the color should be drawn in bold.
39  *
40  * Each entry can also be transparent, in which case the terminal
41  * display should avoid drawing the background for any characters
42  * using the entry as a background.
43  */
44 class ColorEntry
45 {
46 public:
47   /**
48    * Constructs a new color palette entry.
49    *
50    * @param c The color value for this entry.
51    * @param tr Specifies that the color should be transparent when used as a background color.
52    * @param b Specifies that text drawn with this color should be bold.
53    */
ColorEntry(QColor c,bool tr,bool b)54   ColorEntry(QColor c, bool tr, bool b) : color(c), transparent(tr), bold(b) {}
55 
56   /**
57    * Constructs a new color palette entry with an undefined color, and
58    * with the transparent and bold flags set to false.
59    */
ColorEntry()60   ColorEntry() : transparent(false), bold(false) {}
61 
62   /**
63    * Sets the color, transparency and boldness of this color to those of @p rhs.
64    */
65   void operator=(const ColorEntry& rhs)
66   {
67        color = rhs.color;
68        transparent = rhs.transparent;
69        bold = rhs.bold;
70   }
71 
72   /** The color value of this entry for display. */
73   QColor color;
74 
75   /**
76    * If true character backgrounds using this color should be transparent.
77    * This is not applicable when the color is used to render text.
78    */
79   bool   transparent;
80   /**
81    * If true characters drawn using this color should be bold.
82    * This is not applicable when the color is used to draw a character's background.
83    */
84   bool   bold;
85 };
86 
87 
88 // Attributed Character Representations ///////////////////////////////
89 
90 // Colors
91 
92 #define BASE_COLORS   (2+8)
93 #define INTENSITIES   2
94 #define TABLE_COLORS  (INTENSITIES*BASE_COLORS)
95 
96 #define DEFAULT_FORE_COLOR 0
97 #define DEFAULT_BACK_COLOR 1
98 
99 //a standard set of colors using black text on a white background.
100 //defined in TerminalDisplay.cpp
101 
102 static const ColorEntry base_color_table[TABLE_COLORS] =
103 {
104     // normal
105     ColorEntry(QColor(0x00,0x00,0x00), 1, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 ), // Dfore, Dback
106     ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
107     ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
108     ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
109     ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
110     // intensiv
111     ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
112     ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
113     ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
114     ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
115     ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
116 };
117 
118 /* CharacterColor is a union of the various color spaces.
119 
120    Assignment is as follows:
121 
122    Type  - Space        - Values
123 
124    0     - Undefined   - u:  0,      v:0        w:0
125    1     - Default     - u:  0..1    v:intense  w:0
126    2     - System      - u:  0..7    v:intense  w:0
127    3     - Index(256)  - u: 16..255  v:0        w:0
128    4     - RGB         - u:  0..255  v:0..256   w:0..256
129 
130    Default colour space has two separate colours, namely
131    default foreground and default background colour.
132 */
133 
134 #define COLOR_SPACE_UNDEFINED   0
135 #define COLOR_SPACE_DEFAULT     1
136 #define COLOR_SPACE_SYSTEM      2
137 #define COLOR_SPACE_256         3
138 #define COLOR_SPACE_RGB         4
139 
140 /**
141  * Describes the color of a single character in the terminal.
142  */
143 class CharacterColor
144 {
145     friend class Character;
146 
147 public:
148   /** Constructs a new CharacterColor whoose color and color space are undefined. */
CharacterColor()149   CharacterColor()
150       : _colorSpace(COLOR_SPACE_UNDEFINED),
151         _u(0),
152         _v(0),
153         _w(0)
154   {}
155 
156   /**
157    * Constructs a new CharacterColor using the specified @p colorSpace and with
158    * color value @p co
159    *
160    * The meaning of @p co depends on the @p colorSpace used.
161    *
162    * TODO : Document how @p co relates to @p colorSpace
163    *
164    * TODO : Add documentation about available color spaces.
165    */
CharacterColor(quint8 colorSpace,int co)166   CharacterColor(quint8 colorSpace, int co)
167       : _colorSpace(colorSpace),
168         _u(0),
169         _v(0),
170         _w(0)
171   {
172     switch (colorSpace)
173     {
174         case COLOR_SPACE_DEFAULT:
175             _u = co & 1;
176             break;
177         case COLOR_SPACE_SYSTEM:
178             _u = co & 7;
179             _v = (co >> 3) & 1;
180             break;
181         case COLOR_SPACE_256:
182             _u = co & 255;
183             break;
184         case COLOR_SPACE_RGB:
185             _u = co >> 16;
186             _v = co >> 8;
187             _w = co;
188             break;
189         default:
190             _colorSpace = COLOR_SPACE_UNDEFINED;
191     }
192   }
193 
194   /**
195    * Returns true if this character color entry is valid.
196    */
isValid()197   bool isValid()
198   {
199         return _colorSpace != COLOR_SPACE_UNDEFINED;
200   }
201 
202   /**
203    * Toggles the value of this color between a normal system color and the corresponding intensive
204    * system color.
205    *
206    * This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
207    * color spaces.
208    */
209   void toggleIntensive();
210 
211   /**
212    * Returns the color within the specified color @palette
213    *
214    * The @p palette is only used if this color is one of the 16 system colors, otherwise
215    * it is ignored.
216    */
217   QColor color(const ColorEntry* palette) const;
218 
219   /**
220    * Compares two colors and returns true if they represent the same color value and
221    * use the same color space.
222    */
223   friend bool operator == (const CharacterColor& a, const CharacterColor& b);
224   /**
225    * Compares two colors and returns true if they represent different color values
226    * or use different color spaces.
227    */
228   friend bool operator != (const CharacterColor& a, const CharacterColor& b);
229 
230 private:
231   quint8 _colorSpace;
232 
233   // bytes storing the character color
234   quint8 _u;
235   quint8 _v;
236   quint8 _w;
237 };
238 
239 inline bool operator == (const CharacterColor& a, const CharacterColor& b)
240 {
241     return a._colorSpace == b._colorSpace &&
242 	       a._u == b._u &&
243 	       a._v == b._v &&
244            a._w == b._w;
245 }
246 
247 inline bool operator != (const CharacterColor& a, const CharacterColor& b)
248 {
249     return !operator==(a,b);
250 }
251 
color256(quint8 u,const ColorEntry * base)252 inline const QColor color256(quint8 u, const ColorEntry* base)
253 {
254   //   0.. 16: system colors
255   if (u <   8) return base[u+2            ].color; u -= 8;
256   if (u <   8) return base[u+2+BASE_COLORS].color; u -= 8;
257 
258   //  16..231: 6x6x6 rgb color cube
259   if (u < 216) return QColor(255*((u/36)%6)/5,
260                              255*((u/ 6)%6)/5,
261                              255*((u/ 1)%6)/5); u -= 216;
262 
263   // 232..255: gray, leaving out black and white
264   int gray = u*10+8; return QColor(gray,gray,gray);
265 }
266 
color(const ColorEntry * base)267 inline QColor CharacterColor::color(const ColorEntry* base) const
268 {
269   switch (_colorSpace)
270   {
271     case COLOR_SPACE_DEFAULT: return base[_u+0+(_v?BASE_COLORS:0)].color;
272     case COLOR_SPACE_SYSTEM: return base[_u+2+(_v?BASE_COLORS:0)].color;
273     case COLOR_SPACE_256: return color256(_u,base);
274     case COLOR_SPACE_RGB: return QColor(_u,_v,_w);
275     case COLOR_SPACE_UNDEFINED: return QColor();
276   }
277 
278   Q_ASSERT(false); // invalid color space
279 
280   return QColor();
281 }
282 
toggleIntensive()283 inline void CharacterColor::toggleIntensive()
284 {
285   if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT)
286   {
287     _v = !_v;
288   }
289 }
290 
291 #endif // CHARACTERCOLOR_H
292