1 /*
2     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
3     SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #ifndef CHARACTERCOLOR_H
9 #define CHARACTERCOLOR_H
10 
11 // Qt
12 #include <QColor>
13 
14 namespace Konsole
15 {
16 // Attributed Character Representations ///////////////////////////////
17 
18 // Colors
19 
20 #define BASE_COLORS (2 + 8)
21 #define INTENSITIES 3
22 #define TABLE_COLORS (INTENSITIES * BASE_COLORS)
23 
24 enum ColorTableIndex {
25     ColorFgIndex,
26     ColorBgIndex,
27     Color0Index,
28     Color1Index,
29     Color2Index,
30     Color3Index,
31     Color4Index,
32     Color5Index,
33     Color6Index,
34     Color7Index,
35 
36     ColorFgIntenseIndex,
37     ColorBgIntenseIndex,
38     Color0IntenseIndex,
39     Color1IntenseIndex,
40     Color2IntenseIndex,
41     Color3IntenseIndex,
42     Color4IntenseIndex,
43     Color5IntenseIndex,
44     Color6IntenseIndex,
45     Color7IntenseIndex,
46 
47     ColorFgFaintIndex,
48     ColorBgFaintIndex,
49     Color0FaintIndex,
50     Color1FaintIndex,
51     Color2FaintIndex,
52     Color3FaintIndex,
53     Color4FaintIndex,
54     Color5FaintIndex,
55     Color6FaintIndex,
56     Color7FaintIndex,
57 };
58 
59 #define DEFAULT_FORE_COLOR 0
60 #define DEFAULT_BACK_COLOR 1
61 
62 /* CharacterColor is a union of the various color spaces.
63 
64    Assignment is as follows:
65 
66    Type  - Space        - Values
67 
68    0     - Undefined   - u:  0,      v:0        w:0
69    1     - Default     - u:  0..1    v:intense  w:0
70    2     - System      - u:  0..7    v:intense  w:0
71    3     - Index(256)  - u: 16..255  v:0        w:0
72    4     - RGB         - u:  0..255  v:0..256   w:0..256
73 
74    ``intense'' is either 0 (normal), 1 (intensive), or 2 (faint)
75 
76    Default color space has two separate colors, namely
77    default foreground and default background color.
78 */
79 
80 #define COLOR_SPACE_UNDEFINED 0
81 #define COLOR_SPACE_DEFAULT 1
82 #define COLOR_SPACE_SYSTEM 2
83 #define COLOR_SPACE_256 3
84 #define COLOR_SPACE_RGB 4
85 
86 /**
87  * Describes the color of a single character in the terminal.
88  */
89 class CharacterColor
90 {
91     friend class Character;
92 
93 public:
94     /** Constructs a new CharacterColor whose color and color space are undefined. */
CharacterColor()95     CharacterColor()
96         : _colorSpace(COLOR_SPACE_UNDEFINED)
97         , _u(0)
98         , _v(0)
99         , _w(0)
100     {
101     }
102 
103     /**
104      * Constructs a new CharacterColor using the specified @p colorSpace and with
105      * color value @p co
106      *
107      * The meaning of @p co depends on the @p colorSpace used.
108      *
109      * TODO : Document how @p co relates to @p colorSpace
110      *
111      * TODO : Add documentation about available color spaces.
112      */
CharacterColor(quint8 colorSpace,int co)113     CharacterColor(quint8 colorSpace, int co)
114         : _colorSpace(colorSpace)
115         , _u(0)
116         , _v(0)
117         , _w(0)
118     {
119         switch (colorSpace) {
120         case COLOR_SPACE_DEFAULT:
121             _u = co & 1;
122             break;
123         case COLOR_SPACE_SYSTEM:
124             _u = co & 7;
125             _v = (co >> 3) & 3;
126             break;
127         case COLOR_SPACE_256:
128             _u = co & 255;
129             break;
130         case COLOR_SPACE_RGB:
131             _u = co >> 16;
132             _v = co >> 8;
133             _w = co;
134             break;
135         default:
136             _colorSpace = COLOR_SPACE_UNDEFINED;
137         }
138     }
139 
colorSpace()140     quint8 colorSpace() const
141     {
142         return _colorSpace;
143     }
termColor(int * u,int * v,int * w)144     void termColor(int *u, int *v, int *w)
145     {
146         *u = _u;
147         *v = _v;
148         *w = _w;
149     }
150 
151     /**
152      * Returns true if this character color entry is valid.
153      */
isValid()154     bool isValid() const
155     {
156         return _colorSpace != COLOR_SPACE_UNDEFINED;
157     }
158 
159     /**
160      * Set this color as an intensive system color.
161      *
162      * This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
163      * color spaces.
164      */
165     void setIntensive();
166 
167     /**
168      * Set this color as a faint system color.
169      *
170      * This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
171      * color spaces.
172      */
173     void setFaint();
174 
175     /**
176      * Returns the color within the specified color @p base
177      *
178      * The @p base is only used if this color is one of the 16 system colors, otherwise
179      * it is ignored.
180      */
181     QColor color(const QColor *base) const;
182 
183     /**
184      * Compares two colors and returns true if they represent the same color value and
185      * use the same color space.
186      */
187     friend bool operator==(const CharacterColor &a, const CharacterColor &b);
188     /**
189      * Compares two colors and returns true if they represent different color values
190      * or use different color spaces.
191      */
192     friend bool operator!=(const CharacterColor &a, const CharacterColor &b);
193 
194 private:
195     quint8 _colorSpace;
196 
197     // bytes storing the character color
198     quint8 _u;
199     quint8 _v;
200     quint8 _w;
201 };
202 
203 inline bool operator==(const CharacterColor &a, const CharacterColor &b)
204 {
205     return a._colorSpace == b._colorSpace && a._u == b._u && a._v == b._v && a._w == b._w;
206 }
207 
208 inline bool operator!=(const CharacterColor &a, const CharacterColor &b)
209 {
210     return !operator==(a, b);
211 }
212 
color256(quint8 u,const QColor * base)213 inline const QColor color256(quint8 u, const QColor *base)
214 {
215     //   0.. 16: system colors
216     if (u < 8) {
217         return base[u + 2];
218     }
219     u -= 8;
220     if (u < 8) {
221         return base[u + 2 + BASE_COLORS];
222     }
223     u -= 8;
224 
225     //  16..231: 6x6x6 rgb color cube
226     if (u < 216) {
227         return QColor(((u / 36) % 6) ? (40 * ((u / 36) % 6) + 55) : 0,
228                       ((u / 6) % 6) ? (40 * ((u / 6) % 6) + 55) : 0,
229                       ((u / 1) % 6) ? (40 * ((u / 1) % 6) + 55) : 0);
230     }
231     u -= 216;
232 
233     // 232..255: gray, leaving out black and white
234     int gray = u * 10 + 8;
235 
236     return QColor(gray, gray, gray);
237 }
238 
color(const QColor * base)239 inline QColor CharacterColor::color(const QColor *base) const
240 {
241     switch (_colorSpace) {
242     case COLOR_SPACE_DEFAULT:
243         return base[_u + 0 + (_v * BASE_COLORS)];
244     case COLOR_SPACE_SYSTEM:
245         return base[_u + 2 + (_v * BASE_COLORS)];
246     case COLOR_SPACE_256:
247         return color256(_u, base);
248     case COLOR_SPACE_RGB:
249         return QColor(_u, _v, _w);
250     case COLOR_SPACE_UNDEFINED:
251         return QColor();
252     }
253 
254     Q_ASSERT(false); // invalid color space
255 
256     return QColor();
257 }
258 
setIntensive()259 inline void CharacterColor::setIntensive()
260 {
261     if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT) {
262         _v = 1;
263     }
264 }
265 
setFaint()266 inline void CharacterColor::setFaint()
267 {
268     if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT) {
269         _v = 2;
270     }
271 }
272 }
273 
274 #endif // CHARACTERCOLOR_H
275