blob: 855d6a98e88a5c645ed028413d5bf31a310634a0 [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
11////////////////////////////////////////////////////////////////////////
12
13SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags))
14{
15 fWidth = fHeight = 0;
16 fLoc.set(0, 0);
17 fParent = fFirstChild = fNextSibling = fPrevSibling = NULL;
reed@google.comf03bb562011-11-11 21:42:12 +000018 fMatrix.setIdentity();
reed@android.com8a1c16f2008-12-17 15:59:43 +000019 fContainsFocus = 0;
20}
21
22SkView::~SkView()
23{
24 this->detachAllChildren();
25}
26
27void SkView::setFlags(uint32_t flags)
28{
29 SkASSERT((flags & ~kAllFlagMasks) == 0);
30
31 uint32_t diff = fFlags ^ flags;
32
33 if (diff & kVisible_Mask)
34 this->inval(NULL);
35
36 fFlags = SkToU8(flags);
37
38 if (diff & kVisible_Mask)
39 {
40 this->inval(NULL);
41 }
42}
43
44void SkView::setVisibleP(bool pred)
45{
46 this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
47}
48
49void SkView::setEnabledP(bool pred)
50{
51 this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
52}
53
54void SkView::setFocusableP(bool pred)
55{
56 this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
57}
58
reed@android.comf2b98d62010-12-20 18:26:13 +000059void SkView::setClipToBounds(bool pred) {
60 this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
61}
62
reed@android.com8a1c16f2008-12-17 15:59:43 +000063void SkView::setSize(SkScalar width, SkScalar height)
64{
65 width = SkMaxScalar(0, width);
66 height = SkMaxScalar(0, height);
67
68 if (fWidth != width || fHeight != height)
69 {
70 this->inval(NULL);
71 fWidth = width;
72 fHeight = height;
73 this->inval(NULL);
74 this->onSizeChange();
75 this->invokeLayout();
76 }
77}
78
79void SkView::setLoc(SkScalar x, SkScalar y)
80{
81 if (fLoc.fX != x || fLoc.fY != y)
82 {
83 this->inval(NULL);
84 fLoc.set(x, y);
reed@google.comf03bb562011-11-11 21:42:12 +000085 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +000086 }
87}
88
89void SkView::offset(SkScalar dx, SkScalar dy)
90{
91 if (dx || dy)
92 this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
93}
94
reed@google.comf03bb562011-11-11 21:42:12 +000095void SkView::setLocalMatrix(const SkMatrix& matrix)
96{
97 this->inval(NULL);
98 fMatrix = matrix;
99 this->inval(NULL);
100}
101
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102void SkView::draw(SkCanvas* canvas)
103{
104 if (fWidth && fHeight && this->isVisible())
105 {
106 SkRect r;
107 r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
reed@android.comf2b98d62010-12-20 18:26:13 +0000108 if (this->isClipToBounds() &&
109 canvas->quickReject(r, SkCanvas::kBW_EdgeType)) {
110 return;
111 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112
113 SkAutoCanvasRestore as(canvas, true);
114
reed@android.comf2b98d62010-12-20 18:26:13 +0000115 if (this->isClipToBounds()) {
116 canvas->clipRect(r);
117 }
reed@google.comf03bb562011-11-11 21:42:12 +0000118
119 canvas->translate(fLoc.fX, fLoc.fY);
120 canvas->concat(fMatrix);
121
reed@android.com6c5f6f22009-08-14 16:08:38 +0000122 if (fParent) {
123 fParent->beforeChild(this, canvas);
124 }
reed@android.com562ea922010-02-08 21:45:03 +0000125
126 int sc = canvas->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 this->onDraw(canvas);
reed@android.com562ea922010-02-08 21:45:03 +0000128 canvas->restoreToCount(sc);
129
reed@android.com6c5f6f22009-08-14 16:08:38 +0000130 if (fParent) {
131 fParent->afterChild(this, canvas);
132 }
133
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134 B2FIter iter(this);
135 SkView* child;
136
137 SkCanvas* childCanvas = this->beforeChildren(canvas);
138
139 while ((child = iter.next()) != NULL)
140 child->draw(childCanvas);
141
142 this->afterChildren(canvas);
143 }
144}
145
reed@android.comf2b98d62010-12-20 18:26:13 +0000146void SkView::inval(SkRect* rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 SkView* view = this;
reed@android.comf2b98d62010-12-20 18:26:13 +0000148 SkRect storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149
reed@android.comf2b98d62010-12-20 18:26:13 +0000150 for (;;) {
151 if (!view->isVisible()) {
152 return;
153 }
154 if (view->isClipToBounds()) {
155 SkRect bounds;
156 view->getLocalBounds(&bounds);
157 if (rect && !bounds.intersect(*rect)) {
158 return;
159 }
160 storage = bounds;
161 rect = &storage;
162 }
163 if (view->handleInval(rect)) {
164 return;
165 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 SkView* parent = view->fParent;
reed@android.comf2b98d62010-12-20 18:26:13 +0000168 if (parent == NULL) {
169 return;
170 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171
reed@android.comf2b98d62010-12-20 18:26:13 +0000172 if (rect) {
173 rect->offset(view->fLoc.fX, view->fLoc.fY);
174 }
175 view = parent;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 }
177}
178
179////////////////////////////////////////////////////////////////////////////
180
181bool SkView::setFocusView(SkView* fv)
182{
183 SkView* view = this;
184
185 do {
186 if (view->onSetFocusView(fv))
187 return true;
188 } while ((view = view->fParent) != NULL);
189 return false;
190}
191
192SkView* SkView::getFocusView() const
193{
194 SkView* focus = NULL;
195 const SkView* view = this;
196 do {
197 if (view->onGetFocusView(&focus))
198 break;
199 } while ((view = view->fParent) != NULL);
200 return focus;
201}
202
203bool SkView::hasFocus() const
204{
205 return this == this->getFocusView();
206}
207
208bool SkView::acceptFocus()
209{
210 return this->isFocusable() && this->setFocusView(this);
211}
212
213/*
214 Try to give focus to this view, or its children
215*/
216SkView* SkView::acceptFocus(FocusDirection dir)
217{
218 if (dir == kNext_FocusDirection)
219 {
220 if (this->acceptFocus())
221 return this;
222
223 B2FIter iter(this);
224 SkView* child, *focus;
225 while ((child = iter.next()) != NULL)
226 if ((focus = child->acceptFocus(dir)) != NULL)
227 return focus;
228 }
229 else // prev
230 {
231 F2BIter iter(this);
232 SkView* child, *focus;
233 while ((child = iter.next()) != NULL)
234 if ((focus = child->acceptFocus(dir)) != NULL)
235 return focus;
236
237 if (this->acceptFocus())
238 return this;
239 }
240
241 return NULL;
242}
243
244SkView* SkView::moveFocus(FocusDirection dir)
245{
246 SkView* focus = this->getFocusView();
247
248 if (focus == NULL)
249 { // start with the root
250 focus = this;
251 while (focus->fParent)
252 focus = focus->fParent;
253 }
254
255 SkView* child, *parent;
256
257 if (dir == kNext_FocusDirection)
258 {
259 parent = focus;
260 child = focus->fFirstChild;
261 if (child)
262 goto FIRST_CHILD;
263 else
264 goto NEXT_SIB;
265
266 do {
267 while (child != parent->fFirstChild)
268 {
269 FIRST_CHILD:
270 if ((focus = child->acceptFocus(dir)) != NULL)
271 return focus;
272 child = child->fNextSibling;
273 }
274 NEXT_SIB:
275 child = parent->fNextSibling;
276 parent = parent->fParent;
277 } while (parent != NULL);
278 }
279 else // prevfocus
280 {
281 parent = focus->fParent;
282 if (parent == NULL) // we're the root
283 return focus->acceptFocus(dir);
284 else
285 {
286 child = focus;
287 while (parent)
288 {
289 while (child != parent->fFirstChild)
290 {
291 child = child->fPrevSibling;
292 if ((focus = child->acceptFocus(dir)) != NULL)
293 return focus;
294 }
295 if (parent->acceptFocus())
296 return parent;
297
298 child = parent;
299 parent = parent->fParent;
300 }
301 }
302 }
303 return NULL;
304}
305
306void SkView::onFocusChange(bool gainFocusP)
307{
308 this->inval(NULL);
309}
310
311////////////////////////////////////////////////////////////////////////////
312
313SkView::Click::Click(SkView* target)
314{
Scroggod3aed392011-06-22 13:26:56 +0000315 SkASSERT(target);
316 fTargetID = target->getSinkID();
317 fType = NULL;
318 fWeOwnTheType = false;
319 fOwner = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320}
321
322SkView::Click::~Click()
323{
324 this->resetType();
325}
326
327void SkView::Click::resetType()
328{
329 if (fWeOwnTheType)
330 {
331 sk_free(fType);
332 fWeOwnTheType = false;
333 }
334 fType = NULL;
335}
336
337bool SkView::Click::isType(const char type[]) const
338{
339 const char* t = fType;
340
341 if (type == t)
342 return true;
343
344 if (type == NULL)
345 type = "";
346 if (t == NULL)
347 t = "";
348 return !strcmp(t, type);
349}
350
351void SkView::Click::setType(const char type[])
352{
353 this->resetType();
354 fType = (char*)type;
355}
356
357void SkView::Click::copyType(const char type[])
358{
359 if (fType != type)
360 {
361 this->resetType();
362 if (type)
363 {
364 size_t len = strlen(type) + 1;
365 fType = (char*)sk_malloc_throw(len);
366 memcpy(fType, type, len);
367 fWeOwnTheType = true;
368 }
369 }
370}
371
372SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y)
373{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000374 if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
375 return NULL;
reed@android.come72fee52009-11-16 14:52:01 +0000376 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377
reed@android.come72fee52009-11-16 14:52:01 +0000378 if (this->onSendClickToChildren(x, y)) {
379 F2BIter iter(this);
380 SkView* child;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000381
reed@android.come72fee52009-11-16 14:52:01 +0000382 while ((child = iter.next()) != NULL)
383 {
reed@google.comf03bb562011-11-11 21:42:12 +0000384 SkPoint p;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000385 if (!child->globalToLocal(x, y, &p)) {
386 continue;
387 }
388
reed@google.comf03bb562011-11-11 21:42:12 +0000389 Click* click = child->findClickHandler(p.fX, p.fY);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000390
reed@android.come72fee52009-11-16 14:52:01 +0000391 if (click) {
392 return click;
393 }
394 }
395 }
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000396
397 return this->onFindClickHandler(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398}
399
400void SkView::DoClickDown(Click* click, int x, int y)
401{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000402 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000404 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
405 if (NULL == target) {
406 return;
407 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000409 click->fIOrig.set(x, y);
410 click->fICurr = click->fIPrev = click->fIOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000412 click->fOrig.iset(x, y);
413 if (!target->globalToLocal(&click->fOrig)) {
414 // no history to let us recover from this failure
415 return;
416 }
417 click->fPrev = click->fCurr = click->fOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000419 click->fState = Click::kDown_State;
420 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421}
422
423void SkView::DoClickMoved(Click* click, int x, int y)
424{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000425 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000427 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
428 if (NULL == target) {
429 return;
430 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000432 click->fIPrev = click->fICurr;
433 click->fICurr.set(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000435 click->fPrev = click->fCurr;
436 click->fCurr.iset(x, y);
437 if (!target->globalToLocal(&click->fCurr)) {
438 // on failure pretend the mouse didn't move
439 click->fCurr = click->fPrev;
440 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000442 click->fState = Click::kMoved_State;
443 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444}
445
446void SkView::DoClickUp(Click* click, int x, int y)
447{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000448 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000450 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
451 if (NULL == target) {
452 return;
453 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000455 click->fIPrev = click->fICurr;
456 click->fICurr.set(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000458 click->fPrev = click->fCurr;
459 click->fCurr.iset(x, y);
460 if (!target->globalToLocal(&click->fCurr)) {
461 // on failure pretend the mouse didn't move
462 click->fCurr = click->fPrev;
463 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000465 click->fState = Click::kUp_State;
466 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467}
468
469//////////////////////////////////////////////////////////////////////
470
reed@android.come72fee52009-11-16 14:52:01 +0000471void SkView::invokeLayout() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000472 SkView::Layout* layout = this->getLayout();
473
reed@android.come72fee52009-11-16 14:52:01 +0000474 if (layout) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 layout->layoutChildren(this);
reed@android.come72fee52009-11-16 14:52:01 +0000476 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000477}
478
reed@android.come72fee52009-11-16 14:52:01 +0000479void SkView::onDraw(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000480 Artist* artist = this->getArtist();
481
reed@android.come72fee52009-11-16 14:52:01 +0000482 if (artist) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483 artist->draw(this, canvas);
reed@android.come72fee52009-11-16 14:52:01 +0000484 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485}
486
reed@android.come72fee52009-11-16 14:52:01 +0000487void SkView::onSizeChange() {}
488
489bool SkView::onSendClickToChildren(SkScalar x, SkScalar y) {
490 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000491}
492
reed@android.come72fee52009-11-16 14:52:01 +0000493SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000494 return NULL;
495}
496
reed@android.come72fee52009-11-16 14:52:01 +0000497bool SkView::onClick(Click*) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 return false;
499}
500
reed@android.comf2b98d62010-12-20 18:26:13 +0000501bool SkView::handleInval(const SkRect*) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502 return false;
503}
504
505//////////////////////////////////////////////////////////////////////
506
507void SkView::getLocalBounds(SkRect* bounds) const
508{
509 if (bounds)
510 bounds->set(0, 0, fWidth, fHeight);
511}
512
513//////////////////////////////////////////////////////////////////////
514//////////////////////////////////////////////////////////////////////
515
516void SkView::detachFromParent_NoLayout()
517{
518 if (fParent == NULL)
519 return;
520
521 if (fContainsFocus)
522 (void)this->setFocusView(NULL);
523
524 this->inval(NULL);
525
526 SkView* next = NULL;
527
528 if (fNextSibling != this) // do we have any siblings
529 {
530 fNextSibling->fPrevSibling = fPrevSibling;
531 fPrevSibling->fNextSibling = fNextSibling;
532 next = fNextSibling;
533 }
534
535 if (fParent->fFirstChild == this)
536 fParent->fFirstChild = next;
537
538 fParent = fNextSibling = fPrevSibling = NULL;
539
540 this->unref();
541}
542
543void SkView::detachFromParent()
544{
545 SkView* parent = fParent;
546
547 if (parent)
548 {
549 this->detachFromParent_NoLayout();
550 parent->invokeLayout();
551 }
552}
553
554SkView* SkView::attachChildToBack(SkView* child)
555{
556 SkASSERT(child != this);
557
558 if (child == NULL || fFirstChild == child)
559 goto DONE;
560
561 child->ref();
562 child->detachFromParent_NoLayout();
563
564 if (fFirstChild == NULL)
565 {
566 child->fNextSibling = child;
567 child->fPrevSibling = child;
568 }
569 else
570 {
571 child->fNextSibling = fFirstChild;
572 child->fPrevSibling = fFirstChild->fPrevSibling;
573 fFirstChild->fPrevSibling->fNextSibling = child;
574 fFirstChild->fPrevSibling = child;
575 }
576
577 fFirstChild = child;
578 child->fParent = this;
579 child->inval(NULL);
580
581 this->invokeLayout();
582DONE:
583 return child;
584}
585
586SkView* SkView::attachChildToFront(SkView* child)
587{
588 SkASSERT(child != this);
589
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000590 if (child == NULL || (fFirstChild && fFirstChild->fPrevSibling == child))
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591 goto DONE;
592
593 child->ref();
594 child->detachFromParent_NoLayout();
595
596 if (fFirstChild == NULL)
597 {
598 fFirstChild = child;
599 child->fNextSibling = child;
600 child->fPrevSibling = child;
601 }
602 else
603 {
604 child->fNextSibling = fFirstChild;
605 child->fPrevSibling = fFirstChild->fPrevSibling;
606 fFirstChild->fPrevSibling->fNextSibling = child;
607 fFirstChild->fPrevSibling = child;
608 }
609
610 child->fParent = this;
611 child->inval(NULL);
612
613 this->invokeLayout();
614DONE:
615 return child;
616}
617
618void SkView::detachAllChildren()
619{
620 while (fFirstChild)
621 fFirstChild->detachFromParent_NoLayout();
622}
623
reed@google.comf03bb562011-11-11 21:42:12 +0000624void SkView::localToGlobal(SkMatrix* matrix) const
625{
626 if (matrix) {
627 matrix->reset();
628 const SkView* view = this;
629 while (view)
630 {
631 matrix->preConcat(view->getLocalMatrix());
632 matrix->preTranslate(-view->fLoc.fX, -view->fLoc.fY);
633 view = view->fParent;
634 }
635 }
636}
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000637bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000639 SkASSERT(this);
640
641 if (NULL != local) {
reed@google.comf03bb562011-11-11 21:42:12 +0000642 SkMatrix m;
643 this->localToGlobal(&m);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000644 if (!m.invert(&m)) {
645 return false;
646 }
reed@google.comf03bb562011-11-11 21:42:12 +0000647 SkPoint p;
reed@google.comf03bb562011-11-11 21:42:12 +0000648 m.mapXY(x, y, &p);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000649 local->set(p.fX, p.fY);
650 }
651
652 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653}
654
655//////////////////////////////////////////////////////////////////
656
657/* Even if the subclass overrides onInflate, they should always be
658 sure to call the inherited method, so that we get called.
659*/
660void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
661{
662 SkScalar x, y;
663
664 x = this->locX();
665 y = this->locY();
666 (void)dom.findScalar(node, "x", &x);
667 (void)dom.findScalar(node, "y", &y);
668 this->setLoc(x, y);
669
670 x = this->width();
671 y = this->height();
672 (void)dom.findScalar(node, "width", &x);
673 (void)dom.findScalar(node, "height", &y);
674 this->setSize(x, y);
675
676 // inflate the flags
677
678 static const char* gFlagNames[] = {
679 "visible", "enabled", "focusable", "flexH", "flexV"
680 };
681 SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
682
683 bool b;
684 uint32_t flags = this->getFlags();
685 for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++)
686 if (dom.findBool(node, gFlagNames[i], &b))
687 flags = SkSetClearShift(flags, b, i);
688 this->setFlags(flags);
689}
690
691void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node)
692{
693 this->onInflate(dom, node);
694}
695
696void SkView::onPostInflate(const SkTDict<SkView*>&)
697{
698 // override in subclass as needed
699}
700
701void SkView::postInflate(const SkTDict<SkView*>& dict)
702{
703 this->onPostInflate(dict);
704
705 B2FIter iter(this);
706 SkView* child;
707 while ((child = iter.next()) != NULL)
708 child->postInflate(dict);
709}
710
711//////////////////////////////////////////////////////////////////
712
713SkView* SkView::sendEventToParents(const SkEvent& evt)
714{
715 SkView* parent = fParent;
reed@android.com34245c72009-11-03 04:00:48 +0000716
reed@android.com8a1c16f2008-12-17 15:59:43 +0000717 while (parent)
718 {
719 if (parent->doEvent(evt))
720 return parent;
721 parent = parent->fParent;
722 }
723 return NULL;
724}
725
reed@android.com34245c72009-11-03 04:00:48 +0000726SkView* SkView::sendQueryToParents(SkEvent* evt) {
727 SkView* parent = fParent;
728
729 while (parent) {
730 if (parent->doQuery(evt)) {
731 return parent;
732 }
733 parent = parent->fParent;
734 }
735 return NULL;
736}
737
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738//////////////////////////////////////////////////////////////////
739//////////////////////////////////////////////////////////////////
740
741SkView::F2BIter::F2BIter(const SkView* parent)
742{
743 fFirstChild = parent ? parent->fFirstChild : NULL;
744 fChild = fFirstChild ? fFirstChild->fPrevSibling : NULL;
745}
746
747SkView* SkView::F2BIter::next()
748{
749 SkView* curr = fChild;
750
751 if (fChild)
752 {
753 if (fChild == fFirstChild)
754 fChild = NULL;
755 else
756 fChild = fChild->fPrevSibling;
757 }
758 return curr;
759}
760
761SkView::B2FIter::B2FIter(const SkView* parent)
762{
763 fFirstChild = parent ? parent->fFirstChild : NULL;
764 fChild = fFirstChild;
765}
766
767SkView* SkView::B2FIter::next()
768{
769 SkView* curr = fChild;
770
771 if (fChild)
772 {
773 SkView* next = fChild->fNextSibling;
774 if (next == fFirstChild)
775 next = NULL;
776 fChild = next;
777 }
778 return curr;
779}
780
781//////////////////////////////////////////////////////////////////
782//////////////////////////////////////////////////////////////////
783
784#ifdef SK_DEBUG
785
786static inline void show_if_nonzero(const char name[], SkScalar value)
787{
788 if (value)
789 SkDebugf("%s=\"%g\"", name, value/65536.);
790}
791
792static void tab(int level)
793{
794 for (int i = 0; i < level; i++)
795 SkDebugf(" ");
796}
797
798static void dumpview(const SkView* view, int level, bool recurse)
799{
800 tab(level);
801
802 SkDebugf("<view");
803 show_if_nonzero(" x", view->locX());
804 show_if_nonzero(" y", view->locY());
805 show_if_nonzero(" width", view->width());
806 show_if_nonzero(" height", view->height());
807
808 if (recurse)
809 {
810 SkView::B2FIter iter(view);
811 SkView* child;
812 bool noChildren = true;
813
814 while ((child = iter.next()) != NULL)
815 {
816 if (noChildren)
817 SkDebugf(">\n");
818 noChildren = false;
819 dumpview(child, level + 1, true);
820 }
821
822 if (!noChildren)
823 {
824 tab(level);
825 SkDebugf("</view>\n");
826 }
827 else
828 goto ONELINER;
829 }
830 else
831 {
832 ONELINER:
833 SkDebugf(" />\n");
834 }
835}
836
837void SkView::dump(bool recurse) const
838{
839 dumpview(this, 0, recurse);
840}
841
842#endif