• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 SkEvent* SkListSource::getEvent(int index)
18 {
19 	return NULL;
20 }
21 
22 #include "SkOSFile.h"
23 
24 class SkDirListSource : public SkListSource {
25 public:
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 
98 private:
99 	SkString		fPath, fSuffix;
100 	SkString		fTarget;
101 	SkOSFile::Iter	fIter;
102 	int				fCount;
103 	int				fIndex;
104 };
105 
106 SkListSource* SkListSource::CreateFromDir(const char path[], const char suffix[], const char target[])
107 {
108 	return new SkDirListSource(path, suffix, target);
109 }
110 
111 //////////////////////////////////////////////////////////////////
112 
113 class SkDOMListSource : public SkListSource {
114 public:
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 
196 private:
197 	int			fCount;
198 	ItemRec*	fList;
199 	SkString	fDirTail;
200 };
201 
202 SkListSource* SkListSource::CreateFromDOM(const SkDOM& dom, const SkDOM::Node* node)
203 {
204 	return new SkDOMListSource(dom, node);
205 }
206 
207 //////////////////////////////////////////////////////////////////
208 //////////////////////////////////////////////////////////////////
209 
210 SkListView::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 
226 SkListView::~SkListView()
227 {
228 	delete[] fStrCache;
229 	fSource->safeUnref();
230 }
231 
232 void 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 
244 void 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 
262 void 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 
275 void 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 
288 void SkListView::invalSelection()
289 {
290 	SkRect	r;
291 	if (this->getRowRect(fCurrIndex, &r))
292 		this->inval(&r);
293 }
294 
295 void 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 
318 bool 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 
336 SkPaint& SkListView::paint(Attr attr)
337 {
338 	SkASSERT((unsigned)attr < kAttrCount);
339 	return fPaint[attr];
340 }
341 
342 SkListSource* 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 
354 void 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 
402 void 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 
419 void SkListView::dirtyStrCache()
420 {
421 	if (fStrCache)
422 	{
423 		delete[] fStrCache;
424 		fStrCache = NULL;
425 	}
426 }
427 
428 void 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 
440 bool 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 
474 void 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 
518 class SkScrollBarView : public SkView {
519 public:
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 	}
533 protected:
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 	}
545 private:
546 	SkBitmapRef*	fBGRef, *fFGRef;
547 };
548 
549 SkGridView::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 
566 SkGridView::~SkGridView()
567 {
568 	fSource->safeUnref();
569 }
570 
571 void SkGridView::getCellSize(SkPoint* size) const
572 {
573 	if (size)
574 		*size = fCellSize;
575 }
576 
577 void 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 
588 void 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 
607 void 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 
620 void 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 
633 void 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 
648 void 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 
672 bool 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 
698 SkPaint& SkGridView::paint(Attr attr)
699 {
700 	SkASSERT((unsigned)attr < kAttrCount);
701 	return fPaint[attr];
702 }
703 
704 SkListSource* 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 
718 static 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 
737 void 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 
796 static 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 
804 void 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 
831 bool 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 
863 void 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