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

3828 lines
103 KiB

  1. #include "ctlspriv.h"
  2. #pragma hdrstop
  3. #include "usrctl32.h"
  4. #include "edit.h"
  5. //---------------------------------------------------------------------------//
  6. //
  7. // Language pack notes:
  8. // With the language pack loaded all positional processing is based on
  9. // ped->xOffset rather than ped->ichScreenStart. The non-lpk optimisation of
  10. // maintaining ped->ichScreenStart doesn't work because of the
  11. // glyph reordering features of complex scripts.
  12. //
  13. //---------------------------------------------------------------------------//
  14. //
  15. // Forwards
  16. //
  17. VOID EditSL_ChangeSelection(PED, HDC, ICH, ICH);
  18. VOID EditSL_DrawLine(PED, HDC, int, int, ICH, int, BOOL);
  19. BOOL EditSL_Undo(PED);
  20. //---------------------------------------------------------------------------//
  21. //
  22. typedef BOOL (*FnGetTextExtentPoint)(HDC, PVOID, int, LPSIZE);
  23. //---------------------------------------------------------------------------//
  24. INT EditSL_CalcStringWidth(PED ped, HDC hdc, ICH ich, ICH cch)
  25. {
  26. if (cch == 0)
  27. {
  28. return 0;
  29. }
  30. if (ped->charPasswordChar)
  31. {
  32. return cch * ped->cPasswordCharWidth;
  33. }
  34. else
  35. {
  36. SIZE size;
  37. if (ped->fNonPropFont && !ped->fDBCS)
  38. {
  39. size.cx = cch * ped->aveCharWidth;
  40. }
  41. else
  42. {
  43. PSTR pText = Edit_Lock(ped);
  44. if (ped->fAnsi)
  45. {
  46. GetTextExtentPointA(hdc, (LPSTR)(pText + ich), cch, &size);
  47. }
  48. else
  49. {
  50. GetTextExtentPointW(hdc, (LPWSTR)pText + ich, cch, &size);
  51. }
  52. Edit_Unlock(ped);
  53. }
  54. return size.cx - ped->charOverhang;
  55. }
  56. }
  57. //---------------------------------------------------------------------------//
  58. //
  59. // EditSL_CalcXOffsetLeft
  60. //
  61. // Calculates the starting offset for left-aligned strings.
  62. //
  63. INT EditSL_CalcXOffsetLeft(PED ped, HDC hdc, ICH ich)
  64. {
  65. int cch = (int)(ich - ped->ichScreenStart);
  66. if (cch <= 0)
  67. {
  68. return 0;
  69. }
  70. return EditSL_CalcStringWidth(ped, hdc, ped->ichScreenStart, cch);
  71. }
  72. //---------------------------------------------------------------------------//
  73. //
  74. // EditSL_CalcXOffsetSpecial
  75. //
  76. // Calculates the horizontal offset (indent) required for right or center
  77. // justified lines.
  78. //
  79. INT EditSL_CalcXOffsetSpecial(PED ped, HDC hdc, ICH ich)
  80. {
  81. PSTR pText;
  82. ICH cch, ichStart = ped->ichScreenStart;
  83. int cx;
  84. //
  85. // Calc the number of characters from start to right end.
  86. //
  87. pText = Edit_Lock(ped);
  88. cch = Edit_CchInWidth(ped, hdc, (LPSTR)(pText + ichStart * ped->cbChar),
  89. ped->cch - ichStart, ped->rcFmt.right - ped->rcFmt.left, TRUE);
  90. Edit_Unlock(ped);
  91. //
  92. // Once the last character of the string has been scrolled out of
  93. // the view, use normal offset calculation.
  94. //
  95. if (ped->ichScreenStart + cch < ped->cch)
  96. {
  97. return EditSL_CalcXOffsetLeft(ped, hdc, ich);
  98. }
  99. cx = ped->rcFmt.right - ped->rcFmt.left - EditSL_CalcStringWidth(ped,
  100. hdc, ichStart, cch);
  101. if (ped->format == ES_CENTER)
  102. {
  103. cx = max(0, cx / 2);
  104. }
  105. else if (ped->format == ES_RIGHT)
  106. {
  107. //
  108. // Subtract 1 so that the 1 pixel wide cursor will be in the visible
  109. // region on the very right side of the screen, mle does this.
  110. //
  111. cx = max(0, cx - 1);
  112. }
  113. return cx + EditSL_CalcStringWidth(ped, hdc, ichStart, ich - ichStart);
  114. }
  115. //---------------------------------------------------------------------------//
  116. //
  117. // EditSL_SetCaretPosition AorW
  118. //
  119. // If the window has the focus, find where the caret belongs and move
  120. // it there.
  121. //
  122. VOID EditSL_SetCaretPosition(PED ped, HDC hdc)
  123. {
  124. int xPosition;
  125. //
  126. // We will only position the caret if we have the focus since we don't want
  127. // to move the caret while another window could own it.
  128. //
  129. if (!ped->fFocus)
  130. {
  131. return;
  132. }
  133. if (ped->fCaretHidden)
  134. {
  135. SetCaretPos(-20000, -20000);
  136. return;
  137. }
  138. xPosition = EditSL_IchToLeftXPos(ped, hdc, ped->ichCaret);
  139. //
  140. // Don't let caret go out of bounds of edit control if there is too much
  141. // text.
  142. //
  143. if (ped->pLpkEditCallout)
  144. {
  145. xPosition += ped->iCaretOffset;
  146. xPosition = max(xPosition , 0);
  147. xPosition = min(xPosition, ped->rcFmt.right - 1 -
  148. ((ped->cxSysCharWidth > ped->aveCharWidth) ? 1 : 2));
  149. }
  150. else
  151. {
  152. xPosition = min(xPosition, ped->rcFmt.right -
  153. ((ped->cxSysCharWidth > ped->aveCharWidth) ? 1 : 2));
  154. }
  155. SetCaretPos(xPosition, ped->rcFmt.top);
  156. //
  157. // FE_IME EditSL_SetCaretPosition - ECImmSetCompostionWindow( CFS_POINT )
  158. //
  159. if (g_fIMMEnabled && ImmIsIME(GetKeyboardLayout(0)))
  160. {
  161. Edit_ImmSetCompositionWindow(ped, xPosition, ped->rcFmt.top);
  162. }
  163. }
  164. //---------------------------------------------------------------------------//
  165. //
  166. // EditSL_IchToLeftXPos AorW
  167. //
  168. // Given a character index, find its (left side) x coordinate within
  169. // the ped->rcFmt rectangle assuming the character ped->ichScreenStart is at
  170. // coordinates (ped->rcFmt.top, ped->rcFmt.left). A negative value is
  171. // return ed if the character ich is to the left of ped->ichScreenStart. WARNING:
  172. // ASSUMES AT MOST 1000 characters will be VISIBLE at one time on the screen.
  173. // There may be 64K total characters in the editcontrol, but we can only
  174. // display 1000 without scrolling. This shouldn't be a problem obviously.
  175. //
  176. INT EditSL_IchToLeftXPos(PED ped, HDC hdc, ICH ich)
  177. {
  178. int textExtent;
  179. PSTR pText;
  180. SIZE size;
  181. int cchDiff;
  182. if (ped->pLpkEditCallout)
  183. {
  184. pText = Edit_Lock(ped);
  185. textExtent = ped->pLpkEditCallout->EditIchToXY((PED0)ped, hdc, pText, ped->cch, ich);
  186. Edit_Unlock(ped);
  187. return textExtent;
  188. }
  189. //
  190. // Check if we are adding lots and lots of chars. A paste for example could
  191. // cause this and GetTextExtents could overflow on this.
  192. //
  193. cchDiff = (int)ich - (int)ped->ichScreenStart;
  194. if (cchDiff > 1000)
  195. {
  196. return (30000);
  197. }
  198. else if (cchDiff < -1000)
  199. {
  200. return (-30000);
  201. }
  202. if (ped->format != ES_LEFT)
  203. {
  204. return (ped->rcFmt.left + EditSL_CalcXOffsetSpecial(ped, hdc, ich));
  205. }
  206. //
  207. // Caret position /w DBCS text, we can not optimize...
  208. //
  209. if (ped->fNonPropFont && !ped->fDBCS)
  210. {
  211. return (ped->rcFmt.left + cchDiff*ped->aveCharWidth);
  212. }
  213. //
  214. // Check if password hidden chars are being used.
  215. //
  216. if (ped->charPasswordChar)
  217. {
  218. return ( ped->rcFmt.left + cchDiff*ped->cPasswordCharWidth);
  219. }
  220. pText = Edit_Lock(ped);
  221. if (ped->fAnsi)
  222. {
  223. if (cchDiff >= 0)
  224. {
  225. GetTextExtentPointA(hdc, (LPSTR)(pText + ped->ichScreenStart),
  226. cchDiff, &size);
  227. textExtent = size.cx;
  228. //
  229. // In case of signed/unsigned overflow since the text extent may be
  230. // greater than maxint. This happens with long single line edit
  231. // controls. The rect we edit text in will never be greater than 30000
  232. // pixels so we are ok if we just ignore them.
  233. //
  234. if (textExtent < 0 || textExtent > 31000)
  235. {
  236. textExtent = 30000;
  237. }
  238. }
  239. else
  240. {
  241. GetTextExtentPointA(hdc,(LPSTR)(pText + ich), -cchDiff, &size);
  242. textExtent = (-1) * size.cx;
  243. }
  244. }
  245. else
  246. {
  247. if (cchDiff >= 0)
  248. {
  249. GetTextExtentPointW(hdc, (LPWSTR)(pText + ped->ichScreenStart*sizeof(WCHAR)),
  250. cchDiff, &size);
  251. textExtent = size.cx;
  252. //
  253. // In case of signed/unsigned overflow since the text extent may be
  254. // greater than maxint. This happens with long single line edit
  255. // controls. The rect we edit text in will never be greater than 30000
  256. // pixels so we are ok if we just ignore them.
  257. //
  258. if (textExtent < 0 || textExtent > 31000)
  259. {
  260. textExtent = 30000;
  261. }
  262. }
  263. else
  264. {
  265. GetTextExtentPointW(hdc,(LPWSTR)(pText + ich*sizeof(WCHAR)), -cchDiff, &size);
  266. textExtent = (-1) * size.cx;
  267. }
  268. }
  269. Edit_Unlock(ped);
  270. return (ped->rcFmt.left + textExtent - (textExtent ? ped->charOverhang : 0));
  271. }
  272. //---------------------------------------------------------------------------//
  273. //
  274. // EditSL_SetSelection AorW
  275. //
  276. // Sets the PED to have the new selection specified.
  277. //
  278. VOID EditSL_SetSelection(PED ped, ICH ichSelStart, ICH ichSelEnd)
  279. {
  280. HDC hdc = Edit_GetDC(ped, FALSE);
  281. if (ichSelStart == 0xFFFFFFFF)
  282. {
  283. //
  284. // Set no selection if we specify -1
  285. //
  286. ichSelStart = ichSelEnd = ped->ichCaret;
  287. }
  288. //
  289. // Bounds ichSelStart, ichSelEnd are checked in EditSL_ChangeSelection...
  290. //
  291. EditSL_ChangeSelection(ped, hdc, ichSelStart, ichSelEnd);
  292. //
  293. // Put the caret at the end of the selected text
  294. //
  295. ped->ichCaret = ped->ichMaxSel;
  296. EditSL_SetCaretPosition(ped, hdc);
  297. //
  298. // We may need to scroll the text to bring the caret into view...
  299. //
  300. EditSL_ScrollText(ped, hdc);
  301. Edit_ReleaseDC(ped, hdc, FALSE);
  302. }
  303. //---------------------------------------------------------------------------//
  304. VOID EditSL_GetClipRect(PED ped, HDC hdc, ICH ichStart, int iCount, LPRECT lpClipRect)
  305. {
  306. int iStCount;
  307. PSTR pText;
  308. if (ped->pLpkEditCallout)
  309. {
  310. TraceMsg(TF_STANDARD, "UxEdit: EditSL_GetClipRect - Error - Invalid call with language pack loaded");
  311. memset(lpClipRect, 0, SIZEOF(RECT));
  312. return;
  313. }
  314. CopyRect(lpClipRect, &ped->rcFmt);
  315. pText = Edit_Lock(ped);
  316. //
  317. // Calculates the starting pos for this piece of text
  318. //
  319. if ((iStCount = (int)(ichStart - ped->ichScreenStart)) > 0)
  320. {
  321. if (ped->format == ES_LEFT)
  322. {
  323. lpClipRect->left += EditSL_CalcXOffsetLeft(ped, hdc, ichStart);
  324. }
  325. }
  326. else
  327. {
  328. //
  329. // Reset the values to visible portions
  330. //
  331. iCount -= (ped->ichScreenStart - ichStart);
  332. ichStart = ped->ichScreenStart;
  333. }
  334. if (ped->format != ES_LEFT)
  335. {
  336. lpClipRect->left += EditSL_CalcXOffsetSpecial(ped, hdc, ichStart);
  337. }
  338. if (iCount < 0)
  339. {
  340. //
  341. // This is not in the visible area of the edit control, so return
  342. // an empty rect.
  343. //
  344. SetRectEmpty(lpClipRect);
  345. Edit_Unlock(ped);
  346. return;
  347. }
  348. if (ped->charPasswordChar)
  349. {
  350. lpClipRect->right = lpClipRect->left + ped->cPasswordCharWidth * iCount;
  351. }
  352. else
  353. {
  354. SIZE size;
  355. if ( ped->fAnsi)
  356. {
  357. GetTextExtentPointA(hdc, pText + ichStart, iCount, &size);
  358. }
  359. else
  360. {
  361. GetTextExtentPointW(hdc, ((LPWSTR)pText) + ichStart, iCount, &size);
  362. }
  363. lpClipRect->right = lpClipRect->left + size.cx - ped->charOverhang;
  364. }
  365. Edit_Unlock(ped);
  366. }
  367. //---------------------------------------------------------------------------//
  368. //
  369. // EditSL_LpkEditDrawText
  370. //
  371. // lpk!EditDrawText always sets the BkMode for single line edits to OPAQUE.
  372. // This causes painting problems for read-only edits in property sheets.
  373. // Unfortunately, lpk.dll can't be changed since it would break the user32
  374. // edit, so I'm faking lpk!EditDrawText into thinking this isn't a single
  375. // line edit.
  376. //
  377. __inline VOID EditSL_LpkEditDrawText(PED ped, HDC hdc, PSTR pText)
  378. {
  379. BOOL fSingleSave;
  380. fSingleSave = ped->fSingle;
  381. ped->fSingle = FALSE;
  382. ped->pLpkEditCallout->EditDrawText((PED0)ped, hdc, pText, ped->cch, ped->ichMinSel, ped->ichMaxSel, ped->rcFmt.top);
  383. ped->fSingle = fSingleSave;
  384. }
  385. //---------------------------------------------------------------------------//
  386. //
  387. // EditSL_ChangeSelection AorW
  388. //
  389. // Changes the current selection to have the specified starting and
  390. // ending values. Properly highlights the new selection and unhighlights
  391. // anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
  392. // them. Doesn't update the caret position.
  393. //
  394. VOID EditSL_ChangeSelection(PED ped, HDC hdc, ICH ichNewMinSel, ICH ichNewMaxSel)
  395. {
  396. ICH temp;
  397. ICH ichOldMinSel;
  398. ICH ichOldMaxSel;
  399. if (ichNewMinSel > ichNewMaxSel)
  400. {
  401. temp = ichNewMinSel;
  402. ichNewMinSel = ichNewMaxSel;
  403. ichNewMaxSel = temp;
  404. }
  405. ichNewMinSel = min(ichNewMinSel, ped->cch);
  406. ichNewMaxSel = min(ichNewMaxSel, ped->cch);
  407. //
  408. // To avoid position to half of DBCS, check and ajust position if necessary
  409. //
  410. // We check ped->fDBCS and ped->fAnsi though Edit_AdjustIch checks these bits.
  411. // We're worrying about the overhead of EcLock and EcUnlock.
  412. //
  413. if (ped->fDBCS && ped->fAnsi)
  414. {
  415. PSTR pText;
  416. pText = Edit_Lock(ped);
  417. ichNewMinSel = Edit_AdjustIch( ped, pText, ichNewMinSel );
  418. ichNewMaxSel = Edit_AdjustIch( ped, pText, ichNewMaxSel );
  419. Edit_Unlock(ped);
  420. }
  421. //
  422. // Preserve the Old selection
  423. //
  424. ichOldMinSel = ped->ichMinSel;
  425. ichOldMaxSel = ped->ichMaxSel;
  426. //
  427. // Set new selection
  428. //
  429. ped->ichMinSel = ichNewMinSel;
  430. ped->ichMaxSel = ichNewMaxSel;
  431. //
  432. // We will find the intersection of current selection rectangle with the new
  433. // selection rectangle. We will then invert the parts of the two rectangles
  434. // not in the intersection.
  435. //
  436. if (IsWindowVisible(ped->hwnd) && (ped->fFocus || ped->fNoHideSel))
  437. {
  438. SELBLOCK Blk[2];
  439. int i;
  440. RECT rc;
  441. if (ped->fFocus)
  442. {
  443. HideCaret(ped->hwnd);
  444. }
  445. if (ped->pLpkEditCallout)
  446. {
  447. //
  448. // The language pack handles display while complex script support present
  449. //
  450. PSTR pText;
  451. HBRUSH hbr = NULL;
  452. BOOL fNeedDelete = FALSE;
  453. //
  454. // Give user a chance to manipulate the DC
  455. //
  456. hbr = Edit_GetBrush(ped, hdc, &fNeedDelete);
  457. FillRect(hdc, &ped->rcFmt, hbr);
  458. pText = Edit_Lock(ped);
  459. EditSL_LpkEditDrawText(ped, hdc, pText);
  460. Edit_Unlock(ped);
  461. if (hbr && fNeedDelete)
  462. {
  463. DeleteObject(hbr);
  464. }
  465. }
  466. else
  467. {
  468. Blk[0].StPos = ichOldMinSel;
  469. Blk[0].EndPos = ichOldMaxSel;
  470. Blk[1].StPos = ped->ichMinSel;
  471. Blk[1].EndPos = ped->ichMaxSel;
  472. if (Edit_CalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
  473. (LPSELBLOCK)&Blk[0], (LPSELBLOCK)&Blk[1]))
  474. {
  475. //
  476. // Paint the rectangles where selection has changed.
  477. // Paint both Blk[0] and Blk[1], if they exist.
  478. //
  479. for (i = 0; i < 2; i++)
  480. {
  481. if (Blk[i].StPos != 0xFFFFFFFF)
  482. {
  483. EditSL_GetClipRect(ped, hdc, Blk[i].StPos,
  484. Blk[i].EndPos - Blk[i].StPos, (LPRECT)&rc);
  485. EditSL_DrawLine(ped, hdc, rc.left, rc.right, Blk[i].StPos,
  486. Blk[i].EndPos - Blk[i].StPos,
  487. ((Blk[i].StPos >= ped->ichMinSel) &&
  488. (Blk[i].StPos < ped->ichMaxSel)));
  489. }
  490. }
  491. }
  492. }
  493. //
  494. // Update caret.
  495. //
  496. EditSL_SetCaretPosition(ped, hdc);
  497. if (ped->fFocus)
  498. {
  499. ShowCaret(ped->hwnd);
  500. }
  501. }
  502. }
  503. //---------------------------------------------------------------------------//
  504. //
  505. // EditSL_DrawLine()
  506. //
  507. // This draws the line starting from ichStart, iCount number of characters;
  508. // fSelStatus is TRUE if we're to draw the text as selected.
  509. //
  510. VOID EditSL_DrawLine(PED ped, HDC hdc, int xClipStPos, int xClipEndPos, ICH ichStart, int iCount, BOOL fSelStatus)
  511. {
  512. RECT rc;
  513. RECT rcClip;
  514. PSTR pText;
  515. DWORD rgbSaveBk;
  516. DWORD rgbSaveText;
  517. DWORD wSaveBkMode;
  518. int iStCount;
  519. ICH ichNewStart;
  520. HBRUSH hbrBack = NULL;
  521. BOOL fNeedDelete = FALSE;
  522. HRESULT hr;
  523. if (ped->pLpkEditCallout)
  524. {
  525. TraceMsg(TF_STANDARD, "UxEdit: EditSL_DrawLine - Error - Invalid call with language pack loaded");
  526. return;
  527. }
  528. //
  529. // Anything to draw?
  530. //
  531. // PORTPORT: Note the symantics of IsWindowVisible and _IsWindowVisible are
  532. // slightly different.
  533. if (xClipStPos >= xClipEndPos || !IsWindowVisible(ped->hwnd) )
  534. {
  535. return;
  536. }
  537. if (ped->fAnsi && ped->fDBCS)
  538. {
  539. PSTR pT,pTOrg;
  540. int iTCount;
  541. pText = Edit_Lock(ped);
  542. ichNewStart = 0;
  543. if (ichStart > 0)
  544. {
  545. pT = pText + ichStart;
  546. ichNewStart = ichStart;
  547. while (ichNewStart &&
  548. (ichStart - ichNewStart < ped->wMaxNegCcharPos))
  549. {
  550. pT = Edit_AnsiPrev(ped, pText, pT);
  551. ichNewStart = (ICH)(pT - pText);
  552. if (!ichNewStart)
  553. {
  554. break;
  555. }
  556. }
  557. //
  558. // B#16152 - win95.
  559. // In case of T2, SLE always set an additional margin
  560. // to erase a character (iCount == 0 case), using aveCharWidth.
  561. // It erases unexpected an extra char if we don't use ichNewStart
  562. // and it happens when wMaxNegCcharPos == 0.
  563. //
  564. if (ped->wMaxNegCcharPos == 0 && iCount == 0)
  565. {
  566. pT = Edit_AnsiPrev(ped, pText, pT);
  567. ichNewStart = (ICH)(pT - pText);
  568. }
  569. }
  570. iTCount = 0;
  571. if (ichStart + iCount < ped->cch)
  572. {
  573. pTOrg = pT = pText + ichStart + iCount;
  574. while ((iTCount < (int)ped->wMaxNegAcharPos) &&
  575. (ichStart + iCount + iTCount < ped->cch))
  576. {
  577. pT = Edit_AnsiNext(ped, pT);
  578. iTCount = (int)(pT - pTOrg);
  579. }
  580. }
  581. Edit_Unlock(ped);
  582. iCount = (int)(min(ichStart+iCount+iTCount, ped->cch) - ichNewStart);
  583. }
  584. else
  585. {
  586. //
  587. // Reset ichStart to take care of the negative C widths
  588. //
  589. ichNewStart = max((int)(ichStart - ped->wMaxNegCcharPos), 0);
  590. //
  591. // Reset ichCount to take care of the negative C and A widths
  592. //
  593. iCount = (int)(min(ichStart+iCount+ped->wMaxNegAcharPos, ped->cch)
  594. - ichNewStart);
  595. }
  596. ichStart = ichNewStart;
  597. //
  598. // Reset ichStart and iCount to the first one visible on the screen
  599. //
  600. if (ichStart < ped->ichScreenStart)
  601. {
  602. if (ichStart+iCount < ped->ichScreenStart)
  603. {
  604. return;
  605. }
  606. iCount -= (ped->ichScreenStart-ichStart);
  607. ichStart = ped->ichScreenStart;
  608. }
  609. CopyRect(&rc, &ped->rcFmt);
  610. //
  611. // Set the drawing rectangle
  612. //
  613. rcClip.left = xClipStPos;
  614. rcClip.right = xClipEndPos;
  615. rcClip.top = rc.top;
  616. rcClip.bottom = rc.bottom;
  617. //
  618. // Set the proper clipping rectangle
  619. //
  620. Edit_SetClip(ped, hdc, TRUE);
  621. pText = Edit_Lock(ped);
  622. //
  623. // Calculate the starting pos for this piece of text
  624. //
  625. if (ped->format == ES_LEFT)
  626. {
  627. if (iStCount = (int)(ichStart - ped->ichScreenStart))
  628. {
  629. rc.left += EditSL_CalcXOffsetLeft(ped, hdc, ichStart);
  630. }
  631. }
  632. else
  633. {
  634. rc.left += EditSL_CalcXOffsetSpecial(ped, hdc, ichStart);
  635. }
  636. //
  637. // Set the background mode before calling NtUserGetControlBrush so that the app
  638. // can change it to TRANSPARENT if it wants to.
  639. //
  640. SetBkMode(hdc, OPAQUE);
  641. hr = E_FAIL;
  642. #ifdef _USE_DRAW_THEME_TEXT_
  643. if ( ped->hTheme )
  644. {
  645. INT iState;
  646. INT iProp;
  647. COLORREF clrBk;
  648. COLORREF clrText;
  649. iState = fSelStatus ? ETS_SELECTED : Edit_GetStateId(ped);
  650. iProp = fSelStatus ? TMT_HIGHLIGHT : TMT_FILLCOLOR;
  651. hr = GetThemeColor(ped->hTheme, EP_EDITTEXT, iState, iProp, &clrBk);
  652. if ( SUCCEEDED(hr) )
  653. {
  654. iProp = fSelStatus ? TMT_HIGHLIGHTTEXT : TMT_TEXTCOLOR;
  655. hr = GetThemeColor(ped->hTheme, EP_EDITTEXT, iState, iProp, &clrText);
  656. if ( SUCCEEDED(hr) )
  657. {
  658. hbrBack = CreateSolidBrush(clrBk);
  659. fNeedDelete = TRUE;
  660. rgbSaveBk = SetBkColor(hdc, clrBk);
  661. rgbSaveText = SetTextColor(hdc, clrText);
  662. }
  663. }
  664. }
  665. #endif // _USE_DRAW_THEME_TEXT_
  666. if ( !ped->hTheme || FAILED(hr) )
  667. {
  668. if (fSelStatus)
  669. {
  670. //
  671. // if we're not themed or we are themed but failed
  672. // to get the highlight and highlighttext colors
  673. //
  674. // use normal colors
  675. //
  676. hbrBack = GetSysColorBrush(COLOR_HIGHLIGHT);
  677. if (hbrBack == NULL)
  678. {
  679. goto sldl_errorexit;
  680. }
  681. rgbSaveBk = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  682. rgbSaveText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  683. }
  684. else
  685. {
  686. //
  687. // We always want to send this so that the app has a chance to muck
  688. // with the DC.
  689. //
  690. // Note that ReadOnly and Disabled edit fields are drawn as "static"
  691. // instead of as "active."
  692. //
  693. hbrBack = Edit_GetBrush(ped, hdc, &fNeedDelete);
  694. rgbSaveBk = GetBkColor(hdc);
  695. rgbSaveText = GetTextColor(hdc);
  696. }
  697. }
  698. //
  699. // Erase the rectangular area before text is drawn. Note that we inflate
  700. // the rect by 1 so that the selection color has a one pixel border around
  701. // the text.
  702. //
  703. InflateRect(&rcClip, 0, 1);
  704. FillRect(hdc, &rcClip, hbrBack);
  705. InflateRect(&rcClip, 0, -1);
  706. if (ped->charPasswordChar)
  707. {
  708. wSaveBkMode = SetBkMode(hdc, TRANSPARENT);
  709. for (iStCount = 0; iStCount < iCount; iStCount++)
  710. {
  711. if ( ped->fAnsi )
  712. {
  713. ExtTextOutA(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
  714. (LPSTR)&ped->charPasswordChar, 1, NULL);
  715. }
  716. else
  717. {
  718. ExtTextOutW(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
  719. (LPWSTR)&ped->charPasswordChar, 1, NULL);
  720. }
  721. rc.left += ped->cPasswordCharWidth;
  722. }
  723. SetBkMode(hdc, wSaveBkMode);
  724. }
  725. else
  726. {
  727. if ( ped->fAnsi )
  728. {
  729. ExtTextOutA(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
  730. pText+ichStart,iCount, NULL);
  731. }
  732. else
  733. {
  734. ExtTextOutW(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
  735. ((LPWSTR)pText)+ichStart,iCount, NULL);
  736. }
  737. }
  738. SetTextColor(hdc, rgbSaveText);
  739. SetBkColor(hdc, rgbSaveBk);
  740. if (hbrBack && fNeedDelete)
  741. {
  742. DeleteObject(hbrBack);
  743. }
  744. sldl_errorexit:
  745. Edit_Unlock(ped);
  746. }
  747. //---------------------------------------------------------------------------//
  748. //
  749. // EditSL_GetBlkEnd AorW
  750. //
  751. // Given a Starting point and and end point, this function return s whether the
  752. // first few characters fall inside or outside the selection block and if so,
  753. // howmany characters?
  754. //
  755. INT EditSL_GetBlkEnd(PED ped, ICH ichStart, ICH ichEnd, BOOL *lpfStatus)
  756. {
  757. *lpfStatus = FALSE;
  758. if (ichStart >= ped->ichMinSel)
  759. {
  760. if (ichStart >= ped->ichMaxSel)
  761. {
  762. return (ichEnd - ichStart);
  763. }
  764. *lpfStatus = TRUE;
  765. return (min(ichEnd, ped->ichMaxSel) - ichStart);
  766. }
  767. return (min(ichEnd, ped->ichMinSel) - ichStart);
  768. }
  769. //---------------------------------------------------------------------------//
  770. //
  771. // EditSL_DrawCueBannerText (Unicode Only!)
  772. //
  773. // This function is called by EditSL_DrawText to display the cue banner text in
  774. // the edit box.
  775. //
  776. // Note:
  777. // May need to call pLpkEditCallout to support complex scripts.
  778. //
  779. VOID EditSL_DrawCueBannerText(PED ped, HDC hdc, RECT rc)
  780. {
  781. //
  782. // Draw the overlay of the cue banner text.
  783. // Only draw this text if:
  784. // 1. has cue banner text to display
  785. // 2. the edit box is empty,
  786. // 3. does not have focus,
  787. // 4. is not disabled
  788. // 5. and is not read only
  789. //
  790. if (ped->pszCueBannerText
  791. && ped->cch == 0
  792. && !ped->fFocus
  793. && !ped->fDisabled
  794. && !ped->fReadOnly)
  795. {
  796. COLORREF crOldColor;
  797. UINT iOldAlign;
  798. //
  799. // Setup the font to be light gray
  800. // NOTE: Should this be read from the theme manager?
  801. //
  802. crOldColor = SetTextColor(hdc, GetSysColor(COLOR_BTNSHADOW));
  803. //
  804. // Setup the alignment for the text to display.
  805. // We will match our alignment with the alignment that is
  806. // actually used for text in the edit control
  807. //
  808. switch (ped->format)
  809. {
  810. case ES_LEFT:
  811. iOldAlign = SetTextAlign(hdc, TA_LEFT);
  812. break;
  813. case ES_RIGHT:
  814. iOldAlign = SetTextAlign(hdc, TA_RIGHT);
  815. break;
  816. case ES_CENTER:
  817. iOldAlign = SetTextAlign(hdc, TA_CENTER);
  818. break;
  819. }
  820. // Draw the text to the box:
  821. ExtTextOutW(hdc,
  822. rc.left,
  823. rc.top,
  824. ETO_CLIPPED,
  825. &(ped->rcFmt),
  826. ped->pszCueBannerText, // Text
  827. wcslen(ped->pszCueBannerText), // Size of text
  828. NULL);
  829. //
  830. // Reset the alignment
  831. //
  832. SetTextAlign(hdc, iOldAlign);
  833. //
  834. // Reset the color back:
  835. //
  836. SetTextColor(hdc, crOldColor);
  837. }
  838. }
  839. //---------------------------------------------------------------------------//
  840. //
  841. // EditSL_DrawText AorW
  842. //
  843. // Draws text for a single line edit control in the rectangle
  844. // specified by ped->rcFmt. If ichStart == 0, starts drawing text at the left
  845. // side of the window starting at character index ped->ichScreenStart and draws
  846. // as much as will fit. If ichStart > 0, then it appends the characters
  847. // starting at ichStart to the end of the text showing in the window. (ie. We
  848. // are just growing the text length and keeping the left side
  849. // (ped->ichScreenStart to ichStart characters) the same. Assumes the hdc came
  850. // from Edit_GetDC so that the caret and such are properly hidden.
  851. //
  852. VOID EditSL_DrawText(PED ped, HDC hdc, ICH ichStart)
  853. {
  854. ICH cchToDraw;
  855. RECT rc;
  856. PSTR pText;
  857. BOOL fSelStatus;
  858. int iCount, iStCount;
  859. ICH ichEnd;
  860. BOOL fNoSelection;
  861. BOOL fCalcRect;
  862. BOOL fDrawLeftMargin = FALSE;
  863. BOOL fDrawEndOfLineStrip = FALSE;
  864. SIZE size;
  865. HBRUSH hbr = NULL;
  866. BOOL fNeedDelete = FALSE;
  867. //
  868. // PORTPORT: Note the symantics of IsWindowVisible and _IsWindowVisible are
  869. // slightly different.
  870. //
  871. if (!IsWindowVisible(ped->hwnd))
  872. {
  873. return;
  874. }
  875. if (ped->pLpkEditCallout)
  876. {
  877. //
  878. // The language pack handles display while complex script support present
  879. //
  880. //
  881. // Give user a chance to manipulate the DC
  882. //
  883. hbr = Edit_GetBrush(ped, hdc, &fNeedDelete);
  884. pText = Edit_Lock(ped);
  885. EditSL_LpkEditDrawText(ped, hdc, pText);
  886. Edit_Unlock(ped);
  887. EditSL_SetCaretPosition(ped, hdc);
  888. if (hbr && fNeedDelete)
  889. {
  890. DeleteObject(hbr);
  891. }
  892. return;
  893. }
  894. //
  895. // When drawing the entire visible content of special-aligned sle
  896. // erase the view.
  897. //
  898. if (ped->format != ES_LEFT && ichStart == 0)
  899. {
  900. hbr = Edit_GetBrush(ped, hdc, &fNeedDelete);
  901. FillRect(hdc, &ped->rcFmt, hbr);
  902. if (hbr && fNeedDelete)
  903. {
  904. DeleteObject(hbr);
  905. }
  906. }
  907. pText = Edit_Lock(ped);
  908. if (ichStart < ped->ichScreenStart)
  909. {
  910. #if DBG
  911. ICH ichCompare = Edit_AdjustIch(ped, pText, ped->ichScreenStart);
  912. UserAssert(ichCompare == ped->ichScreenStart);
  913. #endif
  914. ichStart = ped->ichScreenStart;
  915. }
  916. else if (ped->fDBCS && ped->fAnsi)
  917. {
  918. //
  919. // If ichStart stays on trailing byte of DBCS, we have to
  920. // adjust it.
  921. //
  922. ichStart = Edit_AdjustIch(ped, pText, ichStart);
  923. }
  924. CopyRect((LPRECT)&rc, (LPRECT)&ped->rcFmt);
  925. //
  926. // Find out how many characters will fit on the screen so that we don't do
  927. // any needless drawing.
  928. //
  929. cchToDraw = Edit_CchInWidth(ped, hdc,
  930. (LPSTR)(pText + ped->ichScreenStart * ped->cbChar),
  931. ped->cch - ped->ichScreenStart, rc.right - rc.left, TRUE);
  932. ichEnd = ped->ichScreenStart + cchToDraw;
  933. //
  934. // There is no selection if,
  935. // 1. MinSel and MaxSel are equal OR
  936. // 2. (This has lost the focus AND Selection is to be hidden)
  937. //
  938. fNoSelection = ((ped->ichMinSel == ped->ichMaxSel) || (!ped->fFocus && !ped->fNoHideSel));
  939. if (ped->format == ES_LEFT)
  940. {
  941. if (iStCount = (int)(ichStart - ped->ichScreenStart))
  942. {
  943. rc.left += EditSL_CalcXOffsetLeft(ped, hdc, ichStart);
  944. }
  945. }
  946. else
  947. {
  948. rc.left += EditSL_CalcXOffsetSpecial(ped, hdc, ichStart);
  949. }
  950. //
  951. // If this is the begining of the whole line, we may have to draw a blank
  952. // strip at the begining.
  953. //
  954. if ((ichStart == 0) && ped->wLeftMargin)
  955. {
  956. fDrawLeftMargin = TRUE;
  957. }
  958. //
  959. // If there is nothing to draw, that means we need to draw the end of
  960. // line strip, which erases the last character.
  961. //
  962. if (ichStart == ichEnd)
  963. {
  964. fDrawEndOfLineStrip = TRUE;
  965. rc.left -= ped->wLeftMargin;
  966. }
  967. while (ichStart < ichEnd)
  968. {
  969. fCalcRect = TRUE;
  970. if (fNoSelection)
  971. {
  972. fSelStatus = FALSE;
  973. iCount = ichEnd - ichStart;
  974. }
  975. else
  976. {
  977. if (fDrawLeftMargin)
  978. {
  979. iCount = 0;
  980. fSelStatus = FALSE;
  981. fCalcRect = FALSE;
  982. rc.right = rc.left;
  983. }
  984. else
  985. {
  986. iCount = EditSL_GetBlkEnd(ped, ichStart, ichEnd,
  987. (BOOL *)&fSelStatus);
  988. }
  989. }
  990. if (ichStart+iCount == ichEnd)
  991. {
  992. if (fSelStatus)
  993. {
  994. fDrawEndOfLineStrip = TRUE;
  995. }
  996. else
  997. {
  998. rc.right = ped->rcFmt.right + ped->wRightMargin;
  999. fCalcRect = FALSE;
  1000. }
  1001. }
  1002. if (fCalcRect)
  1003. {
  1004. if (ped->charPasswordChar)
  1005. {
  1006. rc.right = rc.left + ped->cPasswordCharWidth * iCount;
  1007. }
  1008. else
  1009. {
  1010. if ( ped->fAnsi )
  1011. {
  1012. GetTextExtentPointA(hdc, pText + ichStart,
  1013. iCount, &size);
  1014. }
  1015. else
  1016. {
  1017. GetTextExtentPointW(hdc, ((LPWSTR)pText) + ichStart,
  1018. iCount, &size);
  1019. }
  1020. rc.right = rc.left + size.cx;
  1021. //
  1022. // The extent is equal to the advance width. So for TrueType fonts
  1023. // we need to take care of Neg A and C. For non TrueType, the extent
  1024. // includes the overhang.
  1025. // If drawing the selection, draw only the advance width
  1026. //
  1027. if (fSelStatus)
  1028. {
  1029. rc.right -= ped->charOverhang;
  1030. }
  1031. else if (ped->fTrueType)
  1032. {
  1033. rc.right += ped->wMaxNegC;
  1034. if (iStCount > 0)
  1035. {
  1036. rc.right += ped->wMaxNegA;
  1037. iStCount = 0;
  1038. }
  1039. }
  1040. }
  1041. }
  1042. if (fDrawLeftMargin)
  1043. {
  1044. fDrawLeftMargin = FALSE;
  1045. rc.left -= ped->wLeftMargin;
  1046. if (rc.right < rc.left)
  1047. {
  1048. rc.right = rc.left;
  1049. }
  1050. }
  1051. EditSL_DrawLine(ped, hdc, rc.left, rc.right, ichStart, iCount, fSelStatus);
  1052. ichStart += iCount;
  1053. rc.left = rc.right;
  1054. //
  1055. // If we're going to draw the selection, adjust rc.left
  1056. // to include advance width of the selected text
  1057. // For non TT fonts, ped->wMaxNegC equals ped->charOverhang
  1058. //
  1059. if (!fSelStatus && (iCount != 0) && (ichStart < ichEnd))
  1060. {
  1061. rc.left -= ped->wMaxNegC;
  1062. }
  1063. }
  1064. Edit_Unlock(ped);
  1065. //
  1066. // Check if anything to be erased on the right hand side
  1067. //
  1068. if (fDrawEndOfLineStrip &&
  1069. (rc.left < (rc.right = (ped->rcFmt.right+ped->wRightMargin))))
  1070. {
  1071. EditSL_DrawLine(ped, hdc, rc.left, rc.right, ichStart, 0, FALSE);
  1072. }
  1073. EditSL_SetCaretPosition(ped, hdc);
  1074. //
  1075. // Call the function to display the cue banner text into the edit box
  1076. //
  1077. EditSL_DrawCueBannerText(ped, hdc, rc);
  1078. }
  1079. //---------------------------------------------------------------------------//
  1080. //
  1081. // EditSL_ScrollText AorW
  1082. //
  1083. // Scrolls the text to bring the caret into view. If the text is
  1084. // scrolled, the current selection is unhighlighted. Returns TRUE if the text
  1085. // is scrolled else return s false.
  1086. //
  1087. BOOL EditSL_ScrollText(PED ped, HDC hdc)
  1088. {
  1089. PSTR pTextScreenStart;
  1090. ICH scrollAmount;
  1091. ICH newScreenStartX = ped->ichScreenStart;
  1092. ICH cch;
  1093. BOOLEAN fAdjustNext = FALSE;
  1094. if (!ped->fAutoHScroll)
  1095. {
  1096. return FALSE;
  1097. }
  1098. if (ped->pLpkEditCallout)
  1099. {
  1100. BOOL fChanged;
  1101. //
  1102. // With complex script glyph reordering, use lpk to do horz scroll
  1103. //
  1104. pTextScreenStart = Edit_Lock(ped);
  1105. fChanged = ped->pLpkEditCallout->EditHScroll((PED0)ped, hdc, pTextScreenStart);
  1106. Edit_Unlock(ped);
  1107. if (fChanged)
  1108. {
  1109. EditSL_DrawText(ped, hdc, 0);
  1110. }
  1111. return fChanged;
  1112. }
  1113. //
  1114. // Calculate the new starting screen position
  1115. //
  1116. if (ped->ichCaret <= ped->ichScreenStart)
  1117. {
  1118. //
  1119. // Caret is to the left of the starting text on the screen we must
  1120. // scroll the text backwards to bring it into view. Watch out when
  1121. // subtracting unsigned numbers when we have the possibility of going
  1122. // negative.
  1123. //
  1124. pTextScreenStart = Edit_Lock(ped);
  1125. scrollAmount = Edit_CchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
  1126. ped->ichCaret, (ped->rcFmt.right - ped->rcFmt.left) / 4, FALSE);
  1127. newScreenStartX = ped->ichCaret - scrollAmount;
  1128. Edit_Unlock(ped);
  1129. }
  1130. else if (ped->ichCaret != ped->ichScreenStart)
  1131. {
  1132. pTextScreenStart = Edit_Lock(ped);
  1133. pTextScreenStart += ped->ichScreenStart * ped->cbChar;
  1134. cch = Edit_CchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
  1135. ped->ichCaret - ped->ichScreenStart,
  1136. ped->rcFmt.right - ped->rcFmt.left, FALSE);
  1137. if (cch < ped->ichCaret - ped->ichScreenStart)
  1138. {
  1139. fAdjustNext = TRUE;
  1140. //
  1141. // Scroll Forward 1/4 -- if that leaves some empty space
  1142. // at the end, scroll back enough to fill the space
  1143. //
  1144. newScreenStartX = ped->ichCaret - (3 * cch / 4);
  1145. cch = Edit_CchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
  1146. ped->cch - ped->ichScreenStart,
  1147. ped->rcFmt.right - ped->rcFmt.left, FALSE);
  1148. if (newScreenStartX > (ped->cch - cch))
  1149. {
  1150. newScreenStartX = ped->cch - cch;
  1151. }
  1152. }
  1153. else if (ped->format != ES_LEFT)
  1154. {
  1155. cch = Edit_CchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
  1156. ped->cch - ped->ichScreenStart,
  1157. ped->rcFmt.right - ped->rcFmt.left, FALSE);
  1158. //
  1159. // Scroll the text hidden behind the left border back
  1160. // into view.
  1161. //
  1162. if (ped->ichScreenStart == ped->cch - cch)
  1163. {
  1164. pTextScreenStart -= ped->ichScreenStart * ped->cbChar;
  1165. cch = Edit_CchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
  1166. ped->cch, ped->rcFmt.right - ped->rcFmt.left, FALSE);
  1167. newScreenStartX = ped->cch - cch;
  1168. }
  1169. }
  1170. Edit_Unlock(ped);
  1171. }
  1172. //
  1173. // Adjust newScreenStartX
  1174. //
  1175. if (ped->fAnsi && ped->fDBCS)
  1176. {
  1177. newScreenStartX = (fAdjustNext ? Edit_AdjustIchNext : Edit_AdjustIch)(ped,
  1178. Edit_Lock(ped),
  1179. newScreenStartX);
  1180. Edit_Unlock(ped);
  1181. }
  1182. if (ped->ichScreenStart != newScreenStartX)
  1183. {
  1184. //
  1185. // Check if we have to wipe out the left margin
  1186. //
  1187. if (ped->wLeftMargin && (ped->ichScreenStart == 0))
  1188. {
  1189. RECT rc;
  1190. HBRUSH hBrush = NULL;
  1191. BOOL fNeedDelete = FALSE;
  1192. hBrush = Edit_GetBrush(ped, hdc, &fNeedDelete);
  1193. CopyRect(&rc, &ped->rcFmt);
  1194. InflateRect(&rc, 0, 1);
  1195. rc.right = rc.left;
  1196. rc.left -= ped->wLeftMargin;
  1197. FillRect(hdc, &rc, hBrush);
  1198. if (hBrush && fNeedDelete)
  1199. {
  1200. DeleteObject(hBrush);
  1201. }
  1202. }
  1203. ped->ichScreenStart = newScreenStartX;
  1204. EditSL_DrawText(ped, hdc, 0);
  1205. //
  1206. // Caret pos is set by EditSL_DrawText().
  1207. //
  1208. return TRUE;
  1209. }
  1210. return FALSE;
  1211. }
  1212. //---------------------------------------------------------------------------//
  1213. //
  1214. // EditSL_InsertText AorW
  1215. //
  1216. // Adds up to cchInsert characters from lpText to the ped starting at
  1217. // ichCaret. If the ped only allows a maximum number of characters, then we
  1218. // will only add that many characters to the ped and send a EN_MAXTEXT
  1219. // notification code to the parent of the ec. Also, if !fAutoHScroll, then we
  1220. // only allow as many chars as will fit in the client rectangle. The number of
  1221. // characters actually added is return ed (could be 0). If we can't allocate
  1222. // the required space, we notify the parent with EN_ERRSPACE and no characters
  1223. // are added.
  1224. //
  1225. ICH EditSL_InsertText(PED ped, LPSTR lpText, ICH cchInsert)
  1226. {
  1227. HDC hdc;
  1228. PSTR pText;
  1229. ICH cchInsertCopy = cchInsert;
  1230. ICH cchT;
  1231. int textWidth;
  1232. SIZE size;
  1233. //
  1234. // First determine exactly how many characters from lpText we can insert
  1235. // into the ped.
  1236. //
  1237. if( ped->cchTextMax <= ped->cch)
  1238. {
  1239. cchInsert = 0;
  1240. }
  1241. else
  1242. {
  1243. if (!ped->fAutoHScroll)
  1244. {
  1245. pText = Edit_Lock(ped);
  1246. hdc = Edit_GetDC(ped, TRUE);
  1247. cchInsert = min(cchInsert, (unsigned)(ped->cchTextMax - ped->cch));
  1248. if (ped->charPasswordChar)
  1249. {
  1250. textWidth = ped->cch * ped->cPasswordCharWidth;
  1251. }
  1252. else
  1253. {
  1254. if (ped->fAnsi)
  1255. {
  1256. GetTextExtentPointA(hdc, (LPSTR)pText, ped->cch, &size);
  1257. }
  1258. else
  1259. {
  1260. GetTextExtentPointW(hdc, (LPWSTR)pText, ped->cch, &size);
  1261. }
  1262. textWidth = size.cx;
  1263. }
  1264. cchT = Edit_CchInWidth(ped, hdc, lpText, cchInsert,
  1265. ped->rcFmt.right - ped->rcFmt.left -
  1266. textWidth, TRUE);
  1267. cchInsert = min(cchInsert, cchT);
  1268. Edit_Unlock(ped);
  1269. Edit_ReleaseDC(ped, hdc, TRUE);
  1270. }
  1271. else
  1272. {
  1273. cchInsert = min((unsigned)(ped->cchTextMax - ped->cch), cchInsert);
  1274. }
  1275. }
  1276. //
  1277. // Now try actually adding the text to the ped
  1278. //
  1279. if (cchInsert && !Edit_InsertText(ped, lpText, &cchInsert))
  1280. {
  1281. Edit_NotifyParent(ped, EN_ERRSPACE);
  1282. return 0;
  1283. }
  1284. if (cchInsert)
  1285. {
  1286. ped->fDirty = TRUE;
  1287. }
  1288. if (cchInsert < cchInsertCopy)
  1289. {
  1290. //
  1291. // Notify parent that we couldn't insert all the text requested
  1292. //
  1293. Edit_NotifyParent(ped, EN_MAXTEXT);
  1294. }
  1295. //
  1296. // Update selection extents and the caret position. Note that Edit_InsertText
  1297. // updates ped->ichCaret, ped->ichMinSel, and ped->ichMaxSel to all be after
  1298. // the inserted text.
  1299. //
  1300. return cchInsert;
  1301. }
  1302. //---------------------------------------------------------------------------//
  1303. //
  1304. // EditSL_PasteText AorW
  1305. //
  1306. // Pastes a line of text from the clipboard into the edit control
  1307. // starting at ped->ichMaxSel. Updates ichMaxSel and ichMinSel to point to
  1308. // the end of the inserted text. Notifies the parent if space cannot be
  1309. // allocated. Returns how many characters were inserted.
  1310. //
  1311. ICH EditSL_PasteText(PED ped)
  1312. {
  1313. HANDLE hData;
  1314. LPSTR lpchClip;
  1315. ICH cchAdded = 0;
  1316. ICH clipLength;
  1317. if (!OpenClipboard(ped->hwnd))
  1318. {
  1319. goto PasteExitNoCloseClip;
  1320. }
  1321. hData = GetClipboardData(ped->fAnsi ? CF_TEXT : CF_UNICODETEXT);
  1322. if (!hData || (GlobalFlags(hData) == GMEM_INVALID_HANDLE))
  1323. {
  1324. TraceMsg(TF_STANDARD, "UxEdit: EditSL_PasteText(): couldn't get a valid handle(%x)", hData);
  1325. goto PasteExit;
  1326. }
  1327. lpchClip = GlobalLock(hData);
  1328. if (lpchClip == NULL)
  1329. {
  1330. TraceMsg(TF_STANDARD, "UxEdit: EditSL_PasteText(): USERGLOBALLOCK(%x) failed.", hData);
  1331. goto PasteExit;
  1332. }
  1333. if (ped->fAnsi)
  1334. {
  1335. LPSTR lpchClip2 = lpchClip;
  1336. //
  1337. // Find the first carrage return or line feed. Just add text to that point.
  1338. //
  1339. clipLength = (UINT)strlen(lpchClip);
  1340. for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
  1341. {
  1342. if (*lpchClip2++ == 0x0D)
  1343. {
  1344. break;
  1345. }
  1346. }
  1347. }
  1348. else
  1349. {
  1350. LPWSTR lpwstrClip2 = (LPWSTR)lpchClip;
  1351. //
  1352. // Find the first carrage return or line feed. Just add text to that point.
  1353. //
  1354. clipLength = (UINT)wcslen((LPWSTR)lpchClip);
  1355. for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
  1356. {
  1357. if (*lpwstrClip2++ == 0x0D)
  1358. {
  1359. break;
  1360. }
  1361. }
  1362. }
  1363. //
  1364. // Insert the text (EditSL_InsertText checks line length)
  1365. //
  1366. cchAdded = EditSL_InsertText(ped, lpchClip, cchAdded);
  1367. GlobalUnlock(hData);
  1368. PasteExit:
  1369. CloseClipboard();
  1370. PasteExitNoCloseClip:
  1371. return cchAdded;
  1372. }
  1373. //---------------------------------------------------------------------------//
  1374. //
  1375. // EditSL_ReplaceSel AorW
  1376. //
  1377. // Replaces the text in the current selection with the given text.
  1378. //
  1379. VOID EditSL_ReplaceSel(PED ped, LPSTR lpText)
  1380. {
  1381. UINT cchText;
  1382. //
  1383. // Delete text, putting it into the clean undo buffer.
  1384. //
  1385. Edit_EmptyUndo(Pundo(ped));
  1386. Edit_DeleteText(ped);
  1387. //
  1388. // B#3356
  1389. // Some apps do "clear" by selecting all of the text, then replacing it
  1390. // with "", in which case EditSL_InsertText() will return 0. But that
  1391. // doesn't mean failure...
  1392. //
  1393. if ( ped->fAnsi )
  1394. {
  1395. cchText = strlen(lpText);
  1396. }
  1397. else
  1398. {
  1399. cchText = wcslen((LPWSTR)lpText);
  1400. }
  1401. if (cchText)
  1402. {
  1403. BOOL fFailed;
  1404. UNDO undo;
  1405. HWND hwndSave;
  1406. //
  1407. // Save undo buffer, but DO NOT CLEAR IT!
  1408. //
  1409. Edit_SaveUndo(Pundo(ped), &undo, FALSE);
  1410. hwndSave = ped->hwnd;
  1411. fFailed = (BOOL) !EditSL_InsertText(ped, lpText, cchText);
  1412. if (!IsWindow(hwndSave))
  1413. {
  1414. return;
  1415. }
  1416. if (fFailed)
  1417. {
  1418. //
  1419. // UNDO the previous edit.
  1420. //
  1421. Edit_SaveUndo(&undo, Pundo(ped), FALSE);
  1422. EditSL_Undo(ped);
  1423. return;
  1424. }
  1425. }
  1426. //
  1427. // Success. So update the display
  1428. //
  1429. Edit_NotifyParent(ped, EN_UPDATE);
  1430. // PORTPORT: Note the symantics of IsWindowVisible and _IsWindowVisible are
  1431. // slightly different.
  1432. if (IsWindowVisible(ped->hwnd))
  1433. {
  1434. HDC hdc;
  1435. hdc = Edit_GetDC(ped, FALSE);
  1436. if (!EditSL_ScrollText(ped, hdc))
  1437. {
  1438. EditSL_DrawText(ped, hdc, 0);
  1439. }
  1440. Edit_ReleaseDC(ped, hdc, FALSE);
  1441. }
  1442. Edit_NotifyParent(ped, EN_CHANGE);
  1443. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
  1444. }
  1445. //---------------------------------------------------------------------------//
  1446. //
  1447. // EditSL_Char AorW
  1448. //
  1449. // Handles character input
  1450. //
  1451. VOID EditSL_Char(PED ped, DWORD keyValue)
  1452. {
  1453. HDC hdc;
  1454. WCHAR keyPress;
  1455. BOOL updateText = FALSE;
  1456. HWND hwndSave = ped->hwnd;
  1457. int InsertTextLen = 1;
  1458. int DBCSkey;
  1459. if (ped->fAnsi)
  1460. {
  1461. keyPress = LOBYTE(keyValue);
  1462. }
  1463. else
  1464. {
  1465. keyPress = LOWORD(keyValue);
  1466. }
  1467. if (ped->fMouseDown || (ped->fReadOnly && keyPress != 3))
  1468. {
  1469. //
  1470. // Don't do anything if we are in the middle of a mousedown deal or if
  1471. // this is a read only edit control, with exception of allowing
  1472. // ctrl-C in order to copy to the clipboard.
  1473. //
  1474. return;
  1475. }
  1476. if (g_fIMMEnabled)
  1477. {
  1478. Edit_InOutReconversionMode(ped, FALSE);
  1479. }
  1480. switch (keyPress)
  1481. {
  1482. case VK_BACK:
  1483. DeleteSelection:
  1484. if (Edit_DeleteText(ped))
  1485. {
  1486. updateText = TRUE;
  1487. }
  1488. break;
  1489. default:
  1490. if (keyPress >= TEXT(' '))
  1491. {
  1492. //
  1493. // If this is in [a-z],[A-Z] and we are an ES_NUMBER
  1494. // edit field, bail.
  1495. //
  1496. if (ped->f40Compat && (GET_STYLE(ped) & ES_NUMBER))
  1497. {
  1498. if (!Edit_IsCharNumeric(ped, keyPress))
  1499. {
  1500. Edit_ShowBalloonTipWrap(ped->hwnd, IDS_NUMERIC_TITLE, IDS_NUMERIC_MSG, TTI_ERROR);
  1501. goto IllegalChar;
  1502. }
  1503. }
  1504. goto DeleteSelection;
  1505. }
  1506. break;
  1507. }
  1508. switch (keyPress)
  1509. {
  1510. case 3:
  1511. //
  1512. // CTRL-C Copy
  1513. //
  1514. SendMessage(ped->hwnd, WM_COPY, 0, 0L);
  1515. return;
  1516. case VK_BACK:
  1517. //
  1518. // Delete any selected text or delete character left if no sel
  1519. //
  1520. if (!updateText && ped->ichMinSel)
  1521. {
  1522. //
  1523. // There was no selection to delete so we just delete character
  1524. // left if available
  1525. //
  1526. // Calling PrevIch rather than just doing a decrement for VK_BACK
  1527. //
  1528. ped->ichMinSel = Edit_PrevIch( ped, NULL, ped->ichMinSel);
  1529. Edit_DeleteText(ped);
  1530. updateText = TRUE;
  1531. }
  1532. break;
  1533. case 22:
  1534. //
  1535. // CTRL-V Paste
  1536. //
  1537. SendMessage(ped->hwnd, WM_PASTE, 0, 0L);
  1538. return;
  1539. case 24:
  1540. //
  1541. // CTRL-X Cut
  1542. //
  1543. if (ped->ichMinSel == ped->ichMaxSel)
  1544. {
  1545. goto IllegalChar;
  1546. }
  1547. SendMessage(ped->hwnd, WM_CUT, 0, 0L);
  1548. return;
  1549. case 26:
  1550. //
  1551. // CTRL-Z Undo
  1552. //
  1553. SendMessage(ped->hwnd, EM_UNDO, 0, 0L);
  1554. return;
  1555. case VK_RETURN:
  1556. case VK_ESCAPE:
  1557. //
  1558. // If this is an edit control for a combobox and the dropdown list
  1559. // is visible, forward it up to the combo.
  1560. //
  1561. if (ped->listboxHwnd && SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L))
  1562. {
  1563. SendMessage(ped->hwndParent, WM_KEYDOWN, (WPARAM)keyPress, 0L);
  1564. }
  1565. else
  1566. {
  1567. goto IllegalChar;
  1568. }
  1569. return;
  1570. default:
  1571. if (keyPress >= 0x1E)
  1572. {
  1573. //
  1574. // 1E,1F are unicode block and segment separators
  1575. //
  1576. //
  1577. // Hide the cursor if typing, if the mouse is captured, do not mess with this
  1578. // as it is going to desapear forever (no WM_SETCURSOR is sent to restore it
  1579. // at the first mouse-move)
  1580. // MCostea #166951
  1581. //
  1582. if (GetCapture() == NULL)
  1583. {
  1584. SetCursor(NULL);
  1585. }
  1586. if (g_fDBCSEnabled && ped->fAnsi && (Edit_IsDBCSLeadByte(ped,(BYTE)keyPress)))
  1587. {
  1588. if ((DBCSkey = DbcsCombine(ped->hwnd, keyPress)) != 0 &&
  1589. EditSL_InsertText(ped,(LPSTR)&DBCSkey, 2) == 2)
  1590. {
  1591. InsertTextLen = 2;
  1592. updateText = TRUE;
  1593. }
  1594. else
  1595. {
  1596. MessageBeep(0);
  1597. }
  1598. }
  1599. else
  1600. {
  1601. InsertTextLen = 1;
  1602. if (EditSL_InsertText(ped, (LPSTR)&keyPress, 1))
  1603. {
  1604. updateText = TRUE;
  1605. }
  1606. else
  1607. {
  1608. //
  1609. // Beep. Since we couldn't add the text
  1610. //
  1611. MessageBeep(0);
  1612. }
  1613. }
  1614. }
  1615. else
  1616. {
  1617. IllegalChar:
  1618. MessageBeep(0);
  1619. }
  1620. if (!IsWindow(hwndSave))
  1621. {
  1622. return;
  1623. }
  1624. break;
  1625. }
  1626. if (updateText)
  1627. {
  1628. //
  1629. // Dirty flag (ped->fDirty) was set when we inserted text
  1630. //
  1631. Edit_NotifyParent(ped, EN_UPDATE);
  1632. hdc = Edit_GetDC(ped, FALSE);
  1633. if (!EditSL_ScrollText(ped, hdc))
  1634. {
  1635. if (ped->format == ES_LEFT)
  1636. {
  1637. //
  1638. // Call EditSL_DrawText with correct ichStart
  1639. //
  1640. EditSL_DrawText(ped, hdc, max(0, (int)(ped->ichCaret - InsertTextLen - ped->wMaxNegCcharPos)));
  1641. }
  1642. else
  1643. {
  1644. //
  1645. // We can't just draw from ichStart because string may have
  1646. // shifted because of alignment.
  1647. //
  1648. EditSL_DrawText(ped, hdc, 0);
  1649. }
  1650. }
  1651. Edit_ReleaseDC(ped, hdc, FALSE);
  1652. Edit_NotifyParent(ped, EN_CHANGE);
  1653. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
  1654. }
  1655. }
  1656. //---------------------------------------------------------------------------//
  1657. //
  1658. // EditSL_MoveSelectionRestricted AorW
  1659. //
  1660. // Moves the selection like Edit_MoveSelection, but also obeys limitations
  1661. // imposed by some languages such as Thai, where the cursor cannot stop
  1662. // between a character and it's attached vowel or tone marks.
  1663. //
  1664. // Only called if the language pack is loaded.
  1665. //
  1666. ICH EditSL_MoveSelectionRestricted(PED ped, ICH ich, BOOL fLeft)
  1667. {
  1668. PSTR pText;
  1669. HDC hdc;
  1670. ICH ichResult;
  1671. pText = Edit_Lock(ped);
  1672. hdc = Edit_GetDC(ped, TRUE);
  1673. ichResult = ped->pLpkEditCallout->EditMoveSelection((PED0)ped, hdc, pText, ich, fLeft);
  1674. Edit_ReleaseDC(ped, hdc, TRUE);
  1675. Edit_Unlock(ped);
  1676. return ichResult;
  1677. }
  1678. //---------------------------------------------------------------------------//
  1679. void EditSL_CheckCapsLock(PED ped)
  1680. {
  1681. if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0)
  1682. {
  1683. Edit_ShowBalloonTipWrap(ped->hwnd, IDS_CAPSLOCK_TITLE, IDS_CAPSLOCK_MSG, TTI_WARNING);
  1684. }
  1685. }
  1686. //---------------------------------------------------------------------------//
  1687. //
  1688. // EditSL_KeyDown AorW
  1689. //
  1690. // Handles cursor movement and other VIRT KEY stuff. keyMods allows
  1691. // us to make EditSL_KeyDownHandler calls and specify if the modifier keys (shift
  1692. // and control) are up or down. This is useful for imnplementing the
  1693. // cut/paste/clear messages for single line edit controls. If keyMods == 0,
  1694. // we get the keyboard state using GetKeyState(VK_SHIFT) etc. Otherwise, the
  1695. // bits in keyMods define the state of the shift and control keys.
  1696. //
  1697. VOID EditSL_KeyDown(PED ped, DWORD virtKeyCode, int keyMods)
  1698. {
  1699. HDC hdc;
  1700. //
  1701. // Variables we will use for redrawing the updated text
  1702. //
  1703. ICH newMaxSel = ped->ichMaxSel;
  1704. ICH newMinSel = ped->ichMinSel;
  1705. //
  1706. // Flags for drawing the updated text
  1707. //
  1708. BOOL updateText = FALSE;
  1709. BOOL changeSelection = FALSE; // new selection is specified by
  1710. // newMinSel, newMaxSel
  1711. //
  1712. // Comparisons we do often
  1713. //
  1714. BOOL MinEqMax = (newMaxSel == newMinSel);
  1715. BOOL MinEqCar = (ped->ichCaret == newMinSel);
  1716. BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
  1717. //
  1718. // State of shift and control keys.
  1719. //
  1720. int scState;
  1721. //
  1722. // Combo box support
  1723. //
  1724. BOOL fIsListVisible;
  1725. BOOL fIsExtendedUI;
  1726. if (ped->fMouseDown)
  1727. {
  1728. //
  1729. // If we are in the middle of a mouse down handler, then don't do
  1730. // anything. ie. ignore keyboard input.
  1731. //
  1732. return;
  1733. }
  1734. if (ped->hwndBalloon)
  1735. {
  1736. Edit_HideBalloonTip(ped->hwnd);
  1737. }
  1738. scState = Edit_GetModKeys(keyMods);
  1739. switch (virtKeyCode)
  1740. {
  1741. case VK_UP:
  1742. if ( ped->listboxHwnd )
  1743. {
  1744. //
  1745. // Handle Combobox support
  1746. //
  1747. fIsExtendedUI = (BOOL)SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0);
  1748. fIsListVisible = (BOOL)SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0);
  1749. if (!fIsListVisible && fIsExtendedUI)
  1750. {
  1751. DropExtendedUIListBox:
  1752. //
  1753. // Since an extendedui combo box doesn't do anything on f4, we
  1754. // turn off the extended ui, send the f4 to drop, and turn it
  1755. // back on again.
  1756. //
  1757. SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 0, 0);
  1758. SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0);
  1759. SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 1, 0);
  1760. return;
  1761. }
  1762. else
  1763. {
  1764. goto SendKeyToListBox;
  1765. }
  1766. }
  1767. //
  1768. // else fall through
  1769. //
  1770. case VK_LEFT:
  1771. //
  1772. // If the caret isn't at the beginning, we can move left
  1773. //
  1774. if (ped->ichCaret)
  1775. {
  1776. //
  1777. // Get new caret pos.
  1778. //
  1779. if (scState & CTRLDOWN)
  1780. {
  1781. //
  1782. // Move caret word left
  1783. //
  1784. Edit_Word(ped, ped->ichCaret, TRUE, &ped->ichCaret, NULL);
  1785. }
  1786. else
  1787. {
  1788. //
  1789. // Move caret char left
  1790. //
  1791. if (ped->pLpkEditCallout)
  1792. {
  1793. ped->ichCaret = EditSL_MoveSelectionRestricted(ped, ped->ichCaret, TRUE);
  1794. }
  1795. else
  1796. {
  1797. ped->ichCaret = Edit_PrevIch(ped,NULL,ped->ichCaret);
  1798. }
  1799. }
  1800. //
  1801. // Get new selection
  1802. //
  1803. if (scState & SHFTDOWN)
  1804. {
  1805. if (MaxEqCar && !MinEqMax)
  1806. {
  1807. //
  1808. // Reduce selection
  1809. //
  1810. newMaxSel = ped->ichCaret;
  1811. UserAssert(newMinSel == ped->ichMinSel);
  1812. }
  1813. else
  1814. {
  1815. //
  1816. // Extend selection
  1817. //
  1818. newMinSel = ped->ichCaret;
  1819. }
  1820. }
  1821. else
  1822. {
  1823. //
  1824. // Clear selection
  1825. //
  1826. newMaxSel = newMinSel = ped->ichCaret;
  1827. }
  1828. changeSelection = TRUE;
  1829. }
  1830. else
  1831. {
  1832. //
  1833. // If the user tries to move left and we are at the 0th
  1834. // character and there is a selection, then cancel the
  1835. // selection.
  1836. //
  1837. if ( (ped->ichMaxSel != ped->ichMinSel) && !(scState & SHFTDOWN) )
  1838. {
  1839. changeSelection = TRUE;
  1840. newMaxSel = newMinSel = ped->ichCaret;
  1841. }
  1842. }
  1843. break;
  1844. case VK_DOWN:
  1845. if (ped->listboxHwnd)
  1846. {
  1847. //
  1848. // Handle Combobox support
  1849. //
  1850. fIsExtendedUI = (BOOL)SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0);
  1851. fIsListVisible = (BOOL)SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0);
  1852. if (!fIsListVisible && fIsExtendedUI)
  1853. {
  1854. goto DropExtendedUIListBox;
  1855. }
  1856. else
  1857. {
  1858. goto SendKeyToListBox;
  1859. }
  1860. }
  1861. //
  1862. // else fall through
  1863. //
  1864. case VK_RIGHT:
  1865. //
  1866. // If the caret isn't at the end, we can move right.
  1867. //
  1868. if (ped->ichCaret < ped->cch)
  1869. {
  1870. //
  1871. // Get new caret pos.
  1872. //
  1873. if (scState & CTRLDOWN)
  1874. {
  1875. //
  1876. // Move caret word right
  1877. //
  1878. Edit_Word(ped, ped->ichCaret, FALSE, NULL, &ped->ichCaret);
  1879. }
  1880. else
  1881. {
  1882. //
  1883. // Move caret char right
  1884. //
  1885. if (ped->pLpkEditCallout)
  1886. {
  1887. ped->ichCaret = EditSL_MoveSelectionRestricted(ped, ped->ichCaret, FALSE);
  1888. }
  1889. else
  1890. {
  1891. ped->ichCaret = Edit_NextIch(ped,NULL,ped->ichCaret);
  1892. }
  1893. }
  1894. //
  1895. // Get new selection.
  1896. //
  1897. if (scState & SHFTDOWN)
  1898. {
  1899. if (MinEqCar && !MinEqMax)
  1900. {
  1901. //
  1902. // Reduce selection
  1903. //
  1904. newMinSel = ped->ichCaret;
  1905. UserAssert(newMaxSel == ped->ichMaxSel);
  1906. }
  1907. else
  1908. {
  1909. //
  1910. // Extend selection
  1911. //
  1912. newMaxSel = ped->ichCaret;
  1913. }
  1914. }
  1915. else
  1916. {
  1917. //
  1918. // Clear selection
  1919. //
  1920. newMaxSel = newMinSel = ped->ichCaret;
  1921. }
  1922. changeSelection = TRUE;
  1923. }
  1924. else
  1925. {
  1926. //
  1927. // If the user tries to move right and we are at the last
  1928. // character and there is a selection, then cancel the
  1929. // selection.
  1930. //
  1931. if ( (ped->ichMaxSel != ped->ichMinSel) &&
  1932. !(scState & SHFTDOWN) )
  1933. {
  1934. newMaxSel = newMinSel = ped->ichCaret;
  1935. changeSelection = TRUE;
  1936. }
  1937. }
  1938. break;
  1939. case VK_HOME:
  1940. //
  1941. // Move caret to top.
  1942. //
  1943. ped->ichCaret = 0;
  1944. //
  1945. // Update selection.
  1946. //
  1947. if (scState & SHFTDOWN)
  1948. {
  1949. if (MaxEqCar && !MinEqMax)
  1950. {
  1951. //
  1952. // Reduce selection
  1953. //
  1954. newMinSel = ped->ichCaret;
  1955. newMaxSel = ped->ichMinSel;
  1956. }
  1957. else
  1958. {
  1959. //
  1960. // Extend selection
  1961. //
  1962. newMinSel = ped->ichCaret;
  1963. }
  1964. }
  1965. else
  1966. {
  1967. //
  1968. // Clear selection
  1969. //
  1970. newMaxSel = newMinSel = ped->ichCaret;
  1971. }
  1972. changeSelection = TRUE;
  1973. break;
  1974. case VK_END:
  1975. //
  1976. // Move caret to end.
  1977. //
  1978. ped->ichCaret = ped->cch;
  1979. //
  1980. // Update selection.
  1981. //
  1982. newMaxSel = ped->ichCaret;
  1983. if (scState & SHFTDOWN)
  1984. {
  1985. if (MinEqCar && !MinEqMax)
  1986. {
  1987. //
  1988. // Reduce selection
  1989. //
  1990. newMinSel = ped->ichMaxSel;
  1991. }
  1992. }
  1993. else
  1994. {
  1995. //
  1996. // Clear selection
  1997. //
  1998. newMinSel = ped->ichCaret;
  1999. }
  2000. changeSelection = TRUE;
  2001. break;
  2002. case VK_DELETE:
  2003. if (ped->fReadOnly)
  2004. {
  2005. break;
  2006. }
  2007. switch (scState)
  2008. {
  2009. case NONEDOWN:
  2010. //
  2011. // Clear selection. If no selection, delete (clear) character
  2012. // right.
  2013. //
  2014. if ((ped->ichMaxSel < ped->cch) && (ped->ichMinSel == ped->ichMaxSel))
  2015. {
  2016. //
  2017. // Move cursor forwards and simulate a backspace.
  2018. //
  2019. if (ped->pLpkEditCallout)
  2020. {
  2021. ped->ichMinSel = ped->ichCaret;
  2022. ped->ichMaxSel = ped->ichCaret = EditSL_MoveSelectionRestricted(ped, ped->ichCaret, FALSE);
  2023. }
  2024. else
  2025. {
  2026. ped->ichCaret = Edit_NextIch(ped,NULL,ped->ichCaret);
  2027. ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
  2028. }
  2029. EditSL_Char(ped, (UINT)VK_BACK);
  2030. }
  2031. if (ped->ichMinSel != ped->ichMaxSel)
  2032. {
  2033. EditSL_Char(ped, (UINT)VK_BACK);
  2034. }
  2035. break;
  2036. case SHFTDOWN:
  2037. //
  2038. // Send ourself a WM_CUT message if a selection exists.
  2039. // Otherwise, delete the left character.
  2040. //
  2041. if (ped->ichMinSel == ped->ichMaxSel)
  2042. {
  2043. UserAssert(!ped->fEatNextChar);
  2044. EditSL_Char(ped, VK_BACK);
  2045. }
  2046. else
  2047. {
  2048. SendMessage(ped->hwnd, WM_CUT, 0, 0L);
  2049. }
  2050. break;
  2051. case CTRLDOWN:
  2052. //
  2053. // Delete to end of line if no selection else delete (clear)
  2054. // selection.
  2055. //
  2056. if ((ped->ichMaxSel < ped->cch) && (ped->ichMinSel == ped->ichMaxSel))
  2057. {
  2058. //
  2059. // Move cursor to end of line and simulate a backspace.
  2060. //
  2061. ped->ichMaxSel = ped->ichCaret = ped->cch;
  2062. }
  2063. if (ped->ichMinSel != ped->ichMaxSel)
  2064. {
  2065. EditSL_Char(ped, (UINT)VK_BACK);
  2066. }
  2067. break;
  2068. }
  2069. //
  2070. // No need to update text or selection since BACKSPACE message does it
  2071. // for us.
  2072. //
  2073. break;
  2074. case VK_INSERT:
  2075. switch (scState)
  2076. {
  2077. case CTRLDOWN:
  2078. //
  2079. // Copy current selection to clipboard
  2080. //
  2081. SendMessage(ped->hwnd, WM_COPY, 0, 0);
  2082. break;
  2083. case SHFTDOWN:
  2084. SendMessage(ped->hwnd, WM_PASTE, 0, 0L);
  2085. break;
  2086. }
  2087. break;
  2088. case VK_HANJA:
  2089. //
  2090. // VK_HANJA support
  2091. //
  2092. if ( HanjaKeyHandler( ped ) )
  2093. {
  2094. changeSelection = TRUE;
  2095. newMinSel = ped->ichCaret;
  2096. newMaxSel = ped->ichCaret + (ped->fAnsi ? 2 : 1);
  2097. }
  2098. break;
  2099. case VK_CAPITAL:
  2100. if (GET_STYLE(ped) & ES_PASSWORD)
  2101. {
  2102. EditSL_CheckCapsLock(ped);
  2103. }
  2104. break;
  2105. case VK_F4:
  2106. case VK_PRIOR:
  2107. case VK_NEXT:
  2108. //
  2109. // Send keys to the listbox if we are a part of a combo box. This
  2110. // assumes the listbox ignores keyup messages which is correct right
  2111. // now.
  2112. //
  2113. SendKeyToListBox:
  2114. if (ped->listboxHwnd)
  2115. {
  2116. //
  2117. // Handle Combobox support
  2118. //
  2119. SendMessage(ped->listboxHwnd, WM_KEYDOWN, virtKeyCode, 0L);
  2120. return;
  2121. }
  2122. }
  2123. if (changeSelection || updateText)
  2124. {
  2125. hdc = Edit_GetDC(ped, FALSE);
  2126. //
  2127. // Scroll if needed
  2128. //
  2129. EditSL_ScrollText(ped, hdc);
  2130. if (changeSelection)
  2131. {
  2132. EditSL_ChangeSelection(ped, hdc, newMinSel, newMaxSel);
  2133. }
  2134. if (updateText)
  2135. {
  2136. EditSL_DrawText(ped, hdc, 0);
  2137. }
  2138. Edit_ReleaseDC(ped, hdc, FALSE);
  2139. if (updateText)
  2140. {
  2141. Edit_NotifyParent(ped, EN_CHANGE);
  2142. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
  2143. }
  2144. }
  2145. }
  2146. //---------------------------------------------------------------------------//
  2147. //
  2148. // EditSL_MouseToIch AorW
  2149. //
  2150. // Returns the closest cch to where the mouse point is.
  2151. //
  2152. ICH EditSL_MouseToIch(PED ped, HDC hdc, LPPOINT mousePt)
  2153. {
  2154. PSTR pText;
  2155. int width = mousePt->x;
  2156. int lastHighWidth, lastLowWidth;
  2157. SIZE size;
  2158. ICH cch;
  2159. ICH cchLo, cchHi;
  2160. LPSTR lpText;
  2161. FnGetTextExtentPoint pGetTextExtentPoint;
  2162. if (ped->pLpkEditCallout)
  2163. {
  2164. pText = Edit_Lock(ped);
  2165. cch = ped->pLpkEditCallout->EditMouseToIch((PED0)ped, hdc, pText, ped->cch, width);
  2166. Edit_Unlock(ped);
  2167. return cch;
  2168. }
  2169. if (width <= ped->rcFmt.left)
  2170. {
  2171. //
  2172. // Return either the first non visible character or return 0 if at
  2173. // beginning of text
  2174. //
  2175. if (ped->ichScreenStart)
  2176. {
  2177. return (ped->ichScreenStart - 1);
  2178. }
  2179. else
  2180. {
  2181. return 0;
  2182. }
  2183. }
  2184. if (width > ped->rcFmt.right)
  2185. {
  2186. pText = Edit_Lock(ped);
  2187. //
  2188. // Return last char in text or one plus the last char visible
  2189. //
  2190. cch = Edit_CchInWidth(ped, hdc,
  2191. (LPSTR)(pText + ped->ichScreenStart * ped->cbChar),
  2192. ped->cch - ped->ichScreenStart, ped->rcFmt.right -
  2193. ped->rcFmt.left, TRUE) + ped->ichScreenStart;
  2194. //
  2195. // This is marked as JAPAN in Win31J. But it should be a DBCS
  2196. // issue. LiZ -- 5/5/93
  2197. // We must check DBCS Lead byte. Because Edit_AdjustIch() pick up Prev Char.
  2198. // 1993.3.9 by yutakas
  2199. //
  2200. if (ped->fAnsi && ped->fDBCS)
  2201. {
  2202. if (cch >= ped->cch)
  2203. {
  2204. cch = ped->cch;
  2205. }
  2206. else
  2207. {
  2208. if (Edit_IsDBCSLeadByte(ped,*(pText+cch)))
  2209. {
  2210. cch += 2;
  2211. }
  2212. else
  2213. {
  2214. cch ++;
  2215. }
  2216. }
  2217. Edit_Unlock(ped);
  2218. return cch;
  2219. }
  2220. else
  2221. {
  2222. Edit_Unlock(ped);
  2223. if (cch >= ped->cch)
  2224. {
  2225. return (ped->cch);
  2226. }
  2227. else
  2228. {
  2229. return (cch + 1);
  2230. }
  2231. }
  2232. }
  2233. if (ped->format != ES_LEFT)
  2234. {
  2235. width -= EditSL_CalcXOffsetSpecial(ped, hdc, ped->ichScreenStart);
  2236. }
  2237. //
  2238. // Check if password hidden chars are being used.
  2239. //
  2240. if (ped->charPasswordChar)
  2241. {
  2242. return min( (DWORD)( (width - ped->rcFmt.left) / ped->cPasswordCharWidth),
  2243. ped->cch);
  2244. }
  2245. if (!ped->cch)
  2246. {
  2247. return 0;
  2248. }
  2249. pText = Edit_Lock(ped);
  2250. lpText = pText + ped->ichScreenStart * ped->cbChar;
  2251. pGetTextExtentPoint = ped->fAnsi ? (FnGetTextExtentPoint)GetTextExtentPointA
  2252. : (FnGetTextExtentPoint)GetTextExtentPointW;
  2253. width -= ped->rcFmt.left;
  2254. //
  2255. // If the user clicked past the end of the text, return the last character
  2256. //
  2257. cchHi = ped->cch - ped->ichScreenStart;
  2258. pGetTextExtentPoint(hdc, lpText, cchHi, &size);
  2259. if (size.cx <= width)
  2260. {
  2261. cch = cchHi;
  2262. goto edAdjust;
  2263. }
  2264. //
  2265. // Initialize Binary Search Bounds
  2266. //
  2267. cchLo = 0;
  2268. cchHi ++;
  2269. lastLowWidth = 0;
  2270. lastHighWidth = size.cx;
  2271. //
  2272. // Binary search for closest char
  2273. //
  2274. while (cchLo < cchHi - 1)
  2275. {
  2276. cch = (cchHi + cchLo) / 2;
  2277. pGetTextExtentPoint(hdc, lpText, cch, &size);
  2278. if (size.cx <= width)
  2279. {
  2280. cchLo = cch;
  2281. lastLowWidth = size.cx;
  2282. }
  2283. else
  2284. {
  2285. cchHi = cch;
  2286. lastHighWidth = size.cx;
  2287. }
  2288. }
  2289. //
  2290. // When the while ends, you can't know the exact position.
  2291. // Try to see if the mouse pointer was on the farest half
  2292. // of the char we got and if so, adjust cch.
  2293. //
  2294. if (cchLo == cch)
  2295. {
  2296. //
  2297. // Need to compare with lastHighWidth
  2298. //
  2299. if ((lastHighWidth - width) < (width - size.cx))
  2300. {
  2301. cch++;
  2302. }
  2303. }
  2304. else
  2305. {
  2306. //
  2307. // Need to compare with lastLowWidth
  2308. //
  2309. if ((width - lastLowWidth) < (size.cx - width))
  2310. {
  2311. cch--;
  2312. }
  2313. }
  2314. edAdjust:
  2315. //
  2316. // Avoid to point the intermediate of double byte character
  2317. //
  2318. cch = Edit_AdjustIch(ped, pText, cch + ped->ichScreenStart);
  2319. Edit_Unlock(ped);
  2320. return cch;
  2321. }
  2322. //---------------------------------------------------------------------------//
  2323. VOID EditSL_MouseMotion(PED ped, UINT message, UINT virtKeyDown, LPPOINT mousePt)
  2324. {
  2325. DWORD selectionl;
  2326. DWORD selectionh;
  2327. BOOL changeSelection;
  2328. ICH newMaxSel;
  2329. ICH newMinSel;
  2330. HDC hdc;
  2331. ICH mouseIch;
  2332. LPSTR pText;
  2333. changeSelection = FALSE;
  2334. newMinSel = ped->ichMinSel;
  2335. newMaxSel = ped->ichMaxSel;
  2336. hdc = Edit_GetDC(ped, FALSE);
  2337. mouseIch = EditSL_MouseToIch(ped, hdc, mousePt);
  2338. switch (message)
  2339. {
  2340. case WM_LBUTTONDBLCLK:
  2341. //
  2342. // if shift key is down, extend selection to word we double clicked on
  2343. // else clear current selection and select word.
  2344. //
  2345. // in DBCS, we have different word breaking. LiZ -- 5/5/93
  2346. // In Hangeul Environment we use word selection feature because Hangeul
  2347. // use SPACE as word break
  2348. //
  2349. if (ped->fAnsi && ped->fDBCS)
  2350. {
  2351. pText = Edit_Lock(ped) + mouseIch;
  2352. Edit_Word(ped, mouseIch,
  2353. (Edit_IsDBCSLeadByte(ped,*pText) && mouseIch < ped->cch) ? FALSE : TRUE,
  2354. &selectionl, &selectionh);
  2355. Edit_Unlock(ped);
  2356. }
  2357. else
  2358. {
  2359. Edit_Word(ped, mouseIch, (mouseIch) ? TRUE : FALSE, &selectionl, &selectionh);
  2360. }
  2361. if (!(virtKeyDown & MK_SHIFT))
  2362. {
  2363. //
  2364. // If shift key isn't down, move caret to mouse point and clear
  2365. // old selection
  2366. //
  2367. newMinSel = selectionl;
  2368. newMaxSel = ped->ichCaret = selectionh;
  2369. }
  2370. else
  2371. {
  2372. //
  2373. // Shiftkey is down so we want to maintain the current selection
  2374. // (if any) and just extend or reduce it
  2375. //
  2376. if (ped->ichMinSel == ped->ichCaret)
  2377. {
  2378. newMinSel = ped->ichCaret = selectionl;
  2379. Edit_Word(ped, newMaxSel, TRUE, &selectionl, &selectionh);
  2380. }
  2381. else
  2382. {
  2383. newMaxSel = ped->ichCaret = selectionh;
  2384. Edit_Word(ped, newMinSel, FALSE, &selectionl, &selectionh);
  2385. }
  2386. ped->ichMaxSel = ped->ichCaret;
  2387. }
  2388. ped->ichStartMinSel = selectionl;
  2389. ped->ichStartMaxSel = selectionh;
  2390. goto InitDragSelect;
  2391. case WM_MOUSEMOVE:
  2392. //
  2393. // We know the mouse button's down -- otherwise the OPTIMIZE
  2394. // test would've failed in EditSL_WndProc and never called
  2395. //
  2396. changeSelection = TRUE;
  2397. //
  2398. // Extend selection, move caret word right
  2399. //
  2400. if (ped->ichStartMinSel || ped->ichStartMaxSel)
  2401. {
  2402. //
  2403. // We're in WORD SELECT mode
  2404. //
  2405. BOOL fReverse = (mouseIch <= ped->ichStartMinSel);
  2406. Edit_Word(ped, mouseIch, !fReverse, &selectionl, &selectionh);
  2407. if (fReverse)
  2408. {
  2409. newMinSel = ped->ichCaret = selectionl;
  2410. newMaxSel = ped->ichStartMaxSel;
  2411. }
  2412. else
  2413. {
  2414. newMinSel = ped->ichStartMinSel;
  2415. newMaxSel = ped->ichCaret = selectionh;
  2416. }
  2417. }
  2418. else if ((ped->ichMinSel == ped->ichCaret) &&
  2419. (ped->ichMinSel != ped->ichMaxSel))
  2420. {
  2421. //
  2422. // Reduce selection extent
  2423. //
  2424. newMinSel = ped->ichCaret = mouseIch;
  2425. }
  2426. else
  2427. {
  2428. // Extend selection extent
  2429. newMaxSel = ped->ichCaret=mouseIch;
  2430. }
  2431. break;
  2432. case WM_LBUTTONDOWN:
  2433. //
  2434. // If we currently don't have the focus yet, try to get it.
  2435. //
  2436. if (!ped->fFocus)
  2437. {
  2438. if (!ped->fNoHideSel)
  2439. {
  2440. //
  2441. // Clear the selection before setting the focus so that we
  2442. // don't get refresh problems and flicker. Doesn't matter
  2443. // since the mouse down will end up changing it anyway.
  2444. //
  2445. ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;
  2446. }
  2447. SetFocus(ped->hwnd);
  2448. //
  2449. // BOGUS
  2450. // (1) We should see if SetFocus() succeeds.
  2451. // (2) We should ignore mouse messages if the first window
  2452. // ancestor with a caption isn't "active."
  2453. //
  2454. // If we are part of a combo box, then this is the first time
  2455. // the edit control is getting the focus so we just want to
  2456. // highlight the selection and we don't really want to position
  2457. // the caret.
  2458. //
  2459. if (ped->listboxHwnd)
  2460. {
  2461. break;
  2462. }
  2463. //
  2464. // We yield at SetFocus -- text might have changed at that point
  2465. // update selection and caret info accordingly
  2466. // FIX for bug # 11743 -- JEFFBOG 8/23/91
  2467. //
  2468. newMaxSel = ped->ichMaxSel;
  2469. newMinSel = ped->ichMinSel;
  2470. mouseIch = min(mouseIch, ped->cch);
  2471. }
  2472. if (ped->fFocus)
  2473. {
  2474. //
  2475. // Only do this if we have the focus since a clever app may not
  2476. // want to give us the focus at the SetFocus call above.
  2477. //
  2478. if (!(virtKeyDown & MK_SHIFT))
  2479. {
  2480. //
  2481. // If shift key isn't down, move caret to mouse point and
  2482. // clear old selection
  2483. //
  2484. newMinSel = newMaxSel = ped->ichCaret = mouseIch;
  2485. }
  2486. else
  2487. {
  2488. //
  2489. // Shiftkey is down so we want to maintain the current
  2490. // selection (if any) and just extend or reduce it
  2491. //
  2492. if (ped->ichMinSel == ped->ichCaret)
  2493. {
  2494. newMinSel = ped->ichCaret = mouseIch;
  2495. }
  2496. else
  2497. {
  2498. newMaxSel = ped->ichCaret = mouseIch;
  2499. }
  2500. }
  2501. ped->ichStartMinSel = ped->ichStartMaxSel = 0;
  2502. InitDragSelect:
  2503. ped->fMouseDown = FALSE;
  2504. SetCapture(ped->hwnd);
  2505. ped->fMouseDown = TRUE;
  2506. changeSelection = TRUE;
  2507. }
  2508. break;
  2509. case WM_LBUTTONUP:
  2510. if (ped->fMouseDown)
  2511. {
  2512. ped->fMouseDown = FALSE;
  2513. ReleaseCapture();
  2514. }
  2515. break;
  2516. }
  2517. if (changeSelection)
  2518. {
  2519. EditSL_ScrollText(ped,hdc);
  2520. EditSL_ChangeSelection(ped, hdc, newMinSel, newMaxSel);
  2521. }
  2522. Edit_ReleaseDC(ped, hdc, FALSE);
  2523. }
  2524. //---------------------------------------------------------------------------//
  2525. //
  2526. // EditSL_Paint AorW
  2527. //
  2528. // Handles painting of the edit control window. Draws the border if
  2529. // necessary and draws the text in its current state.
  2530. //
  2531. VOID EditSL_Paint(PED ped, HDC hdc)
  2532. {
  2533. RECT rcEdit;
  2534. HWND hwnd = ped->hwnd;
  2535. HBRUSH hBrushRemote = NULL;
  2536. BOOL fNeedDelete = FALSE;
  2537. HANDLE hOldFont;
  2538. //
  2539. // Had to put in hide/show carets. The first one needs to be done before
  2540. // beginpaint to correctly paint the caret if part is in the update region
  2541. // and part is out. The second is for 1.03 compatibility. It breaks
  2542. // micrografix's worksheet edit control if not there.
  2543. //
  2544. HideCaret(hwnd);
  2545. if (IsWindowVisible(hwnd))
  2546. {
  2547. CCDBUFFER db;
  2548. //
  2549. // Erase the background since we don't do it in the erasebkgnd message.
  2550. //
  2551. GetClientRect(hwnd, &rcEdit);
  2552. hdc = CCBeginDoubleBuffer(hdc, &rcEdit, &db);
  2553. #ifdef _USE_DRAW_THEME_TEXT_
  2554. if (!ped->hTheme)
  2555. #endif // _USE_DRAW_THEME_TEXT_
  2556. {
  2557. hBrushRemote = Edit_GetBrush(ped, hdc, &fNeedDelete);
  2558. if (hBrushRemote)
  2559. {
  2560. FillRect(hdc, &rcEdit, hBrushRemote);
  2561. if (fNeedDelete)
  2562. {
  2563. DeleteObject(hBrushRemote);
  2564. }
  2565. }
  2566. if (ped->fFlatBorder)
  2567. {
  2568. DrawFrame(hdc, &rcEdit, 1, DF_WINDOWFRAME);
  2569. }
  2570. }
  2571. #ifdef _USE_DRAW_THEME_TEXT_
  2572. else
  2573. {
  2574. HRESULT hr;
  2575. INT iStateId = Edit_GetStateId(ped);
  2576. hr = DrawThemeBackground(ped->hTheme, hdc, EP_EDITTEXT, iStateId, &rcEdit, 0);
  2577. }
  2578. #endif // _USE_DRAW_THEME_TEXT_
  2579. if (ped->hFont != NULL)
  2580. {
  2581. //
  2582. // We have to select in the font since this may be a subclassed dc
  2583. // or a begin paint dc which hasn't been initialized with out fonts
  2584. // like Edit_GetDC does.
  2585. //
  2586. hOldFont = SelectObject(hdc, ped->hFont);
  2587. }
  2588. EditSL_DrawText(ped, hdc, 0);
  2589. if (ped->hFont != NULL && hOldFont != NULL)
  2590. {
  2591. SelectObject(hdc, hOldFont);
  2592. }
  2593. CCEndDoubleBuffer(&db);
  2594. }
  2595. ShowCaret(hwnd);
  2596. }
  2597. //---------------------------------------------------------------------------//
  2598. //
  2599. // EditSL_SetFocus AorW
  2600. //
  2601. // Gives the edit control the focus and notifies the parent
  2602. // EN_SETFOCUS.
  2603. //
  2604. VOID EditSL_SetFocus(PED ped)
  2605. {
  2606. if (!ped->fFocus)
  2607. {
  2608. HDC hdc;
  2609. UINT cxCaret;
  2610. ped->fFocus = TRUE;
  2611. InvalidateRect(ped->hwnd, NULL, TRUE);
  2612. //
  2613. // We don't want to muck with the caret since it isn't created.
  2614. //
  2615. hdc = Edit_GetDC(ped, TRUE);
  2616. //
  2617. // Show the current selection if necessary.
  2618. //
  2619. if (!ped->fNoHideSel)
  2620. {
  2621. EditSL_DrawText(ped, hdc, 0);
  2622. }
  2623. //
  2624. // Create the caret
  2625. //
  2626. SystemParametersInfo(SPI_GETCARETWIDTH, 0, (LPVOID)&cxCaret, 0);
  2627. if (ped->pLpkEditCallout)
  2628. {
  2629. ped->pLpkEditCallout->EditCreateCaret ((PED0)ped, hdc, cxCaret,
  2630. ped->lineHeight, 0);
  2631. }
  2632. else
  2633. {
  2634. CreateCaret(ped->hwnd, (HBITMAP)NULL, cxCaret, ped->lineHeight);
  2635. }
  2636. EditSL_SetCaretPosition(ped, hdc);
  2637. Edit_ReleaseDC(ped, hdc, TRUE);
  2638. ShowCaret(ped->hwnd);
  2639. //
  2640. // check the capslock key
  2641. //
  2642. if (GET_STYLE(ped) & ES_PASSWORD)
  2643. {
  2644. EditSL_CheckCapsLock(ped);
  2645. }
  2646. }
  2647. //
  2648. // Notify parent we have the focus
  2649. //
  2650. Edit_NotifyParent(ped, EN_SETFOCUS);
  2651. }
  2652. //---------------------------------------------------------------------------//
  2653. //
  2654. // EditSL_KillFocus
  2655. //
  2656. // The edit control loses the focus and notifies the parent via EN_KILLFOCUS.
  2657. //
  2658. void EditSL_KillFocus(PED ped, HWND newFocusHwnd)
  2659. {
  2660. HWND hwnd = ped->hwnd;
  2661. if (ped->fFocus)
  2662. {
  2663. DestroyCaret();
  2664. ped->fFocus = FALSE;
  2665. //
  2666. // Do this only if we still have the focus. But we always notify the
  2667. // parent that we lost the focus whether or not we originally had the
  2668. // focus.
  2669. //
  2670. // Hide the current selection if needed
  2671. //
  2672. #ifdef _USE_DRAW_THEME_TEXT_
  2673. if ((!ped->fNoHideSel && (ped->ichMinSel != ped->ichMaxSel)) || ped->hTheme)
  2674. #else
  2675. if ((!ped->fNoHideSel && (ped->ichMinSel != ped->ichMaxSel)))
  2676. #endif // _USE_DRAW_THEME_TEXT_
  2677. {
  2678. InvalidateRect(hwnd, NULL, FALSE);
  2679. }
  2680. }
  2681. //
  2682. // If we aren't a combo box, notify parent that we lost the focus.
  2683. //
  2684. if (!ped->listboxHwnd)
  2685. {
  2686. Edit_NotifyParent(ped, EN_KILLFOCUS);
  2687. }
  2688. else
  2689. {
  2690. //
  2691. // This editcontrol is part of a combo box and is losing the focus. If
  2692. // the focus is NOT being sent to another control in the combo box
  2693. // window, then it means the combo box is losing the focus. So we will
  2694. // notify the combo box of this fact.
  2695. //
  2696. if ((newFocusHwnd == NULL) || (!IsChild(ped->hwndParent, newFocusHwnd)))
  2697. {
  2698. //
  2699. // Excel has a slaker in it's midst. They're not using our combo
  2700. // boxes, but they still expect to get all the internal messages
  2701. // that we give to OUR comboboxes. And they expect them to be at
  2702. // the same offset from WM_USER as they were in 3.1.
  2703. // (JEFFBOG - 01/26/94)
  2704. //
  2705. // Focus is being sent to a window which is not a child of the combo
  2706. // box window which implies that the combo box is losing the focus.
  2707. // Send a message to the combo box informing him of this fact so
  2708. // that he can clean up...
  2709. //
  2710. SendMessage(ped->hwndParent, CBEC_KILLCOMBOFOCUS, 0, 0L);
  2711. }
  2712. }
  2713. //
  2714. // If we're still valid, invalidate to cause a redraw. It's common
  2715. // for some controls be destroyed after losing focus.
  2716. //
  2717. if ( IsWindow(hwnd) )
  2718. {
  2719. InvalidateRect(hwnd, NULL, FALSE);
  2720. }
  2721. }
  2722. //---------------------------------------------------------------------------//
  2723. //
  2724. // EditSL_Paste()
  2725. //
  2726. // Does actual text paste and update.
  2727. //
  2728. VOID EditSL_Paste(PED ped)
  2729. {
  2730. HDC hdc;
  2731. //
  2732. // Insert contents of clipboard, after unhilighting current selection
  2733. // and deleting it.
  2734. //
  2735. Edit_DeleteText(ped);
  2736. EditSL_PasteText(ped);
  2737. //
  2738. // Update display
  2739. //
  2740. Edit_NotifyParent(ped, EN_UPDATE);
  2741. hdc = Edit_GetDC(ped,FALSE);
  2742. EditSL_ScrollText(ped, hdc);
  2743. EditSL_DrawText(ped, hdc, 0);
  2744. Edit_ReleaseDC(ped,hdc,FALSE);
  2745. //
  2746. // Tell parent our text contents changed.
  2747. //
  2748. Edit_NotifyParent(ped, EN_CHANGE);
  2749. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
  2750. }
  2751. //---------------------------------------------------------------------------//
  2752. //
  2753. // EditSL_Create
  2754. //
  2755. // Creates the edit control for the window hwnd by allocating memory
  2756. // as required from the application's heap. Notifies parent if no memory
  2757. // error (after cleaning up if needed). Returns TRUE if no error else return s
  2758. // -1.
  2759. //
  2760. LONG EditSL_Create(PED ped, LPCREATESTRUCT lpCreateStruct)
  2761. {
  2762. LPSTR lpWindowText;
  2763. LONG windowStyle = GET_STYLE(ped);
  2764. //
  2765. // Do the standard creation stuff
  2766. //
  2767. if (!Edit_Create(ped, windowStyle))
  2768. {
  2769. return -1;
  2770. }
  2771. //
  2772. // Single lines always have no undo and 1 line
  2773. //
  2774. ped->cLines = 1;
  2775. ped->undoType = UNDO_NONE;
  2776. //
  2777. // Check if this edit control is part of a combobox and get a pointer to the
  2778. // combobox structure.
  2779. //
  2780. if (windowStyle & ES_COMBOBOX)
  2781. {
  2782. ped->listboxHwnd = GetDlgItem(lpCreateStruct->hwndParent, CBLISTBOXID);
  2783. }
  2784. //
  2785. // Set the default font to be the system font.
  2786. //
  2787. if ( !Edit_SetFont(ped, NULL, FALSE) )
  2788. {
  2789. // If setting the font fails, our textmetrics can potentially be left
  2790. // unitialize. Fail to create the control.
  2791. return -1;
  2792. }
  2793. //
  2794. // Set the window text if needed. Return false if we can't set the text
  2795. // SLSetText notifies the parent in case there is a no memory error.
  2796. //
  2797. lpWindowText = (LPSTR)lpCreateStruct->lpszName;
  2798. if ((lpWindowText != NULL)
  2799. && !IsEmptyString(lpWindowText, ped->fAnsi)
  2800. && !Edit_SetEditText(ped, lpWindowText))
  2801. {
  2802. return -1;
  2803. }
  2804. if (windowStyle & ES_PASSWORD)
  2805. {
  2806. LOGFONT lfFont = {0};
  2807. LoadString(HINST_THISDLL, IDS_PASSWORDCHARFONT, lfFont.lfFaceName, ARRAYSIZE(lfFont.lfFaceName));
  2808. lfFont.lfWeight = FW_NORMAL;
  2809. lfFont.lfCharSet = DEFAULT_CHARSET;
  2810. ped->hFontPassword = CreateFontIndirect(&lfFont);
  2811. if (ped->hFontPassword && Edit_SetFont(ped, ped->hFontPassword, FALSE))
  2812. {
  2813. WCHAR szChar[10];
  2814. UINT uChar;
  2815. LoadString(HINST_THISDLL, IDS_PASSWORDCHAR, szChar, ARRAYSIZE(szChar));
  2816. uChar = StrToInt(szChar);
  2817. Edit_SetPasswordCharHandler(ped, uChar);
  2818. }
  2819. else
  2820. {
  2821. Edit_SetPasswordCharHandler(ped, (UINT)'*');
  2822. }
  2823. }
  2824. //
  2825. // Since memory cleared to 0 when allocated, this should still be NULL
  2826. //
  2827. ASSERT(ped->pszCueBannerText == NULL);
  2828. return TRUE;
  2829. }
  2830. //---------------------------------------------------------------------------//
  2831. //
  2832. // EditSL_Undo AorW
  2833. //
  2834. // Handles UNDO for single line edit controls.
  2835. //
  2836. BOOL EditSL_Undo(PED ped)
  2837. {
  2838. PBYTE hDeletedText = ped->hDeletedText;
  2839. BOOL fDelete = (BOOL)(ped->undoType & UNDO_DELETE);
  2840. ICH cchDeleted = ped->cchDeleted;
  2841. ICH ichDeleted = ped->ichDeleted;
  2842. BOOL fUpdate = FALSE;
  2843. if (ped->undoType == UNDO_NONE)
  2844. {
  2845. //
  2846. // No undo...
  2847. //
  2848. return FALSE;
  2849. }
  2850. ped->hDeletedText = NULL;
  2851. ped->cchDeleted = 0;
  2852. ped->ichDeleted = (ICH)-1;
  2853. ped->undoType &= ~UNDO_DELETE;
  2854. if (ped->undoType == UNDO_INSERT)
  2855. {
  2856. ped->undoType = UNDO_NONE;
  2857. //
  2858. // Set the selection to the inserted text
  2859. //
  2860. EditSL_SetSelection(ped, ped->ichInsStart, ped->ichInsEnd);
  2861. ped->ichInsStart = ped->ichInsEnd = (ICH)-1;
  2862. //
  2863. // Delete the selected text and save it in undo buff.
  2864. // Call Edit_DeleteText() instead of sending a VK_BACK message
  2865. // which results in an EN_UPDATE notification send even before
  2866. // we insert the deleted chars. This results in Bug #6610.
  2867. // Fix for Bug #6610 -- SANKAR -- 04/19/91 --
  2868. //
  2869. if (Edit_DeleteText(ped))
  2870. {
  2871. //
  2872. // Text was deleted -- flag for update and clear selection
  2873. //
  2874. fUpdate = TRUE;
  2875. EditSL_SetSelection(ped, ichDeleted, ichDeleted);
  2876. }
  2877. }
  2878. if (fDelete)
  2879. {
  2880. HWND hwndSave = ped->hwnd; // Used for validation.
  2881. //
  2882. // Insert deleted chars. Set the selection to the inserted text.
  2883. //
  2884. EditSL_SetSelection(ped, ichDeleted, ichDeleted);
  2885. EditSL_InsertText(ped, hDeletedText, cchDeleted);
  2886. GlobalFree(hDeletedText);
  2887. if (!IsWindow(hwndSave))
  2888. {
  2889. return FALSE;
  2890. }
  2891. EditSL_SetSelection(ped, ichDeleted, ichDeleted + cchDeleted);
  2892. fUpdate = TRUE;
  2893. }
  2894. if (fUpdate)
  2895. {
  2896. //
  2897. // If we have something to update, send EN_UPDATE before and
  2898. // EN_CHANGE after the actual update.
  2899. // A part of the fix for Bug #6610 -- SANKAR -- 04/19/91 --
  2900. //
  2901. Edit_NotifyParent(ped, EN_UPDATE);
  2902. if (IsWindowVisible(ped->hwnd))
  2903. {
  2904. Edit_InvalidateClient(ped, FALSE);
  2905. }
  2906. Edit_NotifyParent(ped, EN_CHANGE);
  2907. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
  2908. }
  2909. return TRUE;
  2910. }
  2911. //---------------------------------------------------------------------------//
  2912. //
  2913. // EditSL_SetCueBanner (Unicode Only)
  2914. //
  2915. // Handles setting the cue banner text for an edit control.
  2916. //
  2917. BOOL EditSL_SetCueBanner(PED ped, LPCWSTR pszBanner)
  2918. {
  2919. BOOL retVal = FALSE;
  2920. if (pszBanner != NULL)
  2921. {
  2922. //
  2923. // Store the input string into the ped's pointer. Str_SetPtr will
  2924. // allocate/free memory as needed.
  2925. //
  2926. retVal = Str_SetPtr(&(ped->pszCueBannerText), pszBanner);
  2927. //
  2928. // Redraw the control
  2929. //
  2930. InvalidateRect(ped->hwnd, NULL, FALSE);
  2931. }
  2932. return retVal;
  2933. }
  2934. //---------------------------------------------------------------------------//
  2935. //
  2936. // EditSL_WndProc
  2937. //
  2938. // Class procedure for all single line edit controls.
  2939. // Dispatches all messages to the appropriate handlers which are named
  2940. // as follows:
  2941. // EditSL_ (single line) prefixes all single line edit control procedures while
  2942. // Edit_ (edit control) prefixes all common handlers.
  2943. //
  2944. // The EditSL_WndProc only handles messages specific to single line edit
  2945. // controls.
  2946. //
  2947. LRESULT EditSL_WndProc(PED ped, UINT message, WPARAM wParam, LPARAM lParam)
  2948. {
  2949. HDC hdc;
  2950. PAINTSTRUCT ps;
  2951. POINT pt;
  2952. switch (message)
  2953. {
  2954. case WM_INPUTLANGCHANGE:
  2955. if (ped && ped->fFocus && ped->pLpkEditCallout)
  2956. {
  2957. UINT cxCaret;
  2958. SystemParametersInfo(SPI_GETCARETWIDTH, 0, (LPVOID)&cxCaret, 0);
  2959. HideCaret(ped->hwnd);
  2960. hdc = Edit_GetDC(ped, TRUE);
  2961. DestroyCaret();
  2962. ped->pLpkEditCallout->EditCreateCaret ((PED0)ped, hdc, cxCaret, ped->lineHeight, (UINT)lParam);
  2963. EditSL_SetCaretPosition(ped, hdc);
  2964. Edit_ReleaseDC(ped, hdc, TRUE);
  2965. ShowCaret(ped->hwnd);
  2966. }
  2967. goto PassToDefaultWindowProc;
  2968. case WM_STYLECHANGED:
  2969. if (ped && ped->pLpkEditCallout)
  2970. {
  2971. switch (wParam)
  2972. {
  2973. case GWL_STYLE:
  2974. Edit_UpdateFormat(ped, ((LPSTYLESTRUCT)lParam)->styleNew, GET_EXSTYLE(ped));
  2975. return 1L;
  2976. case GWL_EXSTYLE:
  2977. Edit_UpdateFormat(ped, GET_STYLE(ped), ((LPSTYLESTRUCT)lParam)->styleNew);
  2978. return 1L;
  2979. }
  2980. }
  2981. goto PassToDefaultWindowProc;
  2982. case WM_CHAR:
  2983. //
  2984. // wParam - the value of the key
  2985. // lParam - modifiers, repeat count etc (not used)
  2986. //
  2987. if (!ped->fEatNextChar)
  2988. {
  2989. EditSL_Char(ped, (UINT)wParam);
  2990. }
  2991. else
  2992. {
  2993. ped->fEatNextChar = FALSE;
  2994. }
  2995. break;
  2996. case WM_ERASEBKGND:
  2997. //
  2998. // wParam - device context handle
  2999. // lParam - not used
  3000. // We do nothing on this message and we don't want DefWndProc to do
  3001. // anything, so return 1
  3002. //
  3003. return 1;
  3004. case WM_GETDLGCODE:
  3005. {
  3006. LONG code = DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS;
  3007. //
  3008. // If this is a WM_SYSCHAR message generated by the UNDO keystroke
  3009. // we want this message so we can EAT IT in "case WM_SYSCHAR:"
  3010. //
  3011. if (lParam)
  3012. {
  3013. switch (((LPMSG)lParam)->message)
  3014. {
  3015. case WM_SYSCHAR:
  3016. if ((HIWORD(((LPMSG)lParam)->lParam) & SYS_ALTERNATE) &&
  3017. ((WORD)wParam == VK_BACK))
  3018. {
  3019. code |= DLGC_WANTMESSAGE;
  3020. }
  3021. break;
  3022. case WM_KEYDOWN:
  3023. if (( (((WORD)wParam == VK_RETURN) ||
  3024. ((WORD)wParam == VK_ESCAPE)) &&
  3025. (ped->listboxHwnd) &&
  3026. (GetWindowStyle(ped->hwndParent) & CBS_DROPDOWN) &&
  3027. SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L)))
  3028. {
  3029. code |= DLGC_WANTMESSAGE;
  3030. }
  3031. break;
  3032. }
  3033. }
  3034. return code;
  3035. }
  3036. break;
  3037. case WM_KEYDOWN:
  3038. //
  3039. // wParam - virt keycode of the given key
  3040. // lParam - modifiers such as repeat count etc. (not used)
  3041. //
  3042. EditSL_KeyDown(ped, (UINT)wParam, 0);
  3043. break;
  3044. case WM_KILLFOCUS:
  3045. //
  3046. // wParam - handle of the window that receives the input focus
  3047. // lParam - not used
  3048. //
  3049. EditSL_KillFocus(ped, (HWND)wParam);
  3050. break;
  3051. case WM_CAPTURECHANGED:
  3052. if (ped->fMouseDown)
  3053. {
  3054. ped->fMouseDown = FALSE;
  3055. }
  3056. break;
  3057. case WM_MOUSEMOVE:
  3058. UserAssert(ped->fMouseDown);
  3059. //
  3060. // FALL THRU
  3061. //
  3062. case WM_LBUTTONDBLCLK:
  3063. case WM_LBUTTONDOWN:
  3064. case WM_LBUTTONUP:
  3065. //
  3066. // wParam - contains a value that indicates which virtual keys are down
  3067. // lParam - contains x and y coords of the mouse cursor
  3068. //
  3069. POINTSTOPOINT(pt, lParam);
  3070. EditSL_MouseMotion(ped, message, (UINT)wParam, &pt);
  3071. break;
  3072. case WM_CREATE:
  3073. //
  3074. // wParam - handle to window being created
  3075. // lParam - points to a CREATESTRUCT that contains copies of parameters
  3076. // passed to the CreateWindow function.
  3077. //
  3078. return EditSL_Create(ped, (LPCREATESTRUCT)lParam);
  3079. break;
  3080. case WM_PRINTCLIENT:
  3081. //
  3082. // wParam -- can be hdc from subclassed paint
  3083. // lParam -- unused
  3084. //
  3085. EditSL_Paint(ped, (HDC) wParam);
  3086. break;
  3087. case WM_PAINT:
  3088. //
  3089. // wParam -- can be hdc from subclassed paint
  3090. // lParam -- unused
  3091. //
  3092. if (wParam)
  3093. {
  3094. hdc = (HDC) wParam;
  3095. }
  3096. else
  3097. {
  3098. //
  3099. // this hide/show caret is outside Begin/EndPaint to handle the
  3100. // case when the caret is half in/half out of the update region
  3101. //
  3102. HideCaret(ped->hwnd);
  3103. hdc = BeginPaint(ped->hwnd, &ps);
  3104. }
  3105. //
  3106. // PORTPORT: Note the symantics of IsWindowVisible and _IsWindowVisible are
  3107. // slightly different.
  3108. //
  3109. if (IsWindowVisible(ped->hwnd))
  3110. {
  3111. EditSL_Paint(ped, hdc);
  3112. }
  3113. if (!wParam)
  3114. {
  3115. EndPaint(ped->hwnd, &ps);
  3116. ShowCaret(ped->hwnd);
  3117. }
  3118. break;
  3119. case WM_PASTE:
  3120. //
  3121. // wParam - not used
  3122. // lParam - not used
  3123. //
  3124. if (!ped->fReadOnly)
  3125. {
  3126. EditSL_Paste(ped);
  3127. }
  3128. break;
  3129. case WM_SETFOCUS:
  3130. //
  3131. // wParam - handle of window that loses the input focus (may be NULL)
  3132. // lParam - not used
  3133. //
  3134. EditSL_SetFocus(ped);
  3135. break;
  3136. case WM_SIZE:
  3137. // wParam - defines the type of resizing fullscreen, sizeiconic,
  3138. // sizenormal etc.
  3139. // lParam - new width in LOWORD, new height in HIGHWORD of client area
  3140. Edit_Size(ped, NULL, TRUE);
  3141. return 0;
  3142. case WM_SYSKEYDOWN:
  3143. //
  3144. // wParam -- virtual key code
  3145. // lParam -- modifiers
  3146. //
  3147. //
  3148. // Are we in a combobox with the Alt key down?
  3149. //
  3150. if (ped->listboxHwnd && (lParam & 0x20000000L))
  3151. {
  3152. //
  3153. // Handle Combobox support. We want alt up or down arrow to behave
  3154. // like F4 key which completes the combo box selection
  3155. //
  3156. if (lParam & 0x1000000)
  3157. {
  3158. //
  3159. // This is an extended key such as the arrow keys not on the
  3160. // numeric keypad so just drop the combobox.
  3161. //
  3162. if (wParam == VK_DOWN || wParam == VK_UP)
  3163. {
  3164. goto DropCombo;
  3165. }
  3166. else
  3167. {
  3168. goto SkipDropCombo;
  3169. }
  3170. }
  3171. if (!(GetKeyState(VK_NUMLOCK) & 1) &&
  3172. (wParam == VK_DOWN || wParam == VK_UP))
  3173. {
  3174. //
  3175. // NUMLOCK is up and the keypad up or down arrow hit:
  3176. // eat character generated by keyboard driver.
  3177. //
  3178. ped->fEatNextChar = TRUE;
  3179. }
  3180. else
  3181. {
  3182. goto SkipDropCombo;
  3183. }
  3184. DropCombo:
  3185. if (SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0) & 0x00000001)
  3186. {
  3187. //
  3188. // Extended ui doesn't honor VK_F4.
  3189. //
  3190. if (SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0))
  3191. {
  3192. return SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 0, 0);
  3193. }
  3194. else
  3195. {
  3196. return SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 1, 0);
  3197. }
  3198. }
  3199. else
  3200. {
  3201. return SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0);
  3202. }
  3203. }
  3204. SkipDropCombo:
  3205. if (wParam == VK_BACK)
  3206. {
  3207. SendMessage(ped->hwnd, WM_UNDO, 0, 0L);
  3208. break;
  3209. }
  3210. else
  3211. {
  3212. goto PassToDefaultWindowProc;
  3213. }
  3214. break;
  3215. case EM_GETLINE:
  3216. //
  3217. // wParam - line number to copy (always the first line for SL)
  3218. // lParam - buffer to copy text to. FIrst word is max # of bytes to copy
  3219. //
  3220. return Edit_GetTextHandler(ped, (*(LPWORD)lParam), (LPSTR)lParam, FALSE);
  3221. case EM_LINELENGTH:
  3222. //
  3223. // wParam - ignored
  3224. // lParam - ignored
  3225. //
  3226. return (LONG)ped->cch;
  3227. case EM_SETSEL:
  3228. //
  3229. // wParam -- start pos
  3230. // lParam -- end pos
  3231. //
  3232. EditSL_SetSelection(ped, (ICH)wParam, (ICH)lParam);
  3233. break;
  3234. case EM_REPLACESEL:
  3235. //
  3236. // wParam - flag for 4.0+ apps saying whether to clear undo
  3237. // lParam - points to a null terminated string of replacement text
  3238. //
  3239. EditSL_ReplaceSel(ped, (LPSTR)lParam);
  3240. if (!ped->f40Compat || !wParam)
  3241. {
  3242. Edit_EmptyUndo(Pundo(ped));
  3243. }
  3244. break;
  3245. case EM_GETFIRSTVISIBLELINE:
  3246. //
  3247. // wParam - not used
  3248. // lParam - not used
  3249. //
  3250. // effects: Returns the first visible line for single line edit controls.
  3251. //
  3252. return ped->ichScreenStart;
  3253. case EM_POSFROMCHAR:
  3254. //
  3255. // wParam -- char index in text
  3256. // lParam -- not used
  3257. // This function returns the (x,y) position of the character.
  3258. // y is always 0 for single.
  3259. //
  3260. case EM_CHARFROMPOS:
  3261. //
  3262. // wParam -- unused
  3263. // lParam -- pt in edit client coords
  3264. // This function returns
  3265. // LOWORD: the position of the _closest_ char
  3266. // to the passed in point.
  3267. // HIWORD: the index of the line (always 0 for single)
  3268. {
  3269. LONG xyPos;
  3270. hdc = Edit_GetDC(ped, TRUE);
  3271. if (message == EM_POSFROMCHAR)
  3272. {
  3273. xyPos = MAKELONG(EditSL_IchToLeftXPos(ped, hdc, (ICH)wParam), 0);
  3274. }
  3275. else
  3276. {
  3277. POINTSTOPOINT(pt, lParam);
  3278. xyPos = EditSL_MouseToIch(ped, hdc, &pt);
  3279. }
  3280. Edit_ReleaseDC(ped, hdc, TRUE);
  3281. return (LRESULT)xyPos;
  3282. }
  3283. case WM_UNDO:
  3284. case EM_UNDO:
  3285. EditSL_Undo(ped);
  3286. break;
  3287. case EM_SETCUEBANNER:
  3288. //
  3289. // This message passes in a LPCWSTR as the lParam to set the
  3290. // cue banner text.
  3291. //
  3292. // Call function to set the text:
  3293. return (LRESULT)EditSL_SetCueBanner(ped, (LPCWSTR) lParam);
  3294. break;
  3295. default:
  3296. PassToDefaultWindowProc:
  3297. return DefWindowProc(ped->hwnd, message, wParam, lParam);
  3298. break;
  3299. }
  3300. return 1L;
  3301. }