blob: 652eb850258b8a6a011c51e8cbbd5fc4d8503e56 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkView.h"
2#include "SkCanvas.h"
3
4////////////////////////////////////////////////////////////////////////
5
6SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags))
7{
8 fWidth = fHeight = 0;
9 fLoc.set(0, 0);
10 fParent = fFirstChild = fNextSibling = fPrevSibling = NULL;
11
12 fContainsFocus = 0;
13}
14
15SkView::~SkView()
16{
17 this->detachAllChildren();
18}
19
20void SkView::setFlags(uint32_t flags)
21{
22 SkASSERT((flags & ~kAllFlagMasks) == 0);
23
24 uint32_t diff = fFlags ^ flags;
25
26 if (diff & kVisible_Mask)
27 this->inval(NULL);
28
29 fFlags = SkToU8(flags);
30
31 if (diff & kVisible_Mask)
32 {
33 this->inval(NULL);
34 }
35}
36
37void SkView::setVisibleP(bool pred)
38{
39 this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
40}
41
42void SkView::setEnabledP(bool pred)
43{
44 this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
45}
46
47void SkView::setFocusableP(bool pred)
48{
49 this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
50}
51
52void SkView::setSize(SkScalar width, SkScalar height)
53{
54 width = SkMaxScalar(0, width);
55 height = SkMaxScalar(0, height);
56
57 if (fWidth != width || fHeight != height)
58 {
59 this->inval(NULL);
60 fWidth = width;
61 fHeight = height;
62 this->inval(NULL);
63 this->onSizeChange();
64 this->invokeLayout();
65 }
66}
67
68void SkView::setLoc(SkScalar x, SkScalar y)
69{
70 if (fLoc.fX != x || fLoc.fY != y)
71 {
72 this->inval(NULL);
73 fLoc.set(x, y);
74 this->inval(NULL);
75 }
76}
77
78void SkView::offset(SkScalar dx, SkScalar dy)
79{
80 if (dx || dy)
81 this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
82}
83
84void SkView::draw(SkCanvas* canvas)
85{
86 if (fWidth && fHeight && this->isVisible())
87 {
88 SkRect r;
89 r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
90 if (canvas->quickReject(r, SkCanvas::kBW_EdgeType))
91 return;
92
93 SkAutoCanvasRestore as(canvas, true);
94
95 canvas->clipRect(r);
96 canvas->translate(fLoc.fX, fLoc.fY);
97
reed@android.com6c5f6f22009-08-14 16:08:38 +000098 if (fParent) {
99 fParent->beforeChild(this, canvas);
100 }
reed@android.com562ea922010-02-08 21:45:03 +0000101
102 int sc = canvas->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 this->onDraw(canvas);
reed@android.com562ea922010-02-08 21:45:03 +0000104 canvas->restoreToCount(sc);
105
reed@android.com6c5f6f22009-08-14 16:08:38 +0000106 if (fParent) {
107 fParent->afterChild(this, canvas);
108 }
109
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110 B2FIter iter(this);
111 SkView* child;
112
113 SkCanvas* childCanvas = this->beforeChildren(canvas);
114
115 while ((child = iter.next()) != NULL)
116 child->draw(childCanvas);
117
118 this->afterChildren(canvas);
119 }
120}
121
122void SkView::inval(SkRect* rect)
123{
124 if (!this->isVisible())
125 return;
126
127 SkRect bounds;
128
129 this->getLocalBounds(&bounds);
130 if (rect && !bounds.intersect(*rect))
131 return;
132
133 rect = &bounds;
134 SkView* view = this;
135
136 for (;;)
137 {
138 if (view->handleInval(bounds))
139 break;
140
141 SkRect parentR;
142 SkView* parent = view->fParent;
143
144 if (parent == NULL || !parent->isVisible())
145 break;
146
147 bounds.offset(view->fLoc.fX, view->fLoc.fY);
148 parent->getLocalBounds(&parentR);
149 if (!bounds.intersect(parentR))
150 return;
151
152 view = parent;
153 }
154}
155
156////////////////////////////////////////////////////////////////////////////
157
158bool SkView::setFocusView(SkView* fv)
159{
160 SkView* view = this;
161
162 do {
163 if (view->onSetFocusView(fv))
164 return true;
165 } while ((view = view->fParent) != NULL);
166 return false;
167}
168
169SkView* SkView::getFocusView() const
170{
171 SkView* focus = NULL;
172 const SkView* view = this;
173 do {
174 if (view->onGetFocusView(&focus))
175 break;
176 } while ((view = view->fParent) != NULL);
177 return focus;
178}
179
180bool SkView::hasFocus() const
181{
182 return this == this->getFocusView();
183}
184
185bool SkView::acceptFocus()
186{
187 return this->isFocusable() && this->setFocusView(this);
188}
189
190/*
191 Try to give focus to this view, or its children
192*/
193SkView* SkView::acceptFocus(FocusDirection dir)
194{
195 if (dir == kNext_FocusDirection)
196 {
197 if (this->acceptFocus())
198 return this;
199
200 B2FIter iter(this);
201 SkView* child, *focus;
202 while ((child = iter.next()) != NULL)
203 if ((focus = child->acceptFocus(dir)) != NULL)
204 return focus;
205 }
206 else // prev
207 {
208 F2BIter iter(this);
209 SkView* child, *focus;
210 while ((child = iter.next()) != NULL)
211 if ((focus = child->acceptFocus(dir)) != NULL)
212 return focus;
213
214 if (this->acceptFocus())
215 return this;
216 }
217
218 return NULL;
219}
220
221SkView* SkView::moveFocus(FocusDirection dir)
222{
223 SkView* focus = this->getFocusView();
224
225 if (focus == NULL)
226 { // start with the root
227 focus = this;
228 while (focus->fParent)
229 focus = focus->fParent;
230 }
231
232 SkView* child, *parent;
233
234 if (dir == kNext_FocusDirection)
235 {
236 parent = focus;
237 child = focus->fFirstChild;
238 if (child)
239 goto FIRST_CHILD;
240 else
241 goto NEXT_SIB;
242
243 do {
244 while (child != parent->fFirstChild)
245 {
246 FIRST_CHILD:
247 if ((focus = child->acceptFocus(dir)) != NULL)
248 return focus;
249 child = child->fNextSibling;
250 }
251 NEXT_SIB:
252 child = parent->fNextSibling;
253 parent = parent->fParent;
254 } while (parent != NULL);
255 }
256 else // prevfocus
257 {
258 parent = focus->fParent;
259 if (parent == NULL) // we're the root
260 return focus->acceptFocus(dir);
261 else
262 {
263 child = focus;
264 while (parent)
265 {
266 while (child != parent->fFirstChild)
267 {
268 child = child->fPrevSibling;
269 if ((focus = child->acceptFocus(dir)) != NULL)
270 return focus;
271 }
272 if (parent->acceptFocus())
273 return parent;
274
275 child = parent;
276 parent = parent->fParent;
277 }
278 }
279 }
280 return NULL;
281}
282
283void SkView::onFocusChange(bool gainFocusP)
284{
285 this->inval(NULL);
286}
287
288////////////////////////////////////////////////////////////////////////////
289
290SkView::Click::Click(SkView* target)
291{
292 SkASSERT(target);
293 fTargetID = target->getSinkID();
294 fType = NULL;
295 fWeOwnTheType = false;
296}
297
298SkView::Click::~Click()
299{
300 this->resetType();
301}
302
303void SkView::Click::resetType()
304{
305 if (fWeOwnTheType)
306 {
307 sk_free(fType);
308 fWeOwnTheType = false;
309 }
310 fType = NULL;
311}
312
313bool SkView::Click::isType(const char type[]) const
314{
315 const char* t = fType;
316
317 if (type == t)
318 return true;
319
320 if (type == NULL)
321 type = "";
322 if (t == NULL)
323 t = "";
324 return !strcmp(t, type);
325}
326
327void SkView::Click::setType(const char type[])
328{
329 this->resetType();
330 fType = (char*)type;
331}
332
333void SkView::Click::copyType(const char type[])
334{
335 if (fType != type)
336 {
337 this->resetType();
338 if (type)
339 {
340 size_t len = strlen(type) + 1;
341 fType = (char*)sk_malloc_throw(len);
342 memcpy(fType, type, len);
343 fWeOwnTheType = true;
344 }
345 }
346}
347
348SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y)
349{
reed@android.come72fee52009-11-16 14:52:01 +0000350 if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 return false;
reed@android.come72fee52009-11-16 14:52:01 +0000352 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353
reed@android.come72fee52009-11-16 14:52:01 +0000354 if (this->onSendClickToChildren(x, y)) {
355 F2BIter iter(this);
356 SkView* child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357
reed@android.come72fee52009-11-16 14:52:01 +0000358 while ((child = iter.next()) != NULL)
359 {
360 Click* click = child->findClickHandler(x - child->fLoc.fX,
361 y - child->fLoc.fY);
362 if (click) {
363 return click;
364 }
365 }
366 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 return this->onFindClickHandler(x, y);
368}
369
370void SkView::DoClickDown(Click* click, int x, int y)
371{
372 SkASSERT(click);
373
374 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
375 if (target == NULL)
376 return;
377
378 click->fIOrig.set(x, y);
379 click->fICurr = click->fIPrev = click->fIOrig;
380
381 click->fOrig.iset(x, y);
382 target->globalToLocal(&click->fOrig);
383 click->fPrev = click->fCurr = click->fOrig;
384
385 click->fState = Click::kDown_State;
386 target->onClick(click);
387}
388
389void SkView::DoClickMoved(Click* click, int x, int y)
390{
391 SkASSERT(click);
392
393 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
394 if (target == NULL)
395 return;
396
397 click->fIPrev = click->fICurr;
398 click->fICurr.set(x, y);
399
400 click->fPrev = click->fCurr;
401 click->fCurr.iset(x, y);
402 target->globalToLocal(&click->fCurr);
403
404 click->fState = Click::kMoved_State;
405 target->onClick(click);
406}
407
408void SkView::DoClickUp(Click* click, int x, int y)
409{
410 SkASSERT(click);
411
412 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
413 if (target == NULL)
414 return;
415
416 click->fIPrev = click->fICurr;
417 click->fICurr.set(x, y);
418
419 click->fPrev = click->fCurr;
420 click->fCurr.iset(x, y);
421 target->globalToLocal(&click->fCurr);
422
423 click->fState = Click::kUp_State;
424 target->onClick(click);
425}
426
427//////////////////////////////////////////////////////////////////////
428
reed@android.come72fee52009-11-16 14:52:01 +0000429void SkView::invokeLayout() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430 SkView::Layout* layout = this->getLayout();
431
reed@android.come72fee52009-11-16 14:52:01 +0000432 if (layout) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 layout->layoutChildren(this);
reed@android.come72fee52009-11-16 14:52:01 +0000434 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435}
436
reed@android.come72fee52009-11-16 14:52:01 +0000437void SkView::onDraw(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 Artist* artist = this->getArtist();
439
reed@android.come72fee52009-11-16 14:52:01 +0000440 if (artist) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 artist->draw(this, canvas);
reed@android.come72fee52009-11-16 14:52:01 +0000442 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443}
444
reed@android.come72fee52009-11-16 14:52:01 +0000445void SkView::onSizeChange() {}
446
447bool SkView::onSendClickToChildren(SkScalar x, SkScalar y) {
448 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449}
450
reed@android.come72fee52009-11-16 14:52:01 +0000451SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 return NULL;
453}
454
reed@android.come72fee52009-11-16 14:52:01 +0000455bool SkView::onClick(Click*) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456 return false;
457}
458
reed@android.come72fee52009-11-16 14:52:01 +0000459bool SkView::handleInval(const SkRect& r) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460 return false;
461}
462
463//////////////////////////////////////////////////////////////////////
464
465void SkView::getLocalBounds(SkRect* bounds) const
466{
467 if (bounds)
468 bounds->set(0, 0, fWidth, fHeight);
469}
470
471//////////////////////////////////////////////////////////////////////
472//////////////////////////////////////////////////////////////////////
473
474void SkView::detachFromParent_NoLayout()
475{
476 if (fParent == NULL)
477 return;
478
479 if (fContainsFocus)
480 (void)this->setFocusView(NULL);
481
482 this->inval(NULL);
483
484 SkView* next = NULL;
485
486 if (fNextSibling != this) // do we have any siblings
487 {
488 fNextSibling->fPrevSibling = fPrevSibling;
489 fPrevSibling->fNextSibling = fNextSibling;
490 next = fNextSibling;
491 }
492
493 if (fParent->fFirstChild == this)
494 fParent->fFirstChild = next;
495
496 fParent = fNextSibling = fPrevSibling = NULL;
497
498 this->unref();
499}
500
501void SkView::detachFromParent()
502{
503 SkView* parent = fParent;
504
505 if (parent)
506 {
507 this->detachFromParent_NoLayout();
508 parent->invokeLayout();
509 }
510}
511
512SkView* SkView::attachChildToBack(SkView* child)
513{
514 SkASSERT(child != this);
515
516 if (child == NULL || fFirstChild == child)
517 goto DONE;
518
519 child->ref();
520 child->detachFromParent_NoLayout();
521
522 if (fFirstChild == NULL)
523 {
524 child->fNextSibling = child;
525 child->fPrevSibling = child;
526 }
527 else
528 {
529 child->fNextSibling = fFirstChild;
530 child->fPrevSibling = fFirstChild->fPrevSibling;
531 fFirstChild->fPrevSibling->fNextSibling = child;
532 fFirstChild->fPrevSibling = child;
533 }
534
535 fFirstChild = child;
536 child->fParent = this;
537 child->inval(NULL);
538
539 this->invokeLayout();
540DONE:
541 return child;
542}
543
544SkView* SkView::attachChildToFront(SkView* child)
545{
546 SkASSERT(child != this);
547
548 if (child == NULL || fFirstChild && fFirstChild->fPrevSibling == child)
549 goto DONE;
550
551 child->ref();
552 child->detachFromParent_NoLayout();
553
554 if (fFirstChild == NULL)
555 {
556 fFirstChild = child;
557 child->fNextSibling = child;
558 child->fPrevSibling = child;
559 }
560 else
561 {
562 child->fNextSibling = fFirstChild;
563 child->fPrevSibling = fFirstChild->fPrevSibling;
564 fFirstChild->fPrevSibling->fNextSibling = child;
565 fFirstChild->fPrevSibling = child;
566 }
567
568 child->fParent = this;
569 child->inval(NULL);
570
571 this->invokeLayout();
572DONE:
573 return child;
574}
575
576void SkView::detachAllChildren()
577{
578 while (fFirstChild)
579 fFirstChild->detachFromParent_NoLayout();
580}
581
582void SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const
583{
584 SkASSERT(this);
585
586 if (local)
587 {
588 const SkView* view = this;
589 while (view)
590 {
591 x -= view->fLoc.fX;
592 y -= view->fLoc.fY;
593 view = view->fParent;
594 }
595 local->set(x, y);
596 }
597}
598
599//////////////////////////////////////////////////////////////////
600
601/* Even if the subclass overrides onInflate, they should always be
602 sure to call the inherited method, so that we get called.
603*/
604void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
605{
606 SkScalar x, y;
607
608 x = this->locX();
609 y = this->locY();
610 (void)dom.findScalar(node, "x", &x);
611 (void)dom.findScalar(node, "y", &y);
612 this->setLoc(x, y);
613
614 x = this->width();
615 y = this->height();
616 (void)dom.findScalar(node, "width", &x);
617 (void)dom.findScalar(node, "height", &y);
618 this->setSize(x, y);
619
620 // inflate the flags
621
622 static const char* gFlagNames[] = {
623 "visible", "enabled", "focusable", "flexH", "flexV"
624 };
625 SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
626
627 bool b;
628 uint32_t flags = this->getFlags();
629 for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++)
630 if (dom.findBool(node, gFlagNames[i], &b))
631 flags = SkSetClearShift(flags, b, i);
632 this->setFlags(flags);
633}
634
635void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node)
636{
637 this->onInflate(dom, node);
638}
639
640void SkView::onPostInflate(const SkTDict<SkView*>&)
641{
642 // override in subclass as needed
643}
644
645void SkView::postInflate(const SkTDict<SkView*>& dict)
646{
647 this->onPostInflate(dict);
648
649 B2FIter iter(this);
650 SkView* child;
651 while ((child = iter.next()) != NULL)
652 child->postInflate(dict);
653}
654
655//////////////////////////////////////////////////////////////////
656
657SkView* SkView::sendEventToParents(const SkEvent& evt)
658{
659 SkView* parent = fParent;
reed@android.com34245c72009-11-03 04:00:48 +0000660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 while (parent)
662 {
663 if (parent->doEvent(evt))
664 return parent;
665 parent = parent->fParent;
666 }
667 return NULL;
668}
669
reed@android.com34245c72009-11-03 04:00:48 +0000670SkView* SkView::sendQueryToParents(SkEvent* evt) {
671 SkView* parent = fParent;
672
673 while (parent) {
674 if (parent->doQuery(evt)) {
675 return parent;
676 }
677 parent = parent->fParent;
678 }
679 return NULL;
680}
681
reed@android.com8a1c16f2008-12-17 15:59:43 +0000682//////////////////////////////////////////////////////////////////
683//////////////////////////////////////////////////////////////////
684
685SkView::F2BIter::F2BIter(const SkView* parent)
686{
687 fFirstChild = parent ? parent->fFirstChild : NULL;
688 fChild = fFirstChild ? fFirstChild->fPrevSibling : NULL;
689}
690
691SkView* SkView::F2BIter::next()
692{
693 SkView* curr = fChild;
694
695 if (fChild)
696 {
697 if (fChild == fFirstChild)
698 fChild = NULL;
699 else
700 fChild = fChild->fPrevSibling;
701 }
702 return curr;
703}
704
705SkView::B2FIter::B2FIter(const SkView* parent)
706{
707 fFirstChild = parent ? parent->fFirstChild : NULL;
708 fChild = fFirstChild;
709}
710
711SkView* SkView::B2FIter::next()
712{
713 SkView* curr = fChild;
714
715 if (fChild)
716 {
717 SkView* next = fChild->fNextSibling;
718 if (next == fFirstChild)
719 next = NULL;
720 fChild = next;
721 }
722 return curr;
723}
724
725//////////////////////////////////////////////////////////////////
726//////////////////////////////////////////////////////////////////
727
728#ifdef SK_DEBUG
729
730static inline void show_if_nonzero(const char name[], SkScalar value)
731{
732 if (value)
733 SkDebugf("%s=\"%g\"", name, value/65536.);
734}
735
736static void tab(int level)
737{
738 for (int i = 0; i < level; i++)
739 SkDebugf(" ");
740}
741
742static void dumpview(const SkView* view, int level, bool recurse)
743{
744 tab(level);
745
746 SkDebugf("<view");
747 show_if_nonzero(" x", view->locX());
748 show_if_nonzero(" y", view->locY());
749 show_if_nonzero(" width", view->width());
750 show_if_nonzero(" height", view->height());
751
752 if (recurse)
753 {
754 SkView::B2FIter iter(view);
755 SkView* child;
756 bool noChildren = true;
757
758 while ((child = iter.next()) != NULL)
759 {
760 if (noChildren)
761 SkDebugf(">\n");
762 noChildren = false;
763 dumpview(child, level + 1, true);
764 }
765
766 if (!noChildren)
767 {
768 tab(level);
769 SkDebugf("</view>\n");
770 }
771 else
772 goto ONELINER;
773 }
774 else
775 {
776 ONELINER:
777 SkDebugf(" />\n");
778 }
779}
780
781void SkView::dump(bool recurse) const
782{
783 dumpview(this, 0, recurse);
784}
785
786#endif