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