1/* Hierarchical diagram elements.
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 under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for 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#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
32using namespace text_art;
33
34/* class text_art::widget. */
35
36canvas
37widget::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
54const char *
55vbox_widget::get_desc () const
56{
57 return "vbox_widget";
58}
59
60canvas::size_t
61vbox_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
73void
74vbox_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
90const char *
91text_widget::get_desc () const
92{
93 return "text_widget";
94}
95
96canvas::size_t
97text_widget::calc_req_size ()
98{
99 return canvas::size_t (m_str.size (), 1);
100}
101
102void
103text_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
110const char *
111canvas_widget::get_desc () const
112{
113 return "canvas_widget";
114}
115
116canvas::size_t
117canvas_widget::calc_req_size ()
118{
119 return m_canvas.get_size ();
120}
121
122void
123canvas_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
136namespace 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
142class test_widget : public leaf_widget
143{
144public:
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
162private:
163 canvas::size_t m_test_size;
164 char m_ch;
165};
166
167static void
168test_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
180static void
181test_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
191static void
192test_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
204static void
205test_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
224static void
225test_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
243static void
244test_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
262void
263text_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

source code of gcc/text-art/widget.cc