13 is_terminal_supporting_utf8()
15 const char* clang = std::getenv(
"LANG");
19 const auto lang = std::string(clang);
39 return c ==
' ' ||
c == 0;
56 return connections[
c-1];
63 if(is_terminal_supporting_utf8())
74 TextBox::TextBox() =
default;
101 TextBox::extend_to(
int x,
int y)
109 data[y].resize(x+1,
' ');
119 const std::string&
line
132 tb.put_string(
x,
y,
s);
145 for(
int data_index = 0; data_index <
c_sizet_to_int(
box.data.size()); data_index+=1)
147 const auto line =
box.data[data_index];
148 const auto y = y_start + data_index;
151 extend_to(x_start+size_minus_1,
y);
155 const auto x = x_start + line_index;
156 const auto source_texel =
line[line_index];
160 if(!is_emtpy(source_texel))
162 char& target = data[
y][
x];
163 if(is_emtpy(target) || has_char(source_texel))
165 target = source_texel;
169 if( has_char(target) )
173 target =
static_cast<char>(target | source_texel);
201 while(
end > 0 && is_emtpy(
s[
end - 1]))
208 while(!data.empty() && data.back().empty())
227 for(
const auto&
s: data)
253 for(
int line_index=0; line_index<line_width; line_index+=1)
262 if(line_index>0 || bef)
267 if(aft || (line_index+1)<line_width)
286 for(
int line_index=0; line_index<line_height; line_index+=1)
295 if(line_index>0 || bef)
300 if(aft || (line_index+1)<line_height)
314 int reduce = my_width;
315 for(
int line_index=0; line_index<
box.get_height(); line_index+=1)
317 reduce =
std::min(reduce, find_right_padding(
y+line_index) +
box.find_left_padding(line_index));
320 return my_width - reduce;
333 int reduce = my_height;
334 for(
int box_x=0; box_x<
box.get_width(); box_x+=1)
336 reduce =
std::min(reduce, find_bottom_padding(
x+box_x) +
box.find_top_padding(box_x));
339 return my_height - reduce;
343 std::vector<std::string>
346 std::vector<std::string> ret;
347 bool want_newline =
true;
348 auto last_line = [&ret, &want_newline]() -> std::string&
352 ret.emplace_back(
"");
353 want_newline =
false;
356 return ret[ret.size()-1];
359 auto append = [&](
char c)
377 for(
int y = 0;
y <
h;
y+=1)
379 const std::string&
s = data[
y];
386 for(
auto line_char: str)
403 TextBox::find_left_padding(
int y)
const
412 const std::string&
line = data[y];
425 TextBox::find_right_padding(
int y)
const
434 const std::string&
line = data[
y];
452 TextBox::find_bottom_padding(
int x)
const
462 (x >=
c_sizet_to_int(data[position-1].size()) || is_emtpy(data[position - 1][x]))
474 TextBox::find_top_padding(
int x)
const
482 (x >=
c_sizet_to_int(data[result].size()) || is_emtpy(data[result][x]))
493 TextBox::create_tree_graph_impl
497 const std::vector<TextBox>& boxes,
498 bool consider_oneliner,
499 bool consider_simple,
500 const std::string& label,
505 constexpr
int min_y = 1;
507 const int totalwidth = boxes.empty() ? 0 :
513 [](
auto t,
const auto& b) {return t + b.get_width();}
517 bool oneliner = consider_oneliner &&
519 bool simple = consider_simple && oneliner && boxes.size() == 1;
521 int y = simple ? 0 : 1;
523 for(
auto box_iterator = boxes.begin(); box_iterator != boxes.end(); box_iterator+=1)
525 const TextBox& current_box = *box_iterator;
526 const int usemargin = (simple || oneliner) ? (margin/2) : margin;
527 const auto first_valid_x = result->get_horizontal_append_position(y, current_box);
528 int x = first_valid_x != 0 ? first_valid_x + usemargin
535 if(!oneliner && (x + current_box.get_width() > maxwidth))
546 bool horizontal =
x > firstx;
551 std::next(box_iterator) != boxes.end()
554 const auto& next_box = *std::next(box_iterator);
556 current_box.get_horizontal_append_position(0, next_box) +
560 if(combined_width <= maxwidth)
565 const TextBox combined = current_box.put_box_copy
567 current_box.get_horizontal_append_position(0, next_box) + margin,
573 result->get_vertical_append_position(x, combined),
586 result->get_vertical_append_position(x, current_box),
590 if(horizontal && !simple && !oneliner)
598 std::string(1+x,
'-')
600 if(result->get_horizontal_append_position(y-1, connector) > x)
610 result->get_vertical_append_position(x, current_box),
629 result->put_horizontal_line
644 int cy =
y > min_y ?
y-min_y : 0;
647 result->put_horizontal_line
656 result->put_vertical_line(cx, cy, min_y,
false,
true);
662 result->put_vertical_line(0, 1, 1 + (cy-1),
true,
false);
663 result->put_horizontal_line(0, cy, 1 + (cx-0),
false,
false);
664 result->put_vertical_line(cx, cy, 1,
false,
true);
670 result->put_vertical_line(0,1, 1 + (cy-1),
true,
false);
671 result->put_horizontal_line(0,cy, 1 + (cx-0),
false,
true);
674 result->put_box(x, y, current_box);
std::string to_lower(const std::string &str)
Generate a string containing only lower characters.
std::string from_char_to_string(char c, CharToStringStyle style)
constexpr TextBoxStyle ascii_style
constexpr TextBoxStyle utf8_rounded_style
constexpr unsigned char bit_no_line
constexpr unsigned char bit_down
constexpr unsigned char bit_up
TextBoxStyle get_terminal_style()
constexpr unsigned char bit_right
constexpr unsigned char bit_left
int c_sizet_to_int(size_t t)
bool ends_with(const std::string &str, char c)
size2f min(const size2f lhs, const size2f rhs)
size2f max(const size2f lhs, const size2f rhs)
String utility functions.
std::string_view get_string(char s) const
int get_vertical_append_position(int x, const TextBox &b) const
Calculate the earliest Y coordinate where the given box could be placed without colliding with existi...
void put_box(int x, int y, const TextBox &b)
void mod_char(int x, int y, F &&func)
Modify a character using a callback.
int get_height() const
Calculate the current dimensions of the string.
int get_horizontal_append_position(int y, const TextBox &b) const
Calculate the earliest X coordinate where the given box could be placed.
static TextBox create_empty()
void put_string(int x, int y, const std::string &s)
Put a string of characters starting at the given coordinate.
TextBox put_box_copy(int x, int y, const TextBox &b) const
void put_horizontal_line(int x, int y, int width, bool bef, bool aft)
Draw a horizontal line.
static TextBox create_from_strings(const std::vector< std::string > &str)
void put_char(int x, int y, char c)
Place a single character in the given coordinate.
void trim()
Delete trailing blank from the bottom and right edges.
std::pair< int, int > get_size() const
static TextBox from_string(const std::string &s, int x=0, int y=0)
std::vector< std::string > to_string(const TextBoxStyle &style=get_terminal_style()) const
void put_vertical_line(int x, int y, int height, bool bef, bool aft)
Draw a vertical line.