aboutsummaryrefslogtreecommitdiff
path: root/gcc/text-art/widget.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/text-art/widget.h')
-rw-r--r--gcc/text-art/widget.h245
1 files changed, 245 insertions, 0 deletions
diff --git a/gcc/text-art/widget.h b/gcc/text-art/widget.h
new file mode 100644
index 0000000..8798e43
--- /dev/null
+++ b/gcc/text-art/widget.h
@@ -0,0 +1,245 @@
+/* Hierarchical diagram elements.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_TEXT_ART_WIDGET_H
+#define GCC_TEXT_ART_WIDGET_H
+
+#include "text-art/canvas.h"
+#include "text-art/table.h"
+
+namespace text_art {
+
+/* Abstract base class: something that knows how to size itself and
+ how to paint itself to a canvas, potentially with children, with
+ support for hierarchical sizing and positioning.
+
+ Widgets have a two-phase sizing/positioning algorithm.
+
+ Step 1: size requests: the root widget is asked for its size request i.e
+ how big it wants to be. This is handled by recursively asking child
+ widgets for their requested sizes. Each widget subclass can implement
+ their own logic for this in the "calc_req_size" vfunc, and the result
+ is cached in m_req_size.
+
+ Step 2: rect allocation: the root widget is set a canvas::rect_t as
+ its "allocated" rectangle. Each widget subclass can then place its
+ children recursively using the "update_child_alloc_rects" vfunc.
+ For simplicity, all coordinates in the hierarchy are within the same
+ coordinate system (rather than attempting to store per-child offsets).
+
+ Widget subclasses are responsible for managing their own children. */
+
+/* Subclasses in this header, with indentation indicating inheritance. */
+
+class widget; /* Abstract base class. */
+ class wrapper_widget; /* Concrete subclass: a widget with a single child. */
+ class container_widget; /* Abstract subclass: widgets with an arbitrary
+ number of children. */
+ class vbox_widget; /* Concrete widget subclass: lay out children
+ vertically. */
+ class leaf_widget; /* Abstract subclass: a widget with no children. */
+ class text_widget; /* Concrete subclass: a text string. */
+ class canvas_widget; /* Concrete subclass: a pre-rendered canvas. */
+
+class widget
+{
+ public:
+ /* This can be very useful for debugging when implementing new
+ widget subclasses. */
+ static const bool DEBUG_GEOMETRY = false;
+
+ virtual ~widget () {}
+
+ canvas to_canvas (const style_manager &style_mgr);
+
+ canvas::size_t get_req_size ()
+ {
+ m_req_size = calc_req_size();
+ if (DEBUG_GEOMETRY)
+ fprintf (stderr, "calc_req_size (%s) -> (w:%i, h:%i)\n",
+ get_desc (),
+ m_req_size.w, m_req_size.h);
+ return m_req_size;
+ }
+
+ void set_alloc_rect (const canvas::rect_t &rect)
+ {
+ if (DEBUG_GEOMETRY)
+ fprintf (stderr, "set_alloc_rect (%s): ((x:%i, y:%i), (w:%i, h:%i))\n",
+ get_desc (),
+ rect.m_top_left.x, rect.m_top_left.y,
+ rect.m_size.w, rect.m_size.h);
+ m_alloc_rect = rect;
+ update_child_alloc_rects ();
+ }
+
+ virtual const char *get_desc () const = 0;
+ virtual canvas::size_t calc_req_size () = 0;
+ virtual void update_child_alloc_rects () = 0;
+ virtual void paint_to_canvas (canvas &canvas) = 0;
+
+ /* Access to the cached size request of this widget. */
+ const canvas::size_t get_req_size () const { return m_req_size; }
+ int get_req_w () const { return m_req_size.w; }
+ int get_req_h () const { return m_req_size.h; }
+
+ /* Access to the allocated canvas coordinates of this widget. */
+ const canvas::rect_t &get_alloc_rect () const { return m_alloc_rect; }
+ int get_alloc_w () const { return m_alloc_rect.get_width (); }
+ int get_alloc_h () const { return m_alloc_rect.get_height (); }
+ int get_min_x () const { return m_alloc_rect.get_min_x (); }
+ int get_max_x () const { return m_alloc_rect.get_max_x (); }
+ int get_next_x () const { return m_alloc_rect.get_next_x (); }
+ int get_min_y () const { return m_alloc_rect.get_min_y (); }
+ int get_max_y () const { return m_alloc_rect.get_max_y (); }
+ int get_next_y () const { return m_alloc_rect.get_max_y (); }
+ canvas::range_t get_x_range () const { return m_alloc_rect.get_x_range (); }
+ canvas::range_t get_y_range () const { return m_alloc_rect.get_y_range (); }
+ const canvas::coord_t &get_top_left () const
+ {
+ return m_alloc_rect.m_top_left;
+ }
+
+ protected:
+ widget ()
+ : m_req_size (0, 0),
+ m_alloc_rect (canvas::coord_t (0, 0),
+ canvas::size_t (0, 0))
+ {}
+
+private:
+ /* How much size this widget requested. */
+ canvas::size_t m_req_size;
+ /* Where (and how big) this widget was allocated. */
+ canvas::rect_t m_alloc_rect;
+};
+
+/* Concrete subclass for a widget with a single child. */
+
+class wrapper_widget : public widget
+{
+ public:
+ wrapper_widget (std::unique_ptr<widget> child)
+ : m_child (std::move (child))
+ {}
+
+ const char *get_desc () const override
+ {
+ return "wrapper_widget";
+ }
+ canvas::size_t calc_req_size () override
+ {
+ return m_child->get_req_size ();
+ }
+ void update_child_alloc_rects ()
+ {
+ m_child->set_alloc_rect (get_alloc_rect ());
+ }
+ void paint_to_canvas (canvas &canvas) override
+ {
+ m_child->paint_to_canvas (canvas);
+ }
+ private:
+ std::unique_ptr<widget> m_child;
+};
+
+/* Abstract subclass for widgets with an arbitrary number of children. */
+
+class container_widget : public widget
+{
+ public:
+ void add_child (std::unique_ptr<widget> child)
+ {
+ m_children.push_back (std::move (child));
+ }
+
+ void paint_to_canvas (canvas &canvas) final override
+ {
+ for (auto &child : m_children)
+ child->paint_to_canvas (canvas);
+ }
+
+ protected:
+ std::vector<std::unique_ptr<widget>> m_children;
+};
+
+/* Concrete widget subclass: lay out children vertically. */
+
+class vbox_widget : public container_widget
+{
+ public:
+ const char *get_desc () const override;
+ canvas::size_t calc_req_size () override;
+ void update_child_alloc_rects () final override;
+};
+
+/* Abstract subclass for widgets with no children. */
+
+class leaf_widget : public widget
+{
+ public:
+ void update_child_alloc_rects () final override
+ {
+ /* no-op. */
+ }
+
+ protected:
+ leaf_widget () : widget () {}
+};
+
+/* Concrete widget subclass for a text string. */
+
+class text_widget : public leaf_widget
+{
+ public:
+ text_widget (styled_string str)
+ : leaf_widget (), m_str (std::move (str))
+ {
+ }
+
+ const char *get_desc () const override;
+ canvas::size_t calc_req_size () final override;
+ void paint_to_canvas (canvas &canvas) final override;
+
+private:
+ styled_string m_str;
+};
+
+/* Concrete widget subclass for a pre-rendered canvas. */
+
+class canvas_widget : public leaf_widget
+{
+ public:
+ canvas_widget (canvas &&c)
+ : leaf_widget (), m_canvas (std::move (c))
+ {
+ }
+
+ const char *get_desc () const override;
+ canvas::size_t calc_req_size () final override;
+ void paint_to_canvas (canvas &canvas) final override;
+
+private:
+ canvas m_canvas;
+};
+
+} // namespace text_art
+
+#endif /* GCC_TEXT_ART_WIDGET_H */