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