/* * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * * This program 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 2, or (at your option) * any later version. * * This program 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 this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifndef __UI_WIDGET_H__ #define __UI_WIDGET_H__ #include "ui.hpp" #include "ui_text.hpp" #include "ui_painter.hpp" #include "ui_focus.hpp" #include "rtc_time.hpp" #include "radio.hpp" #include "portapack.hpp" #include "utility.hpp" #include #include #include #include #include namespace ui { void dirty_set(); void dirty_clear(); bool is_dirty(); class Context { public: FocusManager& focus_manager() { return focus_manager_; } private: FocusManager focus_manager_{}; }; class Widget { public: Widget() : _parent_rect{} { } Widget( Rect parent_rect) : _parent_rect{parent_rect} { } Widget(const Widget&) = delete; Widget(Widget&&) = delete; Widget& operator=(const Widget&) = delete; Widget& operator=(Widget&&) = delete; virtual ~Widget() = default; Point screen_pos(); Size size() const; Rect screen_rect() const; Rect parent_rect() const; virtual void set_parent_rect(const Rect new_parent_rect); Widget* parent() const; void set_parent(Widget* const widget); bool hidden() const { return flags.hidden; } void hidden(bool hide); virtual void focus(); virtual void on_focus(); virtual void blur(); virtual void on_blur(); bool focusable() const; void set_focusable(const bool value); bool has_focus(); virtual void paint(Painter& painter) = 0; virtual void on_show(){}; virtual void on_hide(){}; virtual bool on_key(const KeyEvent event); virtual bool on_encoder(const EncoderEvent event); virtual bool on_touch(const TouchEvent event); virtual const std::vector& children() const; virtual Context& context() const; void set_style(const Style* new_style); const Style& style() const; int16_t id = 0; // State management methods. void set_dirty(); bool dirty() const; void set_clean(); void visible(bool v); bool visible() { return flags.visible; }; bool highlighted() const; void set_highlighted(const bool value); protected: void dirty_overlapping_children_in_rect(const Rect& child_rect); private: /* Widget rectangle relative to parent pos(). */ Rect _parent_rect; const Style* style_{nullptr}; Widget* parent_{nullptr}; struct flags_t { bool dirty : 1; // Widget content has changed. bool hidden : 1; // Hide widget and children. bool focusable : 1; // Widget can receive focus. bool highlighted : 1; // Show in a highlighted style. bool visible : 1; // Object was visible during last paint. }; flags_t flags{ .dirty = true, .hidden = false, .focusable = false, .highlighted = false, .visible = false, }; static const std::vector no_children; }; class View : public Widget { public: View() { } View(Rect parent_rect) { set_parent_rect(parent_rect); } // TODO: ~View() should on_hide() all children? void paint(Painter& painter) override; void add_child(Widget* const widget); void add_children(const std::initializer_list children); void remove_child(Widget* const widget); void remove_children(const std::vector& children); const std::vector& children() const override; virtual std::string title() const; protected: std::vector children_{}; void invalidate_child(Widget* const widget); }; class Rectangle : public Widget { public: Rectangle(Color c); Rectangle(Rect parent_rect, Color c); Rectangle() : Rectangle{{}, {}} { } void paint(Painter& painter) override; void set_color(const Color c); void set_outline(const bool outline); private: Color color; bool _outline = false; }; class Text : public Widget { public: Text() : text{""} { } Text(Rect parent_rect, std::string text); Text(Rect parent_rect); void set(std::string_view value); void paint(Painter& painter) override; protected: // NB: Don't truncate this string. The UI will only render // as many characters as will fit in its rectange. // Apps expect to be able to retrieve this string to avoid // needing to hold additional copies in memory. std::string text; }; class Labels : public Widget { public: struct Label { Point pos; std::string text; ui::Color color; }; Labels(const Labels&) = delete; Labels(Labels&&) = delete; Labels& operator=(const Labels&) = delete; Labels& operator=(Labels&&) = delete; Labels(std::initializer_list