Line data Source code
1 : /* Hierarchical diagram elements.
2 : Copyright (C) 2023-2026 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_VECTOR
23 : #include "system.h"
24 : #include "coretypes.h"
25 : #include "pretty-print.h"
26 : #include "selftest.h"
27 : #include "text-art/selftests.h"
28 : #include "text-art/widget.h"
29 :
30 : using namespace text_art;
31 :
32 : /* class text_art::widget. */
33 :
34 : canvas
35 112 : widget::to_canvas (const style_manager &style_mgr)
36 : {
37 112 : const canvas::size_t req_size = get_req_size ();
38 :
39 : /* For now we don't constrain the allocation; we give
40 : the widget the full size it requested, and widgets
41 : assume they got their full size request. */
42 112 : const canvas::size_t alloc_size = req_size;
43 :
44 112 : set_alloc_rect (canvas::rect_t (canvas::coord_t (0, 0), alloc_size));
45 112 : canvas c (alloc_size, style_mgr);
46 112 : paint_to_canvas (c);
47 112 : return c;
48 : }
49 :
50 : /* class text_art::vbox_widget : public text_art::container_widget. */
51 :
52 : const char *
53 0 : vbox_widget::get_desc () const
54 : {
55 0 : return "vbox_widget";
56 : }
57 :
58 : canvas::size_t
59 76 : vbox_widget::calc_req_size ()
60 : {
61 76 : canvas::size_t result (0, 0);
62 381 : for (auto &child : m_children)
63 : {
64 305 : canvas::size_t child_req_size = child->get_req_size();
65 305 : result.h += child_req_size.h;
66 305 : result.w = std::max (result.w, child_req_size.w);
67 : }
68 76 : return result;
69 : }
70 :
71 : void
72 80 : vbox_widget::update_child_alloc_rects ()
73 : {
74 80 : const int x = get_min_x ();
75 80 : int y = get_min_y ();
76 385 : for (auto &child : m_children)
77 : {
78 305 : child->set_alloc_rect
79 610 : (canvas::rect_t (canvas::coord_t (x, y),
80 : canvas::size_t (get_alloc_w (),
81 305 : child->get_req_h ())));
82 305 : y += child->get_req_h ();
83 : }
84 80 : }
85 :
86 : /* class text_art::text_widget : public text_art::leaf_widget. */
87 :
88 : const char *
89 0 : text_widget::get_desc () const
90 : {
91 0 : return "text_widget";
92 : }
93 :
94 : canvas::size_t
95 140 : text_widget::calc_req_size ()
96 : {
97 140 : return canvas::size_t (m_str.size (), 1);
98 : }
99 :
100 : void
101 140 : text_widget::paint_to_canvas (canvas &canvas)
102 : {
103 140 : canvas.paint_text (get_top_left (), m_str);
104 140 : }
105 :
106 : /* class text_art::canvas_widget : public text_art::leaf_widget. */
107 :
108 : const char *
109 0 : canvas_widget::get_desc () const
110 : {
111 0 : return "canvas_widget";
112 : }
113 :
114 : canvas::size_t
115 4 : canvas_widget::calc_req_size ()
116 : {
117 4 : return m_canvas.get_size ();
118 : }
119 :
120 : void
121 4 : canvas_widget::paint_to_canvas (canvas &canvas)
122 : {
123 16 : for (int y = 0; y < m_canvas.get_size ().h; y++)
124 72 : for (int x = 0; x < m_canvas.get_size ().w; x++)
125 : {
126 60 : canvas::coord_t rel_xy (x, y);
127 60 : canvas.paint (get_top_left () + rel_xy,
128 60 : m_canvas.get (rel_xy));
129 : }
130 4 : }
131 :
132 : #if CHECKING_P
133 :
134 : namespace selftest {
135 :
136 : /* Concrete widget subclass for writing selftests.
137 : Requests a hard-coded size, and fills its allocated rectangle
138 : with a specific character. */
139 :
140 4 : class test_widget : public leaf_widget
141 : {
142 : public:
143 20 : test_widget (canvas::size_t size, char ch)
144 4 : : m_test_size (size), m_ch (ch)
145 : {}
146 :
147 0 : const char *get_desc () const final override
148 : {
149 0 : return "test_widget";
150 : }
151 20 : canvas::size_t calc_req_size () final override
152 : {
153 20 : return m_test_size;
154 : }
155 20 : void paint_to_canvas (canvas &canvas) final override
156 : {
157 20 : canvas.fill (get_alloc_rect (), canvas::cell_t (m_ch));
158 20 : }
159 :
160 : private:
161 : canvas::size_t m_test_size;
162 : char m_ch;
163 : };
164 :
165 : static void
166 4 : test_test_widget ()
167 : {
168 4 : style_manager sm;
169 4 : test_widget w (canvas::size_t (3, 3), 'A');
170 4 : canvas c (w.to_canvas (sm));
171 4 : ASSERT_CANVAS_STREQ
172 : (c, false,
173 : ("AAA\n"
174 : "AAA\n"
175 : "AAA\n"));
176 4 : }
177 :
178 : static void
179 4 : test_text_widget ()
180 : {
181 4 : style_manager sm;
182 4 : text_widget w (styled_string (sm, "hello world"));
183 4 : canvas c (w.to_canvas (sm));
184 4 : ASSERT_CANVAS_STREQ
185 : (c, false,
186 : ("hello world\n"));
187 4 : }
188 :
189 : static void
190 4 : test_wrapper_widget ()
191 : {
192 4 : style_manager sm;
193 4 : wrapper_widget w (std::make_unique<test_widget> (canvas::size_t (3, 3), 'B'));
194 4 : canvas c (w.to_canvas (sm));
195 4 : ASSERT_CANVAS_STREQ
196 : (c, false,
197 : ("BBB\n"
198 : "BBB\n"
199 : "BBB\n"));
200 4 : }
201 :
202 : static void
203 4 : test_empty_wrapper_widget ()
204 : {
205 4 : style_manager sm;
206 4 : wrapper_widget w (nullptr);
207 4 : canvas c (w.to_canvas (sm));
208 4 : ASSERT_CANVAS_STREQ (c, false, "");
209 4 : }
210 :
211 : static void
212 4 : test_vbox_1 ()
213 : {
214 4 : style_manager sm;
215 4 : vbox_widget w;
216 24 : for (int i = 0; i < 5; i++)
217 20 : w.add_child
218 20 : (std::make_unique <text_widget>
219 20 : (styled_string::from_fmt (sm, nullptr,
220 : "this is line %i", i)));
221 4 : canvas c (w.to_canvas (sm));
222 4 : ASSERT_CANVAS_STREQ
223 : (c, false,
224 : ("this is line 0\n"
225 : "this is line 1\n"
226 : "this is line 2\n"
227 : "this is line 3\n"
228 : "this is line 4\n"));
229 4 : }
230 :
231 : static void
232 4 : test_vbox_2 ()
233 : {
234 4 : style_manager sm;
235 4 : vbox_widget w;
236 4 : w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 3), 'A'));
237 4 : w.add_child (std::make_unique<test_widget> (canvas::size_t (4, 1), 'B'));
238 4 : w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 2), 'C'));
239 4 : canvas c (w.to_canvas (sm));
240 4 : ASSERT_CANVAS_STREQ
241 : (c, false,
242 : ("AAAA\n"
243 : "AAAA\n"
244 : "AAAA\n"
245 : "BBBB\n"
246 : "CCCC\n"
247 : "CCCC\n"));
248 4 : }
249 :
250 : static void
251 4 : test_canvas_widget ()
252 : {
253 4 : style_manager sm;
254 4 : canvas inner_canvas (canvas::size_t (5, 3), sm);
255 4 : inner_canvas.fill (canvas::rect_t (canvas::coord_t (0, 0),
256 4 : canvas::size_t (5, 3)),
257 4 : canvas::cell_t ('a'));
258 4 : canvas_widget cw (std::move (inner_canvas));
259 4 : canvas c (cw.to_canvas (sm));
260 4 : ASSERT_CANVAS_STREQ
261 : (c, false,
262 : ("aaaaa\n"
263 : "aaaaa\n"
264 : "aaaaa\n"));
265 4 : }
266 :
267 : /* Run all selftests in this file. */
268 :
269 : void
270 4 : text_art_widget_cc_tests ()
271 : {
272 4 : test_test_widget ();
273 4 : test_text_widget ();
274 4 : test_wrapper_widget ();
275 4 : test_empty_wrapper_widget ();
276 4 : test_vbox_1 ();
277 4 : test_vbox_2 ();
278 4 : test_canvas_widget ();
279 4 : }
280 :
281 : } // namespace selftest
282 :
283 :
284 : #endif /* #if CHECKING_P */
|