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