1 | /* Hierarchical diagram elements. |
2 | Copyright (C) 2023-2024 Free Software Foundation, Inc. |
3 | Contributed by David Malcolm <dmalcolm@redhat.com>. |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #include "config.h" |
22 | #define INCLUDE_MEMORY |
23 | #define INCLUDE_VECTOR |
24 | #include "system.h" |
25 | #include "coretypes.h" |
26 | #include "pretty-print.h" |
27 | #include "selftest.h" |
28 | #include "make-unique.h" |
29 | #include "text-art/selftests.h" |
30 | #include "text-art/widget.h" |
31 | |
32 | using namespace text_art; |
33 | |
34 | /* class text_art::widget. */ |
35 | |
36 | canvas |
37 | widget::to_canvas (const style_manager &style_mgr) |
38 | { |
39 | const canvas::size_t req_size = get_req_size (); |
40 | |
41 | /* For now we don't constrain the allocation; we give |
42 | the widget the full size it requested, and widgets |
43 | assume they got their full size request. */ |
44 | const canvas::size_t alloc_size = req_size; |
45 | |
46 | set_alloc_rect (canvas::rect_t (canvas::coord_t (0, 0), alloc_size)); |
47 | canvas c (alloc_size, style_mgr); |
48 | paint_to_canvas (canvas&: c); |
49 | return c; |
50 | } |
51 | |
52 | /* class text_art::vbox_widget : public text_art::container_widget. */ |
53 | |
54 | const char * |
55 | vbox_widget::get_desc () const |
56 | { |
57 | return "vbox_widget" ; |
58 | } |
59 | |
60 | canvas::size_t |
61 | vbox_widget::calc_req_size () |
62 | { |
63 | canvas::size_t result (0, 0); |
64 | for (auto &child : m_children) |
65 | { |
66 | canvas::size_t child_req_size = child->get_req_size(); |
67 | result.h += child_req_size.h; |
68 | result.w = std::max (a: result.w, b: child_req_size.w); |
69 | } |
70 | return result; |
71 | } |
72 | |
73 | void |
74 | vbox_widget::update_child_alloc_rects () |
75 | { |
76 | const int x = get_min_x (); |
77 | int y = get_min_y (); |
78 | for (auto &child : m_children) |
79 | { |
80 | child->set_alloc_rect |
81 | (canvas::rect_t (canvas::coord_t (x, y), |
82 | canvas::size_t (get_alloc_w (), |
83 | child->get_req_h ()))); |
84 | y += child->get_req_h (); |
85 | } |
86 | } |
87 | |
88 | /* class text_art::text_widget : public text_art::leaf_widget. */ |
89 | |
90 | const char * |
91 | text_widget::get_desc () const |
92 | { |
93 | return "text_widget" ; |
94 | } |
95 | |
96 | canvas::size_t |
97 | text_widget::calc_req_size () |
98 | { |
99 | return canvas::size_t (m_str.size (), 1); |
100 | } |
101 | |
102 | void |
103 | text_widget::paint_to_canvas (canvas &canvas) |
104 | { |
105 | canvas.paint_text (coord: get_top_left (), text: m_str); |
106 | } |
107 | |
108 | /* class text_art::canvas_widget : public text_art::leaf_widget. */ |
109 | |
110 | const char * |
111 | canvas_widget::get_desc () const |
112 | { |
113 | return "canvas_widget" ; |
114 | } |
115 | |
116 | canvas::size_t |
117 | canvas_widget::calc_req_size () |
118 | { |
119 | return m_canvas.get_size (); |
120 | } |
121 | |
122 | void |
123 | canvas_widget::paint_to_canvas (canvas &canvas) |
124 | { |
125 | for (int y = 0; y < m_canvas.get_size ().h; y++) |
126 | for (int x = 0; x < m_canvas.get_size ().w; x++) |
127 | { |
128 | canvas::coord_t rel_xy (x, y); |
129 | canvas.paint (coord: get_top_left () + rel_xy, |
130 | c: m_canvas.get (coord: rel_xy)); |
131 | } |
132 | } |
133 | |
134 | #if CHECKING_P |
135 | |
136 | namespace selftest { |
137 | |
138 | /* Concrete widget subclass for writing selftests. |
139 | Requests a hard-coded size, and fills its allocated rectangle |
140 | with a specific character. */ |
141 | |
142 | class test_widget : public leaf_widget |
143 | { |
144 | public: |
145 | test_widget (canvas::size_t size, char ch) |
146 | : m_test_size (size), m_ch (ch) |
147 | {} |
148 | |
149 | const char *get_desc () const final override |
150 | { |
151 | return "test_widget" ; |
152 | } |
153 | canvas::size_t calc_req_size () final override |
154 | { |
155 | return m_test_size; |
156 | } |
157 | void paint_to_canvas (canvas &canvas) final override |
158 | { |
159 | canvas.fill (rect: get_alloc_rect (), c: canvas::cell_t (m_ch)); |
160 | } |
161 | |
162 | private: |
163 | canvas::size_t m_test_size; |
164 | char m_ch; |
165 | }; |
166 | |
167 | static void |
168 | test_test_widget () |
169 | { |
170 | style_manager sm; |
171 | test_widget w (canvas::size_t (3, 3), 'A'); |
172 | canvas c (w.to_canvas (style_mgr: sm)); |
173 | ASSERT_CANVAS_STREQ |
174 | (c, false, |
175 | ("AAA\n" |
176 | "AAA\n" |
177 | "AAA\n" )); |
178 | } |
179 | |
180 | static void |
181 | test_text_widget () |
182 | { |
183 | style_manager sm; |
184 | text_widget w (styled_string (sm, "hello world" )); |
185 | canvas c (w.to_canvas (style_mgr: sm)); |
186 | ASSERT_CANVAS_STREQ |
187 | (c, false, |
188 | ("hello world\n" )); |
189 | } |
190 | |
191 | static void |
192 | test_wrapper_widget () |
193 | { |
194 | style_manager sm; |
195 | wrapper_widget w (::make_unique<test_widget> (args: canvas::size_t (3, 3), args: 'B')); |
196 | canvas c (w.to_canvas (style_mgr: sm)); |
197 | ASSERT_CANVAS_STREQ |
198 | (c, false, |
199 | ("BBB\n" |
200 | "BBB\n" |
201 | "BBB\n" )); |
202 | } |
203 | |
204 | static void |
205 | test_vbox_1 () |
206 | { |
207 | style_manager sm; |
208 | vbox_widget w; |
209 | for (int i = 0; i < 5; i++) |
210 | w.add_child |
211 | (child: ::make_unique <text_widget> |
212 | (args: styled_string::from_fmt (sm, format_decoder: nullptr, |
213 | fmt: "this is line %i" , i))); |
214 | canvas c (w.to_canvas (style_mgr: sm)); |
215 | ASSERT_CANVAS_STREQ |
216 | (c, false, |
217 | ("this is line 0\n" |
218 | "this is line 1\n" |
219 | "this is line 2\n" |
220 | "this is line 3\n" |
221 | "this is line 4\n" )); |
222 | } |
223 | |
224 | static void |
225 | test_vbox_2 () |
226 | { |
227 | style_manager sm; |
228 | vbox_widget w; |
229 | w.add_child (child: ::make_unique<test_widget> (args: canvas::size_t (1, 3), args: 'A')); |
230 | w.add_child (child: ::make_unique<test_widget> (args: canvas::size_t (4, 1), args: 'B')); |
231 | w.add_child (child: ::make_unique<test_widget> (args: canvas::size_t (1, 2), args: 'C')); |
232 | canvas c (w.to_canvas (style_mgr: sm)); |
233 | ASSERT_CANVAS_STREQ |
234 | (c, false, |
235 | ("AAAA\n" |
236 | "AAAA\n" |
237 | "AAAA\n" |
238 | "BBBB\n" |
239 | "CCCC\n" |
240 | "CCCC\n" )); |
241 | } |
242 | |
243 | static void |
244 | test_canvas_widget () |
245 | { |
246 | style_manager sm; |
247 | canvas inner_canvas (canvas::size_t (5, 3), sm); |
248 | inner_canvas.fill (rect: canvas::rect_t (canvas::coord_t (0, 0), |
249 | canvas::size_t (5, 3)), |
250 | c: canvas::cell_t ('a')); |
251 | canvas_widget cw (std::move (inner_canvas)); |
252 | canvas c (cw.to_canvas (style_mgr: sm)); |
253 | ASSERT_CANVAS_STREQ |
254 | (c, false, |
255 | ("aaaaa\n" |
256 | "aaaaa\n" |
257 | "aaaaa\n" )); |
258 | } |
259 | |
260 | /* Run all selftests in this file. */ |
261 | |
262 | void |
263 | text_art_widget_cc_tests () |
264 | { |
265 | test_test_widget (); |
266 | test_text_widget (); |
267 | test_wrapper_widget (); |
268 | test_vbox_1 (); |
269 | test_vbox_2 (); |
270 | test_canvas_widget (); |
271 | } |
272 | |
273 | } // namespace selftest |
274 | |
275 | |
276 | #endif /* #if CHECKING_P */ |
277 | |