File indexing completed on 2024-05-19 05:28:14

0001 /*
0002     This file is part of Konsole, KDE's terminal.
0003 
0004     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0005     SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program; if not, write to the Free Software
0016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0017     02110-1301  USA.
0018 */
0019 
0020 #ifndef CHARACTERCOLOR_H
0021 #define CHARACTERCOLOR_H
0022 
0023 // Qt
0024 #include <QColor>
0025 #include <span>
0026 
0027 // #include <kdemacros.h>
0028 #define KDE_NO_EXPORT
0029 
0030 namespace Konsole
0031 {
0032 
0033 /**
0034  * An entry in a terminal display's color palette.
0035  *
0036  * A color palette is an array of 16 ColorEntry instances which map
0037  * system color indexes (from 0 to 15) into actual colors.
0038  *
0039  * Each entry can be set as bold, in which case any text
0040  * drawn using the color should be drawn in bold.
0041  *
0042  * Each entry can also be transparent, in which case the terminal
0043  * display should avoid drawing the background for any characters
0044  * using the entry as a background.
0045  */
0046 class ColorEntry
0047 {
0048 public:
0049     /** Specifies the weight to use when drawing text with this color. */
0050     enum FontWeight {
0051         /** Always draw text in this color with a bold weight. */
0052         Bold,
0053         /** Always draw text in this color with a normal weight. */
0054         Normal,
0055         /**
0056          * Use the current font weight set by the terminal application.
0057          * This is the default behavior.
0058          */
0059         UseCurrentFormat
0060     };
0061 
0062     /**
0063      * Constructs a new color palette entry.
0064      *
0065      * @param c The color value for this entry.
0066      * @param tr Specifies that the color should be transparent when used as a background color.
0067      * @param weight Specifies the font weight to use when drawing text with this color.
0068      */
0069     constexpr ColorEntry(QColor c, bool tr, FontWeight weight = UseCurrentFormat)
0070         : color(c)
0071         , transparent(tr)
0072         , fontWeight(weight)
0073     {
0074     }
0075 
0076     /**
0077      * Constructs a new color palette entry with an undefined color, and
0078      * with the transparent and bold flags set to false.
0079      */
0080     ColorEntry()
0081         : transparent(false)
0082         , fontWeight(UseCurrentFormat)
0083     {
0084     }
0085 
0086     /** The color value of this entry for display. */
0087     QColor color;
0088 
0089     /**
0090      * If true character backgrounds using this color should be transparent.
0091      * This is not applicable when the color is used to render text.
0092      */
0093     bool transparent;
0094     /**
0095      * Specifies the font weight to use when drawing text with this color.
0096      * This is not applicable when the color is used to draw a character's background.
0097      */
0098     FontWeight fontWeight;
0099 };
0100 
0101 // Attributed Character Representations ///////////////////////////////
0102 
0103 // Colors
0104 
0105 constexpr auto BASE_COLORS = (2 + 8);
0106 constexpr auto INTENSITIES = 2;
0107 constexpr auto TABLE_COLORS = (INTENSITIES * BASE_COLORS);
0108 
0109 constexpr auto DEFAULT_FORE_COLOR = 0;
0110 constexpr auto DEFAULT_BACK_COLOR = 1;
0111 
0112 // a standard set of colors using black text on a white background.
0113 // defined in TerminalDisplay.cpp
0114 
0115 /* CharacterColor is a union of the various color spaces.
0116 
0117    Assignment is as follows:
0118 
0119    Type  - Space        - Values
0120 
0121    0     - Undefined   - u:  0,      v:0        w:0
0122    1     - Default     - u:  0..1    v:intense  w:0
0123    2     - System      - u:  0..7    v:intense  w:0
0124    3     - Index(256)  - u: 16..255  v:0        w:0
0125    4     - RGB         - u:  0..255  v:0..256   w:0..256
0126 
0127    Default colour space has two separate colours, namely
0128    default foreground and default background colour.
0129 */
0130 
0131 #define COLOR_SPACE_UNDEFINED 0
0132 #define COLOR_SPACE_DEFAULT 1
0133 #define COLOR_SPACE_SYSTEM 2
0134 #define COLOR_SPACE_256 3
0135 #define COLOR_SPACE_RGB 4
0136 
0137 /**
0138  * Describes the color of a single character in the terminal.
0139  */
0140 class CharacterColor
0141 {
0142     friend class Character;
0143 
0144 public:
0145     /** Constructs a new CharacterColor whoose color and color space are undefined. */
0146     constexpr CharacterColor()
0147         : _colorSpace(COLOR_SPACE_UNDEFINED)
0148         , _u(0)
0149         , _v(0)
0150         , _w(0)
0151     {
0152     }
0153 
0154     /**
0155      * Constructs a new CharacterColor using the specified @p colorSpace and with
0156      * color value @p co
0157      *
0158      * The meaning of @p co depends on the @p colorSpace used.
0159      *
0160      * TODO : Document how @p co relates to @p colorSpace
0161      *
0162      * TODO : Add documentation about available color spaces.
0163      */
0164     constexpr CharacterColor(quint8 colorSpace, int co)
0165         : _colorSpace(colorSpace)
0166         , _u(0)
0167         , _v(0)
0168         , _w(0)
0169     {
0170         switch (colorSpace) {
0171         case COLOR_SPACE_DEFAULT:
0172             _u = co & 1;
0173             break;
0174         case COLOR_SPACE_SYSTEM:
0175             _u = co & 7;
0176             _v = (co >> 3) & 1;
0177             break;
0178         case COLOR_SPACE_256:
0179             _u = co & 255;
0180             break;
0181         case COLOR_SPACE_RGB:
0182             _u = co >> 16;
0183             _v = co >> 8;
0184             _w = co;
0185             break;
0186         default:
0187             _colorSpace = COLOR_SPACE_UNDEFINED;
0188         }
0189     }
0190 
0191     /**
0192      * Returns true if this character color entry is valid.
0193      */
0194     constexpr bool isValid() const
0195     {
0196         return _colorSpace != COLOR_SPACE_UNDEFINED;
0197     }
0198 
0199     /**
0200      * Set the value of this color from a normal system color to the corresponding intensive
0201      * system color if it's not already an intensive system color.
0202      *
0203      * This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
0204      * color spaces.
0205      */
0206     void setIntensive();
0207 
0208     /**
0209      * Returns the color within the specified color @p palette
0210      *
0211      * The @p palette is only used if this color is one of the 16 system colors, otherwise
0212      * it is ignored.
0213      */
0214     constexpr QColor color(std::span<const ColorEntry> palette) const;
0215 
0216     /**
0217      * Compares two colors and returns true if they represent the same color value and
0218      * use the same color space.
0219      */
0220     constexpr friend bool operator==(const CharacterColor &a, const CharacterColor &b);
0221     /**
0222      * Compares two colors and returns true if they represent different color values
0223      * or use different color spaces.
0224      */
0225     constexpr friend bool operator!=(const CharacterColor &a, const CharacterColor &b);
0226 
0227 private:
0228     quint8 _colorSpace;
0229 
0230     // bytes storing the character color
0231     quint8 _u;
0232     quint8 _v;
0233     quint8 _w;
0234 };
0235 
0236 constexpr inline bool operator==(const CharacterColor &a, const CharacterColor &b)
0237 {
0238     return a._colorSpace == b._colorSpace && a._u == b._u && a._v == b._v && a._w == b._w;
0239 }
0240 
0241 constexpr inline bool operator!=(const CharacterColor &a, const CharacterColor &b)
0242 {
0243     return !operator==(a, b);
0244 }
0245 
0246 constexpr inline const QColor color256(quint8 u, std::span<const ColorEntry> base)
0247 {
0248     //   0.. 16: system colors
0249     if (u < 8)
0250         return base[u + 2].color;
0251     u -= 8;
0252     if (u < 8)
0253         return base[u + 2 + BASE_COLORS].color;
0254     u -= 8;
0255 
0256     //  16..231: 6x6x6 rgb color cube
0257     if (u < 216)
0258         return QColor(((u / 36) % 6) ? (40 * ((u / 36) % 6) + 55) : 0,
0259                       ((u / 6) % 6) ? (40 * ((u / 6) % 6) + 55) : 0,
0260                       ((u / 1) % 6) ? (40 * ((u / 1) % 6) + 55) : 0);
0261     u -= 216;
0262 
0263     // 232..255: gray, leaving out black and white
0264     int gray = u * 10 + 8;
0265     return QColor(gray, gray, gray);
0266 }
0267 
0268 constexpr inline QColor CharacterColor::color(std::span<const ColorEntry> base) const
0269 {
0270     switch (_colorSpace) {
0271     case COLOR_SPACE_DEFAULT:
0272         return base[_u + 0 + (_v ? BASE_COLORS : 0)].color;
0273     case COLOR_SPACE_SYSTEM:
0274         return base[_u + 2 + (_v ? BASE_COLORS : 0)].color;
0275     case COLOR_SPACE_256:
0276         return color256(_u, base);
0277     case COLOR_SPACE_RGB:
0278         return {_u, _v, _w};
0279     case COLOR_SPACE_UNDEFINED:
0280         return QColor();
0281     }
0282 
0283     Q_ASSERT(false); // invalid color space
0284 
0285     return QColor();
0286 }
0287 
0288 inline void CharacterColor::setIntensive()
0289 {
0290     if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT) {
0291         _v = 1;
0292     }
0293 }
0294 }
0295 
0296 #endif // CHARACTERCOLOR_H