Numworks Epsilon  1.4.1
Graphing Calculator Operating System
view.cpp
Go to the documentation of this file.
1 extern "C" {
2 #include <assert.h>
3 }
4 #include <escher/view.h>
5 
7  m_frame(KDRectZero),
8  m_superview(nullptr),
9  m_dirtyRect(KDRectZero)
10 {
11 }
12 
14  for (int i = 0; i < numberOfSubviews(); i++) {
15  View * subview = subviewAtIndex(i);
16  if (subview != nullptr) {
17  subview->m_superview = nullptr;
18  }
19  }
20 }
21 
23  m_superview = nullptr;
24 }
25 
26 void View::drawRect(KDContext * ctx, KDRect rect) const {
27  // By default, a view doesn't do anything
28  // It's transparent!
29 }
30 
31 const Window * View::window() const {
32  if (m_superview == nullptr) {
33  return nullptr;
34  } else {
35  return m_superview->window();
36  }
37 }
38 
40  m_dirtyRect = m_dirtyRect.unionedWith(rect);
41 }
42 
43 KDRect View::redraw(KDRect rect, KDRect forceRedrawRect) {
44  /* View::redraw recursively redraws the rectangle 'rect' of the view and all
45  * its subviews.
46  * To optimize the function, we redraw only the union of the current dirty
47  * rectangle with a rectangle forced to be redrawn (forceRedrawRect). This
48  * rectangle is initially empty and recursively expands by unioning with the
49  * rectangles that are redrawn. This process handles the case when several
50  * sister views are overlapping (provided that the sister views are indexed in
51  * the right order).
52  */
53  if (window() == nullptr) {
54  /* That view (and all of its subviews) is offscreen. That means so are all
55  * of its subviews. So there's no point in drawing them. */
56  return KDRectZero;
57  }
58 
59  /* First, for the current view, the rectangle to redraw is the union of the
60  * dirty rectangle and the rectangle forced to be redrawn. The rectangle to
61  * redraw must also be included in the current view bounds and in the
62  * rectangle rect. */
63  KDRect rectNeedingRedraw = rect
64  .intersectedWith(m_dirtyRect)
65  .unionedWith(forceRedrawRect
66  .intersectedWith(bounds()));
67 
68  // This redraws the rectNeedingRedraw calling drawRect.
69  if (!rectNeedingRedraw.isEmpty()) {
70  KDPoint absOrigin = absoluteOrigin();
71  KDRect absRect = rectNeedingRedraw.translatedBy(absOrigin);
72  KDRect absClippingRect = absoluteVisibleFrame().intersectedWith(absRect);
74  ctx->setOrigin(absOrigin);
75  ctx->setClippingRect(absClippingRect);
76  this->drawRect(ctx, rectNeedingRedraw);
77  }
78  // This initializes the area that has been redrawn.
79  KDRect redrawnArea = rectNeedingRedraw;
80 
81  // Then, let's recursively draw our children over ourself
82  for (uint8_t i=0; i<numberOfSubviews(); i++) {
83  View * subview = this->subview(i);
84  if (subview == nullptr) {
85  continue;
86  }
87  assert(subview->m_superview == this);
88 
89  // We transpose rect and forcedRedrawArea in the subview coordinates.
90  KDRect intersectionInSubview = rect
93  KDRect forcedRedrawAreaInSubview = redrawnArea
95 
96  // We redraw the current subview by passing the rectangle previously redrawn
97  // (by the parent view or previous sister views) as forced to be redraw.
98  KDRect subviewRedrawnArea =
99  subview->redraw(intersectionInSubview, forcedRedrawAreaInSubview);
100 
101  // We expand the redrawn area to include the area just drawn.
102  redrawnArea = redrawnArea.unionedWith(subviewRedrawnArea.translatedBy(subview->m_frame.origin()));
103  }
104  // Eventually, mark that we don't need to be redrawn
105  m_dirtyRect = KDRectZero;
106 
107  // The function returns the total area that have been redrawn.
108  return redrawnArea;
109 }
110 
111 View * View::subview(int index) {
112  assert(index >= 0 && index < numberOfSubviews());
113  View * subview = subviewAtIndex(index);
114  if (subview != nullptr) {
115  subview->m_superview = this;
116  }
117  return subview;
118 }
119 
120 void View::setSize(KDSize size) {
121  setFrame(KDRect(m_frame.origin(), size));
122 }
123 
124 
125 void View::setFrame(KDRect frame) {
126  if (frame == m_frame) {
127  return;
128  }
129  /* CAUTION: This code is not resilient to multiple consecutive setFrame()
130  * calls without intermediate redraw() calls. */
131 
132  // TODO: Return if frame is equal to m_frame
133  if (m_superview != nullptr) {
134  /* We will move this view. This will leave a blank spot in its superview
135  * were it previously was.
136  * At this point, we know that the only area that really needs to be redrawn
137  * in the superview is the value of m_frame at the start of that method. */
138  m_superview->markRectAsDirty(m_frame);
139  }
140 
141  m_frame = frame;
142 
143  /* Now that we have moved, we have also dirtied our new absolute frame.
144  * There are two ways to declare this, which are semantically equivalent: we
145  * can either mark an area of our superview as dirty, or mark our whole frame
146  * as dirty. We pick the second option because it is more efficient. */
148  // FIXME: m_dirtyRect = bounds(); would be more correct (in case the view is being shrinked)
149 
150  layoutSubviews();
151 }
152 
154  return point.translatedBy(view->absoluteOrigin().translatedBy(absoluteOrigin().opposite()));
155 }
156 
158  return m_frame.movedTo(KDPointZero);
159 }
160 
161 KDPoint View::absoluteOrigin() const {
162  if (m_superview == nullptr) {
163  assert(this == (View *)window());
164  return m_frame.origin();
165  } else {
166  return m_frame.origin().translatedBy(m_superview->absoluteOrigin());
167  }
168 }
169 
170 KDRect View::absoluteVisibleFrame() const {
171  if (m_superview == nullptr) {
172  assert(this == (View *)window());
173  return m_frame;
174  } else {
175  KDRect parentDrawingArea = m_superview->absoluteVisibleFrame();
176 
177  KDRect absoluteFrame = m_frame.movedTo(absoluteOrigin());
178 
179  return absoluteFrame.intersectedWith(parentDrawingArea);
180  }
181 }
182 
184  return KDSizeZero;
185 }
186 
187 int View::numberOfSubviews() const {
188  return 0;
189 }
190 
191 View * View::subviewAtIndex(int index) {
192  assert(false);
193  return nullptr;
194 }
195 
196 void View::layoutSubviews() {
197 }
198 
199 
200 #if ESCHER_VIEW_LOGGING
201 const char * View::className() const {
202  return "View";
203 }
204 
205 void View::logAttributes(std::ostream &os) const {
206  os << " address=\"" << this << "\"";
207  os << " frame=\"" << m_frame.x << "," << m_frame.y << "," << m_frame.width << "," << m_frame.height << "\"";
208 }
209 
210 std::ostream &operator<<(std::ostream &os, View &view) {
211  os << "<" << view.className();
212  view.logAttributes(os);
213  os << ">";
214  for (int i=0; i<view.numberOfSubviews(); i++) {
215  assert(view.subview(i)->m_superview == &view);
216  os << *view.subview(i);
217  }
218  os << "</" << view.className() << ">";
219  return os;
220 }
221 #endif
222 
KDRect translatedBy(KDPoint p) const
Definition: rect.cpp:108
#define assert(e)
Definition: assert.h:9
Definition: window.h:6
KDCoordinate x() const
Definition: rect.h:36
void setFrame(KDRect frame)
Definition: view.cpp:125
void markRectAsDirty(KDRect rect)
Definition: view.cpp:39
bool isEmpty() const
Definition: rect.cpp:116
virtual ~View()
Definition: view.cpp:13
constexpr KDPoint KDPointZero
Definition: point.h:25
unsigned char uint8_t
Definition: stdint.h:4
void setOrigin(KDPoint origin)
Definition: context.cpp:10
virtual void drawRect(KDContext *ctx, KDRect rect) const
Definition: view.cpp:26
KDRect unionedWith(const KDRect &other) const
Definition: rect.cpp:71
Definition: point.h:6
void setSize(KDSize size)
Definition: view.cpp:120
Definition: size.h:6
KDRect m_frame
Definition: view.h:66
static KDIonContext * sharedContext()
Definition: ion_context.cpp:4
void setClippingRect(KDRect clippingRect)
Definition: context.cpp:14
KDCoordinate y() const
Definition: rect.h:37
virtual KDSize minimalSizeForOptimalDisplay() const
Definition: view.cpp:183
constexpr KDRect KDRectZero
Definition: rect.h:70
Definition: rect.h:26
constexpr KDSize KDSizeZero
Definition: size.h:17
View()
Definition: view.cpp:6
Definition: view.h:23
KDPoint opposite() const
Definition: point.cpp:7
KDPoint origin() const
Definition: rect.h:38
KDCoordinate width() const
Definition: rect.h:39
KDRect movedTo(KDPoint p) const
Definition: rect.cpp:112
KDRect intersectedWith(const KDRect &other) const
Definition: rect.cpp:33
KDPoint translatedBy(KDPoint other) const
Definition: point.cpp:3
View * subview(int index)
Definition: view.cpp:111
void resetSuperview()
Definition: view.cpp:22
KDCoordinate height() const
Definition: rect.h:40
KDRect bounds() const
Definition: view.cpp:157
KDPoint pointFromPointInView(View *view, KDPoint point)
Definition: view.cpp:153