XComboList.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. // XComboList.cpp
  2. //
  3. // Author: Hans Dietrich
  4. // hdietrich2@hotmail.com
  5. //
  6. // This software is released into the public domain.
  7. // You are free to use it in any way you like.
  8. //
  9. // This software is provided "as is" with no expressed
  10. // or implied warranty. I accept no liability for any
  11. // damage or loss of business that this software may cause.
  12. //
  13. ///////////////////////////////////////////////////////////////////////////////
  14. #include "stdafx.h"
  15. #include "XComboList.h"
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21. UINT NEAR WM_XCOMBOLIST_VK_RETURN = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_VK_RETURN"));
  22. UINT NEAR WM_XCOMBOLIST_VK_ESCAPE = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_VK_ESCAPE"));
  23. UINT NEAR WM_XCOMBOLIST_KEYDOWN = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_KEYDOWN"));
  24. UINT NEAR WM_XCOMBOLIST_LBUTTONUP = ::RegisterWindowMessage(_T("WM_XCOMBOLIST_LBUTTONUP"));
  25. BEGIN_MESSAGE_MAP(CXComboList, CWnd)
  26. //{{AFX_MSG_MAP(CXComboList)
  27. ON_WM_LBUTTONDOWN()
  28. ON_WM_KILLFOCUS()
  29. ON_WM_CREATE()
  30. ON_WM_VSCROLL()
  31. ON_WM_DESTROY()
  32. ON_WM_TIMER()
  33. //}}AFX_MSG_MAP
  34. END_MESSAGE_MAP()
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // ctor
  37. CXComboList::CXComboList(CWnd *pParent) :
  38. m_pParent(pParent),
  39. m_nCount(0),
  40. m_bFirstTime(TRUE)
  41. {
  42. ASSERT(m_pParent);
  43. }
  44. CXComboList::~CXComboList()
  45. {
  46. }
  47. ///////////////////////////////////////////////////////////////////////////////
  48. // SetActive
  49. void CXComboList::SetActive(int nScrollBarWidth)
  50. {
  51. XLISTCTRL_TRACE(_T("in CXComboList::SetActive\n"));
  52. if (!::IsWindow(m_ListBox.m_hWnd))
  53. return;
  54. m_ListBox.SetFocus();
  55. if (m_bFirstTime)
  56. {
  57. m_bFirstTime = FALSE;
  58. CRect rect;
  59. GetWindowRect(&rect);
  60. // set listbox size according to item height
  61. int nItemHeight = m_ListBox.GetItemHeight(0);
  62. CRect lbrect;
  63. GetClientRect(&lbrect);
  64. lbrect.top += 1;
  65. lbrect.bottom = lbrect.top + (rect.Height() / nItemHeight) * nItemHeight;
  66. lbrect.left += 1;
  67. lbrect.right -= nScrollBarWidth;
  68. int nItemsInView = (lbrect.Height()) / nItemHeight;
  69. // set size of listbox wrapper (from size of listbox)
  70. rect.bottom = rect.top + lbrect.Height() + 4;
  71. MoveWindow(&rect);
  72. m_ListBox.MoveWindow(&lbrect);
  73. m_ListBox.BringWindowToTop();
  74. // set size and position for vertical scroll bar
  75. CRect sbrect;
  76. sbrect = lbrect;
  77. sbrect.left = lbrect.right;
  78. sbrect.right += nScrollBarWidth;
  79. m_wndSBVert.MoveWindow(&sbrect);
  80. SCROLLINFO si;
  81. si.cbSize = sizeof(si);
  82. si.fMask = SIF_ALL;
  83. m_wndSBVert.GetScrollInfo(&si);
  84. // set info for scrollbar
  85. si.nMin = 0;
  86. si.nMax = m_ListBox.GetCount();
  87. if (si.nMax < 0)
  88. si.nMax = 1;
  89. si.nPage = nItemsInView;
  90. int nCurSel = m_ListBox.GetCurSel();
  91. if (nCurSel == LB_ERR || nCurSel < 0)
  92. nCurSel = 0;
  93. si.nPos = nCurSel;
  94. // set top index, to force selected item to be in view
  95. m_ListBox.SetTopIndex(nCurSel > 0 ? nCurSel - 1 : 0);
  96. if (si.nPos < 0)
  97. si.nPos = 0;
  98. m_wndSBVert.SetScrollInfo(&si);
  99. m_wndSBVert.SetScrollPos(si.nPos, TRUE);
  100. //RedrawWindow();
  101. SetTimer(1, 80, NULL);
  102. }
  103. }
  104. ///////////////////////////////////////////////////////////////////////////////
  105. // GetScrollBarCtrl
  106. CScrollBar* CXComboList::GetScrollBarCtrl(int nBar)
  107. {
  108. UNUSED_ALWAYS(nBar);
  109. return &m_wndSBVert;
  110. }
  111. ///////////////////////////////////////////////////////////////////////////////
  112. // SendRegisteredMessage
  113. void CXComboList::SendRegisteredMessage(UINT nMsg, WPARAM wParam, LPARAM lParam)
  114. {
  115. CWnd *pWnd = m_pParent;
  116. if (pWnd)
  117. pWnd->SendMessage(nMsg, wParam, lParam);
  118. }
  119. ///////////////////////////////////////////////////////////////////////////////
  120. // OnLButtonDown
  121. void CXComboList::OnLButtonDown(UINT nFlags, CPoint point)
  122. {
  123. SendRegisteredMessage(WM_XCOMBOLIST_LBUTTONUP, 0, 0);
  124. CWnd::OnLButtonUp(nFlags, point); //????? why up
  125. }
  126. ///////////////////////////////////////////////////////////////////////////////
  127. // PreTranslateMessage
  128. BOOL CXComboList::PreTranslateMessage(MSG* pMsg)
  129. {
  130. switch (pMsg->message)
  131. {
  132. case WM_KEYDOWN:
  133. {
  134. ///////////////////////////////////////////////////////////////////
  135. // we need to trap all cursor keys & alpha keys to reposition the
  136. // scroll bar
  137. ///////////////////////////////////////////////////////////////////
  138. //XLISTCTRL_TRACE(" WM_KEYDOWN\n");
  139. SCROLLINFO si =
  140. {
  141. sizeof(SCROLLINFO),
  142. SIF_ALL | SIF_DISABLENOSCROLL,
  143. };
  144. m_wndSBVert.GetScrollInfo(&si);
  145. BOOL bSetScrollInfo = FALSE;
  146. int nIndex = 0;
  147. if (::IsWindow(m_ListBox.m_hWnd))
  148. nIndex = m_ListBox.GetCurSel();
  149. if (nIndex == LB_ERR || nIndex < 0)
  150. nIndex = 0;
  151. // use index from listbox, because scroll position cannot be relied
  152. // upon here
  153. switch (pMsg->wParam)
  154. {
  155. case VK_RETURN:
  156. SendRegisteredMessage(WM_XCOMBOLIST_VK_RETURN, 0, 0);
  157. break;
  158. case VK_ESCAPE:
  159. SendRegisteredMessage(WM_XCOMBOLIST_VK_ESCAPE, 0, 0);
  160. break;
  161. // handle scrolling messages
  162. case VK_DOWN:
  163. si.nPos = nIndex + 1;
  164. bSetScrollInfo = TRUE;
  165. break;
  166. case VK_END:
  167. si.nPos = si.nMax;
  168. bSetScrollInfo = TRUE;
  169. break;
  170. case VK_HOME:
  171. si.nPos = 0;
  172. bSetScrollInfo = TRUE;
  173. break;
  174. case VK_NEXT: // PAGE DOWN
  175. si.nPos = nIndex + (si.nPage-1);
  176. bSetScrollInfo = TRUE;
  177. break;
  178. case VK_PRIOR: // PAGE UP
  179. si.nPos = nIndex - (si.nPage - 1);
  180. bSetScrollInfo = TRUE;
  181. break;
  182. case VK_UP:
  183. si.nPos = nIndex - 1;
  184. bSetScrollInfo = TRUE;
  185. break;
  186. default:
  187. if (pMsg->wParam >= 0x41/*VK_A*/ && pMsg->wParam <= 0x5A/*VK_Z*/)
  188. {
  189. // this was an alpha key - try to find listbox index
  190. CString strAlpha;
  191. strAlpha = (_TCHAR) pMsg->wParam;
  192. int nIndex2 = 0;
  193. if (::IsWindow(m_ListBox.m_hWnd))
  194. nIndex2 = m_ListBox.FindString(nIndex, strAlpha);
  195. if (nIndex2 != LB_ERR)
  196. {
  197. si.nPos = nIndex2;
  198. bSetScrollInfo = TRUE;
  199. }
  200. }
  201. break;
  202. }
  203. if (bSetScrollInfo)
  204. {
  205. // let parent know the selection has changed
  206. SendRegisteredMessage(WM_XCOMBOLIST_KEYDOWN, 0, 0);
  207. // update scrollbar
  208. if (si.nPos < 0)
  209. si.nPos = 0;
  210. if (si.nPos > si.nMax)
  211. si.nPos = si.nMax;
  212. m_wndSBVert.SetScrollInfo(&si);
  213. }
  214. break;
  215. }
  216. case WM_LBUTTONUP:
  217. SendRegisteredMessage(WM_XCOMBOLIST_LBUTTONUP, 0, 0);
  218. break;
  219. }
  220. return CWnd::PreTranslateMessage(pMsg);
  221. }
  222. ///////////////////////////////////////////////////////////////////////////////
  223. // OnKillFocus
  224. void CXComboList::OnKillFocus(CWnd* pNewWnd)
  225. {
  226. XLISTCTRL_TRACE(_T("in CXComboList::OnKillFocus\n"));
  227. CWnd::OnKillFocus(pNewWnd);
  228. m_nCount++;
  229. if (m_nCount > 2)
  230. {
  231. SendRegisteredMessage(WM_XCOMBOLIST_VK_ESCAPE, 0, 0);
  232. }
  233. }
  234. ///////////////////////////////////////////////////////////////////////////////
  235. // OnCreate
  236. int CXComboList::OnCreate(LPCREATESTRUCT lpCreateStruct)
  237. {
  238. XLISTCTRL_TRACE(_T("in CXComboList::OnCreate\n"));
  239. if (CWnd::OnCreate(lpCreateStruct) == -1)
  240. return -1;
  241. CRect rect2(0,0,0,0);
  242. // create the listbox that we're wrapping
  243. VERIFY(m_ListBox.Create(WS_VISIBLE|WS_CHILD|LBS_NOINTEGRALHEIGHT/*|WS_BORDER*/,
  244. rect2, this, 0));
  245. // create the vertical scrollbar
  246. VERIFY(m_wndSBVert.Create(WS_VISIBLE|WS_CHILD|SBS_VERT,
  247. rect2, this, 0));
  248. // set font from parent
  249. CFont *font = GetParent()->GetFont();
  250. if (font)
  251. {
  252. SetFont(font, FALSE);
  253. m_wndSBVert.SetFont(font, FALSE);
  254. }
  255. return 0;
  256. }
  257. ///////////////////////////////////////////////////////////////////////////////
  258. // OnVScroll
  259. void CXComboList::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*)
  260. {
  261. if (!::IsWindow(m_ListBox.m_hWnd))
  262. return;
  263. // forward scroll message to listbox
  264. const MSG* pMsg = GetCurrentMessage();
  265. m_ListBox.SendMessage(WM_VSCROLL, pMsg->wParam, pMsg->lParam);
  266. SCROLLINFO si =
  267. {
  268. sizeof(SCROLLINFO),
  269. SIF_ALL | SIF_DISABLENOSCROLL,
  270. };
  271. m_wndSBVert.GetScrollInfo(&si);
  272. switch (nSBCode)
  273. {
  274. case SB_BOTTOM: // scroll to bottom
  275. si.nPos = si.nMax;
  276. break;
  277. case SB_TOP: // scroll to top
  278. si.nPos = 0;
  279. break;
  280. case SB_PAGEDOWN: // scroll one page down
  281. si.nPos += si.nPage;
  282. break;
  283. case SB_PAGEUP: // scroll one page up
  284. si.nPos -= si.nPage;
  285. break;
  286. case SB_LINEDOWN: // scroll one line up
  287. si.nPos += 1;
  288. break;
  289. case SB_LINEUP: // scroll one line up
  290. si.nPos -= 1;
  291. break;
  292. case SB_THUMBTRACK: // drag scroll box to specified position. The
  293. // current position is provided in nPos
  294. case SB_THUMBPOSITION: // scroll to the absolute position. The current
  295. // position is provided in nPos
  296. si.nPos = nPos;
  297. break;
  298. case SB_ENDSCROLL: // end scroll
  299. return;
  300. default:
  301. break;
  302. }
  303. if (si.nPos < 0)
  304. si.nPos = 0;
  305. if (si.nPos > si.nMax)
  306. si.nPos = si.nMax;
  307. m_wndSBVert.SetScrollInfo(&si);
  308. }
  309. ///////////////////////////////////////////////////////////////////////////////
  310. // OnDestroy
  311. void CXComboList::OnDestroy()
  312. {
  313. XLISTCTRL_TRACE(_T("in CXComboList::OnDestroy\n"));
  314. KillTimer(1);
  315. if (::IsWindow(m_ListBox.m_hWnd))
  316. m_ListBox.DestroyWindow();
  317. CWnd::OnDestroy();
  318. }
  319. ///////////////////////////////////////////////////////////////////////////////
  320. // OnTimer
  321. void CXComboList::OnTimer(UINT nIDEvent)
  322. {
  323. UNUSED_ALWAYS(nIDEvent);
  324. if (!::IsWindow(m_ListBox.m_hWnd))
  325. return;
  326. // get current mouse position
  327. POINT point;
  328. ::GetCursorPos(&point);
  329. ScreenToClient(&point);
  330. BOOL bOutside;
  331. int nIndex = m_ListBox.ItemFromPoint(point, bOutside);
  332. //XLISTCTRL_TRACE(" nIndex=%d bOutside=%d\n", nIndex, bOutside);
  333. if (!bOutside)
  334. {
  335. int nCurSel = m_ListBox.GetCurSel();
  336. if (nIndex != nCurSel)
  337. if (nIndex >= 0 && nIndex < m_ListBox.GetCount())
  338. m_ListBox.SetCurSel(nIndex);
  339. }
  340. }