Euphoria
textbox.h
Go to the documentation of this file.
1 #pragma once
2 
3 
4 #include <array>
5 #include <algorithm>
6 #include <functional>
7 
8 #include "assert/assert.h"
9 
10 namespace eu::core
11 {
12  // bitmasks
13  constexpr unsigned char bit_up = 1 << 0;
14  constexpr unsigned char bit_down = 1 << 1;
15  constexpr unsigned char bit_left = 1 << 2;
16  constexpr unsigned char bit_right = 1 << 3;
17  constexpr unsigned char bit_no_line = static_cast<unsigned char>(~(bit_up | bit_down | bit_left | bit_right));
18 
19  struct TextBoxStyle
20  {
21  template<typename F>
22  constexpr explicit TextBoxStyle(F connections_func)
23  {
24  for (char connection_index = 0; connection_index < 15; connection_index += 1)
25  {
26  connections[connection_index] = connections_func(static_cast<char>(connection_index + 1));
27  }
28  }
29 
30  [[nodiscard]] std::string_view get_string(char s) const;
31 
32  private:
33  std::array<std::string_view, 15> connections;
34 
35  constexpr TextBoxStyle() = default;
36  };
37 
38  TextBoxStyle get_terminal_style();
39 
41  switch (c)
42  {
43  case bit_left:
44  case bit_right:
45  case bit_left | bit_right: return "─";
46  case bit_up:
47  case bit_down:
48  case bit_up | bit_down: return "│";
49  case bit_left | bit_up: return "┘";
50  case bit_left | bit_down: return "┐";
51  case bit_right | bit_up: return "└";
52  case bit_right | bit_down: return "┌";
53  case bit_left | bit_right | bit_up: return "┴";
54  case bit_left | bit_right | bit_down: return "┬";
55  case bit_left | bit_up | bit_down: return "┤";
56  case bit_right | bit_up | bit_down: return "├";
57  case bit_left | bit_right | bit_up | bit_down: return "┼";
58  default:
59  DIE("Invalid combination");
60  return "X";
61  }
62  }};
63 
65  switch (c)
66  {
67  case bit_left:
68  case bit_right:
69  case bit_left | bit_right: return "─";
70  case bit_up:
71  case bit_down:
72  case bit_up | bit_down: return "│";
73  case bit_left | bit_up: return "╯";
74  case bit_left | bit_down: return "╮";
75  case bit_right | bit_up: return "╰";
76  case bit_right | bit_down: return "╭";
77  case bit_left | bit_right | bit_up: return "┴";
78  case bit_left | bit_right | bit_down: return "┬";
79  case bit_left | bit_up | bit_down: return "┤";
80  case bit_right | bit_up | bit_down: return "├";
81  case bit_left | bit_right | bit_up | bit_down: return "┼";
82  default:
83  DIE("Invalid combination");
84  return "X";
85  }
86  }};
87 
89  switch (c)
90  {
91  case bit_left:
92  case bit_right:
93  case bit_left | bit_right: return "═";
94  case bit_up:
95  case bit_down:
96  case bit_up | bit_down: return "║";
97  case bit_left | bit_up: return "╝";
98  case bit_left | bit_down: return "╗";
99  case bit_right | bit_up: return "╚";
100  case bit_right | bit_down: return "╔";
101  case bit_left | bit_right | bit_up: return "╩";
102  case bit_left | bit_right | bit_down: return "╦";
103  case bit_left | bit_up | bit_down: return "╣";
104  case bit_right | bit_up | bit_down: return "╠";
105  case bit_left | bit_right | bit_up | bit_down: return "╬";
106  default:
107  DIE("Invalid combination");
108  return "X";
109  }
110  }};
111 
112  constexpr TextBoxStyle ascii_style = TextBoxStyle { [](char c) {
113  switch (c)
114  {
115  case bit_left:
116  case bit_right:
117  case bit_left | bit_right: return "-";
118  case bit_up:
119  case bit_down:
120  case bit_up | bit_down: return "|";
121  case bit_left | bit_up: return "'";
122  case bit_left | bit_down: return ".";
123  case bit_right | bit_up: return "`";
124  case bit_right | bit_down: return ",";
125  case bit_left | bit_right | bit_up:
126  case bit_left | bit_right | bit_down:
127  case bit_left | bit_up | bit_down:
128  case bit_right | bit_up | bit_down:
129  case bit_left | bit_right | bit_up | bit_down: return "+";
130  default:
131  DIE("Invalid combination");
132  return "X";
133  }
134  }};
135 
136  /* TextBox: Abstraction for 2-dimensional text strings with linedrawing support
137  Copyright (c) 2017 Joel Yliluoma - http://iki.fi/bisqwit/
138  License: MIT
139  https://gist.github.com/bisqwit/458048c60d271ab2536665cb81595c6b
140  */
141  // todo(Gustav): change to allow origin and negative drawing indices
142  struct TextBox
143  {
144  static TextBox create_empty();
145  static TextBox create_from_strings(const std::vector<std::string>& str);
146  static TextBox from_string(const std::string& s, int x = 0, int y = 0);
147 
204  template
205  <
206  typename T,
207  typename TToStringFunc,
208  typename TCountChildrenFunc,
209  typename TOneLinerTestFunc,
210  typename TSimpleTestFunc
211  >
212  static TextBox
214  (
215  const T& e,
216  int maxwidth,
217  TToStringFunc&& to_string,
218  TCountChildrenFunc&& count_children_func,
219  TOneLinerTestFunc&& oneliner_test_func,
220  TSimpleTestFunc&& simple_test_func,
221  int margin = 4,
222  int firstx = 2
223  )
224  {
225  ASSERTX(maxwidth >=16, maxwidth);
226 
227  const auto label = to_string(e);
228  auto result = TextBox::from_string(label);
229 
230  if(auto [begin, end] = count_children_func(e); begin != end)
231  {
232  std::vector<TextBox> boxes;
233  boxes.reserve(std::distance(begin, end));
234  for(auto child_iterator = begin; child_iterator != end; ++child_iterator)
235  {
236  boxes.emplace_back
237  (
239  (
240  *child_iterator,
241  std::max<int>(maxwidth - 2, 16),
242  to_string,
243  count_children_func,
244  oneliner_test_func,
245  simple_test_func,
246  margin,
247  firstx
248  )
249  );
250  }
251  create_tree_graph_impl
252  (
253  &result,
254  maxwidth,
255  boxes,
256  oneliner_test_func(e),
257  simple_test_func(e),
258  label,
259  margin,
260  firstx
261  );
262  }
263  result.trim();
264  return result;
265  }
266 
268  // Drawing functions
269 
272  void put_char(int x, int y, char c);
273 
275  template<typename F>
276  void mod_char(int x, int y, F&& func)
277  {
278  extend_to(x,y);
279  func(data[y][x]);
280  }
281 
286  void put_string(int x, int y, const std::string& s);
287 
288  /* Put a 2D string starting at the given coordinate */
289  void put_box(int x, int y, const TextBox& b);
290 
295  (
296  int x,
297  int y,
298  int width,
299  bool bef,
300  bool aft
301  );
302 
306  void put_vertical_line
307  (
308  int x,
309  int y,
310  int height,
311  bool bef,
312  bool aft
313  );
314 
316  void trim();
317 
318 
319 
320  [[nodiscard]] TextBox put_box_copy(int x, int y, const TextBox& b) const;
321  [[nodiscard]] std::vector<std::string> to_string(const TextBoxStyle& style = get_terminal_style()) const;
322 
327  [[nodiscard]] int get_horizontal_append_position(int y, const TextBox& b) const;
328 
332  [[nodiscard]] int get_vertical_append_position(int x, const TextBox& b) const;
333 
335  [[nodiscard]] int get_height() const;
336 
337  [[nodiscard]] int get_width() const;
338 
340  [[nodiscard]] std::pair<int, int> get_size() const;
341 
342  private:
343  std::vector<std::string> data;
344 
345  TextBox();
346 
347  void extend_to(int x, int y);
348 
349  [[nodiscard]] int find_left_padding(int y) const;
350  [[nodiscard]] int find_right_padding(int y) const;
351  [[nodiscard]] int find_top_padding(int x) const;
352  [[nodiscard]] int find_bottom_padding(int x) const;
353 
354  static void create_tree_graph_impl
355  (
356  TextBox* result,
357  int maxwidth,
358  const std::vector<TextBox>& boxes,
359  bool oneliner_test_func,
360  bool simple_test_func,
361  const std::string& label,
362  int margin,
363  int firstx
364  );
365  };
366 }
#define ASSERTX(x,...)
Definition: assert.h:48
#define DIE(message)
Definition: assert.h:67
constexpr TextBoxStyle utf_8double_line_style
Definition: textbox.h:88
constexpr TextBoxStyle ascii_style
Definition: textbox.h:112
constexpr TextBoxStyle utf8_straight_style
Definition: textbox.h:40
constexpr TextBoxStyle utf8_rounded_style
Definition: textbox.h:64
constexpr unsigned char bit_no_line
Definition: textbox.h:17
constexpr unsigned char bit_down
Definition: textbox.h:14
constexpr unsigned char bit_up
Definition: textbox.h:13
TextBoxStyle get_terminal_style()
Definition: textbox.cc:61
constexpr unsigned char bit_right
Definition: textbox.h:16
constexpr unsigned char bit_left
Definition: textbox.h:15
constexpr TextBoxStyle(F connections_func)
Definition: textbox.h:22
std::string_view get_string(char s) const
Definition: textbox.cc:47
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...
Definition: textbox.cc:326
void put_box(int x, int y, const TextBox &b)
Definition: textbox.cc:139
void mod_char(int x, int y, F &&func)
Modify a character using a callback.
Definition: textbox.h:276
int get_height() const
Calculate the current dimensions of the string.
Definition: textbox.cc:216
int get_horizontal_append_position(int y, const TextBox &b) const
Calculate the earliest X coordinate where the given box could be placed.
Definition: textbox.cc:310
static TextBox create_empty()
Definition: textbox.cc:77
int get_width() const
Definition: textbox.cc:223
void put_string(int x, int y, const std::string &s)
Put a string of characters starting at the given coordinate.
Definition: textbox.cc:116
TextBox put_box_copy(int x, int y, const TextBox &b) const
Definition: textbox.cc:183
static TextBox create_tree_graph(const T &e, int maxwidth, TToStringFunc &&to_string, TCountChildrenFunc &&count_children_func, TOneLinerTestFunc &&oneliner_test_func, TSimpleTestFunc &&simple_test_func, int margin=4, int firstx=2)
An utility function that can be used to create a tree graph rendering from a structure.
Definition: textbox.h:214
void put_horizontal_line(int x, int y, int width, bool bef, bool aft)
Draw a horizontal line.
Definition: textbox.cc:245
static TextBox create_from_strings(const std::vector< std::string > &str)
Definition: textbox.cc:84
void put_char(int x, int y, char c)
Place a single character in the given coordinate.
Definition: textbox.cc:93
void trim()
Delete trailing blank from the bottom and right edges.
Definition: textbox.cc:196
std::pair< int, int > get_size() const
Definition: textbox.cc:237
static TextBox from_string(const std::string &s, int x=0, int y=0)
Definition: textbox.cc:129
std::vector< std::string > to_string(const TextBoxStyle &style=get_terminal_style()) const
Definition: textbox.cc:344
void put_vertical_line(int x, int y, int height, bool bef, bool aft)
Draw a vertical line.
Definition: textbox.cc:278