blob: dae47d6f7c221e92dd91a4762e63df635895195e [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
reed@google.comf03bb562011-11-11 21:42:12 +000098void SkView::setLocalMatrix(const SkMatrix& matrix)
99{
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 {
109 SkRect r;
110 r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
111 if (this->isClipToBounds() &&
reed@android.comf2b98d62010-12-20 18:26:13 +0000112 canvas->quickReject(r, SkCanvas::kBW_EdgeType)) {
113 return;
114 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115
robertphillips@google.coma22e2112012-08-16 14:58:06 +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 }
reed@google.comf03bb562011-11-11 21:42:12 +0000121
122 canvas->translate(fLoc.fX, fLoc.fY);
123 canvas->concat(fMatrix);
124
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 }
136
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000137 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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144
145 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) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +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;
187
188 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{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000197 SkView* focus = NULL;
198 const SkView* view = this;
199 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
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000226 B2FIter iter(this);
227 SkView* child, *focus;
228 while ((child = iter.next()) != NULL)
229 if ((focus = child->acceptFocus(dir)) != NULL)
230 return focus;
231 }
232 else // prev
233 {
234 F2BIter iter(this);
235 SkView* child, *focus;
236 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)
252 { // start with the root
253 focus = this;
254 while (focus->fParent)
255 focus = focus->fParent;
256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257
robertphillips@google.coma22e2112012-08-16 14:58:06 +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 }
282 else // prevfocus
283 {
284 parent = focus->fParent;
285 if (parent == NULL) // we're the root
286 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 {
367 size_t len = strlen(type) + 1;
368 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
375SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y)
376{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000377 if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
378 return NULL;
reed@android.come72fee52009-11-16 14:52:01 +0000379 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380
reed@android.come72fee52009-11-16 14:52:01 +0000381 if (this->onSendClickToChildren(x, y)) {
382 F2BIter iter(this);
383 SkView* child;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000384
reed@android.come72fee52009-11-16 14:52:01 +0000385 while ((child = iter.next()) != NULL)
386 {
reed@google.comf03bb562011-11-11 21:42:12 +0000387 SkPoint p;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000388 if (!child->globalToLocal(x, y, &p)) {
389 continue;
390 }
391
reed@google.comf03bb562011-11-11 21:42:12 +0000392 Click* click = child->findClickHandler(p.fX, p.fY);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000393
reed@android.come72fee52009-11-16 14:52:01 +0000394 if (click) {
395 return click;
396 }
397 }
398 }
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000399
400 return this->onFindClickHandler(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401}
402
403void SkView::DoClickDown(Click* click, int x, int y)
404{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000405 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000407 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
408 if (NULL == target) {
409 return;
410 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000412 click->fIOrig.set(x, y);
413 click->fICurr = click->fIPrev = click->fIOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000415 click->fOrig.iset(x, y);
416 if (!target->globalToLocal(&click->fOrig)) {
417 // no history to let us recover from this failure
418 return;
419 }
420 click->fPrev = click->fCurr = click->fOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000422 click->fState = Click::kDown_State;
423 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424}
425
426void SkView::DoClickMoved(Click* click, int x, int y)
427{
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;
446 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447}
448
449void SkView::DoClickUp(Click* click, int x, int y)
450{
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000451 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000453 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
454 if (NULL == target) {
455 return;
456 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000458 click->fIPrev = click->fICurr;
459 click->fICurr.set(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000461 click->fPrev = click->fCurr;
462 click->fCurr.iset(x, y);
463 if (!target->globalToLocal(&click->fCurr)) {
464 // on failure pretend the mouse didn't move
465 click->fCurr = click->fPrev;
466 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000468 click->fState = Click::kUp_State;
469 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000470}
471
472//////////////////////////////////////////////////////////////////////
473
reed@android.come72fee52009-11-16 14:52:01 +0000474void SkView::invokeLayout() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000475 SkView::Layout* layout = this->getLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000477 if (layout) {
478 layout->layoutChildren(this);
reed@android.come72fee52009-11-16 14:52:01 +0000479 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000480}
481
reed@android.come72fee52009-11-16 14:52:01 +0000482void SkView::onDraw(SkCanvas* canvas) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000483 Artist* artist = this->getArtist();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000484
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000485 if (artist) {
486 artist->draw(this, canvas);
reed@android.come72fee52009-11-16 14:52:01 +0000487 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000488}
489
reed@android.come72fee52009-11-16 14:52:01 +0000490void SkView::onSizeChange() {}
491
492bool SkView::onSendClickToChildren(SkScalar x, SkScalar y) {
493 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000494}
495
reed@android.come72fee52009-11-16 14:52:01 +0000496SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000497 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498}
499
reed@android.come72fee52009-11-16 14:52:01 +0000500bool SkView::onClick(Click*) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000501 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502}
503
reed@android.comf2b98d62010-12-20 18:26:13 +0000504bool SkView::handleInval(const SkRect*) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000505 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506}
507
508//////////////////////////////////////////////////////////////////////
509
510void SkView::getLocalBounds(SkRect* bounds) const
511{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000512 if (bounds)
513 bounds->set(0, 0, fWidth, fHeight);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514}
515
516//////////////////////////////////////////////////////////////////////
517//////////////////////////////////////////////////////////////////////
518
519void SkView::detachFromParent_NoLayout()
520{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000521 if (fParent == NULL)
522 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000524 if (fContainsFocus)
525 (void)this->setFocusView(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000527 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000529 SkView* next = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000531 if (fNextSibling != this) // do we have any siblings
532 {
533 fNextSibling->fPrevSibling = fPrevSibling;
534 fPrevSibling->fNextSibling = fNextSibling;
535 next = fNextSibling;
536 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000538 if (fParent->fFirstChild == this)
539 fParent->fFirstChild = next;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000541 fParent = fNextSibling = fPrevSibling = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000543 this->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544}
545
546void SkView::detachFromParent()
547{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000548 SkView* parent = fParent;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000550 if (parent)
551 {
552 this->detachFromParent_NoLayout();
553 parent->invokeLayout();
554 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555}
556
557SkView* SkView::attachChildToBack(SkView* child)
558{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000559 SkASSERT(child != this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000561 if (child == NULL || fFirstChild == child)
562 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000564 child->ref();
565 child->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000567 if (fFirstChild == NULL)
568 {
569 child->fNextSibling = child;
570 child->fPrevSibling = child;
571 }
572 else
573 {
574 child->fNextSibling = fFirstChild;
575 child->fPrevSibling = fFirstChild->fPrevSibling;
576 fFirstChild->fPrevSibling->fNextSibling = child;
577 fFirstChild->fPrevSibling = child;
578 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000580 fFirstChild = child;
581 child->fParent = this;
582 child->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000584 this->invokeLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585DONE:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000586 return child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587}
588
589SkView* SkView::attachChildToFront(SkView* child)
590{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000591 SkASSERT(child != this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000592
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000593 if (child == NULL || (fFirstChild && fFirstChild->fPrevSibling == child))
594 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000596 child->ref();
597 child->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000599 if (fFirstChild == NULL)
600 {
601 fFirstChild = child;
602 child->fNextSibling = child;
603 child->fPrevSibling = child;
604 }
605 else
606 {
607 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
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000616 this->invokeLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617DONE:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000618 return child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619}
620
621void SkView::detachAllChildren()
622{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000623 while (fFirstChild)
624 fFirstChild->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625}
626
reed@google.comf03bb562011-11-11 21:42:12 +0000627void SkView::localToGlobal(SkMatrix* matrix) const
628{
629 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
660/* 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*/
663void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
664{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000665 SkScalar x, y;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000667 x = this->locX();
668 y = this->locY();
669 (void)dom.findScalar(node, "x", &x);
670 (void)dom.findScalar(node, "y", &y);
671 this->setLoc(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000672
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000673 x = this->width();
674 y = this->height();
675 (void)dom.findScalar(node, "width", &x);
676 (void)dom.findScalar(node, "height", &y);
677 this->setSize(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000679 // inflate the flags
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000681 static const char* gFlagNames[] = {
682 "visible", "enabled", "focusable", "flexH", "flexV"
683 };
684 SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000686 bool b;
687 uint32_t flags = this->getFlags();
688 for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++)
689 if (dom.findBool(node, gFlagNames[i], &b))
690 flags = SkSetClearShift(flags, b, i);
691 this->setFlags(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692}
693
694void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node)
695{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000696 this->onInflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697}
698
699void SkView::onPostInflate(const SkTDict<SkView*>&)
700{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000701 // override in subclass as needed
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702}
703
704void SkView::postInflate(const SkTDict<SkView*>& dict)
705{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000706 this->onPostInflate(dict);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000707
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000708 B2FIter iter(this);
709 SkView* child;
710 while ((child = iter.next()) != NULL)
711 child->postInflate(dict);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712}
713
714//////////////////////////////////////////////////////////////////
715
716SkView* SkView::sendEventToParents(const SkEvent& evt)
717{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000718 SkView* parent = fParent;
reed@android.com34245c72009-11-03 04:00:48 +0000719
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000720 while (parent)
721 {
722 if (parent->doEvent(evt))
723 return parent;
724 parent = parent->fParent;
725 }
726 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000727}
728
reed@android.com34245c72009-11-03 04:00:48 +0000729SkView* SkView::sendQueryToParents(SkEvent* evt) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000730 SkView* parent = fParent;
reed@android.com34245c72009-11-03 04:00:48 +0000731
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000732 while (parent) {
733 if (parent->doQuery(evt)) {
734 return parent;
reed@android.com34245c72009-11-03 04:00:48 +0000735 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000736 parent = parent->fParent;
737 }
738 return NULL;
reed@android.com34245c72009-11-03 04:00:48 +0000739}
740
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741//////////////////////////////////////////////////////////////////
742//////////////////////////////////////////////////////////////////
743
744SkView::F2BIter::F2BIter(const SkView* parent)
745{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000746 fFirstChild = parent ? parent->fFirstChild : NULL;
747 fChild = fFirstChild ? fFirstChild->fPrevSibling : NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000748}
749
750SkView* SkView::F2BIter::next()
751{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000752 SkView* curr = fChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000754 if (fChild)
755 {
756 if (fChild == fFirstChild)
757 fChild = NULL;
758 else
759 fChild = fChild->fPrevSibling;
760 }
761 return curr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762}
763
764SkView::B2FIter::B2FIter(const SkView* parent)
765{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000766 fFirstChild = parent ? parent->fFirstChild : NULL;
767 fChild = fFirstChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768}
769
770SkView* SkView::B2FIter::next()
771{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000772 SkView* curr = fChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000774 if (fChild)
775 {
776 SkView* next = fChild->fNextSibling;
777 if (next == fFirstChild)
778 next = NULL;
779 fChild = next;
780 }
781 return curr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782}
783
784//////////////////////////////////////////////////////////////////
785//////////////////////////////////////////////////////////////////
786
787#ifdef SK_DEBUG
788
789static inline void show_if_nonzero(const char name[], SkScalar value)
790{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000791 if (value)
792 SkDebugf("%s=\"%g\"", name, value/65536.);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000793}
794
795static void tab(int level)
796{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000797 for (int i = 0; i < level; i++)
798 SkDebugf(" ");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799}
800
801static void dumpview(const SkView* view, int level, bool recurse)
802{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000803 tab(level);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000805 SkDebugf("<view");
806 show_if_nonzero(" x", view->locX());
807 show_if_nonzero(" y", view->locY());
808 show_if_nonzero(" width", view->width());
809 show_if_nonzero(" height", view->height());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000811 if (recurse)
812 {
813 SkView::B2FIter iter(view);
814 SkView* child;
815 bool noChildren = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000817 while ((child = iter.next()) != NULL)
818 {
819 if (noChildren)
820 SkDebugf(">\n");
821 noChildren = false;
822 dumpview(child, level + 1, true);
823 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000825 if (!noChildren)
826 {
827 tab(level);
828 SkDebugf("</view>\n");
829 }
830 else
831 goto ONELINER;
832 }
833 else
834 {
835 ONELINER:
836 SkDebugf(" />\n");
837 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838}
839
840void SkView::dump(bool recurse) const
841{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000842 dumpview(this, 0, recurse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843}
844
845#endif