InPlaceList.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // InPlaceList.cpp : implementation file
  2. //
  3. // Written by Chris Maunder (chrismaunder@codeguru.com)
  4. // Copyright (c) 1998.
  5. //
  6. // The code contained in this file is based on the original
  7. // CInPlaceList from http://www.codeguru.com/listview
  8. //
  9. // This code may be used in compiled form in any way you desire. This
  10. // file may be redistributed unmodified by any means PROVIDING it is
  11. // not sold for profit without the authors written consent, and
  12. // providing that this notice and the authors name is included. If
  13. // the source code in this file is used in any commercial application
  14. // then acknowledgement must be made to the author of this file
  15. // (in whatever form you wish).
  16. //
  17. // This file is provided "as is" with no expressed or implied warranty.
  18. // The author accepts no liability for any damage/loss of business that
  19. // this product may cause.
  20. //
  21. // Expect bugs!
  22. //
  23. // Please use and enjoy. Please let me know of any bugs/mods/improvements
  24. // that you have found/implemented and I will fix/incorporate them into this
  25. // file.
  26. //
  27. // 6 Aug 1998 - Added CComboEdit to subclass the edit control - code provided by
  28. // Roelf Werkman <rdw@inn.nl>. Added nID to the constructor param list.
  29. // 29 Nov 1998 - bug fix in onkeydown (Markus Irtenkauf)
  30. //
  31. /////////////////////////////////////////////////////////////////////////////
  32. #include "stdafx.h"
  33. #include "InPlaceList.h"
  34. #include "GridCtrl.h"
  35. #ifdef _DEBUG
  36. #define new DEBUG_NEW
  37. #undef THIS_FILE
  38. static char THIS_FILE[] = __FILE__;
  39. #endif
  40. /////////////////////////////////////////////////////////////////////////////
  41. // CComboEdit
  42. CComboEdit::CComboEdit()
  43. {
  44. }
  45. CComboEdit::~CComboEdit()
  46. {
  47. }
  48. // Stoopid win95 accelerator key problem workaround - Matt Weagle.
  49. BOOL CComboEdit::PreTranslateMessage(MSG* pMsg)
  50. {
  51. // Make sure that the keystrokes continue to the appropriate handlers
  52. if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP)
  53. {
  54. ::TranslateMessage(pMsg);
  55. ::DispatchMessage(pMsg);
  56. return TRUE;
  57. }
  58. // Catch the Alt key so we don't choke if focus is going to an owner drawn button
  59. if (pMsg->message == WM_SYSCHAR)
  60. return TRUE;
  61. return CEdit::PreTranslateMessage(pMsg);
  62. }
  63. BEGIN_MESSAGE_MAP(CComboEdit, CEdit)
  64. //{{AFX_MSG_MAP(CComboEdit)
  65. ON_WM_KILLFOCUS()
  66. ON_WM_KEYDOWN()
  67. ON_WM_KEYUP()
  68. //}}AFX_MSG_MAP
  69. END_MESSAGE_MAP()
  70. /////////////////////////////////////////////////////////////////////////////
  71. // CComboEdit message handlers
  72. void CComboEdit::OnKillFocus(CWnd* pNewWnd)
  73. {
  74. CEdit::OnKillFocus(pNewWnd);
  75. CInPlaceList* pOwner = (CInPlaceList*) GetOwner(); // This MUST be a CInPlaceList
  76. if (pOwner)
  77. pOwner->EndEdit();
  78. }
  79. void CComboEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  80. {
  81. if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
  82. nChar == VK_DOWN || nChar == VK_UP ||
  83. nChar == VK_RIGHT || nChar == VK_LEFT) &&
  84. (GetKeyState(VK_CONTROL) < 0 && GetDlgCtrlID() == IDC_COMBOEDIT))
  85. {
  86. CWnd* pOwner = GetOwner();
  87. if (pOwner)
  88. pOwner->SendMessage(WM_KEYDOWN, nChar, nRepCnt+ (((DWORD)nFlags)<<16));
  89. return;
  90. }
  91. CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
  92. }
  93. void CComboEdit::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  94. {
  95. if (nChar == VK_ESCAPE)
  96. {
  97. CWnd* pOwner = GetOwner();
  98. if (pOwner)
  99. pOwner->SendMessage(WM_KEYUP, nChar, nRepCnt + (((DWORD)nFlags)<<16));
  100. return;
  101. }
  102. if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
  103. {
  104. CWnd* pOwner = GetOwner();
  105. if (pOwner)
  106. pOwner->SendMessage(WM_KEYUP, nChar, nRepCnt + (((DWORD)nFlags)<<16));
  107. return;
  108. }
  109. CEdit::OnKeyUp(nChar, nRepCnt, nFlags);
  110. }
  111. /////////////////////////////////////////////////////////////////////////////
  112. // CInPlaceList
  113. CInPlaceList::CInPlaceList(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
  114. int nRow, int nColumn,
  115. CStringArray& Items, CString sInitText,
  116. UINT nFirstChar)
  117. {
  118. m_nNumLines = 4;
  119. m_sInitText = sInitText;
  120. m_nRow = nRow;
  121. m_nCol = nColumn;
  122. m_nLastChar = 0;
  123. m_bExitOnArrows = FALSE; //(nFirstChar != VK_LBUTTON); // If mouse click brought us here,
  124. // Create the combobox
  125. DWORD dwComboStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|
  126. CBS_AUTOHSCROLL | dwStyle;
  127. int nHeight = rect.Height();
  128. rect.bottom = rect.bottom + m_nNumLines*nHeight + ::GetSystemMetrics(SM_CYHSCROLL);
  129. if (!Create(dwComboStyle, rect, pParent, nID)) return;
  130. // Add the strings
  131. for (int i = 0; i < Items.GetSize(); i++)
  132. AddString(Items[i]);
  133. // Get the maximum width of the text strings
  134. int nMaxLength = 0;
  135. CClientDC dc(GetParent());
  136. CFont* pOldFont = dc.SelectObject(pParent->GetFont());
  137. for (i = 0; i < Items.GetSize(); i++)
  138. nMaxLength = max(nMaxLength, dc.GetTextExtent(Items[i]).cx);
  139. nMaxLength += (::GetSystemMetrics(SM_CXVSCROLL) + dc.GetTextExtent(_T(" ")).cx*2);
  140. dc.SelectObject(pOldFont);
  141. if (nMaxLength > rect.Width())
  142. rect.right = rect.left + nMaxLength;
  143. // Resize the edit window and the drop down window
  144. MoveWindow(rect);
  145. SetFont(pParent->GetFont());
  146. SetItemHeight(-1, nHeight);
  147. SetDroppedWidth(nMaxLength);
  148. SetHorizontalExtent(0); // no horz scrolling
  149. // Set the initial text to m_sInitText
  150. if (SelectString(-1, m_sInitText) == CB_ERR)
  151. SetWindowText(m_sInitText); // No text selected, so restore what was there before
  152. // Subclass the combobox edit control if style includes CBS_DROPDOWN
  153. if ((dwStyle & CBS_DROPDOWNLIST) != CBS_DROPDOWNLIST)
  154. {
  155. m_edit.SubclassDlgItem(IDC_COMBOEDIT, this);
  156. SetFocus();
  157. switch (nFirstChar)
  158. {
  159. case VK_LBUTTON:
  160. case VK_RETURN: m_edit.SetSel((int)_tcslen(m_sInitText), -1); return;
  161. case VK_BACK: m_edit.SetSel((int)_tcslen(m_sInitText), -1); break;
  162. case VK_DOWN:
  163. case VK_UP:
  164. case VK_RIGHT:
  165. case VK_LEFT:
  166. case VK_NEXT:
  167. case VK_PRIOR:
  168. case VK_HOME:
  169. case VK_END: m_edit.SetSel(0,-1); return;
  170. default: m_edit.SetSel(0,-1);
  171. }
  172. SendMessage(WM_CHAR, nFirstChar);
  173. }
  174. else
  175. SetFocus();
  176. }
  177. CInPlaceList::~CInPlaceList()
  178. {
  179. }
  180. void CInPlaceList::EndEdit()
  181. {
  182. CString str;
  183. GetWindowText(str);
  184. // Send Notification to parent
  185. GV_DISPINFO dispinfo;
  186. dispinfo.hdr.hwndFrom = GetSafeHwnd();
  187. dispinfo.hdr.idFrom = GetDlgCtrlID();
  188. dispinfo.hdr.code = GVN_ENDLABELEDIT;
  189. dispinfo.item.mask = LVIF_TEXT|LVIF_PARAM;
  190. dispinfo.item.row = m_nRow;
  191. dispinfo.item.col = m_nCol;
  192. dispinfo.item.szText = str;
  193. dispinfo.item.lParam = (LPARAM) m_nLastChar;
  194. CWnd* pOwner = GetOwner();
  195. if (IsWindow(pOwner->GetSafeHwnd()))
  196. pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo );
  197. // Close this window (PostNcDestroy will delete this)
  198. PostMessage(WM_CLOSE, 0, 0);
  199. }
  200. void CInPlaceList::PostNcDestroy()
  201. {
  202. CComboBox::PostNcDestroy();
  203. delete this;
  204. }
  205. BEGIN_MESSAGE_MAP(CInPlaceList, CComboBox)
  206. //{{AFX_MSG_MAP(CInPlaceList)
  207. ON_WM_KILLFOCUS()
  208. ON_WM_KEYDOWN()
  209. ON_WM_KEYUP()
  210. //}}AFX_MSG_MAP
  211. END_MESSAGE_MAP()
  212. /////////////////////////////////////////////////////////////////////////////
  213. // CInPlaceList message handlers
  214. void CInPlaceList::OnKillFocus(CWnd* pNewWnd)
  215. {
  216. CComboBox::OnKillFocus(pNewWnd);
  217. if (GetSafeHwnd() == pNewWnd->GetSafeHwnd())
  218. return;
  219. // Only end editing on change of focus if we're using the CBS_DROPDOWNLIST style
  220. if ((GetStyle() & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
  221. EndEdit();
  222. }
  223. // If an arrow key (or associated) is pressed, then exit if
  224. // a) The Ctrl key was down, or
  225. // b) m_bExitOnArrows == TRUE
  226. void CInPlaceList::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  227. {
  228. if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
  229. nChar == VK_DOWN || nChar == VK_UP ||
  230. nChar == VK_RIGHT || nChar == VK_LEFT) &&
  231. (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0))
  232. {
  233. m_nLastChar = nChar;
  234. GetParent()->SetFocus();
  235. return;
  236. }
  237. CComboBox::OnKeyDown(nChar, nRepCnt, nFlags);
  238. }
  239. // Need to keep a lookout for Tabs, Esc and Returns.
  240. void CInPlaceList::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  241. {
  242. if (nChar == VK_ESCAPE)
  243. SetWindowText(m_sInitText); // restore previous text
  244. if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
  245. {
  246. m_nLastChar = nChar;
  247. GetParent()->SetFocus(); // This will destroy this window
  248. return;
  249. }
  250. CComboBox::OnKeyUp(nChar, nRepCnt, nFlags);
  251. }