Branch data Line data Source code
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
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 : 96 : virtual ~widget () {}
69 : :
70 : : canvas to_canvas (const style_manager &style_mgr);
71 : :
72 : 709 : canvas::size_t get_req_size ()
73 : : {
74 : 709 : m_req_size = calc_req_size();
75 : 709 : 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 : 709 : return m_req_size;
80 : : }
81 : :
82 : 709 : void set_alloc_rect (const canvas::rect_t &rect)
83 : : {
84 : 709 : 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 : 709 : m_alloc_rect = rect;
90 : 709 : update_child_alloc_rects ();
91 : : }
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 : 717 : widget ()
122 : 597 : : m_req_size (0, 0),
123 : 717 : m_alloc_rect (canvas::coord_t (0, 0),
124 : 625 : 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 : 76 : class wrapper_widget : public widget
137 : : {
138 : : public:
139 : 76 : wrapper_widget (std::unique_ptr<widget> child)
140 : 76 : : m_child (std::move (child))
141 : : {}
142 : :
143 : 0 : const char *get_desc () const override
144 : : {
145 : 0 : return "wrapper_widget";
146 : : }
147 : 76 : canvas::size_t calc_req_size () override
148 : : {
149 : 76 : return m_child->get_req_size ();
150 : : }
151 : 76 : void update_child_alloc_rects () override
152 : : {
153 : 76 : m_child->set_alloc_rect (get_alloc_rect ());
154 : 76 : }
155 : 76 : void paint_to_canvas (canvas &canvas) override
156 : : {
157 : 76 : m_child->paint_to_canvas (canvas);
158 : 76 : }
159 : : private:
160 : : std::unique_ptr<widget> m_child;
161 : : };
162 : :
163 : : /* Abstract subclass for widgets with an arbitrary number of children. */
164 : :
165 : 96 : class container_widget : public widget
166 : : {
167 : : public:
168 : 305 : void add_child (std::unique_ptr<widget> child)
169 : : {
170 : 305 : m_children.push_back (std::move (child));
171 : : }
172 : :
173 : 80 : void paint_to_canvas (canvas &canvas) final override
174 : : {
175 : 385 : for (auto &child : m_children)
176 : 305 : child->paint_to_canvas (canvas);
177 : 80 : }
178 : :
179 : : protected:
180 : : std::vector<std::unique_ptr<widget>> m_children;
181 : : };
182 : :
183 : : /* Concrete widget subclass: lay out children vertically. */
184 : :
185 : 88 : class vbox_widget : public container_widget
186 : : {
187 : : public:
188 : : const char *get_desc () const override;
189 : : canvas::size_t calc_req_size () override;
190 : : void update_child_alloc_rects () final override;
191 : : };
192 : :
193 : : /* Abstract subclass for widgets with no children. */
194 : :
195 : 4 : class leaf_widget : public widget
196 : : {
197 : : public:
198 : 437 : void update_child_alloc_rects () final override
199 : : {
200 : : /* no-op. */
201 : 437 : }
202 : :
203 : : protected:
204 : 329 : leaf_widget () : widget () {}
205 : : };
206 : :
207 : : /* Concrete widget subclass for a text string. */
208 : :
209 : 4 : class text_widget : public leaf_widget
210 : : {
211 : : public:
212 : 144 : text_widget (styled_string str)
213 : 144 : : leaf_widget (), m_str (std::move (str))
214 : : {
215 : : }
216 : :
217 : : const char *get_desc () const override;
218 : : canvas::size_t calc_req_size () final override;
219 : : void paint_to_canvas (canvas &canvas) final override;
220 : :
221 : : private:
222 : : styled_string m_str;
223 : : };
224 : :
225 : : /* Concrete widget subclass for a pre-rendered canvas. */
226 : :
227 : 4 : class canvas_widget : public leaf_widget
228 : : {
229 : : public:
230 : 4 : canvas_widget (canvas &&c)
231 : 4 : : leaf_widget (), m_canvas (std::move (c))
232 : : {
233 : 4 : }
234 : :
235 : : const char *get_desc () const override;
236 : : canvas::size_t calc_req_size () final override;
237 : : void paint_to_canvas (canvas &canvas) final override;
238 : :
239 : : private:
240 : : canvas m_canvas;
241 : : };
242 : :
243 : : } // namespace text_art
244 : :
245 : : #endif /* GCC_TEXT_ART_WIDGET_H */
|