1
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 */
8#include "SkWidget.h"
9#include "SkCanvas.h"
10#include "SkEvent.h"
11#include "SkKey.h"
12#include "SkParsePaint.h"
13#include "SkSystemEventTypes.h"
14
15#if 0
16
17SkEvent* SkListSource::getEvent(int index)
18{
19	return NULL;
20}
21
22#include "SkOSFile.h"
23
24class SkDirListSource : public SkListSource {
25public:
26	SkDirListSource(const char path[], const char suffix[], const char target[])
27		: fPath(path), fSuffix(suffix), fTarget(target)
28	{
29		fCount = -1;
30	}
31	virtual int	countRows()
32	{
33		if (fCount < 0)
34		{
35			fCount = 0;
36			fIter.reset(fPath.c_str(), fSuffix.c_str());
37			while (fIter.next(NULL))
38				fCount += 1;
39			fIter.reset(fPath.c_str(), fSuffix.c_str());
40			fIndex = 0;
41		}
42		return fCount;
43	}
44	virtual void getRow(int index, SkString* left, SkString* right)
45	{
46		(void)this->countRows();
47		SkASSERT((unsigned)index < (unsigned)fCount);
48
49		if (fIndex > index)
50		{
51			fIter.reset(fPath.c_str(), fSuffix.c_str());
52			fIndex = 0;
53		}
54
55		while (fIndex < index)
56		{
57			fIter.next(NULL);
58			fIndex += 1;
59		}
60
61		if (fIter.next(left))
62		{
63			if (left)
64				left->remove(left->size() - fSuffix.size(), fSuffix.size());
65		}
66		else
67		{
68			if (left)
69				left->reset();
70		}
71		if (right)	// only set to ">" if we know we're on a sub-directory
72			right->reset();
73
74		fIndex += 1;
75	}
76	virtual SkEvent* getEvent(int index)
77	{
78		SkASSERT((unsigned)index < (unsigned)fCount);
79
80		SkEvent*	evt = new SkEvent();
81		SkString	label;
82
83		this->getRow(index, &label, NULL);
84		evt->setString("name", label.c_str());
85
86		int c = fPath.c_str()[fPath.size() - 1];
87		if (c != '/' && c != '\\')
88			label.prepend("/");
89		label.prepend(fPath);
90		label.append(fSuffix);
91		evt->setString("path", label.c_str());
92		evt->setS32("index", index);
93		evt->setS32("duration", 22);
94		evt->setType(fTarget);
95		return evt;
96	}
97
98private:
99	SkString		fPath, fSuffix;
100	SkString		fTarget;
101	SkOSFile::Iter	fIter;
102	int				fCount;
103	int				fIndex;
104};
105
106SkListSource* SkListSource::CreateFromDir(const char path[], const char suffix[], const char target[])
107{
108	return new SkDirListSource(path, suffix, target);
109}
110
111//////////////////////////////////////////////////////////////////
112
113class SkDOMListSource : public SkListSource {
114public:
115	enum Type {
116		kUnknown_Type,
117		kDir_Type,
118		kToggle_Type
119	};
120	struct ItemRec {
121		SkString	fLabel;
122		SkString	fTail, fAltTail;
123		SkString	fTarget;
124		Type		fType;
125	};
126
127	SkDOMListSource(const SkDOM& dom, const SkDOM::Node* node) : fDirTail(">")
128	{
129		const SkDOM::Node* child = dom.getFirstChild(node, "item");
130		int	count = 0;
131
132		while (child)
133		{
134			count += 1;
135			child = dom.getNextSibling(child, "item");
136		}
137
138		fCount = count;
139		fList = NULL;
140		if (count)
141		{
142			ItemRec* rec = fList = new ItemRec[count];
143
144			child = dom.getFirstChild(node, "item");
145			while (child)
146			{
147				rec->fLabel.set(dom.findAttr(child, "label"));
148				rec->fTail.set(dom.findAttr(child, "tail"));
149				rec->fAltTail.set(dom.findAttr(child, "alt-tail"));
150				rec->fTarget.set(dom.findAttr(child, "target"));
151				rec->fType = kUnknown_Type;
152
153				int	index = dom.findList(child, "type", "dir,toggle");
154				if (index >= 0)
155					rec->fType = (Type)(index + 1);
156
157				child = dom.getNextSibling(child, "item");
158				rec += 1;
159			}
160		}
161	}
162	virtual ~SkDOMListSource()
163	{
164		delete[] fList;
165	}
166	virtual int	countRows()
167	{
168		return fCount;
169	}
170	virtual void getRow(int index, SkString* left, SkString* right)
171	{
172		SkASSERT((unsigned)index < (unsigned)fCount);
173
174		if (left)
175			*left = fList[index].fLabel;
176		if (right)
177			*right = fList[index].fType == kDir_Type ? fDirTail : fList[index].fTail;
178	}
179	virtual SkEvent* getEvent(int index)
180	{
181		SkASSERT((unsigned)index < (unsigned)fCount);
182
183		if (fList[index].fType == kDir_Type)
184		{
185			SkEvent* evt = new SkEvent();
186			evt->setType(fList[index].fTarget);
187			evt->setFast32(index);
188			return evt;
189		}
190		if (fList[index].fType == kToggle_Type)
191			fList[index].fTail.swap(fList[index].fAltTail);
192
193		return NULL;
194	}
195
196private:
197	int			fCount;
198	ItemRec*	fList;
199	SkString	fDirTail;
200};
201
202SkListSource* SkListSource::CreateFromDOM(const SkDOM& dom, const SkDOM::Node* node)
203{
204	return new SkDOMListSource(dom, node);
205}
206
207//////////////////////////////////////////////////////////////////
208//////////////////////////////////////////////////////////////////
209
210SkListView::SkListView(U32 flags) : SkWidgetView(flags)
211{
212	fSource = NULL;
213	fScrollIndex = 0;
214	fCurrIndex = -1;
215	fRowHeight = SkIntToScalar(16);
216	fVisibleRowCount = 0;
217	fStrCache = NULL;
218
219	fPaint[kBG_Attr].setColor(0);
220	fPaint[kNormalText_Attr].setTextSize(SkIntToScalar(14));
221	fPaint[kHiliteText_Attr].setTextSize(SkIntToScalar(14));
222	fPaint[kHiliteText_Attr].setColor(SK_ColorWHITE);
223	fPaint[kHiliteCell_Attr].setColor(SK_ColorBLUE);
224}
225
226SkListView::~SkListView()
227{
228	delete[] fStrCache;
229	fSource->safeUnref();
230}
231
232void SkListView::setRowHeight(SkScalar height)
233{
234	SkASSERT(height >= 0);
235
236	if (fRowHeight != height)
237	{
238		fRowHeight = height;
239		this->inval(NULL);
240		this->onSizeChange();
241	}
242}
243
244void SkListView::setSelection(int index)
245{
246	if (fCurrIndex != index)
247	{
248		this->invalSelection();
249		fCurrIndex = index;
250		this->invalSelection();
251		this->ensureSelectionIsVisible();
252
253		{
254			SkEvent	evt;
255			evt.setType("listview-selection");
256			evt.setFast32(index);
257			this->sendEventToParents(evt);
258		}
259	}
260}
261
262void SkListView::moveSelectionUp()
263{
264	if (fSource)
265	{
266		int	index = fCurrIndex;
267		if (index < 0)	// no selection
268			index = fSource->countRows() - 1;
269		else
270			index = SkMax32(index - 1, 0);
271		this->setSelection(index);
272	}
273}
274
275void SkListView::moveSelectionDown()
276{
277	if (fSource)
278	{
279		int	index = fCurrIndex;
280		if (index < 0)	// no selection
281			index = 0;
282		else
283			index = SkMin32(index + 1, fSource->countRows() - 1);
284		this->setSelection(index);
285	}
286}
287
288void SkListView::invalSelection()
289{
290	SkRect	r;
291	if (this->getRowRect(fCurrIndex, &r))
292		this->inval(&r);
293}
294
295void SkListView::ensureSelectionIsVisible()
296{
297	if (fSource == NULL)
298		return;
299
300	if ((unsigned)fCurrIndex < (unsigned)fSource->countRows())
301	{
302		int index = this->logicalToVisualIndex(fCurrIndex);
303
304		if ((unsigned)index >= (unsigned)fVisibleRowCount)	// need to scroll
305		{
306			if (index < 0)	// too high
307				fScrollIndex = fCurrIndex;
308			else
309				fScrollIndex = fCurrIndex - fVisibleRowCount + 1;
310			SkASSERT((unsigned)fScrollIndex < (unsigned)fSource->countRows());
311
312			this->dirtyStrCache();
313			this->inval(NULL);
314		}
315	}
316}
317
318bool SkListView::getRowRect(int index, SkRect* r) const
319{
320	SkASSERT(r);
321	index = this->logicalToVisualIndex(index);
322	if (index >= 0)
323	{
324		SkScalar top = index * fRowHeight;
325
326		if (top < this->height())
327		{
328			if (r)
329				r->set(0, top, this->width(), top + fRowHeight);
330			return true;
331		}
332	}
333	return false;
334}
335
336SkPaint& SkListView::paint(Attr attr)
337{
338	SkASSERT((unsigned)attr < kAttrCount);
339	return fPaint[attr];
340}
341
342SkListSource* SkListView::setListSource(SkListSource* src)
343{
344	if (fSource != src)
345	{
346		SkRefCnt_SafeAssign(fSource, src);
347		this->dirtyStrCache();
348		this->ensureSelectionIsVisible();
349		this->inval(NULL);
350	}
351	return src;
352}
353
354void SkListView::onDraw(SkCanvas* canvas)
355{
356	this->INHERITED::onDraw(canvas);
357
358	canvas->drawPaint(fPaint[kBG_Attr]);
359
360	int	visibleCount = SkMin32(fVisibleRowCount, fSource->countRows() - fScrollIndex);
361	if (visibleCount == 0)
362		return;
363
364	this->ensureStrCache(visibleCount);
365	int currIndex = this->logicalToVisualIndex(fCurrIndex);
366
367	if ((unsigned)currIndex < (unsigned)visibleCount)
368	{
369		SkAutoCanvasRestore	restore(canvas, true);
370		SkRect	r;
371
372		canvas->translate(0, currIndex * fRowHeight);
373		(void)this->getRowRect(fScrollIndex, &r);
374		canvas->drawRect(r, fPaint[kHiliteCell_Attr]);
375	}
376
377	SkPaint*	p;
378	SkScalar	y, x = SkIntToScalar(6);
379	SkScalar	rite = this->width() - x;
380
381	{
382		SkScalar ascent, descent;
383		fPaint[kNormalText_Attr].measureText(0, NULL, &ascent, &descent);
384		y = SkScalarHalf(fRowHeight - descent + ascent) - ascent;
385	}
386
387	for (int i = 0; i < visibleCount; i++)
388	{
389		if (i == currIndex)
390			p = &fPaint[kHiliteText_Attr];
391		else
392			p = &fPaint[kNormalText_Attr];
393
394		p->setTextAlign(SkPaint::kLeft_Align);
395		canvas->drawText(fStrCache[i].c_str(), fStrCache[i].size(), x, y, *p);
396		p->setTextAlign(SkPaint::kRight_Align);
397		canvas->drawText(fStrCache[i + visibleCount].c_str(), fStrCache[i + visibleCount].size(), rite, y, *p);
398		canvas->translate(0, fRowHeight);
399	}
400}
401
402void SkListView::onSizeChange()
403{
404	SkScalar count = SkScalarDiv(this->height(), fRowHeight);
405	int		 n = SkScalarFloor(count);
406
407	// only want to show rows that are mostly visible
408	if (n == 0 || count - SkIntToScalar(n) > SK_Scalar1*75/100)
409		n += 1;
410
411	if (fVisibleRowCount != n)
412	{
413		fVisibleRowCount = n;
414		this->ensureSelectionIsVisible();
415		this->dirtyStrCache();
416	}
417}
418
419void SkListView::dirtyStrCache()
420{
421	if (fStrCache)
422	{
423		delete[] fStrCache;
424		fStrCache = NULL;
425	}
426}
427
428void SkListView::ensureStrCache(int count)
429{
430	if (fStrCache == NULL)
431	{
432		fStrCache = new SkString[count << 1];
433
434		if (fSource)
435			for (int i = 0; i < count; i++)
436				fSource->getRow(i + fScrollIndex, &fStrCache[i], &fStrCache[i + count]);
437	}
438}
439
440bool SkListView::onEvent(const SkEvent& evt)
441{
442	if (evt.isType(SK_EventType_Key))
443	{
444		switch (evt.getFast32()) {
445		case kUp_SkKey:
446			this->moveSelectionUp();
447			return true;
448		case kDown_SkKey:
449			this->moveSelectionDown();
450			return true;
451		case kRight_SkKey:
452		case kOK_SkKey:
453			if (fSource && fCurrIndex >= 0)
454			{
455				SkEvent* evt = fSource->getEvent(fCurrIndex);
456				if (evt)
457				{
458					SkView* view = this->sendEventToParents(*evt);
459					delete evt;
460					return view != NULL;
461				}
462				else	// hack to make toggle work
463				{
464					this->dirtyStrCache();
465					this->inval(NULL);
466				}
467			}
468			break;
469		}
470	}
471	return this->INHERITED::onEvent(evt);
472}
473
474void SkListView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
475{
476	this->INHERITED::onInflate(dom, node);
477
478	SkScalar			x;
479	const SkDOM::Node*	child;
480
481	if (dom.findScalar(node, "row-height", &x))
482		this->setRowHeight(x);
483
484	if ((child = dom.getFirstChild(node, "hilite-paint")) != NULL)
485		SkPaint_Inflate(&this->paint(kHiliteCell_Attr), dom, child);
486
487	// look for a listsource
488	{
489		SkListSource* src = NULL;
490
491		if ((child = dom.getFirstChild(node, "file-listsource")) != NULL)
492		{
493			const char* path = dom.findAttr(child, "path");
494			if (path)
495				src = SkListSource::CreateFromDir(	path,
496													dom.findAttr(child, "filter"),
497													dom.findAttr(child, "target"));
498		}
499		else if ((child = dom.getFirstChild(node, "xml-listsource")) != NULL)
500		{
501			src = SkListSource::CreateFromDOM(dom, child);
502		}
503
504		if (src)
505		{
506			this->setListSource(src)->unref();
507			this->setSelection(0);
508		}
509	}
510}
511
512///////////////////////////////////////////////////////////////////////////////////////////
513///////////////////////////////////////////////////////////////////////////////////////////
514
515#include "SkImageDecoder.h"
516#include "SkShader.h"
517
518class SkScrollBarView : public SkView {
519public:
520	SkScrollBarView(const char bg[], const char fg[])
521	{
522		fBGRef = SkBitmapRef::Decode(bg, true);
523		fFGRef = SkBitmapRef::Decode(fg, true);
524
525		if (fBGRef)
526			this->setWidth(SkIntToScalar(fBGRef->bitmap().width()));
527	}
528	~SkScrollBarView()
529	{
530		delete fBGRef;
531		delete fFGRef;
532	}
533protected:
534	virtual void onDraw(SkCanvas* canvas)
535	{
536		if (fBGRef == NULL) return;
537
538		SkPaint	paint;
539
540		SkShader* shader = SkShader::CreateBitmapShader(fBGRef->bitmap(), false, SkPaint::kNo_FilterType, SkShader::kClamp_TileMode);
541		paint.setShader(shader)->unref();
542
543		canvas->drawPaint(paint);
544	}
545private:
546	SkBitmapRef*	fBGRef, *fFGRef;
547};
548
549SkGridView::SkGridView(U32 flags) : SkWidgetView(flags)
550{
551	fSource = NULL;
552	fCurrIndex = -1;
553	fVisibleCount.set(0, 0);
554
555	fPaint[kBG_Attr].setColor(SK_ColorWHITE);
556	fPaint[kHiliteCell_Attr].setColor(SK_ColorYELLOW);
557	fPaint[kHiliteCell_Attr].setStyle(SkPaint::kStroke_Style);
558	fPaint[kHiliteCell_Attr].setAntiAliasOn(true);
559	fPaint[kHiliteCell_Attr].setStrokeWidth(SK_Scalar1*3);
560
561	fScrollBar = new SkScrollBarView("icons/scrollbarGrey.jpg", "icons/scrollbarBlue.jpg");
562	this->attachChildToFront(fScrollBar)->unref();
563	fScrollBar->setVisibleP(true);
564}
565
566SkGridView::~SkGridView()
567{
568	fSource->safeUnref();
569}
570
571void SkGridView::getCellSize(SkPoint* size) const
572{
573	if (size)
574		*size = fCellSize;
575}
576
577void SkGridView::setCellSize(SkScalar x, SkScalar y)
578{
579	SkASSERT(x >= 0 && y >= 0);
580
581	if (!fCellSize.equals(x, y))
582	{
583		fCellSize.set(x, y);
584		this->inval(NULL);
585	}
586}
587
588void SkGridView::setSelection(int index)
589{
590	if (fCurrIndex != index)
591	{
592		this->invalSelection();
593		fCurrIndex = index;
594		this->invalSelection();
595		this->ensureSelectionIsVisible();
596
597		// this generates the click
598		{
599			SkEvent	evt;
600			evt.setType("listview-selection");
601			evt.setFast32(index);
602			this->sendEventToParents(evt);
603		}
604	}
605}
606
607void SkGridView::moveSelectionUp()
608{
609	if (fSource)
610	{
611		int	index = fCurrIndex;
612		if (index < 0)	// no selection
613			index = fSource->countRows() - 1;
614		else
615			index = SkMax32(index - 1, 0);
616		this->setSelection(index);
617	}
618}
619
620void SkGridView::moveSelectionDown()
621{
622	if (fSource)
623	{
624		int	index = fCurrIndex;
625		if (index < 0)	// no selection
626			index = 0;
627		else
628			index = SkMin32(index + 1, fSource->countRows() - 1);
629		this->setSelection(index);
630	}
631}
632
633void SkGridView::invalSelection()
634{
635	SkRect	r;
636	if (this->getCellRect(fCurrIndex, &r))
637	{
638		SkScalar inset = 0;
639		if (fPaint[kHiliteCell_Attr].getStyle() != SkPaint::kFill_Style)
640			inset += fPaint[kHiliteCell_Attr].getStrokeWidth() / 2;
641		if (fPaint[kHiliteCell_Attr].isAntiAliasOn())
642			inset += SK_Scalar1;
643		r.inset(-inset, -inset);
644		this->inval(&r);
645	}
646}
647
648void SkGridView::ensureSelectionIsVisible()
649{
650	if (fSource == NULL)
651		return;
652#if 0
653	if ((unsigned)fCurrIndex < (unsigned)fSource->countRows())
654	{
655		int index = this->logicalToVisualIndex(fCurrIndex);
656
657		if ((unsigned)index >= (unsigned)fVisibleRowCount)	// need to scroll
658		{
659			if (index < 0)	// too high
660				fScrollIndex = fCurrIndex;
661			else
662				fScrollIndex = fCurrIndex - fVisibleRowCount + 1;
663			SkASSERT((unsigned)fScrollIndex < (unsigned)fSource->countRows());
664
665			this->dirtyStrCache();
666			this->inval(NULL);
667		}
668	}
669#endif
670}
671
672bool SkGridView::getCellRect(int index, SkRect* r) const
673{
674	if (fVisibleCount.fY == 0)
675		return false;
676
677	index = this->logicalToVisualIndex(index);
678	if (index >= 0)
679	{
680		SkRect	bounds;
681		int row = index / fVisibleCount.fY;
682		int col = index % fVisibleCount.fY;
683
684		bounds.set(0, 0, fCellSize.fX, fCellSize.fY);
685		bounds.offset(col * (fCellSize.fX + SkIntToScalar(col > 0)),
686					  row * (fCellSize.fY + SkIntToScalar(row > 0)));
687
688		if (bounds.fTop < this->height())
689		{
690			if (r)
691				*r = bounds;
692			return true;
693		}
694	}
695	return false;
696}
697
698SkPaint& SkGridView::paint(Attr attr)
699{
700	SkASSERT((unsigned)attr < kAttrCount);
701	return fPaint[attr];
702}
703
704SkListSource* SkGridView::setListSource(SkListSource* src)
705{
706	if (fSource != src)
707	{
708		SkRefCnt_SafeAssign(fSource, src);
709	//	this->dirtyStrCache();
710		this->ensureSelectionIsVisible();
711		this->inval(NULL);
712	}
713	return src;
714}
715
716#include "SkShader.h"
717
718static void copybits(SkCanvas* canvas, const SkBitmap& bm, const SkRect& dst, const SkPaint& paint)
719{
720	SkRect		src;
721	SkMatrix	matrix;
722
723	src.set(0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()));
724	if (matrix.setRectToRect(src, dst))
725	{
726		SkPaint	  p(paint);
727		SkShader* shader = SkShader::CreateBitmapShader(bm, false, SkPaint::kNo_FilterType, SkShader::kClamp_TileMode);
728		p.setShader(shader)->unref();
729
730		shader->setLocalMatrix(matrix);
731		canvas->drawRect(dst, p);
732	}
733}
734
735#include "SkImageDecoder.h"
736
737void SkGridView::onDraw(SkCanvas* canvas)
738{
739	this->INHERITED::onDraw(canvas);
740
741	canvas->drawPaint(fPaint[kBG_Attr]);
742
743	if (fSource == NULL)
744		return;
745
746#if 0
747	int	visibleCount = SkMin32(fVisibleRowCount, fSource->countRows() - fScrollIndex);
748	if (visibleCount == 0)
749		return;
750
751	this->ensureStrCache(visibleCount);
752	int currIndex = this->logicalToVisualIndex(fCurrIndex);
753#endif
754
755	SkPaint	p;
756	for (int i = 0; i < fSource->countRows(); i++)
757	{
758		bool	 forced = false;
759		SkEvent* evt = fSource->getEvent(i);
760		SkASSERT(evt);
761		SkString path(evt->findString("path"));
762		delete evt;
763
764		SkBitmapRef* bmr = SkBitmapRef::Decode(path.c_str(), false);
765		if (bmr == NULL)
766		{
767			bmr = SkBitmapRef::Decode(path.c_str(), true);
768			if (bmr)
769				forced = true;
770		}
771
772		if (bmr)
773		{
774			SkAutoTDelete<SkBitmapRef>	autoRef(bmr);
775			SkRect	r;
776			if (!this->getCellRect(i, &r))
777				break;
778			copybits(canvas, bmr->bitmap(), r, p);
779		}
780		// only draw one forced bitmap at a time
781		if (forced)
782		{
783			this->inval(NULL);	// could inval only the remaining visible cells...
784			break;
785		}
786	}
787
788	// draw the hilite
789	{
790		SkRect	r;
791		if (fCurrIndex >= 0 && this->getCellRect(fCurrIndex, &r))
792			canvas->drawRect(r, fPaint[kHiliteCell_Attr]);
793	}
794}
795
796static int check_count(int n, SkScalar s)
797{
798	// only want to show cells that are mostly visible
799	if (n == 0 || s - SkIntToScalar(n) > SK_Scalar1*75/100)
800		n += 1;
801	return n;
802}
803
804void SkGridView::onSizeChange()
805{
806	fScrollBar->setHeight(this->height());
807	fScrollBar->setLoc(this->locX() + this->width() - fScrollBar->width(), 0);
808
809	if (fCellSize.equals(0, 0))
810	{
811		fVisibleCount.set(0, 0);
812		return;
813	}
814
815	SkScalar rows = SkScalarDiv(this->height(), fCellSize.fY);
816	SkScalar cols = SkScalarDiv(this->width(), fCellSize.fX);
817	int		 y = SkScalarFloor(rows);
818	int		 x = SkScalarFloor(cols);
819
820	y = check_count(y, rows);
821	x = check_count(x, cols);
822
823	if (!fVisibleCount.equals(x, y))
824	{
825		fVisibleCount.set(x, y);
826		this->ensureSelectionIsVisible();
827	//	this->dirtyStrCache();
828	}
829}
830
831bool SkGridView::onEvent(const SkEvent& evt)
832{
833	if (evt.isType(SK_EventType_Key))
834	{
835		switch (evt.getFast32()) {
836		case kUp_SkKey:
837			this->moveSelectionUp();
838			return true;
839		case kDown_SkKey:
840			this->moveSelectionDown();
841			return true;
842		case kRight_SkKey:
843		case kOK_SkKey:
844			if (fSource && fCurrIndex >= 0)
845			{
846				SkEvent* evt = fSource->getEvent(fCurrIndex);
847				if (evt)
848				{
849					// augment the event with our local rect
850					(void)this->getCellRect(fCurrIndex, (SkRect*)evt->setScalars("local-rect", 4, NULL));
851
852					SkView* view = this->sendEventToParents(*evt);
853					delete evt;
854					return view != NULL;
855				}
856			}
857			break;
858		}
859	}
860	return this->INHERITED::onEvent(evt);
861}
862
863void SkGridView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
864{
865	this->INHERITED::onInflate(dom, node);
866
867	SkScalar			x[2];
868	const SkDOM::Node*	child;
869
870	if (dom.findScalars(node, "cell-size", x, 2))
871		this->setCellSize(x[0], x[1]);
872
873	if ((child = dom.getFirstChild(node, "hilite-paint")) != NULL)
874		SkPaint_Inflate(&this->paint(kHiliteCell_Attr), dom, child);
875
876	// look for a listsource
877	{
878		SkListSource* src = NULL;
879
880		if ((child = dom.getFirstChild(node, "file-listsource")) != NULL)
881		{
882			const char* path = dom.findAttr(child, "path");
883			if (path)
884				src = SkListSource::CreateFromDir(	path,
885													dom.findAttr(child, "filter"),
886													dom.findAttr(child, "target"));
887		}
888		else if ((child = dom.getFirstChild(node, "xml-listsource")) != NULL)
889		{
890			src = SkListSource::CreateFromDOM(dom, child);
891		}
892
893		if (src)
894		{
895			this->setListSource(src)->unref();
896			this->setSelection(0);
897		}
898	}
899	this->onSizeChange();
900}
901
902#endif
903