diff --git a/escher/include/escher/childless_view.h b/escher/include/escher/childless_view.h index 90e0da874..9f9d7c7b8 100644 --- a/escher/include/escher/childless_view.h +++ b/escher/include/escher/childless_view.h @@ -7,7 +7,7 @@ class ChildlessView : public View { using View::View; protected: int numberOfSubviews() const override; - const View * subview(int index) const override; + View * subview(int index) override; void storeSubviewAtIndex(View * v, int index) override; void layoutSubviews() override; }; diff --git a/escher/include/escher/scroll_view.h b/escher/include/escher/scroll_view.h index 23713f944..2c95a0de2 100644 --- a/escher/include/escher/scroll_view.h +++ b/escher/include/escher/scroll_view.h @@ -8,7 +8,7 @@ public: ScrollView(View * contentView); int numberOfSubviews() const override; - const View * subview(int index) const override; + View * subview(int index) override; void storeSubviewAtIndex(View * view, int index) override; void layoutSubviews() override; diff --git a/escher/include/escher/tab_view.h b/escher/include/escher/tab_view.h index 58b6b6507..c57d71191 100644 --- a/escher/include/escher/tab_view.h +++ b/escher/include/escher/tab_view.h @@ -10,7 +10,7 @@ class TabView : public View { public: TabView(); int numberOfSubviews() const override; - const View * subview(int index) const override; + View * subview(int index) override; void layoutSubviews() override; void addTabNamed(const char * name); diff --git a/escher/include/escher/tab_view_controller.h b/escher/include/escher/tab_view_controller.h index 7b5b994ec..49aefd888 100644 --- a/escher/include/escher/tab_view_controller.h +++ b/escher/include/escher/tab_view_controller.h @@ -22,7 +22,7 @@ private: ContentView(); int numberOfSubviews() const override; - const View * subview(int index) const override; + View * subview(int index) override; void storeSubviewAtIndex(View * view, int index) override; void layoutSubviews() override; diff --git a/escher/include/escher/view.h b/escher/include/escher/view.h index a3121509e..1dbbb0356 100644 --- a/escher/include/escher/view.h +++ b/escher/include/escher/view.h @@ -22,6 +22,7 @@ extern "C" { class Window; class View { + friend class Window; public: View(); @@ -30,12 +31,17 @@ public: //void addSubview(View * subview); //void removeFromSuperview(); void setFrame(KDRect frame); + + void markAsNeedingRedraw(); + /* + void markAsDirty() const; void redraw() const; + */ void setSubview(View * v, int index); KDRect bounds() const; #if ESCHER_VIEW_LOGGING - friend std::ostream &operator<<(std::ostream &os, const View &view); + friend std::ostream &operator<<(std::ostream &os, View &view); #endif protected: #if ESCHER_VIEW_LOGGING @@ -44,15 +50,16 @@ protected: #endif virtual const Window * window() const; virtual int numberOfSubviews() const = 0; - virtual const View * subview(int index) const = 0; + virtual View * subview(int index) = 0; virtual void storeSubviewAtIndex(View * v, int index) = 0; virtual void layoutSubviews() = 0; private: - void redraw(KDRect rect) const; + void redraw(KDRect rect); KDRect absoluteDrawingArea() const; View * m_superview; KDRect m_frame; + bool m_needsRedraw; //TODO: We may want a dynamic size at some point /* static constexpr uint8_t k_maxNumberOfSubviews = 4; diff --git a/escher/include/escher/window.h b/escher/include/escher/window.h index b1eb28615..dc53e43b1 100644 --- a/escher/include/escher/window.h +++ b/escher/include/escher/window.h @@ -6,13 +6,14 @@ class Window : public View { public: Window(); + void redraw(); protected: #if ESCHER_VIEW_LOGGING const char * className() const override; #endif const Window * window() const override; int numberOfSubviews() const override; - const View * subview(int index) const override; + View * subview(int index) override; void layoutSubviews() override; void storeSubviewAtIndex(View * view, int index) override; private: diff --git a/escher/src/app.cpp b/escher/src/app.cpp index 3549fa387..ba1863f36 100644 --- a/escher/src/app.cpp +++ b/escher/src/app.cpp @@ -17,6 +17,7 @@ void App::run() { while (true) { ion_event_t event = ion_get_event(); // This is a blocking call dispatchEvent(event); + window.redraw(); } } diff --git a/escher/src/childless_view.cpp b/escher/src/childless_view.cpp index 9374b81df..01395f11c 100644 --- a/escher/src/childless_view.cpp +++ b/escher/src/childless_view.cpp @@ -7,7 +7,7 @@ int ChildlessView::numberOfSubviews() const { return 0; } -const View * ChildlessView::subview(int index) const { +View * ChildlessView::subview(int index) { assert(false); return nullptr; } diff --git a/escher/src/scroll_view.cpp b/escher/src/scroll_view.cpp index 925382a93..25f52488c 100644 --- a/escher/src/scroll_view.cpp +++ b/escher/src/scroll_view.cpp @@ -16,7 +16,7 @@ int ScrollView::numberOfSubviews() const { return 1; } -const View * ScrollView::subview(int index) const { +View * ScrollView::subview(int index) { assert(index == 0); return m_contentView; } diff --git a/escher/src/scroll_view_indicator.cpp b/escher/src/scroll_view_indicator.cpp index 2f4dd7382..c6c8e5772 100644 --- a/escher/src/scroll_view_indicator.cpp +++ b/escher/src/scroll_view_indicator.cpp @@ -34,12 +34,12 @@ void ScrollViewIndicator::drawRect(KDRect rect) const { void ScrollViewIndicator::setStart(float start) { m_start = start; - redraw(); + markAsNeedingRedraw(); } void ScrollViewIndicator::setEnd(float end) { m_end = end; - redraw(); + markAsNeedingRedraw(); } #if ESCHER_VIEW_LOGGING diff --git a/escher/src/tab_view.cpp b/escher/src/tab_view.cpp index 614407b21..1ab5c648c 100644 --- a/escher/src/tab_view.cpp +++ b/escher/src/tab_view.cpp @@ -17,7 +17,7 @@ void TabView::addTabNamed(const char * name) { m_cells[tabIndex].setName(name); m_numberOfTabs++; setSubview(&m_cells[tabIndex], tabIndex); - redraw(); + markAsNeedingRedraw(); } void TabView::setActiveIndex(int index) { @@ -34,7 +34,7 @@ int TabView::numberOfSubviews() const { return m_numberOfTabs; } -const View * TabView::subview(int index) const { +View * TabView::subview(int index) { assert(index < m_numberOfTabs); return &m_cells[index]; } diff --git a/escher/src/tab_view_cell.cpp b/escher/src/tab_view_cell.cpp index 448c232a9..c418f6026 100644 --- a/escher/src/tab_view_cell.cpp +++ b/escher/src/tab_view_cell.cpp @@ -12,12 +12,12 @@ TabViewCell::TabViewCell() : void TabViewCell::setName(const char * name) { m_name = name; - redraw(); + markAsNeedingRedraw(); } void TabViewCell::setActive(bool active) { m_active = active; - redraw(); + markAsNeedingRedraw(); } void TabViewCell::drawRect(KDRect rect) const { diff --git a/escher/src/tab_view_controller.cpp b/escher/src/tab_view_controller.cpp index c4da7a601..da2e9eee1 100644 --- a/escher/src/tab_view_controller.cpp +++ b/escher/src/tab_view_controller.cpp @@ -37,7 +37,7 @@ int TabViewController::ContentView::numberOfSubviews() const { return 2; } -const View * TabViewController::ContentView::subview(int index) const { +View * TabViewController::ContentView::subview(int index) { if (index == 0) { return &m_tabView; } else { @@ -111,7 +111,7 @@ void TabViewController::setActiveTab(uint8_t i) { m_view.setActiveView(activeVC->view()); m_view.m_tabView.setActiveIndex(i); m_activeChildIndex = i; - m_view.redraw(); + m_view.markAsNeedingRedraw(); } View * TabViewController::view() { diff --git a/escher/src/view.cpp b/escher/src/view.cpp index 5707b8176..59d3fcd8f 100644 --- a/escher/src/view.cpp +++ b/escher/src/view.cpp @@ -5,13 +5,9 @@ extern "C" { View::View() : m_superview(nullptr), - m_frame(KDRectZero) + m_frame(KDRectZero), + m_needsRedraw(true) { - /* - for (uint8_t i=0; imarkAsNeedingRedraw(); + } } -void View::redraw(KDRect rect) const { - if (window() == nullptr) { +void View::redraw(KDRect rect) { + /* CAUTION: do NOT call redraw directly. + * This may seem to work, but will not. Namely, it won't clip. + * Example : our superview is smaller than we are. If we redraw ourself, we + * will overflow our superview. */ + + if (window() == nullptr || !m_needsRedraw) { return; } - // Fisrt, let's draw our own content by calling drawRect + // First, let's draw our own content by calling drawRect KDSetDrawingArea(absoluteDrawingArea()); this->drawRect(rect); + // Then, let's recursively draw our children over ourself for (uint8_t i=0; isubview(i); + View * subview = this->subview(i); if (subview == nullptr) { continue; } @@ -53,13 +64,16 @@ void View::redraw(KDRect rect) const { subview->redraw(intersection); } } + + // Eventually, mark that we don't need to be redrawn + m_needsRedraw = false; } void View::setSubview(View * view, int index) { view->m_superview = this; storeSubviewAtIndex(view, index); assert(subview(index) == view); - redraw(); + view->markAsNeedingRedraw(); } /* @@ -98,16 +112,18 @@ void View::removeFromSuperview() { void View::setFrame(KDRect frame) { // TODO: Return if frame is equal to m_frame - KDRect previousFrame = m_frame; m_frame = frame; if (m_superview != nullptr) { /* We have moved this view. This left a blank spot in its superview were it - * previously was. So let's redraw that part of the superview. */ - m_superview->redraw(previousFrame); + * previously was. + * At this point, we know that the only area that really needs to be redrawn + * in the superview is the value of m_frame at the start of that method. + * However, let's not try to optimize too early, and let's simply mark the + * whole superview as needing redraw. */ + m_superview->markAsNeedingRedraw(); } layoutSubviews(); - // The view now needs to redraw itself entirely - redraw(); + markAsNeedingRedraw(); } KDRect View::bounds() const { @@ -141,7 +157,7 @@ void View::logAttributes(std::ostream &os) const { os << " frame=\"" << m_frame.x << "," << m_frame.y << "," << m_frame.width << "," << m_frame.height << "\""; } -std::ostream &operator<<(std::ostream &os, const View &view) { +std::ostream &operator<<(std::ostream &os, View &view) { os << "<" << view.className(); view.logAttributes(os); os << ">"; diff --git a/escher/src/window.cpp b/escher/src/window.cpp index 588a671d7..7057463b8 100644 --- a/escher/src/window.cpp +++ b/escher/src/window.cpp @@ -8,6 +8,10 @@ Window::Window() : { } +void Window::redraw() { + View::redraw(bounds()); +} + const Window * Window::window() const { return this; } @@ -16,7 +20,7 @@ int Window::numberOfSubviews() const { return (m_contentView == nullptr ? 0 : 1); } -const View * Window::subview(int index) const { +View * Window::subview(int index) { assert(m_contentView != nullptr && index == 0); return m_contentView; }