123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- // XComboList.cpp
- //
- // Author: Hans Dietrich
- // hdietrich2@hotmail.com
- //
- // This software is released into the public domain.
- // You are free to use it in any way you like.
- //
- // This software is provided "as is" with no expressed
- // or implied warranty. I accept no liability for any
- // damage or loss of business that this software may cause.
- //
- ///////////////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "XComboList.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- UINT NEAR WM_XCOMBOLIST_VK_RETURN = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_VK_RETURN"));
- UINT NEAR WM_XCOMBOLIST_VK_ESCAPE = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_VK_ESCAPE"));
- UINT NEAR WM_XCOMBOLIST_KEYDOWN = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_KEYDOWN"));
- UINT NEAR WM_XCOMBOLIST_LBUTTONUP = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_LBUTTONUP"));
- BEGIN_MESSAGE_MAP(CXComboList, CWnd)
- //{{AFX_MSG_MAP(CXComboList)
- ON_WM_LBUTTONDOWN()
- ON_WM_KILLFOCUS()
- ON_WM_CREATE()
- ON_WM_VSCROLL()
- ON_WM_DESTROY()
- ON_WM_TIMER()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- ///////////////////////////////////////////////////////////////////////////////
- // ctor
- CXComboList::CXComboList(CWnd *pParent) :
- m_pParent(pParent),
- m_nCount(0),
- m_bFirstTime(TRUE)
- {
- ASSERT(m_pParent);
- }
- CXComboList::~CXComboList()
- {
- }
- ///////////////////////////////////////////////////////////////////////////////
- // SetActive
- void CXComboList::SetActive(int nScrollBarWidth)
- {
- XLISTCTRL_TRACE(_T("in CXComboList::SetActive\n"));
- if (!::IsWindow(m_ListBox.m_hWnd))
- return;
- m_ListBox.SetFocus();
- if (m_bFirstTime)
- {
- m_bFirstTime = FALSE;
- CRect rect;
- GetWindowRect(&rect);
- // set listbox size according to item height
- int nItemHeight = m_ListBox.GetItemHeight(0);
- CRect lbrect;
- GetClientRect(&lbrect);
- lbrect.top += 1;
- lbrect.bottom = lbrect.top + (rect.Height() / nItemHeight) * nItemHeight;
- lbrect.left += 1;
- lbrect.right -= nScrollBarWidth;
- int nItemsInView = (lbrect.Height()) / nItemHeight;
- // set size of listbox wrapper (from size of listbox)
- rect.bottom = rect.top + lbrect.Height() + 4;
- MoveWindow(&rect);
- m_ListBox.MoveWindow(&lbrect);
- m_ListBox.BringWindowToTop();
- // set size and position for vertical scroll bar
- CRect sbrect;
- sbrect = lbrect;
- sbrect.left = lbrect.right;
- sbrect.right += nScrollBarWidth;
- m_wndSBVert.MoveWindow(&sbrect);
- SCROLLINFO si;
- si.cbSize = sizeof(si);
- si.fMask = SIF_ALL;
- m_wndSBVert.GetScrollInfo(&si);
- // set info for scrollbar
- si.nMin = 0;
- si.nMax = m_ListBox.GetCount();
- if (si.nMax < 0)
- si.nMax = 1;
- si.nPage = nItemsInView;
- int nCurSel = m_ListBox.GetCurSel();
- if (nCurSel == LB_ERR || nCurSel < 0)
- nCurSel = 0;
- si.nPos = nCurSel;
- // set top index, to force selected item to be in view
- m_ListBox.SetTopIndex(nCurSel > 0 ? nCurSel - 1 : 0);
- if (si.nPos < 0)
- si.nPos = 0;
- m_wndSBVert.SetScrollInfo(&si);
- m_wndSBVert.SetScrollPos(si.nPos, TRUE);
- //RedrawWindow();
- SetTimer(1, 80, NULL);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // GetScrollBarCtrl
- CScrollBar* CXComboList::GetScrollBarCtrl(int nBar)
- {
- UNUSED_ALWAYS(nBar);
- return &m_wndSBVert;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // SendRegisteredMessage
- void CXComboList::SendRegisteredMessage(UINT nMsg, WPARAM wParam, LPARAM lParam)
- {
- CWnd *pWnd = m_pParent;
- if (pWnd)
- pWnd->SendMessage(nMsg, wParam, lParam);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // OnLButtonDown
- void CXComboList::OnLButtonDown(UINT nFlags, CPoint point)
- {
- SendRegisteredMessage(WM_XCOMBOLIST_LBUTTONUP, 0, 0);
- CWnd::OnLButtonUp(nFlags, point); //????? why up
- }
- ///////////////////////////////////////////////////////////////////////////////
- // PreTranslateMessage
- BOOL CXComboList::PreTranslateMessage(MSG* pMsg)
- {
- switch (pMsg->message)
- {
- case WM_KEYDOWN:
- {
- ///////////////////////////////////////////////////////////////////
- // we need to trap all cursor keys & alpha keys to reposition the
- // scroll bar
- ///////////////////////////////////////////////////////////////////
- //XLISTCTRL_TRACE(" WM_KEYDOWN\n");
- SCROLLINFO si =
- {
- sizeof(SCROLLINFO),
- SIF_ALL | SIF_DISABLENOSCROLL,
- };
- m_wndSBVert.GetScrollInfo(&si);
- BOOL bSetScrollInfo = FALSE;
- int nIndex = 0;
- if (::IsWindow(m_ListBox.m_hWnd))
- nIndex = m_ListBox.GetCurSel();
- if (nIndex == LB_ERR || nIndex < 0)
- nIndex = 0;
- // use index from listbox, because scroll position cannot be relied
- // upon here
- switch (pMsg->wParam)
- {
- case VK_RETURN:
- SendRegisteredMessage(WM_XCOMBOLIST_VK_RETURN, 0, 0);
- break;
- case VK_ESCAPE:
- SendRegisteredMessage(WM_XCOMBOLIST_VK_ESCAPE, 0, 0);
- break;
- // handle scrolling messages
- case VK_DOWN:
- si.nPos = nIndex + 1;
- bSetScrollInfo = TRUE;
- break;
- case VK_END:
- si.nPos = si.nMax;
- bSetScrollInfo = TRUE;
- break;
- case VK_HOME:
- si.nPos = 0;
- bSetScrollInfo = TRUE;
- break;
- case VK_NEXT: // PAGE DOWN
- si.nPos = nIndex + (si.nPage-1);
- bSetScrollInfo = TRUE;
- break;
- case VK_PRIOR: // PAGE UP
- si.nPos = nIndex - (si.nPage - 1);
- bSetScrollInfo = TRUE;
- break;
- case VK_UP:
- si.nPos = nIndex - 1;
- bSetScrollInfo = TRUE;
- break;
- default:
- if (pMsg->wParam >= 0x41/*VK_A*/ && pMsg->wParam <= 0x5A/*VK_Z*/)
- {
- // this was an alpha key - try to find listbox index
- CString strAlpha;
- strAlpha = (_TCHAR) pMsg->wParam;
- int nIndex2 = 0;
- if (::IsWindow(m_ListBox.m_hWnd))
- nIndex2 = m_ListBox.FindString(nIndex, strAlpha);
- if (nIndex2 != LB_ERR)
- {
- si.nPos = nIndex2;
- bSetScrollInfo = TRUE;
- }
- }
- break;
- }
- if (bSetScrollInfo)
- {
- // let parent know the selection has changed
- SendRegisteredMessage(WM_XCOMBOLIST_KEYDOWN, 0, 0);
- // update scrollbar
- if (si.nPos < 0)
- si.nPos = 0;
- if (si.nPos > si.nMax)
- si.nPos = si.nMax;
- m_wndSBVert.SetScrollInfo(&si);
- }
- break;
- }
- case WM_LBUTTONUP:
- SendRegisteredMessage(WM_XCOMBOLIST_LBUTTONUP, 0, 0);
- break;
- }
-
- return CWnd::PreTranslateMessage(pMsg);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // OnKillFocus
- void CXComboList::OnKillFocus(CWnd* pNewWnd)
- {
- XLISTCTRL_TRACE(_T("in CXComboList::OnKillFocus\n"));
- CWnd::OnKillFocus(pNewWnd);
- m_nCount++;
- if (m_nCount > 2)
- {
- SendRegisteredMessage(WM_XCOMBOLIST_VK_ESCAPE, 0, 0);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // OnCreate
- int CXComboList::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- XLISTCTRL_TRACE(_T("in CXComboList::OnCreate\n"));
- if (CWnd::OnCreate(lpCreateStruct) == -1)
- return -1;
- CRect rect2(0,0,0,0);
- // create the listbox that we're wrapping
- VERIFY(m_ListBox.Create(WS_VISIBLE|WS_CHILD|LBS_NOINTEGRALHEIGHT/*|WS_BORDER*/,
- rect2, this, 0));
- // create the vertical scrollbar
- VERIFY(m_wndSBVert.Create(WS_VISIBLE|WS_CHILD|SBS_VERT,
- rect2, this, 0));
- // set font from parent
- CFont *font = GetParent()->GetFont();
- if (font)
- {
- SetFont(font, FALSE);
- m_wndSBVert.SetFont(font, FALSE);
- }
- return 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // OnVScroll
- void CXComboList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*)
- {
- if (!::IsWindow(m_ListBox.m_hWnd))
- return;
- // forward scroll message to listbox
- const MSG* pMsg = GetCurrentMessage();
- m_ListBox.SendMessage(WM_VSCROLL, pMsg->wParam, pMsg->lParam);
- SCROLLINFO si =
- {
- sizeof(SCROLLINFO),
- SIF_ALL | SIF_DISABLENOSCROLL,
- };
- m_wndSBVert.GetScrollInfo(&si);
- switch (nSBCode)
- {
- case SB_BOTTOM: // scroll to bottom
- si.nPos = si.nMax;
- break;
- case SB_TOP: // scroll to top
- si.nPos = 0;
- break;
- case SB_PAGEDOWN: // scroll one page down
- si.nPos += si.nPage;
- break;
- case SB_PAGEUP: // scroll one page up
- si.nPos -= si.nPage;
- break;
- case SB_LINEDOWN: // scroll one line up
- si.nPos += 1;
- break;
- case SB_LINEUP: // scroll one line up
- si.nPos -= 1;
- break;
- case SB_THUMBTRACK: // drag scroll box to specified position. The
- // current position is provided in nPos
- case SB_THUMBPOSITION: // scroll to the absolute position. The current
- // position is provided in nPos
- si.nPos = nPos;
- break;
- case SB_ENDSCROLL: // end scroll
- return;
- default:
- break;
- }
- if (si.nPos < 0)
- si.nPos = 0;
- if (si.nPos > si.nMax)
- si.nPos = si.nMax;
- m_wndSBVert.SetScrollInfo(&si);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // OnDestroy
- void CXComboList::OnDestroy()
- {
- XLISTCTRL_TRACE(_T("in CXComboList::OnDestroy\n"));
- KillTimer(1);
- if (::IsWindow(m_ListBox.m_hWnd))
- m_ListBox.DestroyWindow();
- CWnd::OnDestroy();
- }
- ///////////////////////////////////////////////////////////////////////////////
- // OnTimer
- void CXComboList::OnTimer(UINT nIDEvent)
- {
- UNUSED_ALWAYS(nIDEvent);
- if (!::IsWindow(m_ListBox.m_hWnd))
- return;
- // get current mouse position
- POINT point;
- ::GetCursorPos(&point);
- ScreenToClient(&point);
- BOOL bOutside;
- int nIndex = m_ListBox.ItemFromPoint(point, bOutside);
- //XLISTCTRL_TRACE(" nIndex=%d bOutside=%d\n", nIndex, bOutside);
- if (!bOutside)
- {
- int nCurSel = m_ListBox.GetCurSel();
- if (nIndex != nCurSel)
- if (nIndex >= 0 && nIndex < m_ListBox.GetCount())
- m_ListBox.SetCurSel(nIndex);
- }
- }
|