Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3087 lines
77 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module LBHOST.CPP -- Text Host for CreateWindow() Rich Edit
  5. * Combo Box Control |
  6. * Implements CCmbBxWinHost message
  7. *
  8. * Original Author:
  9. * Jerry Kim
  10. *
  11. * History: <nl>
  12. * 01/30/97 - v-jerrki Created
  13. *
  14. * Set tabs every four (4) columns
  15. *
  16. * Copyright (c) 1997-1998 Microsoft Corporation. All rights reserved.
  17. */
  18. #include "_common.h"
  19. #include "_host.h"
  20. #include "imm.h"
  21. #include "_format.h"
  22. #include "_edit.h"
  23. #include "_cfpf.h"
  24. #include "_cbhost.h"
  25. ASSERTDATA
  26. // Helper function in edit.cpp
  27. LONG GetECDefaultHeightAndWidth(
  28. ITextServices *pts,
  29. HDC hdc,
  30. LONG lZoomNumerator,
  31. LONG lZoomDenominator,
  32. LONG yPixelsPerInch,
  33. LONG *pxAveWidth,
  34. LONG *pxOverhang,
  35. LONG *pxUnderhang);
  36. // For effeciency and to avoid Winnt thunking layer we will call
  37. // the listbox winproc directly
  38. LRESULT CALLBACK RichListBoxWndProc(
  39. HWND hwnd,
  40. UINT msg,
  41. WPARAM wparam,
  42. LPARAM lparam);
  43. //////////////////////////// System Window Procs ////////////////////////////
  44. /*
  45. * RichComboBoxWndProc (hwnd, msg, wparam, lparam)
  46. *
  47. * @mfunc
  48. * Handle window messages pertinent to the host and pass others on to
  49. * text services.
  50. * #rdesc
  51. * LRESULT = (code processed) ? 0 : 1
  52. */
  53. LRESULT CALLBACK RichComboBoxWndProc(
  54. HWND hwnd,
  55. UINT msg,
  56. WPARAM wparam,
  57. LPARAM lparam)
  58. {
  59. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "RichComboBoxWndProc");
  60. LRESULT lres = 1; //signify we didn't handle the message
  61. HRESULT hr = S_FALSE;
  62. CCmbBxWinHost *phost = (CCmbBxWinHost *) GetWindowLongPtr(hwnd, ibPed);
  63. #ifdef DEBUG
  64. Tracef(TRCSEVINFO, "hwnd %lx, msg %lx, wparam %lx, lparam %lx", hwnd, msg, wparam, lparam);
  65. #endif // DEBUG
  66. switch(msg)
  67. {
  68. case WM_NCCREATE:
  69. return CCmbBxWinHost::OnNCCreate(hwnd, (CREATESTRUCT *)lparam);
  70. case WM_CREATE:
  71. // We may be on a system with no WM_NCCREATE (e.g. WINCE)
  72. if (!phost)
  73. {
  74. (void) CCmbBxWinHost::OnNCCreate(hwnd, (CREATESTRUCT *) lparam);
  75. phost = (CCmbBxWinHost *) GetWindowLongPtr(hwnd, ibPed);
  76. }
  77. break;
  78. case WM_DESTROY:
  79. if(phost)
  80. CCmbBxWinHost::OnNCDestroy(phost);
  81. return 0;
  82. }
  83. if (!phost)
  84. return ::DefWindowProc(hwnd, msg, wparam, lparam);
  85. // in certain out-of-memory situations, clients may try to re-enter us
  86. // with calls. Just bail on the call if we don't have a text services
  87. // pointer.
  88. if(!phost->_pserv)
  89. return 0;
  90. // stabilize ourselves
  91. phost->AddRef();
  92. switch(msg)
  93. {
  94. case WM_MOUSEMOVE:
  95. if (!phost->OnMouseMove(wparam, lparam))
  96. break;
  97. goto serv;
  98. case WM_LBUTTONUP:
  99. if (!phost->OnLButtonUp(wparam, lparam))
  100. break;
  101. goto serv;
  102. case WM_MOUSEWHEEL:
  103. if (!phost->OnMouseWheel(wparam, lparam))
  104. break;
  105. goto defproc;
  106. case WM_LBUTTONDBLCLK:
  107. case WM_LBUTTONDOWN:
  108. if (!phost->OnLButtonDown(wparam, lparam))
  109. goto Exit;
  110. goto serv;
  111. case WM_COMMAND:
  112. if (!phost->OnCommand(wparam, lparam))
  113. break;
  114. goto serv;
  115. case WM_CREATE:
  116. lres = phost->OnCreate((CREATESTRUCT*)lparam);
  117. break;
  118. case WM_KEYDOWN:
  119. if (!phost->OnKeyDown((WORD) wparam, (DWORD) lparam))
  120. break;
  121. goto serv; // give it to text services
  122. case WM_SETTEXT:
  123. if (phost->_cbType != CCmbBxWinHost::kDropDown)
  124. {
  125. lres = CB_ERR;
  126. break;
  127. }
  128. goto serv;
  129. case WM_GETTEXT:
  130. GETTEXTEX gt;
  131. if (W32->OnWin9x() || phost->_fANSIwindow)
  132. W32->AnsiFilter( msg, wparam, lparam, (void *) &gt );
  133. goto serv;
  134. case WM_GETTEXTLENGTH:
  135. GETTEXTLENGTHEX gtl;
  136. if (W32->OnWin9x() || phost->_fANSIwindow)
  137. W32->AnsiFilter( msg, wparam, lparam, (void *) &gtl );
  138. goto serv;
  139. case WM_CHAR:
  140. if (W32->OnWin9x() || phost->_fANSIwindow)
  141. {
  142. CW32System::WM_CHAR_INFO wmci;
  143. wmci._fAccumulate = phost->_fAccumulateDBC != 0;
  144. W32->AnsiFilter( msg, wparam, lparam, (void *) &wmci );
  145. if (wmci._fLeadByte)
  146. {
  147. phost->_fAccumulateDBC = TRUE;
  148. phost->_chLeadByte = wparam << 8;
  149. goto Exit; // Wait for trail byte
  150. }
  151. else if (wmci._fTrailByte)
  152. {
  153. // UNDONE:
  154. // Need to see what we should do in WM_IME_CHAR
  155. wparam = phost->_chLeadByte | wparam;
  156. phost->_fAccumulateDBC = FALSE;
  157. phost->_chLeadByte = 0;
  158. msg = WM_IME_CHAR;
  159. goto serv;
  160. }
  161. else if (wmci._fIMEChar)
  162. {
  163. msg = WM_IME_CHAR;
  164. goto serv;
  165. }
  166. else if (wmci._fIMEChar)
  167. {
  168. msg = WM_IME_CHAR;
  169. goto serv;
  170. }
  171. }
  172. if(!phost->OnChar((WORD) wparam, (DWORD) lparam))
  173. // processed code: break out
  174. break;
  175. goto serv; // else give it to text services
  176. case WM_DRAWITEM:
  177. lres = phost->CbMessageItemHandler(NULL, ITEM_MSG_DRAWLIST, wparam, lparam);
  178. if (lres)
  179. break;
  180. goto defproc;
  181. case WM_DELETEITEM:
  182. lres = phost->CbMessageItemHandler(NULL, ITEM_MSG_DELETE, wparam, lparam);
  183. if (lres)
  184. break;
  185. goto defproc;
  186. case WM_ENABLE:
  187. if (phost->OnEnable(wparam, lparam))
  188. {
  189. if(!wparam ^ phost->_fDisabled)
  190. {
  191. // Stated of window changed so invalidate it so it will
  192. // get redrawn.
  193. InvalidateRect(phost->_hwnd, NULL, TRUE);
  194. phost->SetScrollBarsForWmEnable(wparam);
  195. // Need to enable the listbox window
  196. ::EnableWindow(phost->_hwndList, wparam);
  197. }
  198. phost->_fDisabled = !wparam; // Set disabled flag
  199. lres = 0; // Return value for message
  200. }
  201. // Fall thru to WM_SYSCOLORCHANGE?
  202. case WM_SYSCOLORCHANGE:
  203. //forward message to listbox first then pass to textservice
  204. SendMessage(phost->_hwndList, msg, wparam, lparam);
  205. phost->OnSysColorChange();
  206. goto serv; // Notify text services that
  207. // system colors have changed
  208. case WM_GETDLGCODE:
  209. //forward message to listbox first then pass to textservice
  210. SendMessage(phost->_hwndList, msg, wparam, lparam);
  211. lres = phost->OnGetDlgCode(wparam, lparam);
  212. break;
  213. case WM_STYLECHANGING:
  214. // Just pass this one to the default window proc
  215. lres = ::DefWindowProc(hwnd, msg, wparam, lparam);
  216. break;
  217. case WM_SIZE:
  218. lres = phost->OnSize(wparam, lparam);
  219. break;
  220. case WM_SETCURSOR:
  221. // Only set cursor when over us rather than a child; this
  222. // helps prevent us from fighting it out with an inplace child
  223. if((HWND)wparam == hwnd)
  224. {
  225. if(!(lres = ::DefWindowProc(hwnd, msg, wparam, lparam)))
  226. lres = phost->OnSetCursor(wparam, lparam);
  227. }
  228. break;
  229. case WM_SHOWWINDOW:
  230. hr = phost->OnTxVisibleChange((BOOL)wparam);
  231. break;
  232. case WM_NCPAINT:
  233. lres = ::DefWindowProc(hwnd, msg, wparam, lparam);
  234. if(phost->TxGetEffects() == TXTEFFECT_SUNKEN && dwMajorVersion < VERS4)
  235. {
  236. HDC hdc = GetDC(hwnd);
  237. if(hdc)
  238. {
  239. phost->DrawSunkenBorder(hwnd, hdc);
  240. ReleaseDC(hwnd, hdc);
  241. }
  242. }
  243. break;
  244. case WM_PAINT:
  245. lres = phost->OnPaint(wparam, lparam);
  246. break;
  247. case WM_KILLFOCUS:
  248. lres = phost->OnKillFocus(wparam, lparam);
  249. if (!lres)
  250. goto serv;
  251. goto defproc;
  252. case LBCB_TRACKING:
  253. // release any mousedown stuff
  254. phost->OnLButtonUp(0, 0);
  255. phost->_fFocus = 1;
  256. phost->_fLBCBMessage = 1;
  257. // Fall through case!!!
  258. case WM_SETFOCUS:
  259. lres = phost->OnSetFocus(wparam, lparam);
  260. if (lres)
  261. goto defproc;
  262. goto serv;
  263. case WM_SYSKEYDOWN:
  264. if (phost->OnSyskeyDown((WORD)wparam, (DWORD)lparam))
  265. goto serv;
  266. break;
  267. case WM_CAPTURECHANGED:
  268. if (!phost->OnCaptureChanged(wparam, lparam))
  269. goto serv;
  270. break;
  271. //bug fix #4076
  272. case CB_GETDROPPEDSTATE:
  273. lres = phost->_fListVisible;
  274. goto Exit;
  275. // combo box messages
  276. case CB_GETEXTENDEDUI:
  277. lres = phost->CbGetExtendedUI();
  278. break;
  279. case CB_SETEXTENDEDUI:
  280. lres = phost->CbSetExtendedUI(wparam);
  281. break;
  282. case CB_SETITEMHEIGHT:
  283. lres = phost->CbSetItemHeight((wparam == (unsigned)-1) ? TRUE : FALSE, (int)lparam);
  284. break;
  285. case CB_GETITEMHEIGHT:
  286. lres = phost->CbGetItemHeight((wparam == (unsigned)-1) ? TRUE : FALSE);
  287. break;
  288. // Listbox specific messages
  289. case CB_DELETESTRING:
  290. msg = LB_DELETESTRING;
  291. goto deflstproc;
  292. case CB_SETTOPINDEX:
  293. msg = LB_SETTOPINDEX;
  294. goto deflstproc;
  295. case CB_GETTOPINDEX:
  296. msg = LB_GETTOPINDEX;
  297. goto deflstproc;
  298. case CB_GETCOUNT:
  299. msg = LB_GETCOUNT;
  300. goto deflstproc;
  301. case CB_GETCURSEL:
  302. msg = LB_GETCURSEL;
  303. goto deflstproc;
  304. case CB_GETLBTEXT:
  305. msg = LB_GETTEXT;
  306. goto deflstproc;
  307. case CB_GETLBTEXTLEN:
  308. msg = LB_GETTEXTLEN;
  309. goto deflstproc;
  310. case CB_INSERTSTRING:
  311. msg = LB_INSERTSTRING;
  312. goto deflstproc;
  313. case CB_RESETCONTENT:
  314. msg = LB_RESETCONTENT;
  315. goto deflstproc;
  316. case CB_FINDSTRING:
  317. msg = LB_FINDSTRING;
  318. goto deflstproc;
  319. case CB_FINDSTRINGEXACT:
  320. msg = LB_FINDSTRINGEXACT;
  321. goto deflstproc;
  322. case CB_SELECTSTRING:
  323. //bug fix
  324. // The system control does 2 things here. 1) selects the requested item
  325. // 2) sets the newly selected item to the top of the list
  326. lres = CB_ERR;
  327. if (phost->_hwndList)
  328. {
  329. lres = RichListBoxWndProc(phost->_hwndList, LB_SELECTSTRING, wparam, lparam);
  330. phost->UpdateEditBox();
  331. }
  332. break;
  333. case CB_GETITEMDATA:
  334. msg = LB_GETITEMDATA;
  335. goto deflstproc;
  336. case CB_SETITEMDATA:
  337. msg = LB_SETITEMDATA;
  338. goto deflstproc;
  339. case CB_SETCURSEL:
  340. //bug fix
  341. // The system control does 2 things here. 1) selects the requested item
  342. // 2) sets the newly selected item to the top of the list
  343. if (phost->_hwndList)
  344. {
  345. lres = RichListBoxWndProc(phost->_hwndList, LB_SETCURSEL, wparam, lparam);
  346. if (lres != -1)
  347. RichListBoxWndProc(phost->_hwndList, LB_SETTOPINDEX, wparam, 0);
  348. phost->UpdateEditBox();
  349. }
  350. break;
  351. case CB_ADDSTRING:
  352. msg = LB_ADDSTRING;
  353. goto deflstproc;
  354. // edit box specific messages
  355. case CB_GETEDITSEL:
  356. msg = EM_GETSEL;
  357. goto serv;
  358. case CB_LIMITTEXT:
  359. msg = EM_SETLIMITTEXT;
  360. goto serv;
  361. case CB_SETEDITSEL:
  362. if (phost->_cbType == CCmbBxWinHost::kDropDownList)
  363. {
  364. lres = CB_ERR;
  365. break;
  366. }
  367. msg = EM_SETSEL;
  368. // When we are in a dialog box that is empty, EM_SETSEL will not select
  369. // the final always existing EOP if the control is rich.
  370. if (phost->_fUseSpecialSetSel &&
  371. ((CTxtEdit *)phost->_pserv)->GetAdjustedTextLength() == 0 &&
  372. wparam != -1)
  373. {
  374. lparam = 0;
  375. wparam = 0;
  376. }
  377. else
  378. {
  379. //parameters are different between CB and EM messages
  380. wparam = (WPARAM)(signed short)LOWORD(lparam);
  381. lparam = (LPARAM)(signed short)HIWORD(lparam);
  382. }
  383. goto serv;
  384. case EM_SETMARGINS: //PPT uses this message for the combo box. bug fix #4072
  385. // We need to keep track of the margins size because we have a minimum inset
  386. // value bug fix #4659
  387. if (wparam & EC_LEFTMARGIN)
  388. phost->_dxLOffset = LOWORD(lparam);
  389. if (wparam & EC_RIGHTMARGIN)
  390. phost->_dxROffset = HIWORD(lparam);
  391. phost->OnSetMargins(wparam, LOWORD(lparam) + phost->_dxLInset,
  392. HIWORD(lparam) + phost->_dxRInset);
  393. break;
  394. case EM_GETOPTIONS:
  395. lres = phost->OnGetOptions();
  396. break;
  397. case EM_SETOPTIONS:
  398. phost->OnSetOptions((WORD) wparam, (DWORD) lparam);
  399. lres = (phost->_dwStyle & ECO_STYLES);
  400. if(phost->_fEnableAutoWordSel)
  401. lres |= ECO_AUTOWORDSELECTION;
  402. break;
  403. case EM_HIDESELECTION:
  404. if(lparam)
  405. {
  406. DWORD dwPropertyBits = 0;
  407. phost->_dwStyle |= ES_NOHIDESEL;
  408. if(wparam)
  409. {
  410. phost->_dwStyle &= ~ES_NOHIDESEL;
  411. dwPropertyBits = TXTBIT_HIDESELECTION;
  412. }
  413. // Notify text services of change in status.
  414. phost->_pserv->OnTxPropertyBitsChange(TXTBIT_HIDESELECTION,
  415. dwPropertyBits);
  416. }
  417. goto serv;
  418. case EM_GETPASSWORDCHAR:
  419. #ifndef NOACCESSIBILITY
  420. lres = 0;
  421. break;
  422. #endif
  423. // We should ignore any EM_ messages which we don't handle ourselves
  424. case EM_SETPALETTE:
  425. case EM_GETRECT:
  426. case EM_SETBKGNDCOLOR:
  427. case EM_SETPASSWORDCHAR:
  428. case EM_SETREADONLY:
  429. case EM_SETRECTNP:
  430. case EM_SETRECT:
  431. case CB_GETDROPPEDCONTROLRECT:
  432. case CB_SETDROPPEDWIDTH:
  433. case CB_GETDROPPEDWIDTH:
  434. case CB_INITSTORAGE:
  435. case CB_GETHORIZONTALEXTENT:
  436. case CB_SETHORIZONTALEXTENT:
  437. case CB_SETLOCALE:
  438. case CB_GETLOCALE:
  439. AssertSz(FALSE, "Message not supported");
  440. //FALL THROUGH!!!
  441. case WM_STYLECHANGED:
  442. break;
  443. case EM_SETTEXTEX:
  444. phost->OnSetTextEx(wparam, lparam);
  445. break;
  446. case CB_SHOWDROPDOWN:
  447. if (wparam && !phost->_fListVisible)
  448. {
  449. phost->ShowListBox(TRUE);
  450. }
  451. else if (!wparam && phost->_fListVisible)
  452. {
  453. phost->HideListBox(TRUE, FALSE);
  454. }
  455. break;
  456. #ifndef NOACCESSIBILITY
  457. case WM_GETOBJECT:
  458. IUnknown* punk;
  459. phost->QueryInterface(IID_IUnknown, (void**)&punk);
  460. Assert(punk);
  461. lres = W32->LResultFromObject(IID_IUnknown, wparam, (LPUNKNOWN)punk);
  462. AssertSz(!FAILED((HRESULT)lres), "WM_GETOBJECT message FAILED\n");
  463. punk->Release();
  464. break;
  465. #endif
  466. default:
  467. //CTxtWinHost message handler
  468. serv:
  469. hr = phost->_pserv->TxSendMessage(msg, wparam, lparam, &lres);
  470. defproc:
  471. if(hr == S_FALSE)
  472. {
  473. // Message was not processed by text services so send it
  474. // to the default window proc.
  475. lres = ::DefWindowProc(hwnd, msg, wparam, lparam);
  476. }
  477. // Need to do some things after we send the message to ITextService
  478. switch (msg)
  479. {
  480. case EM_SETSEL:
  481. phost->_pserv->TxSendMessage(EM_HIDESELECTION, 0, 0, NULL);
  482. lres = 1;
  483. break;
  484. // Need to return 1 per SDK documentation
  485. case EM_SETLIMITTEXT:
  486. lres = 1;
  487. break;
  488. case WM_SETFONT:
  489. {
  490. // Special border processing. The inset changes based on the size of the
  491. // defautl character set. So if we got a message that changes the default
  492. // character set, we need to update the inset.
  493. // Update our font height member variable with the new fonts height
  494. // Get the inset information
  495. HDC hdc = GetDC(hwnd);
  496. LONG xAveCharWidth = 0;
  497. LONG yCharHeight = GetECDefaultHeightAndWidth(phost->_pserv, hdc, 1, 1,
  498. W32->GetYPerInchScreenDC(), &xAveCharWidth, NULL, NULL);
  499. ReleaseDC(hwnd, hdc);
  500. if (yCharHeight)
  501. phost->_dyFont = yCharHeight;
  502. // force a recalculation of the edit control
  503. phost->_dyEdit = 0;
  504. phost->CbCalcControlRects(&phost->_rcWindow, TRUE);
  505. // force a resize of the control
  506. phost->_fListVisible = 1;
  507. phost->HideListBox(FALSE, FALSE);
  508. }
  509. goto deflstproc;
  510. case EM_FORMATRANGE:
  511. case EM_SETPARAFORMAT:
  512. case EM_SETCHARFORMAT:
  513. case EM_SETLANGOPTIONS:
  514. case EM_SETBIDIOPTIONS:
  515. case EM_SETTYPOGRAPHYOPTIONS:
  516. goto deflstproc;
  517. }
  518. break;
  519. deflstproc:
  520. //CLstBxWinHost message handler
  521. Assert(phost->_hwndList);
  522. if (phost->_hwndList)
  523. {
  524. lres = SendMessage(phost->_hwndList, msg, wparam, lparam);
  525. switch (msg)
  526. {
  527. case LB_RESETCONTENT:
  528. //need to remove the content from the edit box
  529. phost->_pserv->TxSendMessage(WM_SETTEXT, wparam, NULL, &lres);
  530. break;
  531. case LB_SETCURSEL:
  532. // need to update the edit control
  533. phost->UpdateEditBox();
  534. break;
  535. }
  536. }
  537. break;
  538. }
  539. Exit:
  540. phost->Release();
  541. return lres;
  542. }
  543. //////////////// CCmbBxWinHost Creation/Initialization/Destruction ///////////////////////
  544. #ifndef NOACCESSIBILITY
  545. /*
  546. * CCmbBxWinHost::QueryInterface(REFIID riid, void **ppv)
  547. *
  548. * @mfunc
  549. *
  550. */
  551. HRESULT CCmbBxWinHost::QueryInterface(REFIID riid, void **ppv)
  552. {
  553. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CTxtWinHost::QueryInterface");
  554. if(riid == IID_IAccessible)
  555. *ppv = (IAccessible*)this;
  556. else if (riid == IID_IDispatch)
  557. *ppv = (IDispatch*)(IAccessible*)this;
  558. else if (IsEqualIID(riid, IID_IUnknown))
  559. *ppv = (IUnknown*)(IAccessible*)this;
  560. else
  561. return CTxtWinHost::QueryInterface(riid, ppv);
  562. AddRef();
  563. return NOERROR;
  564. }
  565. #endif
  566. /*
  567. * CCmbBxWinHost::OnNCCreate (hwnd, pcs)
  568. *
  569. * @mfunc
  570. * Static global method to handle WM_NCCREATE message (see remain.c)
  571. */
  572. LRESULT CCmbBxWinHost::OnNCCreate(
  573. HWND hwnd,
  574. const CREATESTRUCT *pcs)
  575. {
  576. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnNCCreate");
  577. CCmbBxWinHost *phost = new CCmbBxWinHost();
  578. if (!phost)
  579. {
  580. // Allocation failure.
  581. return 0;
  582. }
  583. if(!phost->Init(hwnd, pcs)) // Stores phost in associated
  584. { // window data
  585. phost->Shutdown();
  586. delete phost;
  587. return 0;
  588. }
  589. return TRUE;
  590. }
  591. /*
  592. * CCmbBxWinHost::OnNCDestroy (phost)
  593. *
  594. * @mfunc
  595. * Static global method to handle WM_NCCREATE message
  596. *
  597. * @devnote
  598. * phost ptr is stored in window data (GetWindowLongPtr())
  599. */
  600. void CCmbBxWinHost::OnNCDestroy(
  601. CCmbBxWinHost *phost)
  602. {
  603. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnNCDestroy");
  604. // NOTE:
  605. // We have to be careful when we destroy the window because there can be cases
  606. // when we have a valid hwnd but no host for the hwnd so we have to check for
  607. // both cases
  608. if (phost->_plbHost)
  609. {
  610. // ALERT!! :The DestroyWindow function does not send the WM_NCDESTROY message for Windows CE
  611. phost->_plbHost->Release();
  612. }
  613. // Destroy list box here so we will get the WM_DELETEITEM before the
  614. // combo box gets destroyed
  615. if (phost->_hwndList)
  616. DestroyWindow(phost->_hwndList);
  617. phost->Shutdown();
  618. phost->Release();
  619. }
  620. /*
  621. * CCmbBxWinHost::CCmbBxWinHost()
  622. *
  623. * @mfunc
  624. * constructor
  625. */
  626. CCmbBxWinHost::CCmbBxWinHost(): CTxtWinHost(), _plbHost(NULL), _hwndList(NULL), _hcurOld(NULL)
  627. {
  628. _dxLInset = _dxRInset = 0;
  629. _fIgnoreUpdate = 0;
  630. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::CTxtWinHost");
  631. }
  632. /*
  633. * CCmbBxWinHost::~CCmbBxWinHost()
  634. *
  635. * @mfunc
  636. * destructor
  637. */
  638. CCmbBxWinHost::~CCmbBxWinHost()
  639. {
  640. }
  641. /*
  642. * CCmbBxWinHost::Init (hwnd, pcs)
  643. *
  644. * @mfunc
  645. * Initialize this CCmbBxWinHost
  646. */
  647. BOOL CCmbBxWinHost::Init(
  648. HWND hwnd, //@parm Window handle for this control
  649. const CREATESTRUCT *pcs) //@parm Corresponding CREATESTRUCT
  650. {
  651. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::Init");
  652. if(!pcs->lpszClass)
  653. return -1;
  654. _fRightAlign = 0;
  655. _fListVisible = 0;
  656. _fOwnerDraw = 0;
  657. _fFocus = 0;
  658. _fMousedown = 0;
  659. _cyList = 0;
  660. _fDisabled = 0;
  661. _fNoIntegralHeight = 0;
  662. _idCtrl = (UINT)(DWORD_PTR) pcs->hMenu;
  663. _fKeyMaskSet = 0;
  664. _fMouseMaskSet = 0;
  665. _fScrollMaskSet = 0;
  666. _fMousedown = 0;
  667. _nCursor = -2;
  668. _fExtendedUI = 0;
  669. _fLBCBMessage = 0;
  670. _dxROffset = _dxLOffset = 0;
  671. // Set pointer back to CCmbBxWinHost from the window
  672. if(hwnd)
  673. SetWindowLongPtr(hwnd, ibPed, (INT_PTR)this);
  674. _hwnd = hwnd;
  675. if(pcs)
  676. {
  677. _hwndParent = pcs->hwndParent;
  678. _dwExStyle = pcs->dwExStyle;
  679. _dwStyle = pcs->style;
  680. // We need to change our Extended because we don't support most of them
  681. DWORD dwExStyle = _dwExStyle & (WS_EX_LEFTSCROLLBAR | WS_EX_TOPMOST | WS_EX_RIGHT |
  682. WS_EX_RTLREADING | WS_EX_CLIENTEDGE);
  683. // NOTE:
  684. // The order in which we check the style flags immulate
  685. // WinNT's order. So please verify with NT order before
  686. // reaaranging order.
  687. if (_dwStyle & CBS_DROPDOWN)
  688. {
  689. _cbType = kDropDown;
  690. if (_dwStyle & CBS_SIMPLE)
  691. _cbType = kDropDownList;
  692. }
  693. else
  694. {
  695. AssertSz(FALSE, "CBS_SIMPLE not supported");
  696. }
  697. if (_dwStyle & CBS_OWNERDRAWFIXED)
  698. _fOwnerDraw = 1;
  699. if (_dwStyle & WS_DISABLED)
  700. _fDisabled = 1;
  701. if (_dwStyle & CBS_NOINTEGRALHEIGHT)
  702. _fNoIntegralHeight = 1;
  703. // the combobox doesn't support ES_RIGHT because its value is the
  704. // same as CBS_DROPDOWN!!
  705. if (_dwExStyle & WS_EX_RIGHT)
  706. {
  707. _fRightAlign = 1;
  708. _dwStyle |= ES_RIGHT;
  709. }
  710. // implicitly set the ES_AUTOHSCROLL style bit
  711. _dwStyle |= ES_AUTOHSCROLL;
  712. _dwStyle &= ~ES_AUTOVSCROLL;
  713. // If we have any kind of border it will always be a 3d border
  714. if (_dwStyle & WS_BORDER || _dwExStyle & WS_EX_CLIENTEDGE)
  715. {
  716. _fBorder = 1;
  717. _dwStyle &= ~WS_BORDER;
  718. _dwExStyle |= WS_EX_CLIENTEDGE;
  719. dwExStyle |= WS_EX_CLIENTEDGE;
  720. }
  721. // handle default disabled
  722. if(_dwStyle & WS_DISABLED)
  723. _fDisabled = TRUE;
  724. DWORD dwStyle = _dwStyle;
  725. // Remove the verticle scroll style for the window
  726. if (_dwStyle & WS_VSCROLL)
  727. dwStyle &= ~WS_VSCROLL;
  728. // Set the window styles
  729. SetWindowLong(_hwnd, GWL_STYLE, dwStyle);
  730. SetWindowLong(_hwnd, GWL_EXSTYLE, dwExStyle);
  731. }
  732. // Create Text Services component
  733. if(FAILED(CreateTextServices()))
  734. return FALSE;
  735. _xInset = 1;
  736. _yInset = 1;
  737. PARAFORMAT PF2;
  738. PF2.dwMask = 0;
  739. if(_dwExStyle & WS_EX_RIGHT)
  740. {
  741. PF2.dwMask |= PFM_ALIGNMENT;
  742. PF2.wAlignment = (WORD)(PFA_RIGHT); // right or center-aligned
  743. }
  744. if(_dwExStyle & WS_EX_RTLREADING)
  745. {
  746. PF2.dwMask |= PFM_RTLPARA;
  747. PF2.wEffects = PFE_RTLPARA; // RTL reading order
  748. }
  749. if (PF2.dwMask)
  750. {
  751. PF2.cbSize = sizeof(PARAFORMAT2);
  752. // tell text services
  753. _pserv->TxSendMessage(EM_SETPARAFORMAT, SPF_SETDEFAULT, (LPARAM)&PF2, NULL);
  754. }
  755. PARAFORMAT PF; // If left or right alignment,
  756. if(_fRightAlign) // tell text services
  757. {
  758. PF.cbSize = sizeof(PARAFORMAT);
  759. PF.dwMask = PFM_ALIGNMENT;
  760. PF.wAlignment = (WORD)PFA_RIGHT;
  761. _pserv->TxSendMessage(EM_SETPARAFORMAT, SPF_SETDEFAULT, (LPARAM)&PF, NULL);
  762. }
  763. //bug fix #4644 we want the EN_CHANGE and EN_UPDATE notifications
  764. _pserv->TxSendMessage(EM_SETEVENTMASK, 0, ENM_UPDATE | ENM_CHANGE, NULL);
  765. // Tell textservices to turn-on auto font sizing
  766. _pserv->TxSendMessage(EM_SETLANGOPTIONS, 0,
  767. IMF_AUTOKEYBOARD | IMF_AUTOFONT | IMF_AUTOFONTSIZEADJUST | IMF_UIFONTS |
  768. IMF_IMEALWAYSSENDNOTIFY, NULL);
  769. return TRUE;
  770. }
  771. /*
  772. * CCmbBxWinHost::OnCreate (pcs)
  773. *
  774. * @mfunc
  775. * Handle WM_CREATE message
  776. *
  777. * @rdesc
  778. * LRESULT = -1 if failed to in-place activate; else 0
  779. */
  780. LRESULT CCmbBxWinHost::OnCreate(const CREATESTRUCT *pcs)
  781. {
  782. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnCreate");
  783. RECT rcClient;
  784. // sometimes, these values are -1 (from windows itself); just treat them
  785. // as zero in that case
  786. LONG cy = (pcs->cy < 0) ? 0 : pcs->cy;
  787. LONG cx = (pcs->cx < 0) ? 0 : pcs->cx;
  788. rcClient.top = pcs->y;
  789. rcClient.bottom = rcClient.top + cy;
  790. rcClient.left = pcs->x;
  791. rcClient.right = rcClient.left + cx;
  792. // Notify Text Services that we are in place active
  793. if(FAILED(_pserv->OnTxInPlaceActivate(&rcClient)))
  794. return -1;
  795. // Get the font height to base the control heights from
  796. // Initially the font height is the item height
  797. HDC hdc = GetDC(_hwnd);
  798. LONG xAveCharWidth = 0;
  799. _dyFont = GetECDefaultHeightAndWidth(_pserv, hdc, 1, 1,
  800. W32->GetYPerInchScreenDC(), &xAveCharWidth, NULL, NULL);
  801. Assert(_dyFont != 0); // _yInset should be zero since listbox's doesn't have yinsets
  802. ReleaseDC(_hwnd, hdc);
  803. // init variables
  804. _idCtrl = (UINT)(DWORD_PTR)pcs->hMenu;
  805. // Need to calculate the rects of EVERYTHING!!
  806. // Force a request of itemHeight
  807. _rcButton.left = 0;
  808. _dyEdit = 0;
  809. _cyList = -1;
  810. CbCalcControlRects(&rcClient, TRUE);
  811. // Now lets handle the listbox stuff!
  812. // create and tranlate styles for combo box to listbox
  813. DWORD lStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | LBS_NOTIFY | LBS_COMBOBOX | WS_CLIPSIBLINGS;
  814. if (_dwStyle & CBS_HASSTRINGS)
  815. lStyle |= LBS_HASSTRINGS;
  816. if (_dwStyle & CBS_SORT)
  817. lStyle |= LBS_SORT;
  818. if (_dwStyle & CBS_DISABLENOSCROLL)
  819. lStyle |= LBS_DISABLENOSCROLL;
  820. if (_dwStyle & CBS_NOINTEGRALHEIGHT)
  821. lStyle |= LBS_NOINTEGRALHEIGHT;
  822. if (_dwStyle & CBS_OWNERDRAWFIXED)
  823. {
  824. _fOwnerDraw;
  825. lStyle |= LBS_OWNERDRAWFIXED;
  826. }
  827. // copy over some window styles
  828. lStyle |= (_dwStyle & WS_DISABLED);
  829. lStyle |= (_dwStyle & WS_VSCROLL);
  830. DWORD lExStyle = _dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
  831. //NOTE. It doesn't matter if the listbox is made with the correct size since
  832. // it's going to get resized anyways
  833. if (!W32->OnWin9x())
  834. {
  835. //WinNT
  836. _hwndList = ::CreateWindowExW(lExStyle | WS_EX_TOOLWINDOW, L"REListBox20W",
  837. NULL, lStyle, _rcList.left, _rcList.top, _rcList.right - _rcList.left,
  838. _rcList.bottom - _rcList.top, _hwnd, (HMENU)CB_LISTBOXID, NULL, this);
  839. }
  840. else
  841. {
  842. // Win '95, '98 system
  843. _hwndList = ::CreateWindowExA(lExStyle | WS_EX_TOOLWINDOW, "REListBox20W",
  844. NULL, lStyle, _rcList.left, _rcList.top, _rcList.right - _rcList.left,
  845. _rcList.bottom - _rcList.top, _hwnd, (HMENU)CB_LISTBOXID, NULL, this);
  846. }
  847. Assert(_hwndList);
  848. _plbHost = (CLstBxWinHost *) GetWindowLongPtr(_hwndList, ibPed);
  849. Assert(_plbHost);
  850. if (!_plbHost)
  851. return -1;
  852. // increment reference counter!
  853. _plbHost->AddRef();
  854. if (_cbType != kSimple)
  855. ShowWindow(_hwndList, SW_HIDE);
  856. SetParent(_hwndList, NULL);
  857. if (_cbType == kDropDownList)
  858. {
  859. AssertSz(!((CTxtEdit*)_pserv)->_fReadOnly, "edit is readonly");
  860. // Tell textservices to select the entire background
  861. _pserv->TxSendMessage(EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR, NULL);
  862. // format the paragraph to immulate the system control
  863. PARAFORMAT2 pf;
  864. pf.cbSize = sizeof(PARAFORMAT2);
  865. pf.dwMask = PFM_STARTINDENT;
  866. pf.dxStartIndent = (1440.0 / W32->GetXPerInchScreenDC());
  867. _pserv->TxSendMessage(EM_SETPARAFORMAT, SPF_SETDEFAULT, (LPARAM)&pf, NULL);
  868. _usIMEMode = ES_NOIME;
  869. // Tell textservices to turnoff ime
  870. _pserv->TxSendMessage(EM_SETEDITSTYLE, SES_NOIME, SES_NOIME, NULL);
  871. }
  872. else
  873. {
  874. // make the richedit control behave like the edit control
  875. _pserv->TxSendMessage(EM_SETEDITSTYLE, SES_EMULATESYSEDIT, SES_EMULATESYSEDIT, NULL);
  876. }
  877. // Need to resize the list box
  878. if (_cbType != kSimple)
  879. SetDropSize(&_rcList);
  880. return 0;
  881. }
  882. /////////////////////////// CCmbBxWinHost Helper functions /////////////////////////////////
  883. /*
  884. * CCmbBxWinHost::GetTextLength ()
  885. *
  886. * @mfunc
  887. * returns the text length of the edit control using CR and NOT CRLF
  888. *
  889. * @rdesc
  890. * LRESULT = text length
  891. */
  892. LRESULT CCmbBxWinHost::GetTextLength()
  893. {
  894. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::GetTextLength");
  895. LRESULT lr = 0;
  896. GETTEXTLENGTHEX gtl;
  897. gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
  898. gtl.codepage = 1200;
  899. #ifdef DEBUG
  900. HRESULT hr = _pserv->TxSendMessage(EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0, &lr);
  901. Assert(hr == NOERROR);
  902. #else
  903. _pserv->TxSendMessage(EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0, &lr);
  904. #endif
  905. return lr;
  906. }
  907. /*
  908. * CCmbBxWinHost::GetEditText (LPTSTR, int)
  909. *
  910. * @mfunc
  911. * returns the text length in the edit control in UNICODE
  912. *
  913. * @rdesc
  914. * LRESULT = text length copied to passed in buffer
  915. */
  916. LRESULT CCmbBxWinHost::GetEditText (LPTSTR szStr, int nSize)
  917. {
  918. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::GetEditText");
  919. LRESULT lr = 0;
  920. GETTEXTEX gt;
  921. gt.cb = nSize * sizeof(TCHAR);
  922. gt.flags = 0;
  923. gt.codepage = 1200;
  924. gt.lpDefaultChar = NULL;
  925. gt.lpUsedDefChar = NULL;
  926. #ifdef DEBUG
  927. HRESULT hr = _pserv->TxSendMessage(EM_GETTEXTEX, (WPARAM)&gt, (LPARAM)szStr, &lr);
  928. Assert(hr == NOERROR);
  929. #else
  930. _pserv->TxSendMessage(EM_GETTEXTEX, (WPARAM)&gt, (LPARAM)szStr, &lr);
  931. #endif
  932. return lr;
  933. }
  934. /*
  935. * CCmbBxWinHost::SetDropSize(RECT* prc)
  936. *
  937. * @mfunc
  938. * Compute the drop down window's width and max height
  939. *
  940. * @rdesc
  941. * BOOL = SUCCESSFUL ? TRUE : FALSE
  942. */
  943. void CCmbBxWinHost::SetDropSize(RECT* prc)
  944. {
  945. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::SetDropSize");
  946. _fListVisible = TRUE;
  947. HideListBox(FALSE, FALSE);
  948. POINT pt1 = {prc->left, prc->top};
  949. POINT pt2 = {prc->right, prc->bottom};
  950. ::ClientToScreen(_hwnd, &pt1);
  951. ::ClientToScreen(_hwnd, &pt2);
  952. MoveWindow(_hwndList, pt1.x, pt1.y, pt2.x - pt1.x,
  953. pt2.y - pt1.y, FALSE);
  954. }
  955. /*
  956. * CCmbBxWinHost::SetSizeEdit(int nLeft, int nTop, int nRight, int nBottom)
  957. *
  958. * @mfunc
  959. * sets the edit controls size
  960. *
  961. * @rdesc
  962. * BOOL = SUCCESSFUL ? TRUE : FALSE
  963. */
  964. void CCmbBxWinHost::SetSizeEdit(int nLeft, int nTop, int nRight, int nBottom)
  965. {
  966. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::SizeEdit");
  967. // Generate default view rect from client rect
  968. if(_fBorder)
  969. {
  970. // Factors in space for borders
  971. _rcViewInset.top = W32->DYtoHimetricY(nTop, W32->GetYPerInchScreenDC());
  972. _rcViewInset.bottom = W32->DYtoHimetricY(nBottom, W32->GetYPerInchScreenDC());
  973. _rcViewInset.left = W32->DXtoHimetricX(nLeft, W32->GetXPerInchScreenDC());
  974. _rcViewInset.right = W32->DXtoHimetricX(nRight, W32->GetXPerInchScreenDC());
  975. }
  976. else
  977. {
  978. // Default the top and bottom inset to 0 and the left and right
  979. // to the size of the border.
  980. _rcViewInset.top = 0;
  981. _rcViewInset.bottom = 0;
  982. _rcViewInset.left = W32->DXtoHimetricX(nLeft, W32->GetXPerInchScreenDC());
  983. _rcViewInset.right = W32->DXtoHimetricX(nRight, W32->GetXPerInchScreenDC());
  984. }
  985. }
  986. /*
  987. * CCmbBxWinHost::CbCalcControlRects(RECT* prc, BOOL bCalcChange)
  988. *
  989. * @mfunc
  990. * Calculates the RECT for all the controls. The rect should
  991. * include the non-client area's also
  992. *
  993. * @rdesc
  994. * BOOL = SUCCESSFUL ? TRUE : FALSE
  995. */
  996. BOOL CCmbBxWinHost::CbCalcControlRects(RECT* prc, BOOL bCalcChange)
  997. {
  998. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::CbCalcControlRects");
  999. // copy over the window rect
  1000. _rcWindow = *prc;
  1001. // Item specific things
  1002. const int smY = GetSystemMetrics(SM_CYEDGE);
  1003. const int smX = GetSystemMetrics(SM_CXEDGE);
  1004. _cxCombo = _rcWindow.right - _rcWindow.left;
  1005. if (!_dyEdit)
  1006. _dyEdit = _dyFont + 2 + ((_fBorder) ? (2 * _yInset) : 0);
  1007. if (_fOwnerDraw)
  1008. {
  1009. if (bCalcChange)
  1010. {
  1011. // No height has been defined yet for the static text window. Send
  1012. // a measure item message to the parent
  1013. MEASUREITEMSTRUCT mis;
  1014. mis.CtlType = ODT_COMBOBOX;
  1015. mis.CtlID = _idCtrl;
  1016. mis.itemID = (UINT)-1;
  1017. mis.itemHeight = _dyEdit;
  1018. mis.itemData = 0;
  1019. SendMessage(_hwndParent, WM_MEASUREITEM, _idCtrl, (LPARAM)&mis);
  1020. _dyEdit = mis.itemHeight;
  1021. }
  1022. }
  1023. else
  1024. {
  1025. // NOTE:
  1026. // Richedit prevents us from trying to set the itemHeight less than the
  1027. // font height so we need to take account of this by preventing user from
  1028. // setting height less than font height
  1029. int nyEdit = _dyFont + ((_fBorder) ? 2 * _yInset : 0);
  1030. if (_dyEdit > nyEdit)
  1031. {
  1032. //In order for the highlighting to work properly we need to empty
  1033. //the richedit control
  1034. LRESULT nLen;
  1035. _pserv->TxSendMessage(WM_GETTEXTLENGTH, 0, 0, &nLen);
  1036. TCHAR* pwch = NULL;
  1037. if (nLen && _cbType == kDropDownList)
  1038. {
  1039. pwch = new TCHAR[nLen + 1 /*NULL*/];
  1040. AssertSz(pwch, "Unable to allocate memory for string");
  1041. if (pwch)
  1042. {
  1043. // Get the text from richedit and emtpy it
  1044. _pserv->TxSendMessage(WM_GETTEXT, nLen + 1, (LPARAM)pwch, NULL);
  1045. _pserv->TxSendMessage(WM_SETTEXT, 0, NULL, NULL);
  1046. }
  1047. else
  1048. {
  1049. // something bad happened so send a message
  1050. // to client
  1051. TxNotify(EN_ERRSPACE, NULL);
  1052. }
  1053. }
  1054. else if (_cbType == kDropDown && nLen == 0)
  1055. {
  1056. // we need to insert a dummy character into the richedit
  1057. // control so it won't try to highlight space after
  1058. // the paragraph
  1059. _pserv->TxSendMessage(WM_SETTEXT, 0, (LPARAM)L" ", NULL);
  1060. }
  1061. // Calculate the difference in size
  1062. nyEdit = _dyEdit - nyEdit;
  1063. PARAFORMAT2 pf;
  1064. pf.cbSize = sizeof(PARAFORMAT2);
  1065. pf.dwMask = PFM_SPACEAFTER;
  1066. pf.dySpaceAfter = (int)(((double)nyEdit * 1440.0) / (double)W32->GetYPerInchScreenDC());
  1067. _pserv->TxSendMessage(EM_SETPARAFORMAT, SPF_SETDEFAULT, (LPARAM)&pf, NULL);
  1068. //Reset the text which was there before in the richedit control
  1069. if (pwch || (_cbType == kDropDown && nLen == 0))
  1070. {
  1071. _pserv->TxSendMessage(WM_SETTEXT, 0, (LPARAM)(pwch ? pwch : NULL), NULL);
  1072. if (pwch)
  1073. delete pwch;
  1074. }
  1075. }
  1076. else
  1077. _dyEdit = nyEdit; // stabalize ourselves
  1078. }
  1079. // For Bordered Combobox we take account of the clientedge for the top
  1080. // and bottom. And since we want to draw the focus rect within the yellow
  1081. // area we need to subtract 1.
  1082. _cyCombo = min(_dyEdit + ((_fBorder) ? 2 * smY : 0),
  1083. _rcWindow.bottom - _rcWindow.top);
  1084. // recompute the max height of the dropdown listbox -- full window
  1085. // size MINUS edit/static height
  1086. if (_cyList == -1)
  1087. _cyList = max((_rcWindow.bottom - _rcWindow.top) - _cyCombo, 0);
  1088. // calculate the rect for the buttons
  1089. if (_cbType != kSimple)
  1090. {
  1091. _rcButton.top = 0;
  1092. _rcButton.bottom = min(_dyEdit, _rcWindow.bottom - _rcWindow.top);
  1093. if (_fRightAlign)
  1094. {
  1095. _rcButton.left = 0;
  1096. _rcButton.right = _rcButton.left + GetSystemMetrics(SM_CXVSCROLL);
  1097. }
  1098. else
  1099. {
  1100. _rcButton.right = _cxCombo - ((_fBorder) ? (2 * smX): 0);
  1101. _rcButton.left = _rcButton.right - GetSystemMetrics(SM_CXVSCROLL);
  1102. }
  1103. }
  1104. // calculate the edit control rect
  1105. int nTop = _yInset;
  1106. int nBottom = 0;
  1107. _dxLInset = _xInset;
  1108. _dxRInset = _xInset;
  1109. if (_cbType != kSimple)
  1110. {
  1111. if (_fRightAlign)
  1112. _dxLInset = (_rcButton.right - _rcButton.left) + smX;
  1113. else
  1114. _dxRInset = (_rcButton.right - _rcButton.left) + smX;
  1115. }
  1116. SetSizeEdit(_dxLInset + _dxLOffset, nTop, _dxRInset + _dxROffset, nBottom);
  1117. // calculate the rect for the list box window
  1118. _rcList.left = (_fBorder) ? - smX : 0;
  1119. _rcList.top = _cyCombo - ((_fBorder) ? smY : 0);
  1120. _rcList.right = (_fBorder) ? max(_cxCombo - smX, 0) : _rcWindow.right;
  1121. _rcList.bottom = _cyCombo + _cyList;
  1122. return TRUE;
  1123. }
  1124. /*
  1125. * CCmbBxWinHost::DrawButton(HDC, BOOL)
  1126. *
  1127. * @mfunc
  1128. * Draws the combo box button given an hdc
  1129. *
  1130. * @rdesc
  1131. * BOOL = SUCCESSFUL ? TRUE : FALSE
  1132. */
  1133. void CCmbBxWinHost::DrawButton(HDC hdc, BOOL bDown)
  1134. {
  1135. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::DrawButton");
  1136. // Check if we have to draw the drop down button
  1137. if (_cbType != kSimple)
  1138. {
  1139. BOOL bRelease = !hdc;
  1140. if (!hdc)
  1141. hdc = TxGetDC();
  1142. DrawFrameControl(hdc, &_rcButton, DFC_SCROLL, DFCS_SCROLLCOMBOBOX |
  1143. (bDown ? DFCS_PUSHED | DFCS_FLAT: 0) | (!_fBorder ? DFCS_FLAT : 0) |
  1144. (!_fDisabled ? 0 : DFCS_INACTIVE));
  1145. if (bRelease)
  1146. TxReleaseDC(hdc);
  1147. }
  1148. }
  1149. /*
  1150. * CCmbBxWinHost::TxNotify (iNotify, pv)
  1151. *
  1152. * @mfunc
  1153. * Notify Text Host of various events. Note that there are
  1154. * two basic categories of events, "direct" events and
  1155. * "delayed" events. In the case of the combobox we will
  1156. * notify parent of only two edit notifications; EN_CHANGE
  1157. * and EN_UPDATE. The others will be from the listbox
  1158. * or be generated because of focus changing
  1159. *
  1160. *
  1161. * @rdesc
  1162. * S_OK - call succeeded <nl>
  1163. * S_FALSE -- success, but do some different action
  1164. * depending on the event type (see below).
  1165. *
  1166. * @comm
  1167. * <CBN_DBLCLK> user double-clicks an item in the list box
  1168. *
  1169. * <CBN_ERRSPACE> The list box cannot allocate enough memory to
  1170. * fulfill a request
  1171. *
  1172. * <CBN_KILLFOCUS> The list box loses the keyboard focus
  1173. *
  1174. * <CBN_SELENDCANCEL> notification message is sent when the user
  1175. * selects an item, but then selects another control or closes the
  1176. * dialog box
  1177. *
  1178. * <CBN_SELCHANGE> notification message is sent when the user changes
  1179. * the current selection in the list box of a combo box
  1180. *
  1181. * <CBN_SETFOCUS> The list box receives the keyboard focus
  1182. *
  1183. * <CBN_CLOSEUP> This message is sent when the listbox has been closed
  1184. *
  1185. * <CBN_SELENDOK> notification message is sent when the user selects a
  1186. * list item, or selects an item and then closes the list
  1187. *
  1188. * <CBN_EDITCHANGE> notification message is sent after the user
  1189. * has taken an action that may have altered the text in the edit
  1190. * control portion of a combo box
  1191. *
  1192. * <CBN_EDITUPDATE> notification message is sent when the edit control
  1193. * portion of a combo box is about to display altered text
  1194. *
  1195. * <CBN_DROPDOWN> This message is sent when the listbox has been made visible
  1196. */
  1197. HRESULT CCmbBxWinHost::TxNotify(
  1198. DWORD iNotify, //@parm Event to notify host of. One of the
  1199. // EN_XXX values from Win32, e.g., EN_CHANGE
  1200. void *pv) //@parm In-only parameter with extra data. Type
  1201. // dependent on <p iNotify>
  1202. {
  1203. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CCmbBxWinHost::TxNotify");
  1204. HRESULT hr = S_FALSE;
  1205. if(_hwndParent)
  1206. {
  1207. // First, handle WM_NOTIFY style notifications
  1208. //WPARAM LOWORD(_idCtrl) ; LPARAM - HWND(COMBO)
  1209. switch(iNotify)
  1210. {
  1211. case EN_CHANGE:
  1212. //update the listbox bug fix #5206
  1213. if (_fIgnoreChange)
  1214. {
  1215. _fIgnoreChange = 0;
  1216. return hr;
  1217. }
  1218. if (_fListVisible && _cbType == kDropDown)
  1219. UpdateListBox(FALSE);
  1220. else if (_cbType == kDropDownList)
  1221. // don't send notification if dropdownlist
  1222. return S_FALSE;
  1223. iNotify = CBN_EDITCHANGE;
  1224. goto sndmsg;
  1225. case EN_UPDATE:
  1226. //bug fix - we're sending too much CBN_UPDATE notifications
  1227. if (_fIgnoreUpdate)
  1228. return hr;
  1229. if (_cbType == kDropDownList)
  1230. return S_FALSE;
  1231. iNotify = CBN_EDITUPDATE;
  1232. goto sndmsg;
  1233. case EN_ERRSPACE:
  1234. iNotify = (unsigned)CBN_ERRSPACE;
  1235. goto sndmsg;
  1236. case CBN_SELCHANGE:
  1237. case CBN_SELENDCANCEL:
  1238. case CBN_CLOSEUP:
  1239. case CBN_DBLCLK:
  1240. case CBN_DROPDOWN:
  1241. case CBN_KILLFOCUS:
  1242. case CBN_SELENDOK:
  1243. case CBN_SETFOCUS:
  1244. sndmsg:
  1245. hr = SendMessage(_hwndParent, WM_COMMAND,
  1246. GET_WM_COMMAND_MPS(_idCtrl, _hwnd, iNotify));
  1247. }
  1248. }
  1249. return hr;
  1250. }
  1251. /*
  1252. * CCmbBxWinHost::DrawEditFocus(HDC)
  1253. *
  1254. * @mfunc
  1255. * Either draws or notifies owner to draw the focus rect
  1256. *
  1257. * @rdesc
  1258. * void
  1259. */
  1260. void CCmbBxWinHost::DrawEditFocus(HDC hdc)
  1261. {
  1262. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::DrawEditFocus");
  1263. BOOL bRelease = FALSE;
  1264. if (!hdc)
  1265. {
  1266. hdc = TxGetDC();
  1267. bRelease = TRUE;
  1268. }
  1269. RECT rc;
  1270. GetClientRect(_hwnd, &rc);
  1271. if (!_fOwnerDraw)
  1272. {
  1273. HiliteEdit(_fFocus);
  1274. if (_cbType == kDropDownList)
  1275. {
  1276. // shrink the focus rect by the inset
  1277. rc.top += _yInset;
  1278. rc.bottom -= _yInset;
  1279. if (_fRightAlign)
  1280. rc.left = _rcButton.right;
  1281. else
  1282. rc.right = _rcButton.left;
  1283. rc.left += _xInset;
  1284. rc.right -= _xInset;
  1285. DrawFocusRect(hdc, &rc);
  1286. }
  1287. }
  1288. if (bRelease)
  1289. TxReleaseDC(hdc);
  1290. }
  1291. /*
  1292. * CCmbBxWinHost::SetSelectionInfo(BOOL bOk, int nIdx)
  1293. *
  1294. * @mfunc
  1295. * Completes the text in the edit box with the closest match from the
  1296. * listbox. If a prefix match can't be found, the edit control text isn't
  1297. * updated. Assume a DROPDOWN style combo box.
  1298. *
  1299. * @rdesc
  1300. * void
  1301. */
  1302. void CCmbBxWinHost::SetSelectionInfo(BOOL bOk, int nIdx)
  1303. {
  1304. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::SetSelectionInfo");
  1305. _nCursor = nIdx;
  1306. _bSelOk = bOk;
  1307. }
  1308. /*
  1309. * CCmbBxWinHost::AutoUpdateEdit(int i)
  1310. *
  1311. * @mfunc
  1312. * Completes the text in the edit box with the closest match from the
  1313. * listbox. If a prefix match can't be found, the edit control text isn't
  1314. * updated. Assume a DROPDOWN style combo box.
  1315. *
  1316. * @rdesc
  1317. * void
  1318. */
  1319. void CCmbBxWinHost::AutoUpdateEdit(int nItem)
  1320. {
  1321. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::AutoUpdateEdit");
  1322. // We update the edit part of the combo box with the current selection of
  1323. // the list box
  1324. int cch;
  1325. TCHAR* pszText;
  1326. LRESULT lr;
  1327. // find the best matching string in the list box
  1328. if (nItem == -1 || nItem == -2)
  1329. {
  1330. cch = GetTextLength();
  1331. // no text to search so just get out
  1332. if (!cch)
  1333. return;
  1334. cch++; // account for null character
  1335. pszText = new TCHAR[cch];
  1336. AssertSz(pszText, "string allocation failed");
  1337. if (!pszText)
  1338. {
  1339. TxNotify((unsigned)CBN_ERRSPACE, NULL);
  1340. return;
  1341. }
  1342. // get string from edit control and try to find a exact match else a match
  1343. // in the list box
  1344. GetEditText(pszText, cch);
  1345. nItem = RichListBoxWndProc(_hwndList, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pszText);
  1346. if (nItem == -1)
  1347. nItem = RichListBoxWndProc(_hwndList, LB_FINDSTRING, (WPARAM)-1, (LPARAM)pszText);
  1348. delete [] pszText;
  1349. // no match found so just get out
  1350. if (nItem == -1)
  1351. return;
  1352. }
  1353. cch = RichListBoxWndProc(_hwndList, LB_GETTEXTLEN, nItem, 0);
  1354. if (cch <= 0)
  1355. return;
  1356. cch++; // account for null character
  1357. pszText = new TCHAR[cch];
  1358. AssertSz(pszText, "Unable to allocate string");
  1359. if (!pszText)
  1360. {
  1361. TxNotify((unsigned)CBN_ERRSPACE, NULL);
  1362. return;
  1363. }
  1364. RichListBoxWndProc(_hwndList, LB_GETTEXT, nItem, (LPARAM)pszText);
  1365. _fIgnoreChange = 1;
  1366. _pserv->TxSendMessage(WM_SETTEXT, 0, (LPARAM)pszText, &lr);
  1367. HiliteEdit(TRUE);
  1368. delete [] pszText;
  1369. }
  1370. /*
  1371. * CCmbBxWinHost::HiliteEdit(BOOL)
  1372. *
  1373. * @mfunc
  1374. * Sets the hilite background or selects the entire text for the
  1375. * edit control
  1376. *
  1377. * @rdesc
  1378. * void
  1379. */
  1380. void CCmbBxWinHost::HiliteEdit(BOOL bSelect)
  1381. {
  1382. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::HiliteEdit");
  1383. //bug fix 4073
  1384. Assert(!_fOwnerDraw || _cbType == kDropDown);
  1385. if (_cbType != kDropDownList)
  1386. {
  1387. //if bSelect is true else put cursor at beginning of text
  1388. _pserv->TxSendMessage(EM_SETSEL, 0, (LPARAM)((bSelect) ? -1 : 0), NULL);
  1389. }
  1390. else
  1391. {
  1392. //Get the range of the paragraph
  1393. ITextRange* pRange;
  1394. if (NOERROR != ((CTxtEdit*)_pserv)->Range(0, 0, &pRange))
  1395. {
  1396. AssertSz(FALSE, "unable to get range");
  1397. return;
  1398. }
  1399. Assert(pRange);
  1400. DWORD crFore = (unsigned)tomAutoColor;
  1401. DWORD crBack = (unsigned)tomAutoColor;
  1402. if (bSelect)
  1403. {
  1404. crFore = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  1405. crBack = ::GetSysColor(COLOR_HIGHLIGHT);
  1406. }
  1407. // Get the entire paragraph
  1408. ITextFont* pFont = NULL;
  1409. // Select entire text
  1410. CHECKNOERROR(pRange->SetIndex(tomParagraph, 1, 1));
  1411. // Set the background and forground color
  1412. CHECKNOERROR(pRange->GetFont(&pFont));
  1413. Assert(pFont);
  1414. CHECKNOERROR(pFont->SetBackColor(crBack));
  1415. CHECKNOERROR(pFont->SetForeColor(crFore));
  1416. CleanExit:
  1417. // Release pointers
  1418. if (pFont)
  1419. pFont->Release();
  1420. pRange->Release();
  1421. }
  1422. }
  1423. /*
  1424. * CCmbBxWinHost::UpdateEditBox()
  1425. *
  1426. * @mfunc
  1427. * Updates the editcontrol window so that it contains the text
  1428. * given by the current selection in the listbox. If the listbox has no
  1429. * selection (ie. -1), then we erase all the text in the editcontrol.
  1430. *
  1431. * hdc is from WM_PAINT messages Begin/End Paint hdc. If null, we should
  1432. * get our own dc.
  1433. *
  1434. * @rdesc
  1435. * void
  1436. */
  1437. void CCmbBxWinHost::UpdateEditBox()
  1438. {
  1439. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::UpdateEditBox");
  1440. Assert(_hwndList);
  1441. Assert(_plbHost);
  1442. // Update the edit box
  1443. if (_cbType == kDropDownList && _fOwnerDraw)
  1444. {
  1445. CbMessageItemHandler(NULL, ITEM_MSG_DRAWCOMBO, 0, 0);
  1446. return;
  1447. }
  1448. else
  1449. {
  1450. TCHAR* pszText = NULL;
  1451. int nItem = (signed)_plbHost->GetCursor();
  1452. if (nItem != -1)
  1453. {
  1454. int cch = RichListBoxWndProc(_hwndList, LB_GETTEXTLEN, (LPARAM)nItem, 0);
  1455. pszText = new TCHAR[cch + 1];
  1456. AssertSz(pszText, "allocation failed");
  1457. // just get out if memory allocation failed
  1458. if (!pszText)
  1459. {
  1460. TxNotify((unsigned)CBN_ERRSPACE, NULL);
  1461. return;
  1462. }
  1463. RichListBoxWndProc(_hwndList, LB_GETTEXT, (WPARAM)nItem, (LPARAM)pszText);
  1464. }
  1465. // if the cursor is on a valid item then update edit with the item text
  1466. // else we just display a blank text
  1467. TCHAR szEmpty[] = L"";
  1468. _fIgnoreChange = 1;
  1469. _pserv->TxSendMessage(WM_SETTEXT, 0, (LPARAM)((pszText) ? pszText : szEmpty), NULL);
  1470. DrawEditFocus(NULL);
  1471. if (pszText)
  1472. delete pszText;
  1473. }
  1474. }
  1475. /*
  1476. * CCmbBxWinHost::UpdateListBox(BOOL)
  1477. *
  1478. * @mfunc
  1479. * Updates the list box by searching and moving to the top the text in
  1480. * edit control. And possibly pre-selecting the item if bSetSel is set
  1481. *
  1482. * @rdesc
  1483. * int = found ? index of item : -1
  1484. */
  1485. int CCmbBxWinHost::UpdateListBox(BOOL bSetSel)
  1486. {
  1487. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::UpdateListBox");
  1488. int nItem = -1;
  1489. int nSel = -1;
  1490. TCHAR* pszText;
  1491. int cch;
  1492. // Get text from edit box
  1493. cch = GetTextLength();
  1494. if (cch)
  1495. {
  1496. // add one for null string
  1497. cch++;
  1498. pszText = new TCHAR[cch];
  1499. if (pszText != NULL)
  1500. {
  1501. if (GetEditText(pszText, cch))
  1502. {
  1503. //Bypass Winnt thunking layer by calling the function directly
  1504. nItem = RichListBoxWndProc(_hwndList, LB_FINDSTRING, (WPARAM)-1L, (LPARAM)pszText);
  1505. }
  1506. delete [] pszText;
  1507. }
  1508. else
  1509. {
  1510. TxNotify((unsigned)CBN_ERRSPACE, NULL);
  1511. return 0;
  1512. }
  1513. }
  1514. if (bSetSel)
  1515. nSel = nItem;
  1516. // update the list box
  1517. RichListBoxWndProc(_hwndList, LB_SETCURSEL, (LPARAM)nSel, 0);
  1518. RichListBoxWndProc(_hwndList, LB_SETTOPINDEX, (LPARAM)max(nItem, 0), 0);
  1519. return nItem;
  1520. }
  1521. /*
  1522. * CCmbBxWinHost::HideListBox(BOOL, BOOL)
  1523. *
  1524. * @mfunc
  1525. * Hides the list box
  1526. *
  1527. * @rdesc
  1528. * void
  1529. */
  1530. BOOL CCmbBxWinHost::HideListBox(BOOL bNotify, BOOL fSelOk)
  1531. {
  1532. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::HideListBox");
  1533. //send CBN_SELENDOK to all types of comboboxes but only
  1534. // allow CBN_SELENDCANCEL to be sent for droppable comboboxes
  1535. if (bNotify)
  1536. {
  1537. if (fSelOk)
  1538. {
  1539. TxNotify(CBN_SELENDOK, NULL);
  1540. }
  1541. else if (_cbType != kSimple)
  1542. {
  1543. TxNotify(CBN_SELENDCANCEL, NULL);
  1544. }
  1545. }
  1546. // return, we don't hide simple combo boxes.
  1547. if (!_fListVisible || _cbType == kSimple)
  1548. return TRUE;
  1549. // Tell the listbox to end tracking
  1550. Assert(_plbHost);
  1551. _plbHost->OnCBTracking(LBCBM_END, 0);
  1552. // Hide the listbox window
  1553. _fListVisible = 0;
  1554. ShowWindow(_hwndList, SW_HIDE);
  1555. if (_fCapture)
  1556. {
  1557. _fCapture = FALSE;
  1558. TxSetCapture(FALSE);
  1559. }
  1560. _fResizing = 1;
  1561. // Invalidate the item area now since SWP() might update stuff.
  1562. // Since the combo is CS_VREDRAW/CS_HREDRAW, a size change will
  1563. // redraw the whole thing, including the item rect. But if it
  1564. // isn't changing size, we still want to redraw the item anyway
  1565. // to show focus/selection
  1566. if (_cbType == kDropDownList)
  1567. {
  1568. if (!_fOwnerDraw)
  1569. HiliteEdit(_fFocus);
  1570. InvalidateRect(_hwnd, NULL, TRUE);
  1571. }
  1572. //bug fix
  1573. // The button may look depressed so we must redraw the button
  1574. if (_fMousedown)
  1575. {
  1576. _fMousedown = FALSE;
  1577. InvalidateRect(_hwnd, &_rcButton, FALSE);
  1578. }
  1579. SetWindowPos(_hwnd, HWND_TOP, 0, 0, _cxCombo, _cyCombo,
  1580. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1581. _fResizing = 0;
  1582. if (_cbType == kDropDown)
  1583. AutoUpdateEdit(_nCursor);
  1584. _nCursor = -2;
  1585. // In case size didn't change
  1586. UpdateWindow(_hwnd);
  1587. if (bNotify)
  1588. {
  1589. //Notify parent we will be popping up the combo box.
  1590. TxNotify(CBN_CLOSEUP, NULL);
  1591. }
  1592. // reset back to old cursor if mouse cursor was set
  1593. if (_hcurOld)
  1594. {
  1595. TxSetCursor2(_hcurOld, NULL);
  1596. _hcurOld = NULL;
  1597. }
  1598. return(TRUE);
  1599. }
  1600. /*
  1601. * CCmbBxWinHost::ShowListBox(BOOL)
  1602. *
  1603. * @mfunc
  1604. * Displays the list box
  1605. *
  1606. * @rdesc
  1607. * void
  1608. */
  1609. void CCmbBxWinHost::ShowListBox(BOOL fTrack)
  1610. {
  1611. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::ShowListBox");
  1612. Assert(_cbType != kSimple);
  1613. Assert(_hwndList);
  1614. // Notify parent window we are about to drop down the list box
  1615. TxNotify(CBN_DROPDOWN, NULL);
  1616. // force a redraw of the button so it looks depressed
  1617. InvalidateRect(_hwnd, &_rcButton, TRUE);
  1618. _fListVisible = TRUE;
  1619. _fIgnoreChange = 0;
  1620. _bSelOk = 0;
  1621. if (_cbType == kDropDown)
  1622. {
  1623. UpdateListBox(!_fMousedown);
  1624. if (!_fMousedown)
  1625. AutoUpdateEdit(-1);
  1626. _nCursor = _plbHost->GetCursor();
  1627. }
  1628. else
  1629. {
  1630. // Scroll the currently selected item to the top of the listbox.
  1631. int idx = (signed)_plbHost->GetCursor();
  1632. _nCursor = idx;
  1633. if (idx == -1)
  1634. idx = 0;
  1635. // set the top index if there is something in the list box
  1636. if (_plbHost->GetCount() > 0)
  1637. RichListBoxWndProc(_hwndList, LB_SETTOPINDEX, idx, 0);
  1638. // We are to lose focus in this case
  1639. _fFocus = 0;
  1640. if (!_fOwnerDraw)
  1641. HiliteEdit(FALSE);
  1642. // We need to invalidate the edit rect so that the focus frame/invert
  1643. // will be turned off when the listbox is visible. Tandy wants this for
  1644. // his typical reasons...
  1645. InvalidateRect(_hwnd, NULL, TRUE);
  1646. }
  1647. // Figure out where to position the dropdown listbox.
  1648. // We want the dropdown to pop below or above the combo
  1649. // Get screen coords
  1650. RECT rcList;
  1651. POINT pt1;
  1652. pt1.x = _rcList.left;
  1653. pt1.y = _rcList.top;
  1654. TxClientToScreen(&pt1);
  1655. rcList.left = pt1.x;
  1656. rcList.top = pt1.y;
  1657. rcList.right = rcList.left + (_rcList.right - _rcList.left);
  1658. rcList.bottom = rcList.top + _cyList;
  1659. // List area
  1660. int cyItem = _plbHost->GetItemHeight();
  1661. AssertSz(cyItem, "LB_GETITEMHEIGHT is returning 0");
  1662. if (cyItem == 0)
  1663. cyItem = _plbHost->GetFontHeight();
  1664. // Windows NT comment:
  1665. // we shoulda' just been able to use cyDrop here, but thanks to VB's need
  1666. // to do things their OWN SPECIAL WAY, we have to keep monitoring the size
  1667. // of the listbox 'cause VB changes it directly (jeffbog 03/21/94)
  1668. int iHeight = max(_cyList, _rcWindow.bottom - _rcWindow.top);
  1669. DWORD dwMult = (DWORD)RichListBoxWndProc(_hwndList, LB_GETCOUNT, 0, 0);
  1670. if (dwMult)
  1671. {
  1672. dwMult = (DWORD)(LOWORD(dwMult) * cyItem);
  1673. dwMult += GetSystemMetrics(SM_CYEDGE);
  1674. if (dwMult < 0x7FFF)
  1675. iHeight = min(LOWORD(dwMult), iHeight);
  1676. }
  1677. if (!_fNoIntegralHeight)
  1678. {
  1679. iHeight = ((iHeight - GetSystemMetrics(SM_CYEDGE)) / cyItem) * cyItem +
  1680. GetSystemMetrics(SM_CYEDGE);
  1681. }
  1682. //UNDONE: Multi-monitor
  1683. // We need to change the following code if we are to support multi-monitor
  1684. int yTop;
  1685. int nScreenHeight = GetSystemMetrics(SM_CYFULLSCREEN);
  1686. if (rcList.top + iHeight <= nScreenHeight)
  1687. {
  1688. yTop = rcList.top;
  1689. if (!_fBorder)
  1690. yTop -= GetSystemMetrics(SM_CYBORDER);
  1691. }
  1692. else
  1693. {
  1694. yTop = max(rcList.top - iHeight - _cyCombo +
  1695. ((_fBorder) ? GetSystemMetrics(SM_CYBORDER) : 0), 0);
  1696. }
  1697. SetWindowPos(_hwndList, HWND_TOPMOST, rcList.left,
  1698. yTop, rcList.right - rcList.left, iHeight, 0);
  1699. Assert(_plbHost);
  1700. _plbHost->SetScrollInfo(SB_VERT, FALSE);
  1701. if (_cbType == kDropDownList)
  1702. _fFocus = 0;
  1703. // UNDONE:
  1704. // Are we going to support window animation?
  1705. ShowWindow(_hwndList, SW_SHOW);
  1706. // We send a message to the listbox to prepare for tracking
  1707. if (fTrack)
  1708. {
  1709. Assert(_plbHost);
  1710. // initialize type searching
  1711. _plbHost->InitSearch();
  1712. _plbHost->OnCBTracking(LBCBM_PREPARE, LBCBM_PREPARE_SAVECURSOR |
  1713. ((_cbType == kDropDownList) ? LBCBM_PREPARE_SETFOCUS : 0));
  1714. }
  1715. // Since we are about to display the list box change mouse cursor to arrow
  1716. if (!_hcurOld)
  1717. _hcurOld = TxSetCursor2(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)), NULL);
  1718. }
  1719. ////////////////////////// Combo box Message Handlers ////////////////////////////////
  1720. /*
  1721. * CCmbBxWinHost::CbSetItemHeight(BOOL, int)
  1722. *
  1723. * @mfunc
  1724. * Sets the size of the edit or list box.
  1725. *
  1726. *
  1727. * @rdesc
  1728. * LRESULT = successful ? 1 : CB_ERR
  1729. */
  1730. LRESULT CCmbBxWinHost::CbSetItemHeight(BOOL bEdit, int nHeight)
  1731. {
  1732. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::CbSetItemHeight");
  1733. //bug fix #4556
  1734. if (nHeight == 0 || nHeight > 255)
  1735. return CB_ERR;
  1736. // We need to update the height internally
  1737. if (bEdit)
  1738. {
  1739. RECT rc;
  1740. GetClientRect(_hwnd, &rc);
  1741. _dyEdit = nHeight;
  1742. OnSize(0, MAKELONG(rc.right - rc.left, rc.bottom - rc.top));
  1743. }
  1744. else
  1745. {
  1746. RichListBoxWndProc(_hwndList, LB_SETITEMHEIGHT, 0, MAKELPARAM(nHeight, 0));
  1747. }
  1748. return 1;
  1749. }
  1750. /*
  1751. * CCmbBxWinHost::CbGetItemHeight(BOOL)
  1752. *
  1753. * @mfunc
  1754. * Retrieves the size of the edit or list box.
  1755. *
  1756. *
  1757. * @rdesc
  1758. * LRESULT = successful ? 1 : CB_ERR
  1759. */
  1760. LRESULT CCmbBxWinHost::CbGetItemHeight(BOOL bEdit)
  1761. {
  1762. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::CbGetItemHeight");
  1763. // We need to update the height internally
  1764. if (bEdit)
  1765. {
  1766. return _dyEdit;
  1767. }
  1768. else
  1769. {
  1770. return RichListBoxWndProc(_hwndList, LB_GETITEMHEIGHT, 0, 0);
  1771. }
  1772. }
  1773. /*
  1774. * CCmbBxWinHost::CbSetExtendedUI(BOOL)
  1775. *
  1776. * @mfunc
  1777. * Retrieves the size of the edit or list box.
  1778. *
  1779. *
  1780. * @rdesc
  1781. * LRESULT = successful ? CB_OKAY : CB_ERR
  1782. */
  1783. LRESULT CCmbBxWinHost::CbSetExtendedUI(BOOL bExtendedUI)
  1784. {
  1785. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::CbSetExtendedUI");
  1786. // We need to update the height internally
  1787. _fExtendedUI = bExtendedUI ? 1 : 0;
  1788. return CB_OKAY;
  1789. }
  1790. /*
  1791. * CCmbBxWinHost::CbMessageItemHandler(int, WPARAM, LPARAM)
  1792. *
  1793. * @mfunc
  1794. * Handles any and all WM_DRAWITEM and WM_DELETEITEM messages
  1795. *
  1796. *
  1797. * @rdesc
  1798. * LRESULT = whatever the parent window returns
  1799. */
  1800. LRESULT CCmbBxWinHost::CbMessageItemHandler(HDC hdc, int ff, WPARAM wparam, LPARAM lparam)
  1801. {
  1802. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::CbMessageItemHandler");
  1803. // modify the structure info a bit and pass it to the parent window
  1804. DRAWITEMSTRUCT dis;
  1805. BOOL bRelease = FALSE;
  1806. UINT msg = WM_DRAWITEM;
  1807. switch (ff)
  1808. {
  1809. case ITEM_MSG_DRAWLIST:
  1810. ((LPDRAWITEMSTRUCT)lparam)->CtlType = ODT_COMBOBOX;
  1811. ((LPDRAWITEMSTRUCT)lparam)->CtlID = _idCtrl;
  1812. ((LPDRAWITEMSTRUCT)lparam)->hwndItem = _hwnd;
  1813. break;
  1814. case ITEM_MSG_DELETE:
  1815. ((LPDELETEITEMSTRUCT)lparam)->CtlType = ODT_COMBOBOX;
  1816. ((LPDELETEITEMSTRUCT)lparam)->CtlID = _idCtrl;
  1817. ((LPDELETEITEMSTRUCT)lparam)->hwndItem = _hwnd;
  1818. msg = WM_DELETEITEM;
  1819. break;
  1820. case ITEM_MSG_DRAWCOMBO:
  1821. if (!hdc)
  1822. {
  1823. bRelease = TRUE;
  1824. hdc = TxGetDC();
  1825. }
  1826. //Fill the DRAWITEMSTRUCT with the unchanging constants
  1827. dis.CtlType = ODT_COMBOBOX;
  1828. dis.CtlID = _idCtrl;
  1829. // Use -1 if an invalid item number is being used. This is so that the app
  1830. // can detect if it should draw the caret (which indicates the lb has the
  1831. // focus) in an empty listbox
  1832. dis.itemID = _plbHost->GetCursor();
  1833. dis.itemAction = ODA_DRAWENTIRE;
  1834. dis.hwndItem = _hwnd;
  1835. dis.hDC = hdc;
  1836. dis.itemData = (_plbHost->GetCount()) ? (((signed)dis.itemID >= 0) ? _plbHost->GetData(dis.itemID) : 0) : 0;
  1837. dis.itemState = (UINT)((_fFocus && !_fListVisible ? ODS_SELECTED | ODS_FOCUS : 0) |
  1838. ((_fDisabled) ? ODS_DISABLED : 0) | ODS_COMBOBOXEDIT);
  1839. // Calculate the drawing rect
  1840. TxGetClientRect(&dis.rcItem);
  1841. if (_cbType != kSimple)
  1842. {
  1843. if (_fRightAlign)
  1844. dis.rcItem.left = _rcButton.right;
  1845. else
  1846. dis.rcItem.right = _rcButton.left;
  1847. }
  1848. // immulate the system by making the HDC invert text if we have focus
  1849. SetBkMode(hdc, OPAQUE);
  1850. PatBlt(hdc, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right - dis.rcItem.left,
  1851. dis.rcItem.bottom - dis.rcItem.top, PATCOPY);
  1852. if (_fFocus && !_fListVisible)
  1853. {
  1854. // only do the FillRect if we know its not
  1855. // ownerdraw item, otherwise we mess up people up
  1856. // BUT: for Compat's sake we still do this for Win 3.1 guys
  1857. SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  1858. SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  1859. }
  1860. // Don't let ownerdraw dudes draw outside of the combo client
  1861. // bounds.
  1862. InflateRect(&dis.rcItem, -1, -1);
  1863. IntersectClipRect(hdc, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
  1864. dis.rcItem.bottom);
  1865. lparam = (LPARAM)&dis;
  1866. }
  1867. LRESULT lres = SendMessage(_hwndParent, msg, _idCtrl, lparam);
  1868. if (bRelease)
  1869. TxReleaseDC(hdc);
  1870. return lres;
  1871. }
  1872. /////////////////////////// Windows Message Handlers /////////////////////////////////
  1873. /*
  1874. * CCmbBxWinHost::OnCommand(WPARAM, LPARAM)
  1875. *
  1876. * @mfunc
  1877. * Handles notification from listbox and reflects it to the parent of
  1878. * the combo box
  1879. *
  1880. * @comm
  1881. * LRESULT = Handled ? 0 : 1
  1882. *
  1883. *
  1884. */
  1885. HRESULT CCmbBxWinHost::OnCommand(WPARAM wparam, LPARAM lparam)
  1886. {
  1887. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEEXTERN, "CCmbBxWinHost::OnCommand");
  1888. // Filter-out all the messages except Listbox notification messages
  1889. Assert(_hwndParent);
  1890. switch (HIWORD(wparam))
  1891. {
  1892. case LBN_DBLCLK:
  1893. TxNotify(CBN_DBLCLK, NULL);
  1894. break;
  1895. case LBN_ERRSPACE:
  1896. TxNotify((unsigned)CBN_ERRSPACE, NULL);
  1897. break;
  1898. case LBN_SELCHANGE:
  1899. case LBN_SELCANCEL:
  1900. if (!_fListVisible)
  1901. HideListBox(TRUE, TRUE);
  1902. TxNotify(CBN_SELCHANGE, NULL);
  1903. UpdateEditBox();
  1904. break;
  1905. default:
  1906. // not handled so pass down the line
  1907. return 1;
  1908. }
  1909. return 0;
  1910. }
  1911. /*
  1912. * CCmbBxWinHost::OnEnable(WPARAM, LPARAM)
  1913. *
  1914. * @mfunc
  1915. * handles the WM_ENABLE message
  1916. *
  1917. * @rdesc
  1918. * LRESULT = Handled ? 0 : 1
  1919. */
  1920. LRESULT CCmbBxWinHost::OnEnable(WPARAM wparam, LPARAM lparam)
  1921. {
  1922. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnEnable");
  1923. if (_fMousedown)
  1924. {
  1925. _fMousedown = FALSE;
  1926. DrawButton(NULL, FALSE);
  1927. //
  1928. // Pop combo listbox back up, canceling.
  1929. //
  1930. if (_fListVisible)
  1931. HideListBox(TRUE, FALSE);
  1932. }
  1933. return 1;
  1934. }
  1935. /*
  1936. * CCmbBxWinHost::OnChar(WPARAM, LPARAM)
  1937. *
  1938. * @mfunc
  1939. * handles the WM_CHAR message
  1940. *
  1941. * @rdesc
  1942. * LRESULT = Handled ? 0 : 1
  1943. */
  1944. LRESULT CCmbBxWinHost::OnChar(WORD wparam, DWORD lparam)
  1945. {
  1946. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnChar");
  1947. // Check if we should eat the message or not
  1948. if (_cbType == kDropDownList)
  1949. {
  1950. //bug fix #5318 - ignore delete, insert and clear
  1951. if (((WCHAR)wparam) == VK_DELETE || ((WCHAR)wparam) == VK_INSERT ||
  1952. ((WCHAR)wparam) == VK_CLEAR)
  1953. return 0;
  1954. // Sending WM_CHAR is BAD!!! call the message handler directly
  1955. // send the character string message to the listbox if visible
  1956. _plbHost->OnChar(LOWORD(wparam), lparam);
  1957. // If Hi-Ansi need to send a wm_syskeyup message to ITextServices to
  1958. // stabalize the state
  1959. if (0x80 <= wparam && wparam <= 0xFF && !HIWORD(GetKeyState(VK_MENU)))
  1960. {
  1961. LRESULT lres;
  1962. _pserv->TxSendMessage(WM_SYSKEYUP, VK_MENU, 0xC0000000, &lres);
  1963. }
  1964. return 0;
  1965. }
  1966. if (_cbType == kDropDown)
  1967. {
  1968. if (_fListVisible)
  1969. {
  1970. if (!_fCapture)
  1971. {
  1972. // Tell listbox to reset capturing by ending then starting it up
  1973. _plbHost->OnCBTracking(LBCBM_END, 0);
  1974. _plbHost->OnCBTracking(LBCBM_PREPARE, 0);
  1975. }
  1976. // Send the message to the edit control iff it's not a tab
  1977. if (((WCHAR)wparam) != VK_TAB)
  1978. _pserv->TxSendMessage(WM_CHAR, wparam, lparam, NULL);
  1979. if (!_fCapture)
  1980. {
  1981. // capture the cursor
  1982. TxSetCapture(TRUE);
  1983. _fCapture = 1;
  1984. }
  1985. }
  1986. else
  1987. {
  1988. // set the cursel to -1 if it already isn't
  1989. if ((wparam != VK_RETURN) && (_plbHost->GetCursor() != -1))
  1990. RichListBoxWndProc(_hwndList, LB_SETCURSEL, (WPARAM)-1, 0);
  1991. // Send the message to the edit control iff it's not CTRL+i or CTRL+h
  1992. if (((WCHAR)wparam) != VK_TAB)
  1993. _pserv->TxSendMessage(WM_CHAR, wparam, lparam, NULL);
  1994. }
  1995. return 0;
  1996. }
  1997. return 1;
  1998. }
  1999. /*
  2000. * CCmbBxWinHost::OnKeyDown(WPARAM, LPARAM)
  2001. *
  2002. * @mfunc
  2003. * handles the WM_KEYDOWN message
  2004. *
  2005. * @rdesc
  2006. * LRESULT = Handled ? 0 : 1
  2007. */
  2008. LRESULT CCmbBxWinHost::OnKeyDown(WORD wparam, DWORD lparam)
  2009. {
  2010. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnKeyDown");
  2011. if (_fListVisible && (wparam == VK_RETURN || wparam == VK_ESCAPE))
  2012. {
  2013. if (wparam == VK_RETURN)
  2014. _nCursor = _plbHost->GetCursor();
  2015. HideListBox(TRUE, wparam == VK_RETURN);
  2016. return 0;
  2017. }
  2018. // if we are in extended mode and F4 is hit
  2019. // we just ignore it
  2020. if (_fExtendedUI && wparam == VK_F4)
  2021. return 0;
  2022. Assert(_plbHost);
  2023. int fExtUI = _fExtendedUI;
  2024. int nCurSel = _plbHost->GetCursor();
  2025. Assert(nCurSel >= -1);
  2026. // if we are a dropdownlist combo box then just forward the message on to the
  2027. // list box
  2028. if (_cbType == kDropDownList)
  2029. {
  2030. switch (wparam)
  2031. {
  2032. case VK_F4:
  2033. if (_fListVisible)
  2034. break;;
  2035. fExtUI = 1;
  2036. Assert(fExtUI && !_fListVisible);
  2037. // fall through case
  2038. case VK_DOWN:
  2039. if (fExtUI && !_fListVisible)
  2040. {
  2041. ShowListBox(TRUE);
  2042. TxSetCapture(TRUE);
  2043. _fCapture = TRUE;
  2044. return 1;
  2045. }
  2046. // Fall through case
  2047. case VK_UP:
  2048. case VK_NEXT:
  2049. case VK_PRIOR:
  2050. case VK_RETURN:
  2051. case VK_ESCAPE:
  2052. break;
  2053. //bug fix #5318
  2054. /*
  2055. case VK_DELETE:
  2056. case VK_CLEAR:
  2057. case VK_INSERT:
  2058. */
  2059. default:
  2060. // There no reason for us to pass these keys to ITextServices since the control is suppose
  2061. // to be read-only
  2062. return 0;
  2063. }
  2064. }
  2065. else
  2066. {
  2067. switch (wparam)
  2068. {
  2069. case VK_F4:
  2070. if (_fListVisible)
  2071. break;
  2072. fExtUI = 1;
  2073. Assert(fExtUI && !_fListVisible);
  2074. // fall through case
  2075. case VK_DOWN:
  2076. if (fExtUI && !_fListVisible)
  2077. {
  2078. ShowListBox(TRUE);
  2079. TxSetCapture(TRUE);
  2080. _fCapture = TRUE;
  2081. return 0;
  2082. }
  2083. // Fall through case
  2084. case VK_UP:
  2085. case VK_NEXT:
  2086. case VK_PRIOR:
  2087. if (_fListVisible)
  2088. {
  2089. if (_fCapture)
  2090. {
  2091. // release our capture flag and tell lb to start tracking
  2092. _fCapture = 0;
  2093. _plbHost->OnCBTracking(LBCBM_START, _fMousedown);
  2094. }
  2095. // selecting the top index and then sending the keydown to the
  2096. // listbox causes 2 moves so handle this ourselves
  2097. if (nCurSel == -1)
  2098. {
  2099. RichListBoxWndProc(_hwndList, LB_SETCURSEL, _plbHost->GetTopIndex(), 0);
  2100. UpdateEditBox();
  2101. UpdateCbWindow();
  2102. return 0;
  2103. }
  2104. }
  2105. else
  2106. {
  2107. // if Listbox isn't visible and the listbox cursor is -1
  2108. // then we should try to select the correct item in the list
  2109. // box
  2110. if (nCurSel == -1)
  2111. {
  2112. UpdateListBox(TRUE);
  2113. if (_plbHost->GetCursor() >= 0)
  2114. {
  2115. HiliteEdit(TRUE);
  2116. return 0;
  2117. } else if (!_plbHost->GetCount())
  2118. {
  2119. return 0;
  2120. }
  2121. }
  2122. }
  2123. break;
  2124. case VK_RETURN:
  2125. case VK_ESCAPE:
  2126. break;
  2127. default:
  2128. // return zero to say we didn't handle this
  2129. return 1;
  2130. }
  2131. }
  2132. // pass message to list box
  2133. _plbHost->OnKeyDown(wparam, lparam, 0);
  2134. UpdateCbWindow();
  2135. return 0;
  2136. }
  2137. /*
  2138. * CCmbBxWinHost::OnSyskeyDown(WORD, DWORD)
  2139. *
  2140. * @mfunc
  2141. * handles the WM_SYSKEYDOWN message
  2142. *
  2143. * @rdesc
  2144. * LRESULT = Handled ? 0 : 1
  2145. */
  2146. LRESULT CCmbBxWinHost::OnSyskeyDown(WORD wparam, DWORD lparam)
  2147. {
  2148. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnSyskeyDown");
  2149. if (lparam & 0x20000000L) /* Check if the alt key is down */
  2150. {
  2151. // Handle Combobox support. We want alt up or down arrow to behave
  2152. // like F4 key which completes the combo box selection
  2153. if (lparam & 0x1000000)
  2154. {
  2155. // We just want to ignore keys on the number pad...
  2156. // This is an extended key such as the arrow keys not on the
  2157. // numeric keypad so just drop the combobox.
  2158. if (wparam != VK_DOWN && wparam != VK_UP)
  2159. return 1;
  2160. }
  2161. else if (GetKeyState(VK_NUMLOCK) & 0x1)
  2162. {
  2163. //If numlock down, just send all system keys to dwp
  2164. return 1;
  2165. }
  2166. else
  2167. {
  2168. if (wparam != VK_DOWN && wparam != VK_UP)
  2169. return 1;
  2170. }
  2171. // If the listbox isn't visible, just show it
  2172. if (!_fListVisible)
  2173. {
  2174. ShowListBox(TRUE);
  2175. TxSetCapture(TRUE);
  2176. _fCapture = TRUE;
  2177. }
  2178. else //Ok, the listbox is visible. So hide the listbox window.
  2179. HideListBox(TRUE, TRUE);
  2180. return 0;
  2181. }
  2182. return 1;
  2183. }
  2184. /*
  2185. * CCmbBxWinHost::OnCaptureChanged(WPARAM, LPARAM)
  2186. *
  2187. * @mfunc
  2188. * handles the WM_CAPTURECHANGED message
  2189. *
  2190. * @rdesc
  2191. * LRESULT = Handled ? 0 : 1
  2192. */
  2193. LRESULT CCmbBxWinHost::OnCaptureChanged(WPARAM wparam, LPARAM lparam)
  2194. {
  2195. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnCaptureChanged");
  2196. if (_fCapture)
  2197. {
  2198. // Pop combo listbox back up, canceling.
  2199. if (_fListVisible)
  2200. HideListBox(TRUE, FALSE);
  2201. else
  2202. {
  2203. _fCapture = FALSE;
  2204. _fMousedown = FALSE;
  2205. DrawButton(NULL, FALSE);
  2206. }
  2207. return 0;
  2208. }
  2209. return 1;
  2210. }
  2211. /*
  2212. * CCmbBxWinHost::OnMouseMove(WPARAM, LPARAM)
  2213. *
  2214. * @mfunc
  2215. * handles the WM_MOUSEMOVE message
  2216. *
  2217. * @rdesc
  2218. * LRESULT = Handled ? 0 : 1
  2219. */
  2220. LRESULT CCmbBxWinHost::OnMouseMove(WPARAM wparam, LPARAM lparam)
  2221. {
  2222. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnMouseMove");
  2223. // We do the following if we have mouse captured or if the listbox is visible
  2224. if (_cbType != kSimple && _fCapture)
  2225. {
  2226. // get the point coordinates of mouse
  2227. POINT pt;
  2228. POINTSTOPOINT(pt, lparam);
  2229. if (_fListVisible)
  2230. {
  2231. // if the listbox is visible visible check if the cursor went over
  2232. // list box
  2233. RECT rc;
  2234. POINT ptScreen = pt;
  2235. GetWindowRect(_hwndList, &rc);
  2236. TxClientToScreen(&ptScreen);
  2237. if (PtInRect(&rc, ptScreen))
  2238. {
  2239. // Release the capture state of the mouse
  2240. if (_fCapture)
  2241. {
  2242. _fCapture = FALSE;
  2243. TxSetCapture(FALSE);
  2244. }
  2245. // notify the listbox to start tracking
  2246. Assert(_plbHost);
  2247. ::PostMessage(_hwndList, LBCB_TRACKING, LBCBM_START, _fMousedown);
  2248. _fMousedown = 0;
  2249. }
  2250. }
  2251. DrawButton(NULL, _fMousedown ? PtInRect(&_rcButton, pt) : FALSE);
  2252. return FALSE;
  2253. }
  2254. #ifdef DEBUG
  2255. if (_cbType != kSimple)
  2256. Assert(!_fListVisible);
  2257. #endif
  2258. return TRUE;
  2259. }
  2260. /*
  2261. * CCmbBxWinHost::OnLButtonUp(WPARAM, LPARAM)
  2262. *
  2263. * @mfunc
  2264. * handles the WM_LBUTTONUP message
  2265. *
  2266. * @rdesc
  2267. * LRESULT = Handled ? 0 : 1
  2268. */
  2269. LRESULT CCmbBxWinHost::OnLButtonUp(WPARAM wparam, LPARAM lparam)
  2270. {
  2271. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnLButtonUp");
  2272. if (_fMousedown)
  2273. {
  2274. _fMousedown = FALSE;
  2275. if (_cbType != kSimple)
  2276. {
  2277. // If an item in the listbox matches the text in the edit
  2278. // control, scroll it to the top of the listbox. Select the
  2279. // item only if the mouse button isn't down otherwise we
  2280. // will select the item when the mouse button goes up.
  2281. if (_cbType == kDropDown)
  2282. {
  2283. UpdateListBox(TRUE);
  2284. AutoUpdateEdit(-1);
  2285. }
  2286. // if we recieved a mouse up and the listbox is still visible then user
  2287. // hasn't selected any items from the listbox so don't release the capture yet
  2288. if (_fCapture && !_fListVisible)
  2289. {
  2290. _fCapture = FALSE;
  2291. TxSetCapture(FALSE);
  2292. }
  2293. DrawButton(NULL, FALSE);
  2294. return FALSE;
  2295. }
  2296. }
  2297. return TRUE;
  2298. }
  2299. /*
  2300. * CCmbBxWinHost::OnLButtonDown(WPARAM, LPARAM)
  2301. *
  2302. * @mfunc
  2303. * Draws the client edges of the combo box
  2304. *
  2305. * @rdesc
  2306. * LRESULT = Handled ? 0 : 1
  2307. */
  2308. LRESULT CCmbBxWinHost::OnLButtonDown(WPARAM wparam, LPARAM lparam)
  2309. {
  2310. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnLButtonDown");
  2311. // check if we should dropdown the list box
  2312. POINT pt;
  2313. POINTSTOPOINT(pt, lparam);
  2314. // if we don't have focus then set the focus first
  2315. if (!_fFocus)
  2316. TxSetFocus();
  2317. _fFocus = 1;
  2318. // listbox is down so pop it back up
  2319. if (_fListVisible)
  2320. {
  2321. return !HideListBox(TRUE, FALSE);
  2322. }
  2323. else if (_cbType == kDropDownList || (_cbType == kDropDown && PtInRect(&_rcButton, pt)))
  2324. {
  2325. // need to show listbox
  2326. ShowListBox(TRUE);
  2327. _fMousedown = TRUE;
  2328. TxSetCapture(TRUE);
  2329. _fCapture = TRUE;
  2330. return 0;
  2331. }
  2332. return 1;
  2333. }
  2334. /*
  2335. * CCmbBxWinHost::OnMouseWheel(WPARAM, LPARAM)
  2336. *
  2337. * @mfunc
  2338. * Draws the client edges of the combo box
  2339. *
  2340. * @rdesc
  2341. * LRESULT = Handled ? 0 : 1
  2342. */
  2343. LRESULT CCmbBxWinHost::OnMouseWheel(WPARAM wparam, LPARAM lparam)
  2344. {
  2345. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnMouseWheel");
  2346. // Handle only scrolling.
  2347. if (wparam & (MK_CONTROL | MK_SHIFT))
  2348. return 1;
  2349. // If the listbox is visible, send it the message to scroll.
  2350. // if the listbox is
  2351. if (_fListVisible)
  2352. {
  2353. _plbHost->OnMouseWheel(wparam, lparam);
  2354. return 0;
  2355. }
  2356. // If we're in extended UI mode or the edit control isn't yet created,
  2357. // bail.
  2358. if (_fExtendedUI)
  2359. return 0;
  2360. // Emulate arrow up/down messages to the edit control.
  2361. int i = abs(((short)HIWORD(wparam))/WHEEL_DELTA);
  2362. wparam = ((short)HIWORD(wparam) > 0) ? VK_UP : VK_DOWN;
  2363. while (i-- > 0)
  2364. OnKeyDown(wparam, lparam);
  2365. return 0;
  2366. }
  2367. /*
  2368. * CCmbBxWinHost::OnSetCursor(WPARAM, LPARAM)
  2369. *
  2370. * @mfunc
  2371. * Changes the cursor depending on where the cursor is
  2372. *
  2373. * @rdesc
  2374. * BOOL = SUCCESSFUL ? TRUE : FALSE
  2375. */
  2376. LRESULT CCmbBxWinHost::OnSetCursor(WPARAM wparam, LPARAM lparam)
  2377. {
  2378. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnSetCursor");
  2379. POINT pt;
  2380. GetCursorPos(&pt);
  2381. ::ScreenToClient(_hwnd, &pt);
  2382. if ((_cbType == kDropDownList) ||
  2383. (_cbType == kDropDown && ((_fRightAlign) ? _rcButton.right >= pt.x : _rcButton.left <= pt.x)))
  2384. {
  2385. TxSetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)), NULL);
  2386. }
  2387. else
  2388. _pserv->OnTxSetCursor(DVASPECT_CONTENT, -1, NULL, NULL, NULL, NULL,
  2389. NULL, pt.x, pt.y);
  2390. return TRUE;
  2391. }
  2392. /*
  2393. * CCmbBxWinHost::OnSetFocus(WPARAM, LPARAM)
  2394. *
  2395. * @mfunc
  2396. * Draws the button and sends the WM_DRAWITEM message for owner draw
  2397. *
  2398. * @rdesc
  2399. * BOOL = SUCCESSFUL ? TRUE : FALSE
  2400. */
  2401. LRESULT CCmbBxWinHost::OnSetFocus(WPARAM wparam, LPARAM lparam)
  2402. {
  2403. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnSetFocus");
  2404. _fFocus = TRUE;
  2405. // Hide the list box
  2406. if (_fListVisible)
  2407. HideListBox(TRUE, _bSelOk);
  2408. else if (_fOwnerDraw && _cbType == kDropDownList)
  2409. CbMessageItemHandler(NULL, ITEM_MSG_DRAWCOMBO, 0, 0);
  2410. else
  2411. DrawEditFocus(NULL); // Draw the focus
  2412. // Notify the parent we have the focus iff this function
  2413. // wasn't called in response to LBCB_TRACKING
  2414. if (_fLBCBMessage)
  2415. _fLBCBMessage = 0;
  2416. else
  2417. TxNotify(CBN_SETFOCUS, NULL);
  2418. // we return 1 if we are owner draw or if
  2419. // we are a kDropDownList, this is because
  2420. // we have to prevent the message from being passed
  2421. // to _pserv
  2422. return (_cbType == kDropDownList);
  2423. }
  2424. /*
  2425. * CCmbBxWinHost::OnKillFocus(WPARAM, LPARAM)
  2426. *
  2427. * @mfunc
  2428. * Draws the button and sends the WM_DRAWITEM message for owner draw
  2429. *
  2430. * @rdesc
  2431. * BOOL = SUCCESSFUL ? TRUE : FALSE
  2432. */
  2433. LRESULT CCmbBxWinHost::OnKillFocus(WPARAM wparam, LPARAM lparam)
  2434. {
  2435. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnKillFocus");
  2436. // if we never had focus or if not list window just get out
  2437. if (_hwndList == NULL)
  2438. return 0;
  2439. if ((HWND)wparam != _hwndList)
  2440. {
  2441. // We only give up the focus if the new window getting the focus
  2442. // doesn't belong to the combo box.
  2443. // The combo box is losing the focus. Send buttonup clicks so that
  2444. // things release the mouse capture if they have it... If the
  2445. // pwndListBox is null, don't do anything. This occurs if the combo box
  2446. // is destroyed while it has the focus.
  2447. OnLButtonUp(0L, 0xFFFFFFFFL);
  2448. if (_fListVisible)
  2449. HideListBox(TRUE, FALSE);
  2450. }
  2451. //bug fix #4013
  2452. if (!_fFocus)
  2453. return 0;
  2454. _fFocus = FALSE;
  2455. // Remove Focus Rect
  2456. if (_cbType != kDropDownList)
  2457. {
  2458. HiliteEdit(FALSE);
  2459. // Hide any selections
  2460. _pserv->TxSendMessage(EM_HIDESELECTION, 1, 0, NULL);
  2461. }
  2462. else if (_fOwnerDraw)
  2463. CbMessageItemHandler(NULL, ITEM_MSG_DRAWCOMBO, 0, 0);
  2464. else
  2465. DrawEditFocus(NULL);
  2466. TxNotify(CBN_KILLFOCUS, NULL);
  2467. if (_cbType == kDropDownList)
  2468. return 1;
  2469. return 0;
  2470. }
  2471. /*
  2472. * CCmbBxWinHost::OnSize(WPARAM, LPARAM)
  2473. *
  2474. * @mfunc
  2475. * Draws the button and sends the WM_DRAWITEM message for owner draw
  2476. *
  2477. * @rdesc
  2478. * BOOL = Processed ? FALSE : TRUE
  2479. */
  2480. LRESULT CCmbBxWinHost::OnSize(WPARAM wparam, LPARAM lparam)
  2481. {
  2482. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnCbSize");
  2483. // only deal with this message if we didn't generate the message and
  2484. // the new size is a valid one
  2485. if (!_fResizing && _hwndList)
  2486. {
  2487. _fResizing = 1;
  2488. RECT rc;
  2489. GetWindowRect(_hwnd, &rc);
  2490. rc.right -= rc.left;
  2491. rc.bottom -= rc.top;
  2492. rc.left = rc.top = 0;
  2493. CbCalcControlRects(&rc, FALSE);
  2494. // Need to resize the list box
  2495. if (_cbType != kSimple)
  2496. SetDropSize(&_rcList);
  2497. _fResizing = 0;
  2498. }
  2499. _pserv->TxSendMessage(WM_SIZE, wparam, lparam, NULL);
  2500. CTxtWinHost::OnSize(_hwnd, wparam, (int)LOWORD(lparam), (int)HIWORD(lparam));
  2501. return FALSE;
  2502. }
  2503. /*
  2504. * CCmbBxWinHost::OnGetDlgCode(WPARAM, LPARAM)
  2505. *
  2506. * @mfunc
  2507. * Draws the button and sends the WM_DRAWITEM message for owner draw
  2508. *
  2509. * @rdesc
  2510. * BOOL = SUCCESSFUL ? TRUE : FALSE
  2511. */
  2512. LRESULT CCmbBxWinHost::OnGetDlgCode(WPARAM wparam, LPARAM lparam)
  2513. {
  2514. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnGetDlgCode");
  2515. // call the parents GetDlgCode first
  2516. LRESULT code = DLGC_WANTCHARS | DLGC_WANTARROWS;
  2517. if (_cbType != kDropDownList)
  2518. code |= DLGC_HASSETSEL;
  2519. // If the listbox is dropped and the ENTER key is pressed,
  2520. // we want this message so we can close up the listbox
  2521. if ((lparam != 0) &&
  2522. (((LPMSG)lparam)->message == WM_KEYDOWN) &&
  2523. _fListVisible &&
  2524. ((wparam == VK_RETURN) || (wparam == VK_ESCAPE)))
  2525. {
  2526. code |= DLGC_WANTMESSAGE;
  2527. }
  2528. _fInDialogBox = TRUE;
  2529. return((LRESULT)code);
  2530. }
  2531. /*
  2532. * CCmbBxWinHost::OnSetTextEx(WPARAM, LPARAM)
  2533. *
  2534. * @mfunc
  2535. * Draws the button and sends the WM_DRAWITEM message for owner draw
  2536. *
  2537. * @rdesc
  2538. * BOOL = SUCCESSFUL ? TRUE : FALSE
  2539. */
  2540. LRESULT CCmbBxWinHost::OnSetTextEx(WPARAM wparam, LPARAM lparam)
  2541. {
  2542. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnSetTextEx");
  2543. WCHAR* psz = (WCHAR*)lparam;
  2544. while (*psz != L'\r')
  2545. psz++;
  2546. *psz = L'\0';
  2547. //Send message to host
  2548. _pserv->TxSendMessage(EM_SETTEXTEX, wparam, lparam, NULL);
  2549. //Set the string back to old and send message to listbox
  2550. *psz = L'\r';
  2551. psz++;
  2552. return ::SendMessage(_hwndList, EM_SETTEXTEX, wparam, (LPARAM)psz);
  2553. }
  2554. /*
  2555. * CCmbBxWinHost::OnPaint(WPARAM, LPARAM)
  2556. *
  2557. * @mfunc
  2558. * Draws the button and sends the WM_DRAWITEM message for owner draw
  2559. *
  2560. * @rdesc
  2561. * BOOL = processed ? 0 : 1
  2562. */
  2563. LRESULT CCmbBxWinHost::OnPaint(WPARAM wparam, LPARAM lparam)
  2564. {
  2565. TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "CCmbBxWinHost::OnPaint");
  2566. PAINTSTRUCT ps;
  2567. HPALETTE hpalOld = NULL;
  2568. HDC hdc = BeginPaint(_hwnd, &ps);
  2569. RECT rcClient;
  2570. // Since we are using the CS_PARENTDC style, make sure
  2571. // the clip region is limited to our client window.
  2572. GetClientRect(_hwnd, &rcClient);
  2573. // pass message on to the parentwindow if owner draw
  2574. if (_cbType != kDropDownList || !_fOwnerDraw)
  2575. {
  2576. RECT rcFocus = rcClient;
  2577. // Set up the palette for drawing our data
  2578. if (_hpal)
  2579. {
  2580. hpalOld = SelectPalette(hdc, _hpal, TRUE);
  2581. RealizePalette(hdc);
  2582. }
  2583. SaveDC(hdc);
  2584. IntersectClipRect(hdc, rcClient.left, rcClient.top, rcClient.right,
  2585. rcClient.bottom);
  2586. // Fill-in the gap between the button and richedit control
  2587. RECT rcGap;
  2588. if (_fRightAlign)
  2589. {
  2590. rcGap.left = _rcButton.right;
  2591. rcGap.right = rcGap.left + _xInset + 1;
  2592. }
  2593. else
  2594. {
  2595. rcGap.right = _rcButton.left;
  2596. rcGap.left = rcGap.right - _xInset - 1;
  2597. }
  2598. rcGap.top = rcClient.top;
  2599. rcGap.bottom = rcClient.bottom;
  2600. FillRect(hdc, &rcGap, (HBRUSH)(DWORD_PTR)(((_fDisabled) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
  2601. if (_fFocus && _cbType == kDropDownList)
  2602. {
  2603. //First if there is a focus rect then remove the focus rect
  2604. // shrink the focus rect by the inset
  2605. rcFocus.top += _yInset;
  2606. rcFocus.bottom -= _yInset;
  2607. if (_fRightAlign)
  2608. rcFocus.left = _rcButton.right;
  2609. else
  2610. rcFocus.right = _rcButton.left;
  2611. rcFocus.left += _xInset;
  2612. rcFocus.right -= _xInset;
  2613. // We need to erase the focus rect if we haven't already
  2614. // erased the background
  2615. DrawFocusRect(hdc, &rcFocus);
  2616. }
  2617. _pserv->TxDraw(
  2618. DVASPECT_CONTENT, // Draw Aspect
  2619. -1, // Lindex
  2620. NULL, // Info for drawing optimazation
  2621. NULL, // target device information
  2622. hdc, // Draw device HDC
  2623. NULL, // Target device HDC
  2624. (const RECTL *) &rcClient,// Bounding client rectangle
  2625. NULL, // Clipping rectangle for metafiles
  2626. &ps.rcPaint, // Update rectangle
  2627. NULL, // Call back function
  2628. NULL, // Call back parameter
  2629. TXTVIEW_ACTIVE); // What view - the active one!
  2630. // Restore palette if there is one
  2631. if(hpalOld)
  2632. SelectPalette(hdc, hpalOld, TRUE);
  2633. RestoreDC(hdc, -1);
  2634. if(TxGetEffects() == TXTEFFECT_SUNKEN && dwMajorVersion < VERS4)
  2635. DrawSunkenBorder(_hwnd, hdc);
  2636. //Redraw the focus rect, don't have to recalc since we already did above
  2637. if (_fFocus && _cbType == kDropDownList)
  2638. DrawFocusRect(hdc, &rcFocus);
  2639. DrawButton(hdc, _fMousedown);
  2640. }
  2641. else
  2642. {
  2643. // We have to draw the button first because CbMessageItemHandler
  2644. // will perform a IntersectClipRect which will prevent us from
  2645. // drawing the button later
  2646. DrawButton(hdc, _fMousedown);
  2647. CbMessageItemHandler(hdc, ITEM_MSG_DRAWCOMBO, 0, 0);
  2648. }
  2649. EndPaint(_hwnd, &ps);
  2650. return FALSE;
  2651. }