Source code of Windows XP (NT5)
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.

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