1 #ifndef CPPURSES_PAINTER_GLYPH_STRING_HPP
2 #define CPPURSES_PAINTER_GLYPH_STRING_HPP
3 #include <codecvt>
4 #include <initializer_list>
5 #include <locale>
6 #include <memory>
7 #include <ostream>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include <cppurses/painter/attribute.hpp>
13 #include <cppurses/painter/glyph.hpp>
14 #include <cppurses/painter/utility/wchar_to_bytes.hpp>
15
16 namespace cppurses {
17
18 /// Holds a collection of Glyphs with a similar interface to std::string.
19 class Glyph_string : private std::vector<Glyph> {
20 public:
21 /// Default constructs an empty Glyph_string.
22 Glyph_string() = default;
23
24 /// Used to indicate 'Until the end of the string'.
25 static const std::size_t npos = -1;
26
27 /// Construct with iterators from any container providing Input Iterators.
28 template <typename InputIterator>
29 Glyph_string(InputIterator first, InputIterator last);
30
31 /// Construct with \p symbols, each having given Attributes applied to them.
32 template <typename... Attributes>
33 Glyph_string(const std::string& symbols, Attributes&&... attrs);
34
35 /// Construct with \p symbols, each having given Attributes applied to them.
36 template <typename... Attributes>
37 Glyph_string(const char* symbols, Attributes&&... attrs);
38
39 /// Construct with \p symbol, having given Attributes applied to it.
40 template <typename... Attributes>
41 Glyph_string(wchar_t symbol, Attributes&&... attrs);
42
43 /// Construct with \p symbols, each having given Attributes applied to them.
44 template <typename... Attributes>
45 Glyph_string(const wchar_t* symbols, Attributes&&... attrs);
46
47 /// Construct with \p symbols, each having given Attributes applied to them.
48 template <typename... Attributes>
49 Glyph_string(const std::wstring& symbols, Attributes&&... attrs);
50
51 /// Construct with \p glyph, adding given Attributes to it.
52 template <typename... Attributes>
53 Glyph_string(const Glyph& glyph, Attributes&&... attrs);
54
55 /// Construct with a std::initializer_list of Glyphs, with \p attrs applied.
56 template <typename... Attributes>
57 Glyph_string(const std::initializer_list<Glyph>& glyphs,
58 Attributes&&... attrs);
59
60 Glyph_string& operator=(const Glyph_string&) = default;
61
62 /// Convert to a std::string, each Glyph being a char.
str() const63 std::string str() const { return utility::wchar_to_bytes(this->w_str()); }
64
65 /// Convert to a std::wstring, each Glyph being a wchar_t.
66 std::wstring w_str() const;
67
68 /// Return the length in Glyphs of the Glyph_string.
length() const69 size_type length() const { return this->size(); }
70
71 /// Compound concatenation assignment operator to append a Glyph.
operator +=(const Glyph & glyph)72 Glyph_string& operator+=(const Glyph& glyph) { return this->append(glyph); }
73
74 /// Concatenation operator to append a Glyph_string.
75 Glyph_string operator+(const Glyph_string& gs) const;
76
77 /// Append single Glyph to the end of the Glyph_string w/given Attributes.
78 template <typename... Attributes>
79 Glyph_string& append(const Glyph& symbol, Attributes&&... attrs);
80
81 /// Append a c-string with given Attributes to the end of the Glyph_string.
82 template <typename... Attributes>
83 Glyph_string& append(const char* symbols, Attributes&&... attrs);
84
85 /// Append std::string with given Attributes to the end of the Glyph_string.
86 template <typename... Attributes>
87 Glyph_string& append(const std::string& symbols, Attributes&&... attrs);
88
89 /// Append a wide c-string with given Attributes to the end of Glyph_string.
90 template <typename... Attributes>
91 Glyph_string& append(const wchar_t* symbols, Attributes&&... attrs);
92
93 /// Append std::wstring with given Attributes to the end of Glyph_string.
94 template <typename... Attributes>
95 Glyph_string& append(const std::wstring& symbols, Attributes&&... attrs);
96
97 /// Append another Glyph_string with Attributes to the end of Glyph_string.
98 template <typename... Attributes>
99 Glyph_string& append(const Glyph_string& gs, Attributes&&... attrs);
100
101 /// Add a list of Attributes to every Glyph within the Glyph_string.
102 template <typename... Attributes>
103 void add_attributes(Attributes&&... attrs);
104
105 /// Remove a single Attribute from every Glyph within the Glyph_string.
106 void remove_attribute(Attribute attr);
107
108 // Import member functions from std::vector<Glyph>
109 using std::vector<Glyph>::value_type;
110 using std::vector<Glyph>::allocator_type;
111 using std::vector<Glyph>::size_type;
112 using std::vector<Glyph>::difference_type;
113 using std::vector<Glyph>::reference;
114 using std::vector<Glyph>::const_reference;
115 using std::vector<Glyph>::pointer;
116 using std::vector<Glyph>::const_pointer;
117 using std::vector<Glyph>::iterator;
118 using std::vector<Glyph>::const_iterator;
119 using std::vector<Glyph>::reverse_iterator;
120 using std::vector<Glyph>::const_reverse_iterator;
121
122 using std::vector<Glyph>::operator[];
123 using std::vector<Glyph>::size;
124 using std::vector<Glyph>::assign;
125 using std::vector<Glyph>::get_allocator;
126 using std::vector<Glyph>::at;
127 using std::vector<Glyph>::front;
128 using std::vector<Glyph>::back;
129 using std::vector<Glyph>::data;
130 using std::vector<Glyph>::begin;
131 using std::vector<Glyph>::cbegin;
132 using std::vector<Glyph>::end;
133 using std::vector<Glyph>::cend;
134 using std::vector<Glyph>::rbegin;
135 using std::vector<Glyph>::crbegin;
136 using std::vector<Glyph>::rend;
137 using std::vector<Glyph>::crend;
138 using std::vector<Glyph>::empty;
139 using std::vector<Glyph>::max_size;
140 using std::vector<Glyph>::reserve;
141 using std::vector<Glyph>::capacity;
142 using std::vector<Glyph>::shrink_to_fit;
143 using std::vector<Glyph>::clear;
144 using std::vector<Glyph>::insert;
145 using std::vector<Glyph>::erase;
146 using std::vector<Glyph>::push_back;
147 using std::vector<Glyph>::pop_back;
148 using std::vector<Glyph>::resize;
149 using std::vector<Glyph>::swap;
150 };
151
152 /// Equality comparison on each Glyph in the Glyph_strings.
153 bool operator==(const Glyph_string& x, const Glyph_string& y);
154
155 /// Inequality comparison on each Glyph in the Glyph_strings.
operator !=(const Glyph_string & x,const Glyph_string & y)156 inline bool operator!=(const Glyph_string& x, const Glyph_string& y) {
157 return !(x == y);
158 }
159
160 /// stream output operator for Glyph_string, outputs the Glyphs as chars to os.
operator <<(std::ostream & os,const Glyph_string & gs)161 inline std::ostream& operator<<(std::ostream& os, const Glyph_string& gs) {
162 return os << gs.str();
163 }
164
165 // TEMPLATE IMPLEMENTATIONS
166 template <typename InputIterator>
Glyph_string(InputIterator first,InputIterator last)167 Glyph_string::Glyph_string(InputIterator first, InputIterator last)
168 : vector<Glyph>::vector(first, last) {}
169
170 template <typename... Attributes>
Glyph_string(const std::string & symbols,Attributes &&...attrs)171 Glyph_string::Glyph_string(const std::string& symbols, Attributes&&... attrs)
172 : vector<Glyph>::vector() {
173 this->append(symbols, std::forward<Attributes>(attrs)...);
174 }
175
176 template <typename... Attributes>
Glyph_string(const char * symbols,Attributes &&...attrs)177 Glyph_string::Glyph_string(const char* symbols, Attributes&&... attrs) {
178 this->append(symbols, std::forward<Attributes>(attrs)...);
179 }
180
181 template <typename... Attributes>
Glyph_string(wchar_t symbol,Attributes &&...attrs)182 Glyph_string::Glyph_string(wchar_t symbol, Attributes&&... attrs) {
183 this->append(Glyph{symbol, std::forward<Attributes>(attrs)...});
184 }
185
186 template <typename... Attributes>
Glyph_string(const wchar_t * symbols,Attributes &&...attrs)187 Glyph_string::Glyph_string(const wchar_t* symbols, Attributes&&... attrs) {
188 this->append(symbols, std::forward<Attributes>(attrs)...);
189 }
190
191 template <typename... Attributes>
Glyph_string(const std::wstring & symbols,Attributes &&...attrs)192 Glyph_string::Glyph_string(const std::wstring& symbols, Attributes&&... attrs)
193 : vector<Glyph>::vector() {
194 this->append(symbols, std::forward<Attributes>(attrs)...);
195 }
196
197 template <typename... Attributes>
Glyph_string(const Glyph & glyph,Attributes &&...attrs)198 Glyph_string::Glyph_string(const Glyph& glyph, Attributes&&... attrs) {
199 this->append(glyph, std::forward<Attributes>(attrs)...);
200 }
201
202 template <typename... Attributes>
Glyph_string(const std::initializer_list<Glyph> & glyphs,Attributes &&...attrs)203 Glyph_string::Glyph_string(const std::initializer_list<Glyph>& glyphs,
204 Attributes&&... attrs) {
205 this->reserve(glyphs.size());
206 for (const Glyph& g : glyphs) {
207 this->append(g, std::forward<Attributes>(attrs)...);
208 }
209 }
210
211 template <typename... Attributes>
append(const Glyph & symbol,Attributes &&...attrs)212 Glyph_string& Glyph_string::append(const Glyph& symbol, Attributes&&... attrs) {
213 this->push_back(symbol);
214 this->back().brush.add_attributes(std::forward<Attributes>(attrs)...);
215 return *this;
216 }
217
218 template <typename... Attributes>
append(const char * symbols,Attributes &&...attrs)219 Glyph_string& Glyph_string::append(const char* symbols, Attributes&&... attrs) {
220 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
221 std::wstring wide_string{converter.from_bytes(symbols)};
222 this->reserve(this->size() + wide_string.size());
223 for (wchar_t sym : wide_string) {
224 this->append(Glyph{sym, std::forward<Attributes>(attrs)...});
225 }
226 return *this;
227 }
228
229 template <typename... Attributes>
append(const std::string & symbols,Attributes &&...attrs)230 Glyph_string& Glyph_string::append(const std::string& symbols,
231 Attributes&&... attrs) {
232 return this->append(symbols.c_str(), std::forward<Attributes>(attrs)...);
233 }
234
235 template <typename... Attributes>
append(const wchar_t * symbols,Attributes &&...attrs)236 Glyph_string& Glyph_string::append(const wchar_t* symbols,
237 Attributes&&... attrs) {
238 for (auto i = std::size_t{0}; symbols[i] != L'\0'; ++i) {
239 this->append(Glyph{symbols[i], std::forward<Attributes>(attrs)...});
240 }
241 return *this;
242 }
243
244 template <typename... Attributes>
append(const std::wstring & symbols,Attributes &&...attrs)245 Glyph_string& Glyph_string::append(const std::wstring& symbols,
246 Attributes&&... attrs) {
247 for (wchar_t sym : symbols) {
248 this->append(Glyph{sym, std::forward<Attributes>(attrs)...});
249 }
250 return *this;
251 }
252
253 template <typename... Attributes>
append(const Glyph_string & gs,Attributes &&...attrs)254 Glyph_string& Glyph_string::append(const Glyph_string& gs,
255 Attributes&&... attrs) {
256 for (const Glyph& glyph : gs) {
257 this->append(glyph, std::forward<Attributes>(attrs)...);
258 }
259 return *this;
260 }
261
262 template <typename... Attributes>
add_attributes(Attributes &&...attrs)263 void Glyph_string::add_attributes(Attributes&&... attrs) {
264 for (auto& glyph : *this) {
265 glyph.brush.add_attributes(std::forward<Attributes>(attrs)...);
266 }
267 }
268
269 } // namespace cppurses
270 #endif // CPPURSES_PAINTER_GLYPH_STRING_HPP
271