| /* Hierarchical diagram elements. |
| Copyright (C) 2023-2025 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/>. */ |
| |
| #include "config.h" |
| #define INCLUDE_VECTOR |
| #include "system.h" |
| #include "coretypes.h" |
| #include "pretty-print.h" |
| #include "selftest.h" |
| #include "text-art/selftests.h" |
| #include "text-art/widget.h" |
| |
| using namespace text_art; |
| |
| /* class text_art::widget. */ |
| |
| canvas |
| widget::to_canvas (const style_manager &style_mgr) |
| { |
| const canvas::size_t req_size = get_req_size (); |
| |
| /* For now we don't constrain the allocation; we give |
| the widget the full size it requested, and widgets |
| assume they got their full size request. */ |
| const canvas::size_t alloc_size = req_size; |
| |
| set_alloc_rect (canvas::rect_t (canvas::coord_t (0, 0), alloc_size)); |
| canvas c (alloc_size, style_mgr); |
| paint_to_canvas (c); |
| return c; |
| } |
| |
| /* class text_art::vbox_widget : public text_art::container_widget. */ |
| |
| const char * |
| vbox_widget::get_desc () const |
| { |
| return "vbox_widget"; |
| } |
| |
| canvas::size_t |
| vbox_widget::calc_req_size () |
| { |
| canvas::size_t result (0, 0); |
| for (auto &child : m_children) |
| { |
| canvas::size_t child_req_size = child->get_req_size(); |
| result.h += child_req_size.h; |
| result.w = std::max (result.w, child_req_size.w); |
| } |
| return result; |
| } |
| |
| void |
| vbox_widget::update_child_alloc_rects () |
| { |
| const int x = get_min_x (); |
| int y = get_min_y (); |
| for (auto &child : m_children) |
| { |
| child->set_alloc_rect |
| (canvas::rect_t (canvas::coord_t (x, y), |
| canvas::size_t (get_alloc_w (), |
| child->get_req_h ()))); |
| y += child->get_req_h (); |
| } |
| } |
| |
| /* class text_art::text_widget : public text_art::leaf_widget. */ |
| |
| const char * |
| text_widget::get_desc () const |
| { |
| return "text_widget"; |
| } |
| |
| canvas::size_t |
| text_widget::calc_req_size () |
| { |
| return canvas::size_t (m_str.size (), 1); |
| } |
| |
| void |
| text_widget::paint_to_canvas (canvas &canvas) |
| { |
| canvas.paint_text (get_top_left (), m_str); |
| } |
| |
| /* class text_art::canvas_widget : public text_art::leaf_widget. */ |
| |
| const char * |
| canvas_widget::get_desc () const |
| { |
| return "canvas_widget"; |
| } |
| |
| canvas::size_t |
| canvas_widget::calc_req_size () |
| { |
| return m_canvas.get_size (); |
| } |
| |
| void |
| canvas_widget::paint_to_canvas (canvas &canvas) |
| { |
| for (int y = 0; y < m_canvas.get_size ().h; y++) |
| for (int x = 0; x < m_canvas.get_size ().w; x++) |
| { |
| canvas::coord_t rel_xy (x, y); |
| canvas.paint (get_top_left () + rel_xy, |
| m_canvas.get (rel_xy)); |
| } |
| } |
| |
| #if CHECKING_P |
| |
| namespace selftest { |
| |
| /* Concrete widget subclass for writing selftests. |
| Requests a hard-coded size, and fills its allocated rectangle |
| with a specific character. */ |
| |
| class test_widget : public leaf_widget |
| { |
| public: |
| test_widget (canvas::size_t size, char ch) |
| : m_test_size (size), m_ch (ch) |
| {} |
| |
| const char *get_desc () const final override |
| { |
| return "test_widget"; |
| } |
| canvas::size_t calc_req_size () final override |
| { |
| return m_test_size; |
| } |
| void paint_to_canvas (canvas &canvas) final override |
| { |
| canvas.fill (get_alloc_rect (), canvas::cell_t (m_ch)); |
| } |
| |
| private: |
| canvas::size_t m_test_size; |
| char m_ch; |
| }; |
| |
| static void |
| test_test_widget () |
| { |
| style_manager sm; |
| test_widget w (canvas::size_t (3, 3), 'A'); |
| canvas c (w.to_canvas (sm)); |
| ASSERT_CANVAS_STREQ |
| (c, false, |
| ("AAA\n" |
| "AAA\n" |
| "AAA\n")); |
| } |
| |
| static void |
| test_text_widget () |
| { |
| style_manager sm; |
| text_widget w (styled_string (sm, "hello world")); |
| canvas c (w.to_canvas (sm)); |
| ASSERT_CANVAS_STREQ |
| (c, false, |
| ("hello world\n")); |
| } |
| |
| static void |
| test_wrapper_widget () |
| { |
| style_manager sm; |
| wrapper_widget w (std::make_unique<test_widget> (canvas::size_t (3, 3), 'B')); |
| canvas c (w.to_canvas (sm)); |
| ASSERT_CANVAS_STREQ |
| (c, false, |
| ("BBB\n" |
| "BBB\n" |
| "BBB\n")); |
| } |
| |
| static void |
| test_empty_wrapper_widget () |
| { |
| style_manager sm; |
| wrapper_widget w (nullptr); |
| canvas c (w.to_canvas (sm)); |
| ASSERT_CANVAS_STREQ (c, false, ""); |
| } |
| |
| static void |
| test_vbox_1 () |
| { |
| style_manager sm; |
| vbox_widget w; |
| for (int i = 0; i < 5; i++) |
| w.add_child |
| (std::make_unique <text_widget> |
| (styled_string::from_fmt (sm, nullptr, |
| "this is line %i", i))); |
| canvas c (w.to_canvas (sm)); |
| ASSERT_CANVAS_STREQ |
| (c, false, |
| ("this is line 0\n" |
| "this is line 1\n" |
| "this is line 2\n" |
| "this is line 3\n" |
| "this is line 4\n")); |
| } |
| |
| static void |
| test_vbox_2 () |
| { |
| style_manager sm; |
| vbox_widget w; |
| w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 3), 'A')); |
| w.add_child (std::make_unique<test_widget> (canvas::size_t (4, 1), 'B')); |
| w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 2), 'C')); |
| canvas c (w.to_canvas (sm)); |
| ASSERT_CANVAS_STREQ |
| (c, false, |
| ("AAAA\n" |
| "AAAA\n" |
| "AAAA\n" |
| "BBBB\n" |
| "CCCC\n" |
| "CCCC\n")); |
| } |
| |
| static void |
| test_canvas_widget () |
| { |
| style_manager sm; |
| canvas inner_canvas (canvas::size_t (5, 3), sm); |
| inner_canvas.fill (canvas::rect_t (canvas::coord_t (0, 0), |
| canvas::size_t (5, 3)), |
| canvas::cell_t ('a')); |
| canvas_widget cw (std::move (inner_canvas)); |
| canvas c (cw.to_canvas (sm)); |
| ASSERT_CANVAS_STREQ |
| (c, false, |
| ("aaaaa\n" |
| "aaaaa\n" |
| "aaaaa\n")); |
| } |
| |
| /* Run all selftests in this file. */ |
| |
| void |
| text_art_widget_cc_tests () |
| { |
| test_test_widget (); |
| test_text_widget (); |
| test_wrapper_widget (); |
| test_empty_wrapper_widget (); |
| test_vbox_1 (); |
| test_vbox_2 (); |
| test_canvas_widget (); |
| } |
| |
| } // namespace selftest |
| |
| |
| #endif /* #if CHECKING_P */ |