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
8 : under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3, or (at your option)
10 : any later version.
11 :
12 : GCC is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : General Public License 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 : #ifndef GCC_TEXT_ART_WIDGET_H
22 : #define GCC_TEXT_ART_WIDGET_H
23 :
24 : #include "text-art/canvas.h"
25 : #include "text-art/table.h"
26 :
27 : namespace text_art {
28 :
29 : /* Abstract base class: something that knows how to size itself and
30 : how to paint itself to a canvas, potentially with children, with
31 : support for hierarchical sizing and positioning.
32 :
33 : Widgets have a two-phase sizing/positioning algorithm.
34 :
35 : Step 1: size requests: the root widget is asked for its size request i.e
36 : how big it wants to be. This is handled by recursively asking child
37 : widgets for their requested sizes. Each widget subclass can implement
38 : their own logic for this in the "calc_req_size" vfunc, and the result
39 : is cached in m_req_size.
40 :
41 : Step 2: rect allocation: the root widget is set a canvas::rect_t as
42 : its "allocated" rectangle. Each widget subclass can then place its
43 : children recursively using the "update_child_alloc_rects" vfunc.
44 : For simplicity, all coordinates in the hierarchy are within the same
45 : coordinate system (rather than attempting to store per-child offsets).
46 :
47 : Widget subclasses are responsible for managing their own children. */
48 :
49 : /* Subclasses in this header, with indentation indicating inheritance. */
50 :
51 : class widget; /* Abstract base class. */
52 : class wrapper_widget; /* Concrete subclass: a widget with a single child. */
53 : class container_widget; /* Abstract subclass: widgets with an arbitrary
54 : number of children. */
55 : class vbox_widget; /* Concrete widget subclass: lay out children
56 : vertically. */
57 : class leaf_widget; /* Abstract subclass: a widget with no children. */
58 : class text_widget; /* Concrete subclass: a text string. */
59 : class canvas_widget; /* Concrete subclass: a pre-rendered canvas. */
60 :
61 : class widget
62 : {
63 : public:
64 : /* This can be very useful for debugging when implementing new
65 : widget subclasses. */
66 : static const bool DEBUG_GEOMETRY = false;
67 :
68 100 : virtual ~widget () {}
69 :
70 : canvas to_canvas (const style_manager &style_mgr);
71 :
72 713 : canvas::size_t get_req_size ()
73 : {
74 713 : m_req_size = calc_req_size();
75 713 : if (DEBUG_GEOMETRY)
76 : fprintf (stderr, "calc_req_size (%s) -> (w:%i, h:%i)\n",
77 : get_desc (),
78 : m_req_size.w, m_req_size.h);
79 713 : return m_req_size;
80 : }
81 :
82 713 : void set_alloc_rect (const canvas::rect_t &rect)
83 : {
84 713 : if (DEBUG_GEOMETRY)
85 : fprintf (stderr, "set_alloc_rect (%s): ((x:%i, y:%i), (w:%i, h:%i))\n",
86 : get_desc (),
87 : rect.m_top_left.x, rect.m_top_left.y,
88 : rect.m_size.w, rect.m_size.h);
89 713 : m_alloc_rect = rect;
90 713 : update_child_alloc_rects ();
91 76 : }
92 :
93 : virtual const char *get_desc () const = 0;
94 : virtual canvas::size_t calc_req_size () = 0;
95 : virtual void update_child_alloc_rects () = 0;
96 : virtual void paint_to_canvas (canvas &canvas) = 0;
97 :
98 : /* Access to the cached size request of this widget. */
99 : const canvas::size_t get_req_size () const { return m_req_size; }
100 : int get_req_w () const { return m_req_size.w; }
101 525 : int get_req_h () const { return m_req_size.h; }
102 :
103 : /* Access to the allocated canvas coordinates of this widget. */
104 20 : const canvas::rect_t &get_alloc_rect () const { return m_alloc_rect; }
105 525 : int get_alloc_w () const { return m_alloc_rect.get_width (); }
106 : int get_alloc_h () const { return m_alloc_rect.get_height (); }
107 312 : int get_min_x () const { return m_alloc_rect.get_min_x (); }
108 : int get_max_x () const { return m_alloc_rect.get_max_x (); }
109 : int get_next_x () const { return m_alloc_rect.get_next_x (); }
110 728 : int get_min_y () const { return m_alloc_rect.get_min_y (); }
111 112 : int get_max_y () const { return m_alloc_rect.get_max_y (); }
112 : int get_next_y () const { return m_alloc_rect.get_max_y (); }
113 : canvas::range_t get_x_range () const { return m_alloc_rect.get_x_range (); }
114 280 : canvas::range_t get_y_range () const { return m_alloc_rect.get_y_range (); }
115 345 : const canvas::coord_t &get_top_left () const
116 : {
117 345 : return m_alloc_rect.m_top_left;
118 : }
119 :
120 : protected:
121 721 : widget ()
122 601 : : m_req_size (0, 0),
123 721 : m_alloc_rect (canvas::coord_t (0, 0),
124 629 : canvas::size_t (0, 0))
125 : {}
126 :
127 : private:
128 : /* How much size this widget requested. */
129 : canvas::size_t m_req_size;
130 : /* Where (and how big) this widget was allocated. */
131 : canvas::rect_t m_alloc_rect;
132 : };
133 :
134 : /* Concrete subclass for a widget with a single child. */
135 :
136 80 : class wrapper_widget : public widget
137 : {
138 : public:
139 80 : wrapper_widget (std::unique_ptr<widget> child)
140 80 : : m_child (std::move (child))
141 : {}
142 :
143 0 : const char *get_desc () const override
144 : {
145 0 : return "wrapper_widget";
146 : }
147 80 : canvas::size_t calc_req_size () override
148 : {
149 80 : if (m_child)
150 76 : return m_child->get_req_size ();
151 : else
152 4 : return canvas::size_t (0,0);
153 : }
154 80 : void update_child_alloc_rects () override
155 : {
156 80 : if (m_child)
157 76 : m_child->set_alloc_rect (get_alloc_rect ());
158 80 : }
159 80 : void paint_to_canvas (canvas &canvas) override
160 : {
161 80 : if (m_child)
162 76 : m_child->paint_to_canvas (canvas);
163 80 : }
164 : private:
165 : std::unique_ptr<widget> m_child;
166 : };
167 :
168 : /* Abstract subclass for widgets with an arbitrary number of children. */
169 :
170 96 : class container_widget : public widget
171 : {
172 : public:
173 305 : void add_child (std::unique_ptr<widget> child)
174 : {
175 305 : m_children.push_back (std::move (child));
176 : }
177 :
178 80 : void paint_to_canvas (canvas &canvas) final override
179 : {
180 385 : for (auto &child : m_children)
181 305 : child->paint_to_canvas (canvas);
182 80 : }
183 :
184 : protected:
185 : std::vector<std::unique_ptr<widget>> m_children;
186 : };
187 :
188 : /* Concrete widget subclass: lay out children vertically. */
189 :
190 88 : class vbox_widget : public container_widget
191 : {
192 : public:
193 : const char *get_desc () const override;
194 : canvas::size_t calc_req_size () override;
195 : void update_child_alloc_rects () final override;
196 : };
197 :
198 : /* Abstract subclass for widgets with no children. */
199 :
200 4 : class leaf_widget : public widget
201 : {
202 : public:
203 437 : void update_child_alloc_rects () final override
204 : {
205 : /* no-op. */
206 437 : }
207 :
208 : protected:
209 329 : leaf_widget () : widget () {}
210 : };
211 :
212 : /* Concrete widget subclass for a text string. */
213 :
214 4 : class text_widget : public leaf_widget
215 : {
216 : public:
217 144 : text_widget (styled_string str)
218 144 : : leaf_widget (), m_str (std::move (str))
219 : {
220 : }
221 :
222 : const char *get_desc () const override;
223 : canvas::size_t calc_req_size () final override;
224 : void paint_to_canvas (canvas &canvas) final override;
225 :
226 : private:
227 : styled_string m_str;
228 : };
229 :
230 : /* Concrete widget subclass for a pre-rendered canvas. */
231 :
232 4 : class canvas_widget : public leaf_widget
233 : {
234 : public:
235 4 : canvas_widget (canvas &&c)
236 4 : : leaf_widget (), m_canvas (std::move (c))
237 : {
238 4 : }
239 :
240 : const char *get_desc () const override;
241 : canvas::size_t calc_req_size () final override;
242 : void paint_to_canvas (canvas &canvas) final override;
243 :
244 : private:
245 : canvas m_canvas;
246 : };
247 :
248 : } // namespace text_art
249 :
250 : #endif /* GCC_TEXT_ART_WIDGET_H */
|