mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-23 07:40:42 +01:00
Escher: Use dirty-tracking for View::redraw
Change-Id: I95da4eee9218784744ac4abc53328d3f537bede6
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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; i<k_maxNumberOfSubviews; i++) {
|
||||
m_subviews[i] = nullptr;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void View::drawRect(KDRect rect) const {
|
||||
@@ -27,21 +23,36 @@ const Window * View::window() const {
|
||||
}
|
||||
}
|
||||
|
||||
void View::redraw() const {
|
||||
redraw(bounds());
|
||||
void View::markAsNeedingRedraw() {
|
||||
// Let's mark ourself as needing redraw
|
||||
m_needsRedraw = true;
|
||||
|
||||
/* And let's mark our parents as needing redraw too. The alternative would be
|
||||
* to have a recursive getter, which would be more resilient to superview
|
||||
* modification, but much slower too. As long as we don't change the view
|
||||
* hierarchy, this way is easier. */
|
||||
if (m_superview) {
|
||||
m_superview->markAsNeedingRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
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; i<numberOfSubviews(); i++) {
|
||||
const View * subview = this->subview(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 << ">";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user