Serenity Operating System
1/*
2 * Copyright (c) 2021, Daniel Bertalan <dani@danielbertalan.dev>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Types.h>
10
11namespace VT {
12
13class Color {
14public:
15 enum class ANSIColor : u16 {
16 Black = 0,
17 Red,
18 Green,
19 Yellow,
20 Blue,
21 Magenta,
22 Cyan,
23 White,
24 BrightBlack,
25 BrightRed,
26 BrightGreen,
27 BrightYellow,
28 BrightBlue,
29 BrightMagenta,
30 BrightCyan,
31 BrightWhite,
32 // We use the values above to directly index into the color lookup table,
33 // but the ones below are handled separately.
34 DefaultForeground = 256,
35 DefaultBackground
36 };
37
38 static constexpr Color rgb(u32 rgb)
39 {
40 return Color(rgb);
41 }
42
43 static constexpr Color indexed(u8 index)
44 {
45 return Color(index);
46 }
47
48 static constexpr Color named(ANSIColor name)
49 {
50 return Color(name);
51 }
52
53 constexpr bool is_rgb() const
54 {
55 return m_kind == Kind::RGB;
56 }
57
58 constexpr bool is_indexed() const
59 {
60 return m_kind == Kind::Indexed;
61 }
62
63 constexpr bool is_named() const
64 {
65 return m_kind == Kind::Named;
66 }
67
68 constexpr u32 as_rgb() const
69 {
70 VERIFY(is_rgb());
71 return m_value.as_rgb;
72 }
73
74 constexpr u8 as_indexed() const
75 {
76 VERIFY(is_indexed());
77 return m_value.as_indexed;
78 }
79
80 constexpr ANSIColor as_named() const
81 {
82 VERIFY(is_named());
83 return m_value.as_named;
84 }
85
86 constexpr Color to_bright() const
87 {
88 if (is_named()) {
89 auto numeric_value = static_cast<u16>(as_named());
90 if (numeric_value < 8)
91 return Color::named(static_cast<ANSIColor>(numeric_value + 8));
92 return *this;
93 } else {
94 return *this;
95 }
96 }
97
98 constexpr bool operator==(Color const& other) const
99 {
100 if (m_kind != other.kind())
101 return false;
102
103 switch (m_kind) {
104 case RGB:
105 return m_value.as_rgb == other.as_rgb();
106 case Indexed:
107 return m_value.as_indexed == other.as_indexed();
108 case Named:
109 return m_value.as_named == other.as_named();
110 default:
111 VERIFY_NOT_REACHED();
112 };
113 }
114
115 enum Kind {
116 RGB,
117 Indexed,
118 Named
119 };
120
121 constexpr Kind kind() const
122 {
123 return m_kind;
124 }
125
126private:
127 Kind m_kind;
128
129 union {
130 u32 as_rgb;
131 u8 as_indexed;
132 ANSIColor as_named;
133 } m_value;
134
135 constexpr Color(u32 rgb)
136 : m_kind(Kind::RGB)
137 {
138 m_value.as_rgb = rgb;
139 }
140
141 constexpr Color(u8 index)
142 : m_kind(Kind::Indexed)
143 {
144 m_value.as_indexed = index;
145 }
146
147 constexpr Color(ANSIColor name)
148 : m_kind(Kind::Named)
149 {
150 m_value.as_named = name;
151 }
152};
153}