123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882 |
- #include "pch.h"
- /////////////////////////////////////////////////////////////////////////////
- //
- // Default ItemPainter
- //
- /////////////////////////////////////////////////////////////////////////////
- class DefaultItemPainter : public ItemPainter {
- public:
- int GetXSize()
- {
- return 1;
- }
- int GetYSize()
- {
- return 1;
- }
- void Paint(ItemID pitem, Surface* psurface, bool bSelected, bool bFocus)
- {
- }
- };
- /////////////////////////////////////////////////////////////////////////////
- //
- // List Pane
- //
- /////////////////////////////////////////////////////////////////////////////
- template<class Interface>
- class ListPaneImpl :
- public Interface, // should contain ListPane,
- public IEventSink,
- public IIntegerEventSink
- {
- private:
- TRef<List> m_plist;
- TRef<ItemPainter> m_ppainter;
- TRef<ScrollPane> m_pscroll;
- ItemID m_pitemSelection;
- ItemID m_pitemSelectionPrevious;
- TRef<IEventSink> m_peventSink;
- TRef<IIntegerEventSink> m_pintegerEventSink;
- TRef<IItemEvent::SourceImpl> m_peventSelection;
- TRef<EventSourceImpl> m_peventSingleClick;
- TRef<EventSourceImpl> m_peventDoubleClick;
- int m_indexSelection;
- int m_posScroll;
- WinPoint m_sizeMin;
- bool m_bHorizontal;
- TVector<ItemID> m_vectItemsOld;
- bool m_bNeedScrollUpdate;
- bool m_bNeedSelectionOnScreen;
- int m_iOldSelection;
- public:
- ListPaneImpl(
- const WinPoint& sizeMin,
- List* plist,
- ItemPainter* ppainter,
- ScrollPane* pscroll,
- bool bHorizontal
- ) :
- m_sizeMin(sizeMin),
- m_ppainter(ppainter),
- m_pscroll(pscroll),
- m_indexSelection(0),
- m_posScroll(0),
- m_pitemSelection(NULL),
- m_pitemSelectionPrevious(NULL),
- m_bHorizontal(bHorizontal),
- m_iOldSelection(-1),
- m_bNeedScrollUpdate(false),
- m_bNeedSelectionOnScreen(false)
- {
- m_peventSelection = new IItemEvent::SourceImpl();
- m_peventSingleClick = new EventSourceImpl();
- m_peventDoubleClick = new EventSourceImpl();
- if (m_ppainter == NULL) {
- m_ppainter = new DefaultItemPainter();
- }
- if (m_pscroll) {
- m_pscroll->GetEventSource()->AddSink(
- m_pintegerEventSink = IIntegerEventSink::CreateDelegate(this)
- );
- }
- if (plist == NULL) {
- SetList(new EmptyList());
- } else {
- SetList(plist);
- }
- UpdateScrollBar();
- }
- ~ListPaneImpl()
- {
- m_plist->GetChangedEvent()->RemoveSink(m_peventSink);
- if (m_pscroll) {
- m_pscroll->GetEventSource()->RemoveSink(m_pintegerEventSink);
- }
- }
- const int GetSignificantSize() // returns size of the significant dimension
- {
- if (m_bHorizontal)
- {
- return GetSize().X();
- }
- else
- {
- return GetSize().Y();
- }
- }
- const int GetSignificantSize(ItemPainter & itempainter) // returns size of the significant dimension
- {
- if (m_bHorizontal)
- {
- return itempainter.GetXSize();
- }
- else
- {
- return itempainter.GetYSize();
- }
- }
- int GetScrollPos()
- {
- return m_posScroll;
- }
- void SetScrollPos(int pos)
- {
- m_posScroll =
- max(min(pos, m_plist->GetCount() * GetSignificantSize(*m_ppainter) - GetSignificantSize()), 0);
- if (m_pscroll) {
- m_pscroll->SetPos(m_posScroll);
- }
- }
- void UpdateScrollBar()
- {
- if (m_pscroll) {
- m_pscroll->SetLineSize(GetSignificantSize(*m_ppainter));//1);
- m_pscroll->SetSizes(
- m_plist->GetCount() * GetSignificantSize(*m_ppainter),
- GetSignificantSize()/* / GetSignificantSize(*m_ppainter)*/
- );
- }
- }
- ScrollPane * GetScrollPane()
- {
- return m_pscroll;
- }
- void UpdateScrollPos()
- {
- m_bNeedScrollUpdate = true;
- }
- void NextItem()
- {
- if (m_indexSelection < m_plist->GetCount() - 1) {
- m_indexSelection++;
- m_pitemSelection = m_plist->GetNext(m_pitemSelection);
- NeedPaint();
- SelectionChanged();
- m_bNeedScrollUpdate = true;
- m_bNeedSelectionOnScreen = true;
- }
- }
- void PreviousItem()
- {
- if (m_indexSelection != 0) {
- m_indexSelection--;
- m_pitemSelection = m_plist->GetItem(m_indexSelection);
- NeedPaint();
- SelectionChanged();
- m_bNeedScrollUpdate = true;
- m_bNeedSelectionOnScreen = true;
- }
- }
- void PageUp()
- {
- int delta = GetSignificantSize() / GetSignificantSize(*m_ppainter);
- while (delta > 0) {
- PreviousItem();
- delta--;
- }
- }
- void PageDown()
- {
- int delta = GetSignificantSize() / GetSignificantSize(*m_ppainter);
- while (delta > 0) {
- NextItem();
- delta--;
- }
- }
- void SelectionChanged()
- {
- if (m_pitemSelectionPrevious != m_pitemSelection) {
- m_peventSelection->Trigger(m_pitemSelection);
- m_pitemSelectionPrevious = m_pitemSelection;
- }
- }
- void ListChanged()
- {
- int index;
-
- if (m_pitemSelection != NULL)
- index = m_plist->GetIndex(m_pitemSelection);
- else
- index = -1;
- if (index == -1)
- {
- m_pitemSelection = NULL;
- m_iOldSelection = -1;
- }
- m_indexSelection = index;
- UpdateScrollBar();
- UpdateScrollPos();
- NeedLayout();
- NeedPaint();
- SelectionChanged();
- }
- void ScrollBarChanged()
- {
- m_posScroll = m_pscroll->GetPos()/* * GetSignificantSize(*m_ppainter)*/;
- NeedPaint();
- }
- //
- // ListPane Methods
- //
- void SetList(List* plist)
- {
- if (plist != m_plist) {
- if (m_plist != NULL) {
- m_plist->GetChangedEvent()->RemoveSink(m_peventSink);
- }
- if (plist == NULL) {
- m_plist = new EmptyList();
- } else {
- m_plist = plist;
- }
- m_plist->GetChangedEvent()->AddSink(
- m_peventSink = IEventSink::CreateDelegate(this)
- );
- ListChanged();
- }
- }
- void SetItemPainter(ItemPainter* ppainter)
- {
- if (ppainter == NULL) {
- m_ppainter = new DefaultItemPainter();
- } else {
- m_ppainter = ppainter;
- }
- UpdateScrollBar();
- UpdateScrollPos();
- NeedLayout();
- NeedPaint();
- }
- void SetSelection(ItemID pitem)
- {
- if (pitem != m_pitemSelection)
- {
- if (pitem)
- {
- m_indexSelection = m_plist->GetIndex(pitem);
-
- if (m_indexSelection == -1)
- {
- assert(false);
- pitem = NULL;
- }
- }
- else
- m_indexSelection = -1;
- m_pitemSelection = pitem;
- if (m_bNeedScrollUpdate)
- m_iOldSelection = -1;
- else
- m_iOldSelection = m_indexSelection;
- SelectionChanged();
- NeedPaint();
- }
- }
- void SetSelection(int nIndex)
- {
- SetSelection(m_plist->GetItem(nIndex));
- }
- virtual ItemID GetSelection()
- {
- return m_pitemSelection;
- }
- IItemEvent::Source* GetSelectionEventSource()
- {
- return m_peventSelection;
- }
- IEventSource* GetDoubleClickEventSource()
- {
- return m_peventDoubleClick;
- }
- IEventSource* GetSingleClickEventSource()
- {
- return m_peventSingleClick;
- }
- void ScrollToItem(ItemID pitem)
- {
- int index = 0;
-
- if (pitem != NULL)
- index = m_plist->GetIndex(pitem);
-
- // try to center the selected item
- SetScrollPos(((2 * index + 1) * GetSignificantSize(*m_ppainter) - GetSignificantSize())/2);
- }
- void ForceRefresh()
- {
- NeedPaint();
- }
- //
- // IEventSink Methods
- //
- bool OnEvent(IEventSource* pevent)
- {
- ListChanged();
- return true;
- }
- bool OnEvent(IIntegerEventSource* pevent, int value)
- {
- ScrollBarChanged();
- return true;
- }
- //
- // Pane Methods
- //
- void UpdateLayout()
- {
- InternalSetSize(
- WinPoint(
- max(m_ppainter->GetXSize(), m_sizeMin.X()),
- max( GetExpand().Y(), m_sizeMin.Y())
- )
- );
- UpdateScrollBar();
- }
- void VerifyScrollPos()
- {
- if (m_bNeedScrollUpdate) {
- m_bNeedScrollUpdate = false;
- if (m_bNeedSelectionOnScreen) {
- m_bNeedSelectionOnScreen = false;
- //
- // Figure out where the selection is
- //
- int nItemSize = GetSignificantSize(*m_ppainter);
- int ySelection = m_indexSelection * nItemSize - GetScrollPos();
- //
- // Make sure the selection is in the window
- //
-
- if (ySelection + GetSignificantSize(*m_ppainter) >= GetSignificantSize()) {
- ySelection = GetSignificantSize() - GetSignificantSize(*m_ppainter);
- }
-
- if (ySelection < 0) {
- ySelection = 0;
- }
-
- //
- // Adjust the scroll bar so that the selection doesn't move
- //
-
- if (m_pscroll && m_plist->GetCount() * GetSignificantSize(*m_ppainter) > GetSignificantSize()) {
- SetScrollPos(m_indexSelection * GetSignificantSize(*m_ppainter) - ySelection);
- } else {
- SetScrollPos(0);
- }
- } else {
- //
- // find the top item in the old list
- //
- int nItemSize = GetSignificantSize(*m_ppainter);
- int iOldTop = GetScrollPos() / nItemSize;
- //
- // use the selected item as the basis if it was visible, otherwise use
- // the top item
- //
- int nLinesPerScreen = GetSignificantSize() / nItemSize;
- int iOldBasis;
- if (
- m_iOldSelection >= iOldTop
- && m_iOldSelection < iOldTop + nLinesPerScreen
- ) {
- //
- // visible
- //
- iOldBasis = m_iOldSelection;
- } else {
- iOldBasis = iOldTop;
- }
- //
- // get the scroll offset from the basis to the top, so we can try
- // to keep the basis perfectly stable.
- //
- int nTopFromBasis = GetScrollPos() - iOldBasis * nItemSize;
- //
- // find the new basis...
- //
- int iNewBasis = FindNearestNewIndex(iOldBasis);
- //
- // set the scroll position relative to the new basis
- //
- SetScrollPos(iNewBasis * nItemSize + nTopFromBasis);
- }
- //
- // update m_vectItemsOld to contain the new contents
- //
- int nNewCount = m_plist->GetCount();
- m_vectItemsOld.SetCount(nNewCount);
- for (int i = 0; i < nNewCount; i++) {
- m_vectItemsOld.Set(i, m_plist->GetItem(i));
- }
- m_iOldSelection = m_indexSelection;
- }
- }
- int FindNearestNewIndex(int nOldIndex)
- {
- if (nOldIndex == -1 || m_vectItemsOld.GetCount() == 0)
- return -1;
-
- ZAssert(nOldIndex >= 0 && nOldIndex < m_vectItemsOld.GetCount());
- int nNewIndex;
- // check to see if the old item exists in the new list
- nNewIndex = m_plist->GetIndex(m_vectItemsOld[nOldIndex]);
- // if we haven't found a new index yet, try searching the items around it
- int iDelta = 1;
- while (nNewIndex == -1
- && (nOldIndex - iDelta >= 0
- || nOldIndex + iDelta < m_vectItemsOld.GetCount()))
- {
- if (nOldIndex - iDelta >= 0)
- nNewIndex = m_plist->GetIndex(m_vectItemsOld[nOldIndex - iDelta]);
- if (nNewIndex != -1 && nOldIndex + iDelta < m_vectItemsOld.GetCount())
- nNewIndex = m_plist->GetIndex(m_vectItemsOld[nOldIndex - iDelta]);
- ++iDelta;
- }
- // if we still haven't found a new index, default to the first item
- if (nNewIndex == -1)
- {
- nNewIndex = 0;
- }
- return nNewIndex;
- }
- void Paint(Surface* psurface)
- {
- VerifyScrollPos();
- //
- // Find the item at the top of the list
- //
- int ysize = GetSignificantSize(*m_ppainter);
- int index = GetScrollPos() / ysize;
- int y = index * ysize - GetScrollPos();
- ItemID pitem = m_plist->GetItem(index);
- while (
- pitem != NULL
- && y < GetSignificantSize()
- ) {
- if (m_bHorizontal)
- psurface->Offset(WinPoint(y, 0));
- else
- psurface->Offset(WinPoint(0, y));
- m_ppainter->Paint(
- pitem,
- psurface,
- pitem == m_pitemSelection,
- false
- );
- if (m_bHorizontal)
- psurface->Offset(WinPoint(-y, 0));
- else
- psurface->Offset(WinPoint(0, -y));
- y += ysize;
- pitem = m_plist->GetNext(pitem);
- }
- }
- //
- // IMouseInput
- //
- MouseResult Button(
- IInputProvider* pprovider,
- const Point& point,
- int button,
- bool bCaptured,
- bool bInside,
- bool bDown
- ) {
- VerifyScrollPos();
- if (button == 0 && bDown) {
- int nSize = GetSignificantSize(*m_ppainter);
- int nSignificantMouseDim = (int)(m_bHorizontal ? point.X(): point.Y());
- SetSelection(m_plist->GetItem((nSignificantMouseDim + GetScrollPos()) / nSize));
- NeedPaint();
- SelectionChanged();
- if (pprovider->IsDoubleClick()) {
- m_peventDoubleClick->Trigger();
- }
- else {
- m_peventSingleClick->Trigger();
- }
- }
- return MouseResult();
- }
- //
- // IKeyboardInput
- //
- bool OnKey(IInputProvider* pprovider, const KeyState& ks, bool& fForceTranslate)
- {
- VerifyScrollPos();
- if (ks.bDown) {
- switch (ks.vk) {
- case VK_DOWN:
- NextItem();
- SelectionChanged();
- return true;
- case VK_UP:
- PreviousItem();
- SelectionChanged();
- return true;
-
- case VK_PRIOR: // page up
- PageUp();
- SelectionChanged();
- return true;
- case VK_NEXT: // page down
- PageDown();
- SelectionChanged();
- return true;
- }
- }
- return false;
- }
- };
- /////////////////////////////////////////////////////////////////////////////
- //
- // Constructor
- //
- /////////////////////////////////////////////////////////////////////////////
- TRef<ListPane> CreateListPane(
- const WinPoint& sizeMin,
- List* plist,
- ItemPainter* ppainter,
- ScrollPane* pscroll,
- bool bHorizontal
- ) {
- return new ListPaneImpl<ListPane>(sizeMin, plist, ppainter, pscroll, bHorizontal);
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // StringList
- //
- /////////////////////////////////////////////////////////////////////////////
- class StringListImpl :
- public StringList
- {
- private:
- //////////////////////////////////////////////////////////////////////////////
- //
- // Data members
- //
- //////////////////////////////////////////////////////////////////////////////
- TRef<IEngineFont> m_pfont;
- Color m_color;
- Color m_colorSelected;
- int m_xsize;
- TRef<EventSourceImpl> m_peventSource;
- TRef<StringListItem> m_pitem;
- int m_count;
- public:
- //////////////////////////////////////////////////////////////////////////////
- //
- // Constructor
- //
- //////////////////////////////////////////////////////////////////////////////
- StringListImpl(
- IEngineFont* pfont,
- const Color& color,
- const Color& colorSelected,
- int xsize
- ) :
- m_pfont(pfont),
- m_color(color),
- m_colorSelected(colorSelected),
- m_xsize(xsize),
- m_count(0)
- {
- m_peventSource = new EventSourceImpl();
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // StringList Methods
- //
- //////////////////////////////////////////////////////////////////////////////
- void AddItem(const ZString& str)
- {
- m_count++;
- m_pitem = new StringListItem(str, m_pitem);
- m_peventSource->Trigger();
- }
- void SetEmpty()
- {
- m_count = 0;
- m_pitem = NULL;
- m_peventSource->Trigger();
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // List Methods
- //
- //////////////////////////////////////////////////////////////////////////////
- int GetCount()
- {
- return m_count;
- }
- ItemID GetItem(int index)
- {
- ZAssert(index >= 0);
- if (index < m_count) {
- StringListItem* pitem = m_pitem;
- while (index > 0) {
- pitem = pitem->GetNext();
- index--;
- }
- return pitem;
- } else {
- return NULL;
- }
- }
- int GetIndex(ItemID pitemFind)
- {
- StringListItem* pitem = m_pitem;
- int index = 0;
- while (pitem != NULL) {
- if ((ItemID)pitem == pitemFind) {
- return index;
- }
- pitem = pitem->GetNext();
- index++;
- }
- return -1;
- }
- ItemID GetNext(ItemID pitem)
- {
- return ((StringListItem*)pitem)->GetNext();
- }
- IEventSource* GetChangedEvent()
- {
- return m_peventSource;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // ItemPainter Methods
- //
- //////////////////////////////////////////////////////////////////////////////
- int GetXSize()
- {
- return m_xsize;
- }
- int GetYSize()
- {
- return m_pfont->GetHeight();
- }
- void Paint(ItemID pitemArg, Surface* psurface, bool bSelected, bool bFocus)
- {
- StringListItem* pitem = (StringListItem*)pitemArg;
- if (bSelected) {
- psurface->FillRect(
- WinRect(0, 0, GetXSize(), GetYSize()),
- m_colorSelected
- );
- }
- psurface->DrawString(m_pfont, m_color, WinPoint(0, 0), pitem->GetString());
- }
- };
- TRef<StringList> CreateStringList(
- IEngineFont* pfont,
- const Color& color,
- const Color& colorSelected,
- int xsize
- ) {
- return
- new StringListImpl(
- pfont,
- color,
- colorSelected,
- xsize
- );
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // StringListPane
- //
- /////////////////////////////////////////////////////////////////////////////
- class StringListPaneImpl:
- public ListPaneImpl<StringListPane>
- {
- public:
- StringListPaneImpl(
- const WinPoint& sizeMin,
- List* plist,
- ItemPainter* ppainter,
- ScrollPane* pscroll,
- bool bHorizontal,
- IEngineFont* pfont,
- const Color& color,
- const Color& colorSelected
- ) :
- ListPaneImpl<StringListPane>(sizeMin, plist, ppainter, pscroll, bHorizontal)
- {
- m_pStringList = CreateStringList(pfont, color, colorSelected, sizeMin.X());
- SetList(m_pStringList);
- SetItemPainter(m_pStringList);
- }
- TRef<StringList> GetStringList()
- {
- return m_pStringList;
- }
- private:
- TRef<StringList> m_pStringList;
- };
- TRef<StringListPane> CreateStringListPane(
- const WinPoint& sizeMin,
- List* plist,
- ItemPainter* ppainter,
- ScrollPane* pscroll,
- bool bHorizontal,
- IEngineFont* pfont,
- const Color& color,
- const Color& colorSelected
- )
- {
- return new StringListPaneImpl(sizeMin, plist, ppainter, pscroll, bHorizontal, pfont, color, colorSelected);
- }
|