11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2011 Google Inc.
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
80b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkWidgetViews.h"
90b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkAnimator.h"
110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkScrollBarView.h"
120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerextern void init_skin_anim(const char name[], SkAnimator*);
140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerstruct SkListView::BindingRec {
160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkString	fSlotName;
170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	int			fFieldIndex;
180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger};
190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
200b15698a8c76bb8abc1b555c1d91892669b4118fDerek SollenbergerSkListView::SkListView()
210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fSource = NULL;				// our list-source
230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fScrollBar = NULL;
240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fAnims = NULL;				// array of animators[fVisibleRowCount]
250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fBindings = NULL;			// our fields->slot array
260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fBindingCount = 0;			// number of entries in fSlots array
270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fScrollIndex = 0;			// number of cells to skip before first visible cell
280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fCurrIndex = -1;			// index of "selected" cell
290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fVisibleRowCount = 0;		// number of cells that can fit in our bounds
300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fAnimContentDirty = true;	// true if fAnims[] have their correct content
310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fAnimFocusDirty = true;
320b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fHeights[kNormal_Height] = SkIntToScalar(16);
340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fHeights[kSelected_Height] = SkIntToScalar(16);
350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	this->setFlags(this->getFlags() | kFocusable_Mask);
370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
380b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
390b15698a8c76bb8abc1b555c1d91892669b4118fDerek SollenbergerSkListView::~SkListView()
400b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
410b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkSafeUnref(fScrollBar);
420b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkSafeUnref(fSource);
430b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	delete[] fAnims;
440b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	delete[] fBindings;
450b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
460b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
470b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::setHasScrollBar(bool hasSB)
480b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
490b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (hasSB != this->hasScrollBar())
500b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
510b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (hasSB)
520b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
530b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			SkASSERT(fScrollBar == NULL);
540b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar = (SkScrollBarView*)SkWidgetFactory(kScroll_WidgetEnum);
550b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar->setVisibleP(true);
560b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->attachChildToFront(fScrollBar);
570b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar->setHeight(this->height());	// assume it auto-sets its width
580b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		//	fScrollBar->setLoc(this->getContentWidth(), 0);
590b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar->setLoc(this->width()-SkIntToScalar(10), 0);
600b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
610b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		else
620b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
630b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			SkASSERT(fScrollBar);
640b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar->detachFromParent();
650b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar->unref();
660b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar = NULL;
670b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
680b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->dirtyCache(kAnimContent_DirtyFlag);
690b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
700b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
710b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
720b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::setSelection(int index)
730b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
740b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fCurrIndex != index)
750b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
760b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimFocusDirty = true;
770b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->inval(NULL);
780b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
790b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->invalSelection();
800b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fCurrIndex = index;
810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->invalSelection();
820b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->ensureSelectionIsVisible();
830b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
840b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
850b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
860b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerbool SkListView::moveSelectionUp()
870b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
880b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fSource)
890b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
900b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int	index = fCurrIndex;
910b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (index < 0)	// no selection
920b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			index = fSource->countRecords() - 1;
930b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		else
940b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			index = SkMax32(index - 1, 0);
950b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
960b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (fCurrIndex != index)
970b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
980b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->setSelection(index);
990b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			return true;
1000b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
1010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
1020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return false;
1030b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1040b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1050b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerbool SkListView::moveSelectionDown()
1060b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
1070b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fSource)
1080b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
1090b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int	index = fCurrIndex;
1100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (index < 0)	// no selection
1110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			index = 0;
1120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		else
1130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			index = SkMin32(index + 1, fSource->countRecords() - 1);
1140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (fCurrIndex != index)
1160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
1170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->setSelection(index);
1180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			return true;
1190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
1200b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
1210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return false;
1220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::invalSelection()
1250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
1260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkRect	r;
1270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (this->getRowRect(fCurrIndex, &r))
1280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->inval(&r);
1290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::ensureSelectionIsVisible()
1320b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
1330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fSource && (unsigned)fCurrIndex < (unsigned)fSource->countRecords())
1340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
1350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int index = this->logicalToVisualIndex(fCurrIndex);
1360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if ((unsigned)index >= (unsigned)fVisibleRowCount)	// need to scroll
1380b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
1390b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			int newIndex;
1400b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1410b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			if (index < 0)	// too high
1420b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				newIndex = fCurrIndex;
1430b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			else
1440b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				newIndex = fCurrIndex - fVisibleRowCount + 1;
1450b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			SkASSERT((unsigned)newIndex < (unsigned)fSource->countRecords());
1460b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->inval(NULL);
1470b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1480b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			if (fScrollIndex != newIndex)
1490b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			{
1500b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				fScrollIndex = newIndex;
1510b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				if (fScrollBar)
1520b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger					fScrollBar->setStart(newIndex);
1530b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				this->dirtyCache(kAnimContent_DirtyFlag);
1540b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			}
1550b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
1560b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
1570b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1580b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1590b15698a8c76bb8abc1b555c1d91892669b4118fDerek SollenbergerSkScalar SkListView::getContentWidth() const
1600b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
1610b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkScalar width = this->width();
1620b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1630b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fScrollBar)
1640b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
1650b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		width -= fScrollBar->width();
1660b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (width < 0)
1670b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			width = 0;
1680b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
1690b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return width;
1700b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1710b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1720b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerbool SkListView::getRowRect(int index, SkRect* r) const
1730b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
1740b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkASSERT(r);
1750b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1760b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	index = this->logicalToVisualIndex(index);
1770b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (index >= 0)
1780b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
1790b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int	selection = this->logicalToVisualIndex(fCurrIndex);
1800b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkScalar height = fHeights[index == selection ? kSelected_Height : kNormal_Height];
1820b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkScalar top = index * fHeights[kNormal_Height];
1830b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1840b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (index > selection && selection >= 0)
1850b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			top += fHeights[kSelected_Height] - fHeights[kNormal_Height];
1860b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1870b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (top < this->height())
1880b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
1890b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			if (r)
1900b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				r->set(0, top, this->getContentWidth(), top + height);
1910b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			return true;
1920b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
1930b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
1940b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return false;
1950b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1960b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1970b15698a8c76bb8abc1b555c1d91892669b4118fDerek SollenbergerSkListSource* SkListView::setListSource(SkListSource* src)
1980b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
1990b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fSource != src)
2000b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
2010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkRefCnt_SafeAssign(fSource, src);
2020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->ensureSelectionIsVisible();
2030b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->inval(NULL);
2040b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2050b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (fScrollBar)
2060b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar->setTotal(fSource->countRecords());
2070b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
2080b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return src;
2090b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
2100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::dirtyCache(unsigned dirtyFlags)
2120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
2130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (dirtyFlags & kAnimCount_DirtyFlag)
2140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
2150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		delete fAnims;
2160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnims = NULL;
2170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimContentDirty = true;
2180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimFocusDirty = true;
2190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
2200b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (dirtyFlags & kAnimContent_DirtyFlag)
2210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
2220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (!fAnimContentDirty)
2230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
2240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->inval(NULL);
2250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fAnimContentDirty = true;
2260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
2270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimFocusDirty = true;
2280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
2290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
2300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerbool SkListView::ensureCache()
2320b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
2330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fSkinName.size() == 0)
2340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		return false;
2350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fAnims == NULL)
2370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
2380b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int n = SkMax32(1, fVisibleRowCount);
2390b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2400b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT(fAnimContentDirty);
2410b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnims = new SkAnimator[n];
2420b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		for (int i = 0; i < n; i++)
2430b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
2440b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fAnims[i].setHostEventSink(this);
2450b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			init_skin_anim(fSkinName.c_str(), &fAnims[i]);
2460b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
2470b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2480b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fHeights[kNormal_Height] = fAnims[0].getScalar("idleHeight", "value");
2490b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fHeights[kSelected_Height] = fAnims[0].getScalar("focusedHeight", "value");
2500b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2510b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimFocusDirty = true;
2520b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
2530b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2540b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fAnimContentDirty && fSource)
2550b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
2560b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimContentDirty = false;
2570b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2580b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkString	str;
2590b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkEvent		evt("user");
2600b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		evt.setString("id", "setFields");
2610b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		evt.setS32("rowCount", fVisibleRowCount);
2620b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2630b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkEvent	dimEvt("user");
2640b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		dimEvt.setString("id", "setDim");
2650b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		dimEvt.setScalar("dimX", this->getContentWidth());
2660b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		dimEvt.setScalar("dimY", this->height());
2670b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2680b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		for (int i = fScrollIndex; i < fScrollIndex + fVisibleRowCount; i++)
2690b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
2700b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			evt.setS32("relativeIndex", i - fScrollIndex);
2710b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			for (int j = 0; j < fBindingCount; j++)
2720b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			{
2730b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				fSource->getRecord(i, fBindings[j].fFieldIndex, &str);
2740b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger//SkDEBUGF(("getRecord(%d,%d,%s) slot(%s)\n", i, fBindings[j].fFieldIndex, str.c_str(), fBindings[j].fSlotName.c_str()));
2750b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				evt.setString(fBindings[j].fSlotName.c_str(), str.c_str());
2760b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			}
2770b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			(void)fAnims[i % fVisibleRowCount].doUserEvent(evt);
2780b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			(void)fAnims[i % fVisibleRowCount].doUserEvent(dimEvt);
2790b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
2800b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimFocusDirty = true;
2810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
2820b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2830b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fAnimFocusDirty)
2840b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
2850b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger//SkDEBUGF(("service fAnimFocusDirty\n"));
2860b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fAnimFocusDirty = false;
2870b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2880b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkEvent		focusEvt("user");
2890b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		focusEvt.setString("id", "setFocus");
2900b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2910b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		for (int i = fScrollIndex; i < fScrollIndex + fVisibleRowCount; i++)
2920b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
2930b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			focusEvt.setS32("FOCUS", i == fCurrIndex);
2940b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			(void)fAnims[i % fVisibleRowCount].doUserEvent(focusEvt);
2950b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
2960b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
2970b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
2980b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return true;
2990b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
3000b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::ensureVisibleRowCount()
3020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
3030b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkScalar	height = this->height();
3040b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	int			n = 0;
3050b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3060b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (height > 0)
3070b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
3080b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		n = 1;
3090b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		height -= fHeights[kSelected_Height];
3100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (height > 0)
3110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
3120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			SkScalar count = SkScalarDiv(height, fHeights[kNormal_Height]);
3130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			n += SkScalarFloor(count);
3140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			if (count - SkIntToScalar(n) > SK_Scalar1*3/4)
3150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				n += 1;
3160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		//	SkDebugf("count %g, n %d\n", count/65536., n);
3180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
3190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
3200b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fVisibleRowCount != n)
3220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
3230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (fScrollBar)
3240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fScrollBar->setShown(n);
3250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fVisibleRowCount = n;
3270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->ensureSelectionIsVisible();
3280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->dirtyCache(kAnimCount_DirtyFlag | kAnimContent_DirtyFlag);
3290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
3300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
3310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3320b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger///////////////////////////////////////////////////////////////////////////////////////////////
3330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkSystemEventTypes.h"
3350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkTime.h"
3360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::onSizeChange()
3380b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
3390b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	this->INHERITED::onSizeChange();
3400b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3410b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fScrollBar)
3420b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fScrollBar->setLoc(this->width()-SkIntToScalar(10), 0);
3430b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3440b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	this->ensureVisibleRowCount();
3450b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
3460b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3470b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::onDraw(SkCanvas* canvas)
3480b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
3490b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	this->INHERITED::onDraw(canvas);
3500b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3510b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	this->ensureVisibleRowCount();
3520b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3530b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	int	visibleCount = SkMin32(fVisibleRowCount, fSource->countRecords() - fScrollIndex);
3540b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (visibleCount == 0 || !this->ensureCache())
3550b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		return;
3560b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3570b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger//SkDebugf("visibleCount %d scrollIndex %d currIndex %d\n", visibleCount, fScrollIndex, fCurrIndex);
3580b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3590b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkAutoCanvasRestore	ar(canvas, true);
3600b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkMSec				now = SkTime::GetMSecs();
3610b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkRect				bounds;
3620b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3630b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	bounds.fLeft	= 0;
3640b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	bounds.fRight	= this->getContentWidth();
3650b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	bounds.fBottom	= 0;
3660b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	// assign bounds.fTop inside the loop
3670b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3680b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	// hack to reveal our bounds for debugging
3690b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (this->hasFocus())
3700b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		canvas->drawARGB(0x11, 0, 0, 0xFF);
3710b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	else
3720b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		canvas->drawARGB(0x11, 0x88, 0x88, 0x88);
3730b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3740b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	for (int i = fScrollIndex; i < fScrollIndex + visibleCount; i++)
3750b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
3760b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkPaint	 paint;
3770b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkScalar height = fHeights[i == fCurrIndex ? kSelected_Height : kNormal_Height];
3780b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3790b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		bounds.fTop = bounds.fBottom;
3800b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		bounds.fBottom += height;
3810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3820b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		canvas->save();
3830b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (fAnims[i % fVisibleRowCount].draw(canvas, &paint, now) != SkAnimator::kNotDifferent)
3840b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->inval(&bounds);
3850b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		canvas->restore();
3860b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3870b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		canvas->translate(0, height);
3880b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
3890b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
3900b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
3910b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerbool SkListView::onEvent(const SkEvent& evt)
3920b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
3930b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (evt.isType(SK_EventType_Key))
3940b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
3950b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		switch (evt.getFast32()) {
3960b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		case kUp_SkKey:
3970b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			return this->moveSelectionUp();
3980b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		case kDown_SkKey:
3990b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			return this->moveSelectionDown();
4000b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		case kRight_SkKey:
4010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		case kOK_SkKey:
4020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->postWidgetEvent();
4030b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			return true;
4040b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		default:
4050b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			break;
4060b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
4070b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
4080b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return this->INHERITED::onEvent(evt);
4090b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
4100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger///////////////////////////////////////////////////////////////////////////////////////////////
4120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerstatic const char gListViewEventSlot[] = "sk-listview-slot-name";
4140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger/*virtual*/ bool SkListView::onPrepareWidgetEvent(SkEvent* evt)
4160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
4170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (fSource && fCurrIndex >= 0 && this->INHERITED::onPrepareWidgetEvent(evt) &&
4180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fSource->prepareWidgetEvent(evt, fCurrIndex))
4190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
4200b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		evt->setS32(gListViewEventSlot, fCurrIndex);
4210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		return true;
4220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
4230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return false;
4240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
4250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerint SkListView::GetWidgetEventListIndex(const SkEvent& evt)
4270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
4280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	int32_t	index;
4290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return evt.findS32(gListViewEventSlot, &index) ? index : -1;
4310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
4320b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger///////////////////////////////////////////////////////////////////////////////////////////////
4340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkListView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
4360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
4370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	this->INHERITED::onInflate(dom, node);
4380b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4390b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
4400b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		bool hasScrollBar;
4410b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (dom.findBool(node, "scrollBar", &hasScrollBar))
4420b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			this->setHasScrollBar(hasScrollBar);
4430b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
4440b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4450b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	const SkDOM::Node*	child;
4460b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4470b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if ((child = dom.getFirstChild(node, "bindings")) != NULL)
4480b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
4490b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		delete[] fBindings;
4500b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fBindings = NULL;
4510b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fBindingCount = 0;
4520b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4530b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkListSource* listSrc = SkListSource::Factory(dom.findAttr(child, "data-fields"));
4540b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT(listSrc);
4550b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fSkinName.set(dom.findAttr(child, "skin-slots"));
4560b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT(fSkinName.size());
4570b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4580b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->setListSource(listSrc)->unref();
4590b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4600b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int count = dom.countChildren(child, "bind");
4610b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (count > 0)
4620b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
4630b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fBindings = new BindingRec[count];
4640b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			count = 0;	// reuse this to count up to the number of valid bindings
4650b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4660b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			child = dom.getFirstChild(child, "bind");
4670b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			SkASSERT(child);
4680b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			do {
4690b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				const char* fieldName = dom.findAttr(child, "field");
4700b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				const char* slotName = dom.findAttr(child, "slot");
4710b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				if (fieldName && slotName)
4720b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				{
4730b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger					fBindings[count].fFieldIndex = listSrc->findFieldIndex(fieldName);
4740b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger					if (fBindings[count].fFieldIndex >= 0)
4750b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger						fBindings[count++].fSlotName.set(slotName);
4760b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				}
4770b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			} while ((child = dom.getNextSibling(child, "bind")) != NULL);
4780b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4790b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fBindingCount = SkToU16(count);
4800b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			if (count == 0)
4810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			{
4820b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				SkDEBUGF(("SkListView::onInflate: no valid <bind> elements in <listsource>\n"));
4830b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				delete[] fBindings;
4840b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			}
4850b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
4860b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->dirtyCache(kAnimCount_DirtyFlag);
4870b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->setSelection(0);
4880b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
4890b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
4900b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4910b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger/////////////////////////////////////////////////////////////////////////////////////////////
4920b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger/////////////////////////////////////////////////////////////////////////////////////////////
4930b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
4940b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerclass SkXMLListSource : public SkListSource {
4950b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerpublic:
4960b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkXMLListSource(const char doc[], size_t len);
4970b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	virtual ~SkXMLListSource()
4980b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
4990b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		delete[] fFields;
5000b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		delete[] fRecords;
5010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
5020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5030b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	virtual int countFields() { return fFieldCount; }
5040b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	virtual void getFieldName(int index, SkString* field)
5050b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
5060b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT((unsigned)index < (unsigned)fFieldCount);
5070b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (field)
5080b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			*field = fFields[index];
5090b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
5100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	virtual int findFieldIndex(const char field[])
5110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
5120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		for (int i = 0; i < fFieldCount; i++)
5130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			if (fFields[i].equals(field))
5140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				return i;
5150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		return -1;
5160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
5170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	virtual int	countRecords() { return fRecordCount; }
5190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	virtual void getRecord(int rowIndex, int fieldIndex, SkString* data)
5200b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
5210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT((unsigned)rowIndex < (unsigned)fRecordCount);
5220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT((unsigned)fieldIndex < (unsigned)fFieldCount);
5230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		if (data)
5240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			*data = fRecords[rowIndex * fFieldCount + fieldIndex];
5250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
5260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	virtual bool prepareWidgetEvent(SkEvent* evt, int rowIndex)
5280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
5290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		// hack, for testing right now. Need the xml to tell us what to jam in and where
5300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkString	data;
5310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5320b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		this->getRecord(rowIndex, 0, &data);
5330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		evt->setString("xml-listsource", data.c_str());
5340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		return true;
5350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
5360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerprivate:
5380b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkString*	fFields;	// [fFieldCount]
5390b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkString*	fRecords;	// [fRecordCount][fFieldCount]
5400b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	int			fFieldCount, fRecordCount;
5410b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger};
5420b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5430b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkDOM.h"
5440b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5450b15698a8c76bb8abc1b555c1d91892669b4118fDerek SollenbergerSkXMLListSource::SkXMLListSource(const char doc[], size_t len)
5460b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
5470b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fFieldCount = fRecordCount = 0;
5480b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	fFields = fRecords = NULL;
5490b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5500b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkDOM	dom;
5510b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5520b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	const SkDOM::Node* node = dom.build(doc, len);
5530b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	SkASSERT(node);
5540b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	const SkDOM::Node*	child;
5550b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5560b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	child = dom.getFirstChild(node, "fields");
5570b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (child)
5580b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
5590b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fFieldCount = dom.countChildren(child, "field");
5600b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fFields = new SkString[fFieldCount];
5610b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5620b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int n = 0;
5630b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		child = dom.getFirstChild(child, "field");
5640b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		while (child)
5650b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
5660b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			fFields[n].set(dom.findAttr(child, "name"));
5670b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			child = dom.getNextSibling(child, "field");
5680b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			n += 1;
5690b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
5700b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT(n == fFieldCount);
5710b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
5720b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5730b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	child = dom.getFirstChild(node, "records");
5740b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	if (child)
5750b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	{
5760b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fRecordCount = dom.countChildren(child, "record");
5770b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		fRecords = new SkString[fRecordCount * fFieldCount];
5780b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5790b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		int n = 0;
5800b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		child = dom.getFirstChild(child, "record");
5810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		while (child)
5820b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		{
5830b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			for (int i = 0; i < fFieldCount; i++)
5840b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				fRecords[n * fFieldCount + i].set(dom.findAttr(child, fFields[i].c_str()));
5850b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			child = dom.getNextSibling(child, "record");
5860b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			n += 1;
5870b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		}
5880b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		SkASSERT(n == fRecordCount);
5890b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	}
5900b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
5910b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5920b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger/////////////////////////////////////////////////////////////////////////////////////////////
5930b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
5940b15698a8c76bb8abc1b555c1d91892669b4118fDerek SollenbergerSkListSource* SkListSource::Factory(const char name[])
5950b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger{
5960b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	static const char gDoc[] =
5970b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		"<db name='contacts.db'>"
5980b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			"<fields>"
5990b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<field name='name'/>"
6000b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<field name='work-num'/>"
6010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<field name='home-num'/>"
6020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<field name='type'/>"
6030b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			"</fields>"
6040b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			"<records>"
6050b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Andy McFadden' work-num='919 357-1234' home-num='919 123-4567' type='0'/>"
6060b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Brian Swetland' work-num='919 123-1234' home-num='929 123-4567' type='1' />"
6070b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Chris Desalvo' work-num='919 345-1234' home-num='949 123-4567' type='1' />"
6080b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Chris White' work-num='919 234-1234' home-num='939 123-4567' type='2' />"
6090b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Dan Bornstein' work-num='919 357-1234' home-num='919 123-4567' type='0' />"
6100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Don Cung' work-num='919 123-1234' home-num='929 123-4567' type='2' />"
6110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Eric Fischer' work-num='919 345-1234' home-num='949 123-4567' type='2' />"
6120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Ficus Kirkpatric' work-num='919 234-1234' home-num='939 123-4567' type='1' />"
6130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Jack Veenstra' work-num='919 234-1234' home-num='939 123-4567' type='2' />"
6140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Jeff Yaksick' work-num='919 234-1234' home-num='939 123-4567' type='0' />"
6150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Joe Onorato' work-num='919 234-1234' home-num='939 123-4567' type='0' />"
6160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Mathias Agopian' work-num='919 234-1234' home-num='939 123-4567' type='1' />"
6170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Mike Fleming' work-num='919 234-1234' home-num='939 123-4567' type='2' />"
6180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Nick Sears' work-num='919 234-1234' home-num='939 123-4567' type='1' />"
6190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Rich Miner' work-num='919 234-1234' home-num='939 123-4567' type='1' />"
6200b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Tracey Cole' work-num='919 234-1234' home-num='939 123-4567' type='0' />"
6210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger				"<record name='Wei Huang' work-num='919 234-1234' home-num='939 123-4567' type='0' />"
6220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger			"</records>"
6230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger		"</db>";
6240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
6250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger//SkDebugf("doc size %d\n", sizeof(gDoc)-1);
6260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger	return new SkXMLListSource(gDoc, sizeof(gDoc) - 1);
6270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
6280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
6290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
6300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
631