Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1785 lines
52 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * EDITSL.C
  8. * Win16 edit control code
  9. *
  10. * History:
  11. *
  12. * Created 28-May-1991 by Jeff Parsons (jeffpar)
  13. * Copied from WIN31 and edited (as little as possible) for WOW16.
  14. --*/
  15. /****************************************************************************/
  16. /* editsl.c - Edit controls rewrite. Version II of edit controls. */
  17. /* */
  18. /* */
  19. /* Created: 24-Jul-88 davidds */
  20. /****************************************************************************/
  21. #define NO_LOCALOBJ_TAGS
  22. #include "user.h"
  23. #include "edit.h"
  24. /****************************************************************************/
  25. /* Single Line Support Routines */
  26. /****************************************************************************/
  27. void FAR PASCAL SLSetCaretPosition(ped,hdc)
  28. register PED ped;
  29. HDC hdc;
  30. /* effects: If the window has the focus, find where the caret belongs and move
  31. * it there.
  32. */
  33. {
  34. int xPosition;
  35. /* We will only position the caret if we have the focus since we don't want
  36. * to move the caret while another window could own it.
  37. */
  38. if (ped->fNoRedraw || !ped->fFocus)
  39. return;
  40. xPosition = SLIchToLeftXPos(ped, hdc, ped->ichCaret);
  41. if (!ped->fAutoHScroll)
  42. /* Don't leet caret go out of bounds of edit contol if there is too much
  43. * text in a non scrolling edit control.
  44. */
  45. xPosition = min(xPosition, ped->rcFmt.right-1);
  46. SetCaretPos(xPosition, ped->rcFmt.top);
  47. }
  48. int NEAR PASCAL SLIchToLeftXPos(ped, hdc, ich)
  49. register PED ped;
  50. HDC hdc;
  51. ICH ich;
  52. /* effects: Given a character index, find its (left side) x coordinate within
  53. * the ped->rcFmt rectangle assuming the character ped->screenStart is at
  54. * coordinates (ped->rcFmt.top, ped->rcFmt.left). A negative value is
  55. * returned if the character ich is to the left of ped->screenStart. WARNING:
  56. * ASSUMES AT MOST 1000 characters will be VISIBLE at one time on the screen.
  57. * There may be 64K total characters in the editcontrol, but we can only
  58. * display 1000 without scrolling. This shouldn't be a problem obviously.
  59. */
  60. {
  61. int textExtent;
  62. register PSTR pText;
  63. /* Check if we are adding lots and lots of chars. A paste for example could
  64. * cause this and GetTextExtents could overflow on this.
  65. */
  66. if (ich > ped->screenStart && ich - ped->screenStart > 1000)
  67. return(30000);
  68. if (ped->screenStart > ich && ped->screenStart - ich > 1000)
  69. return(-30000);
  70. if (ped->fNonPropFont)
  71. return((ich-ped->screenStart)*ped->aveCharWidth + ped->rcFmt.left);
  72. /* Check if password hidden chars are being used. */
  73. if (ped->charPasswordChar)
  74. return((ich-ped->screenStart)*ped->cPasswordCharWidth+ped->rcFmt.left);
  75. pText = LocalLock(ped->hText);
  76. if (ped->screenStart <= ich)
  77. {
  78. textExtent = LOWORD(GetTextExtent(hdc,
  79. (LPSTR)(pText + ped->screenStart),
  80. ich-ped->screenStart));
  81. /* In case of signed/unsigned overflow since the text extent may be
  82. * greater than maxint. This happens with long single line edit
  83. * controls. The rect we edit text in will never be greater than 30000
  84. * pixels so we are ok if we just ignore them.
  85. */
  86. if (textExtent < 0 || textExtent > 31000)
  87. textExtent = 30000;
  88. }
  89. else
  90. textExtent = (-1) *
  91. (int)LOWORD(GetTextExtent(hdc,(LPSTR)(pText + ich),
  92. ped->screenStart-ich));
  93. LocalUnlock(ped->hText);
  94. return(textExtent-ped->charOverhang + ped->rcFmt.left);
  95. }
  96. /* effects: This finds out if the given ichPos falls within the current
  97. * Selection range and if so returns TRUE; Else returns FALSE.
  98. */
  99. BOOL NEAR PASCAL SLGetHiliteAttr(PED ped, ICH ichPos)
  100. {
  101. return((ichPos >= ped->ichMinSel) && (ichPos < ped->ichMaxSel));
  102. }
  103. /* effects: This takes care of erasing the old selection and drawing the new
  104. * selection
  105. */
  106. void NEAR PASCAL SLRepaintChangedSelection(
  107. PED ped, HDC hdc,
  108. ICH ichOldMinSel, ICH ichOldMaxSel)
  109. {
  110. BLOCK Blk[2];
  111. int i;
  112. Blk[0].StPos = ichOldMinSel;
  113. Blk[0].EndPos = ichOldMaxSel;
  114. Blk[1].StPos = ped->ichMinSel;
  115. Blk[1].EndPos = ped->ichMaxSel;
  116. if(ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
  117. (LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1]))
  118. {
  119. UpdateWindow(ped->hwnd);
  120. /* Paint the rectangles where selection has changed */
  121. /* Paint both Blk[0] and Blk[1], if they exist */
  122. for(i = 0; i < 2; i++)
  123. {
  124. if (Blk[i].StPos != -1)
  125. SLDrawLine(ped, hdc, Blk[i].StPos, Blk[i].EndPos - Blk[i].StPos,
  126. SLGetHiliteAttr(ped, Blk[i].StPos));
  127. }
  128. }
  129. }
  130. void FAR PASCAL SLChangeSelection(ped, hdc, ichNewMinSel, ichNewMaxSel)
  131. register PED ped;
  132. HDC hdc;
  133. ICH ichNewMinSel;
  134. ICH ichNewMaxSel;
  135. /* effects: Changes the current selection to have the specified starting and
  136. * ending values. Properly highlights the new selection and unhighlights
  137. * anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
  138. * them. Doesn't update the caret position.
  139. */
  140. {
  141. ICH temp;
  142. ICH ichOldMinSel;
  143. ICH ichOldMaxSel;
  144. if (ichNewMinSel > ichNewMaxSel)
  145. {
  146. temp = ichNewMinSel;
  147. ichNewMinSel = ichNewMaxSel;
  148. ichNewMaxSel = temp;
  149. }
  150. ichNewMinSel = umin(ichNewMinSel, ped->cch);
  151. ichNewMaxSel = umin(ichNewMaxSel, ped->cch);
  152. /* Preserve the Old selection */
  153. ichOldMinSel = ped->ichMinSel;
  154. ichOldMaxSel = ped->ichMaxSel;
  155. /* Set new selection */
  156. ped->ichMinSel = ichNewMinSel;
  157. ped->ichMaxSel = ichNewMaxSel;
  158. /* We will find the intersection of current selection rectangle with the new
  159. * selection rectangle. We will then invert the parts of the two rectangles
  160. * not in the intersection.
  161. */
  162. if (!ped->fNoRedraw && (ped->fFocus || ped->fNoHideSel))
  163. {
  164. if (ped->fFocus)
  165. HideCaret(ped->hwnd);
  166. SLRepaintChangedSelection(ped, hdc, ichOldMinSel, ichOldMaxSel);
  167. SLSetCaretPosition(ped,hdc);
  168. if (ped->fFocus)
  169. ShowCaret(ped->hwnd);
  170. }
  171. }
  172. void NEAR PASCAL SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus)
  173. register PED ped;
  174. register HDC hdc;
  175. ICH ichStart;
  176. int iCount;
  177. BOOL fSelStatus;
  178. /* This draws the line starting from ichStart, iCount number of characters;
  179. * fSelStatus is TRUE, if it is to be drawn with the "selection" attribute.
  180. */
  181. {
  182. RECT rc;
  183. HBRUSH hBrush;
  184. PSTR pText;
  185. DWORD rgbSaveBk;
  186. DWORD rgbSaveText;
  187. int iStCount;
  188. DWORD rgbGray=0;
  189. if (ped->fNoRedraw)
  190. return;
  191. if (ichStart < ped->screenStart)
  192. {
  193. if (ichStart+iCount < ped->screenStart)
  194. return;
  195. iCount = iCount - (ped->screenStart-ichStart);
  196. ichStart = ped->screenStart;
  197. }
  198. CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
  199. /* Set the proper clipping rectangle */
  200. ECSetEditClip(ped, hdc);
  201. pText = (PSTR) LocalLock(ped->hText);
  202. /* Calculates the rectangle area to be wiped out */
  203. if (iStCount = ichStart - ped->screenStart)
  204. {
  205. if (ped->charPasswordChar)
  206. rc.left += ped->cPasswordCharWidth * iStCount;
  207. else
  208. rc.left += LOWORD(GetTextExtent(hdc,
  209. (LPSTR)(pText + ped->screenStart),
  210. iStCount)) -
  211. ped->charOverhang;
  212. }
  213. if (ped->charPasswordChar)
  214. rc.right = rc.left + ped->cPasswordCharWidth * iCount;
  215. else
  216. rc.right = rc.left + LOWORD(GetTextExtent(hdc,
  217. (LPSTR)(pText + ichStart),
  218. iCount));
  219. /* Set the background mode before calling GetControlBrush so that the app
  220. * can change it to TRANSPARENT if it wants to.
  221. */
  222. SetBkMode(hdc, OPAQUE);
  223. if (fSelStatus)
  224. {
  225. hBrush = ped->hbrHiliteBk;
  226. rgbSaveBk = SetBkColor(hdc, ped->rgbHiliteBk);
  227. rgbSaveText = SetTextColor(hdc, ped->rgbHiliteText);
  228. }
  229. else
  230. {
  231. /* We always want to send this so that the app has a chance to muck with
  232. * the DC
  233. */
  234. hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
  235. }
  236. if (ped->fDisabled &&
  237. (rgbGray = GetSysColor(COLOR_GRAYTEXT)))
  238. {
  239. /* Grey the text in the edit control if disabled.
  240. */
  241. rgbSaveText = SetTextColor(hdc, rgbGray);
  242. }
  243. /* Erase the rectangular area before text is drawn. Note that we inflate the
  244. * rect by 1 so that the selection color has a one pixel border around the
  245. * text.
  246. */
  247. InflateRect((LPRECT)&rc, 0, 1);
  248. /* Use paint rect so that the brush gets aligned if dithered.
  249. */
  250. PaintRect(ped->hwndParent, ped->hwnd, hdc, hBrush, (LPRECT)&rc);
  251. InflateRect((LPRECT)&rc, 0, -1);
  252. if (ped->charPasswordChar)
  253. {
  254. for (iStCount = 0; iStCount < iCount; iStCount++)
  255. TextOut(hdc,
  256. rc.left+iStCount*ped->cPasswordCharWidth,
  257. rc.top,
  258. (LPSTR)&ped->charPasswordChar,
  259. 1);
  260. }
  261. else
  262. TextOut(hdc,rc.left,rc.top,(LPSTR)(pText+ichStart),iCount);
  263. if (fSelStatus || rgbGray)
  264. {
  265. SetTextColor(hdc, rgbSaveText);
  266. if (fSelStatus)
  267. SetBkColor(hdc, rgbSaveBk);
  268. }
  269. LocalUnlock(ped->hText);
  270. }
  271. int NEAR PASCAL SLGetBlkEnd(ped, ichStart, ichEnd, lpfStatus)
  272. register PED ped;
  273. register ICH ichStart;
  274. ICH ichEnd;
  275. BOOL FAR *lpfStatus;
  276. /* Given a Starting point and and end point, this function returns whether the
  277. * first few characters fall inside or outside the selection block and if so,
  278. * howmany characters?
  279. */
  280. {
  281. *lpfStatus = FALSE;
  282. if (ichStart >= ped->ichMinSel)
  283. {
  284. if(ichStart >= ped->ichMaxSel)
  285. return(ichEnd - ichStart);
  286. *lpfStatus = TRUE;
  287. return(min(ichEnd, ped->ichMaxSel) - ichStart);
  288. }
  289. return(min(ichEnd, ped->ichMinSel) - ichStart);
  290. }
  291. void NEAR PASCAL SLDrawText(ped, hdc, ichStart)
  292. register PED ped;
  293. register HDC hdc;
  294. ICH ichStart;
  295. /* effects: Draws text for a single line edit control in the rectangle
  296. * specified by ped->rcFmt. If ichStart == 0, starts drawing text at the left
  297. * side of the window starting at character index ped->screenStart and draws
  298. * as much as will fit. If ichStart > 0, then it appends the characters
  299. * starting at ichStart to the end of the text showing in the window. (ie. We
  300. * are just growing the text length and keeping the left side
  301. * (ped->screenStart to ichStart characters) the same. Assumes the hdc came
  302. * from ECGetEditDC so that the caret and such are properly hidden.
  303. */
  304. {
  305. ICH cchToDraw;
  306. RECT rc;
  307. PSTR pText;
  308. BOOL fSelStatus;
  309. int iCount;
  310. ICH ichEnd;
  311. BOOL fNoSelection;
  312. if (ped->fNoRedraw)
  313. return;
  314. if (ichStart == 0)
  315. ichStart = ped->screenStart;
  316. CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
  317. /* Find out how many characters will fit on the screen so that we don't do
  318. * any needless drawing.
  319. */
  320. pText = (PSTR) LocalLock(ped->hText);
  321. cchToDraw = ECCchInWidth(ped, hdc,
  322. (LPSTR)(pText+ped->screenStart),
  323. ped->cch-ped->screenStart,
  324. rc.right - rc.left);
  325. ichEnd = ped->screenStart + cchToDraw;
  326. /*
  327. * There is no selection if,
  328. * 1. MinSel and MaxSel are equal OR
  329. * 2. (This has lost the focus AND Selection is to be hidden)
  330. */
  331. fNoSelection = ((ped->ichMinSel == ped->ichMaxSel) ||
  332. (!ped->fFocus && !ped->fNoHideSel));
  333. while (ichStart < ichEnd)
  334. {
  335. if (fNoSelection)
  336. {
  337. fSelStatus = FALSE;
  338. iCount = ichEnd - ichStart;
  339. }
  340. else
  341. iCount = SLGetBlkEnd(ped, ichStart, ichEnd,
  342. (BOOL FAR *)&fSelStatus);
  343. SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus);
  344. ichStart += iCount;
  345. }
  346. if (cchToDraw)
  347. {
  348. /* Check if password hidden chars are being used. */
  349. if (ped->charPasswordChar)
  350. rc.left += ped->cPasswordCharWidth * cchToDraw;
  351. else
  352. rc.left += LOWORD(GetTextExtent(hdc,
  353. (LPSTR)(pText + ped->screenStart), cchToDraw));
  354. }
  355. LocalUnlock(ped->hText);
  356. /* Check if anything to be erased on the right hand side */
  357. if (rc.left < rc.right)
  358. {
  359. SetBkMode(hdc, OPAQUE);
  360. /* Erase the rectangular area before text is drawn. Note that we inflate
  361. * the rect by 1 so that the selection color has a one pixel border
  362. * around the text.
  363. */
  364. InflateRect((LPRECT)&rc, 0, 1);
  365. PaintRect(ped->hwndParent, ped->hwnd, hdc, NULL, (LPRECT)&rc);
  366. }
  367. SLSetCaretPosition(ped, hdc);
  368. }
  369. BOOL FAR PASCAL SLScrollText(ped, hdc)
  370. register PED ped;
  371. HDC hdc;
  372. /* effects: Scrolls the text to bring the caret into view. If the text is
  373. * scrolled, the current selection is unhighlighted. Returns TRUE if the text
  374. * is scrolled else returns false.
  375. */
  376. {
  377. register PSTR pText;
  378. ICH scrollAmount = (ped->rcFmt.right-ped->rcFmt.left)/4/ped->aveCharWidth+1;
  379. ICH newScreenStartX = ped->screenStart;
  380. if (!ped->fAutoHScroll)
  381. return(FALSE);
  382. /* Calculate the new starting screen position */
  383. if (ped->ichCaret <= ped->screenStart)
  384. {
  385. /* Caret is to the left of the starting text on the screen we must
  386. * scroll the text backwards to bring it into view. Watch out when
  387. * subtracting unsigned numbers when we have the possibility of going
  388. * negative.
  389. */
  390. if (ped->ichCaret > scrollAmount)
  391. newScreenStartX = ped->ichCaret - scrollAmount;
  392. else
  393. newScreenStartX = 0;
  394. }
  395. else
  396. {
  397. pText = (PSTR) LocalLock(ped->hText);
  398. if ((ped->ichCaret != ped->screenStart) &&
  399. (ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
  400. ped->ichCaret - ped->screenStart,
  401. ped->rcFmt.right-ped->rcFmt.left) <
  402. ped->ichCaret - ped->screenStart))
  403. {
  404. newScreenStartX = ((ped->ichCaret < scrollAmount*2) ? 0 :
  405. ped->ichCaret - scrollAmount*2);
  406. }
  407. LocalUnlock(ped->hText);
  408. }
  409. #ifdef FE_SB
  410. pText = (PSTR) LocalLock(ped->hText);
  411. newScreenStartX = ECAdjustIch( ped,pText,newScreenStartX );
  412. LocalUnlock(ped->hText);
  413. #endif
  414. if (ped->screenStart != newScreenStartX)
  415. {
  416. ped->screenStart = newScreenStartX;
  417. SLDrawText(ped, hdc, 0);
  418. /* Caret pos is set by drawtext */
  419. return(TRUE);
  420. }
  421. return(FALSE);
  422. }
  423. ICH FAR PASCAL SLInsertText(ped, lpText, cchInsert)
  424. register PED ped;
  425. LPSTR lpText;
  426. register ICH cchInsert;
  427. /* effects: Adds up to cchInsert characters from lpText to the ped starting at
  428. * ichCaret. If the ped only allows a maximum number of characters, then we
  429. * will only add that many characters to the ped and send a EN_MAXTEXT
  430. * notification code to the parent of the ec. Also, if !fAutoHScroll, then we
  431. * only allow as many chars as will fit in the client rectangle. The number of
  432. * characters actually added is returned (could be 0). If we can't allocate
  433. * the required space, we notify the parent with EN_ERRSPACE and no characters
  434. * are added.
  435. */
  436. {
  437. HDC hdc;
  438. PSTR pText;
  439. ICH cchInsertCopy = cchInsert;
  440. int textWidth;
  441. /* First determine exactly how many characters from lpText we can insert
  442. * into the ped.
  443. */
  444. if (!ped->fAutoHScroll)
  445. {
  446. pText = (PSTR)LocalLock(ped->hText);
  447. hdc = ECGetEditDC(ped, TRUE);
  448. /* If ped->fAutoHScroll bit is not set, then we only insert as many
  449. * characters as will fit in the ped->rcFmt rectangle upto a maximum of
  450. * ped->cchTextMax - ped->cch characters. Note that if password style is
  451. * on, we allow the user to enter as many chars as the number of
  452. * password chars which fit in the rect.
  453. */
  454. if (ped->cchTextMax <= ped->cch)
  455. cchInsert = 0;
  456. else
  457. {
  458. cchInsert = umin(cchInsert, (unsigned)(ped->cchTextMax - ped->cch));
  459. if (ped->charPasswordChar)
  460. textWidth = ped->cch * ped->cPasswordCharWidth;
  461. else
  462. textWidth = LOWORD(GetTextExtent(hdc, (LPSTR)pText, ped->cch));
  463. cchInsert = umin(cchInsert,
  464. ECCchInWidth(ped, hdc, lpText, cchInsert,
  465. ped->rcFmt.right-ped->rcFmt.left-
  466. textWidth));
  467. }
  468. LocalUnlock(ped->hText);
  469. ECReleaseEditDC(ped, hdc, TRUE);
  470. }
  471. else
  472. {
  473. if (ped->cchTextMax <= ped->cch)
  474. cchInsert = 0;
  475. else
  476. cchInsert = umin((unsigned)(ped->cchTextMax - ped->cch), cchInsert);
  477. }
  478. /* Now try actually adding the text to the ped */
  479. if (cchInsert && !ECInsertText(ped, lpText, cchInsert))
  480. {
  481. ECNotifyParent(ped, EN_ERRSPACE);
  482. return(0);
  483. }
  484. if (cchInsert)
  485. ped->fDirty = TRUE; /* Set modify flag */
  486. if (cchInsert < cchInsertCopy)
  487. /* Notify parent that we couldn't insert all the text requested */
  488. ECNotifyParent(ped, EN_MAXTEXT);
  489. /* Update selection extents and the caret position. Note that ECInsertText
  490. * updates ped->ichCaret, ped->ichMinSel, and ped->ichMaxSel to all be after
  491. * the inserted text.
  492. */
  493. return(cchInsert);
  494. }
  495. ICH PASCAL NEAR SLPasteText(register PED ped)
  496. /* effects: Pastes a line of text from the clipboard into the edit control
  497. * starting at ped->ichMaxSel. Updates ichMaxSel and ichMinSel to point to
  498. * the end of the inserted text. Notifies the parent if space cannot be
  499. * allocated. Returns how many characters were inserted.
  500. */
  501. {
  502. HANDLE hData;
  503. LPSTR lpchClip;
  504. LPSTR lpchClip2;
  505. register ICH cchAdded;
  506. ICH clipLength;
  507. if (!OpenClipboard(ped->hwnd))
  508. return(0);
  509. if (!(hData = GetClipboardData(CF_TEXT)))
  510. {
  511. CloseClipboard();
  512. return(0);
  513. }
  514. lpchClip2 = lpchClip = (LPSTR) GlobalLock(hData);
  515. /* Find the first carrage return or line feed. Just add text to that point.
  516. */
  517. clipLength = (WORD)lstrlen(lpchClip);
  518. for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
  519. if (*lpchClip2++ == 0x0D)
  520. break;
  521. /* Insert the text (SLInsertText checks line length) */
  522. cchAdded = SLInsertText(ped, lpchClip, cchAdded);
  523. GlobalUnlock(hData);
  524. CloseClipboard();
  525. return(cchAdded);
  526. }
  527. void NEAR PASCAL SLReplaceSelHandler(register PED ped,
  528. LPSTR lpText)
  529. /* effects: Replaces the text in the current selection with the given text.
  530. */
  531. {
  532. BOOL fUpdate;
  533. HDC hdc;
  534. SwapHandle(&lpText);
  535. ECEmptyUndo(ped);
  536. fUpdate = (BOOL)ECDeleteText(ped);
  537. ECEmptyUndo(ped);
  538. SwapHandle(&lpText);
  539. fUpdate = (BOOL)SLInsertText(ped, lpText, lstrlen(lpText)) || fUpdate;
  540. ECEmptyUndo(ped);
  541. if (fUpdate)
  542. {
  543. ECNotifyParent(ped, EN_UPDATE);
  544. hdc = ECGetEditDC(ped,FALSE);
  545. if (!SLScrollText(ped,hdc))
  546. SLDrawText(ped,hdc,0);
  547. ECReleaseEditDC(ped,hdc,FALSE);
  548. ECNotifyParent(ped,EN_CHANGE);
  549. }
  550. }
  551. void FAR PASCAL SLCharHandler(ped, keyValue, keyMods)
  552. register PED ped;
  553. WORD keyValue;
  554. int keyMods;
  555. /* effects: Handles character input (really, no foolin')
  556. */
  557. {
  558. register HDC hdc;
  559. unsigned char keyPress = LOBYTE(keyValue);
  560. BOOL updateText = FALSE;
  561. #ifdef FE_SB
  562. PSTR pText;
  563. int InsertTextLen = 0;
  564. WORD DBCSkey;
  565. #endif
  566. if (ped->fMouseDown || ped->fReadOnly)
  567. /* Don't do anything if we are in the middle of a mousedown deal or if
  568. * this is a read only edit control.
  569. */
  570. return;
  571. if ((keyPress == BACKSPACE) || (keyPress >= ' '))
  572. {
  573. /* Delete the selected text if any */
  574. if (ECDeleteText(ped))
  575. updateText=TRUE;
  576. }
  577. switch(keyPress)
  578. {
  579. case BACKSPACE:
  580. /* Delete any selected text or delete character left if no sel */
  581. if (!updateText && ped->ichMinSel)
  582. {
  583. /* There was no selection to delete so we just delete character
  584. left if available */
  585. #ifdef FE_SB
  586. pText = LMHtoP( ped->hText );
  587. if( ECAnsiPrev( ped,pText, pText+ped->ichMinSel) == pText+ped->ichMinSel-2)
  588. ped->ichMinSel--;
  589. #endif
  590. ped->ichMinSel--;
  591. (void) ECDeleteText(ped);
  592. updateText = TRUE;
  593. }
  594. break;
  595. default:
  596. if (keyPress >= ' ')
  597. {
  598. #ifdef FE_SB
  599. InsertTextLen = 1;
  600. if( IsDBCSLeadByte( keyPress ) )
  601. if( ( DBCSkey = DBCSCombine( ped->hwnd, keyPress ) ) != NULL )
  602. if( SLInsertText( ped, (LPSTR)&DBCSkey, 2 ) == 2){
  603. InsertTextLen = 2;
  604. updateText = TRUE;
  605. }else
  606. MessageBeep(0);
  607. else
  608. MessageBeep(0);
  609. else
  610. #endif
  611. if (SLInsertText(ped, (LPSTR) &keyPress, 1))
  612. updateText = TRUE;
  613. else
  614. /* Beep. Since we couldn't add the text */
  615. MessageBeep(0);
  616. }
  617. else
  618. /* User hit an illegal control key */
  619. MessageBeep(0);
  620. break;
  621. }
  622. if (updateText)
  623. {
  624. /* Dirty flag (ped->fDirty) was set when we inserted text */
  625. ECNotifyParent(ped, EN_UPDATE);
  626. hdc = ECGetEditDC(ped,FALSE);
  627. if (!SLScrollText(ped,hdc))
  628. #ifdef FE_SB
  629. SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - InsertTextLen));
  630. #else
  631. SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - 1));
  632. #endif
  633. ECReleaseEditDC(ped,hdc,FALSE);
  634. ECNotifyParent(ped,EN_CHANGE);
  635. }
  636. }
  637. void NEAR PASCAL SLKeyDownHandler(register PED ped,
  638. WORD virtKeyCode,
  639. int keyMods)
  640. /* effects: Handles cursor movement and other VIRT KEY stuff. keyMods allows
  641. * us to make SLKeyDownHandler calls and specify if the modifier keys (shift
  642. * and control) are up or down. This is useful for imnplementing the
  643. * cut/paste/clear messages for single line edit controls. If keyMods == 0,
  644. * we get the keyboard state using GetKeyState(VK_SHIFT) etc. Otherwise, the
  645. * bits in keyMods define the state of the shift and control keys.
  646. */
  647. {
  648. HDC hdc;
  649. /* Variables we will use for redrawing the updated text */
  650. register ICH newMaxSel = ped->ichMaxSel;
  651. ICH newMinSel = ped->ichMinSel;
  652. /* Flags for drawing the updated text */
  653. BOOL updateText = FALSE;
  654. BOOL changeSelection = FALSE; /* new selection is specified by
  655. newMinSel, newMaxSel */
  656. /* Comparisons we do often */
  657. BOOL MinEqMax = (newMaxSel == newMinSel);
  658. BOOL MinEqCar = (ped->ichCaret == newMinSel);
  659. BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
  660. /* State of shift and control keys. */
  661. int scState = 0;
  662. /* Combo box support */
  663. BOOL fIsListVisible;
  664. BOOL fIsExtendedUI;
  665. #ifdef FE_SB
  666. PSTR pText;
  667. #endif
  668. if (ped->fMouseDown)
  669. {
  670. /* If we are in the middle of a mouse down handler, then don't do
  671. * anything. ie. ignore keyboard input.
  672. */
  673. return;
  674. }
  675. if (!keyMods)
  676. {
  677. /* Get state of modifier keys for use later. */
  678. scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
  679. scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0);
  680. }
  681. else
  682. scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
  683. switch(virtKeyCode)
  684. {
  685. case VK_UP:
  686. if (ped->listboxHwnd)
  687. {
  688. /* Handle Combobox support */
  689. fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
  690. fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
  691. if (!fIsListVisible && fIsExtendedUI)
  692. {
  693. /* For TandyT
  694. */
  695. DropExtendedUIListBox:
  696. /* Since an extendedui combo box doesn't do anything on f4, we
  697. * turn off the extended ui, send the f4 to drop, and turn it
  698. * back on again.
  699. */
  700. SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 0, 0L);
  701. SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L);
  702. SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 1, 0L);
  703. return;
  704. }
  705. else
  706. goto SendKeyToListBox;
  707. }
  708. /* else fall through */
  709. case VK_LEFT:
  710. /* If the caret isn't already at 0, we can move left */
  711. if (ped->ichCaret)
  712. {
  713. switch (scState)
  714. {
  715. case NONEDOWN:
  716. /* Clear selection, move caret left */
  717. #ifdef FE_SB
  718. pText = LMHtoP( ped->hText );
  719. if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
  720. pText + ped->ichCaret - 2 )
  721. ped->ichCaret--;
  722. #endif
  723. ped->ichCaret--;
  724. newMaxSel = newMinSel = ped->ichCaret;
  725. break;
  726. case CTRLDOWN:
  727. /* Clear selection, move caret word left */
  728. ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
  729. newMaxSel = newMinSel = ped->ichCaret;
  730. break;
  731. case SHFTDOWN:
  732. /* Extend selection, move caret left */
  733. #ifdef FE_SB
  734. pText = LMHtoP( ped->hText );
  735. if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
  736. pText + ped->ichCaret - 2 )
  737. ped->ichCaret--;
  738. #endif
  739. ped->ichCaret--;
  740. if (MaxEqCar && !MinEqMax)
  741. /* Reduce selection extent */
  742. newMaxSel = ped->ichCaret;
  743. else
  744. /* Extend selection extent */
  745. newMinSel = ped->ichCaret;
  746. break;
  747. case SHCTDOWN:
  748. /* Extend selection, move caret word left */
  749. ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
  750. if (MaxEqCar && !MinEqMax)
  751. {
  752. /* Reduce selection extent */
  753. /*
  754. * Hint: Suppose WORD. OR is selected. Cursor between R
  755. * and D. Hit select word left, we want to just select the
  756. * W and leave cursor before the W.
  757. */
  758. newMinSel = ped->ichMinSel;
  759. newMaxSel = ped->ichCaret;
  760. }
  761. else
  762. /* Extend selection extent */
  763. newMinSel = ped->ichCaret;
  764. break;
  765. }
  766. changeSelection = TRUE;
  767. }
  768. else
  769. {
  770. /* If the user tries to move left and we are at the 0th character
  771. and there is a selection, then cancel the selection. */
  772. if (ped->ichMaxSel != ped->ichMinSel &&
  773. (scState == NONEDOWN || scState == CTRLDOWN))
  774. {
  775. changeSelection = TRUE;
  776. newMaxSel = newMinSel = ped->ichCaret;
  777. }
  778. }
  779. break;
  780. case VK_DOWN:
  781. if (ped->listboxHwnd)
  782. {
  783. /* Handle Combobox support */
  784. fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
  785. fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
  786. if (!fIsListVisible && fIsExtendedUI)
  787. {
  788. /* For TandyT
  789. */
  790. goto DropExtendedUIListBox;
  791. }
  792. else
  793. goto SendKeyToListBox;
  794. }
  795. /* else fall through */
  796. case VK_RIGHT:
  797. /*
  798. * If the caret isn't already at ped->cch, we can move right.
  799. */
  800. if (ped->ichCaret < ped->cch)
  801. {
  802. switch (scState)
  803. {
  804. case NONEDOWN:
  805. /* Clear selection, move caret right */
  806. #ifdef FE_SB
  807. pText = LMHtoP( ped->hText ) + ped->ichCaret;
  808. if( ECIsDBCSLeadByte( ped, *pText ) )
  809. ped->ichCaret++;
  810. #endif
  811. ped->ichCaret++;
  812. newMaxSel = newMinSel = ped->ichCaret;
  813. break;
  814. case CTRLDOWN:
  815. /* Clear selection, move caret word right */
  816. ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
  817. newMaxSel = newMinSel = ped->ichCaret;
  818. break;
  819. case SHFTDOWN:
  820. /* Extend selection, move caret right */
  821. #ifdef FE_SB
  822. pText = LMHtoP( ped->hText ) + ped->ichCaret;
  823. if( ECIsDBCSLeadByte( ped, *pText ) )
  824. ped->ichCaret++;
  825. #endif
  826. ped->ichCaret++;
  827. if (MinEqCar && !MinEqMax)
  828. /* Reduce selection extent */
  829. newMinSel = ped->ichCaret;
  830. else
  831. /* Extend selection extent */
  832. newMaxSel = ped->ichCaret;
  833. break;
  834. case SHCTDOWN:
  835. /* Extend selection, move caret word right */
  836. ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
  837. if (MinEqCar && !MinEqMax)
  838. {
  839. /* Reduce selection extent */
  840. newMinSel = ped->ichCaret;
  841. newMaxSel = ped->ichMaxSel;
  842. }
  843. else
  844. /* Extend selection extent */
  845. newMaxSel = ped->ichCaret;
  846. break;
  847. }
  848. changeSelection = TRUE;
  849. }
  850. else
  851. {
  852. /* If the user tries to move right and we are at the last character
  853. and there is a selection, then cancel the selection. */
  854. if (ped->ichMaxSel != ped->ichMinSel &&
  855. (scState == NONEDOWN || scState == CTRLDOWN))
  856. {
  857. newMaxSel = newMinSel = ped->ichCaret;
  858. changeSelection = TRUE;
  859. }
  860. }
  861. break;
  862. case VK_HOME:
  863. ped->ichCaret = 0;
  864. switch (scState)
  865. {
  866. case NONEDOWN:
  867. case CTRLDOWN:
  868. /* Clear selection, move caret home */
  869. newMaxSel = newMinSel = ped->ichCaret;
  870. break;
  871. case SHFTDOWN:
  872. case SHCTDOWN:
  873. /* Extend selection, move caret home */
  874. if (MaxEqCar && !MinEqMax)
  875. {
  876. /* Reduce/negate selection extent */
  877. newMinSel = 0;
  878. newMaxSel = ped->ichMinSel;
  879. }
  880. else
  881. /* Extend selection extent */
  882. newMinSel = ped->ichCaret;
  883. break;
  884. }
  885. changeSelection = TRUE;
  886. break;
  887. case VK_END:
  888. newMaxSel = ped->ichCaret = ped->cch;
  889. switch (scState)
  890. {
  891. case NONEDOWN:
  892. case CTRLDOWN:
  893. /* Clear selection, move caret to end of text */
  894. newMinSel = ped->cch;
  895. break;
  896. case SHFTDOWN:
  897. case SHCTDOWN:
  898. /* Extend selection, move caret to end of text */
  899. if (MinEqCar && !MinEqMax)
  900. /* Reduce/negate selection extent */
  901. newMinSel = ped->ichMaxSel;
  902. /* else Extend selection extent */
  903. break;
  904. }
  905. changeSelection = TRUE;
  906. break;
  907. case VK_DELETE:
  908. if (ped->fReadOnly)
  909. break;
  910. switch (scState)
  911. {
  912. case NONEDOWN:
  913. /* Clear selection. If no selection, delete (clear) character
  914. * right.
  915. */
  916. if ((ped->ichMaxSel<ped->cch) &&
  917. (ped->ichMinSel==ped->ichMaxSel))
  918. {
  919. /* Move cursor forwards and simulate a backspace.
  920. */
  921. #ifdef FE_SB
  922. pText = LMHtoP( ped->hText ) + ped->ichCaret;
  923. if( ECIsDBCSLeadByte( ped, *pText ) )
  924. ped->ichCaret++;
  925. #endif
  926. ped->ichCaret++;
  927. ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
  928. SLCharHandler(ped, (WORD) BACKSPACE, 0);
  929. }
  930. if (ped->ichMinSel != ped->ichMaxSel)
  931. SLCharHandler(ped, (WORD) BACKSPACE, 0);
  932. break;
  933. case SHFTDOWN:
  934. /* CUT selection ie. remove and copy to clipboard, or if no
  935. * selection, delete (clear) character left.
  936. */
  937. if (SendMessage(ped->hwnd, WM_COPY, (WORD)0,0L) ||
  938. (ped->ichMinSel == ped->ichMaxSel))
  939. /* If copy successful, delete the copied text by simulating a
  940. * backspace message which will redraw the text and take care
  941. * of notifying the parent of changes. Or if there is no
  942. * selection, just delete char left.
  943. */
  944. SLCharHandler(ped, (WORD) BACKSPACE, 0);
  945. break;
  946. case CTRLDOWN:
  947. /* Delete to end of line if no selection else delete (clear)
  948. * selection.
  949. */
  950. if ((ped->ichMaxSel<ped->cch) &&
  951. (ped->ichMinSel==ped->ichMaxSel))
  952. {
  953. /* Move cursor to end of line and simulate a backspace.
  954. */
  955. ped->ichMaxSel = ped->ichCaret = ped->cch;
  956. }
  957. if (ped->ichMinSel != ped->ichMaxSel)
  958. SLCharHandler(ped, (WORD) BACKSPACE, 0);
  959. break;
  960. }
  961. /* No need to update text or selection since BACKSPACE message does it
  962. * for us.
  963. */
  964. break;
  965. case VK_INSERT:
  966. switch (scState)
  967. {
  968. case CTRLDOWN:
  969. /* Copy current selection to clipboard */
  970. SendMessage(ped->hwnd, WM_COPY, (WORD)NULL, (LONG)NULL);
  971. break;
  972. case SHFTDOWN:
  973. if (ped->fReadOnly)
  974. break;
  975. /* Insert contents of clipboard (PASTE) */
  976. /* Unhighlight current selection and delete it, if any */
  977. ECDeleteText(ped);
  978. SLPasteText(ped);
  979. updateText = TRUE;
  980. ECNotifyParent(ped, EN_UPDATE);
  981. break;
  982. }
  983. break;
  984. case VK_F4:
  985. case VK_PRIOR:
  986. case VK_NEXT:
  987. /* Send keys to the listbox if we are a part of a combo box. This
  988. * assumes the listbox ignores keyup messages which is correct right
  989. * now.
  990. */
  991. if (ped->listboxHwnd)
  992. {
  993. SendKeyToListBox:
  994. /* Handle Combobox support */
  995. SendMessage(ped->listboxHwnd, WM_KEYDOWN, virtKeyCode, 0L);
  996. return;
  997. }
  998. }
  999. if (changeSelection || updateText)
  1000. {
  1001. hdc = ECGetEditDC(ped,FALSE);
  1002. /* Scroll if needed */
  1003. SLScrollText(ped,hdc);
  1004. if (changeSelection)
  1005. SLChangeSelection(ped,hdc,newMinSel,newMaxSel);
  1006. if (updateText)
  1007. SLDrawText(ped,hdc,0);
  1008. /* SLSetCaretPosition(ped,hdc);*/
  1009. ECReleaseEditDC(ped,hdc,FALSE);
  1010. if (updateText)
  1011. ECNotifyParent(ped, EN_CHANGE);
  1012. }
  1013. }
  1014. ICH NEAR PASCAL SLMouseToIch(ped, hdc, mousePt)
  1015. register PED ped;
  1016. HDC hdc;
  1017. POINT mousePt;
  1018. /* effects: Returns the closest cch to where the mouse point is.
  1019. */
  1020. {
  1021. register PSTR pText;
  1022. int width = mousePt.x;
  1023. int textWidth;
  1024. ICH cch;
  1025. if (width <= ped->rcFmt.left)
  1026. {
  1027. /* Return either the first non visible character or return 0 if at
  1028. * beginning of text
  1029. */
  1030. if (ped->screenStart)
  1031. return(ped->screenStart - 1);
  1032. else
  1033. return(0);
  1034. }
  1035. if (width > ped->rcFmt.right)
  1036. {
  1037. pText = LocalLock(ped->hText);
  1038. /* Return last char in text or one plus the last char visible */
  1039. cch = ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
  1040. ped->cch - ped->screenStart,
  1041. ped->rcFmt.right-ped->rcFmt.left) +
  1042. ped->screenStart;
  1043. LocalUnlock(ped->hText);
  1044. if (cch >= ped->cch)
  1045. return(ped->cch);
  1046. else
  1047. return(cch+1);
  1048. }
  1049. /* Check if password hidden chars are being used. */
  1050. if (ped->charPasswordChar)
  1051. return(umin((width-ped->rcFmt.left)/ped->cPasswordCharWidth,ped->cch));
  1052. if (!ped->cch)
  1053. return(0);
  1054. pText = LocalLock(ped->hText);
  1055. cch = ped->cch;
  1056. while(((textWidth =
  1057. LOWORD(GetTextExtent(hdc, (LPSTR)(pText+ped->screenStart),
  1058. cch-ped->screenStart)))
  1059. > (width-ped->rcFmt.left)) && (cch-ped->screenStart) )
  1060. {
  1061. /* For that "feel" */
  1062. if ((textWidth - ped->aveCharWidth/2) < (width-ped->rcFmt.left))
  1063. break;
  1064. cch--;
  1065. }
  1066. #ifdef FE_SB
  1067. cch = ECAdjustIch( ped, pText, cch );
  1068. #endif
  1069. LocalUnlock(ped->hText);
  1070. return(cch);
  1071. }
  1072. void NEAR PASCAL SLMouseMotionHandler(ped, message, virtKeyDown, mousePt)
  1073. register PED ped;
  1074. WORD message;
  1075. WORD virtKeyDown;
  1076. POINT mousePt;
  1077. {
  1078. LONG selection;
  1079. BOOL changeSelection = FALSE;
  1080. HDC hdc = ECGetEditDC(ped,FALSE);
  1081. ICH newMaxSel = ped->ichMaxSel;
  1082. ICH newMinSel = ped->ichMinSel;
  1083. ICH mouseIch = SLMouseToIch(ped, hdc, mousePt);
  1084. #ifdef FE_SB
  1085. LPSTR pText;
  1086. pText = LocalLock( ped->hText );
  1087. mouseIch = ECAdjustIch( ped, pText, mouseIch );
  1088. LocalUnlock( ped->hText );
  1089. #endif
  1090. switch (message)
  1091. {
  1092. case WM_LBUTTONDBLCLK:
  1093. /* Note that we don't have to worry about this control having the focus
  1094. * since it got it when the WM_LBUTTONDOWN message was first sent. If
  1095. * shift key is down, extend selection to word we double clicked on else
  1096. * clear current selection and select word.
  1097. */
  1098. #ifdef FE_SB
  1099. pText = LocalLock( ped->hText ) + ped->ichCaret;
  1100. selection = ECWord(ped,ped->ichCaret,
  1101. (ECIsDBCSLeadByte(ped,*pText) && ped->ichCaret < ped->cch) ? FALSE : TRUE );
  1102. LocalUnlock( ped->hText );
  1103. #else
  1104. selection = ECWord(ped,ped->ichCaret,TRUE);
  1105. #endif
  1106. newMinSel = LOWORD(selection);
  1107. newMaxSel = ped->ichCaret = HIWORD(selection);
  1108. changeSelection = TRUE;
  1109. /* Set mouse down to false so that the caret isn't reposition on the
  1110. * mouseup message or on an accidental move...
  1111. */
  1112. ped->fMouseDown = FALSE;
  1113. break;
  1114. case WM_MOUSEMOVE:
  1115. if (ped->fMouseDown)
  1116. {
  1117. changeSelection = TRUE;
  1118. /* Extend selection, move caret word right */
  1119. if ((ped->ichMinSel == ped->ichCaret) &&
  1120. (ped->ichMinSel != ped->ichMaxSel))
  1121. {
  1122. /* Reduce selection extent */
  1123. newMinSel = ped->ichCaret = mouseIch;
  1124. newMaxSel = ped->ichMaxSel;
  1125. }
  1126. else
  1127. /* Extend selection extent */
  1128. newMaxSel = ped->ichCaret=mouseIch;
  1129. }
  1130. break;
  1131. case WM_LBUTTONDOWN:
  1132. /*
  1133. * If we currently don't have the focus yet, try to get it.
  1134. */
  1135. if (!ped->fFocus)
  1136. {
  1137. if (!ped->fNoHideSel)
  1138. /* Clear the selection before setting the focus so that we don't
  1139. * get refresh problems and flicker. Doesn't matter since the
  1140. * mouse down will end up changing it anyway.
  1141. */
  1142. ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;
  1143. SetFocus(ped->hwnd);
  1144. /* If we are part of a combo box, then this is the first time the
  1145. * edit control is getting the focus so we just want to highlight
  1146. * the selection and we don't really want to position the caret.
  1147. */
  1148. if (ped->listboxHwnd)
  1149. break;
  1150. }
  1151. if (ped->fFocus)
  1152. {
  1153. /* Only do this if we have the focus since a clever app may not want
  1154. * to give us the focus at the SetFocus call above.
  1155. */
  1156. ped->fMouseDown = TRUE;
  1157. SetCapture(ped->hwnd);
  1158. changeSelection = TRUE;
  1159. if (!(virtKeyDown & MK_SHIFT))
  1160. {
  1161. /*
  1162. * If shift key isn't down, move caret to mouse point and clear
  1163. * old selection
  1164. */
  1165. newMinSel = newMaxSel = ped->ichCaret = mouseIch;
  1166. }
  1167. else
  1168. {
  1169. /* Shiftkey is down so we want to maintain the current selection
  1170. * (if any) and just extend or reduce it
  1171. */
  1172. if (ped->ichMinSel == ped->ichCaret)
  1173. newMinSel = ped->ichCaret = mouseIch;
  1174. else
  1175. newMaxSel = ped->ichCaret = mouseIch;
  1176. }
  1177. }
  1178. break;
  1179. case WM_LBUTTONUP:
  1180. if (ped->fMouseDown)
  1181. {
  1182. ReleaseCapture();
  1183. /*SLSetCaretPosition(ped,hdc);*/
  1184. ped->fMouseDown = FALSE;
  1185. }
  1186. break;
  1187. }
  1188. if (changeSelection)
  1189. {
  1190. SLScrollText(ped,hdc);
  1191. SLChangeSelection(ped, hdc, newMinSel, newMaxSel);
  1192. }
  1193. ECReleaseEditDC(ped,hdc,FALSE);
  1194. }
  1195. void NEAR PASCAL SLPaintHandler(ped,althdc)
  1196. register PED ped;
  1197. HDC althdc;
  1198. /* effects: Handles painting of the edit control window. Draws the border if
  1199. * necessary and draws the text in its current state.
  1200. */
  1201. {
  1202. HWND hwnd = ped->hwnd;
  1203. HBRUSH hBrush;
  1204. register HDC hdc;
  1205. PAINTSTRUCT paintstruct;
  1206. RECT rcEdit;
  1207. HANDLE hOldFont;
  1208. /* Had to put in hide/show carets. The first one needs to be done before
  1209. * beginpaint to correctly paint the caret if part is in the update region
  1210. * and part is out. The second is for 1.03 compatibility. It breaks
  1211. * micrografix's worksheet edit control if not there.
  1212. */
  1213. HideCaret(hwnd);
  1214. /* Allow subclassing hdc */
  1215. if (!althdc)
  1216. hdc = BeginPaint(hwnd, (PAINTSTRUCT FAR *)&paintstruct);
  1217. else
  1218. hdc = althdc;
  1219. HideCaret(hwnd);
  1220. if (!ped->fNoRedraw && IsWindowVisible(ped->hwnd))
  1221. {
  1222. /* Erase the background since we don't do it in the erasebkgnd message.
  1223. */
  1224. hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
  1225. FillWindow(ped->hwndParent, hwnd, hdc, hBrush);
  1226. if (ped->fBorder)
  1227. {
  1228. GetClientRect(hwnd, (LPRECT)&rcEdit);
  1229. DrawFrame(hdc, (LPRECT)&rcEdit, 1, DF_WINDOWFRAME);
  1230. }
  1231. if (ped->hFont)
  1232. /* We have to select in the font since this may be a subclassed dc
  1233. * or a begin paint dc which hasn't been initialized with out fonts
  1234. * like ECGetEditDC does.
  1235. */
  1236. hOldFont = SelectObject(hdc, ped->hFont);
  1237. SLDrawText(ped, hdc, 0);
  1238. if (ped->hFont && hOldFont)
  1239. SelectObject(hdc, hOldFont);
  1240. }
  1241. ShowCaret(hwnd);
  1242. if (!althdc)
  1243. EndPaint(hwnd, (LPPAINTSTRUCT)&paintstruct);
  1244. ShowCaret(hwnd);
  1245. }
  1246. void NEAR PASCAL SLSetFocusHandler(ped)
  1247. register PED ped;
  1248. /* effects: Gives the edit control the focus and notifies the parent
  1249. * EN_SETFOCUS.
  1250. */
  1251. {
  1252. register HDC hdc;
  1253. if (!ped->fFocus)
  1254. {
  1255. UpdateWindow(ped->hwnd);
  1256. ped->fFocus = TRUE; /* Set focus */
  1257. /* We don't want to muck with the caret since it isn't created. */
  1258. hdc = ECGetEditDC(ped,TRUE);
  1259. /* Show the current selection. Only if the selection was hidden when we
  1260. * lost the focus, must we invert (show) it.
  1261. */
  1262. if (!ped->fNoHideSel)
  1263. SLDrawText(ped, hdc, 0);
  1264. /* Create the caret. Add in the +1 because we have an extra pixel for
  1265. * highlighting around the text. If the font is at least as wide as the
  1266. * system font, use a wide caret else use a 1 pixel wide caret.
  1267. */
  1268. CreateCaret(ped->hwnd, (HBITMAP)NULL,
  1269. (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
  1270. ped->lineHeight+1);
  1271. SLSetCaretPosition(ped,hdc);
  1272. ECReleaseEditDC(ped,hdc,TRUE);
  1273. ShowCaret(ped->hwnd);
  1274. }
  1275. /* Notify parent we have the focus */
  1276. ECNotifyParent(ped, EN_SETFOCUS);
  1277. }
  1278. void NEAR PASCAL SLKillFocusHandler(ped, newFocusHwnd)
  1279. register PED ped;
  1280. HWND newFocusHwnd;
  1281. /* effects: The edit control loses the focus and notifies the parent via
  1282. * EN_KILLFOCUS.
  1283. */
  1284. {
  1285. RECT rcEdit;
  1286. if (ped->fFocus)
  1287. {
  1288. /* Destroy the caret */
  1289. HideCaret(ped->hwnd);
  1290. DestroyCaret();
  1291. ped->fFocus = FALSE; /* Clear focus */
  1292. /* Do this only if we still have the focus. But we always notify the
  1293. * parent that we lost the focus whether or not we originally had the
  1294. * focus.
  1295. */
  1296. /* Hide the current selection if needed */
  1297. if (!ped->fNoHideSel && (ped->ichMinSel != ped->ichMaxSel))
  1298. {
  1299. GetClientRect(ped->hwnd, (LPRECT)&rcEdit);
  1300. if (ped->fBorder && rcEdit.right-rcEdit.left &&
  1301. rcEdit.bottom-rcEdit.top)
  1302. {
  1303. /* Don't invalidate the border so that we avoid flicker */
  1304. InflateRect((LPRECT)&rcEdit, -1, -1);
  1305. }
  1306. InvalidateRect(ped->hwnd, (LPRECT)&rcEdit, FALSE);
  1307. UpdateWindow(ped->hwnd);
  1308. #if 0
  1309. SLSetSelectionHandler(ped, ped->ichCaret, ped->ichCaret);
  1310. #endif
  1311. }
  1312. }
  1313. /* If we aren't a combo box, notify parent that we lost the focus.
  1314. */
  1315. if (!ped->listboxHwnd)
  1316. ECNotifyParent(ped, EN_KILLFOCUS);
  1317. else
  1318. {
  1319. /* This editcontrol is part of a combo box and is losing the focus. If
  1320. * the focus is NOT being sent to another control in the combo box
  1321. * window, then it means the combo box is losing the focus. So we will
  1322. * notify the combo box of this fact.
  1323. */
  1324. if (!IsChild(ped->hwndParent, newFocusHwnd))
  1325. {
  1326. /* Focus is being sent to a window which is not a child of the combo
  1327. * box window which implies that the combo box is losing the focus.
  1328. * Send a message to the combo box informing him of this fact so
  1329. * that he can clean up...
  1330. */
  1331. SendMessage(ped->hwndParent, CBEC_KILLCOMBOFOCUS, 0, 0L);
  1332. }
  1333. }
  1334. }
  1335. /*******************/
  1336. /* SLEditWndProc() */
  1337. /*******************/
  1338. LONG FAR PASCAL SLEditWndProc(hwnd, ped, message, wParam, lParam)
  1339. HWND hwnd;
  1340. register PED ped;
  1341. WORD message;
  1342. register WORD wParam;
  1343. LONG lParam;
  1344. /* effects: Class procedure for all single line edit controls.
  1345. Dispatches all messages to the appropriate handlers which are named
  1346. as follows:
  1347. SL (single line) prefixes all single line edit control procedures while
  1348. EC (edit control) prefixes all common handlers.
  1349. The SLEditWndProc only handles messages specific to single line edit
  1350. controls.
  1351. */
  1352. {
  1353. /* Dispatch the various messages we can receive */
  1354. switch (message)
  1355. {
  1356. case WM_CLEAR:
  1357. /* wParam - not used
  1358. lParam - not used */
  1359. /*
  1360. * Call SLKeyDownHandler with a VK_DELETE keycode to clear the selected
  1361. * text.
  1362. */
  1363. if (ped->ichMinSel != ped->ichMaxSel)
  1364. SLKeyDownHandler(ped, VK_DELETE, NOMODIFY);
  1365. break;
  1366. case WM_CHAR:
  1367. /* wParam - the value of the key
  1368. lParam - modifiers, repeat count etc (not used) */
  1369. if (!ped->fEatNextChar)
  1370. SLCharHandler(ped, wParam, 0);
  1371. else
  1372. ped->fEatNextChar = FALSE;
  1373. break;
  1374. case WM_CUT:
  1375. /* wParam - not used
  1376. lParam - not used */
  1377. /* Call SLKeyDownHandler with a VK_DELETE keycode to cut the selected
  1378. * text. (Delete key with shift modifier.) This is needed so that apps
  1379. * can send us WM_PASTE messages.
  1380. */
  1381. if (ped->ichMinSel != ped->ichMaxSel)
  1382. SLKeyDownHandler(ped, VK_DELETE, SHFTDOWN);
  1383. break;
  1384. case WM_ERASEBKGND:
  1385. /* wParam - device context handle
  1386. lParam - not used */
  1387. /* We do nothing on this message and we don't want DefWndProc to do
  1388. * anything, so return 1
  1389. */
  1390. return(1L);
  1391. break;
  1392. case WM_GETDLGCODE:
  1393. /* wParam - not used
  1394. lParam - not used */
  1395. return(DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS);
  1396. break;
  1397. case WM_KEYDOWN:
  1398. /* wParam - virt keycode of the given key
  1399. lParam - modifiers such as repeat count etc. (not used) */
  1400. SLKeyDownHandler(ped, wParam, 0);
  1401. break;
  1402. case WM_KILLFOCUS:
  1403. /* wParam - handle of the window that receives the input focus
  1404. lParam - not used */
  1405. SLKillFocusHandler(ped, (HWND)wParam);
  1406. break;
  1407. case WM_MOUSEMOVE:
  1408. case WM_LBUTTONDBLCLK:
  1409. case WM_LBUTTONDOWN:
  1410. case WM_LBUTTONUP:
  1411. /* wParam - contains a value that indicates which virtual keys are down
  1412. lParam - contains x and y coords of the mouse cursor */
  1413. SLMouseMotionHandler(ped, message, wParam, MAKEPOINT(lParam));
  1414. break;
  1415. case WM_CREATE:
  1416. /* wParam - handle to window being created
  1417. lParam - points to a CREATESTRUCT that contains copies of parameters
  1418. passed to the CreateWindow function. */
  1419. return(SLCreateHandler(hwnd, ped, (LPCREATESTRUCT) lParam));
  1420. break;
  1421. case WM_PAINT:
  1422. /* wParam - not used - actually sometimes used as a hdc when subclassing
  1423. lParam - not used */
  1424. SLPaintHandler(ped, wParam);
  1425. break;
  1426. case WM_PASTE:
  1427. /* wParam - not used
  1428. lParam - not used */
  1429. /* Call SLKeyDownHandler with a SHIFT VK_INSERT keycode to paste the
  1430. * clipboard into the edit control. This is needed so that apps can
  1431. * send us WM_PASTE messages.
  1432. */
  1433. SLKeyDownHandler(ped, VK_INSERT, SHFTDOWN);
  1434. break;
  1435. case WM_SETFOCUS:
  1436. /* wParam - handle of window that loses the input focus (may be NULL)
  1437. lParam - not used */
  1438. SLSetFocusHandler(ped);
  1439. break;
  1440. case WM_SETTEXT:
  1441. /* wParam - not used
  1442. lParam - points to a null-terminated string that is used to set the
  1443. window text. */
  1444. return(SLSetTextHandler(ped, (LPSTR)lParam));
  1445. break;
  1446. case WM_SIZE:
  1447. /* wParam - defines the type of resizing fullscreen, sizeiconic,
  1448. sizenormal etc.
  1449. lParam - new width in LOWORD, new height in HIGHWORD of client area */
  1450. SLSizeHandler(ped);
  1451. return(0L);
  1452. break;
  1453. case WM_SYSKEYDOWN:
  1454. if (ped->listboxHwnd && /* Check if we are in a combo box */
  1455. (lParam & 0x20000000L)) /* Check if the alt key is down */
  1456. {
  1457. /*
  1458. * Handle Combobox support. We want alt up or down arrow to behave
  1459. * like F4 key which completes the combo box selection
  1460. */
  1461. ped->fEatNextChar = FALSE;
  1462. if (lParam & 0x1000000)
  1463. {
  1464. /* This is an extended key such as the arrow keys not on the
  1465. * numeric keypad so just drop the combobox.
  1466. */
  1467. if (wParam == VK_DOWN || wParam == VK_UP)
  1468. goto DropCombo;
  1469. else
  1470. goto foo;
  1471. }
  1472. if (GetKeyState(VK_NUMLOCK) < 0)
  1473. {
  1474. ped->fEatNextChar = FALSE;
  1475. /* If numlock down, just send all system keys to dwp */
  1476. goto foo;
  1477. }
  1478. else
  1479. /* Num lock is up. Eat the characters generated by the key board
  1480. * driver.
  1481. */
  1482. ped->fEatNextChar = TRUE;
  1483. if (!(wParam == VK_DOWN || wParam == VK_UP))
  1484. goto foo;
  1485. DropCombo:
  1486. if (SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L) & 0x00000001)
  1487. {
  1488. /* Extended ui doesn't honor VK_F4. */
  1489. if (SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L))
  1490. return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 0, 0L));
  1491. else
  1492. return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 1, 0L));
  1493. }
  1494. else
  1495. return(SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L));
  1496. }
  1497. foo:
  1498. if (wParam == VK_BACK)
  1499. {
  1500. SendMessage(ped->hwnd, EM_UNDO, 0, 0L);
  1501. break;
  1502. }
  1503. goto PassToDefaultWindowProc;
  1504. break;
  1505. case EM_GETLINE:
  1506. /* wParam - line number to copy (always the first line for SL)
  1507. lParam - buffer to copy text to. FIrst word is max # of bytes to copy
  1508. */
  1509. return(ECGetTextHandler(ped, (*(WORD FAR *)lParam), (LPSTR)lParam));
  1510. break;
  1511. case EM_LINELENGTH:
  1512. /* wParam - ignored
  1513. lParam - ignored */
  1514. return((LONG)ped->cch);
  1515. break;
  1516. case EM_SETSEL:
  1517. /* wParam - not used
  1518. lParam - starting pos in lowword ending pos in high word */
  1519. SLSetSelectionHandler(ped, LOWORD(lParam), HIWORD(lParam));
  1520. break;
  1521. case EM_REPLACESEL:
  1522. /* wParam - not used
  1523. lParam - points to a null terminated string of replacement text */
  1524. SLReplaceSelHandler(ped, (LPSTR)lParam);
  1525. break;
  1526. case WM_UNDO:
  1527. case EM_UNDO:
  1528. SLUndoHandler(ped);
  1529. break;
  1530. default:
  1531. PassToDefaultWindowProc:
  1532. return(DefWindowProc(hwnd,message,wParam,lParam));
  1533. break;
  1534. } /* switch (message) */
  1535. return(1L);
  1536. } /* SLEditWndProc */