blob: 17eb3800f47456d1f1bfecb04d7084a24396d072 [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"
reed76a834a2016-01-03 18:36:05 -080016#include "../private/SkTDict.h"
reed@google.comf03bb562011-11-11 21:42:12 +000017#include "SkMatrix.h"
mike@reedtribe.orge78dd4b2013-01-02 04:10:33 +000018#include "SkMetaData.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
20class SkCanvas;
21class SkLayerView;
22
23/** \class SkView
24
25 SkView is the base class for screen management. All widgets and controls inherit
26 from SkView.
27*/
28class SkView : public SkEventSink {
29public:
30 enum Flag_Shift {
31 kVisible_Shift,
32 kEnabled_Shift,
33 kFocusable_Shift,
34 kFlexH_Shift,
35 kFlexV_Shift,
reed@android.comf2b98d62010-12-20 18:26:13 +000036 kNoClip_Shift,
reed@android.com8a1c16f2008-12-17 15:59:43 +000037
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
reed@android.comf2b98d62010-12-20 18:26:13 +000046 kNoClip_Mask = 1 << kNoClip_Shift, //!< set if the view is not clipped to its bounds
reed@android.com8a1c16f2008-12-17 15:59:43 +000047
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; }
reed@android.comf2b98d62010-12-20 18:26:13 +000066 int isClipToBounds() const { return !(fFlags & kNoClip_Mask); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 /** Helper to set/clear the view's kVisible_Mask flag */
68 void setVisibleP(bool);
69 void setEnabledP(bool);
70 void setFocusableP(bool);
reed@android.comf2b98d62010-12-20 18:26:13 +000071 void setClipToBounds(bool);
reed@android.com8a1c16f2008-12-17 15:59:43 +000072
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
reed@google.comf03bb562011-11-11 21:42:12 +000085 /** Loc - the view's offset with respect to its parent in its view hiearchy.
rmistry@google.comfbfcd562012-08-23 18:09:54 +000086 NOTE: For more complex transforms, use Local Matrix. The tranformations
reed@google.comf03bb562011-11-11 21:42:12 +000087 are applied in the following order:
rmistry@google.comfbfcd562012-08-23 18:09:54 +000088 canvas->translate(fLoc.fX, fLoc.fY);
reed@google.comf03bb562011-11-11 21:42:12 +000089 canvas->concat(fMatrix);
90 */
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 /** 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); }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000100
101 /** Local Matrix - matrix used to tranform the view with respect to its
102 parent in its view hiearchy. Use setLocalMatrix to apply matrix
reed@google.comf03bb562011-11-11 21:42:12 +0000103 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:
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000106 canvas->translate(fLoc.fX, fLoc.fY);
reed@google.comf03bb562011-11-11 21:42:12 +0000107 canvas->concat(fMatrix);
108 */
109 const SkMatrix& getLocalMatrix() const { return fMatrix; }
110 void setLocalMatrix(const SkMatrix& matrix);
111
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 /** 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. */
reed@android.come522ca52009-11-23 20:10:41 +0000116 virtual void draw(SkCanvas* canvas);
117
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 /** 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;
Scroggod3aed392011-06-22 13:26:56 +0000158 void* fOwner;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000159 unsigned fModifierKeys;
mike@reedtribe.orge78dd4b2013-01-02 04:10:33 +0000160
161 SkMetaData fMeta;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 private:
163 SkEventSinkID fTargetID;
164 char* fType;
165 bool fWeOwnTheType;
166
167 void resetType();
168
169 friend class SkView;
170 };
reed@google.com4d5c26d2013-01-08 16:17:50 +0000171 Click* findClickHandler(SkScalar x, SkScalar y, unsigned modifierKeys);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172
reed@google.com4d5c26d2013-01-08 16:17:50 +0000173 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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176
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.
reed@android.com34245c72009-11-03 04:00:48 +0000180 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 SkView* sendEventToParents(const SkEvent&);
reed@android.com34245c72009-11-03 04:00:48 +0000182 /** 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 // 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
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000210 * Return true on success; false on failure
211 */
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000212 bool globalToLocal(SkPoint* pt) const {
bsalomon49f085d2014-09-05 13:34:00 -0700213 if (pt) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000214 return this->globalToLocal(pt->fX, pt->fY, pt);
215 }
216 return true; // nothing to do so return true
217 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 /** Convert the specified x,y from global coordinates into view-local coordinates, returning
219 the answer in the local parameter.
220 */
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000221 bool globalToLocal(SkScalar globalX, SkScalar globalY, SkPoint* local) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222
223 /** \class F2BIter
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 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
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 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
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000254
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 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:
mtklein2766c002015-06-26 11:45:03 -0700261
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000262
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 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*);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000268 private:
269 typedef SkRefCnt INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 };
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
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000282
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 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:
mtklein2766c002015-06-26 11:45:03 -0700289
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000290
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 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*);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000296 private:
297 typedef SkRefCnt INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 };
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
327protected:
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 */
reed@android.comf2b98d62010-12-20 18:26:13 +0000336 virtual bool handleInval(const SkRect*);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000337 //! called once before all of the children are drawn (or clipped/translated)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 virtual SkCanvas* beforeChildren(SkCanvas* c) { return c; }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000339 //! called once after all of the children are drawn (or clipped/translated)
djsollenc87dd2c2014-11-14 11:11:46 -0800340 virtual void afterChildren(SkCanvas*) {}
reed@android.com6c5f6f22009-08-14 16:08:38 +0000341
342 //! called right before this child's onDraw is called
djsollenc87dd2c2014-11-14 11:11:46 -0800343 virtual void beforeChild(SkView* /*child*/, SkCanvas*) {}
reed@android.com6c5f6f22009-08-14 16:08:38 +0000344 //! called right after this child's onDraw is called
djsollenc87dd2c2014-11-14 11:11:46 -0800345 virtual void afterChild(SkView* /*child*/, SkCanvas*) {}
reed@android.com6c5f6f22009-08-14 16:08:38 +0000346
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 /** Override this if you might handle the click
348 */
reed@google.com4d5c26d2013-01-08 16:17:50 +0000349 virtual Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi);
reed@android.come72fee52009-11-16 14:52:01 +0000350 /** 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 */
reed@google.com4d5c26d2013-01-08 16:17:50 +0000355 virtual bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 /** 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
367public:
reed@google.com079813e2013-06-14 17:46:07 +0000368#ifdef SK_DEBUG
369 void validate() const;
370#else
371 void validate() const {}
372#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373 // default action is to inval the view
374 virtual void onFocusChange(bool gainFocusP);
reed@google.com079813e2013-06-14 17:46:07 +0000375
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376protected:
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
382private:
383 SkScalar fWidth, fHeight;
reed@google.comf03bb562011-11-11 21:42:12 +0000384 SkMatrix fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385 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;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000395
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396 friend class SkLayerView;
397
398 bool setFocusView(SkView* fvOrNull);
399 SkView* acceptFocus(FocusDirection);
400 void detachFromParent_NoLayout();
reed@google.comf03bb562011-11-11 21:42:12 +0000401 /** Compute the matrix to transform view-local coordinates into global ones */
402 void localToGlobal(SkMatrix* matrix) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403};
404
405#endif