/* Hierarchical diagram elements. Copyright (C) 2023-2024 Free Software Foundation, Inc. Contributed by David Malcolm . 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 . */ #include "config.h" #define INCLUDE_MEMORY #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" #include "pretty-print.h" #include "selftest.h" #include "make-unique.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 (::make_unique (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_vbox_1 () { style_manager sm; vbox_widget w; for (int i = 0; i < 5; i++) w.add_child (::make_unique (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 (::make_unique (canvas::size_t (1, 3), 'A')); w.add_child (::make_unique (canvas::size_t (4, 1), 'B')); w.add_child (::make_unique (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_vbox_1 (); test_vbox_2 (); test_canvas_widget (); } } // namespace selftest #endif /* #if CHECKING_P */