Line data Source code
1 : #pragma once 2 : 3 : #include <AH/Containers/LinkedList.hpp> 4 : #include <Display/DisplayInterface.hpp> 5 : 6 : BEGIN_CS_NAMESPACE 7 : 8 : /** 9 : * @brief An interface for elements that draw to a display. 10 : */ 11 : class DisplayElement : public DoublyLinkable<DisplayElement> { 12 : protected: 13 : /// @brief Create a new DisplayElement. 14 : /// 15 : /// @param display 16 : /// The display that this display element draws to. 17 : DisplayElement(DisplayInterface &display) : display(display) { 18 : // The elements are sorted by the address of their displays. 19 : // This way, all display elements that draw to the same display are next 20 : // to each other. This means that the display buffer can be reused, and 21 : // makes it easier to iterate over the displays and draw to them. 22 : elements.insertSorted( 23 : this, [](const DisplayElement &lhs, const DisplayElement &rhs) { 24 : return &lhs.getDisplay() < &rhs.getDisplay(); 25 : }); 26 : } 27 : 28 : /// @name Enabling and disabling display elements 29 : /// @{ 30 : 31 : /// Enable this display element: insert it into the linked list of 32 : /// instances, so it gets drawn to the display 33 : void enable() { 34 : if (isEnabled()) { 35 : ERROR(F("Error: This element is already enabled."), 0x9212); 36 : return; 37 : } 38 : elements.append(this); 39 : } 40 : 41 : /// Disable this display element: remove it from the linked list of 42 : /// instances, so it no longer gets drawn to the display 43 : void disable() { 44 : if (!isEnabled()) { 45 : ERROR(F("Error: This element is already disabled."), 0x9213); 46 : return; 47 : } 48 : elements.remove(this); 49 : } 50 : 51 : /** 52 : * @brief Check if this display element is enabled. 53 : * 54 : * @note Assumes that the element is not added to a different linked 55 : * list by the user. 56 : */ 57 : bool isEnabled() const { 58 : return elements.couldContain(this); 59 : } 60 : 61 : /// @copydoc DisplayElement::enable 62 : static void enable(DisplayElement *element) { element->enable(); } 63 : /// @copydoc DisplayElement::enable 64 : static void enable(DisplayElement &element) { element.enable(); } 65 : /// @copydoc DisplayElement::enable 66 : template <class U, size_t N> 67 : static void enable(U (&array)[N]) { 68 : for (U &el : array) 69 : enable(el); 70 : } 71 : 72 : /// @copydoc DisplayElement::disable 73 : static void disable(DisplayElement *element) { element->disable(); } 74 : /// @copydoc DisplayElement::disable 75 : static void disable(DisplayElement &element) { element.disable(); } 76 : /// @copydoc DisplayElement::disable 77 : template <class U, size_t N> 78 : static void disable(U (&array)[N]) { 79 : for (U &el : array) 80 : disable(el); 81 : } 82 : 83 : /// @} 84 : 85 : public: 86 : virtual ~DisplayElement() { elements.remove(this); } 87 : 88 : /// Draw this DisplayElement to the display buffer. 89 : virtual void draw() = 0; 90 : 91 : /// Check if this DisplayElement has to be re-drawn. 92 : virtual bool getDirty() const = 0; 93 : 94 : /// Get a reference to the display that this element draws to. 95 0 : DisplayInterface &getDisplay() { return display; } 96 : /// Get a const reference to the display that this element draws to. 97 : const DisplayInterface &getDisplay() const { return display; } 98 : 99 : /// Get the list of all DisplayElement instances. 100 0 : static DoublyLinkedList<DisplayElement> &getAll() { return elements; } 101 : 102 : protected: 103 : DisplayInterface &display; 104 : 105 : static DoublyLinkedList<DisplayElement> elements; 106 : }; 107 : 108 : END_CS_NAMESPACE