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