Branch data Line data Source code
1 : : /* Tree diagrams.
2 : : Copyright (C) 2024-2025 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/tree-widget.h"
29 : : #include "text-art/dump-widget-info.h"
30 : :
31 : : using namespace text_art;
32 : :
33 : : /* class text_art::tree_widget : public text_art::widget. */
34 : :
35 : : static const int margin_width = 3;
36 : :
37 : : std::unique_ptr<tree_widget>
38 : 120 : tree_widget::make (styled_string str, const theme &theme, style::id_t style_id)
39 : : {
40 : 120 : return std::make_unique <tree_widget>
41 : 240 : (std::make_unique <text_widget> (std::move (str)),
42 : : theme,
43 : 120 : style_id);
44 : : }
45 : :
46 : : std::unique_ptr<tree_widget>
47 : 0 : tree_widget::make (const dump_widget_info &dwi, pretty_printer *pp)
48 : : {
49 : 0 : return tree_widget::make (styled_string (dwi.m_sm, pp_formatted_text (pp)),
50 : : dwi.m_theme,
51 : 0 : dwi.get_tree_style_id ());
52 : : }
53 : :
54 : : std::unique_ptr<tree_widget>
55 : 8 : tree_widget::make (const dump_widget_info &dwi, const char *str)
56 : : {
57 : 8 : return tree_widget::make (styled_string (dwi.m_sm, str),
58 : : dwi.m_theme,
59 : 8 : dwi.get_tree_style_id ());
60 : : }
61 : :
62 : : std::unique_ptr<tree_widget>
63 : 112 : tree_widget::from_fmt (const dump_widget_info &dwi,
64 : : printer_fn format_decoder,
65 : : const char *fmt, ...)
66 : : {
67 : 112 : va_list ap;
68 : 112 : va_start (ap, fmt);
69 : 112 : styled_string styled_str
70 : 112 : (styled_string::from_fmt_va (dwi.m_sm, format_decoder, fmt, &ap));
71 : 112 : va_end (ap);
72 : 112 : return make (std::move (styled_str), dwi.m_theme, dwi.get_tree_style_id ());
73 : 112 : }
74 : :
75 : : const char *
76 : 0 : tree_widget::get_desc () const
77 : : {
78 : 0 : return "tree_widget";
79 : : }
80 : :
81 : : canvas::size_t
82 : 116 : tree_widget::calc_req_size ()
83 : : {
84 : 116 : canvas::size_t result (0, 0);
85 : 116 : if (m_node)
86 : : {
87 : 116 : canvas::size_t node_req_size = m_node->get_req_size ();
88 : 116 : result.h += node_req_size.h;
89 : 116 : result.w = std::max (result.w, node_req_size.w);
90 : : }
91 : 220 : for (auto &child : m_children)
92 : : {
93 : 104 : canvas::size_t child_req_size = child->get_req_size ();
94 : 104 : result.h += child_req_size.h;
95 : 104 : result.w = std::max (result.w, child_req_size.w + margin_width);
96 : : }
97 : 116 : return result;
98 : : }
99 : :
100 : : void
101 : 116 : tree_widget::update_child_alloc_rects ()
102 : : {
103 : 116 : const int x = get_min_x ();
104 : 116 : int y = get_min_y ();
105 : 116 : if (m_node)
106 : : {
107 : 116 : m_node->set_alloc_rect
108 : 116 : (canvas::rect_t (canvas::coord_t (x, y),
109 : : canvas::size_t (get_alloc_w (),
110 : 116 : m_node->get_req_h ())));
111 : 116 : y += m_node->get_req_h ();
112 : : }
113 : 220 : for (auto &child : m_children)
114 : : {
115 : 104 : child->set_alloc_rect
116 : 208 : (canvas::rect_t (canvas::coord_t (x + margin_width, y),
117 : 104 : canvas::size_t (get_alloc_w () - margin_width,
118 : 104 : child->get_req_h ())));
119 : 104 : y += child->get_req_h ();
120 : : }
121 : 116 : }
122 : :
123 : : void
124 : 116 : tree_widget::paint_to_canvas (canvas &canvas)
125 : : {
126 : 116 : if (m_node)
127 : 116 : m_node->paint_to_canvas (canvas);
128 : 116 : const int min_x = get_min_x ();
129 : 116 : const canvas::cell_t cell_child_non_final
130 : 116 : (m_theme.get_cell (theme::cell_kind::TREE_CHILD_NON_FINAL, m_style_id));
131 : 116 : const canvas::cell_t cell_child_final
132 : 116 : (m_theme.get_cell (theme::cell_kind::TREE_CHILD_FINAL, m_style_id));
133 : 116 : const canvas::cell_t cell_x_connector
134 : 116 : (m_theme.get_cell (theme::cell_kind::TREE_X_CONNECTOR, m_style_id));
135 : 116 : const canvas::cell_t cell_y_connector
136 : 116 : (m_theme.get_cell (theme::cell_kind::TREE_Y_CONNECTOR, m_style_id));
137 : 116 : size_t idx = 0;
138 : 220 : for (auto &child : m_children)
139 : : {
140 : 104 : child->paint_to_canvas (canvas);
141 : :
142 : 104 : const bool last_child = (++idx == m_children.size ());
143 : 104 : canvas.paint (canvas::coord_t (min_x + 1, child->get_min_y ()),
144 : : cell_x_connector);
145 : 208 : canvas.paint (canvas::coord_t (min_x, child->get_min_y ()),
146 : : last_child ? cell_child_final : cell_child_non_final);
147 : 104 : if (!last_child)
148 : 112 : for (int y = child->get_min_y () + 1; y <= child ->get_max_y (); y++)
149 : 48 : canvas.paint (canvas::coord_t (min_x, y), cell_y_connector);
150 : : }
151 : 116 : }
152 : :
153 : : #if CHECKING_P
154 : :
155 : : namespace selftest {
156 : :
157 : : static std::unique_ptr<tree_widget>
158 : 8 : make_test_tree_widget (const dump_widget_info &dwi)
159 : : {
160 : 8 : std::unique_ptr<tree_widget> w
161 : 8 : (tree_widget::from_fmt (dwi, nullptr, "Root"));
162 : 32 : for (int i = 0; i < 3; i++)
163 : : {
164 : 24 : std::unique_ptr<tree_widget> c
165 : 24 : (tree_widget::from_fmt (dwi, nullptr, "Child %i", i));
166 : 96 : for (int j = 0; j < 3; j++)
167 : 144 : c->add_child (tree_widget::from_fmt (dwi, nullptr,
168 : : "Grandchild %i %i", i, j));
169 : 48 : w->add_child (std::move (c));
170 : 24 : }
171 : 8 : return w;
172 : : }
173 : :
174 : : static void
175 : 4 : test_tree_widget ()
176 : : {
177 : 4 : style_manager sm;
178 : :
179 : 4 : style::id_t default_style_id (sm.get_or_create_id (style ()));
180 : :
181 : 4 : {
182 : 4 : ascii_theme theme;
183 : 4 : dump_widget_info dwi (sm, theme, default_style_id);
184 : 4 : canvas c (make_test_tree_widget (dwi)->to_canvas (sm));
185 : 4 : ASSERT_CANVAS_STREQ
186 : : (c, false,
187 : : ("Root\n"
188 : : "+- Child 0\n"
189 : : "| +- Grandchild 0 0\n"
190 : : "| +- Grandchild 0 1\n"
191 : : "| `- Grandchild 0 2\n"
192 : : "+- Child 1\n"
193 : : "| +- Grandchild 1 0\n"
194 : : "| +- Grandchild 1 1\n"
195 : : "| `- Grandchild 1 2\n"
196 : : "`- Child 2\n"
197 : : " +- Grandchild 2 0\n"
198 : : " +- Grandchild 2 1\n"
199 : : " `- Grandchild 2 2\n"));
200 : 4 : }
201 : :
202 : 4 : {
203 : 4 : unicode_theme theme;
204 : 4 : dump_widget_info dwi (sm, theme, default_style_id);
205 : 4 : canvas c (make_test_tree_widget (dwi)->to_canvas (sm));
206 : 4 : ASSERT_CANVAS_STREQ
207 : : (c, false,
208 : : ("Root\n"
209 : : "├─ Child 0\n"
210 : : "│ ├─ Grandchild 0 0\n"
211 : : "│ ├─ Grandchild 0 1\n"
212 : : "│ ╰─ Grandchild 0 2\n"
213 : : "├─ Child 1\n"
214 : : "│ ├─ Grandchild 1 0\n"
215 : : "│ ├─ Grandchild 1 1\n"
216 : : "│ ╰─ Grandchild 1 2\n"
217 : : "╰─ Child 2\n"
218 : : " ├─ Grandchild 2 0\n"
219 : : " ├─ Grandchild 2 1\n"
220 : : " ╰─ Grandchild 2 2\n"));
221 : 4 : }
222 : 4 : }
223 : :
224 : : /* Run all selftests in this file. */
225 : :
226 : : void
227 : 4 : text_art_tree_widget_cc_tests ()
228 : : {
229 : 4 : test_tree_widget ();
230 : 4 : }
231 : :
232 : : } // namespace selftest
233 : :
234 : :
235 : : #endif /* #if CHECKING_P */
|