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