1/* Support for tabular/grid-based content.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#ifndef GCC_TEXT_ART_TABLE_H
22#define GCC_TEXT_ART_TABLE_H
23
24#include "text-art/canvas.h"
25#include "text-art/theme.h"
26
27namespace text_art {
28
29class table;
30class table_geometry;
31
32/* A class representing the content of a particular table cell,
33 or of a span of table cells. */
34
35class table_cell_content
36{
37 public:
38 table_cell_content () : m_str (), m_size (0, 0) {}
39 table_cell_content (styled_string &&s);
40
41 bool operator== (const table_cell_content &other) const
42 {
43 return m_str == other.m_str;
44 }
45
46 canvas::size_t get_canvas_size () const { return m_size; }
47
48 void paint_to_canvas (canvas &canvas,
49 canvas::coord_t top_left) const;
50
51 private:
52 styled_string m_str;
53 canvas::size_t m_size;
54};
55
56/* A list of required sizes of table rows or columns
57 in canvas units (row heights or column widths). */
58
59struct table_dimension_sizes
60{
61 table_dimension_sizes (unsigned num);
62
63 void require (unsigned idx, int amount)
64 {
65 m_requirements[idx] = std::max (a: m_requirements[idx], b: amount);
66 }
67
68 std::vector<int> m_requirements;
69};
70
71/* A 2D grid of cells. Instances of table_cell_content can be assigned
72 to individual table cells, and to rectangular spans of cells. Such
73 assignments do not have to fully cover the 2D grid, but they must not
74 overlap. */
75
76class table
77{
78 public:
79 typedef size<class table> size_t;
80 typedef coord<class table> coord_t;
81 typedef range<class table> range_t;
82 typedef rect<class table> rect_t;
83
84 /* A record of how a table_cell_content was placed at a table::rect_t
85 with a certain alignment. */
86 class cell_placement
87 {
88 public:
89 cell_placement (rect_t rect,
90 table_cell_content &&content,
91 x_align x_align,
92 y_align y_align)
93 : m_rect (rect),
94 m_content (std::move (content)),
95 m_x_align (x_align),
96 m_y_align (y_align)
97 {
98 }
99
100 bool one_by_one_p () const
101 {
102 return m_rect.m_size.w == 1 && m_rect.m_size.h == 1;
103 }
104
105 canvas::size_t get_min_canvas_size () const
106 {
107 // Doesn't include border
108 return m_content.get_canvas_size ();
109 }
110
111 void paint_cell_contents_to_canvas(canvas &canvas,
112 canvas::coord_t offset,
113 const table_geometry &tg) const;
114
115 const table_cell_content &get_content () const { return m_content; }
116
117 private:
118 friend class table;
119 friend class table_cell_sizes;
120 rect_t m_rect;
121 table_cell_content m_content;
122 x_align m_x_align;
123 y_align m_y_align;
124 };
125
126 table (size_t size);
127 ~table () = default;
128 table (table &&) = default;
129 table (const table &) = delete;
130 table &operator= (const table &) = delete;
131
132 const size_t &get_size () const { return m_size; }
133
134 int add_rows (unsigned num)
135 {
136 int topmost_new_row = m_size.h;
137 m_size.h += num;
138 for (unsigned i = 0; i < num; i++)
139 m_occupancy.add_row (element: -1);
140 return topmost_new_row;
141 }
142
143 int add_row ()
144 {
145 return add_rows (num: 1);
146 }
147
148 void set_cell (coord_t coord,
149 table_cell_content &&content,
150 enum x_align x_align = x_align::CENTER,
151 enum y_align y_align = y_align::CENTER);
152
153 void set_cell_span (rect_t span,
154 table_cell_content &&content,
155 enum x_align x_align = x_align::CENTER,
156 enum y_align y_align = y_align::CENTER);
157
158 void maybe_set_cell_span (rect_t span,
159 table_cell_content &&content,
160 enum x_align x_align = x_align::CENTER,
161 enum y_align y_align = y_align::CENTER);
162
163 canvas to_canvas (const theme &theme, const style_manager &sm) const;
164
165 void paint_to_canvas(canvas &canvas,
166 canvas::coord_t offset,
167 const table_geometry &tg,
168 const theme &theme) const;
169
170 void debug () const;
171
172 void add_other_table (table &&other, table::coord_t offset);
173
174 /* Self-test support. */
175 const cell_placement *get_placement_at (coord_t coord) const;
176
177 private:
178 int get_occupancy_safe (coord_t coord) const;
179 directions get_connections (int table_x, int table_y) const;
180 void paint_cell_borders_to_canvas(canvas &canvas,
181 canvas::coord_t offset,
182 const table_geometry &tg,
183 const theme &theme) const;
184 void paint_cell_contents_to_canvas(canvas &canvas,
185 canvas::coord_t offset,
186 const table_geometry &tg) const;
187
188 friend class table_cell_sizes;
189
190 size_t m_size;
191 std::vector<cell_placement> m_placements;
192 array2<int, size_t, coord_t> m_occupancy; /* indices into the m_placements vec. */
193};
194
195/* A workspace for computing the row heights and column widths
196 of a table (in canvas units).
197 The col_widths and row_heights could be shared between multiple
198 instances, for aligning multiple tables vertically or horizontally. */
199
200class table_cell_sizes
201{
202 public:
203 table_cell_sizes (table_dimension_sizes &col_widths,
204 table_dimension_sizes &row_heights)
205 : m_col_widths (col_widths),
206 m_row_heights (row_heights)
207 {
208 }
209
210 void pass_1 (const table &table);
211 void pass_2 (const table &table);
212
213 canvas::size_t get_canvas_size (const table::rect_t &rect) const;
214
215 table_dimension_sizes &m_col_widths;
216 table_dimension_sizes &m_row_heights;
217};
218
219/* A class responsible for mapping from table cell coords
220 to canvas coords, handling column widths.
221 It's the result of solving "how big are all the table cells and where
222 do they go?"
223 The cell_sizes are passed in, for handling aligning multiple tables,
224 sharing column widths or row heights. */
225
226class table_geometry
227{
228 public:
229 table_geometry (const table &table, table_cell_sizes &cell_sizes);
230
231 void recalc_coords ();
232
233 const canvas::size_t get_canvas_size () const { return m_canvas_size; }
234
235 canvas::coord_t table_to_canvas (table::coord_t table_coord) const;
236 int table_x_to_canvas_x (int table_x) const;
237 int table_y_to_canvas_y (int table_y) const;
238
239 int get_col_width (int table_x) const
240 {
241 return m_cell_sizes.m_col_widths.m_requirements[table_x];
242 }
243
244 canvas::size_t get_canvas_size (const table::rect_t &rect) const
245 {
246 return m_cell_sizes.get_canvas_size (rect);
247 }
248
249 private:
250 table_cell_sizes &m_cell_sizes;
251 canvas::size_t m_canvas_size;
252
253 /* Start canvas column of table cell, including leading border. */
254 std::vector<int> m_col_start_x;
255
256 /* Start canvas row of table cell, including leading border. */
257 std::vector<int> m_row_start_y;
258};
259
260/* Helper class for handling the simple case of a single table
261 that doesn't need to be aligned with respect to anything else. */
262
263struct simple_table_geometry
264{
265 simple_table_geometry (const table &table);
266
267 table_dimension_sizes m_col_widths;
268 table_dimension_sizes m_row_heights;
269 table_cell_sizes m_cell_sizes;
270 table_geometry m_tg;
271};
272
273} // namespace text_art
274
275#endif /* GCC_TEXT_ART_TABLE_H */
276

source code of gcc/text-art/table.h