blob: 9c3e50f83267ceabfba2e16dc4bb89c455ba4147 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkView.h"
9#include "SkCanvas.h"
10
robertphillips@google.coma22e2112012-08-16 14:58:06 +000011SK_DEFINE_INST_COUNT(SkView::Artist)
12SK_DEFINE_INST_COUNT(SkView::Layout)
13
reed@android.com8a1c16f2008-12-17 15:59:43 +000014////////////////////////////////////////////////////////////////////////
15
16SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags))
17{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000018 fWidth = fHeight = 0;
19 fLoc.set(0, 0);
20 fParent = fFirstChild = fNextSibling = fPrevSibling = NULL;
reed@google.comf03bb562011-11-11 21:42:12 +000021 fMatrix.setIdentity();
robertphillips@google.coma22e2112012-08-16 14:58:06 +000022 fContainsFocus = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +000023}
24
25SkView::~SkView()
26{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000027 this->detachAllChildren();
reed@android.com8a1c16f2008-12-17 15:59:43 +000028}
29
30void SkView::setFlags(uint32_t flags)
31{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000032 SkASSERT((flags & ~kAllFlagMasks) == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000033
robertphillips@google.coma22e2112012-08-16 14:58:06 +000034 uint32_t diff = fFlags ^ flags;
reed@android.com8a1c16f2008-12-17 15:59:43 +000035
robertphillips@google.coma22e2112012-08-16 14:58:06 +000036 if (diff & kVisible_Mask)
37 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
robertphillips@google.coma22e2112012-08-16 14:58:06 +000039 fFlags = SkToU8(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
robertphillips@google.coma22e2112012-08-16 14:58:06 +000041 if (diff & kVisible_Mask)
42 {
43 this->inval(NULL);
44 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000045}
46
47void SkView::setVisibleP(bool pred)
48{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000049 this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
reed@android.com8a1c16f2008-12-17 15:59:43 +000050}
51
52void SkView::setEnabledP(bool pred)
53{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000054 this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
57void SkView::setFocusableP(bool pred)
58{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000059 this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
reed@android.com8a1c16f2008-12-17 15:59:43 +000060}
61
reed@android.comf2b98d62010-12-20 18:26:13 +000062void SkView::setClipToBounds(bool pred) {
63 this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
64}
65
reed@android.com8a1c16f2008-12-17 15:59:43 +000066void SkView::setSize(SkScalar width, SkScalar height)
67{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000068 width = SkMaxScalar(0, width);
69 height = SkMaxScalar(0, height);
reed@android.com8a1c16f2008-12-17 15:59:43 +000070
robertphillips@google.coma22e2112012-08-16 14:58:06 +000071 if (fWidth != width || fHeight != height)
72 {
73 this->inval(NULL);
74 fWidth = width;
75 fHeight = height;
76 this->inval(NULL);
77 this->onSizeChange();
78 this->invokeLayout();
79 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000080}
81
82void SkView::setLoc(SkScalar x, SkScalar y)
83{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000084 if (fLoc.fX != x || fLoc.fY != y)
85 {
reed@google.comf03bb562011-11-11 21:42:12 +000086 this->inval(NULL);
robertphillips@google.coma22e2112012-08-16 14:58:06 +000087 fLoc.set(x, y);
88 this->inval(NULL);
89 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000090}
91
92void SkView::offset(SkScalar dx, SkScalar dy)
93{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000094 if (dx || dy)
95 this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +000096}
97
rmistry@google.comd6176b02012-08-23 18:14:13 +000098void SkView::setLocalMatrix(const SkMatrix& matrix)
reed@google.comf03bb562011-11-11 21:42:12 +000099{
100 this->inval(NULL);
101 fMatrix = matrix;
102 this->inval(NULL);
103}
104
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105void SkView::draw(SkCanvas* canvas)
106{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000107 if (fWidth && fHeight && this->isVisible())
108 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000109 SkRect r;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000110 r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
111 if (this->isClipToBounds() &&
reed@google.com3b3e8952012-08-16 20:53:31 +0000112 canvas->quickReject(r)) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000113 return;
114 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115
rmistry@google.comd6176b02012-08-23 18:14:13 +0000116 SkAutoCanvasRestore as(canvas, true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117
reed@android.comf2b98d62010-12-20 18:26:13 +0000118 if (this->isClipToBounds()) {
119 canvas->clipRect(r);
120 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000121
122 canvas->translate(fLoc.fX, fLoc.fY);
reed@google.comf03bb562011-11-11 21:42:12 +0000123 canvas->concat(fMatrix);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000124
reed@android.com6c5f6f22009-08-14 16:08:38 +0000125 if (fParent) {
126 fParent->beforeChild(this, canvas);
127 }
reed@android.com562ea922010-02-08 21:45:03 +0000128
129 int sc = canvas->save();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000130 this->onDraw(canvas);
reed@android.com562ea922010-02-08 21:45:03 +0000131 canvas->restoreToCount(sc);
132
reed@android.com6c5f6f22009-08-14 16:08:38 +0000133 if (fParent) {
134 fParent->afterChild(this, canvas);
135 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000136
137 B2FIter iter(this);
138 SkView* child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139
140 SkCanvas* childCanvas = this->beforeChildren(canvas);
141
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000142 while ((child = iter.next()) != NULL)
143 child->draw(childCanvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 this->afterChildren(canvas);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000146 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147}
148
reed@android.comf2b98d62010-12-20 18:26:13 +0000149void SkView::inval(SkRect* rect) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000150 SkView* view = this;
reed@android.comf2b98d62010-12-20 18:26:13 +0000151 SkRect storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000153 for (;;) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000154 if (!view->isVisible()) {
155 return;
156 }
157 if (view->isClipToBounds()) {
158 SkRect bounds;
159 view->getLocalBounds(&bounds);
160 if (rect && !bounds.intersect(*rect)) {
161 return;
162 }
163 storage = bounds;
164 rect = &storage;
165 }
166 if (view->handleInval(rect)) {
167 return;
168 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000170 SkView* parent = view->fParent;
reed@android.comf2b98d62010-12-20 18:26:13 +0000171 if (parent == NULL) {
172 return;
173 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174
reed@android.comf2b98d62010-12-20 18:26:13 +0000175 if (rect) {
176 rect->offset(view->fLoc.fX, view->fLoc.fY);
177 }
178 view = parent;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000179 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180}
181
182////////////////////////////////////////////////////////////////////////////
183
184bool SkView::setFocusView(SkView* fv)
185{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000186 SkView* view = this;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000187
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000188 do {
189 if (view->onSetFocusView(fv))
190 return true;
191 } while ((view = view->fParent) != NULL);
192 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193}
194
195SkView* SkView::getFocusView() const
196{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000197 SkView* focus = NULL;
198 const SkView* view = this;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000199 do {
200 if (view->onGetFocusView(&focus))
201 break;
202 } while ((view = view->fParent) != NULL);
203 return focus;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204}
205
206bool SkView::hasFocus() const
207{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000208 return this == this->getFocusView();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209}
210
211bool SkView::acceptFocus()
212{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000213 return this->isFocusable() && this->setFocusView(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214}
215
216/*
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000217 Try to give focus to this view, or its children
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218*/
219SkView* SkView::acceptFocus(FocusDirection dir)
220{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000221 if (dir == kNext_FocusDirection)
222 {
223 if (this->acceptFocus())
224 return this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225
rmistry@google.comd6176b02012-08-23 18:14:13 +0000226 B2FIter iter(this);
227 SkView* child, *focus;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000228 while ((child = iter.next()) != NULL)
229 if ((focus = child->acceptFocus(dir)) != NULL)
230 return focus;
231 }
232 else // prev
233 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000234 F2BIter iter(this);
235 SkView* child, *focus;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000236 while ((child = iter.next()) != NULL)
237 if ((focus = child->acceptFocus(dir)) != NULL)
238 return focus;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000240 if (this->acceptFocus())
241 return this;
242 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000244 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245}
246
247SkView* SkView::moveFocus(FocusDirection dir)
248{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000249 SkView* focus = this->getFocusView();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000251 if (focus == NULL)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000252 { // start with the root
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000253 focus = this;
254 while (focus->fParent)
255 focus = focus->fParent;
256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257
rmistry@google.comd6176b02012-08-23 18:14:13 +0000258 SkView* child, *parent;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000260 if (dir == kNext_FocusDirection)
261 {
262 parent = focus;
263 child = focus->fFirstChild;
264 if (child)
265 goto FIRST_CHILD;
266 else
267 goto NEXT_SIB;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000269 do {
270 while (child != parent->fFirstChild)
271 {
272 FIRST_CHILD:
273 if ((focus = child->acceptFocus(dir)) != NULL)
274 return focus;
275 child = child->fNextSibling;
276 }
277 NEXT_SIB:
278 child = parent->fNextSibling;
279 parent = parent->fParent;
280 } while (parent != NULL);
281 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000282 else // prevfocus
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000283 {
284 parent = focus->fParent;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000285 if (parent == NULL) // we're the root
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000286 return focus->acceptFocus(dir);
287 else
288 {
289 child = focus;
290 while (parent)
291 {
292 while (child != parent->fFirstChild)
293 {
294 child = child->fPrevSibling;
295 if ((focus = child->acceptFocus(dir)) != NULL)
296 return focus;
297 }
298 if (parent->acceptFocus())
299 return parent;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000301 child = parent;
302 parent = parent->fParent;
303 }
304 }
305 }
306 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307}
308
309void SkView::onFocusChange(bool gainFocusP)
310{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000311 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312}
313
314////////////////////////////////////////////////////////////////////////////
315
316SkView::Click::Click(SkView* target)
317{
Scroggod3aed392011-06-22 13:26:56 +0000318 SkASSERT(target);
319 fTargetID = target->getSinkID();
320 fType = NULL;
321 fWeOwnTheType = false;
322 fOwner = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323}
324
325SkView::Click::~Click()
326{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000327 this->resetType();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328}
329
330void SkView::Click::resetType()
331{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000332 if (fWeOwnTheType)
333 {
334 sk_free(fType);
335 fWeOwnTheType = false;
336 }
337 fType = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338}
339
340bool SkView::Click::isType(const char type[]) const
341{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000342 const char* t = fType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000344 if (type == t)
345 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000347 if (type == NULL)
348 type = "";
349 if (t == NULL)
350 t = "";
351 return !strcmp(t, type);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352}
353
354void SkView::Click::setType(const char type[])
355{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000356 this->resetType();
357 fType = (char*)type;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358}
359
360void SkView::Click::copyType(const char type[])
361{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000362 if (fType != type)
363 {
364 this->resetType();
365 if (type)
366 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000367 size_t len = strlen(type) + 1;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000368 fType = (char*)sk_malloc_throw(len);
369 memcpy(fType, type, len);
370 fWeOwnTheType = true;
371 }
372 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373}
374
reed@google.com4d5c26d2013-01-08 16:17:50 +0000375SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y, unsigned modi) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000376 if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
377 return NULL;
reed@android.come72fee52009-11-16 14:52:01 +0000378 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379
reed@google.com4d5c26d2013-01-08 16:17:50 +0000380 if (this->onSendClickToChildren(x, y, modi)) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000381 F2BIter iter(this);
382 SkView* child;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000383
reed@android.come72fee52009-11-16 14:52:01 +0000384 while ((child = iter.next()) != NULL)
385 {
reed@google.comf03bb562011-11-11 21:42:12 +0000386 SkPoint p;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000387 if (!child->globalToLocal(x, y, &p)) {
388 continue;
389 }
390
reed@google.com4d5c26d2013-01-08 16:17:50 +0000391 Click* click = child->findClickHandler(p.fX, p.fY, modi);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000392
reed@android.come72fee52009-11-16 14:52:01 +0000393 if (click) {
394 return click;
395 }
396 }
397 }
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000398
reed@google.com4d5c26d2013-01-08 16:17:50 +0000399 return this->onFindClickHandler(x, y, modi);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400}
401
reed@google.com4d5c26d2013-01-08 16:17:50 +0000402void SkView::DoClickDown(Click* click, int x, int y, unsigned modi)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000404 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000406 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
407 if (NULL == target) {
408 return;
409 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000411 click->fIOrig.set(x, y);
412 click->fICurr = click->fIPrev = click->fIOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000414 click->fOrig.iset(x, y);
415 if (!target->globalToLocal(&click->fOrig)) {
416 // no history to let us recover from this failure
417 return;
418 }
419 click->fPrev = click->fCurr = click->fOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000421 click->fState = Click::kDown_State;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000422 click->fModifierKeys = modi;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000423 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424}
425
reed@google.com4d5c26d2013-01-08 16:17:50 +0000426void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000428 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000430 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
431 if (NULL == target) {
432 return;
433 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000435 click->fIPrev = click->fICurr;
436 click->fICurr.set(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000438 click->fPrev = click->fCurr;
439 click->fCurr.iset(x, y);
440 if (!target->globalToLocal(&click->fCurr)) {
441 // on failure pretend the mouse didn't move
442 click->fCurr = click->fPrev;
443 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000445 click->fState = Click::kMoved_State;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000446 click->fModifierKeys = modi;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000447 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448}
449
reed@google.com4d5c26d2013-01-08 16:17:50 +0000450void SkView::DoClickUp(Click* click, int x, int y, unsigned modi)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000452 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000454 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
455 if (NULL == target) {
456 return;
457 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000459 click->fIPrev = click->fICurr;
460 click->fICurr.set(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000462 click->fPrev = click->fCurr;
463 click->fCurr.iset(x, y);
464 if (!target->globalToLocal(&click->fCurr)) {
465 // on failure pretend the mouse didn't move
466 click->fCurr = click->fPrev;
467 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000469 click->fState = Click::kUp_State;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000470 click->fModifierKeys = modi;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000471 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000472}
473
474//////////////////////////////////////////////////////////////////////
475
reed@android.come72fee52009-11-16 14:52:01 +0000476void SkView::invokeLayout() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000477 SkView::Layout* layout = this->getLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000478
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000479 if (layout) {
480 layout->layoutChildren(this);
reed@android.come72fee52009-11-16 14:52:01 +0000481 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000482}
483
reed@android.come72fee52009-11-16 14:52:01 +0000484void SkView::onDraw(SkCanvas* canvas) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000485 Artist* artist = this->getArtist();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000486
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000487 if (artist) {
488 artist->draw(this, canvas);
reed@android.come72fee52009-11-16 14:52:01 +0000489 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490}
491
reed@android.come72fee52009-11-16 14:52:01 +0000492void SkView::onSizeChange() {}
493
reed@google.com4d5c26d2013-01-08 16:17:50 +0000494bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) {
reed@android.come72fee52009-11-16 14:52:01 +0000495 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496}
497
reed@google.com4d5c26d2013-01-08 16:17:50 +0000498SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000499 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500}
501
reed@android.come72fee52009-11-16 14:52:01 +0000502bool SkView::onClick(Click*) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000503 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504}
505
reed@android.comf2b98d62010-12-20 18:26:13 +0000506bool SkView::handleInval(const SkRect*) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000507 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000508}
509
510//////////////////////////////////////////////////////////////////////
511
reed@google.coma25c94e2013-06-13 20:20:17 +0000512void SkView::getLocalBounds(SkRect* bounds) const {
513 if (bounds) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000514 bounds->set(0, 0, fWidth, fHeight);
reed@google.coma25c94e2013-06-13 20:20:17 +0000515 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516}
517
518//////////////////////////////////////////////////////////////////////
519//////////////////////////////////////////////////////////////////////
520
reed@google.coma25c94e2013-06-13 20:20:17 +0000521void SkView::detachFromParent_NoLayout() {
522 this->validate();
523 if (fParent == NULL) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000524 return;
reed@google.coma25c94e2013-06-13 20:20:17 +0000525 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526
reed@google.coma25c94e2013-06-13 20:20:17 +0000527 if (fContainsFocus) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000528 (void)this->setFocusView(NULL);
reed@google.coma25c94e2013-06-13 20:20:17 +0000529 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000531 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532
reed@google.coma25c94e2013-06-13 20:20:17 +0000533 SkView* next = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
reed@google.coma25c94e2013-06-13 20:20:17 +0000535 if (fNextSibling != this) { // do we have any siblings
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000536 fNextSibling->fPrevSibling = fPrevSibling;
537 fPrevSibling->fNextSibling = fNextSibling;
538 next = fNextSibling;
539 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540
reed@google.coma25c94e2013-06-13 20:20:17 +0000541 if (fParent->fFirstChild == this) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000542 fParent->fFirstChild = next;
reed@google.coma25c94e2013-06-13 20:20:17 +0000543 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000545 fParent = fNextSibling = fPrevSibling = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000546
reed@google.coma25c94e2013-06-13 20:20:17 +0000547 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000548 this->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549}
550
reed@google.coma25c94e2013-06-13 20:20:17 +0000551void SkView::detachFromParent() {
552 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000553 SkView* parent = fParent;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554
reed@google.coma25c94e2013-06-13 20:20:17 +0000555 if (parent) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000556 this->detachFromParent_NoLayout();
557 parent->invokeLayout();
558 }
reed@google.coma25c94e2013-06-13 20:20:17 +0000559 this->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560}
561
reed@google.coma25c94e2013-06-13 20:20:17 +0000562SkView* SkView::attachChildToBack(SkView* child) {
563 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000564 SkASSERT(child != this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000566 if (child == NULL || fFirstChild == child)
567 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000568
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000569 child->ref();
570 child->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571
reed@google.coma25c94e2013-06-13 20:20:17 +0000572 if (fFirstChild == NULL) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000573 child->fNextSibling = child;
574 child->fPrevSibling = child;
reed@google.coma25c94e2013-06-13 20:20:17 +0000575 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000576 child->fNextSibling = fFirstChild;
577 child->fPrevSibling = fFirstChild->fPrevSibling;
578 fFirstChild->fPrevSibling->fNextSibling = child;
579 fFirstChild->fPrevSibling = child;
580 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000582 fFirstChild = child;
583 child->fParent = this;
584 child->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585
reed@google.coma25c94e2013-06-13 20:20:17 +0000586 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000587 this->invokeLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588DONE:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000589 return child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590}
591
reed@google.coma25c94e2013-06-13 20:20:17 +0000592SkView* SkView::attachChildToFront(SkView* child) {
593 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000594 SkASSERT(child != this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000596 if (child == NULL || (fFirstChild && fFirstChild->fPrevSibling == child))
597 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000599 child->ref();
600 child->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601
reed@google.coma25c94e2013-06-13 20:20:17 +0000602 if (fFirstChild == NULL) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000603 fFirstChild = child;
604 child->fNextSibling = child;
605 child->fPrevSibling = child;
reed@google.coma25c94e2013-06-13 20:20:17 +0000606 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000607 child->fNextSibling = fFirstChild;
608 child->fPrevSibling = fFirstChild->fPrevSibling;
609 fFirstChild->fPrevSibling->fNextSibling = child;
610 fFirstChild->fPrevSibling = child;
611 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000613 child->fParent = this;
614 child->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615
reed@google.coma25c94e2013-06-13 20:20:17 +0000616 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000617 this->invokeLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000618DONE:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000619 return child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000620}
621
reed@google.coma25c94e2013-06-13 20:20:17 +0000622void SkView::detachAllChildren() {
623 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000624 while (fFirstChild)
625 fFirstChild->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626}
627
reed@google.coma25c94e2013-06-13 20:20:17 +0000628void SkView::localToGlobal(SkMatrix* matrix) const {
reed@google.comf03bb562011-11-11 21:42:12 +0000629 if (matrix) {
630 matrix->reset();
631 const SkView* view = this;
632 while (view)
633 {
634 matrix->preConcat(view->getLocalMatrix());
635 matrix->preTranslate(-view->fLoc.fX, -view->fLoc.fY);
636 view = view->fParent;
637 }
638 }
639}
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000640bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const
reed@android.com8a1c16f2008-12-17 15:59:43 +0000641{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000642 SkASSERT(this);
643
644 if (NULL != local) {
reed@google.comf03bb562011-11-11 21:42:12 +0000645 SkMatrix m;
646 this->localToGlobal(&m);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000647 if (!m.invert(&m)) {
648 return false;
649 }
reed@google.comf03bb562011-11-11 21:42:12 +0000650 SkPoint p;
reed@google.comf03bb562011-11-11 21:42:12 +0000651 m.mapXY(x, y, &p);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000652 local->set(p.fX, p.fY);
653 }
654
655 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656}
657
658//////////////////////////////////////////////////////////////////
659
rmistry@google.comd6176b02012-08-23 18:14:13 +0000660/* Even if the subclass overrides onInflate, they should always be
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000661 sure to call the inherited method, so that we get called.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662*/
reed@google.coma25c94e2013-06-13 20:20:17 +0000663void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000664 SkScalar x, y;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000666 x = this->locX();
667 y = this->locY();
668 (void)dom.findScalar(node, "x", &x);
669 (void)dom.findScalar(node, "y", &y);
670 this->setLoc(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000672 x = this->width();
673 y = this->height();
674 (void)dom.findScalar(node, "width", &x);
675 (void)dom.findScalar(node, "height", &y);
676 this->setSize(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000678 // inflate the flags
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000680 static const char* gFlagNames[] = {
681 "visible", "enabled", "focusable", "flexH", "flexV"
682 };
683 SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000685 bool b;
686 uint32_t flags = this->getFlags();
687 for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++)
688 if (dom.findBool(node, gFlagNames[i], &b))
689 flags = SkSetClearShift(flags, b, i);
690 this->setFlags(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691}
692
reed@google.coma25c94e2013-06-13 20:20:17 +0000693void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000694 this->onInflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695}
696
reed@google.coma25c94e2013-06-13 20:20:17 +0000697void SkView::onPostInflate(const SkTDict<SkView*>&) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000698 // override in subclass as needed
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699}
700
reed@google.coma25c94e2013-06-13 20:20:17 +0000701void SkView::postInflate(const SkTDict<SkView*>& dict) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000702 this->onPostInflate(dict);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703
rmistry@google.comd6176b02012-08-23 18:14:13 +0000704 B2FIter iter(this);
705 SkView* child;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000706 while ((child = iter.next()) != NULL)
707 child->postInflate(dict);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708}
709
710//////////////////////////////////////////////////////////////////
711
reed@google.coma25c94e2013-06-13 20:20:17 +0000712SkView* SkView::sendEventToParents(const SkEvent& evt) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000713 SkView* parent = fParent;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000714
reed@google.coma25c94e2013-06-13 20:20:17 +0000715 while (parent) {
716 if (parent->doEvent(evt)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000717 return parent;
reed@google.coma25c94e2013-06-13 20:20:17 +0000718 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000719 parent = parent->fParent;
720 }
721 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000722}
723
reed@android.com34245c72009-11-03 04:00:48 +0000724SkView* SkView::sendQueryToParents(SkEvent* evt) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000725 SkView* parent = fParent;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000726
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000727 while (parent) {
728 if (parent->doQuery(evt)) {
729 return parent;
reed@android.com34245c72009-11-03 04:00:48 +0000730 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000731 parent = parent->fParent;
732 }
733 return NULL;
reed@android.com34245c72009-11-03 04:00:48 +0000734}
735
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736//////////////////////////////////////////////////////////////////
737//////////////////////////////////////////////////////////////////
738
reed@google.coma25c94e2013-06-13 20:20:17 +0000739SkView::F2BIter::F2BIter(const SkView* parent) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000740 fFirstChild = parent ? parent->fFirstChild : NULL;
741 fChild = fFirstChild ? fFirstChild->fPrevSibling : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742}
743
reed@google.coma25c94e2013-06-13 20:20:17 +0000744SkView* SkView::F2BIter::next() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000745 SkView* curr = fChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746
reed@google.coma25c94e2013-06-13 20:20:17 +0000747 if (fChild) {
748 if (fChild == fFirstChild) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000749 fChild = NULL;
reed@google.coma25c94e2013-06-13 20:20:17 +0000750 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000751 fChild = fChild->fPrevSibling;
reed@google.coma25c94e2013-06-13 20:20:17 +0000752 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000753 }
754 return curr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755}
756
reed@google.coma25c94e2013-06-13 20:20:17 +0000757SkView::B2FIter::B2FIter(const SkView* parent) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000758 fFirstChild = parent ? parent->fFirstChild : NULL;
759 fChild = fFirstChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760}
761
reed@google.coma25c94e2013-06-13 20:20:17 +0000762SkView* SkView::B2FIter::next() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000763 SkView* curr = fChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764
reed@google.coma25c94e2013-06-13 20:20:17 +0000765 if (fChild) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000766 SkView* next = fChild->fNextSibling;
767 if (next == fFirstChild)
768 next = NULL;
769 fChild = next;
770 }
771 return curr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772}
773
774//////////////////////////////////////////////////////////////////
775//////////////////////////////////////////////////////////////////
776
777#ifdef SK_DEBUG
778
reed@google.coma25c94e2013-06-13 20:20:17 +0000779void SkView::validate() const {
780 if (fParent) {
781 SkASSERT(fNextSibling);
782 SkASSERT(fPrevSibling);
783 } else {
784 bool nextNull = NULL == fNextSibling;
785 bool prevNull = NULL == fNextSibling;
786 SkASSERT(nextNull && prevNull || !nextNull && !prevNull);
787 }
788}
789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790static inline void show_if_nonzero(const char name[], SkScalar value)
791{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000792 if (value)
793 SkDebugf("%s=\"%g\"", name, value/65536.);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794}
795
796static void tab(int level)
797{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000798 for (int i = 0; i < level; i++)
799 SkDebugf(" ");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000800}
801
802static void dumpview(const SkView* view, int level, bool recurse)
803{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000804 tab(level);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000806 SkDebugf("<view");
807 show_if_nonzero(" x", view->locX());
808 show_if_nonzero(" y", view->locY());
809 show_if_nonzero(" width", view->width());
810 show_if_nonzero(" height", view->height());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000811
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000812 if (recurse)
813 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000814 SkView::B2FIter iter(view);
815 SkView* child;
816 bool noChildren = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000818 while ((child = iter.next()) != NULL)
819 {
820 if (noChildren)
821 SkDebugf(">\n");
822 noChildren = false;
823 dumpview(child, level + 1, true);
824 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000826 if (!noChildren)
827 {
828 tab(level);
829 SkDebugf("</view>\n");
830 }
831 else
832 goto ONELINER;
833 }
834 else
835 {
836 ONELINER:
837 SkDebugf(" />\n");
838 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839}
840
841void SkView::dump(bool recurse) const
842{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000843 dumpview(this, 0, recurse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844}
845
846#endif