cpp-terminal 1.0.0
Small C++ library for writing multiplatform terminal applications
Loading...
Searching...
No Matches
window.cpp
Go to the documentation of this file.
1/*
2* cpp-terminal
3* C++ library for writing multi-platform terminal applications.
4*
5* SPDX-FileCopyrightText: 2019-2024 cpp-terminal
6*
7* SPDX-License-Identifier: MIT
8*/
9
11
19#include "cpp-terminal/size.hpp"
22
23namespace Term
24{
25
26Term::Window::Window(const Term::Size& size) : m_size(size) { clear(); }
27
28Term::Window::Window(const Term::Screen& screen) : m_size({screen.rows(), screen.columns()}) { clear(); }
29
30char32_t Term::Window::get_char(const std::size_t& column, const std::size_t& row) { return m_chars[index(column, row)]; }
31
32bool Term::Window::get_fg_reset(const std::size_t& column, const std::size_t& row) { return m_fg_reset[index(column, row)]; }
33
34bool Term::Window::get_bg_reset(const std::size_t& column, const std::size_t& row) { return m_bg_reset[index(column, row)]; }
35
36Term::Color Term::Window::get_fg(const std::size_t& column, const std::size_t& row) { return m_fg[index(column, row)]; }
37
38Term::Color Term::Window::get_bg(const std::size_t& column, const std::size_t& row) { return m_bg[index(column, row)]; }
39
40Term::Style Term::Window::get_style(const std::size_t& column, const std::size_t& row) { return m_style[index(column, row)]; }
41
42const Columns& Term::Window::columns() const noexcept { return m_size.columns(); }
43
44const Rows& Term::Window::rows() const noexcept { return m_size.rows(); }
45
46void Term::Window::set_char(const std::size_t& column, const std::size_t& row, const char32_t& character)
47{
48 if(insideWindow(column, row)) { m_chars[index(column, row)] = character; }
49 else { throw Term::Exception("set_char(): (x,y) out of bounds"); }
50}
51
52void Term::Window::set_fg_reset(const std::size_t& column, const std::size_t& row)
53{
54 m_fg_reset[index(column, row)] = true;
55 m_fg[index(column, row)] = Term::Color::Name::Default;
56}
57
58void Term::Window::set_bg_reset(const std::size_t& column, const std::size_t& row)
59{
60 m_bg_reset[index(column, row)] = true;
61 m_bg[index(column, row)] = Term::Color::Name::Default;
62}
63
64void Term::Window::set_fg(const std::size_t& column, const std::size_t& row, const Color& color)
65{
66 m_fg_reset[index(column, row)] = false;
67 m_fg[index(column, row)] = color;
68}
69
70void Term::Window::set_bg(const std::size_t& column, const std::size_t& row, const Color& color)
71{
72 m_bg_reset[index(column, row)] = false;
73 m_bg[index(column, row)] = color;
74}
75
76void Term::Window::set_style(const std::size_t& column, const std::size_t& row, const Style& style) { m_style[index(column, row)] = style; }
77
78void Term::Window::set_cursor_pos(const std::size_t& column, const std::size_t& row) { m_cursor = {row, column}; }
79
80void Term::Window::set_h(const std::size_t& new_h)
81{
82 if(new_h == m_size.rows()) { return; }
83 if(new_h > m_size.rows())
84 {
85 const std::size_t dc = (new_h - m_size.rows()) * m_size.columns();
86 m_chars.insert(m_chars.end(), dc, ' ');
87 m_fg_reset.insert(m_fg_reset.end(), dc, true);
88 m_bg_reset.insert(m_bg_reset.end(), dc, true);
89 m_fg.insert(m_fg.end(), dc, {0, 0, 0});
90 m_bg.insert(m_bg.end(), dc, {0, 0, 0});
91 m_style.insert(m_style.end(), dc, Style::Reset);
92 m_size = {Term::Columns(m_size.columns()), Term::Rows(new_h)};
93 }
94 else { throw Term::Exception("Shrinking height not supported."); }
95}
96
97void Term::Window::print_str(const std::size_t& x, const std::size_t& y, const std::string& s, const std::size_t& indent, bool move_cursor)
98{
99 std::u32string s2 = Private::utf8_to_utf32(s);
100 std::size_t xpos = x;
101 std::size_t ypos = y;
102 for(char32_t i: s2)
103 {
104 if(i == U'\n')
105 {
106 xpos = x + indent;
107 ypos++;
108 if(insideWindow(xpos, ypos))
109 {
110 for(std::size_t j = 0; j < indent; ++j) { set_char(x + j, ypos, '.'); }
111 }
112 else { return; }
113 }
114 else
115 {
116 if(insideWindow(xpos, ypos)) { set_char(xpos, y, i); }
117 else { return; }
118 ++xpos;
119 }
120 }
121 if(move_cursor) { m_cursor = {ypos, xpos}; }
122}
123
124void Term::Window::fill_fg(const std::size_t& x1, const std::size_t& y1, const std::size_t& x2, const std::size_t& y2, const Color& rgb)
125{
126 for(std::size_t j = y1; j <= y2; ++j)
127 {
128 for(std::size_t i = x1; i <= x2; ++i) { set_fg(i, j, rgb); }
129 }
130}
131
132void Term::Window::fill_bg(const std::size_t& x1, const std::size_t& y1, const std::size_t& x2, const std::size_t& y2, const Color& rgb)
133{
134 for(std::size_t j = y1; j <= y2; ++j)
135 {
136 for(std::size_t i = x1; i <= x2; ++i) { set_bg(i, j, rgb); }
137 }
138}
139
140void Term::Window::fill_style(const std::size_t& x1, const std::size_t& y1, const std::size_t& x2, const std::size_t& y2, const Style& color)
141{
142 for(std::size_t j = y1; j <= y2; ++j)
143 {
144 for(std::size_t i = x1; i <= x2; ++i) { set_style(i, j, color); }
145 }
146}
147
148void Term::Window::print_border() { print_rect(1, 1, m_size.columns(), m_size.rows()); }
149
150void Term::Window::print_rect(const std::size_t& x1, const std::size_t& y1, const std::size_t& x2, const std::size_t& y2)
151{
152 std::u32string border = Private::utf8_to_utf32("│─┌┐└┘");
154 {
155 for(std::size_t j = y1 + 1; j <= (y2 - 1); ++j)
156 {
157 set_char(x1, j, border[0]);
158 set_char(x2, j, border[0]);
159 }
160 for(std::size_t i = x1 + 1; i <= (x2 - 1); ++i)
161 {
162 set_char(i, y1, border[1]);
163 set_char(i, y2, border[1]);
164 }
165 set_char(x1, y1, border[2]);
166 set_char(x2, y1, border[3]);
167 set_char(x1, y2, border[4]);
168 set_char(x2, y2, border[5]);
169 }
170 else
171 {
172 for(std::size_t j = y1 + 1; j <= (y2 - 1); ++j)
173 {
174 set_char(x1, j, '|');
175 set_char(x2, j, '|');
176 }
177 for(std::size_t i = x1 + 1; i <= (x2 - 1); ++i)
178 {
179 set_char(i, y1, '-');
180 set_char(i, y2, '-');
181 }
182 set_char(x1, y1, '+');
183 set_char(x2, y1, '+');
184 set_char(x1, y2, '+');
185 set_char(x2, y2, '+');
186 }
187}
188
190{
191 m_style.assign(m_size.area(), Style::Reset);
192 m_bg_reset.assign(m_size.area(), true);
193 m_bg.assign(m_size.area(), Term::Color::Name::Default);
194 m_fg_reset.assign(m_size.area(), true);
195 m_fg.assign(m_size.area(), Term::Color::Name::Default);
196 m_chars.assign(m_size.area(), ' ');
197}
198
199std::string Term::Window::render(const std::size_t& x0, const std::size_t& y0, bool term)
200{
201 std::string out;
202 if(term) { out.append(cursor_off()); }
205 bool current_fg_reset = true;
206 bool current_bg_reset = true;
207 Style current_style = Style::Reset;
208 for(std::size_t j = 1; j <= m_size.rows(); ++j)
209 {
210 if(term) { out.append(cursor_move(y0 + j - 1, x0)); }
211 for(std::size_t i = 1; i <= m_size.columns(); ++i)
212 {
213 bool update_fg = false;
214 bool update_bg = false;
215 bool update_fg_reset = false;
216 bool update_bg_reset = false;
217 bool update_style = false;
218 if(current_fg_reset != get_fg_reset(i, j))
219 {
220 current_fg_reset = get_fg_reset(i, j);
221 if(current_fg_reset)
222 {
223 update_fg_reset = true;
224 current_fg = {255, 255, 255};
225 }
226 }
227
228 if(current_bg_reset != get_bg_reset(i, j))
229 {
230 current_bg_reset = get_bg_reset(i, j);
231 if(current_bg_reset)
232 {
233 update_bg_reset = true;
234 current_bg = {255, 255, 255};
235 }
236 }
237
238 if(!current_fg_reset)
239 {
240 if(!(current_fg == get_fg(i, j)))
241 {
242 current_fg = get_fg(i, j);
243 update_fg = true;
244 }
245 }
246
247 if(!current_fg_reset)
248 {
249 if(!(current_bg == get_bg(i, j)))
250 {
251 current_bg = get_bg(i, j);
252 update_bg = true;
253 }
254 }
255 if(current_style != get_style(i, j))
256 {
257 current_style = get_style(i, j);
258 update_style = true;
259 if(current_style == Style::Reset)
260 {
261 // style::reset: reset fg and bg colors too, we have to
262 // set them again if they are non-default, but if fg or
263 // bg colors are reset, we do not update them, as
264 // style::reset already did that.
265 update_fg = !current_fg_reset;
266 update_bg = !current_bg_reset;
267 }
268 }
269 // Set style first, as style::reset will reset colors too
270 if(update_style) { out.append(style(get_style(i, j))); }
271 if(update_fg_reset) { out.append(color_fg(Term::Color::Name::Default)); }
272 else if(update_fg)
273 {
274 const Term::Color color_tmp = get_fg(i, j);
275 out.append(color_fg(color_tmp));
276 }
277
278 if(update_bg_reset) { out.append(color_bg(Term::Color::Name::Default)); }
279 else if(update_bg)
280 {
281 const Term::Color color_tmp = get_bg(i, j);
282 out.append(color_bg(color_tmp));
283 }
284 out.append(Private::utf32_to_utf8(get_char(i, j)));
285 }
286 if(j < m_size.rows()) { out.append("\n"); }
287 }
288 if(!current_fg_reset) { out.append(color_fg(Term::Color::Name::Default)); }
289 if(!current_bg_reset) { out.append(color_bg(Term::Color::Name::Default)); }
290 if(current_style != Style::Reset) { out.append(style(Style::Reset)); }
291 if(term)
292 {
293 out.append(cursor_move(y0 + (m_cursor.row() - 1), x0 + (m_cursor.column() - 1)));
294 out.append(cursor_on());
295 }
296 return out;
297}
298
299std::size_t Term::Window::index(const std::size_t& column, const std::size_t& row) const
300{
301 if(!insideWindow(column, row)) { throw Term::Exception("Cursor out of range"); }
302 return ((row - 1) * m_size.columns()) + (column - 1);
303}
304
305bool Term::Window::insideWindow(const std::size_t& column, const std::size_t& row) const { return (column >= 1) && (row >= 1) && (column <= m_size.columns()) && (row <= m_size.rows()); }
306} // namespace Term
@ Default
Use the default terminal color, FG: 39, BG: 49.
const Columns & columns() const noexcept
Definition screen.cpp:16
const Rows & rows() const noexcept
Definition screen.cpp:14
static bool get(const Term::Terminfo::Bool &key)
Definition terminfo.cpp:30
@ UTF8
terminal has UTF-8 activated.
void set_h(const std::size_t &)
Definition window.cpp:80
const Rows & rows() const noexcept
Definition window.cpp:44
void print_str(const std::size_t &column, const std::size_t &, const std::string &, const std::size_t &=0, bool=false)
Definition window.cpp:97
void set_char(const std::size_t &column, const std::size_t &row, const char32_t &character)
Definition window.cpp:46
void print_rect(const std::size_t &column, const std::size_t &, const std::size_t &, const std::size_t &)
Definition window.cpp:150
Term::Color get_fg(const std::size_t &column, const std::size_t &row)
Definition window.cpp:36
void fill_bg(const std::size_t &column, const std::size_t &, const std::size_t &, const std::size_t &, const Color &)
Definition window.cpp:132
const Columns & columns() const noexcept
Definition window.cpp:42
void set_fg(const std::size_t &column, const std::size_t &row, const Color &color)
Definition window.cpp:64
void fill_style(const std::size_t &column, const std::size_t &, const std::size_t &, const std::size_t &, const Style &)
Definition window.cpp:140
void set_bg_reset(const std::size_t &column, const std::size_t &row)
Definition window.cpp:58
std::string render(const std::size_t &, const std::size_t &, bool)
Definition window.cpp:199
Term::Color get_bg(const std::size_t &column, const std::size_t &row)
Definition window.cpp:38
void set_cursor_pos(const std::size_t &column, const std::size_t &row)
Definition window.cpp:78
char32_t get_char(const std::size_t &column, const std::size_t &row)
Definition window.cpp:30
bool get_bg_reset(const std::size_t &column, const std::size_t &row)
Definition window.cpp:34
void set_fg_reset(const std::size_t &column, const std::size_t &row)
Definition window.cpp:52
void fill_fg(const std::size_t &column, const std::size_t &, const std::size_t &, const std::size_t &, const Color &)
Definition window.cpp:124
bool insideWindow(const std::size_t &column, const std::size_t &row) const
Definition window.cpp:305
void set_bg(const std::size_t &column, const std::size_t &row, const Color &color)
Definition window.cpp:70
bool get_fg_reset(const std::size_t &column, const std::size_t &row)
Definition window.cpp:32
void set_style(const std::size_t &column, const std::size_t &row, const Style &style)
Definition window.cpp:76
std::size_t index(const std::size_t &column, const std::size_t &row) const
Definition window.cpp:299
Term::Style get_style(const std::size_t &column, const std::size_t &row)
Definition window.cpp:40
void print_border()
Definition window.cpp:148
Window(const Size &size)
Definition window.cpp:26
void clear()
Definition window.cpp:189
std::string utf32_to_utf8(const char32_t &codepoint, const bool &exception=false)
Encode a codepoint using UTF-8 std::string .
Definition unicode.cpp:55
std::u32string utf8_to_utf32(const std::string &str)
Definition args.cpp:13
std::string color_bg(const Term::Color::Name &name)
Definition color.cpp:79
std::string style(const Term::Style &style)
Definition style.cpp:12
std::string cursor_off()
Definition cursor.cpp:28
Style
Definition style.hpp:24
@ Reset
resets all attributes (styles and colors)
std::string cursor_move(const std::size_t &row, const std::size_t &column)
Definition cursor.cpp:32
std::string cursor_on()
Definition cursor.cpp:30
std::string color_fg(const Term::Color::Name &name)
Definition color.cpp:110