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.

3043 lines
84 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * EDITML.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. /* editml.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. /* Multi-Line Support Routines */
  26. /****************************************************************************/
  27. BOOL NEAR _fastcall MLIsDelimiter(char bCharVal)
  28. {
  29. return((bCharVal == ' ') || (bCharVal == '\t'));
  30. }
  31. DWORD NEAR PASCAL LocGetTabbedTextExtent(HDC hdc, PSTR pstring,
  32. int nCount, PED ped)
  33. {
  34. return(ECTabTheTextOut(hdc, 0, 0, (LPSTR)pstring, nCount, ped, 0, FALSE));
  35. }
  36. int FAR PASCAL MLCalcXOffset(register PED ped,
  37. HDC hdc,
  38. int lineNumber)
  39. /* effects: Calculates the horizontal offset (indent) required for centered
  40. * and right justified lines.
  41. */
  42. {
  43. PSTR pText;
  44. ICH lineLength;
  45. register ICH lineWidth;
  46. if (ped->format == ES_LEFT)
  47. return(0);
  48. lineLength = MLLineLength(ped, lineNumber);
  49. if (lineLength)
  50. {
  51. pText = LocalLock(ped->hText)+ped->chLines[lineNumber];
  52. hdc = ECGetEditDC(ped,TRUE);
  53. lineWidth = LOWORD(LocGetTabbedTextExtent(hdc, pText, lineLength,
  54. ped));
  55. ECReleaseEditDC(ped,hdc,TRUE);
  56. LocalUnlock(ped->hText);
  57. }
  58. else
  59. lineWidth = 0;
  60. /*
  61. * If a SPACE or a TAB was eaten at the end of a line by MLBuildchLines
  62. * to prevent a delimiter appearing at the begining of a line, the
  63. * the following calculation will become negative causing this bug.
  64. * So, now, we take zero in such cases.
  65. * Fix for Bug #3566 --01/31/91-- SANKAR --
  66. */
  67. lineWidth = max(0, ped->rcFmt.right-ped->rcFmt.left-lineWidth);
  68. if (ped->format == ES_CENTER)
  69. return(lineWidth/2);
  70. if (ped->format == ES_RIGHT)
  71. /* Subtract 1 so that the 1 pixel wide cursor will be in the visible
  72. * region on the very right side of the screen.
  73. */
  74. return(max(0, lineWidth-1));
  75. }
  76. ICH NEAR PASCAL MLMoveSelection(register PED ped,
  77. ICH ich,
  78. BOOL fLeft)
  79. /* effects: Moves the selection character in the direction indicated. Assumes
  80. * you are starting at a legal point, we decrement/increment the ich. Then,
  81. * This decrements/increments it some more to get past CRLFs...
  82. */
  83. {
  84. register PSTR pText;
  85. if (fLeft && ich > 0)
  86. {
  87. /* Move left */
  88. #ifdef FE_SB
  89. pText = LMHtoP( ped->hText ) + ich;
  90. if( ECIsDBCSLeadByte(ped, *ECAnsiPrev(ped, LMHtoP(ped->hText), pText ) ) )
  91. ich--;
  92. #endif /* FE_SB */
  93. ich--;
  94. if (ich)
  95. {
  96. /* Check for CRLF or CRCRLF */
  97. /*pText = LocalLock(ped->hText)+ich;*/
  98. pText = LMHtoP(ped->hText)+ich;
  99. /* Move before CRLF or CRCRLF */
  100. if (*pText == 0x0A)
  101. {
  102. ich--;
  103. if (ich && *(pText-2) == 0x0D)
  104. ich--;
  105. }
  106. /*LocalUnlock(ped->hText);*/
  107. }
  108. }
  109. else if (!fLeft && ich < ped->cch)
  110. {
  111. #ifdef FE_SB
  112. pText = LMHtoP(ped->hText)+ich;
  113. if( ECIsDBCSLeadByte(ped, *pText ) )
  114. ich++;
  115. #endif /* FE_SB */
  116. ich++;
  117. if (ich < ped->cch)
  118. {
  119. /*pText = LocalLock(ped->hText)+ich;*/
  120. pText = LMHtoP(ped->hText)+ich;
  121. /* Move after CRLF */
  122. if (*pText == 0x0A)
  123. ich++;
  124. else /* Check for CRCRLF */
  125. if (ich && *pText == 0x0D && *(pText-1) == 0x0D)
  126. ich+=2;
  127. /*LocalUnlock(ped->hText);*/
  128. }
  129. }
  130. return(ich);
  131. }
  132. void FAR PASCAL MLSetCaretPosition(register PED ped, HDC hdc)
  133. /* effects: If the window has the focus, find where the caret belongs and move
  134. * it there.
  135. */
  136. {
  137. LONG position;
  138. BOOL prevLine;
  139. /* We will only position the caret if we have the focus since we don't want
  140. * to move the caret while another window could own it.
  141. */
  142. if (!ped->fFocus || ped->fNoRedraw)
  143. return;
  144. if(ped->fCaretHidden)
  145. {
  146. SetCaretPos(-20000, -20000);
  147. return;
  148. }
  149. /* Find the position of the caret */
  150. if ((ped->iCaretLine < ped->screenStart) ||
  151. (ped->iCaretLine > ped->screenStart+ped->ichLinesOnScreen))
  152. /* Caret is not visible. Make it a very small value so that it won't be
  153. * seen.
  154. */
  155. SetCaretPos(-20000,-20000);
  156. else
  157. {
  158. if (ped->cLines-1 != ped->iCaretLine &&
  159. ped->ichCaret == ped->chLines[ped->iCaretLine+1])
  160. prevLine=TRUE;
  161. else
  162. prevLine=FALSE;
  163. position = MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine);
  164. if (ped->fWrap)
  165. {
  166. if (HIWORD(position) > ped->rcFmt.bottom-ped->lineHeight)
  167. SetCaretPos(-20000,-20000);
  168. else
  169. {
  170. /* Make sure the caret is in the visible region if word
  171. * wrapping. This is so that the caret will be visible if the
  172. * line ends with a space.
  173. */
  174. SetCaretPos(min(LOWORD(position),ped->rcFmt.right-1),
  175. HIWORD(position));
  176. }
  177. }
  178. else
  179. {
  180. if (LOWORD(position) > ped->rcFmt.right ||
  181. HIWORD(position) > ped->rcFmt.bottom)
  182. SetCaretPos(-20000,-20000);
  183. else
  184. SetCaretPos(LOWORD(position),HIWORD(position));
  185. }
  186. }
  187. }
  188. ICH FAR PASCAL MLLineLength(register PED ped, int lineNumber)
  189. /* effects: Returns the length of the line given by lineNumber ignoring any
  190. * CRLFs in the line.
  191. */
  192. {
  193. ICH result;
  194. register PSTR pText;
  195. if (lineNumber >= ped->cLines)
  196. return(0);
  197. if (lineNumber == ped->cLines-1)
  198. /* Since we can't have a CRLF on the last line */
  199. return(ped->cch - ped->chLines[ped->cLines-1]);
  200. else
  201. {
  202. result = ped->chLines[lineNumber+1] - ped->chLines[lineNumber];
  203. /* Now check for CRLF or CRCRLF at end of line */
  204. if (result > 1)
  205. {
  206. /*pText = LocalLock(ped->hText)+ped->chLines[lineNumber+1]-2;*/
  207. pText = LMHtoP(ped->hText)+ped->chLines[lineNumber+1]-2;
  208. if (*pText == 0x0D)
  209. {
  210. result = result - 2;
  211. if (result && *(--pText) == 0x0D)
  212. /* In case there was a CRCRLF */
  213. result--;
  214. }
  215. /*LocalUnlock(ped->hText);*/
  216. }
  217. }
  218. return(result);
  219. }
  220. int FAR PASCAL MLIchToLineHandler(register PED ped, ICH ich)
  221. /* effects: Returns the line number (starting from 0) which contains the given
  222. * character index. If ich is -1, return the line the the first char in the
  223. * selection is on (the caret if no selection)
  224. */
  225. {
  226. register int line = ped->cLines-1;
  227. if (ich == 0xFFFF)
  228. ich = ped->ichMinSel;
  229. /* We could do a binary search here but is it really worth it??? We will
  230. * have to wait and see how often this proc is being called...
  231. */
  232. while (line && (ich < ped->chLines[line]))
  233. line--;
  234. return(line);
  235. }
  236. LONG NEAR PASCAL MLIchToXYPos(register PED ped,
  237. HDC hdc,
  238. ICH ich,
  239. BOOL prevLine)
  240. /* effects: Given an ich, return its x,y coordinates with respect to the top
  241. * left character displayed in the window. Returns the coordinates of the top
  242. * left position of the char. If prevLine is TRUE then if the ich is at the
  243. * beginning of the line, we will return the coordinates to the right of the
  244. * last char on the previous line (if it is not a CRLF). x is in the loword,
  245. * y in the highword.
  246. */
  247. {
  248. int iline;
  249. ICH cch;
  250. int xPosition,yPosition;
  251. int xOffset;
  252. /*
  253. * For horizontal scroll displacement on left justified text and
  254. * for indent on centered or right justified text
  255. */
  256. PSTR pText,pTextStart,pLineStart;
  257. /* Determine what line the character is on */
  258. iline = MLIchToLineHandler(ped, ich);
  259. /* Calc. the yPosition now. Note that this may change by the height of one
  260. * char if the prevLine flag is set and the ICH is at the beginning of a
  261. * line.
  262. */
  263. yPosition = (iline-ped->screenStart)*ped->lineHeight+ped->rcFmt.top;
  264. /* Now determine the xPosition of the character */
  265. pTextStart = LocalLock(ped->hText);
  266. if (prevLine && iline && (ich == ped->chLines[iline]) &&
  267. (*(pTextStart+ich-1) != 0x0A))
  268. {
  269. /* First char in the line. We want text extent upto end of the previous
  270. * line if we aren't at the 0th line.
  271. */
  272. iline--;
  273. yPosition = yPosition - ped->lineHeight;
  274. pLineStart = pTextStart+ped->chLines[iline];
  275. /* Note that we are taking the position in front of any CRLFs in the
  276. * text.
  277. */
  278. cch = MLLineLength(ped, iline);
  279. }
  280. else
  281. {
  282. pLineStart = pTextStart + ped->chLines[iline];
  283. pText = pTextStart + ich;
  284. /* Strip off CRLF or CRCRLF. Note that we may be pointing to a CR but in
  285. * which case we just want to strip off a single CR or 2 CRs.
  286. */
  287. /* We want pText to point to the first CR at the end of the line if
  288. * there is one. Thus, we will get an xPosition to the right of the last
  289. * visible char on the line otherwise we will be to the left of
  290. * character ich.
  291. */
  292. /* Check if we at the end of text */
  293. if(ich < ped -> cch)
  294. {
  295. if (ich && *pText == 0x0A)
  296. pText--;
  297. if (ich > 2 && *(pText-1) == 0x0D)
  298. pText--;
  299. }
  300. cch = pText - pLineStart;
  301. }
  302. /* Find out how many pixels we indent the line for funny formats */
  303. if (ped->format != ES_LEFT)
  304. xOffset = MLCalcXOffset(ped, hdc, iline);
  305. else
  306. xOffset = -ped->xOffset;
  307. xPosition = ped->rcFmt.left + xOffset +
  308. LOWORD(LocGetTabbedTextExtent(hdc, pLineStart, cch, ped));
  309. LocalUnlock(ped->hText);
  310. return(MAKELONG(xPosition,yPosition));
  311. }
  312. LONG NEAR PASCAL MLMouseToIch(register PED ped,
  313. HDC hdc,
  314. POINT mousePt)
  315. /* effects: Returns the closest cch to where the mouse point is. cch is in
  316. * the lowword and lineindex is in the high word. (So that we can tell if we
  317. * are at the beginning of the line or end of the previous line.)
  318. */
  319. {
  320. int xOffset;
  321. PSTR pText;
  322. PSTR pLineStart;
  323. int height = mousePt.y;
  324. int line;
  325. int width = mousePt.x;
  326. ICH cch;
  327. ICH cLineLength;
  328. ICH cLineLengthNew;
  329. ICH cLineLengthHigh=0;
  330. ICH cLineLengthLow=0;
  331. int textWidth;
  332. int iOldTextWidth;
  333. int iCurWidth;
  334. /* First determine which line the mouse is pointing to.
  335. */
  336. line = ped->screenStart;
  337. if (height <= ped->rcFmt.top)
  338. /* Either return 0 (the very first line, or one line before the top line
  339. * on the screen. Note that these are signed mins and maxes since we
  340. * don't expect (or allow) more than 32K lines.
  341. */
  342. line = max(0, line-1);
  343. else if (height >= ped->rcFmt.bottom)
  344. /* Are we below the last line displayed */
  345. line = min(line+ped->ichLinesOnScreen,ped->cLines-1);
  346. else
  347. /* We are somewhere on a line visible on screen */
  348. line=min(line+((height-ped->rcFmt.top)/ped->lineHeight),ped->cLines-1);
  349. /* Now determine what horizontal character the mouse is pointing to.
  350. */
  351. pLineStart=(pText=LocalLock(ped->hText))+ped->chLines[line];
  352. cLineLength = MLLineLength(ped,line); /* Length is sans CRLF or CRCRLF */
  353. /* xOffset will be a negative value for center and right justified lines.
  354. * ie. We will just displace the lines left by the amount of indent for
  355. * right and center justification. Note that ped->xOffset will be 0 for
  356. * these lines since we don't support horizontal scrolling with them.
  357. */
  358. if (ped->format != ES_LEFT)
  359. xOffset = MLCalcXOffset(ped,hdc,line);
  360. else
  361. /* So that we handle a horizontally scrolled window for left justified
  362. * text.
  363. */
  364. xOffset = 0;
  365. width = width - xOffset;
  366. /* The code below is tricky... I depend on the fact that ped->xOffset is 0
  367. * for right and center justified lines
  368. */
  369. /* Now find out how many chars fit in the given width */
  370. if (width >= ped->rcFmt.right)
  371. {
  372. /* Return 1+last char in line or one plus the last char visible */
  373. cch = ECCchInWidth(ped, hdc, (LPSTR)pLineStart, cLineLength,
  374. ped->rcFmt.right-ped->rcFmt.left+ped->xOffset);
  375. #ifdef FE_SB
  376. {
  377. ICH cch2;
  378. cch2 = umin(cch+1,cLineLength);
  379. if (ECAdjustIch( ped, pLineStart, cch2 ) != cch2)
  380. /* Displayed character on the right edge is DBCS */
  381. cch = umin(cch+2,cLineLength);
  382. else cch = cch2;
  383. cch += ped->chLines[line];
  384. }
  385. #else
  386. cch = ped->chLines[line]+umin(cch+1,cLineLength);
  387. #endif
  388. }
  389. else if (width <= ped->rcFmt.left + ped->aveCharWidth/2)
  390. {
  391. /* Return first char in line or one minus first char visible. Note that
  392. * ped->xOffset is 0 for right and centered text so we will just return
  393. * the first char in the string for them. (Allow a avecharwidth/2
  394. * positioning border so that the user can be a little off...
  395. */
  396. cch = ECCchInWidth(ped, hdc, (LPSTR)pLineStart, cLineLength,
  397. ped->xOffset);
  398. if (cch)
  399. cch--;
  400. #ifdef FE_SB
  401. cch = ECAdjustIch( ped, pLineStart, cch );
  402. #endif
  403. cch = ped->chLines[line]+cch;
  404. }
  405. else
  406. {
  407. /* Now the mouse is somewhere on the visible portion of the text
  408. * remember cch contains the length the line.
  409. */
  410. iCurWidth = width + ped->xOffset;
  411. cLineLengthHigh = cLineLength+1;
  412. while(cLineLengthLow < cLineLengthHigh-1)
  413. {
  414. cLineLengthNew = umax((cLineLengthHigh-cLineLengthLow)/2,1)+
  415. cLineLengthLow;
  416. /* Add in a avecharwidth/2 so that if user is half way on the next
  417. * char, it is still considered the previous char. For that feel.
  418. */
  419. textWidth = ped->rcFmt.left + ped->aveCharWidth/2 +
  420. LOWORD(LocGetTabbedTextExtent(hdc, pLineStart,
  421. cLineLengthNew, ped));
  422. if (textWidth > iCurWidth)
  423. cLineLengthHigh = cLineLengthNew;
  424. else
  425. cLineLengthLow = cLineLengthNew;
  426. /* Preserve the old Width */
  427. iOldTextWidth = textWidth;
  428. }
  429. /* Find out which side of the character the mouse click occurred */
  430. if ((iOldTextWidth - iCurWidth) < (iCurWidth - textWidth))
  431. cLineLengthNew++;
  432. cLineLength = umin(cLineLengthNew,cLineLength);
  433. #ifdef FE_SB
  434. cLineLength = ECAdjustIch( ped, pLineStart, cLineLength );
  435. #endif
  436. cch = ped->chLines[line]+cLineLength;
  437. }
  438. LocalUnlock(ped->hText);
  439. return(MAKELONG(cch,line));
  440. }
  441. void NEAR PASCAL MLRepaintChangedSelection(PED ped,
  442. HDC hdc,
  443. ICH ichOldMinSel,
  444. ICH ichOldMaxSel)
  445. /* When selection changes, this takes care of drawing the changed portions
  446. * with proper attributes.
  447. */
  448. {
  449. BLOCK Blk[2];
  450. int iBlkCount = 0;
  451. int i;
  452. Blk[0].StPos = ichOldMinSel;
  453. Blk[0].EndPos = ichOldMaxSel;
  454. Blk[1].StPos = ped->ichMinSel;
  455. Blk[1].EndPos = ped->ichMaxSel;
  456. if (ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
  457. (LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1]))
  458. {
  459. /* Paint the rectangles where selection has changed */
  460. /* Paint both Blk[0] and Blk[1], if they exist */
  461. for(i = 0; i < 2; i++)
  462. {
  463. if (Blk[i].StPos != -1)
  464. MLDrawText(ped, hdc, Blk[i].StPos, Blk[i].EndPos);
  465. }
  466. }
  467. }
  468. void FAR PASCAL MLChangeSelection(register PED ped,
  469. HDC hdc,
  470. ICH ichNewMinSel,
  471. ICH ichNewMaxSel)
  472. /* effects: Changes the current selection to have the specified starting and
  473. * ending values. Properly highlights the new selection and unhighlights
  474. * anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
  475. * them. Doesn't update the caret position.
  476. */
  477. {
  478. ICH temp;
  479. ICH ichOldMinSel, ichOldMaxSel;
  480. if (ichNewMinSel > ichNewMaxSel)
  481. {
  482. temp = ichNewMinSel;
  483. ichNewMinSel = ichNewMaxSel;
  484. ichNewMaxSel = temp;
  485. }
  486. ichNewMinSel = umin(ichNewMinSel, ped->cch);
  487. ichNewMaxSel = umin(ichNewMaxSel, ped->cch);
  488. /* Save the current selection */
  489. ichOldMinSel = ped->ichMinSel;
  490. ichOldMaxSel = ped->ichMaxSel;
  491. /* Set new selection */
  492. ped->ichMinSel = ichNewMinSel;
  493. ped->ichMaxSel = ichNewMaxSel;
  494. /* We only update the selection on the screen if redraw is on and if we have
  495. * the focus or if we don't hide the selection when we don't have the focus.
  496. */
  497. if (!ped->fNoRedraw && (ped->fFocus || ped->fNoHideSel))
  498. {
  499. /* Find old selection region, find new region, and invert the XOR of the
  500. * two and invert only the XOR region.
  501. */
  502. MLRepaintChangedSelection(ped, hdc, ichOldMinSel, ichOldMaxSel);
  503. MLSetCaretPosition(ped,hdc);
  504. }
  505. }
  506. // This updates the ped->iCaretLine field from the ped->ichCaret;
  507. // Also, when the caret gets to the beginning of next line, pop it up to
  508. // the end of current line when inserting text;
  509. void NEAR PASCAL MLUpdateiCaretLine(PED ped)
  510. {
  511. PSTR pText;
  512. ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
  513. /* If caret gets to beginning of next line, pop it up to end of current line
  514. * when inserting text.
  515. */
  516. pText = LMHtoP(ped->hText)+ped->ichCaret-1;
  517. if (ped->iCaretLine && ped->chLines[ped->iCaretLine] == ped->ichCaret &&
  518. *pText != 0x0A)
  519. ped->iCaretLine--;
  520. }
  521. ICH FAR PASCAL MLInsertText(ped, lpText, cchInsert, fUserTyping)
  522. register PED ped;
  523. LPSTR lpText;
  524. ICH cchInsert;
  525. BOOL fUserTyping;
  526. /* effects: Adds up to cchInsert characters from lpText to the ped starting at
  527. * ichCaret. If the ped only allows a maximum number of characters, then we
  528. * will only add that many characters to the ped. The number of characters
  529. * actually added is returned (could be 0). If we can't allocate the required
  530. * space, we notify the parent with EN_ERRSPACE and no characters are added.
  531. * We will rebuild the lines array as needed. fUserTyping is true if the
  532. * input was the result of the user typing at the keyboard. This is so we can
  533. * do some stuff faster since we will be getting only one or two chars of
  534. * input.
  535. */
  536. {
  537. HDC hdc;
  538. ICH validCch=cchInsert;
  539. ICH oldCaret = ped->ichCaret;
  540. int oldCaretLine = ped->iCaretLine;
  541. BOOL fCRLF=FALSE;
  542. LONG l;
  543. WORD localundoType = 0;
  544. HANDLE localhDeletedText;
  545. ICH localichDeleted;
  546. ICH localcchDeleted;
  547. ICH localichInsStart;
  548. ICH localichInsEnd;
  549. LONG xyPosInitial=0L;
  550. LONG xyPosFinal=0L;
  551. if (!validCch)
  552. return(0);
  553. if (validCch)
  554. {
  555. /* Limit the amount of text we add */
  556. _asm int 3
  557. if (ped->cchTextMax <= ped->cch)
  558. {
  559. /* When the max chars is reached already, notify parent */
  560. /* Fix for Bug #4183 -- 02/06/91 -- SANKAR -- */
  561. ECNotifyParent(ped,EN_MAXTEXT);
  562. return(0);
  563. }
  564. validCch = umin(validCch, ped->cchTextMax - ped->cch);
  565. /* Make sure we don't split a CRLF in half */
  566. if (validCch && *(lpText+validCch) == 0x0A)
  567. validCch--;
  568. if (!validCch)
  569. {
  570. /* When the max chars is reached already, notify parent */
  571. /* Fix for Bug #4183 -- 02/06/91 -- SANKAR -- */
  572. ECNotifyParent(ped,EN_MAXTEXT);
  573. return(0);
  574. }
  575. if (validCch == 2 && (*(WORD FAR *)lpText) == 0x0A0D)
  576. fCRLF=TRUE;
  577. if (!ped->fAutoVScroll &&
  578. (ped->undoType==UNDO_INSERT || ped->undoType==UNDO_DELETE))
  579. {
  580. /* Save off the current undo state */
  581. localundoType = ped->undoType;
  582. localhDeletedText = ped->hDeletedText;
  583. localichDeleted = ped->ichDeleted;
  584. localcchDeleted = ped->cchDeleted;
  585. localichInsStart = ped->ichInsStart;
  586. localichInsEnd = ped->ichInsEnd;
  587. /* Kill undo */
  588. ped->undoType = UNDO_NONE;
  589. ped->hDeletedText = NULL;
  590. ped->ichDeleted=
  591. ped->cchDeleted =
  592. ped->ichInsStart=
  593. ped->ichInsEnd = 0;
  594. }
  595. hdc = ECGetEditDC(ped,FALSE);
  596. if (ped->cch)
  597. xyPosInitial = MLIchToXYPos(ped, hdc, ped->cch-1, FALSE);
  598. /* Insert the text */
  599. if (!ECInsertText(ped, lpText, validCch))
  600. {
  601. ECReleaseEditDC(ped,hdc,FALSE);
  602. ECNotifyParent(ped, EN_ERRSPACE);
  603. return(0);
  604. }
  605. /* Note that ped->ichCaret is updated by ECInsertText */
  606. }
  607. l = MLBuildchLines(ped, oldCaretLine, validCch,
  608. (fCRLF ? FALSE : fUserTyping));
  609. if (ped->cch)
  610. xyPosFinal = MLIchToXYPos(ped, hdc, ped->cch-1, FALSE);
  611. if (HIWORD(xyPosFinal) < HIWORD(xyPosInitial) &&
  612. ped->screenStart+ped->ichLinesOnScreen >= ped->cLines-1)
  613. {
  614. RECT rc;
  615. CopyRect((LPRECT)&rc, (LPRECT)&ped->rcFmt);
  616. rc.top = HIWORD(xyPosFinal)+ped->lineHeight;
  617. InvalidateRect(ped->hwnd, (LPRECT)&rc, TRUE);
  618. }
  619. if (!ped->fAutoVScroll)
  620. {
  621. if (ped->ichLinesOnScreen < ped->cLines)
  622. {
  623. MLUndoHandler(ped);
  624. ECEmptyUndo(ped);
  625. if (localundoType == UNDO_INSERT || localundoType == UNDO_DELETE)
  626. {
  627. ped->undoType = localundoType;
  628. ped->hDeletedText = localhDeletedText;
  629. ped->ichDeleted = localichDeleted;
  630. ped->cchDeleted = localcchDeleted;
  631. ped->ichInsStart = localichInsStart;
  632. ped->ichInsEnd = localichInsEnd;
  633. }
  634. MessageBeep(0);
  635. ECReleaseEditDC(ped,hdc,FALSE);
  636. return(0);
  637. }
  638. else
  639. {
  640. if (localundoType == UNDO_INSERT || localundoType == UNDO_DELETE)
  641. GlobalFree(localhDeletedText);
  642. }
  643. }
  644. if (fUserTyping && ped->fWrap)
  645. #ifdef FE_SB
  646. /* To avoid oldCaret points intermediate of DBCS character,
  647. * adjust oldCaret position if necessary.
  648. */
  649. oldCaret = ECAdjustIch(ped, LMHtoP(ped->hText), umin(LOWORD(l), oldCaret));
  650. #else
  651. oldCaret = umin(LOWORD(l), oldCaret);
  652. #endif
  653. /* These are updated by ECInsertText so we won't do it again */
  654. /* ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;*/
  655. #ifdef NEVER
  656. ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
  657. /* If caret gets to beginning of next line, pop it up to end of current line
  658. * when inserting text.
  659. */
  660. pText = LMHtoP(ped->hText)+ped->ichCaret-1;
  661. if (ped->iCaretLine && ped->chLines[ped->iCaretLine] == ped->ichCaret &&
  662. *pText != 0x0A)
  663. ped->iCaretLine--;
  664. #else
  665. // Update ped->iCaretLine properly.
  666. MLUpdateiCaretLine(ped);
  667. #endif
  668. ECNotifyParent(ped,EN_UPDATE);
  669. if (fCRLF || !fUserTyping)
  670. /* Redraw to end of screen/text if crlf or large insert.
  671. */
  672. MLDrawText(ped, hdc, (fUserTyping ? oldCaret : 0), ped->cch);
  673. else
  674. MLDrawText(ped, hdc, oldCaret, umax(ped->ichCaret,HIWORD(l)));
  675. ECReleaseEditDC(ped,hdc,FALSE);
  676. /* Make sure we can see the cursor */
  677. MLEnsureCaretVisible(ped);
  678. ped->fDirty = TRUE;
  679. ECNotifyParent(ped,EN_CHANGE);
  680. if (validCch < cchInsert)
  681. ECNotifyParent(ped,EN_MAXTEXT);
  682. return(validCch);
  683. }
  684. ICH NEAR PASCAL MLDeleteText(register PED ped)
  685. /* effects: Deletes the characters between ichMin and ichMax. Returns the
  686. * number of characters we deleted.
  687. */
  688. {
  689. ICH minSel = ped->ichMinSel;
  690. ICH maxSel = ped->ichMaxSel;
  691. ICH cchDelete;
  692. HDC hdc;
  693. int minSelLine;
  694. int maxSelLine;
  695. LONG xyPos;
  696. RECT rc;
  697. BOOL fFastDelete = FALSE;
  698. LONG l;
  699. #ifdef FE_SB
  700. ICH cchcount;
  701. #endif
  702. /* Get what line the min selection is on so that we can start rebuilding the
  703. * text from there if we delete anything.
  704. */
  705. minSelLine = MLIchToLineHandler(ped,minSel);
  706. maxSelLine = MLIchToLineHandler(ped,maxSel);
  707. #ifdef FE_SB
  708. switch(maxSel - minSel)
  709. {
  710. case 2:
  711. if (ECIsDBCSLeadByte(ped,*(LMHtoP(ped->hText)+minSel)) == FALSE)
  712. break;
  713. /* Fall thru */
  714. case 1:
  715. // if ((minSelLine==maxSelLine) && (ped->chLines[minSelLine] != minSel))
  716. if (minSelLine==maxSelLine)
  717. {
  718. if (!ped->fAutoVScroll)
  719. fFastDelete = FALSE;
  720. else
  721. {
  722. fFastDelete = TRUE;
  723. cchcount = ((maxSel - minSel) == 1) ? 0 : -1;
  724. }
  725. }
  726. }
  727. #else
  728. if (((maxSel - minSel) == 1) &&
  729. (minSelLine==maxSelLine) &&
  730. (ped->chLines[minSelLine] != minSel))
  731. {
  732. if (!ped->fAutoVScroll)
  733. fFastDelete = FALSE;
  734. else
  735. fFastDelete = TRUE;
  736. }
  737. #endif
  738. if (!(cchDelete=ECDeleteText(ped)))
  739. return(0);
  740. /* Start building lines at minsel line since caretline may be at the max sel
  741. * point.
  742. */
  743. if (fFastDelete)
  744. {
  745. #ifdef FE_SB
  746. MLShiftchLines(ped, minSelLine+1, -2+cchcount);
  747. #else
  748. MLShiftchLines(ped, minSelLine+1, -2);
  749. #endif
  750. l=MLBuildchLines(ped, minSelLine, 1, TRUE);
  751. }
  752. else
  753. {
  754. MLBuildchLines(ped,max(minSelLine-1,0),-cchDelete, FALSE);
  755. }
  756. #ifdef NEVER
  757. ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
  758. /* If caret gets to beginning of this line, pop it up to end of previous
  759. * line when deleting text
  760. */
  761. pText = LMHtoP(ped->hText)+ped->ichCaret;
  762. if (ped->iCaretLine && ped->chLines[ped->iCaretLine] == ped->ichCaret
  763. && *(pText-1)!= 0x0A)
  764. ped->iCaretLine--;
  765. #else
  766. MLUpdateiCaretLine(ped);
  767. #endif
  768. #if 0
  769. if (!ped->fAutoVScroll)
  770. ECEmptyUndo(ped);
  771. #endif
  772. ECNotifyParent(ped,EN_UPDATE);
  773. /* Now update the screen to reflect the deletion */
  774. hdc = ECGetEditDC(ped,FALSE);
  775. /* Otherwise just redraw starting at the line we just entered */
  776. minSelLine = max(minSelLine-1,0);
  777. if (fFastDelete)
  778. MLDrawText(ped, hdc, ped->chLines[minSelLine], HIWORD(l));
  779. else
  780. MLDrawText(ped, hdc, ped->chLines[minSelLine], ped->cch);
  781. if (ped->cch)
  782. {
  783. /* Clear from end of text to end of window.
  784. */
  785. xyPos = MLIchToXYPos(ped, hdc, ped->cch, FALSE);
  786. CopyRect((LPRECT)&rc, (LPRECT)&ped->rcFmt);
  787. rc.top = HIWORD(xyPos)+ped->lineHeight;
  788. InvalidateRect(ped->hwnd, (LPRECT)&rc, TRUE);
  789. }
  790. else
  791. {
  792. InvalidateRect(ped->hwnd, (LPRECT)&ped->rcFmt, TRUE);
  793. }
  794. ECReleaseEditDC(ped,hdc,FALSE);
  795. MLEnsureCaretVisible(ped);
  796. ped->fDirty = TRUE;
  797. ECNotifyParent(ped,EN_CHANGE);
  798. return(cchDelete);
  799. }
  800. BOOL NEAR PASCAL MLInsertchLine(register PED ped,
  801. int iLine,
  802. ICH ich,
  803. BOOL fUserTyping)
  804. /* effects: Inserts the line iline and sets its starting character index to be
  805. * ich. All the other line indices are moved up. Returns TRUE if successful
  806. * else FALSE and notifies the parent that there was no memory.
  807. */
  808. {
  809. HANDLE hResult;
  810. if (fUserTyping && iLine < ped->cLines)
  811. {
  812. ped->chLines[iLine] = ich;
  813. return(TRUE);
  814. }
  815. hResult =
  816. LocalReAlloc((HANDLE)ped->chLines,(ped->cLines+2)*sizeof(int),LHND);
  817. if (!hResult)
  818. {
  819. ECNotifyParent(ped, EN_ERRSPACE);
  820. return(FALSE);
  821. }
  822. ped->chLines = (int *)hResult;
  823. /* Move indices starting at iLine up */
  824. LCopyStruct((LPSTR)(&ped->chLines[iLine]),(LPSTR)(&ped->chLines[iLine+1]),
  825. (ped->cLines-iLine)*sizeof(int));
  826. ped->cLines++;
  827. ped->chLines[iLine] = ich;
  828. return(TRUE);
  829. }
  830. #if 0
  831. BOOL NEAR PASCAL MLGrowLinesArray(ped, cLines)
  832. register PED ped;
  833. int cLines;
  834. /* effects: Grows the line start array in the ped so that it holds cLines.
  835. * Notifies parent and returns FALSE if no memory error. We won't allow more
  836. * than 32700 lines in the edit control. This allows us to use signed values
  837. * for line counts while still providing good functionality.
  838. */
  839. {
  840. HANDLE hResult;
  841. if (cLines<32700 &&
  842. (hResult = LocalReAlloc((HANDLE)ped->chLines,
  843. (cLines+1)*sizeof(ICH),LHND)))
  844. ped->chLines = (int *)hResult;
  845. else
  846. ECNotifyParent(ped, EN_ERRSPACE);
  847. return((BOOL)hResult);
  848. }
  849. #endif
  850. void NEAR PASCAL MLShiftchLines(register PED ped,
  851. register int iLine,
  852. int delta)
  853. /* effects: Move the starting index of all lines iLine or greater by delta
  854. * bytes.
  855. */
  856. {
  857. if (iLine >= ped->cLines)
  858. return;
  859. /* Just add delta to the starting point of each line after iLine */
  860. for (;iLine<ped->cLines;iLine++)
  861. ped->chLines[iLine] += delta;
  862. }
  863. LONG FAR PASCAL MLBuildchLines(ped, iLine, cchDelta, fUserTyping)
  864. register PED ped;
  865. int iLine;
  866. int cchDelta;
  867. BOOL fUserTyping;
  868. /* effects: Rebuilds the start of line array (ped->chLines) starting at line
  869. * number ichLine. Returns TRUE if any new lines were made else returns
  870. * false.
  871. */
  872. {
  873. register PSTR ptext; /* Starting address of the text */
  874. /* We keep these ICH's so that we can Unlock ped->hText when we have to grow
  875. * the chlines array. With large text handles, it becomes a problem if we
  876. * have a locked block in the way.
  877. */
  878. ICH ichLineStart;
  879. ICH ichLineEnd;
  880. ICH ichLineEndBeforeCRLF;
  881. ICH ichCRLF;
  882. int iLineStart = iLine;
  883. ICH cLineLength;
  884. ICH cch;
  885. HDC hdc;
  886. BOOL fLineBroken = FALSE; /* Initially, no new line breaks are made */
  887. ICH minCchBreak;
  888. ICH maxCchBreak;
  889. if (!ped->cch)
  890. {
  891. ped->maxPixelWidth = 0;
  892. ped->xOffset = 0;
  893. ped->screenStart = 0;
  894. ped->cLines = 1;
  895. return(TRUE);
  896. }
  897. if (fUserTyping && cchDelta)
  898. MLShiftchLines(ped, iLine+1, cchDelta);
  899. hdc = ECGetEditDC(ped, TRUE);
  900. if (!iLine && !cchDelta && !fUserTyping)
  901. {
  902. /* Reset maxpixelwidth only if we will be running through the whole
  903. * text. Better too long than too short.
  904. */
  905. ped->maxPixelWidth = 0;
  906. /* Reset number of lines in text since we will be running through all
  907. * the text anyway...
  908. */
  909. ped->cLines = 1;
  910. }
  911. /* Set min and max line built to be the starting line */
  912. minCchBreak = maxCchBreak = (cchDelta ? ped->chLines[iLine] : 0);
  913. ptext = LocalLock(ped->hText);
  914. ichCRLF = ichLineStart = ped->chLines[iLine];
  915. while (ichLineStart < ped->cch)
  916. {
  917. if (ichLineStart >= ichCRLF)
  918. {
  919. ichCRLF = ichLineStart;
  920. /* Move ichCRLF ahead to either the first CR or to the end of text.
  921. */
  922. while (ichCRLF < ped->cch && *(ptext+ichCRLF) != 0x0D)
  923. ichCRLF++;
  924. }
  925. if (!ped->fWrap)
  926. {
  927. /* If we are not word wrapping, line breaks are signified by CRLF.
  928. */
  929. /* We will limit lines to MAXLINELENGTH characters maximum */
  930. ichLineEnd=ichLineStart + umin(ichCRLF-ichLineStart,MAXLINELENGTH);
  931. #ifdef FE_SB
  932. /* To avoid separating between DBCS char, adjust character
  933. * position to DBCS lead byte if necessary.
  934. */
  935. ichLineEnd = ECAdjustIch(ped, ptext, ichLineEnd);
  936. #endif
  937. /* We will keep track of what the longest line is for the horizontal
  938. * scroll bar thumb positioning.
  939. */
  940. ped->maxPixelWidth = umax(ped->maxPixelWidth,
  941. (unsigned int)
  942. LOWORD(LocGetTabbedTextExtent(hdc,
  943. (ptext+ichLineStart),
  944. ichLineEnd-ichLineStart,
  945. ped)));
  946. }
  947. else
  948. {
  949. /* Find the end of the line based solely on text extents */
  950. ichLineEnd = ichLineStart +
  951. ECCchInWidth(ped, hdc, (LPSTR)(ptext+ichLineStart),
  952. ichCRLF-ichLineStart,
  953. ped->rcFmt.right-ped->rcFmt.left);
  954. if (ichLineEnd == ichLineStart && ichCRLF-ichLineStart)
  955. {
  956. /* Maintain a minimum of one char per line */
  957. ichLineEnd++;
  958. }
  959. #ifdef NEVER
  960. /* Now starting from ichLineEnd, if we are not at a hard line break,
  961. * then if we are not at a space (or CR) or the char before us is
  962. * not a space, we will look word left for the start of the word to
  963. * break at.
  964. */
  965. if (ichLineEnd != ichCRLF)
  966. if (!MLIsDelimiter(*(ptext+ichLineEnd)) ||
  967. *(ptext+ichLineEnd) == 0x0D ||
  968. !MLIsDelimiter(*(ptext+ichLineEnd-1)))
  969. #else
  970. /* Now starting from ichLineEnd, if we are not at a hard line break,
  971. * then if we are not at a space AND the char before us is
  972. * not a space,(OR if we are at a CR) we will look word left for the
  973. * start of the word to break at.
  974. * This change was done for TWO reasons:
  975. * 1. If we are on a delimiter, no need to look word left to break at.
  976. * 2. If the previous char is a delimter, we can break at current char.
  977. * Change done by -- SANKAR --01/31/91--
  978. */
  979. if (ichLineEnd != ichCRLF)
  980. if ((!MLIsDelimiter(*(ptext+ichLineEnd)) &&
  981. !MLIsDelimiter(*(ptext+ichLineEnd-1))) ||
  982. *(ptext+ichLineEnd) == 0x0D)
  983. #endif
  984. {
  985. #ifdef FE_SB
  986. cch = LOWORD(ECWord(ped, ichLineEnd, FALSE));
  987. #else
  988. cch = LOWORD(ECWord(ped, ichLineEnd, TRUE));
  989. #endif
  990. if (cch > ichLineStart)
  991. ichLineEnd = cch;
  992. /* Now, if the above test fails, it means the word left goes
  993. * back before the start of the line ie. a word is longer
  994. * than a line on the screen. So, we just fit as much of
  995. * the word on the line as possible. Thus, we use the
  996. * pLineEnd we calculated solely on width at the beginning
  997. * of this else block...
  998. */
  999. }
  1000. }
  1001. #if 0
  1002. if (!MLIsDelimiter((*(ptext+ichLineEnd-1))) &&
  1003. MLIsDelimiter((*(ptext+ichLineEnd))))
  1004. #endif
  1005. if ((*(ptext+ichLineEnd-1)!= ' ' && *(ptext+ichLineEnd-1)!= TAB) &&
  1006. (*(ptext+ichLineEnd) == ' ' || *(ptext+ichLineEnd) == TAB))
  1007. /* Swallow the space at the end of a line. */
  1008. ichLineEnd++;
  1009. /* Skip over crlf or crcrlf if it exists. Thus, ichLineEnd is the first
  1010. * character in the next line.
  1011. */
  1012. ichLineEndBeforeCRLF = ichLineEnd;
  1013. if (*(ptext+ichLineEnd) == 0x0D)
  1014. ichLineEnd +=2;
  1015. /* Skip over CRCRLF */
  1016. if (*(ptext+ichLineEnd) == 0x0A)
  1017. ichLineEnd++;
  1018. /* Now, increment iLine, allocate space for the next line, and set its
  1019. * starting point
  1020. */
  1021. iLine++;
  1022. if (!fUserTyping ||/* (iLineStart+1 >= iLine) || */
  1023. (iLine > ped->cLines-1) ||
  1024. (ped->chLines[iLine] != ichLineEnd))
  1025. {
  1026. /* The line break occured in a different place than before. */
  1027. if (!fLineBroken)
  1028. {
  1029. /* Since we haven't broken a line before, just set the min break
  1030. * line.
  1031. */
  1032. fLineBroken = TRUE;
  1033. if (ichLineEndBeforeCRLF == ichLineEnd)
  1034. minCchBreak = maxCchBreak = (ichLineEnd ? ichLineEnd-1 : 0);
  1035. else
  1036. minCchBreak = maxCchBreak = ichLineEndBeforeCRLF;
  1037. }
  1038. maxCchBreak = umax(maxCchBreak,ichLineEnd);
  1039. LocalUnlock(ped->hText);
  1040. /* Now insert the new line into the array */
  1041. if (!MLInsertchLine(ped, iLine, ichLineEnd, (BOOL)(cchDelta!=0)))
  1042. {
  1043. ECReleaseEditDC(ped,hdc,TRUE);
  1044. return(MAKELONG(minCchBreak,maxCchBreak));
  1045. }
  1046. ptext = LocalLock(ped->hText);
  1047. }
  1048. else
  1049. {
  1050. maxCchBreak = ped->chLines[iLine];
  1051. /* Quick escape */
  1052. goto EndUp;
  1053. }
  1054. ichLineStart = ichLineEnd;
  1055. } /* end while (ichLineStart < ped->cch) */
  1056. if (iLine != ped->cLines)
  1057. {
  1058. ped->cLines = iLine;
  1059. ped->chLines[ped->cLines] = 0;
  1060. }
  1061. /* Note that we incremented iLine towards the end of the while loop so, the
  1062. * index, iLine, is actually equal to the line count
  1063. */
  1064. if (ped->cch &&
  1065. *(ptext+ped->cch-1) == 0x0A &&
  1066. ped->chLines[ped->cLines-1]<ped->cch)
  1067. /* Make sure last line has no crlf in it */
  1068. {
  1069. if (!fLineBroken)
  1070. {
  1071. /* Since we haven't broken a line before, just set the min break
  1072. * line.
  1073. */
  1074. fLineBroken = TRUE;
  1075. minCchBreak = ped->cch-1;
  1076. }
  1077. maxCchBreak= umax(maxCchBreak,ichLineEnd);
  1078. LocalUnlock(ped->hText);
  1079. MLInsertchLine(ped, iLine, ped->cch, FALSE);
  1080. }
  1081. else
  1082. EndUp:
  1083. LocalUnlock(ped->hText);
  1084. ECReleaseEditDC(ped, hdc, TRUE);
  1085. return(MAKELONG(minCchBreak,maxCchBreak));
  1086. }
  1087. void NEAR PASCAL MLPaintHandler(register PED ped,
  1088. HDC althdc)
  1089. /* effects: Handles WM_PAINT messages.
  1090. */
  1091. {
  1092. PAINTSTRUCT ps;
  1093. HDC hdc;
  1094. HDC hdcWindow;
  1095. RECT rcEdit;
  1096. DWORD dwStyle;
  1097. HANDLE hOldFont;
  1098. POINT pt;
  1099. ICH imin;
  1100. ICH imax;
  1101. /* Allow subclassed hdcs.
  1102. */
  1103. if (althdc)
  1104. hdc = althdc;
  1105. else
  1106. hdc = BeginPaint(ped->hwnd, (PAINTSTRUCT FAR *)&ps);
  1107. if (!ped->fNoRedraw && IsWindowVisible(ped->hwnd))
  1108. {
  1109. #if 0
  1110. if (althdc || ps.fErase)
  1111. {
  1112. hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
  1113. /* Erase the background since we don't do it in the erasebkgnd
  1114. * message
  1115. */
  1116. FillWindow(ped->hwndParent, ped->hwnd, hdc, hBrush);
  1117. }
  1118. #endif
  1119. if (ped->fBorder)
  1120. {
  1121. // hdcWindow = GetWindowDC(ped->hwnd);
  1122. hdcWindow = hdc;
  1123. GetWindowRect(ped->hwnd, &rcEdit);
  1124. OffsetRect(&rcEdit, -rcEdit.left, -rcEdit.top);
  1125. dwStyle = GetWindowLong(ped->hwnd, GWL_STYLE);
  1126. if (HIWORD(dwStyle) & HIWORD(WS_SIZEBOX))
  1127. {
  1128. /* Note we can't use user's globals here since we are on a
  1129. * different ds when in the edit control code.
  1130. */
  1131. InflateRect(&rcEdit,
  1132. -GetSystemMetrics(SM_CXFRAME)+
  1133. GetSystemMetrics(SM_CXBORDER),
  1134. -GetSystemMetrics(SM_CYFRAME)+
  1135. GetSystemMetrics(SM_CYBORDER));
  1136. }
  1137. DrawFrame(hdcWindow, (LPRECT)&rcEdit, 1, DF_WINDOWFRAME);
  1138. // ReleaseDC(ped->hwnd, hdcWindow);
  1139. }
  1140. ECSetEditClip(ped, hdc);
  1141. if (ped->hFont)
  1142. hOldFont = SelectObject(hdc, ped->hFont);
  1143. if (!althdc)
  1144. {
  1145. pt.x = ps.rcPaint.left;
  1146. pt.y = ps.rcPaint.top;
  1147. imin = MLMouseToIch(ped, hdc, pt)-1;
  1148. if (imin == -1)
  1149. imin = 0;
  1150. pt.x = ps.rcPaint.right;
  1151. pt.y = ps.rcPaint.bottom;
  1152. imax = MLMouseToIch(ped, hdc, pt)+1;
  1153. MLDrawText(ped, hdc, imin, imax);
  1154. }
  1155. else
  1156. MLDrawText(ped, hdc, 0, ped->cch);
  1157. if (ped->hFont && hOldFont)
  1158. SelectObject(hdc, hOldFont);
  1159. }
  1160. if (!althdc)
  1161. EndPaint(ped->hwnd, (PAINTSTRUCT FAR *)&ps);
  1162. }
  1163. void FAR PASCAL MLCharHandler(ped, keyValue, keyMods)
  1164. register PED ped;
  1165. WORD keyValue;
  1166. int keyMods;
  1167. /* effects: Handles character input (really, no foolin')
  1168. */
  1169. {
  1170. char unsigned keyPress = LOBYTE(keyValue);
  1171. BOOL updateText = FALSE;
  1172. int scState;
  1173. #ifdef FE_SB
  1174. WORD DBCSkey;
  1175. #endif
  1176. if (ped->fMouseDown || keyPress == VK_ESCAPE)
  1177. /* If we are in the middle of a mousedown command, don't do anything.
  1178. * Also, just ignore it if we get a translated escape key which happens
  1179. * with multiline edit controls in a dialog box.
  1180. */
  1181. return;
  1182. if (!keyMods)
  1183. {
  1184. /* Get state of modifier keys for use later. */
  1185. scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
  1186. /* We are just interested in state of the ctrl key */
  1187. /* scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0); */
  1188. }
  1189. else
  1190. scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
  1191. if (ped->fInDialogBox && ((keyPress == VK_TAB && scState != CTRLDOWN) ||
  1192. keyPress == VK_RETURN))
  1193. /* If this multiline edit control is in a dialog box, then we want the
  1194. * TAB key to take you to the next control, shift TAB to take you to the
  1195. * previous control, and CTRL-TAB to insert a tab into the edit control.
  1196. * We moved the focus when we received the keydown message so we will
  1197. * ignore the TAB key now unless the ctrl key is down. Also, we want
  1198. * CTRL-RETURN to insert a return into the text and RETURN to be sent to
  1199. * the default button.
  1200. */
  1201. return;
  1202. if (ped->fReadOnly)
  1203. /* Ignore keys in read only controls.
  1204. */
  1205. return;
  1206. if (keyPress == 0x0A)
  1207. keyPress = VK_RETURN;
  1208. if (keyPress == VK_TAB || keyPress == VK_RETURN ||
  1209. keyPress == VK_BACK || keyPress >= ' ')
  1210. /* Delete the selected text if any */
  1211. if (MLDeleteText(ped))
  1212. updateText=TRUE;
  1213. #ifdef FE_SB
  1214. if( IsDBCSLeadByte( keyPress ) )
  1215. if( ( DBCSkey = DBCSCombine( ped->hwnd, keyPress ) ) != NULL )
  1216. keyValue = DBCSkey;
  1217. #endif
  1218. switch(keyPress)
  1219. {
  1220. case VK_BACK:
  1221. /* Delete any selected text or delete character left if no sel */
  1222. if (!updateText && ped->ichMinSel)
  1223. {
  1224. /* There was no selection to delete so we just delete character
  1225. * left if available
  1226. */
  1227. ped->ichMinSel = MLMoveSelection(ped,ped->ichCaret,TRUE);
  1228. MLDeleteText(ped);
  1229. }
  1230. break;
  1231. default:
  1232. if (keyPress == VK_RETURN)
  1233. keyValue = 0x0A0D;
  1234. if (keyPress >= ' ' || keyPress == VK_RETURN || keyPress == VK_TAB)
  1235. MLInsertText(ped, (LPSTR) &keyValue,
  1236. HIBYTE(keyValue) ? 2 : 1, TRUE);
  1237. else
  1238. MessageBeep(0);
  1239. break;
  1240. }
  1241. }
  1242. void NEAR PASCAL MLKeyDownHandler(register PED ped,
  1243. WORD virtKeyCode,
  1244. int keyMods)
  1245. /* effects: Handles cursor movement and other VIRT KEY stuff. keyMods allows
  1246. * us to make MLKeyDownHandler calls and specify if the modifier keys (shift
  1247. * and control) are up or down. If keyMods == 0, we get the keyboard state
  1248. * using GetKeyState(VK_SHIFT) etc. Otherwise, the bits in keyMods define the
  1249. * state of the shift and control keys.
  1250. */
  1251. {
  1252. HDC hdc;
  1253. /* Variables we will use for redrawing the updated text */
  1254. register ICH newMaxSel = ped->ichMaxSel;
  1255. register ICH newMinSel = ped->ichMinSel;
  1256. /* Flags for drawing the updated text */
  1257. BOOL changeSelection = FALSE; /* new selection is specified by
  1258. newMinSel, newMaxSel */
  1259. /* Comparisons we do often */
  1260. BOOL MinEqMax = (newMaxSel == newMinSel);
  1261. BOOL MinEqCar = (ped->ichCaret == newMinSel);
  1262. BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
  1263. /* State of shift and control keys. */
  1264. int scState = 0;
  1265. long position;
  1266. BOOL prevLine;
  1267. POINT mousePt;
  1268. int defaultDlgId;
  1269. int iScrollAmt;
  1270. if (ped->fMouseDown)
  1271. /* If we are in the middle of a mousedown command, don't do anything.
  1272. */
  1273. return;
  1274. if (!keyMods)
  1275. {
  1276. /* Get state of modifier keys for use later. */
  1277. scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
  1278. scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0);
  1279. }
  1280. else
  1281. scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
  1282. switch(virtKeyCode)
  1283. {
  1284. case VK_ESCAPE:
  1285. if (ped->fInDialogBox)
  1286. {
  1287. /* This condition is removed because, if the dialogbox does not
  1288. * have a CANCEL button and if ESC is hit when focus is on a
  1289. * ML edit control the dialogbox must close whether it has cancel
  1290. * button or not to be consistent with SL edit control;
  1291. * DefDlgProc takes care of the disabled CANCEL button case.
  1292. * Fix for Bug #4123 -- 02/07/91 -- SANKAR --
  1293. */
  1294. #if 0
  1295. if (GetDlgItem(ped->hwndParent, IDCANCEL))
  1296. #endif
  1297. /* User hit ESC...Send a close message (which in turn sends a
  1298. * cancelID to the app in DefDialogProc...
  1299. */
  1300. PostMessage(ped->hwndParent, WM_CLOSE, 0, 0L);
  1301. }
  1302. return;
  1303. case VK_RETURN:
  1304. if (ped->fInDialogBox)
  1305. {
  1306. /* If this multiline edit control is in a dialog box, then we want
  1307. * the RETURN key to be sent to the default dialog button (if there
  1308. * is one). CTRL-RETURN will insert a RETURN into the text. Note
  1309. * that CTRL-RETURN automatically translates into a linefeed (0x0A)
  1310. * and in the MLCharHandler, we handle this as if a return was
  1311. * entered.
  1312. */
  1313. if (scState != CTRLDOWN)
  1314. {
  1315. defaultDlgId = LOWORD(SendMessage(ped->hwndParent,
  1316. DM_GETDEFID,
  1317. 0, 0L));
  1318. if (defaultDlgId)
  1319. {
  1320. defaultDlgId=(WORD)GetDlgItem(ped->hwndParent,
  1321. defaultDlgId);
  1322. if (defaultDlgId)
  1323. {
  1324. SendMessage(ped->hwndParent, WM_NEXTDLGCTL,
  1325. defaultDlgId, 1L);
  1326. if (!ped->fFocus)
  1327. PostMessage((HWND)defaultDlgId,
  1328. WM_KEYDOWN, VK_RETURN, 0L);
  1329. }
  1330. }
  1331. }
  1332. return;
  1333. }
  1334. break;
  1335. case VK_TAB:
  1336. /* If this multiline edit control is in a dialog box, then we want the
  1337. * TAB key to take you to the next control, shift TAB to take you to the
  1338. * previous control. We always want CTRL-TAB to insert a tab into the
  1339. * edit control regardless of weather or not we're in a dialog box.
  1340. */
  1341. if (scState == CTRLDOWN)
  1342. MLCharHandler(ped, virtKeyCode, keyMods);
  1343. else
  1344. if (ped->fInDialogBox)
  1345. SendMessage(ped->hwndParent, WM_NEXTDLGCTL,
  1346. scState==SHFTDOWN, 0L);
  1347. return;
  1348. break;
  1349. case VK_LEFT:
  1350. /* If the caret isn't already at 0, we can move left */
  1351. if (ped->ichCaret)
  1352. {
  1353. switch (scState)
  1354. {
  1355. case NONEDOWN:
  1356. /* Clear selection, move caret left */
  1357. ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, TRUE);
  1358. newMaxSel = newMinSel = ped->ichCaret;
  1359. break;
  1360. case CTRLDOWN:
  1361. /* Clear selection, move caret word left */
  1362. ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
  1363. newMaxSel = newMinSel = ped->ichCaret;
  1364. break;
  1365. case SHFTDOWN:
  1366. /* Extend selection, move caret left */
  1367. ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, TRUE);
  1368. if (MaxEqCar && !MinEqMax)
  1369. /* Reduce selection extent */
  1370. newMaxSel = ped->ichCaret;
  1371. else
  1372. /* Extend selection extent */
  1373. newMinSel = ped->ichCaret;
  1374. break;
  1375. case SHCTDOWN:
  1376. /* Extend selection, move caret word left */
  1377. ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
  1378. if (MaxEqCar && !MinEqMax)
  1379. {
  1380. /* Reduce selection extent */
  1381. /* Hint: Suppose WORD. OR is selected. Cursor between
  1382. R and D. Hit select word left, we want to just select
  1383. the W and leave cursor before the W. */
  1384. newMinSel = ped->ichMinSel;
  1385. newMaxSel = ped->ichCaret;
  1386. }
  1387. else
  1388. /* Extend selection extent */
  1389. newMinSel = ped->ichCaret;
  1390. break;
  1391. }
  1392. changeSelection = TRUE;
  1393. }
  1394. else
  1395. {
  1396. /* If the user tries to move left and we are at the 0th character
  1397. and there is a selection, then cancel the selection. */
  1398. if (ped->ichMaxSel != ped->ichMinSel &&
  1399. (scState == NONEDOWN || scState == CTRLDOWN))
  1400. {
  1401. changeSelection = TRUE;
  1402. newMaxSel = newMinSel = ped->ichCaret;
  1403. }
  1404. }
  1405. break;
  1406. case VK_RIGHT:
  1407. /* If the caret isn't already at ped->cch, we can move right */
  1408. if (ped->ichCaret < ped->cch)
  1409. {
  1410. switch (scState)
  1411. {
  1412. case NONEDOWN:
  1413. /* Clear selection, move caret right */
  1414. ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE);
  1415. newMaxSel = newMinSel = ped->ichCaret;
  1416. break;
  1417. case CTRLDOWN:
  1418. /* Clear selection, move caret word right */
  1419. ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
  1420. newMaxSel = newMinSel = ped->ichCaret;
  1421. break;
  1422. case SHFTDOWN:
  1423. /* Extend selection, move caret right */
  1424. ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE);
  1425. if (MinEqCar && !MinEqMax)
  1426. /* Reduce selection extent */
  1427. newMinSel = ped->ichCaret;
  1428. else
  1429. /* Extend selection extent */
  1430. newMaxSel = ped->ichCaret;
  1431. break;
  1432. case SHCTDOWN:
  1433. /* Extend selection, move caret word right */
  1434. ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
  1435. if (MinEqCar && !MinEqMax)
  1436. {
  1437. /* Reduce selection extent */
  1438. newMinSel = ped->ichCaret;
  1439. newMaxSel = ped->ichMaxSel;
  1440. }
  1441. else
  1442. /* Extend selection extent */
  1443. newMaxSel = ped->ichCaret;
  1444. break;
  1445. }
  1446. changeSelection = TRUE;
  1447. }
  1448. else
  1449. {
  1450. /* If the user tries to move right and we are at the last character
  1451. * and there is a selection, then cancel the selection.
  1452. */
  1453. if (ped->ichMaxSel != ped->ichMinSel &&
  1454. (scState == NONEDOWN || scState == CTRLDOWN))
  1455. {
  1456. newMaxSel = newMinSel = ped->ichCaret;
  1457. changeSelection = TRUE;
  1458. }
  1459. }
  1460. break;
  1461. case VK_UP:
  1462. case VK_DOWN:
  1463. if (virtKeyCode == VK_UP &&
  1464. ped->cLines-1 != ped->iCaretLine &&
  1465. ped->ichCaret == ped->chLines[ped->iCaretLine+1])
  1466. prevLine= TRUE;
  1467. else
  1468. prevLine=FALSE;
  1469. hdc = ECGetEditDC(ped,TRUE);
  1470. position = MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine);
  1471. ECReleaseEditDC(ped, hdc, TRUE);
  1472. mousePt.x = LOWORD(position);
  1473. mousePt.y = HIWORD(position)+1+
  1474. (virtKeyCode == VK_UP ? -ped->lineHeight : ped->lineHeight);
  1475. if (scState == NONEDOWN || scState == SHFTDOWN)
  1476. {
  1477. /* Send fake mouse messages to handle this */
  1478. /* NONEDOWN: Clear selection, move caret up/down 1 line */
  1479. /* SHFTDOWN: Extend selection, move caret up/down 1 line */
  1480. MLMouseMotionHandler(ped, WM_LBUTTONDOWN,
  1481. scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
  1482. MLMouseMotionHandler(ped, WM_LBUTTONUP,
  1483. scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
  1484. }
  1485. break;
  1486. case VK_HOME:
  1487. switch (scState)
  1488. {
  1489. case NONEDOWN:
  1490. /* Clear selection, move cursor to beginning of line */
  1491. newMaxSel = newMinSel = ped->ichCaret =
  1492. ped->chLines[ped->iCaretLine];
  1493. break;
  1494. case CTRLDOWN:
  1495. /* Clear selection, move caret to beginning of text */
  1496. newMaxSel = newMinSel = ped->ichCaret = 0;
  1497. break;
  1498. case SHFTDOWN:
  1499. /* Extend selection, move caret to beginning of line */
  1500. ped->ichCaret = ped->chLines[ped->iCaretLine];
  1501. if (MaxEqCar && !MinEqMax)
  1502. {
  1503. /* Reduce selection extent */
  1504. newMinSel = ped->ichMinSel;
  1505. newMaxSel = ped->ichCaret;
  1506. }
  1507. else
  1508. /* Extend selection extent */
  1509. newMinSel = ped->ichCaret;
  1510. break;
  1511. case SHCTDOWN:
  1512. /* Extend selection, move caret to beginning of text */
  1513. ped->ichCaret = newMinSel = 0;
  1514. if (MaxEqCar && !MinEqMax)
  1515. /* Reduce/negate selection extent */
  1516. newMaxSel = ped->ichMinSel;
  1517. break;
  1518. }
  1519. changeSelection = TRUE;
  1520. break;
  1521. case VK_END:
  1522. switch (scState)
  1523. {
  1524. case NONEDOWN:
  1525. /* Clear selection, move caret to end of line */
  1526. newMaxSel = newMinSel = ped->ichCaret =
  1527. ped->chLines[ped->iCaretLine]+MLLineLength(ped, ped->iCaretLine);
  1528. break;
  1529. case CTRLDOWN:
  1530. /* Clear selection, move caret to end of text */
  1531. newMaxSel = newMinSel = ped->ichCaret = ped->cch;
  1532. break;
  1533. case SHFTDOWN:
  1534. /* Extend selection, move caret to end of line */
  1535. ped->ichCaret = ped->chLines[ped->iCaretLine]+
  1536. MLLineLength(ped, ped->iCaretLine);
  1537. if (MinEqCar && !MinEqMax)
  1538. {
  1539. /* Reduce selection extent */
  1540. newMinSel = ped->ichCaret;
  1541. newMaxSel = ped->ichMaxSel;
  1542. }
  1543. else
  1544. /* Extend selection extent */
  1545. newMaxSel = ped->ichCaret;
  1546. break;
  1547. case SHCTDOWN:
  1548. newMaxSel = ped->ichCaret = ped->cch;
  1549. /* Extend selection, move caret to end of text */
  1550. if (MinEqCar && !MinEqMax)
  1551. /* Reduce/negate selection extent */
  1552. newMinSel = ped->ichMaxSel;
  1553. /* else Extend selection extent */
  1554. break;
  1555. }
  1556. changeSelection = TRUE;
  1557. break;
  1558. case VK_PRIOR:
  1559. case VK_NEXT:
  1560. switch (scState)
  1561. {
  1562. case NONEDOWN:
  1563. case SHFTDOWN:
  1564. /* Vertical scroll by one visual screen */
  1565. hdc = ECGetEditDC(ped,TRUE);
  1566. position = MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine);
  1567. ECReleaseEditDC(ped, hdc, TRUE);
  1568. mousePt.x = LOWORD(position);
  1569. mousePt.y = HIWORD(position)+1;
  1570. SendMessage(ped->hwnd, WM_VSCROLL,
  1571. virtKeyCode == VK_PRIOR ? SB_PAGEUP : SB_PAGEDOWN,
  1572. 0L);
  1573. /* Move the cursor there */
  1574. MLMouseMotionHandler(ped, WM_LBUTTONDOWN,
  1575. scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
  1576. MLMouseMotionHandler(ped, WM_LBUTTONUP,
  1577. scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
  1578. break;
  1579. case CTRLDOWN:
  1580. /* Horizontal scroll by one screenful minus one char */
  1581. iScrollAmt = ((ped->rcFmt.right - ped->rcFmt.left)
  1582. /ped->aveCharWidth) - 1;
  1583. if(virtKeyCode == VK_PRIOR)
  1584. iScrollAmt *= -1; /* For previous page */
  1585. SendMessage(ped->hwnd, WM_HSCROLL,
  1586. EM_LINESCROLL, (long)iScrollAmt);
  1587. break;
  1588. }
  1589. break;
  1590. case VK_DELETE:
  1591. if (ped->fReadOnly)
  1592. break;
  1593. switch (scState)
  1594. {
  1595. case NONEDOWN:
  1596. /* Clear selection. If no selection, delete (clear) character
  1597. * right
  1598. */
  1599. if ((ped->ichMaxSel<ped->cch) &&
  1600. (ped->ichMinSel==ped->ichMaxSel))
  1601. {
  1602. /* Move cursor forwards and send a backspace message... */
  1603. ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE);
  1604. ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
  1605. SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
  1606. }
  1607. if (ped->ichMinSel != ped->ichMaxSel)
  1608. SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
  1609. break;
  1610. case SHFTDOWN:
  1611. /* CUT selection ie. remove and copy to clipboard, or if no
  1612. * selection, delete (clear) character left.
  1613. */
  1614. if (SendMessage(ped->hwnd, WM_COPY, (WORD)0,0L) ||
  1615. (ped->ichMinSel == ped->ichMaxSel))
  1616. /* If copy successful, delete the copied text by sending a
  1617. * backspace message which will redraw the text and take care
  1618. * of notifying the parent of changes. Or if there is no
  1619. * selection, just delete char left.
  1620. */
  1621. SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
  1622. break;
  1623. case CTRLDOWN:
  1624. /* Clear selection, or delete to end of line if no selection
  1625. */
  1626. if ((ped->ichMaxSel<ped->cch) &&
  1627. (ped->ichMinSel==ped->ichMaxSel))
  1628. {
  1629. ped->ichMaxSel = ped->ichCaret =
  1630. ped->chLines[ped->iCaretLine]+
  1631. MLLineLength(ped, ped->iCaretLine);
  1632. }
  1633. if (ped->ichMinSel != ped->ichMaxSel)
  1634. SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
  1635. break;
  1636. }
  1637. /*
  1638. * No need to update text or selection since BACKSPACE message does it
  1639. * for us.
  1640. */
  1641. break;
  1642. case VK_INSERT:
  1643. if (scState == CTRLDOWN ||
  1644. (scState == SHFTDOWN && !ped->fReadOnly))
  1645. /* if CTRLDOWN Copy current selection to clipboard */
  1646. /* if SHFTDOWN Paste clipboard */
  1647. SendMessage(ped->hwnd, scState == CTRLDOWN ? WM_COPY : WM_PASTE,
  1648. (WORD)NULL, (LONG)NULL);
  1649. break;
  1650. }
  1651. if (changeSelection)
  1652. {
  1653. hdc = ECGetEditDC(ped,FALSE);
  1654. MLChangeSelection(ped,hdc,newMinSel,newMaxSel);
  1655. /* Set the caret's line */
  1656. ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
  1657. if (virtKeyCode == VK_END && ped->ichCaret < ped->cch && ped->fWrap &&
  1658. ped->iCaretLine > 0)
  1659. {
  1660. /* Handle moving to the end of a word wrapped line. This keeps the
  1661. * cursor from falling to the start of the next line if we have word
  1662. * wrapped and there is no CRLF.
  1663. */
  1664. if (*((PSTR)LMHtoP(ped->hText)+ped->chLines[ped->iCaretLine]-2) !=
  1665. 0x0D)
  1666. ped->iCaretLine--;
  1667. }
  1668. /* Since drawtext sets the caret position */
  1669. MLSetCaretPosition(ped,hdc);
  1670. ECReleaseEditDC(ped,hdc,FALSE);
  1671. /* Make sure we can see the cursor */
  1672. MLEnsureCaretVisible(ped);
  1673. }
  1674. }
  1675. ICH PASCAL NEAR MLPasteText(register PED ped)
  1676. /* effects: Pastes a line of text from the clipboard into the edit control
  1677. * starting at ped->ichCaret. Updates ichMaxSel and ichMinSel to point to the
  1678. * end of the inserted text. Notifies the parent if space cannot be
  1679. * allocated. Returns how many characters were inserted.
  1680. */
  1681. {
  1682. HANDLE hData;
  1683. LPSTR lpchClip;
  1684. LPSTR lpchClip2;
  1685. register ICH cchAdded=0; /* No added data initially */
  1686. DWORD clipboardDataSize;
  1687. HCURSOR hCursorOld;
  1688. if (!ped->fAutoVScroll)
  1689. /* Empty the undo buffer if this edit control limits the amount of text
  1690. * the user can add to the window rect. This is so that we can undo this
  1691. * operation if doing in causes us to exceed the window boundaries.
  1692. */
  1693. ECEmptyUndo(ped);
  1694. /* See if any text should be deleted */
  1695. MLDeleteText(ped);
  1696. hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1697. if (!OpenClipboard(ped->hwnd))
  1698. goto PasteExitNoCloseClip;
  1699. if (!(hData = GetClipboardData(CF_TEXT)))
  1700. {
  1701. goto PasteExit;
  1702. }
  1703. if (GlobalFlags(hData) & GMEM_DISCARDED)
  1704. {
  1705. goto PasteExit;
  1706. }
  1707. lpchClip2 = lpchClip = (LPSTR) GlobalLock(hData);
  1708. /* Assumes lstrlen returns at most 64K
  1709. */
  1710. cchAdded = umin((WORD)lstrlen(lpchClip),64000L);
  1711. /* Insert the text (MLInsertText checks line length) */
  1712. cchAdded = MLInsertText(ped, lpchClip, cchAdded, FALSE);
  1713. GlobalUnlock(hData);
  1714. PasteExit:
  1715. CloseClipboard();
  1716. PasteExitNoCloseClip:
  1717. if (hCursorOld)
  1718. SetCursor(hCursorOld);
  1719. return(cchAdded);
  1720. }
  1721. void NEAR PASCAL MLMouseMotionHandler(register PED ped,
  1722. WORD message,
  1723. WORD virtKeyDown,
  1724. POINT mousePt)
  1725. {
  1726. LONG selection;
  1727. BOOL updateText = FALSE;
  1728. BOOL changeSelection = FALSE;
  1729. HDC hdc = ECGetEditDC(ped,TRUE);
  1730. ICH newMaxSel = ped->ichMaxSel;
  1731. ICH newMinSel = ped->ichMinSel;
  1732. ICH ichStart = ped->screenStart;
  1733. ICH mouseCch;
  1734. ICH mouseLine;
  1735. int i,j;
  1736. selection = MLMouseToIch(ped, hdc, mousePt);
  1737. mouseCch = LOWORD(selection);
  1738. mouseLine = HIWORD(selection);
  1739. /* Save for timer */
  1740. ped->ptPrevMouse = mousePt;
  1741. ped->prevKeys = virtKeyDown;
  1742. switch (message)
  1743. {
  1744. case WM_LBUTTONDBLCLK:
  1745. /*
  1746. * if shift key is down, extend selection to word we double clicked on
  1747. * else clear current selection and select word.
  1748. */
  1749. #ifdef FE_SB
  1750. /*
  1751. * if character on the caret is DBCS, word selection is only one
  1752. * DBCS character on the caret (or right side from the caret).
  1753. */
  1754. {
  1755. PSTR pCaretChr = LocalLock(ped->hText)+ped->ichCaret;
  1756. selection = ECWord(ped,ped->ichCaret,
  1757. ECIsDBCSLeadByte(ped,*pCaretChr) ? FALSE : TRUE);
  1758. LocalUnlock(ped->hText);
  1759. }
  1760. #else
  1761. selection = ECWord(ped,ped->ichCaret,TRUE);
  1762. #endif
  1763. newMinSel = LOWORD(selection);
  1764. newMaxSel = ped->ichCaret = HIWORD(selection);
  1765. ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
  1766. changeSelection = TRUE;
  1767. /*
  1768. * Set mouse down to false so that the caret isn't reposition on the
  1769. * mouseup message or on a accidental move...
  1770. */
  1771. ped->fMouseDown = FALSE;
  1772. break;
  1773. case WM_MOUSEMOVE:
  1774. if (ped->fMouseDown)
  1775. {
  1776. /* Set the system timer to automatically scroll when mouse is
  1777. * outside of the client rectangle. Speed of scroll depends on
  1778. * distance from window.
  1779. */
  1780. i = mousePt.y < 0 ? -mousePt.y : mousePt.y - ped->rcFmt.bottom;
  1781. j = 400 - ((WORD)i << 4);
  1782. if (j < 100)
  1783. j = 100;
  1784. SetTimer(ped->hwnd, 1, j, (FARPROC)NULL);
  1785. changeSelection = TRUE;
  1786. /* Extend selection, move caret right */
  1787. if ((ped->ichMinSel == ped->ichCaret) &&
  1788. (ped->ichMinSel != ped->ichMaxSel))
  1789. {
  1790. /* Reduce selection extent */
  1791. newMinSel = ped->ichCaret = mouseCch;
  1792. newMaxSel = ped->ichMaxSel;
  1793. }
  1794. else
  1795. {
  1796. /* Extend selection extent */
  1797. newMaxSel = ped->ichCaret=mouseCch;
  1798. }
  1799. ped->iCaretLine = mouseLine;
  1800. }
  1801. break;
  1802. case WM_LBUTTONDOWN:
  1803. /* if (ped->fFocus)
  1804. {*/
  1805. /*
  1806. * Only handle this if we have the focus.
  1807. */
  1808. ped->fMouseDown = TRUE;
  1809. SetCapture(ped->hwnd);
  1810. changeSelection = TRUE;
  1811. if (!(virtKeyDown & MK_SHIFT))
  1812. {
  1813. /*
  1814. * If shift key isn't down, move caret to mouse point and clear
  1815. * old selection
  1816. */
  1817. newMinSel = newMaxSel = ped->ichCaret = mouseCch;
  1818. ped->iCaretLine = mouseLine;
  1819. }
  1820. else
  1821. {
  1822. /*
  1823. * Shiftkey is down so we want to maintain the current selection
  1824. * (if any) and just extend or reduce it
  1825. */
  1826. if (ped->ichMinSel == ped->ichCaret)
  1827. newMinSel = ped->ichCaret = mouseCch;
  1828. else
  1829. newMaxSel = ped->ichCaret = mouseCch;
  1830. ped->iCaretLine = mouseLine;
  1831. }
  1832. /*
  1833. * Set the timer so that we can scroll automatically when the mouse
  1834. * is moved outside the window rectangle.
  1835. */
  1836. ped->ptPrevMouse=mousePt;
  1837. ped->prevKeys = virtKeyDown;
  1838. SetTimer(ped->hwnd, 1, 400, (FARPROC)NULL);
  1839. /* }*/
  1840. break;
  1841. case WM_LBUTTONUP:
  1842. if (ped->fMouseDown)
  1843. {
  1844. /* Kill the timer so that we don't do auto mouse moves anymore */
  1845. KillTimer(ped->hwnd, 1);
  1846. ReleaseCapture();
  1847. MLSetCaretPosition(ped,hdc);
  1848. ped->fMouseDown = FALSE;
  1849. }
  1850. break;
  1851. }
  1852. if (changeSelection)
  1853. {
  1854. MLChangeSelection(ped, hdc, newMinSel, newMaxSel);
  1855. MLEnsureCaretVisible(ped);
  1856. }
  1857. ECReleaseEditDC(ped,hdc,TRUE);
  1858. if (!ped->fFocus && (message == WM_LBUTTONDOWN))
  1859. /* If we don't have the focus yet, get it */
  1860. SetFocus(ped->hwnd);
  1861. }
  1862. int NEAR PASCAL MLPixelFromCount(register PED ped,
  1863. int dCharLine,
  1864. WORD message)
  1865. /* effects: Given a character or line count (depending on message == hscroll
  1866. * or vscroll), calculate the number of pixels we must scroll to get there.
  1867. * Updates the start of screen or xoffset to reflect the new positions.
  1868. */
  1869. {
  1870. /* This can be an int since we can have 32K max lines/pixels
  1871. */
  1872. int oldLineChar;
  1873. if (message != WM_HSCROLL)
  1874. {
  1875. /* We want to scroll screen by dCharLine lines */
  1876. oldLineChar = ped->screenStart;
  1877. /* Find the new starting line for the ped */
  1878. ped->screenStart = max(ped->screenStart+dCharLine,0);
  1879. ped->screenStart = min(ped->screenStart,ped->cLines-1);
  1880. dCharLine = oldLineChar - ped->screenStart;
  1881. /* We will scroll at most a screen full of text */
  1882. if (dCharLine < 0)
  1883. dCharLine = -min(-dCharLine, ped->ichLinesOnScreen);
  1884. else
  1885. dCharLine = min(dCharLine, ped->ichLinesOnScreen);
  1886. return(dCharLine*ped->lineHeight);
  1887. }
  1888. /* No horizontal scrolling allowed if funny format */
  1889. if (ped->format != ES_LEFT)
  1890. return(0);
  1891. /* Convert delta characters into delta pixels */
  1892. dCharLine = dCharLine*ped->aveCharWidth;
  1893. oldLineChar = ped->xOffset;
  1894. /* Find new horizontal starting point */
  1895. ped->xOffset = max(ped->xOffset+dCharLine,0);
  1896. ped->xOffset = min(ped->xOffset,ped->maxPixelWidth);
  1897. dCharLine = oldLineChar - ped->xOffset;
  1898. /* We will scroll at most a screen full of text */
  1899. if (dCharLine < 0)
  1900. dCharLine = -min(-dCharLine, ped->rcFmt.right+1-ped->rcFmt.left);
  1901. else
  1902. dCharLine = min(dCharLine, ped->rcFmt.right+1-ped->rcFmt.left);
  1903. return(dCharLine);
  1904. }
  1905. int NEAR PASCAL MLPixelFromThumbPos(register PED ped,
  1906. int pos,
  1907. BOOL fVertical)
  1908. /* effects: Given a thumb position from 0 to 100, return the number of pixels
  1909. * we must scroll to get there.
  1910. */
  1911. {
  1912. int dxy;
  1913. int iLineOld;
  1914. ICH iCharOld;
  1915. if (fVertical)
  1916. {
  1917. iLineOld = ped->screenStart;
  1918. ped->screenStart = (int)MultDiv(ped->cLines-1, pos, 100);
  1919. ped->screenStart = min(ped->screenStart,ped->cLines-1);
  1920. dxy = (iLineOld - ped->screenStart)*ped->lineHeight;
  1921. }
  1922. else
  1923. {
  1924. /* Only allow horizontal scrolling with left justified text */
  1925. if (ped->format == ES_LEFT)
  1926. {
  1927. iCharOld = ped->xOffset;
  1928. ped->xOffset = MultDiv(ped->maxPixelWidth-ped->aveCharWidth, pos, 100);
  1929. dxy = iCharOld - ped->xOffset;
  1930. }
  1931. else
  1932. dxy = 0;
  1933. }
  1934. return(dxy);
  1935. }
  1936. int FAR PASCAL MLThumbPosFromPed(register PED ped,
  1937. BOOL fVertical)
  1938. /*
  1939. * effects: Given the current state of the edit control, return its vertical
  1940. * thumb position if fVertical else returns its horizontal thumb position.
  1941. * The thumb position ranges from 0 to 100.
  1942. */
  1943. {
  1944. WORD d1;
  1945. WORD d2;
  1946. if (fVertical)
  1947. {
  1948. if (ped->cLines < 2)
  1949. return(0);
  1950. d1 = (WORD)(ped->screenStart);
  1951. d2 = (WORD)(ped->cLines-1);
  1952. }
  1953. else
  1954. {
  1955. if (ped->maxPixelWidth < (ped->aveCharWidth*2))
  1956. return(0);
  1957. d1 = (WORD)(ped->xOffset);
  1958. d2 = (WORD)(ped->maxPixelWidth);
  1959. }
  1960. /* Do the multiply/division and avoid overflows and divide by zero errors */
  1961. return(MultDiv(d1, 100, d2));
  1962. }
  1963. LONG NEAR PASCAL MLScrollHandler(register PED ped,
  1964. WORD message,
  1965. int cmd,
  1966. int iAmt)
  1967. {
  1968. RECT rc;
  1969. RECT rcUpdate;
  1970. int dx;
  1971. int dy;
  1972. int dcharline;
  1973. BOOL fVertical;
  1974. HDC hdc;
  1975. UpdateWindow(ped->hwnd);
  1976. /* Are we scrolling vertically or horizontally? */
  1977. fVertical = (message != WM_HSCROLL);
  1978. dx = dy = dcharline = 0;
  1979. switch (cmd)
  1980. {
  1981. case SB_LINEDOWN:
  1982. dcharline = 1;
  1983. break;
  1984. case SB_LINEUP:
  1985. dcharline = -1;
  1986. break;
  1987. case SB_PAGEDOWN:
  1988. dcharline = ped->ichLinesOnScreen-1;
  1989. break;
  1990. case SB_PAGEUP:
  1991. dcharline = -(ped->ichLinesOnScreen-1);
  1992. break;
  1993. case SB_THUMBTRACK:
  1994. case SB_THUMBPOSITION:
  1995. dy = MLPixelFromThumbPos(ped, iAmt, fVertical);
  1996. dcharline = -dy / (message == WM_VSCROLL ? ped->lineHeight :
  1997. ped->aveCharWidth);
  1998. if (!fVertical)
  1999. {
  2000. dx = dy;
  2001. dy = 0;
  2002. }
  2003. break;
  2004. case EM_LINESCROLL:
  2005. dcharline = iAmt;
  2006. break;
  2007. case EM_GETTHUMB:
  2008. return(MLThumbPosFromPed(ped,fVertical));
  2009. break;
  2010. default:
  2011. return(0L);
  2012. break;
  2013. }
  2014. GetClientRect(ped->hwnd, (LPRECT)&rc);
  2015. IntersectRect((LPRECT)&rc, (LPRECT)&rc, (LPRECT)&ped->rcFmt);
  2016. rc.bottom++;
  2017. if (cmd != SB_THUMBPOSITION && cmd != SB_THUMBTRACK)
  2018. {
  2019. if (message == WM_VSCROLL)
  2020. {
  2021. dx = 0;
  2022. dy = MLPixelFromCount(ped, dcharline, message);
  2023. }
  2024. else if (message == WM_HSCROLL)
  2025. {
  2026. dx = MLPixelFromCount(ped, dcharline, message);
  2027. dy = 0;
  2028. }
  2029. }
  2030. SetScrollPos(ped->hwnd, fVertical ? SB_VERT : SB_HORZ,
  2031. (int)MLThumbPosFromPed(ped,fVertical), TRUE);
  2032. if (cmd != SB_THUMBTRACK)
  2033. /* We don't want to notify the parent of thumbtracking since they might
  2034. * try to set the thumb position to something bogus. For example
  2035. * NOTEPAD is such a #@@!@#@ an app since they don't use editcontrol
  2036. * scroll bars and depend on these EN_*SCROLL messages to update their
  2037. * fake scroll bars.
  2038. */
  2039. ECNotifyParent(ped,fVertical ? EN_VSCROLL : EN_HSCROLL);
  2040. if (!ped->fNoRedraw)
  2041. {
  2042. hdc = ECGetEditDC(ped,FALSE);
  2043. ScrollDC(hdc,dx,dy, (LPRECT)&rc, (LPRECT)&rc, NULL, (LPRECT)&rcUpdate);
  2044. MLSetCaretPosition(ped,hdc);
  2045. ECReleaseEditDC(ped,hdc,FALSE);
  2046. if (ped->ichLinesOnScreen+ped->screenStart >= ped->cLines)
  2047. {
  2048. InvalidateRect(ped->hwnd, (LPRECT)&rcUpdate, TRUE);
  2049. }
  2050. else
  2051. {
  2052. InvalidateRect(ped->hwnd, (LPRECT)&rcUpdate, FALSE);
  2053. }
  2054. UpdateWindow(ped->hwnd);
  2055. }
  2056. return(MAKELONG(dcharline, 1));
  2057. }
  2058. void NEAR PASCAL MLSetFocusHandler(register PED ped)
  2059. /* effects: Gives the edit control the focus and notifies the parent
  2060. * EN_SETFOCUS.
  2061. */
  2062. {
  2063. HDC hdc;
  2064. if (!ped->fFocus)
  2065. {
  2066. ped->fFocus = 1; /* Set focus */
  2067. hdc = ECGetEditDC(ped,TRUE);
  2068. /* Draw the caret */
  2069. CreateCaret(ped->hwnd, (HBITMAP)NULL, 2, ped->lineHeight);
  2070. ShowCaret(ped->hwnd);
  2071. MLSetCaretPosition(ped, hdc);
  2072. /* Show the current selection. Only if the selection was hidden when we
  2073. * lost the focus, must we invert (show) it.
  2074. */
  2075. if (!ped->fNoHideSel && ped->ichMinSel!=ped->ichMaxSel)
  2076. MLDrawText(ped, hdc, ped->ichMinSel, ped->ichMaxSel);
  2077. ECReleaseEditDC(ped,hdc,TRUE);
  2078. }
  2079. #if 0
  2080. MLEnsureCaretVisible(ped);
  2081. #endif
  2082. /* Notify parent we have the focus */
  2083. ECNotifyParent(ped, EN_SETFOCUS);
  2084. }
  2085. void NEAR PASCAL MLKillFocusHandler(register PED ped)
  2086. /* effects: The edit control loses the focus and notifies the parent via
  2087. * EN_KILLFOCUS.
  2088. */
  2089. {
  2090. HDC hdc;
  2091. if (ped->fFocus)
  2092. {
  2093. ped->fFocus = 0; /* Clear focus */
  2094. /* Do this only if we still have the focus. But we always notify the
  2095. * parent that we lost the focus whether or not we originally had the
  2096. * focus.
  2097. */
  2098. /* Hide the current selection if needed */
  2099. if (!ped->fNoHideSel && ped->ichMinSel!=ped->ichMaxSel)
  2100. {
  2101. hdc = ECGetEditDC(ped,FALSE);
  2102. MLDrawText(ped, hdc, ped->ichMinSel, ped->ichMaxSel);
  2103. ECReleaseEditDC(ped,hdc,FALSE);
  2104. }
  2105. /* Destroy the caret */
  2106. HideCaret(ped->hwnd);
  2107. DestroyCaret();
  2108. }
  2109. /* Notify parent that we lost the focus. */
  2110. ECNotifyParent(ped, EN_KILLFOCUS);
  2111. }
  2112. BOOL FAR PASCAL MLEnsureCaretVisible(ped)
  2113. register PED ped;
  2114. /*
  2115. * effects: Scrolls the caret into the visible region. Returns TRUE if
  2116. * scrolling was done else returns FALSE.
  2117. */
  2118. {
  2119. int cLinesToScroll;
  2120. int iLineMax;
  2121. int xposition;
  2122. BOOL prevLine;
  2123. register HDC hdc;
  2124. BOOL fScrolled = FALSE;
  2125. if (IsWindowVisible(ped->hwnd))
  2126. {
  2127. if (ped->fAutoVScroll)
  2128. {
  2129. iLineMax = ped->screenStart + ped->ichLinesOnScreen-1;
  2130. if (fScrolled = ped->iCaretLine > iLineMax)
  2131. {
  2132. MLScrollHandler(ped, WM_VSCROLL, EM_LINESCROLL,
  2133. ped->iCaretLine-iLineMax);
  2134. }
  2135. else
  2136. {
  2137. if (fScrolled = ped->iCaretLine < ped->screenStart)
  2138. MLScrollHandler(ped, WM_VSCROLL, EM_LINESCROLL,
  2139. ped->iCaretLine-ped->screenStart);
  2140. }
  2141. }
  2142. if (ped->fAutoHScroll &&
  2143. ped->maxPixelWidth > ped->rcFmt.right-ped->rcFmt.left)
  2144. {
  2145. /* Get the current position of the caret in pixels */
  2146. if (ped->cLines-1 != ped->iCaretLine &&
  2147. ped->ichCaret == ped->chLines[ped->iCaretLine+1])
  2148. prevLine=TRUE;
  2149. else
  2150. prevLine=FALSE;
  2151. hdc = ECGetEditDC(ped,TRUE);
  2152. xposition = LOWORD(MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine));
  2153. ECReleaseEditDC(ped,hdc,TRUE);
  2154. /* Remember, MLIchToXYPos returns coordinates with respect to the
  2155. * top left pixel displayed on the screen. Thus, if xPosition < 0,
  2156. * it means xPosition is less than current ped->xOffset.
  2157. */
  2158. if (xposition < 0)
  2159. /* Scroll to the left */
  2160. MLScrollHandler(ped, WM_HSCROLL, EM_LINESCROLL,
  2161. (xposition-(ped->rcFmt.right-ped->rcFmt.left)/3)
  2162. /ped->aveCharWidth);
  2163. else if (xposition > ped->rcFmt.right)
  2164. /* Scroll to the right */
  2165. MLScrollHandler(ped, WM_HSCROLL, EM_LINESCROLL,
  2166. (xposition-ped->rcFmt.right+
  2167. (ped->rcFmt.right-ped->rcFmt.left)/3)/
  2168. ped->aveCharWidth);
  2169. }
  2170. }
  2171. xposition = (int)MLThumbPosFromPed(ped,TRUE);
  2172. if (xposition != GetScrollPos(ped->hwnd, SB_VERT))
  2173. SetScrollPos(ped->hwnd, SB_VERT, xposition, TRUE);
  2174. xposition = (int)MLThumbPosFromPed(ped,FALSE);
  2175. if (xposition != GetScrollPos(ped->hwnd, SB_HORZ))
  2176. SetScrollPos(ped->hwnd, SB_HORZ, xposition, TRUE);
  2177. return(fScrolled);
  2178. }
  2179. void FAR PASCAL MLSetRectHandler(ped, lprect)
  2180. register PED ped;
  2181. LPRECT lprect;
  2182. /*
  2183. * effects: Sets the edit control's format rect to be the rect specified if
  2184. * reasonable. Rebuilds the lines if needed.
  2185. */
  2186. {
  2187. RECT rc;
  2188. CopyRect((LPRECT)&rc, lprect);
  2189. if (!(rc.right-rc.left) || !(rc.bottom-rc.top))
  2190. {
  2191. if (ped->rcFmt.right - ped->rcFmt.left)
  2192. {
  2193. ped->fCaretHidden = 1; // then, hide it.
  2194. SetCaretPos(-20000, -20000);
  2195. /* If rect is being set to zero width or height, and our formatting
  2196. rectangle is already defined, just return. */
  2197. return;
  2198. }
  2199. SetRect((LPRECT)&rc, 0, 0, ped->aveCharWidth*10, ped->lineHeight);
  2200. }
  2201. if (ped->fBorder)
  2202. /* Shrink client area to make room for the border */
  2203. InflateRect((LPRECT)&rc, -(ped->cxSysCharWidth/2),
  2204. -(ped->cySysCharHeight/4));
  2205. /*
  2206. * If resulting rectangle is too small to do anything with, don't change it
  2207. */
  2208. if ((rc.right-rc.left < ped->aveCharWidth) ||
  2209. ((rc.bottom - rc.top)/ped->lineHeight == 0))
  2210. {
  2211. // If the resulting rectangle is too small to display the caret, then
  2212. // do not display the caret.
  2213. ped->fCaretHidden = 1;
  2214. SetCaretPos(-20000, -20000);
  2215. /* If rect is too narrow or too short, do nothing */
  2216. return;
  2217. }
  2218. else
  2219. ped->fCaretHidden = 0;
  2220. /* Calc number of lines we can display on the screen */
  2221. ped->ichLinesOnScreen = (rc.bottom - rc.top)/ped->lineHeight;
  2222. CopyRect((LPRECT)&ped->rcFmt, (LPRECT)&rc);
  2223. /* Get an integral number of lines on the screen */
  2224. ped->rcFmt.bottom = rc.top+ped->ichLinesOnScreen * ped->lineHeight;
  2225. /* Rebuild the chLines if we are word wrapping only */
  2226. if (ped->fWrap)
  2227. {
  2228. MLBuildchLines(ped, 0, 0, FALSE);
  2229. // Update the ped->iCaretLine field properly based on ped->ichCaret
  2230. MLUpdateiCaretLine(ped);
  2231. }
  2232. }
  2233. /*******************/
  2234. /* MLEditWndProc() */
  2235. /*******************/
  2236. LONG FAR PASCAL MLEditWndProc(hwnd, ped, message, wParam, lParam)
  2237. HWND hwnd;
  2238. register PED ped;
  2239. WORD message;
  2240. register WORD wParam;
  2241. LONG lParam;
  2242. /* effects: Class procedure for all multi line edit controls.
  2243. Dispatches all messages to the appropriate handlers which are named
  2244. as follows:
  2245. SL (single line) prefixes all single line edit control procedures while
  2246. EC (edit control) prefixes all common handlers.
  2247. The MLEditWndProc only handles messages specific to multi line edit
  2248. controls.
  2249. */
  2250. {
  2251. switch (message)
  2252. {
  2253. case WM_CHAR:
  2254. /* wParam - the value of the key
  2255. lParam - modifiers, repeat count etc (not used) */
  2256. MLCharHandler(ped, wParam, 0);
  2257. break;
  2258. case WM_CLEAR:
  2259. /* wParam - not used
  2260. lParam - not used */
  2261. if (ped->ichMinSel != ped->ichMaxSel && !ped->fReadOnly)
  2262. SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
  2263. break;
  2264. case WM_CUT:
  2265. /* wParam - not used
  2266. lParam - not used */
  2267. if (ped->ichMinSel != ped->ichMaxSel && !ped->fReadOnly)
  2268. MLKeyDownHandler(ped, VK_DELETE, SHFTDOWN);
  2269. break;
  2270. case WM_ERASEBKGND:
  2271. FillWindow(ped->hwndParent, hwnd, (HDC)wParam, CTLCOLOR_EDIT);
  2272. return((LONG)TRUE);
  2273. case WM_GETDLGCODE:
  2274. /* wParam - not used
  2275. lParam - not used */
  2276. /* Should also return DLGC_WANTALLKEYS for multiline edit controls */
  2277. ped->fInDialogBox=TRUE; /* Mark the ML edit ctrl as in a dialog box */
  2278. return(DLGC_WANTCHARS | DLGC_HASSETSEL |
  2279. DLGC_WANTARROWS | DLGC_WANTALLKEYS);
  2280. break;
  2281. case WM_HSCROLL:
  2282. case WM_VSCROLL:
  2283. return(MLScrollHandler(ped, message, wParam, (int)lParam));
  2284. break;
  2285. case WM_KEYDOWN:
  2286. /* wParam - virt keycode of the given key
  2287. lParam - modifiers such as repeat count etc. (not used) */
  2288. MLKeyDownHandler(ped, wParam, 0);
  2289. break;
  2290. case WM_KILLFOCUS:
  2291. /* wParam - handle of the window that receives the input focus
  2292. lParam - not used */
  2293. MLKillFocusHandler(ped);
  2294. break;
  2295. case WM_SYSTIMER:
  2296. /* This allows us to automatically scroll if the user holds the mouse
  2297. * outside the edit control window. We simulate mouse moves at timer
  2298. * intervals set in MouseMotionHandler.
  2299. */
  2300. if (ped->fMouseDown)
  2301. MLMouseMotionHandler(ped, WM_MOUSEMOVE,
  2302. ped->prevKeys,ped->ptPrevMouse);
  2303. break;
  2304. case WM_MOUSEMOVE:
  2305. if (!ped->fMouseDown)
  2306. break;
  2307. /* else fall through */
  2308. case WM_LBUTTONDBLCLK:
  2309. case WM_LBUTTONDOWN:
  2310. case WM_LBUTTONUP:
  2311. /* wParam - contains a value that indicates which virtual keys are down
  2312. lParam - contains x and y coords of the mouse cursor */
  2313. MLMouseMotionHandler(ped, message, wParam, MAKEPOINT(lParam));
  2314. break;
  2315. case WM_CREATE:
  2316. /* wParam - handle to window being created
  2317. lParam - points to a CREATESTRUCT that contains copies of parameters
  2318. passed to the CreateWindow function. */
  2319. return(MLCreateHandler(hwnd, ped, (LPCREATESTRUCT) lParam));
  2320. break;
  2321. case WM_PAINT:
  2322. /* wParam - officially not used (but some apps pass in a DC here)
  2323. lParam - not used */
  2324. MLPaintHandler(ped, wParam);
  2325. break;
  2326. case WM_PASTE:
  2327. /* wParam - not used
  2328. lParam - not used */
  2329. if (!ped->fReadOnly)
  2330. MLPasteText(ped);
  2331. break;
  2332. case WM_SETFOCUS:
  2333. /* wParam - handle of window that loses the input focus (may be NULL)
  2334. lParam - not used */
  2335. MLSetFocusHandler(ped);
  2336. break;
  2337. case WM_SETTEXT:
  2338. /* wParam - not used
  2339. lParam - points to a null-terminated string that is used to set the
  2340. window text. */
  2341. return(MLSetTextHandler(ped, (LPSTR)lParam));
  2342. break;
  2343. case WM_SIZE:
  2344. /* wParam - defines the type of resizing fullscreen, sizeiconic,
  2345. sizenormal etc.
  2346. lParam - new width in LOWORD, new height in HIGHWORD of client area */
  2347. MLSizeHandler(ped);
  2348. break;
  2349. case EM_FMTLINES:
  2350. /* wParam - indicates disposition of end-of-line chars. If non
  2351. * zero, the chars CR CR LF are placed at the end of a word
  2352. * wrapped line. If wParam is zero, the end of line chars are
  2353. * removed. This is only done when the user gets a handle (via
  2354. * EM_GETHANDLE) to the text. lParam - not used.
  2355. */
  2356. if (wParam)
  2357. MLInsertCrCrLf(ped);
  2358. else
  2359. MLStripCrCrLf(ped);
  2360. MLBuildchLines(ped, 0, 0, FALSE);
  2361. return((LONG)(ped->fFmtLines = wParam));
  2362. break;
  2363. case EM_GETHANDLE:
  2364. /* wParam - not used
  2365. lParam - not used */
  2366. /* effects: Returns a handle to the edit control's text. */
  2367. /*
  2368. * Null terminate the string. Note that we are guaranteed to have the
  2369. * memory for the NULL since ECInsertText allocates an extra
  2370. * byte for the NULL terminator.
  2371. */
  2372. /**(LocalLock(ped->hText)+ped->cch) = 0;*/
  2373. /*LocalUnlock(ped->hText);*/
  2374. *(LMHtoP(ped->hText)+ped->cch) = 0;
  2375. return((LONG)ped->hText);
  2376. break;
  2377. case EM_GETLINE:
  2378. /* wParam - line number to copy (0 is first line)
  2379. lParam - buffer to copy text to. First word is max # of bytes to
  2380. copy */
  2381. return(MLGetLineHandler(ped, wParam,
  2382. *(WORD FAR *)lParam, (LPSTR)lParam));
  2383. break;
  2384. case EM_LINEFROMCHAR:
  2385. /* wParam - Contains the index value for the desired char in the text
  2386. of the edit control. These are 0 based.
  2387. lParam - not used */
  2388. return((LONG)MLIchToLineHandler(ped, wParam));
  2389. break;
  2390. case EM_LINEINDEX:
  2391. /* wParam - specifies the desired line number where the number of the
  2392. first line is 0. If linenumber = 0, the line with the caret is used.
  2393. lParam - not used.
  2394. This function returns the number of character positions that occur
  2395. preceeding the first char in a given line. */
  2396. return((LONG)MLLineIndexHandler(ped, wParam));
  2397. break;
  2398. case EM_LINELENGTH:
  2399. /* wParam - specifies the character index of a character in the
  2400. specified line, where the first line is 0. If -1, the length
  2401. of the current line (with the caret) is returned not including the
  2402. length of any selected text.
  2403. lParam - not used */
  2404. return((LONG)MLLineLengthHandler(ped, wParam));
  2405. break;
  2406. case EM_LINESCROLL:
  2407. /* wParam - not used
  2408. lParam - Contains the number of lines and char positions to scroll */
  2409. MLScrollHandler(ped, WM_VSCROLL, EM_LINESCROLL, LOWORD(lParam));
  2410. MLScrollHandler(ped, WM_HSCROLL, EM_LINESCROLL, HIWORD(lParam));
  2411. break;
  2412. case EM_REPLACESEL:
  2413. /* wParam - not used
  2414. lParam - Points to a null terminated replacement text. */
  2415. SwapHandle(&lParam);
  2416. ECEmptyUndo(ped);
  2417. MLDeleteText(ped);
  2418. ECEmptyUndo(ped);
  2419. SwapHandle(&lParam);
  2420. MLInsertText(ped, (LPSTR)lParam, lstrlen((LPSTR)lParam), FALSE);
  2421. ECEmptyUndo(ped);
  2422. break;
  2423. case EM_SCROLL:
  2424. /* Scroll the window vertically */
  2425. /* wParam - contains the command type
  2426. lParam - not used. */
  2427. return(MLScrollHandler(ped, WM_VSCROLL, wParam, (int)lParam));
  2428. break;
  2429. case EM_SETHANDLE:
  2430. /* wParam - contains a handle to the text buffer
  2431. lParam - not used */
  2432. MLSetHandleHandler(ped, (HANDLE)wParam);
  2433. break;
  2434. case EM_SETRECT:
  2435. /* wParam - not used
  2436. lParam - Points to a RECT which specifies the new dimensions of the
  2437. rectangle. */
  2438. MLSetRectHandler(ped, (LPRECT)lParam);
  2439. /* Do a repaint of the whole client area since the app may have shrunk
  2440. * the rectangle for the text and we want to be able to erase the old
  2441. * text.
  2442. */
  2443. InvalidateRect(hwnd, (LPRECT)NULL, TRUE);
  2444. UpdateWindow(hwnd);
  2445. break;
  2446. case EM_SETRECTNP:
  2447. /* wParam - not used
  2448. lParam - Points to a RECT which specifies the new dimensions of the
  2449. rectangle.
  2450. */
  2451. /* We don't do a repaint here. */
  2452. MLSetRectHandler(ped, (LPRECT)lParam);
  2453. break;
  2454. case EM_SETSEL:
  2455. /* wParam - not used
  2456. lParam - starting pos in lowword ending pos in high word */
  2457. MLSetSelectionHandler(ped, LOWORD(lParam), HIWORD(lParam));
  2458. break;
  2459. case WM_UNDO:
  2460. case EM_UNDO:
  2461. return(MLUndoHandler(ped));
  2462. break;
  2463. case EM_SETTABSTOPS:
  2464. /* This sets the tab stop positions for multiline edit controls.
  2465. * wParam - Number of tab stops
  2466. * lParam - Far ptr to a WORD array containing the Tab stop positions
  2467. */
  2468. return(MLSetTabStops(ped, (int)wParam, (LPINT)lParam));
  2469. break;
  2470. default:
  2471. return(DefWindowProc(hwnd,message,wParam,lParam));
  2472. break;
  2473. }
  2474. return(1L);
  2475. } /* MLEditWndProc */
  2476. void NEAR PASCAL MLDrawText(register PED ped,
  2477. HDC hdc,
  2478. ICH ichStart,
  2479. ICH ichEnd)
  2480. /* effects: draws the characters between ichstart and ichend.
  2481. */
  2482. {
  2483. DWORD textColorSave;
  2484. DWORD bkColorSave;
  2485. LONG xyPos;
  2486. LONG xyNonLeftJustifiedStart;
  2487. HBRUSH hBrush;
  2488. ICH ich;
  2489. PSTR pText;
  2490. int line;
  2491. ICH length;
  2492. ICH length2;
  2493. int xOffset;
  2494. DWORD ext;
  2495. RECT rc;
  2496. BOOL fPartialLine = FALSE;
  2497. BOOL fSelected = FALSE;
  2498. BOOL fLeftJustified = TRUE;
  2499. #ifdef WOW
  2500. HWND hwndSend;
  2501. #endif
  2502. if (ped->fNoRedraw || !ped->ichLinesOnScreen)
  2503. /* Just return if nothing to draw */
  2504. return;
  2505. /* Set initial state of dc */
  2506. #ifndef WOW
  2507. hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
  2508. #else
  2509. if (!(hwndSend = GetParent(ped->hwnd)))
  2510. hwndSend = ped->hwnd;
  2511. SendMessage(hwndSend, WM_CTLCOLOR, (WORD)hdc, MAKELONG(ped->hwnd, CTLCOLOR_EDIT));
  2512. #endif
  2513. if ((WORD)ichStart < (WORD)ped->chLines[ped->screenStart])
  2514. {
  2515. ichStart = ped->chLines[ped->screenStart];
  2516. if (ichStart > ichEnd)
  2517. return;
  2518. }
  2519. line = min(ped->screenStart+ped->ichLinesOnScreen,ped->cLines-1);
  2520. ichEnd = umin(ichEnd, ped->chLines[line]+MLLineLength(ped, line));
  2521. line = MLIchToLineHandler(ped, ichStart);
  2522. if (ped->format != ES_LEFT)
  2523. {
  2524. ichStart = ped->chLines[line];
  2525. fLeftJustified = FALSE;
  2526. }
  2527. pText = LocalLock(ped->hText);
  2528. HideCaret(ped->hwnd);
  2529. while (ichStart <= ichEnd)
  2530. {
  2531. StillWithSameLine:
  2532. length2 = MLLineLength(ped, line);
  2533. if (length2 < (ichStart - ped->chLines[line]))
  2534. {
  2535. goto NextLine;
  2536. }
  2537. length = length2 - (ichStart - ped->chLines[line]);
  2538. xyPos = MLIchToXYPos(ped, hdc, ichStart, FALSE);
  2539. if (!fLeftJustified && ichStart == ped->chLines[line])
  2540. xyNonLeftJustifiedStart = xyPos;
  2541. /* Find out how many pixels we indent the line for funny formats */
  2542. if (ped->format != ES_LEFT)
  2543. xOffset = MLCalcXOffset(ped, hdc, line);
  2544. else
  2545. xOffset = -ped->xOffset;
  2546. if (!(ped->ichMinSel == ped->ichMaxSel ||
  2547. ichStart >= ped->ichMaxSel ||
  2548. ichEnd < ped->ichMinSel ||
  2549. (!ped->fNoHideSel && !ped->fFocus)))
  2550. {
  2551. if (ichStart < ped->ichMinSel)
  2552. {
  2553. fSelected = FALSE;
  2554. length2 = umin(ichStart+length, ped->ichMinSel)-ichStart;
  2555. }
  2556. else
  2557. {
  2558. fSelected = TRUE;
  2559. length2 = umin(ichStart+length, ped->ichMaxSel)-ichStart;
  2560. /* Select in the highlight colors */
  2561. bkColorSave = SetBkColor(hdc, ped->rgbHiliteBk);
  2562. textColorSave = SetTextColor(hdc, ped->rgbHiliteText);
  2563. }
  2564. fPartialLine = (length != length2);
  2565. length = length2;
  2566. }
  2567. ext = ECTabTheTextOut(hdc, LOWORD(xyPos), HIWORD(xyPos),
  2568. (LPSTR)(pText+ichStart), length,
  2569. ped,/*iLeft+xOffset*/ped->rcFmt.left+xOffset, TRUE);
  2570. if (fSelected)
  2571. {
  2572. fSelected = FALSE;
  2573. SetBkColor(hdc, bkColorSave);
  2574. SetTextColor(hdc, textColorSave);
  2575. }
  2576. if (fPartialLine)
  2577. {
  2578. fPartialLine = FALSE;
  2579. ichStart += length;
  2580. goto StillWithSameLine;
  2581. }
  2582. /* Fill to end of line so use a very large width for this rectangle.
  2583. */
  2584. SetRect((LPRECT)&rc,
  2585. LOWORD(xyPos)+LOWORD(ext), HIWORD(xyPos),
  2586. 32764,
  2587. HIWORD(xyPos)+ped->lineHeight);
  2588. ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, (LPRECT)&rc, "",0,0L);
  2589. if (!fLeftJustified)
  2590. {
  2591. SetRect((LPRECT)&rc,
  2592. ped->rcFmt.left,
  2593. HIWORD(xyNonLeftJustifiedStart),
  2594. LOWORD(xyNonLeftJustifiedStart),
  2595. HIWORD(xyNonLeftJustifiedStart)+ped->lineHeight);
  2596. ExtTextOut(hdc, rc.left, rc.top,
  2597. ETO_OPAQUE, (LPRECT)&rc, "",0,0L);
  2598. }
  2599. NextLine:
  2600. line++;
  2601. if (ped->cLines > line)
  2602. {
  2603. ichStart = ped->chLines[line];
  2604. }
  2605. else
  2606. ichStart = ichEnd+1;
  2607. }
  2608. LocalUnlock(ped->hText);
  2609. ShowCaret(ped->hwnd);
  2610. MLSetCaretPosition(ped,hdc);
  2611. }