|
1 |
|
2 /* |
|
3 * Copyright 2006 The Android Open Source Project |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 |
|
10 #ifndef SkView_DEFINED |
|
11 #define SkView_DEFINED |
|
12 |
|
13 #include "SkEventSink.h" |
|
14 #include "SkRect.h" |
|
15 #include "SkDOM.h" |
|
16 #include "SkTDict.h" |
|
17 #include "SkMatrix.h" |
|
18 #include "SkMetaData.h" |
|
19 |
|
20 class SkCanvas; |
|
21 class SkLayerView; |
|
22 |
|
23 /** \class SkView |
|
24 |
|
25 SkView is the base class for screen management. All widgets and controls inherit |
|
26 from SkView. |
|
27 */ |
|
28 class SkView : public SkEventSink { |
|
29 public: |
|
30 enum Flag_Shift { |
|
31 kVisible_Shift, |
|
32 kEnabled_Shift, |
|
33 kFocusable_Shift, |
|
34 kFlexH_Shift, |
|
35 kFlexV_Shift, |
|
36 kNoClip_Shift, |
|
37 |
|
38 kFlagShiftCount |
|
39 }; |
|
40 enum Flag_Mask { |
|
41 kVisible_Mask = 1 << kVisible_Shift, //!< set if the view is visible |
|
42 kEnabled_Mask = 1 << kEnabled_Shift, //!< set if the view is enabled |
|
43 kFocusable_Mask = 1 << kFocusable_Shift, //!< set if the view can receive focus |
|
44 kFlexH_Mask = 1 << kFlexH_Shift, //!< set if the view's width is stretchable |
|
45 kFlexV_Mask = 1 << kFlexV_Shift, //!< set if the view's height is stretchable |
|
46 kNoClip_Mask = 1 << kNoClip_Shift, //!< set if the view is not clipped to its bounds |
|
47 |
|
48 kAllFlagMasks = (uint32_t)(0 - 1) >> (32 - kFlagShiftCount) |
|
49 }; |
|
50 |
|
51 SkView(uint32_t flags = 0); |
|
52 virtual ~SkView(); |
|
53 |
|
54 /** Return the flags associated with the view |
|
55 */ |
|
56 uint32_t getFlags() const { return fFlags; } |
|
57 /** Set the flags associated with the view |
|
58 */ |
|
59 void setFlags(uint32_t flags); |
|
60 |
|
61 /** Helper that returns non-zero if the kVisible_Mask bit is set in the view's flags |
|
62 */ |
|
63 int isVisible() const { return fFlags & kVisible_Mask; } |
|
64 int isEnabled() const { return fFlags & kEnabled_Mask; } |
|
65 int isFocusable() const { return fFlags & kFocusable_Mask; } |
|
66 int isClipToBounds() const { return !(fFlags & kNoClip_Mask); } |
|
67 /** Helper to set/clear the view's kVisible_Mask flag */ |
|
68 void setVisibleP(bool); |
|
69 void setEnabledP(bool); |
|
70 void setFocusableP(bool); |
|
71 void setClipToBounds(bool); |
|
72 |
|
73 /** Return the view's width */ |
|
74 SkScalar width() const { return fWidth; } |
|
75 /** Return the view's height */ |
|
76 SkScalar height() const { return fHeight; } |
|
77 /** Set the view's width and height. These must both be >= 0. This does not affect the view's loc */ |
|
78 void setSize(SkScalar width, SkScalar height); |
|
79 void setSize(const SkPoint& size) { this->setSize(size.fX, size.fY); } |
|
80 void setWidth(SkScalar width) { this->setSize(width, fHeight); } |
|
81 void setHeight(SkScalar height) { this->setSize(fWidth, height); } |
|
82 /** Return a rectangle set to [0, 0, width, height] */ |
|
83 void getLocalBounds(SkRect* bounds) const; |
|
84 |
|
85 /** Loc - the view's offset with respect to its parent in its view hiearchy. |
|
86 NOTE: For more complex transforms, use Local Matrix. The tranformations |
|
87 are applied in the following order: |
|
88 canvas->translate(fLoc.fX, fLoc.fY); |
|
89 canvas->concat(fMatrix); |
|
90 */ |
|
91 /** Return the view's left edge */ |
|
92 SkScalar locX() const { return fLoc.fX; } |
|
93 /** Return the view's top edge */ |
|
94 SkScalar locY() const { return fLoc.fY; } |
|
95 /** Set the view's left and top edge. This does not affect the view's size */ |
|
96 void setLoc(SkScalar x, SkScalar y); |
|
97 void setLoc(const SkPoint& loc) { this->setLoc(loc.fX, loc.fY); } |
|
98 void setLocX(SkScalar x) { this->setLoc(x, fLoc.fY); } |
|
99 void setLocY(SkScalar y) { this->setLoc(fLoc.fX, y); } |
|
100 |
|
101 /** Local Matrix - matrix used to tranform the view with respect to its |
|
102 parent in its view hiearchy. Use setLocalMatrix to apply matrix |
|
103 transformations to the current view and in turn affect its children. |
|
104 NOTE: For simple offsets, use Loc. The transformations are applied in |
|
105 the following order: |
|
106 canvas->translate(fLoc.fX, fLoc.fY); |
|
107 canvas->concat(fMatrix); |
|
108 */ |
|
109 const SkMatrix& getLocalMatrix() const { return fMatrix; } |
|
110 void setLocalMatrix(const SkMatrix& matrix); |
|
111 |
|
112 /** Offset (move) the view by the specified dx and dy. This does not affect the view's size */ |
|
113 void offset(SkScalar dx, SkScalar dy); |
|
114 |
|
115 /** Call this to have the view draw into the specified canvas. */ |
|
116 virtual void draw(SkCanvas* canvas); |
|
117 |
|
118 /** Call this to invalidate part of all of a view, requesting that the view's |
|
119 draw method be called. The rectangle parameter specifies the part of the view |
|
120 that should be redrawn. If it is null, it specifies the entire view bounds. |
|
121 */ |
|
122 void inval(SkRect* rectOrNull); |
|
123 |
|
124 // Focus management |
|
125 |
|
126 SkView* getFocusView() const; |
|
127 bool hasFocus() const; |
|
128 |
|
129 enum FocusDirection { |
|
130 kNext_FocusDirection, |
|
131 kPrev_FocusDirection, |
|
132 |
|
133 kFocusDirectionCount |
|
134 }; |
|
135 bool acceptFocus(); |
|
136 SkView* moveFocus(FocusDirection); |
|
137 |
|
138 // Click handling |
|
139 |
|
140 class Click { |
|
141 public: |
|
142 Click(SkView* target); |
|
143 virtual ~Click(); |
|
144 |
|
145 const char* getType() const { return fType; } |
|
146 bool isType(const char type[]) const; |
|
147 void setType(const char type[]); // does NOT make a copy of the string |
|
148 void copyType(const char type[]); // makes a copy of the string |
|
149 |
|
150 enum State { |
|
151 kDown_State, |
|
152 kMoved_State, |
|
153 kUp_State |
|
154 }; |
|
155 SkPoint fOrig, fPrev, fCurr; |
|
156 SkIPoint fIOrig, fIPrev, fICurr; |
|
157 State fState; |
|
158 void* fOwner; |
|
159 unsigned fModifierKeys; |
|
160 |
|
161 SkMetaData fMeta; |
|
162 private: |
|
163 SkEventSinkID fTargetID; |
|
164 char* fType; |
|
165 bool fWeOwnTheType; |
|
166 |
|
167 void resetType(); |
|
168 |
|
169 friend class SkView; |
|
170 }; |
|
171 Click* findClickHandler(SkScalar x, SkScalar y, unsigned modifierKeys); |
|
172 |
|
173 static void DoClickDown(Click*, int x, int y, unsigned modi); |
|
174 static void DoClickMoved(Click*, int x, int y, unsigned modi); |
|
175 static void DoClickUp(Click*, int x, int y, unsigned modi); |
|
176 |
|
177 /** Send the event to the view's parent, and its parent etc. until one of them |
|
178 returns true from its onEvent call. This view is returned. If no parent handles |
|
179 the event, null is returned. |
|
180 */ |
|
181 SkView* sendEventToParents(const SkEvent&); |
|
182 /** Send the query to the view's parent, and its parent etc. until one of them |
|
183 returns true from its onQuery call. This view is returned. If no parent handles |
|
184 the query, null is returned. |
|
185 */ |
|
186 SkView* sendQueryToParents(SkEvent*); |
|
187 |
|
188 // View hierarchy management |
|
189 |
|
190 /** Return the view's parent, or null if it has none. This does not affect the parent's reference count. */ |
|
191 SkView* getParent() const { return fParent; } |
|
192 SkView* attachChildToFront(SkView* child); |
|
193 /** Attach the child view to this view, and increment the child's reference count. The child view is added |
|
194 such that it will be drawn before all other child views. |
|
195 The child view parameter is returned. |
|
196 */ |
|
197 SkView* attachChildToBack(SkView* child); |
|
198 /** If the view has a parent, detach the view from its parent and decrement the view's reference count. |
|
199 If the parent was the only owner of the view, this will cause the view to be deleted. |
|
200 */ |
|
201 void detachFromParent(); |
|
202 /** Attach the child view to this view, and increment the child's reference count. The child view is added |
|
203 such that it will be drawn after all other child views. |
|
204 The child view parameter is returned. |
|
205 */ |
|
206 /** Detach all child views from this view. */ |
|
207 void detachAllChildren(); |
|
208 |
|
209 /** Convert the specified point from global coordinates into view-local coordinates |
|
210 * Return true on success; false on failure |
|
211 */ |
|
212 bool globalToLocal(SkPoint* pt) const { |
|
213 if (NULL != pt) { |
|
214 return this->globalToLocal(pt->fX, pt->fY, pt); |
|
215 } |
|
216 return true; // nothing to do so return true |
|
217 } |
|
218 /** Convert the specified x,y from global coordinates into view-local coordinates, returning |
|
219 the answer in the local parameter. |
|
220 */ |
|
221 bool globalToLocal(SkScalar globalX, SkScalar globalY, SkPoint* local) const; |
|
222 |
|
223 /** \class F2BIter |
|
224 |
|
225 Iterator that will return each of this view's children, in |
|
226 front-to-back order (the order used for clicking). The first |
|
227 call to next() returns the front-most child view. When |
|
228 next() returns null, there are no more child views. |
|
229 */ |
|
230 class F2BIter { |
|
231 public: |
|
232 F2BIter(const SkView* parent); |
|
233 SkView* next(); |
|
234 private: |
|
235 SkView* fFirstChild, *fChild; |
|
236 }; |
|
237 |
|
238 /** \class B2FIter |
|
239 |
|
240 Iterator that will return each of this view's children, in |
|
241 back-to-front order (the order they are drawn). The first |
|
242 call to next() returns the back-most child view. When |
|
243 next() returns null, there are no more child views. |
|
244 */ |
|
245 class B2FIter { |
|
246 public: |
|
247 B2FIter(const SkView* parent); |
|
248 SkView* next(); |
|
249 private: |
|
250 SkView* fFirstChild, *fChild; |
|
251 }; |
|
252 |
|
253 /** \class Artist |
|
254 |
|
255 Install a subclass of this in a view (calling setArtist()), and then the |
|
256 default implementation of that view's onDraw() will invoke this object |
|
257 automatically. |
|
258 */ |
|
259 class Artist : public SkRefCnt { |
|
260 public: |
|
261 SK_DECLARE_INST_COUNT(Artist) |
|
262 |
|
263 void draw(SkView*, SkCanvas*); |
|
264 void inflate(const SkDOM&, const SkDOM::Node*); |
|
265 protected: |
|
266 virtual void onDraw(SkView*, SkCanvas*) = 0; |
|
267 virtual void onInflate(const SkDOM&, const SkDOM::Node*); |
|
268 private: |
|
269 typedef SkRefCnt INHERITED; |
|
270 }; |
|
271 /** Return the artist attached to this view (or null). The artist's reference |
|
272 count is not affected. |
|
273 */ |
|
274 Artist* getArtist() const; |
|
275 /** Attach the specified artist (or null) to the view, replacing any existing |
|
276 artist. If the new artist is not null, its reference count is incremented. |
|
277 The artist parameter is returned. |
|
278 */ |
|
279 Artist* setArtist(Artist* artist); |
|
280 |
|
281 /** \class Layout |
|
282 |
|
283 Install a subclass of this in a view (calling setLayout()), and then the |
|
284 default implementation of that view's onLayoutChildren() will invoke |
|
285 this object automatically. |
|
286 */ |
|
287 class Layout : public SkRefCnt { |
|
288 public: |
|
289 SK_DECLARE_INST_COUNT(Layout) |
|
290 |
|
291 void layoutChildren(SkView* parent); |
|
292 void inflate(const SkDOM&, const SkDOM::Node*); |
|
293 protected: |
|
294 virtual void onLayoutChildren(SkView* parent) = 0; |
|
295 virtual void onInflate(const SkDOM&, const SkDOM::Node*); |
|
296 private: |
|
297 typedef SkRefCnt INHERITED; |
|
298 }; |
|
299 |
|
300 /** Return the layout attached to this view (or null). The layout's reference |
|
301 count is not affected. |
|
302 */ |
|
303 Layout* getLayout() const; |
|
304 /** Attach the specified layout (or null) to the view, replacing any existing |
|
305 layout. If the new layout is not null, its reference count is incremented. |
|
306 The layout parameter is returned. |
|
307 */ |
|
308 Layout* setLayout(Layout*, bool invokeLayoutNow = true); |
|
309 /** If a layout is attached to this view, call its layoutChildren() method |
|
310 */ |
|
311 void invokeLayout(); |
|
312 |
|
313 /** Call this to initialize this view based on the specified XML node |
|
314 */ |
|
315 void inflate(const SkDOM& dom, const SkDOM::Node* node); |
|
316 /** After a view hierarchy is inflated, this may be called with a dictionary |
|
317 containing pairs of <name, view*>, where the name string was the view's |
|
318 "id" attribute when it was inflated. |
|
319 |
|
320 This will call the virtual onPostInflate for this view, and the recursively |
|
321 call postInflate on all of the view's children. |
|
322 */ |
|
323 void postInflate(const SkTDict<SkView*>& ids); |
|
324 |
|
325 SkDEBUGCODE(void dump(bool recurse) const;) |
|
326 |
|
327 protected: |
|
328 /** Override this to draw inside the view. Be sure to call the inherited version too */ |
|
329 virtual void onDraw(SkCanvas*); |
|
330 /** Override this to be notified when the view's size changes. Be sure to call the inherited version too */ |
|
331 virtual void onSizeChange(); |
|
332 /** Override this if you want to handle an inval request from this view or one of its children. |
|
333 Tyically this is only overridden by the by the "window". If your subclass does handle the |
|
334 request, return true so the request will not continue to propogate to the parent. |
|
335 */ |
|
336 virtual bool handleInval(const SkRect*); |
|
337 //! called once before all of the children are drawn (or clipped/translated) |
|
338 virtual SkCanvas* beforeChildren(SkCanvas* c) { return c; } |
|
339 //! called once after all of the children are drawn (or clipped/translated) |
|
340 virtual void afterChildren(SkCanvas* orig) {} |
|
341 |
|
342 //! called right before this child's onDraw is called |
|
343 virtual void beforeChild(SkView* child, SkCanvas* canvas) {} |
|
344 //! called right after this child's onDraw is called |
|
345 virtual void afterChild(SkView* child, SkCanvas* canvas) {} |
|
346 |
|
347 /** Override this if you might handle the click |
|
348 */ |
|
349 virtual Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi); |
|
350 /** Override this to decide if your children are targets for a click. |
|
351 The default returns true, in which case your children views will be |
|
352 candidates for onFindClickHandler. Returning false wil skip the children |
|
353 and just call your onFindClickHandler. |
|
354 */ |
|
355 virtual bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi); |
|
356 /** Override this to track clicks, returning true as long as you want to track |
|
357 the pen/mouse. |
|
358 */ |
|
359 virtual bool onClick(Click*); |
|
360 /** Override this to initialize your subclass from the XML node. Be sure to call the inherited version too */ |
|
361 virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); |
|
362 /** Override this if you want to perform post initialization work based on the ID dictionary built |
|
363 during XML parsing. Be sure to call the inherited version too. |
|
364 */ |
|
365 virtual void onPostInflate(const SkTDict<SkView*>&); |
|
366 |
|
367 public: |
|
368 #ifdef SK_DEBUG |
|
369 void validate() const; |
|
370 #else |
|
371 void validate() const {} |
|
372 #endif |
|
373 // default action is to inval the view |
|
374 virtual void onFocusChange(bool gainFocusP); |
|
375 |
|
376 protected: |
|
377 |
|
378 // override these if you're acting as a layer/host |
|
379 virtual bool onGetFocusView(SkView**) const { return false; } |
|
380 virtual bool onSetFocusView(SkView*) { return false; } |
|
381 |
|
382 private: |
|
383 SkScalar fWidth, fHeight; |
|
384 SkMatrix fMatrix; |
|
385 SkPoint fLoc; |
|
386 SkView* fParent; |
|
387 SkView* fFirstChild; |
|
388 SkView* fNextSibling; |
|
389 SkView* fPrevSibling; |
|
390 uint8_t fFlags; |
|
391 uint8_t fContainsFocus; |
|
392 |
|
393 friend class B2FIter; |
|
394 friend class F2BIter; |
|
395 |
|
396 friend class SkLayerView; |
|
397 |
|
398 bool setFocusView(SkView* fvOrNull); |
|
399 SkView* acceptFocus(FocusDirection); |
|
400 void detachFromParent_NoLayout(); |
|
401 /** Compute the matrix to transform view-local coordinates into global ones */ |
|
402 void localToGlobal(SkMatrix* matrix) const; |
|
403 }; |
|
404 |
|
405 #endif |