Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

editml.c

Go to the documentation of this file.
00001 /***************************************************************************\ 00002 * editml.c - Edit controls rewrite. Version II of edit controls. 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Multi-Line Support Routines 00007 * 00008 * Created: 24-Jul-88 davidds 00009 \***************************************************************************/ 00010 00011 #include "precomp.h" 00012 #pragma hdrstop 00013 00014 /* 00015 * Number of lines to bump when reallocating index buffer 00016 */ 00017 #define LINEBUMP 32 00018 00019 /* 00020 * Used for ML scroll updates 00021 */ 00022 #define ML_REFRESH 0xffffffff 00023 00024 __inline void MLSanityCheck(PED ped) 00025 { 00026 UNREFERENCED_PARAMETER(ped); // For free build 00027 00028 UserAssert(ped->cch >= ped->chLines[ped->cLines - 1]); 00029 } 00030 00031 00032 /***************************************************************************\ 00033 * 00034 * MLGetLineWidth() 00035 * 00036 * Returns the max width in a line. ECTabTheTextOut() ensures that max 00037 * width won't overflow. 00038 * 00039 \***************************************************************************/ 00040 UINT MLGetLineWidth(HDC hdc, LPSTR lpstr, int nCnt, PED ped) 00041 { 00042 return(ECTabTheTextOut(hdc, 0, 0, 0, 0, lpstr, nCnt, 0, ped, 0, ECT_CALC, NULL)); 00043 } 00044 00045 /***************************************************************************\ 00046 * 00047 * MLSize() 00048 * 00049 * Handles resizing of the edit control window and updating thereof. 00050 * 00051 * Sets the edit field's formatting area given the passed in "client area". 00052 * We fudge it if it doesn't seem reasonable. 00053 * 00054 \***************************************************************************/ 00055 00056 void MLSize(PED ped, BOOL fRedraw) 00057 { 00058 // Calculate the # of lines we can fit in our rectangle. 00059 ped->ichLinesOnScreen = (ped->rcFmt.bottom - ped->rcFmt.top) / ped->lineHeight; 00060 00061 // Make the format rectangle height an integral number of lines 00062 ped->rcFmt.bottom = ped->rcFmt.top + ped->ichLinesOnScreen * ped->lineHeight; 00063 00064 // Rebuild the line array 00065 if (ped->fWrap) { 00066 MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL); 00067 MLUpdateiCaretLine(ped); 00068 } else { 00069 MLScroll(ped, TRUE, ML_REFRESH, 0, fRedraw); 00070 MLScroll(ped, FALSE, ML_REFRESH, 0, fRedraw); 00071 } 00072 } 00073 00074 /***************************************************************************\ 00075 * MLCalcXOffset AorW 00076 * 00077 * Calculates the horizontal offset (indent) required for centered 00078 * and right justified lines. 00079 * 00080 * History: 00081 * 00082 * Not used if language pack loaded. 00083 \***************************************************************************/ 00084 00085 int MLCalcXOffset( 00086 PED ped, 00087 HDC hdc, 00088 int lineNumber) 00089 { 00090 PSTR pText; 00091 ICH lineLength; 00092 ICH lineWidth; 00093 00094 if (ped->format == ES_LEFT) 00095 return (0); 00096 00097 lineLength = MLLine(ped, lineNumber); 00098 00099 if (lineLength) { 00100 00101 pText = ECLock(ped) + ped->chLines[lineNumber] * ped->cbChar; 00102 hdc = ECGetEditDC(ped, TRUE); 00103 lineWidth = MLGetLineWidth(hdc, pText, lineLength, ped); 00104 ECReleaseEditDC(ped, hdc, TRUE); 00105 ECUnlock(ped); 00106 } else { 00107 lineWidth = 0; 00108 } 00109 00110 /* 00111 * If a SPACE or a TAB was eaten at the end of a line by MLBuildchLines 00112 * to prevent a delimiter appearing at the begining of a line, the 00113 * the following calculation will become negative causing this bug. 00114 * So, now, we take zero in such cases. 00115 * Fix for Bug #3566 --01/31/91-- SANKAR -- 00116 */ 00117 lineWidth = max(0, (int)(ped->rcFmt.right-ped->rcFmt.left-lineWidth)); 00118 00119 if (ped->format == ES_CENTER) 00120 return (lineWidth / 2); 00121 00122 if (ped->format == ES_RIGHT) { 00123 00124 /* 00125 * Subtract 1 so that the 1 pixel wide cursor will be in the visible 00126 * region on the very right side of the screen. 00127 */ 00128 return max(0, (int)(lineWidth-1)); 00129 } 00130 00131 return 0; 00132 } 00133 00134 /***************************************************************************\ 00135 * MLMoveSelection AorW 00136 * 00137 * Moves the selection character in the direction indicated. Assumes 00138 * you are starting at a legal point, we decrement/increment the ich. Then, 00139 * This decrements/increments it some more to get past CRLFs... 00140 * 00141 * History: 00142 \***************************************************************************/ 00143 00144 ICH MLMoveSelection( 00145 PED ped, 00146 ICH ich, 00147 BOOL fLeft) 00148 { 00149 00150 if (fLeft && ich > 0) { 00151 00152 /* 00153 * Move left 00154 */ 00155 ich = ECPrevIch( ped, NULL, ich ); 00156 if (ich) { 00157 if (ped->fAnsi) { 00158 LPSTR pText; 00159 00160 /* 00161 * Check for CRLF or CRCRLF 00162 */ 00163 pText = ECLock(ped) + ich; 00164 00165 /* 00166 * Move before CRLF or CRCRLF 00167 */ 00168 if (*(WORD UNALIGNED *)(pText - 1) == 0x0A0D) { 00169 ich--; 00170 if (ich && *(pText - 2) == 0x0D) 00171 ich--; 00172 } 00173 ECUnlock(ped); 00174 } else { // !fAnsi 00175 LPWSTR pwText; 00176 00177 /* 00178 * Check for CRLF or CRCRLF 00179 */ 00180 pwText = (LPWSTR)ECLock(ped) + ich; 00181 00182 /* 00183 * Move before CRLF or CRCRLF 00184 */ 00185 if (*(pwText - 1) == 0x0D && *pwText == 0x0A) { 00186 ich--; 00187 if (ich && *(pwText - 2) == 0x0D) 00188 ich--; 00189 } 00190 ECUnlock(ped); 00191 } 00192 } 00193 } else if (!fLeft && ich < ped->cch) { 00194 /* 00195 * Move right. 00196 */ 00197 ich = ECNextIch( ped, NULL, ich ); 00198 if (ich < ped->cch) { 00199 if (ped->fAnsi) { 00200 LPSTR pText; 00201 pText = ECLock(ped) + ich; 00202 00203 /* 00204 * Move after CRLF 00205 */ 00206 if (*(WORD UNALIGNED *)(pText - 1) == 0x0A0D) 00207 ich++; 00208 else { 00209 00210 /* 00211 * Check for CRCRLF 00212 */ 00213 if (ich && *(WORD UNALIGNED *)pText == 0x0A0D && *(pText - 1) == 0x0D) 00214 ich += 2; 00215 } 00216 ECUnlock(ped); 00217 } else { // !fAnsi 00218 LPWSTR pwText; 00219 pwText = (LPWSTR)ECLock(ped) + ich; 00220 00221 /* 00222 * Move after CRLF 00223 */ 00224 if (*(pwText - 1) == 0x0D && *pwText == 0x0A) 00225 ich++; 00226 else { 00227 00228 /* 00229 * Check for CRCRLF 00230 */ 00231 if (ich && *(pwText - 1) == 0x0D && *pwText == 0x0D && 00232 *(pwText + 1) == 0x0A) 00233 ich += 2; 00234 } 00235 ECUnlock(ped); 00236 } 00237 } 00238 } 00239 return (ich); 00240 } 00241 00242 /***************************************************************************\ 00243 * MLMoveSelectionRestricted AorW 00244 * 00245 * Moves the selection like MLMoveSelection, but also obeys limitations 00246 * imposed by some languages such as Thai, where the cursor cannot stop 00247 * between a character and it's attached vowel or tone marks. 00248 * 00249 * Only called if the language pack is loaded. 00250 * 00251 \***************************************************************************/ 00252 00253 /***************************************************************************\ 00254 * MLMoveSelectionRestricted AorW 00255 * 00256 * Moves the selection like MLMoveSelection, but also obeys limitations 00257 * imposed by some languages such as Thai, where the cursor cannot stop 00258 * between a character and it's attached vowel or tone marks. 00259 * 00260 * Only called if the language pack is loaded. 00261 * 00262 \***************************************************************************/ 00263 00264 ICH MLMoveSelectionRestricted( 00265 PED ped, 00266 ICH ich, 00267 BOOL fLeft) 00268 { 00269 PSTR pText; 00270 HDC hdc; 00271 ICH ichResult; 00272 00273 pText = ECLock(ped); 00274 hdc = ECGetEditDC(ped, TRUE); 00275 ichResult = ped->pLpkEditCallout->EditMoveSelection(ped, hdc, pText, ich, fLeft); 00276 ECReleaseEditDC(ped, hdc, TRUE); 00277 ECUnlock(ped); 00278 00279 return ichResult; 00280 } 00281 00282 00283 /***************************************************************************\ 00284 * MLSetCaretPosition AorW 00285 * 00286 * If the window has the focus, find where the caret belongs and move 00287 * it there. 00288 * 00289 * History: 00290 \***************************************************************************/ 00291 00292 void MLSetCaretPosition( 00293 PED ped, 00294 HDC hdc) 00295 { 00296 POINT position; 00297 BOOL prevLine; 00298 int x = -20000; 00299 int y = -20000; 00300 00301 /* 00302 * We will only position the caret if we have the focus since we don't want 00303 * to move the caret while another window could own it. 00304 */ 00305 if (!ped->fFocus || !_IsWindowVisible(ped->pwnd)) 00306 return; 00307 00308 /* 00309 * Find the position of the caret 00310 */ 00311 if (!ped->fCaretHidden && 00312 ((ICH) ped->iCaretLine >= ped->ichScreenStart) && 00313 ((ICH) ped->iCaretLine < (ped->ichScreenStart + ped->ichLinesOnScreen))) { 00314 00315 RECT rcRealFmt; 00316 00317 if (ped->f40Compat) 00318 { 00319 GetClientRect(ped->hwnd, &rcRealFmt); 00320 IntersectRect(&rcRealFmt, &rcRealFmt, &ped->rcFmt); 00321 } else { 00322 CopyRect(&rcRealFmt, &ped->rcFmt); 00323 } 00324 00325 if (ped->cLines - 1 != ped->iCaretLine && ped->ichCaret == ped->chLines[ped->iCaretLine + 1]) { 00326 prevLine = TRUE; 00327 } else { 00328 prevLine = FALSE; 00329 } 00330 00331 MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine, &position); 00332 00333 if ( (position.y >= rcRealFmt.top) && 00334 (position.y <= rcRealFmt.bottom - ped->lineHeight)) { 00335 int xPos = position.x; 00336 int cxCaret = ECGetCaretWidth(); 00337 00338 if (ped->fWrap || 00339 ((xPos > (rcRealFmt.left - cxCaret)) && 00340 (xPos <= rcRealFmt.right))) { 00341 // Make sure the caret is in the visible region if word 00342 // wrapping. This is so that the caret will be visible if the 00343 // line ends with a space. 00344 x = max(xPos, rcRealFmt.left); 00345 x = min(x, rcRealFmt.right - cxCaret); 00346 y = position.y; 00347 } 00348 } 00349 } 00350 00351 if (ped->pLpkEditCallout) { 00352 NtUserSetCaretPos(x + ped->iCaretOffset, y); 00353 } else { 00354 NtUserSetCaretPos(x, y); 00355 } 00356 00357 // FE_IME : MLSetCaretPosition -- ImmSetCompositionWindow(CFS_RECT) 00358 if (fpImmIsIME(THREAD_HKL())) { 00359 if (x != -20000 && y != -20000) { 00360 ECImmSetCompositionWindow(ped, x, y); 00361 } 00362 } 00363 } 00364 00365 /***************************************************************************\ 00366 * MLLine 00367 * 00368 * Returns the length of the line (cch) given by lineNumber ignoring any 00369 * CRLFs in the line. 00370 * 00371 * History: 00372 \***************************************************************************/ 00373 00374 ICH MLLine( 00375 PED ped, 00376 ICH lineNumber) 00377 { 00378 ICH result; 00379 00380 UserAssert(lineNumber < ped->cLines); 00381 00382 if (lineNumber >= ped->cLines) 00383 return (0); 00384 00385 if (lineNumber == ped->cLines - 1) { 00386 00387 /* 00388 * Since we can't have a CRLF on the last line 00389 */ 00390 return (ped->cch - ped->chLines[ped->cLines - 1]); 00391 } else { 00392 result = ped->chLines[lineNumber + 1] - ped->chLines[lineNumber]; 00393 RIPMSG1(RIP_VERBOSE, "MLLine result=%d\n", result); 00394 00395 /* 00396 * Now check for CRLF or CRCRLF at end of line 00397 */ 00398 if (result > 1) { 00399 if (ped->fAnsi) { 00400 LPSTR pText; 00401 00402 pText = ECLock(ped) + ped->chLines[lineNumber + 1] - 2; 00403 if (*(WORD UNALIGNED *)pText == 0x0A0D) { 00404 result -= 2; 00405 if (result && *(--pText) == 0x0D) 00406 /* 00407 * In case there was a CRCRLF 00408 */ 00409 result--; 00410 } 00411 } else { // !fAnsi 00412 LPWSTR pwText; 00413 00414 pwText = (LPWSTR)ECLock(ped) + 00415 (ped->chLines[lineNumber + 1] - 2); 00416 if (*(DWORD UNALIGNED *)pwText == 0x000A000D) { 00417 result = result - 2; 00418 if (result && *(--pwText) == 0x0D) 00419 /* 00420 * In case there was a CRCRLF 00421 */ 00422 result--; 00423 } 00424 00425 } 00426 ECUnlock(ped); 00427 } 00428 } 00429 return (result); 00430 } 00431 00432 00433 /***************************************************************************\ 00434 * MLIchToLine AorW 00435 * 00436 * Returns the line number (starting from 0) which contains the given 00437 * character index. If ich is -1, return the line the first char in the 00438 * selection is on (the caret if no selection) 00439 * 00440 * History: 00441 \***************************************************************************/ 00442 00443 int MLIchToLine( 00444 PED ped, 00445 ICH ich) 00446 { 00447 int iLo, iHi, iLine; 00448 00449 iLo = 0; 00450 iHi = ped->cLines; 00451 00452 if (ich == (ICH)-1) 00453 ich = ped->ichMinSel; 00454 00455 while (iLo < iHi - 1) { 00456 iLine = max((iHi - iLo)/2, 1) + iLo; 00457 00458 if (ped->chLines[iLine] > ich) { 00459 iHi = iLine; 00460 } else { 00461 iLo = iLine; 00462 } 00463 } 00464 00465 return iLo; 00466 } 00467 00468 /***************************************************************************\ 00469 * MLIchToYPos 00470 * 00471 * Given an ich, return its y coordinate with respect to the top line 00472 * displayed in the window. If prevLine is TRUE and if the ich is at the 00473 * beginning of the line, return the y coordinate of the 00474 * previous line (if it is not a CRLF). 00475 * 00476 * Added for the LPK (3Dec96) - with an LPK installed, calculating X position is 00477 * a far more processor intensive job. Where only the Y position is required 00478 * this routine should be called instead of MLIchToXYPos. 00479 * 00480 * Called only when LPK installed. 00481 * 00482 \***************************************************************************/ 00483 00484 00485 /***************************************************************************\ 00486 * MLIchToYPos 00487 * 00488 * Given an ich, return its y coordinate with respect to the top line 00489 * displayed in the window. If prevLine is TRUE and if the ich is at the 00490 * beginning of the line, return the y coordinate of the 00491 * previous line (if it is not a CRLF). 00492 * 00493 * Added for the LPK (3Dec96) - with an LPK installed, calculating X position is 00494 * a far more processor intensive job. Where only the Y position is required 00495 * this routine should be called instead of MLIchToXYPos. 00496 * 00497 * Called only when LPK installed. 00498 * 00499 \***************************************************************************/ 00500 00501 00502 INT MLIchToYPos( 00503 PED ped, 00504 ICH ich, 00505 BOOL prevLine) 00506 { 00507 int iline; 00508 int yPosition; 00509 PSTR pText; 00510 00511 /* 00512 * Determine what line the character is on 00513 */ 00514 iline = MLIchToLine(ped, ich); 00515 00516 /* 00517 * Calc. the yPosition now. Note that this may change by the height of one 00518 * char if the prevLine flag is set and the ICH is at the beginning of a 00519 * line. 00520 */ 00521 yPosition = (iline - ped->ichScreenStart) * ped->lineHeight + ped->rcFmt.top; 00522 00523 pText = ECLock(ped); 00524 if (prevLine && iline && (ich == ped->chLines[iline]) && 00525 (!AWCOMPARECHAR(ped, pText + (ich - 2) * ped->cbChar, 0x0D) || 00526 !AWCOMPARECHAR(ped, pText + (ich - 1) * ped->cbChar, 0x0A))) { 00527 00528 /* 00529 * First char in the line. We want Y position of the previous 00530 * line if we aren't at the 0th line. 00531 */ 00532 iline--; 00533 00534 yPosition = yPosition - ped->lineHeight; 00535 } 00536 ECUnlock(ped); 00537 00538 return yPosition; 00539 } 00540 00541 /***************************************************************************\ 00542 * MLIchToXYPos 00543 * 00544 * Given an ich, return its x,y coordinates with respect to the top 00545 * left character displayed in the window. Returns the coordinates of the top 00546 * left position of the char. If prevLine is TRUE then if the ich is at the 00547 * beginning of the line, we will return the coordinates to the right of the 00548 * last char on the previous line (if it is not a CRLF). 00549 * 00550 * History: 00551 \***************************************************************************/ 00552 00553 void MLIchToXYPos( 00554 PED ped, 00555 HDC hdc, 00556 ICH ich, 00557 BOOL prevLine, 00558 LPPOINT ppt) 00559 { 00560 int iline; 00561 ICH cch; 00562 int xPosition, yPosition; 00563 int xOffset; 00564 00565 /* 00566 * For horizontal scroll displacement on left justified text and 00567 * for indent on centered or right justified text 00568 */ 00569 PSTR pText, pTextStart, pLineStart; 00570 00571 /* 00572 * Determine what line the character is on 00573 */ 00574 iline = MLIchToLine(ped, ich); 00575 00576 /* 00577 * Calc. the yPosition now. Note that this may change by the height of one 00578 * char if the prevLine flag is set and the ICH is at the beginning of a 00579 * line. 00580 */ 00581 yPosition = (iline - ped->ichScreenStart) * ped->lineHeight + ped->rcFmt.top; 00582 00583 /* 00584 * Now determine the xPosition of the character 00585 */ 00586 pTextStart = ECLock(ped); 00587 00588 if (prevLine && iline && (ich == ped->chLines[iline]) && 00589 (!AWCOMPARECHAR(ped, pTextStart + (ich - 2) * ped->cbChar, 0x0D) || 00590 !AWCOMPARECHAR(ped, pTextStart + (ich - 1) * ped->cbChar, 0x0A))) { 00591 00592 /* 00593 * First char in the line. We want text extent upto end of the previous 00594 * line if we aren't at the 0th line. 00595 */ 00596 iline--; 00597 00598 yPosition = yPosition - ped->lineHeight; 00599 pLineStart = pTextStart + ped->chLines[iline] * ped->cbChar; 00600 00601 /* 00602 * Note that we are taking the position in front of any CRLFs in the 00603 * text. 00604 */ 00605 cch = MLLine(ped, iline); 00606 00607 } else { 00608 00609 pLineStart = pTextStart + ped->chLines[iline] * ped->cbChar; 00610 pText = pTextStart + ich * ped->cbChar; 00611 00612 /* 00613 * Strip off CRLF or CRCRLF. Note that we may be pointing to a CR but in 00614 * which case we just want to strip off a single CR or 2 CRs. 00615 */ 00616 00617 /* 00618 * We want pText to point to the first CR at the end of the line if 00619 * there is one. Thus, we will get an xPosition to the right of the last 00620 * visible char on the line otherwise we will be to the left of 00621 * character ich. 00622 */ 00623 00624 /* 00625 * Check if we at the end of text 00626 */ 00627 if (ich < ped->cch) { 00628 if (ped->fAnsi) { 00629 if (ich && *(WORD UNALIGNED *)(pText - 1) == 0x0A0D) { 00630 pText--; 00631 if (ich > 2 && *(pText - 1) == 0x0D) 00632 pText--; 00633 } 00634 } else { 00635 LPWSTR pwText = (LPWSTR)pText; 00636 00637 if (ich && *(DWORD UNALIGNED *)(pwText - 1) == 0x000A000D) { 00638 pwText--; 00639 if (ich > 2 && *(pwText - 1) == 0x0D) 00640 pwText--; 00641 } 00642 pText = (LPSTR)pwText; 00643 } 00644 } 00645 00646 if (pText < pLineStart) 00647 pText = pLineStart; 00648 00649 cch = (ICH)(pText - pLineStart)/ped->cbChar; 00650 } 00651 00652 /* 00653 * Find out how many pixels we indent the line for funny formats 00654 */ 00655 if (ped->pLpkEditCallout) { 00656 /* 00657 * Must find position at start of character offset cch from start of line. 00658 * This depends on the layout and the reading order 00659 */ 00660 xPosition = ped->pLpkEditCallout->EditIchToXY( 00661 ped, hdc, pLineStart, MLLine(ped, iline), cch); 00662 } else { 00663 if (ped->format != ES_LEFT) { 00664 xOffset = MLCalcXOffset(ped, hdc, iline); 00665 } else { 00666 xOffset = -(int)ped->xOffset; 00667 } 00668 00669 xPosition = ped->rcFmt.left + xOffset + 00670 MLGetLineWidth(hdc, pLineStart, cch, ped); 00671 } 00672 00673 ECUnlock(ped); 00674 ppt->x = xPosition; 00675 ppt->y = yPosition; 00676 return ; 00677 } 00678 00679 /***************************************************************************\ 00680 * MLMouseToIch AorW 00681 * 00682 * Returns the closest cch to where the mouse point is. Also optionally 00683 * returns lineindex in pline (So that we can tell if we are at the beginning 00684 * of the line or end of the previous line.) 00685 * 00686 * History: 00687 \***************************************************************************/ 00688 00689 ICH MLMouseToIch( 00690 PED ped, 00691 HDC hdc, 00692 LPPOINT mousePt, 00693 LPICH pline) 00694 { 00695 int xOffset; 00696 LPSTR pLineStart; 00697 int height = mousePt->y; 00698 int line; //WASINT 00699 int width = mousePt->x; 00700 ICH cch; 00701 ICH cLineLength; 00702 ICH cLineLengthNew; 00703 ICH cLineLengthHigh; 00704 ICH cLineLengthLow; 00705 ICH cLineLengthTemp; 00706 int textWidth; 00707 int iCurWidth; 00708 int lastHighWidth, lastLowWidth; 00709 00710 /* 00711 * First determine which line the mouse is pointing to. 00712 */ 00713 line = ped->ichScreenStart; 00714 if (height <= ped->rcFmt.top) { 00715 00716 /* 00717 * Either return 0 (the very first line, or one line before the top line 00718 * on the screen. Note that these are signed mins and maxes since we 00719 * don't expect (or allow) more than 32K lines. 00720 */ 00721 line = max(0, line-1); 00722 } else if (height >= ped->rcFmt.bottom) { 00723 00724 /* 00725 * Are we below the last line displayed 00726 */ 00727 line = min(line+(int)ped->ichLinesOnScreen, (int)(ped->cLines-1)); 00728 } else { 00729 00730 /* 00731 * We are somewhere on a line visible on screen 00732 */ 00733 line = min(line + (int)((height - ped->rcFmt.top) / ped->lineHeight), 00734 (int)(ped->cLines - 1)); 00735 } 00736 00737 /* 00738 * Now determine what horizontal character the mouse is pointing to. 00739 */ 00740 pLineStart = ECLock(ped) + ped->chLines[line] * ped->cbChar; 00741 cLineLength = MLLine(ped, line); /* Length is sans CRLF or CRCRLF */ 00742 RIPMSG3(RIP_VERBOSE, "MLLine(ped=%x, line=%d) returned %d\n", ped, line, cLineLength); 00743 UserAssert((int)cLineLength >= 0); 00744 00745 /* 00746 * If the language pack is loaded, visual and logical character order 00747 * may differ. 00748 */ 00749 if (ped->pLpkEditCallout) { 00750 /* 00751 * Use the language pack to find the character nearest the cursor. 00752 */ 00753 cch = ped->chLines[line] + ped->pLpkEditCallout->EditMouseToIch 00754 (ped, hdc, pLineStart, cLineLength, width); 00755 } else { 00756 /* 00757 * xOffset will be a negative value for center and right justified lines. 00758 * ie. We will just displace the lines left by the amount of indent for 00759 * right and center justification. Note that ped->xOffset will be 0 for 00760 * these lines since we don't support horizontal scrolling with them. 00761 */ 00762 if (ped->format != ES_LEFT) { 00763 xOffset = MLCalcXOffset(ped, hdc, line); 00764 } else { 00765 /* 00766 * So that we handle a horizontally scrolled window for left justified 00767 * text. 00768 */ 00769 xOffset = 0; 00770 } 00771 00772 width = width - xOffset; 00773 00774 /* 00775 * The code below is tricky... I depend on the fact that ped->xOffset is 0 00776 * for right and center justified lines 00777 */ 00778 00779 /* 00780 * Now find out how many chars fit in the given width 00781 */ 00782 if (width >= ped->rcFmt.right) { 00783 00784 /* 00785 * Return 1+last char in line or one plus the last char visible 00786 */ 00787 cch = ECCchInWidth(ped, hdc, pLineStart, cLineLength, 00788 ped->rcFmt.right - ped->rcFmt.left + ped->xOffset, TRUE); 00789 // 00790 // Consider DBCS in case of width >= ped->rcFmt.right 00791 // 00792 // Since ECCchInWidth and MLLineLength takes care of DBCS, we only need to 00793 // worry about if the last character is a double byte character or not. 00794 // 00795 // cch = ped->chLines[line] + min( ECNextIch(ped, pLineStart, cch), cLineLength); 00796 // 00797 // we need to adjust the position. LiZ -- 5/5/93 00798 if (ped->fAnsi && ped->fDBCS) { 00799 ICH cch2 = min(cch+1,cLineLength); 00800 if (ECAdjustIch(ped, pLineStart, cch2) != cch2) { 00801 /* Displayed character on the right edge is DBCS */ 00802 cch = min(cch+2,cLineLength); 00803 } else { 00804 cch = cch2; 00805 } 00806 cch += ped->chLines[line]; 00807 } else { 00808 cch = ped->chLines[line] + min(cch + 1, cLineLength); 00809 } 00810 } else if (width <= ped->rcFmt.left + ped->aveCharWidth / 2) { 00811 00812 /* 00813 * Return first char in line or one minus first char visible. Note that 00814 * ped->xOffset is 0 for right and centered text so we will just return 00815 * the first char in the string for them. (Allow a avecharwidth/2 00816 * positioning border so that the user can be a little off... 00817 */ 00818 cch = ECCchInWidth(ped, hdc, pLineStart, cLineLength, 00819 ped->xOffset, TRUE); 00820 if (cch) 00821 cch--; 00822 00823 cch = ECAdjustIch( ped, pLineStart, cch ); 00824 cch += ped->chLines[line]; 00825 } else { 00826 00827 if (cLineLength == 0) { 00828 cch = ped->chLines[line]; 00829 goto edUnlock; 00830 } 00831 00832 iCurWidth = width + ped->xOffset - ped->rcFmt.left; 00833 /* 00834 * If the user clicked past the end of the text, return the last character 00835 */ 00836 lastHighWidth = MLGetLineWidth(hdc, pLineStart, cLineLength, ped); 00837 if (lastHighWidth <= iCurWidth) { 00838 cLineLengthNew = cLineLength; 00839 goto edAdjust; 00840 } 00841 /* 00842 * Now the mouse is somewhere on the visible portion of the text 00843 * remember cch contains the length of the line. 00844 */ 00845 cLineLengthLow = 0; 00846 cLineLengthHigh = cLineLength + 1; 00847 lastLowWidth = 0; 00848 00849 while (cLineLengthLow < cLineLengthHigh - 1) { 00850 00851 cLineLengthNew = (cLineLengthHigh + cLineLengthLow) / 2; 00852 00853 if (ped->fAnsi && ped->fDBCS) { 00854 /* 00855 * MLGetLineWidth returns meaningless value for truncated DBCS. 00856 */ 00857 cLineLengthTemp = ECAdjustIch(ped, pLineStart, cLineLengthNew); 00858 textWidth = MLGetLineWidth(hdc, pLineStart, cLineLengthTemp, ped); 00859 00860 } else { 00861 textWidth = MLGetLineWidth(hdc, pLineStart, cLineLengthNew, ped); 00862 } 00863 00864 if (textWidth > iCurWidth) { 00865 cLineLengthHigh = cLineLengthNew; 00866 lastHighWidth = textWidth; 00867 } else { 00868 cLineLengthLow = cLineLengthNew; 00869 lastLowWidth = textWidth; 00870 } 00871 } 00872 00873 /* 00874 * When the while ends, you can't know the exact desired position. 00875 * Try to see if the mouse pointer was on the farest half 00876 * of the char we got and if so, adjust cch. 00877 */ 00878 if (cLineLengthLow == cLineLengthNew) { 00879 /* 00880 * Need to compare with lastHighWidth 00881 */ 00882 if ((lastHighWidth - iCurWidth) < (iCurWidth - textWidth)) { 00883 cLineLengthNew++; 00884 } 00885 } else { 00886 /* 00887 * Need to compare with lastLowHigh 00888 */ 00889 if ((iCurWidth - lastLowWidth) < (textWidth - iCurWidth)) { 00890 cLineLengthNew--; 00891 } 00892 } 00893 edAdjust: 00894 cLineLength = ECAdjustIch( ped, pLineStart, cLineLengthNew ); 00895 00896 cch = ped->chLines[line] + cLineLength; 00897 } 00898 } 00899 edUnlock: 00900 ECUnlock(ped); 00901 00902 if (pline) { 00903 *pline = line; 00904 } 00905 return cch; 00906 } 00907 00908 /***************************************************************************\ 00909 * MLChangeSelection AorW 00910 * 00911 * Changes the current selection to have the specified starting and 00912 * ending values. Properly highlights the new selection and unhighlights 00913 * anything deselected. If NewMinSel and NewMaxSel are out of order, we swap 00914 * them. Doesn't update the caret position. 00915 * 00916 * History: 00917 \***************************************************************************/ 00918 00919 void MLChangeSelection( 00920 PED ped, 00921 HDC hdc, 00922 ICH ichNewMinSel, 00923 ICH ichNewMaxSel) 00924 { 00925 00926 ICH temp; 00927 ICH ichOldMinSel, ichOldMaxSel; 00928 00929 if (ichNewMinSel > ichNewMaxSel) { 00930 temp = ichNewMinSel; 00931 ichNewMinSel = ichNewMaxSel; 00932 ichNewMaxSel = temp; 00933 } 00934 ichNewMinSel = min(ichNewMinSel, ped->cch); 00935 ichNewMaxSel = min(ichNewMaxSel, ped->cch); 00936 00937 /* 00938 * Save the current selection 00939 */ 00940 ichOldMinSel = ped->ichMinSel; 00941 ichOldMaxSel = ped->ichMaxSel; 00942 00943 /* 00944 * Set new selection 00945 */ 00946 ped->ichMinSel = ichNewMinSel; 00947 ped->ichMaxSel = ichNewMaxSel; 00948 00949 /* 00950 * This finds the XOR of the old and new selection regions and redraws it. 00951 * There is nothing to repaint if we aren't visible or our selection 00952 * is hidden. 00953 */ 00954 if (_IsWindowVisible(ped->pwnd) && (ped->fFocus || ped->fNoHideSel)) { 00955 00956 BLOCK Blk[2]; 00957 int i; 00958 00959 if (ped->fFocus) { 00960 NtUserHideCaret(ped->hwnd); 00961 } 00962 00963 Blk[0].StPos = ichOldMinSel; 00964 Blk[0].EndPos = ichOldMaxSel; 00965 Blk[1].StPos = ped->ichMinSel; 00966 Blk[1].EndPos = ped->ichMaxSel; 00967 00968 if (ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel, (LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1])) { 00969 00970 /* 00971 * Paint both Blk[0] and Blk[1], if they exist 00972 */ 00973 for (i = 0; i < 2; i++) { 00974 if (Blk[i].StPos != 0xFFFFFFFF) 00975 MLDrawText(ped, hdc, Blk[i].StPos, Blk[i].EndPos, TRUE); 00976 } 00977 } 00978 00979 /* 00980 * Update caret. 00981 */ 00982 MLSetCaretPosition(ped, hdc); 00983 00984 if (ped->fFocus) { 00985 NtUserShowCaret(ped->hwnd); 00986 } 00987 00988 } 00989 } 00990 00991 00992 /**************************************************************************\ 00993 * MLUpdateiCaretLine AorW 00994 * 00995 * This updates the ped->iCaretLine field from the ped->ichCaret; 00996 * Also, when the caret gets to the beginning of next line, pop it up to 00997 * the end of current line when inserting text; 00998 * 00999 * History 01000 * 4-18-91 Mikehar 31Merge 01001 \**************************************************************************/ 01002 01003 void MLUpdateiCaretLine(PED ped) 01004 { 01005 PSTR pText; 01006 01007 ped->iCaretLine = MLIchToLine(ped, ped->ichCaret); 01008 01009 /* 01010 * If caret gets to beginning of next line, pop it up to end of current line 01011 * when inserting text. 01012 */ 01013 pText = ECLock(ped) + 01014 (ped->ichCaret - 1) * ped->cbChar; 01015 if (ped->iCaretLine && ped->chLines[ped->iCaretLine] == ped->ichCaret && 01016 (!AWCOMPARECHAR(ped, pText - ped->cbChar, 0x0D) || 01017 !AWCOMPARECHAR(ped, pText, 0x0A))) 01018 ped->iCaretLine--; 01019 ECUnlock(ped); 01020 } 01021 01022 /***************************************************************************\ 01023 * MLInsertText AorW 01024 * 01025 * Adds up to cchInsert characters from lpText to the ped starting at 01026 * ichCaret. If the ped only allows a maximum number of characters, then we 01027 * will only add that many characters to the ped. The number of characters 01028 * actually added is return ed (could be 0). If we can't allocate the required 01029 * space, we notify the parent with EN_ERRSPACE and no characters are added. 01030 * We will rebuild the lines array as needed. fUserTyping is true if the 01031 * input was the result of the user typing at the keyboard. This is so we can 01032 * do some stuff faster since we will be getting only one or two chars of 01033 * input. 01034 * 01035 * History: 01036 * Created ??? 01037 * 4-18-91 Mikehar Win31 Merge 01038 \***************************************************************************/ 01039 01040 ICH MLInsertText( 01041 PED ped, 01042 LPSTR lpText, 01043 ICH cchInsert, 01044 BOOL fUserTyping) 01045 { 01046 HDC hdc; 01047 ICH validCch = cchInsert; 01048 ICH oldCaret = ped->ichCaret; 01049 int oldCaretLine = ped->iCaretLine; 01050 BOOL fCRLF = FALSE; 01051 LONG ll, hl; 01052 POINT xyPosInitial; 01053 POINT xyPosFinal; 01054 HWND hwndSave = ped->hwnd; 01055 UNDO undo; 01056 ICH validCchTemp; 01057 01058 xyPosInitial.x=0; 01059 xyPosInitial.y=0; 01060 xyPosFinal.x=0; 01061 xyPosFinal.y=0; 01062 01063 if (validCch == 0) 01064 return 0; 01065 01066 if (ped->cchTextMax <= ped->cch) { 01067 01068 /* 01069 * When the max chars is reached already, notify parent 01070 * Fix for Bug #4183 -- 02/06/91 -- SANKAR -- 01071 */ 01072 ECNotifyParent(ped,EN_MAXTEXT); 01073 return 0; 01074 } 01075 01076 /* 01077 * Limit the amount of text we add 01078 */ 01079 validCch = min(validCch, ped->cchTextMax - ped->cch); 01080 01081 /* 01082 * Make sure we don't split a CRLF in half 01083 */ 01084 if (validCch) { 01085 if (ped->fAnsi) { 01086 if (*(WORD UNALIGNED *)(lpText + validCch - 1) == 0x0A0D) 01087 validCch--; 01088 } else { 01089 if (*(DWORD UNALIGNED *)(lpText + (validCch - 1) * ped->cbChar) == 0x000A000D) 01090 validCch--; 01091 } 01092 } 01093 if (!validCch) { 01094 /* 01095 * When the max chars is reached already, notify parent 01096 * Fix for Bug #4183 -- 02/06/91 -- SANKAR -- 01097 */ 01098 ECNotifyParent(ped,EN_MAXTEXT); 01099 return 0; 01100 } 01101 01102 if (validCch == 2) { 01103 if (ped->fAnsi) { 01104 if (*(WORD UNALIGNED *)lpText == 0x0A0D) 01105 fCRLF = TRUE; 01106 } else { 01107 if (*(DWORD UNALIGNED *)lpText == 0x000A000D) 01108 fCRLF = TRUE; 01109 } 01110 } 01111 01112 // 01113 // Save current undo state always, but clear it out only if !AutoVScroll 01114 // 01115 ECSaveUndo(Pundo(ped), (PUNDO)&undo, !ped->fAutoVScroll); 01116 01117 hdc = ECGetEditDC(ped, FALSE); 01118 /* 01119 * We only need the y position. Since with an LPK loaded 01120 * calculating the x position is an intensive job, just 01121 * call MLIchToYPos. 01122 */ 01123 if (ped->cch) 01124 if (ped->pLpkEditCallout) 01125 xyPosInitial.y = MLIchToYPos(ped, ped->cch-1, FALSE); 01126 else 01127 MLIchToXYPos(ped, hdc, ped->cch - 1, FALSE, &xyPosInitial); 01128 01129 /* 01130 * Insert the text 01131 */ 01132 validCchTemp = validCch; // may not be needed, but just for precautions.. 01133 if (!ECInsertText(ped, lpText, &validCchTemp)) { 01134 01135 // Restore previous undo buffer if it was cleared 01136 if (!ped->fAutoVScroll) 01137 ECSaveUndo((PUNDO)&undo, Pundo(ped), FALSE); 01138 01139 ECReleaseEditDC(ped, hdc, FALSE); 01140 ECNotifyParent(ped, EN_ERRSPACE); 01141 return (0); 01142 } 01143 01144 #if DBG 01145 if (validCch != validCchTemp) { 01146 /* 01147 * All characters in lpText has not been inserted to ped. 01148 * This could happen when cch is close to cchMax. 01149 * Better revisit this after NT5 ships. 01150 */ 01151 RIPMSG2(RIP_WARNING, "MLInsertText: validCch is changed (%x -> %x) in ECInsertText.", 01152 validCch, validCchTemp); 01153 } 01154 #endif 01155 01156 /* 01157 * Note that ped->ichCaret is updated by ECInsertText 01158 */ 01159 MLBuildchLines(ped, (ICH)oldCaretLine, (int)validCch, fCRLF?(BOOL)FALSE:fUserTyping, &ll, &hl); 01160 01161 if (ped->cch) 01162 /* 01163 * We only need the y position. Since with an LPK loaded 01164 * calculating the x position is an intensive job, just 01165 * call MLIchToYPos. 01166 */ 01167 if (ped->pLpkEditCallout) 01168 xyPosFinal.y = MLIchToYPos(ped, ped->cch-1, FALSE); 01169 else 01170 MLIchToXYPos(ped, hdc, ped->cch - 1, FALSE,&xyPosFinal); 01171 01172 if (xyPosFinal.y < xyPosInitial.y && ((ICH)ped->ichScreenStart) + ped->ichLinesOnScreen >= ped->cLines - 1) { 01173 RECT rc; 01174 01175 CopyRect((LPRECT)&rc, (LPRECT)&ped->rcFmt); 01176 rc.top = xyPosFinal.y + ped->lineHeight; 01177 if (ped->pLpkEditCallout) { 01178 int xFarOffset = ped->xOffset + ped->rcFmt.right - ped->rcFmt.left; 01179 // Include left or right margins in display unless clipped 01180 // by horizontal scrolling. 01181 if (ped->wLeftMargin) { 01182 if (!( ped->format == ES_LEFT // Only ES_LEFT (Nearside alignment) can get clipped 01183 && ( (!ped->fRtoLReading && ped->xOffset > 0) // LTR and first char not fully in view 01184 || ( ped->fRtoLReading && xFarOffset < ped->maxPixelWidth)))) { //RTL and last char not fully in view 01185 rc.left -= ped->wLeftMargin; 01186 } 01187 } 01188 01189 // Process right margin 01190 if (ped->wRightMargin) { 01191 if (!( ped->format == ES_LEFT // Only ES_LEFT (Nearside alignment) can get clipped 01192 && ( ( ped->fRtoLReading && ped->xOffset > 0) // RTL and first char not fully in view 01193 || (!ped->fRtoLReading && xFarOffset < ped->maxPixelWidth)))) { // LTR and last char not fully in view 01194 rc.right += ped->wRightMargin; 01195 } 01196 } 01197 } 01198 NtUserInvalidateRect(ped->hwnd, (LPRECT)&rc, TRUE); 01199 } 01200 01201 if (!ped->fAutoVScroll) { 01202 if (ped->ichLinesOnScreen < ped->cLines) { 01203 MLUndo(ped); 01204 ECEmptyUndo(Pundo(ped)); 01205 01206 ECSaveUndo(&undo, Pundo(ped), FALSE); 01207 01208 NtUserMessageBeep(0); 01209 ECReleaseEditDC(ped, hdc, FALSE); 01210 01211 /* 01212 * When the max lines is reached already, notify parent 01213 * Fix for Bug #7586 -- 10/14/91 -- SANKAR -- 01214 */ 01215 ECNotifyParent(ped,EN_MAXTEXT); 01216 return (0); 01217 } else { 01218 ECEmptyUndo(&undo); 01219 } 01220 } 01221 01222 if (fUserTyping && ped->fWrap) { 01223 // 01224 // To avoid oldCaret points intermediate of DBCS character, 01225 // adjust oldCaret position if necessary. 01226 // 01227 // !!!CR If MLBuildchLines() returns reasonable value ( and I think 01228 // it does), we don't probably need this. Check this out later. 01229 // 01230 if (ped->fDBCS && ped->fAnsi) { 01231 oldCaret = ECAdjustIch(ped, 01232 ECLock(ped), 01233 min((ICH)LOWORD(ll),oldCaret)); 01234 /* ECUnlock(ped); */ 01235 } else { // same as original code 01236 oldCaret = min((ICH)LOWORD(ll), oldCaret); 01237 } 01238 } 01239 01240 // Update ped->iCaretLine properly. 01241 MLUpdateiCaretLine(ped); 01242 01243 ECNotifyParent(ped, EN_UPDATE); 01244 01245 /* 01246 * Make sure window still exists. 01247 */ 01248 if (!IsWindow(hwndSave)) 01249 return 0; 01250 01251 if (_IsWindowVisible(ped->pwnd)) { 01252 01253 // 01254 // If the current font has negative A widths, we may have to start 01255 // drawing a few characters before the oldCaret position. 01256 // 01257 if (ped->wMaxNegAcharPos) { 01258 int iLine = MLIchToLine(ped, oldCaret); 01259 oldCaret = max( ((int)(oldCaret - ped->wMaxNegAcharPos)), 01260 ((int)(ped->chLines[iLine]))); 01261 } 01262 01263 // Redraw to end of screen/text if CRLF or large insert 01264 if (fCRLF || !fUserTyping) { 01265 01266 /* 01267 * Redraw to end of screen/text if crlf or large insert. 01268 */ 01269 MLDrawText(ped, hdc, (fUserTyping ? oldCaret : 0), ped->cch, FALSE); 01270 } else 01271 MLDrawText(ped, hdc, oldCaret, max(ped->ichCaret, (ICH)hl), FALSE); 01272 } 01273 01274 ECReleaseEditDC(ped, hdc, FALSE); 01275 01276 /* 01277 * Make sure we can see the cursor 01278 */ 01279 MLEnsureCaretVisible(ped); 01280 01281 ped->fDirty = TRUE; 01282 01283 ECNotifyParent(ped, EN_CHANGE); 01284 01285 if (validCch < cchInsert) 01286 ECNotifyParent(ped, EN_MAXTEXT); 01287 01288 if (validCch && FWINABLE()) { 01289 NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER); 01290 } 01291 01292 /* 01293 * Make sure the window still exists. 01294 */ 01295 if (!IsWindow(hwndSave)) 01296 return 0; 01297 else 01298 return validCch; 01299 } 01300 01301 /***************************************************************************\ 01302 * 01303 * MLReplaceSel() - 01304 * 01305 * Replaces currently selected text with the passed in text, WITH UNDO 01306 * CAPABILITIES. 01307 * 01308 \***************************************************************************/ 01309 void MLReplaceSel(PED ped, LPSTR lpText) 01310 { 01311 ICH cchText; 01312 01313 // 01314 // Delete text, which will put it into the clean undo buffer. 01315 // 01316 ECEmptyUndo(Pundo(ped)); 01317 MLDeleteText(ped); 01318 01319 // 01320 // B#3356 01321 // Some apps do "clear" by selecting all of the text, then replacing 01322 // it with "", in which case MLInsertText() will return 0. But that 01323 // doesn't mean failure... 01324 // 01325 if ( ped->fAnsi ) 01326 cchText = strlen(lpText); 01327 else 01328 cchText = wcslen((LPWSTR)lpText); 01329 01330 if (cchText ) { 01331 BOOL fFailed; 01332 UNDO undo; 01333 HWND hwndSave; 01334 01335 // 01336 // B#1385,1427 01337 // Save undo buffer, but DO NOT CLEAR IT. We want to restore it 01338 // if insertion fails due to OOM. 01339 // 01340 ECSaveUndo(Pundo(ped), (PUNDO)&undo, FALSE); 01341 01342 hwndSave = ped->hwnd; 01343 fFailed = (BOOL) !MLInsertText(ped, lpText, cchText, FALSE); 01344 if (!IsWindow(hwndSave)) 01345 return; 01346 01347 if (fFailed) { 01348 // 01349 // UNDO the previous edit 01350 // 01351 ECSaveUndo((PUNDO)&undo, Pundo(ped), FALSE); 01352 MLUndo(ped); 01353 } 01354 } 01355 } 01356 01357 01358 /***************************************************************************\ 01359 * MLDeleteText AorW 01360 * 01361 * Deletes the characters between ichMin and ichMax. Returns the 01362 * number of characters we deleted. 01363 * 01364 * History: 01365 \***************************************************************************/ 01366 01367 ICH MLDeleteText( 01368 PED ped) 01369 { 01370 ICH minSel = ped->ichMinSel; 01371 ICH maxSel = ped->ichMaxSel; 01372 ICH cchDelete; 01373 HDC hdc; 01374 int minSelLine; 01375 int maxSelLine; 01376 POINT xyPos; 01377 RECT rc; 01378 BOOL fFastDelete = FALSE; 01379 LONG hl; 01380 INT cchcount = 0; 01381 01382 /* 01383 * Get what line the min selection is on so that we can start rebuilding the 01384 * text from there if we delete anything. 01385 */ 01386 minSelLine = MLIchToLine(ped, minSel); 01387 maxSelLine = MLIchToLine(ped, maxSel); 01388 // 01389 // Calculate fFastDelete and cchcount 01390 // 01391 if (ped->fAnsi && ped->fDBCS) { 01392 if ((ped->fAutoVScroll) && 01393 (minSelLine == maxSelLine) && 01394 (ped->chLines[minSelLine] != minSel) && 01395 (ECNextIch(ped,NULL,minSel) == maxSel)) { 01396 01397 fFastDelete = TRUE; 01398 cchcount = ((maxSel - minSel) == 1) ? 0 : -1; 01399 } 01400 } else if (((maxSel - minSel) == 1) && (minSelLine == maxSelLine) && (ped->chLines[minSelLine] != minSel)) { 01401 if (!ped->fAutoVScroll) 01402 fFastDelete = FALSE; 01403 else 01404 fFastDelete = TRUE; 01405 } 01406 if (!(cchDelete = ECDeleteText(ped))) 01407 return (0); 01408 01409 /* 01410 * Start building lines at minsel line since caretline may be at the max sel 01411 * point. 01412 */ 01413 if (fFastDelete) { 01414 // 01415 // cchcount is (-1) if it's a double byte character 01416 // 01417 MLShiftchLines(ped, minSelLine + 1, -2 + cchcount); 01418 MLBuildchLines(ped, minSelLine, 1, TRUE, NULL, &hl); 01419 } else { 01420 MLBuildchLines(ped, max(minSelLine-1,0), -(int)cchDelete, FALSE, NULL, NULL); 01421 } 01422 01423 MLUpdateiCaretLine(ped); 01424 01425 ECNotifyParent(ped, EN_UPDATE); 01426 01427 if (_IsWindowVisible(ped->pwnd)) { 01428 01429 /* 01430 * Now update the screen to reflect the deletion 01431 */ 01432 hdc = ECGetEditDC(ped, FALSE); 01433 01434 /* 01435 * Otherwise just redraw starting at the line we just entered 01436 */ 01437 minSelLine = max(minSelLine-1,0); 01438 MLDrawText(ped, hdc, ped->chLines[minSelLine], 01439 fFastDelete ? hl : ped->cch, FALSE); 01440 01441 CopyRect(&rc, &ped->rcFmt); 01442 rc.left -= ped->wLeftMargin; 01443 rc.right += ped->wRightMargin; 01444 01445 if (ped->cch) { 01446 01447 /* 01448 * Clear from end of text to end of window. 01449 * 01450 * We only need the y position. Since with an LPK loaded 01451 * calculating the x position is an intensive job, just 01452 * call MLIchToYPos. 01453 */ 01454 if (ped->pLpkEditCallout) 01455 xyPos.y = MLIchToYPos(ped, ped->cch, FALSE); 01456 else 01457 MLIchToXYPos(ped, hdc, ped->cch, FALSE, &xyPos); 01458 rc.top = xyPos.y + ped->lineHeight; 01459 } 01460 01461 NtUserInvalidateRect(ped->hwnd, &rc, TRUE); 01462 ECReleaseEditDC(ped, hdc, FALSE); 01463 01464 MLEnsureCaretVisible(ped); 01465 } 01466 01467 ped->fDirty = TRUE; 01468 01469 ECNotifyParent(ped, EN_CHANGE); 01470 01471 if (cchDelete && FWINABLE()) 01472 NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER); 01473 01474 return cchDelete; 01475 } 01476 01477 /***************************************************************************\ 01478 * MLInsertchLine AorW 01479 * 01480 * Inserts the line iline and sets its starting character index to be 01481 * ich. All the other line indices are moved up. Returns TRUE if successful 01482 * else FALSE and notifies the parent that there was no memory. 01483 * 01484 * History: 01485 \***************************************************************************/ 01486 01487 BOOL MLInsertchLine( 01488 PED ped, 01489 ICH iLine, 01490 ICH ich, 01491 BOOL fUserTyping) 01492 { 01493 DWORD dwSize; 01494 01495 if (fUserTyping && iLine < ped->cLines) { 01496 ped->chLines[iLine] = ich; 01497 return (TRUE); 01498 } 01499 01500 dwSize = (ped->cLines + 2) * sizeof(int); 01501 01502 if (dwSize > UserLocalSize(ped->chLines)) { 01503 LPICH hResult; 01504 /* 01505 * Grow the line index buffer 01506 */ 01507 dwSize += LINEBUMP * sizeof(int); 01508 hResult = (LPICH)UserLocalReAlloc(ped->chLines, dwSize, 0); 01509 01510 if (!hResult) { 01511 ECNotifyParent(ped, EN_ERRSPACE); 01512 return FALSE; 01513 } 01514 ped->chLines = hResult; 01515 } 01516 01517 /* 01518 * Move indices starting at iLine up 01519 */ 01520 if (ped->cLines != iLine) 01521 RtlMoveMemory(&ped->chLines[iLine + 1], &ped->chLines[iLine], 01522 (ped->cLines - iLine) * sizeof(int)); 01523 ped->cLines++; 01524 01525 ped->chLines[iLine] = ich; 01526 return TRUE; 01527 } 01528 01529 /***************************************************************************\ 01530 * MLShiftchLines AorW 01531 * 01532 * Move the starting index of all lines iLine or greater by delta 01533 * bytes. 01534 * 01535 * History: 01536 \***************************************************************************/ 01537 01538 void MLShiftchLines( 01539 PED ped, 01540 ICH iLine, 01541 int delta) 01542 { 01543 if (iLine >= ped->cLines) 01544 return; 01545 01546 /* 01547 * Just add delta to the starting point of each line after iLine 01548 */ 01549 for (; iLine < ped->cLines; iLine++) 01550 ped->chLines[iLine] += delta; 01551 } 01552 01553 /***************************************************************************\ 01554 * MLBuildchLines AorW 01555 * 01556 * Rebuilds the start of line array (ped->chLines) starting at line 01557 * number ichLine. 01558 * 01559 * History: 01560 \***************************************************************************/ 01561 01562 void MLBuildchLines( 01563 PED ped, 01564 ICH iLine, 01565 int cchDelta, // Number of chars added or deleted 01566 BOOL fUserTyping, 01567 PLONG pll, 01568 PLONG phl) 01569 { 01570 PSTR ptext; /* Starting address of the text */ 01571 01572 /* 01573 * We keep these ICH's so that we can Unlock ped->hText when we have to grow 01574 * the chlines array. With large text handles, it becomes a problem if we 01575 * have a locked block in the way. 01576 */ 01577 ICH ichLineStart; 01578 ICH ichLineEnd; 01579 ICH ichLineEndBeforeCRLF; 01580 ICH ichCRLF; 01581 01582 ICH cch; 01583 HDC hdc; 01584 01585 BOOL fLineBroken = FALSE; /* Initially, no new line breaks are made */ 01586 ICH minCchBreak; 01587 ICH maxCchBreak; 01588 BOOL fOnDelimiter; 01589 01590 if (!ped->cch) { 01591 ped->maxPixelWidth = 0; 01592 ped->xOffset = 0; 01593 ped->ichScreenStart = 0; 01594 ped->cLines = 1; 01595 01596 if (pll) 01597 *pll = 0; 01598 if (phl) 01599 *phl = 0; 01600 01601 goto UpdateScroll; 01602 } 01603 01604 if (fUserTyping && cchDelta) 01605 MLShiftchLines(ped, iLine + 1, cchDelta); 01606 01607 hdc = ECGetEditDC(ped, TRUE); 01608 01609 if (!iLine && !cchDelta && !fUserTyping) { 01610 01611 /* 01612 * Reset maxpixelwidth only if we will be running through the whole 01613 * text. Better too long than too short. 01614 */ 01615 ped->maxPixelWidth = 0; 01616 01617 /* 01618 * Reset number of lines in text since we will be running through all 01619 * the text anyway... 01620 */ 01621 ped->cLines = 1; 01622 } 01623 01624 /* 01625 * Set min and max line built to be the starting line 01626 */ 01627 minCchBreak = maxCchBreak = (cchDelta ? ped->chLines[iLine] : 0); 01628 01629 ptext = ECLock(ped); 01630 01631 ichCRLF = ichLineStart = ped->chLines[iLine]; 01632 01633 while (ichLineStart < ped->cch) { 01634 if (ichLineStart >= ichCRLF) { 01635 ichCRLF = ichLineStart; 01636 01637 /* 01638 * Move ichCRLF ahead to either the first CR or to the end of text. 01639 */ 01640 if (ped->fAnsi) { 01641 while (ichCRLF < ped->cch) { 01642 if (*(ptext + ichCRLF) == 0x0D) { 01643 if (*(ptext + ichCRLF + 1) == 0x0A || 01644 *(WORD UNALIGNED *)(ptext + ichCRLF + 1) == 0x0A0D) 01645 break; 01646 } 01647 ichCRLF++; 01648 } 01649 } else { 01650 LPWSTR pwtext = (LPWSTR)ptext; 01651 01652 while (ichCRLF < ped->cch) { 01653 if (*(pwtext + ichCRLF) == 0x0D) { 01654 if (*(pwtext + ichCRLF + 1) == 0x0A || 01655 *(DWORD UNALIGNED *)(pwtext + ichCRLF + 1) == 0x000A000D) 01656 break; 01657 } 01658 ichCRLF++; 01659 } 01660 } 01661 } 01662 01663 01664 if (!ped->fWrap) { 01665 01666 UINT LineWidth; 01667 /* 01668 * If we are not word wrapping, line breaks are signified by CRLF. 01669 */ 01670 01671 // 01672 // If we cut off the line at MAXLINELENGTH, we should 01673 // adjust ichLineEnd. 01674 // 01675 if ((ichCRLF - ichLineStart) <= MAXLINELENGTH) { 01676 ichLineEnd = ichCRLF; 01677 } else { 01678 ichLineEnd = ichLineStart + MAXLINELENGTH; 01679 if (ped->fAnsi && ped->fDBCS) { 01680 ichLineEnd = ECAdjustIch( ped, (PSTR)ptext, ichLineEnd); 01681 } 01682 } 01683 01684 /* 01685 * We will keep track of what the longest line is for the horizontal 01686 * scroll bar thumb positioning. 01687 */ 01688 if (ped->pLpkEditCallout) { 01689 LineWidth = ped->pLpkEditCallout->EditGetLineWidth( 01690 ped, hdc, ptext + ichLineStart*ped->cbChar, 01691 ichLineEnd - ichLineStart); 01692 } else { 01693 LineWidth = MLGetLineWidth(hdc, ptext + ichLineStart * ped->cbChar, 01694 ichLineEnd - ichLineStart, 01695 ped); 01696 } 01697 ped->maxPixelWidth = max(ped->maxPixelWidth,(int)LineWidth); 01698 01699 } else { 01700 01701 /* 01702 * Check if the width of the edit control is non-zero; 01703 * a part of the fix for Bug #7402 -- SANKAR -- 01/21/91 -- 01704 */ 01705 if(ped->rcFmt.right > ped->rcFmt.left) { 01706 01707 /* 01708 * Find the end of the line based solely on text extents 01709 */ 01710 if (ped->pLpkEditCallout) { 01711 ichLineEnd = ichLineStart + 01712 ped->pLpkEditCallout->EditCchInWidth( 01713 ped, hdc, ptext + ped->cbChar*ichLineStart, 01714 ichCRLF - ichLineStart, 01715 ped->rcFmt.right - ped->rcFmt.left); 01716 } else { 01717 if (ped->fAnsi) { 01718 ichLineEnd = ichLineStart + 01719 ECCchInWidth(ped, hdc, 01720 ptext + ichLineStart, 01721 ichCRLF - ichLineStart, 01722 ped->rcFmt.right - ped->rcFmt.left, 01723 TRUE); 01724 } else { 01725 ichLineEnd = ichLineStart + 01726 ECCchInWidth(ped, hdc, 01727 (LPSTR)((LPWSTR)ptext + ichLineStart), 01728 ichCRLF - ichLineStart, 01729 ped->rcFmt.right - ped->rcFmt.left, 01730 TRUE); 01731 } 01732 } 01733 } else { 01734 ichLineEnd = ichLineStart; 01735 } 01736 01737 if (ichLineEnd == ichLineStart && ichCRLF - ichLineStart) { 01738 01739 /* 01740 * Maintain a minimum of one char per line 01741 */ 01742 // 01743 // Since it might be a double byte char, so calling ECNextIch. 01744 // 01745 ichLineEnd = ECNextIch(ped, NULL, ichLineEnd); 01746 } 01747 01748 /* 01749 * Now starting from ichLineEnd, if we are not at a hard line break, 01750 * then if we are not at a space AND the char before us is 01751 * not a space,(OR if we are at a CR) we will look word left for the 01752 * start of the word to break at. 01753 * This change was done for TWO reasons: 01754 * 1. If we are on a delimiter, no need to look word left to break at. 01755 * 2. If the previous char is a delimter, we can break at current char. 01756 * Change done by -- SANKAR --01/31/91-- 01757 */ 01758 if (ichLineEnd != ichCRLF) { 01759 if(ped->lpfnNextWord) { 01760 fOnDelimiter = (CALLWORDBREAKPROC(*ped->lpfnNextWord, ptext, 01761 ichLineEnd, ped->cch, WB_ISDELIMITER) || 01762 CALLWORDBREAKPROC(*ped->lpfnNextWord, ptext, ichLineEnd - 1, 01763 ped->cch, WB_ISDELIMITER)); 01764 // 01765 // This change was done for FOUR reasons: 01766 // 01767 // 1. If we are on a delimiter, no need to look word left to break at. 01768 // 2. If we are on a double byte character, we can break at current char. 01769 // 3. If the previous char is a delimter, we can break at current char. 01770 // 4. If the previous char is a double byte character, we can break at current char. 01771 // 01772 } else if (ped->fAnsi) { 01773 fOnDelimiter = (ISDELIMETERA(*(ptext + ichLineEnd)) || 01774 ECIsDBCSLeadByte(ped, *(ptext + ichLineEnd))); 01775 if (!fOnDelimiter) { 01776 PSTR pPrev = ECAnsiPrev(ped,ptext,ptext+ichLineEnd); 01777 01778 fOnDelimiter = ISDELIMETERA(*pPrev) || 01779 ECIsDBCSLeadByte(ped,*pPrev); 01780 } 01781 } else { // Unicode 01782 fOnDelimiter = (ISDELIMETERW(*((LPWSTR)ptext + ichLineEnd)) || 01783 UserIsFullWidth(CP_ACP,*((LPWSTR)ptext + ichLineEnd)) || 01784 ISDELIMETERW(*((LPWSTR)ptext + ichLineEnd - 1)) || 01785 UserIsFullWidth(CP_ACP,*((LPWSTR)ptext + ichLineEnd - 1))); 01786 } 01787 if (!fOnDelimiter || 01788 (ped->fAnsi && *(ptext + ichLineEnd) == 0x0D) || 01789 (!ped->fAnsi && *((LPWSTR)ptext + ichLineEnd) == 0x0D)) { 01790 01791 if (ped->lpfnNextWord != NULL) { 01792 cch = CALLWORDBREAKPROC(*ped->lpfnNextWord, (LPSTR)ptext, ichLineEnd, 01793 ped->cch, WB_LEFT); 01794 } else { 01795 ped->fCalcLines = TRUE; 01796 ECWord(ped, ichLineEnd, TRUE, &cch, NULL); 01797 ped->fCalcLines = FALSE; 01798 } 01799 if (cch > ichLineStart) { 01800 ichLineEnd = cch; 01801 } 01802 01803 /* 01804 * Now, if the above test fails, it means the word left goes 01805 * back before the start of the line ie. a word is longer 01806 * than a line on the screen. So, we just fit as much of 01807 * the word on the line as possible. Thus, we use the 01808 * pLineEnd we calculated solely on width at the beginning 01809 * of this else block... 01810 */ 01811 } 01812 } 01813 } 01814 #if 0 01815 if (!ISDELIMETERAW((*(ptext + (ichLineEnd - 1)*ped->cbChar))) && ISDELIMETERAW((*(ptext + ichLineEnd*ped->cbChar)))) #ERROR 01816 01817 if ((*(ptext + ichLineEnd - 1) != ' ' && 01818 *(ptext + ichLineEnd - 1) != VK_TAB) && 01819 (*(ptext + ichLineEnd) == ' ' || 01820 *(ptext + ichLineEnd) == VK_TAB)) 01821 #endif 01822 if (AWCOMPARECHAR(ped,ptext + ichLineEnd * ped->cbChar, ' ') || 01823 AWCOMPARECHAR(ped,ptext + ichLineEnd * ped->cbChar, VK_TAB)) { 01824 /* 01825 * Swallow the space at the end of a line. 01826 */ 01827 if (ichLineEnd < ped->cch) { 01828 ichLineEnd++; 01829 } 01830 } 01831 01832 /* 01833 * Skip over crlf or crcrlf if it exists. Thus, ichLineEnd is the first 01834 * character in the next line. 01835 */ 01836 ichLineEndBeforeCRLF = ichLineEnd; 01837 01838 if (ped->fAnsi) { 01839 if (ichLineEnd < ped->cch && *(ptext + ichLineEnd) == 0x0D) 01840 ichLineEnd += 2; 01841 01842 /* 01843 * Skip over CRCRLF 01844 */ 01845 if (ichLineEnd < ped->cch && *(ptext + ichLineEnd) == 0x0A) 01846 ichLineEnd++; 01847 UserAssert(ichLineEnd <= ped->cch); 01848 } else { 01849 if (ichLineEnd < ped->cch && *(((LPWSTR)ptext) + ichLineEnd) == 0x0D) 01850 ichLineEnd += 2; 01851 01852 /* 01853 * Skip over CRCRLF 01854 */ 01855 if (ichLineEnd < ped->cch && *(((LPWSTR)ptext) + ichLineEnd) == 0x0A) { 01856 ichLineEnd++; 01857 RIPMSG0(RIP_VERBOSE, "Skip over CRCRLF\n"); 01858 } 01859 UserAssert(ichLineEnd <= ped->cch); 01860 } 01861 01862 /* 01863 * Now, increment iLine, allocate space for the next line, and set its 01864 * starting point 01865 */ 01866 iLine++; 01867 01868 if (!fUserTyping || (iLine > ped->cLines - 1) || (ped->chLines[iLine] != ichLineEnd)) { 01869 01870 /* 01871 * The line break occured in a different place than before. 01872 */ 01873 if (!fLineBroken) { 01874 01875 /* 01876 * Since we haven't broken a line before, just set the min 01877 * break line. 01878 */ 01879 fLineBroken = TRUE; 01880 if (ichLineEndBeforeCRLF == ichLineEnd) 01881 minCchBreak = maxCchBreak = (ichLineEnd ? ichLineEnd - 1 : 0); 01882 else 01883 minCchBreak = maxCchBreak = ichLineEndBeforeCRLF; 01884 } 01885 maxCchBreak = max(maxCchBreak, ichLineEnd); 01886 01887 ECUnlock(ped); 01888 01889 /* 01890 * Now insert the new line into the array 01891 */ 01892 if (!MLInsertchLine(ped, iLine, ichLineEnd, (BOOL)(cchDelta != 0))) 01893 goto EndUp; 01894 01895 ptext = ECLock(ped); 01896 } else { 01897 maxCchBreak = ped->chLines[iLine]; 01898 01899 /* 01900 * Quick escape 01901 */ 01902 goto UnlockAndEndUp; 01903 } 01904 01905 ichLineStart = ichLineEnd; 01906 } /* end while (ichLineStart < ped->cch) */ 01907 01908 01909 if (iLine != ped->cLines) { 01910 RIPMSG1(RIP_VERBOSE, "chLines[%d] is being cleared.\n", iLine); 01911 ped->cLines = iLine; 01912 ped->chLines[ped->cLines] = 0; 01913 } 01914 01915 /* 01916 * Note that we incremented iLine towards the end of the while loop so, the 01917 * index, iLine, is actually equal to the line count 01918 */ 01919 if (ped->cch && AWCOMPARECHAR(ped, ptext + (ped->cch - 1)*ped->cbChar, 0x0A) && 01920 ped->chLines[ped->cLines - 1] < ped->cch) { 01921 01922 /* 01923 * Make sure last line has no crlf in it 01924 */ 01925 if (!fLineBroken) { 01926 01927 /* 01928 * Since we haven't broken a line before, just set the min break 01929 * line. 01930 */ 01931 fLineBroken = TRUE; 01932 minCchBreak = ped->cch - 1; 01933 } 01934 maxCchBreak = max(maxCchBreak, ichLineEnd); 01935 ECUnlock(ped); 01936 MLInsertchLine(ped, iLine, ped->cch, FALSE); 01937 MLSanityCheck(ped); 01938 } else 01939 UnlockAndEndUp: 01940 ECUnlock(ped); 01941 01942 EndUp: 01943 ECReleaseEditDC(ped, hdc, TRUE); 01944 if (pll) 01945 *pll = minCchBreak; 01946 if (phl) 01947 *phl = maxCchBreak; 01948 01949 UpdateScroll: 01950 MLScroll(ped, FALSE, ML_REFRESH, 0, TRUE); 01951 MLScroll(ped, TRUE, ML_REFRESH, 0, TRUE); 01952 01953 MLSanityCheck(ped); 01954 01955 return; 01956 } 01957 01958 /***************************************************************************\ 01959 * 01960 * MLPaint() 01961 * 01962 * Response to WM_PAINT message. 01963 * 01964 \***************************************************************************/ 01965 void MLPaint(PED ped, HDC hdc, LPRECT lprc) 01966 { 01967 HFONT hOldFont; 01968 ICH imin; 01969 ICH imax; 01970 01971 // 01972 // Do we need to draw the border ourself for old apps? 01973 // 01974 if (ped->fFlatBorder) 01975 { 01976 RECT rcT; 01977 01978 _GetClientRect(ped->pwnd, &rcT); 01979 if (TestWF(ped->pwnd, WFSIZEBOX)) 01980 { 01981 InflateRect(&rcT, SYSMET(CXBORDER) - SYSMET(CXFRAME), 01982 SYSMET(CYBORDER) - SYSMET(CYFRAME)); 01983 } 01984 DrawFrame(hdc, &rcT, 1, DF_WINDOWFRAME); 01985 } 01986 01987 ECSetEditClip(ped, hdc, (BOOL) (ped->xOffset == 0)); 01988 01989 if (ped->hFont) 01990 hOldFont = SelectObject(hdc, ped->hFont); 01991 01992 if (!lprc) { 01993 // no partial rect given -- draw all text 01994 imin = 0; 01995 imax = ped->cch; 01996 } else { 01997 // only draw pertinent text 01998 imin = (ICH) MLMouseToIch(ped, hdc, ((LPPOINT) &lprc->left), NULL) - 1; 01999 if (imin == -1) 02000 imin = 0; 02001 02002 // HACK_ALERT: 02003 // The 3 is required here because, MLMouseToIch() returns decremented 02004 // value; We must fix MLMouseToIch. 02005 imax = (ICH) MLMouseToIch(ped, hdc, ((LPPOINT) &lprc->right), NULL) + 3; 02006 if (imax > ped->cch) 02007 imax = ped->cch; 02008 } 02009 02010 MLDrawText(ped, hdc, imin, imax, FALSE); 02011 02012 if (ped->hFont) 02013 SelectObject(hdc, hOldFont); 02014 } 02015 02016 /***************************************************************************\ 02017 * MLKeyDown AorW 02018 * 02019 * Handles cursor movement and other VIRT KEY stuff. keyMods allows 02020 * us to make MLKeyDownHandler calls and specify if the modifier keys (shift 02021 * and control) are up or down. If keyMods == 0, we get the keyboard state 02022 * using GetKeyState(VK_SHIFT) etc. Otherwise, the bits in keyMods define the 02023 * state of the shift and control keys. 02024 * 02025 * History: 02026 \***************************************************************************/ 02027 02028 void MLKeyDown( 02029 PED ped, 02030 UINT virtKeyCode, 02031 int keyMods) 02032 { 02033 HDC hdc; 02034 BOOL prevLine; 02035 POINT mousePt; 02036 int defaultDlgId; 02037 int iScrollAmt; 02038 02039 /* 02040 * Variables we will use for redrawing the updated text 02041 */ 02042 02043 /* 02044 * new selection is specified by newMinSel, newMaxSel 02045 */ 02046 ICH newMaxSel = ped->ichMaxSel; 02047 ICH newMinSel = ped->ichMinSel; 02048 02049 /* 02050 * Flags for drawing the updated text 02051 */ 02052 BOOL changeSelection = FALSE; 02053 02054 /* 02055 * Comparisons we do often 02056 */ 02057 BOOL MinEqMax = (newMaxSel == newMinSel); 02058 BOOL MinEqCar = (ped->ichCaret == newMinSel); 02059 BOOL MaxEqCar = (ped->ichCaret == newMaxSel); 02060 02061 /* 02062 * State of shift and control keys. 02063 */ 02064 int scState; 02065 02066 if (ped->fMouseDown) { 02067 02068 /* 02069 * If we are in the middle of a mousedown command, don't do anything. 02070 */ 02071 return ; 02072 } 02073 02074 scState = ECGetModKeys(keyMods); 02075 02076 switch (virtKeyCode) { 02077 case VK_ESCAPE: 02078 if (ped->fInDialogBox) { 02079 02080 /* 02081 * This condition is removed because, if the dialogbox does not 02082 * have a CANCEL button and if ESC is hit when focus is on a 02083 * ML edit control the dialogbox must close whether it has cancel 02084 * button or not to be consistent with SL edit control; 02085 * DefDlgProc takes care of the disabled CANCEL button case. 02086 * Fix for Bug #4123 -- 02/07/91 -- SANKAR -- 02087 */ 02088 #if 0 02089 if (GetDlgItem(ped->hwndParent, IDCANCEL)) 02090 #endif 02091 02092 /* 02093 * User hit ESC...Send a close message (which in turn sends a 02094 * cancelID to the app in DefDialogProc... 02095 */ 02096 PostMessage(ped->hwndParent, WM_CLOSE, 0, 0L); 02097 } 02098 return ; 02099 02100 case VK_RETURN: 02101 if (ped->fInDialogBox) { 02102 02103 /* 02104 * If this multiline edit control is in a dialog box, then we want 02105 * the RETURN key to be sent to the default dialog button (if there 02106 * is one). CTRL-RETURN will insert a RETURN into the text. Note 02107 * that CTRL-RETURN automatically translates into a linefeed (0x0A) 02108 * and in the MLCharHandler, we handle this as if a return was 02109 * entered. 02110 */ 02111 if (scState != CTRLDOWN) { 02112 02113 if (TestWF(ped->pwnd, EFWANTRETURN)) { 02114 02115 /* 02116 * This edit control wants cr to be inserted so break out of 02117 * case. 02118 */ 02119 return ; 02120 } 02121 02122 defaultDlgId = (int)(DWORD)LOWORD(SendMessage(ped->hwndParent, 02123 DM_GETDEFID, 0, 0L)); 02124 if (defaultDlgId) { 02125 HWND hwnd = GetDlgItem(ped->hwndParent, defaultDlgId); 02126 if (hwnd) { 02127 SendMessage(ped->hwndParent, WM_NEXTDLGCTL, (WPARAM)hwnd, 1L); 02128 if (!ped->fFocus) 02129 PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0L); 02130 } 02131 } 02132 } 02133 02134 return ; 02135 } 02136 break; 02137 02138 case VK_TAB: 02139 02140 /* 02141 * If this multiline edit control is in a dialog box, then we want the 02142 * TAB key to take you to the next control, shift TAB to take you to the 02143 * previous control. We always want CTRL-TAB to insert a tab into the 02144 * edit control regardless of weather or not we're in a dialog box. 02145 */ 02146 if (scState == CTRLDOWN) 02147 MLChar(ped, virtKeyCode, keyMods); 02148 else if (ped->fInDialogBox) 02149 SendMessage(ped->hwndParent, WM_NEXTDLGCTL, scState == SHFTDOWN, 0L); 02150 02151 return ; 02152 02153 case VK_LEFT: 02154 // 02155 // If the caret isn't at the beginning, we can move left 02156 // 02157 if (ped->ichCaret) { 02158 // Get new caret pos. 02159 if (scState & CTRLDOWN) { 02160 // Move caret word left 02161 ECWord(ped, ped->ichCaret, TRUE, &ped->ichCaret, NULL); 02162 } else { 02163 if (ped->pLpkEditCallout) { 02164 ped->ichCaret = MLMoveSelectionRestricted(ped, ped->ichCaret, TRUE); 02165 } else { 02166 // Move caret char left 02167 ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, TRUE); 02168 } 02169 } 02170 02171 // Get new selection 02172 if (scState & SHFTDOWN) { 02173 if (MaxEqCar && !MinEqMax) { 02174 // Reduce selection 02175 newMaxSel = ped->ichCaret; 02176 02177 UserAssert(newMinSel == ped->ichMinSel); 02178 } else { 02179 // Extend selection 02180 newMinSel = ped->ichCaret; 02181 } 02182 } else { 02183 // Clear selection 02184 newMaxSel = newMinSel = ped->ichCaret; 02185 } 02186 02187 changeSelection = TRUE; 02188 } else { 02189 // 02190 // If the user tries to move left and we are at the 0th 02191 // character and there is a selection, then cancel the 02192 // selection. 02193 // 02194 if ( (ped->ichMaxSel != ped->ichMinSel) && 02195 !(scState & SHFTDOWN) ) { 02196 changeSelection = TRUE; 02197 newMaxSel = newMinSel = ped->ichCaret; 02198 } 02199 } 02200 break; 02201 02202 case VK_RIGHT: 02203 // 02204 // If the caret isn't at the end, we can move right. 02205 // 02206 if (ped->ichCaret < ped->cch) { 02207 // 02208 // Get new caret pos. 02209 // 02210 if (scState & CTRLDOWN) { 02211 // Move caret word right 02212 ECWord(ped, ped->ichCaret, FALSE, NULL, &ped->ichCaret); 02213 } else { 02214 // Move caret char right 02215 if (ped->pLpkEditCallout) { 02216 ped->ichCaret = MLMoveSelectionRestricted(ped, ped->ichCaret, FALSE); 02217 } else { 02218 ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE); 02219 } 02220 } 02221 02222 // 02223 // Get new selection. 02224 // 02225 if (scState & SHFTDOWN) { 02226 if (MinEqCar && !MinEqMax) { 02227 // Reduce selection 02228 newMinSel = ped->ichCaret; 02229 02230 UserAssert(newMaxSel == ped->ichMaxSel); 02231 } else { 02232 // Extend selection 02233 newMaxSel = ped->ichCaret; 02234 } 02235 } else { 02236 // Clear selection 02237 newMaxSel = newMinSel = ped->ichCaret; 02238 } 02239 02240 changeSelection = TRUE; 02241 } else { 02242 // 02243 // If the user tries to move right and we are at the last 02244 // character and there is a selection, then cancel the 02245 // selection. 02246 // 02247 if ( (ped->ichMaxSel != ped->ichMinSel) && 02248 !(scState & SHFTDOWN) ) { 02249 newMaxSel = newMinSel = ped->ichCaret; 02250 changeSelection = TRUE; 02251 } 02252 } 02253 break; 02254 02255 case VK_UP: 02256 case VK_DOWN: 02257 if (ped->cLines - 1 != ped->iCaretLine && 02258 ped->ichCaret == ped->chLines[ped->iCaretLine + 1]) 02259 prevLine = TRUE; 02260 else 02261 prevLine = FALSE; 02262 02263 hdc = ECGetEditDC(ped, TRUE); 02264 MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine, &mousePt); 02265 ECReleaseEditDC(ped, hdc, TRUE); 02266 mousePt.y += 1 + (virtKeyCode == VK_UP ? -ped->lineHeight : ped->lineHeight); 02267 02268 if (!(scState & CTRLDOWN)) { 02269 // 02270 // Send fake mouse messages to handle this 02271 // If VK_SHIFT is down, extend selection & move caret up/down 02272 // 1 line. Otherwise, clear selection & move caret. 02273 // 02274 MLMouseMotion(ped, WM_LBUTTONDOWN, 02275 !(scState & SHFTDOWN) ? 0 : MK_SHIFT, &mousePt); 02276 MLMouseMotion(ped, WM_LBUTTONUP, 02277 !(scState & SHFTDOWN) ? 0 : MK_SHIFT, &mousePt); 02278 } 02279 break; 02280 02281 case VK_HOME: 02282 // 02283 // Update caret. 02284 // 02285 if (scState & CTRLDOWN) { 02286 // Move caret to beginning of text. 02287 ped->ichCaret = 0; 02288 } else { 02289 // Move caret to beginning of line. 02290 ped->ichCaret = ped->chLines[ped->iCaretLine]; 02291 } 02292 02293 // 02294 // Update selection. 02295 // 02296 newMinSel = ped->ichCaret; 02297 02298 if (scState & SHFTDOWN) { 02299 if (MaxEqCar && !MinEqMax) { 02300 if (scState & CTRLDOWN) 02301 newMaxSel = ped->ichMinSel; 02302 else { 02303 newMinSel = ped->ichMinSel; 02304 newMaxSel = ped->ichCaret; 02305 } 02306 } 02307 } else { 02308 // Clear selection 02309 newMaxSel = ped->ichCaret; 02310 } 02311 02312 changeSelection = TRUE; 02313 break; 02314 02315 case VK_END: 02316 // 02317 // Update caret. 02318 // 02319 if (scState & CTRLDOWN) { 02320 // Move caret to end of text. 02321 ped->ichCaret = ped->cch; 02322 } else { 02323 // Move caret to end of line. 02324 ped->ichCaret = ped->chLines[ped->iCaretLine] + 02325 MLLine(ped, ped->iCaretLine); 02326 } 02327 02328 // Update selection. 02329 newMaxSel = ped->ichCaret; 02330 02331 if (scState & SHFTDOWN) { 02332 if (MinEqCar && !MinEqMax) { 02333 // Reduce selection 02334 if (scState & CTRLDOWN) { 02335 newMinSel = ped->ichMaxSel; 02336 } else { 02337 newMinSel = ped->ichCaret; 02338 newMaxSel = ped->ichMaxSel; 02339 } 02340 } 02341 } else { 02342 // Clear selection 02343 newMinSel = ped->ichCaret; 02344 } 02345 02346 changeSelection = TRUE; 02347 break; 02348 02349 // FE_IME // EC_INSERT_COMPOSITION_CHAR : MLKeyDown() : VK_HANJA support 02350 case VK_HANJA: 02351 if ( HanjaKeyHandler( ped ) ) { 02352 changeSelection = TRUE; 02353 newMinSel = ped->ichCaret; 02354 newMaxSel = ped->ichCaret + (ped->fAnsi ? 2 : 1); 02355 } 02356 break; 02357 02358 case VK_PRIOR: 02359 case VK_NEXT: 02360 if (!(scState & CTRLDOWN)) { 02361 /* 02362 * Vertical scroll by one visual screen 02363 */ 02364 hdc = ECGetEditDC(ped, TRUE); 02365 MLIchToXYPos(ped, hdc, ped->ichCaret, FALSE, &mousePt); 02366 ECReleaseEditDC(ped, hdc, TRUE); 02367 mousePt.y += 1; 02368 02369 SendMessage(ped->hwnd, WM_VSCROLL, virtKeyCode == VK_PRIOR ? SB_PAGEUP : SB_PAGEDOWN, 0L); 02370 02371 /* 02372 * Move the cursor there 02373 */ 02374 MLMouseMotion(ped, WM_LBUTTONDOWN, !(scState & SHFTDOWN) ? 0 : MK_SHIFT, &mousePt); 02375 MLMouseMotion(ped, WM_LBUTTONUP, !(scState & SHFTDOWN) ? 0 : MK_SHIFT, &mousePt); 02376 02377 } else { 02378 /* 02379 * Horizontal scroll by one screenful minus one char 02380 */ 02381 iScrollAmt = ((ped->rcFmt.right - ped->rcFmt.left) / ped->aveCharWidth) - 1; 02382 if (virtKeyCode == VK_PRIOR) 02383 iScrollAmt *= -1; /* For previous page */ 02384 02385 SendMessage(ped->hwnd, WM_HSCROLL, MAKELONG(EM_LINESCROLL, iScrollAmt), 0); 02386 break; 02387 } 02388 break; 02389 02390 case VK_DELETE: 02391 if (ped->fReadOnly) 02392 break; 02393 02394 switch (scState) { 02395 case NONEDOWN: 02396 02397 /* 02398 * Clear selection. If no selection, delete (clear) character 02399 * right 02400 */ 02401 if ((ped->ichMaxSel < ped->cch) && (ped->ichMinSel == ped->ichMaxSel)) { 02402 02403 /* 02404 * Move cursor forwards and send a backspace message... 02405 */ 02406 if (ped->pLpkEditCallout) { 02407 ped->ichMinSel = ped->ichCaret; 02408 ped->ichMaxSel = MLMoveSelectionRestricted(ped, ped->ichCaret, FALSE); 02409 } else { 02410 ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE); 02411 ped->ichMaxSel = ped->ichMinSel = ped->ichCaret; 02412 } 02413 02414 goto DeleteAnotherChar; 02415 } 02416 break; 02417 02418 case SHFTDOWN: 02419 02420 /* 02421 * CUT selection ie. remove and copy to clipboard, or if no 02422 * selection, delete (clear) character left. 02423 */ 02424 if (ped->ichMinSel == ped->ichMaxSel) { 02425 goto DeleteAnotherChar; 02426 } else { 02427 SendMessage(ped->hwnd, WM_CUT, (UINT)0, 0L); 02428 } 02429 02430 break; 02431 02432 case CTRLDOWN: 02433 02434 /* 02435 * Clear selection, or delete to end of line if no selection 02436 */ 02437 if ((ped->ichMaxSel < ped->cch) && (ped->ichMinSel == ped->ichMaxSel)) { 02438 ped->ichMaxSel = ped->ichCaret = ped->chLines[ped->iCaretLine] + 02439 MLLine(ped, ped->iCaretLine); 02440 } 02441 break; 02442 } 02443 02444 if (!(scState & SHFTDOWN) && (ped->ichMinSel != ped->ichMaxSel)) { 02445 02446 DeleteAnotherChar: 02447 if (GETAPPVER() >= VER40) { 02448 MLChar(ped, VK_BACK, 0); 02449 } else { 02450 SendMessageWorker(ped->pwnd, WM_CHAR, VK_BACK, 0, ped->fAnsi); 02451 } 02452 } 02453 02454 /* 02455 * No need to update text or selection since BACKSPACE message does it 02456 * for us. 02457 */ 02458 break; 02459 02460 case VK_INSERT: 02461 if (scState == CTRLDOWN || scState == SHFTDOWN) { 02462 02463 /* 02464 * if CTRLDOWN Copy current selection to clipboard 02465 */ 02466 02467 /* 02468 * if SHFTDOWN Paste clipboard 02469 */ 02470 SendMessage(ped->hwnd, (UINT)(scState == CTRLDOWN ? WM_COPY : WM_PASTE), 0, 0); 02471 } 02472 break; 02473 } 02474 02475 if (changeSelection) { 02476 hdc = ECGetEditDC(ped, FALSE); 02477 MLChangeSelection(ped, hdc, newMinSel, newMaxSel); 02478 02479 /* 02480 * Set the caret's line 02481 */ 02482 ped->iCaretLine = MLIchToLine(ped, ped->ichCaret); 02483 02484 if (virtKeyCode == VK_END && 02485 // Next line: Win95 Bug#11822, EditControl repaint (Sankar) 02486 (ped->ichCaret == ped->chLines[ped->iCaretLine]) && 02487 ped->ichCaret < ped->cch && 02488 ped->fWrap && ped->iCaretLine > 0) { 02489 LPSTR pText = ECLock(ped); 02490 02491 /* 02492 * Handle moving to the end of a word wrapped line. This keeps the 02493 * cursor from falling to the start of the next line if we have word 02494 * wrapped and there is no CRLF. 02495 */ 02496 if ( ped->fAnsi ) { 02497 if (*(WORD UNALIGNED *)(pText + 02498 ped->chLines[ped->iCaretLine] - 2) != 0x0A0D) { 02499 ped->iCaretLine--; 02500 } 02501 } else { 02502 if (*(DWORD UNALIGNED *)(pText + 02503 (ped->chLines[ped->iCaretLine] - 2)*ped->cbChar) != 0x000A000D) { 02504 ped->iCaretLine--; 02505 } 02506 } 02507 ECUnlock(ped); 02508 } 02509 02510 /* 02511 * Since drawtext sets the caret position 02512 */ 02513 MLSetCaretPosition(ped, hdc); 02514 ECReleaseEditDC(ped, hdc, FALSE); 02515 02516 /* 02517 * Make sure we can see the cursor 02518 */ 02519 MLEnsureCaretVisible(ped); 02520 } 02521 } 02522 02523 /***************************************************************************\ 02524 * MLChar 02525 * 02526 * Handles character and virtual key input 02527 * 02528 * History: 02529 \***************************************************************************/ 02530 02531 void MLChar( 02532 PED ped, 02533 DWORD keyValue, 02534 int keyMods) 02535 { 02536 WCHAR keyPress; 02537 BOOL updateText = FALSE; 02538 02539 /* 02540 * keyValue is either: 02541 * a Virtual Key (eg: VK_TAB, VK_ESCAPE, VK_BACK) 02542 * a character (Unicode or "ANSI") 02543 */ 02544 if (ped->fAnsi) 02545 keyPress = LOBYTE(keyValue); 02546 else 02547 keyPress = LOWORD(keyValue); 02548 02549 if (ped->fMouseDown || keyPress == VK_ESCAPE) { 02550 02551 /* 02552 * If we are in the middle of a mousedown command, don't do anything. 02553 * Also, just ignore it if we get a translated escape key which happens 02554 * with multiline edit controls in a dialog box. 02555 */ 02556 return ; 02557 } 02558 02559 ECInOutReconversionMode(ped, FALSE); 02560 02561 { 02562 int scState; 02563 scState = ECGetModKeys(keyMods); 02564 02565 if (ped->fInDialogBox && scState != CTRLDOWN) { 02566 02567 /* 02568 * If this multiline edit control is in a dialog box, then we want the 02569 * TAB key to take you to the next control, shift TAB to take you to the 02570 * previous control, and CTRL-TAB to insert a tab into the edit control. 02571 * We moved the focus when we received the keydown message so we will 02572 * ignore the TAB key now unless the ctrl key is down. Also, we want 02573 * CTRL-RETURN to insert a return into the text and RETURN to be sent to 02574 * the default button. 02575 */ 02576 if (keyPress == VK_TAB || 02577 (keyPress == VK_RETURN && !TestWF(ped->pwnd, EFWANTRETURN))) 02578 return ; 02579 } 02580 02581 /* 02582 * Allow CTRL+C to copy from a read only edit control 02583 * Ignore all other keys in read only controls 02584 */ 02585 if ((ped->fReadOnly) && !((keyPress == 3) && (scState == CTRLDOWN))) { 02586 return ; 02587 } 02588 } 02589 02590 switch (keyPress) { 02591 case 0x0A: // linefeed 02592 keyPress = VK_RETURN; 02593 /* 02594 * FALL THRU 02595 */ 02596 02597 case VK_RETURN: 02598 case VK_TAB: 02599 case VK_BACK: 02600 DeleteSelection: 02601 if (MLDeleteText(ped)) 02602 updateText = TRUE; 02603 break; 02604 02605 default: 02606 if (keyPress >= TEXT(' ')) { 02607 /* 02608 * If this is in [a-z],[A-Z] and we are an ES_NUMBER 02609 * edit field, bail. 02610 */ 02611 if (ped->f40Compat && TestWF(ped->pwnd, EFNUMBER)) { 02612 if (!ECIsCharNumeric(ped, keyPress)) { 02613 goto IllegalChar; 02614 } 02615 } 02616 02617 goto DeleteSelection; 02618 } 02619 break; 02620 } 02621 02622 /* 02623 * Handle key codes 02624 */ 02625 switch(keyPress) { 02626 UINT msg; 02627 02628 // Ctrl+Z == Undo 02629 case 26: 02630 msg = WM_UNDO; 02631 goto SendEditingMessage; 02632 break; 02633 02634 // Ctrl+X == Cut 02635 case 24: 02636 if (ped->ichMinSel == ped->ichMaxSel) 02637 goto IllegalChar; 02638 else 02639 { 02640 msg = WM_CUT; 02641 goto SendEditingMessage; 02642 } 02643 break; 02644 02645 // Ctrl+C == Copy 02646 case 3: 02647 msg = WM_COPY; 02648 goto SendEditingMessage; 02649 break; 02650 02651 // Ctrl+V == Paste 02652 case 22: 02653 msg = WM_PASTE; 02654 SendEditingMessage: 02655 SendMessage(ped->hwnd, msg, 0, 0L); 02656 break; 02657 02658 case VK_BACK: 02659 // 02660 // Delete any selected text or delete character left if no sel 02661 // 02662 if (!updateText && ped->ichMinSel) 02663 { 02664 // 02665 // There was no selection to delete so we just delete 02666 // character left if available 02667 // 02668 ped->ichMinSel = MLMoveSelection(ped, ped->ichCaret, TRUE); 02669 MLDeleteText(ped); 02670 } 02671 break; 02672 02673 default: 02674 if (keyPress == VK_RETURN) 02675 if (ped->fAnsi) 02676 keyValue = 0x0A0D; 02677 else 02678 keyValue = 0x000A000D; 02679 02680 if ( keyPress >= TEXT(' ') 02681 || keyPress == VK_RETURN 02682 || keyPress == VK_TAB 02683 || keyPress == 0x1E // RS - Unicode block separator 02684 || keyPress == 0x1F // US - Unicode segment separator 02685 ) { 02686 02687 NtUserCallNoParam(SFI_ZZZHIDECURSORNOCAPTURE); 02688 if (ped->fAnsi) { 02689 // 02690 // check if it's a leading byte of double byte character 02691 // 02692 if (ECIsDBCSLeadByte(ped,(BYTE)keyPress)) { 02693 int DBCSkey; 02694 02695 if ((DBCSkey = DbcsCombine(ped->hwnd, keyPress)) != 0) 02696 keyValue = DBCSkey; 02697 } 02698 MLInsertText(ped, (LPSTR)&keyValue, HIBYTE(keyValue) ? 2 : 1, TRUE); 02699 } else 02700 MLInsertText(ped, (LPSTR)&keyValue, HIWORD(keyValue) ? 2 : 1, TRUE); 02701 } else { 02702 IllegalChar: 02703 NtUserMessageBeep(0); 02704 } 02705 break; 02706 } 02707 } 02708 02709 /***************************************************************************\ 02710 * MLPasteText AorW 02711 * 02712 * Pastes a line of text from the clipboard into the edit control 02713 * starting at ped->ichCaret. Updates ichMaxSel and ichMinSel to point to the 02714 * end of the inserted text. Notifies the parent if space cannot be 02715 * allocated. Returns how many characters were inserted. 02716 * 02717 * History: 02718 \***************************************************************************/ 02719 02720 ICH PASCAL NEAR MLPasteText( 02721 PED ped) 02722 { 02723 HANDLE hData; 02724 LPSTR lpchClip; 02725 ICH cchAdded = 0; 02726 HCURSOR hCursorOld; 02727 02728 #ifdef UNDO_CLEANUP // #ifdef Added in Chicago - johnl 02729 if (!ped->fAutoVScroll) { 02730 02731 /* 02732 * Empty the undo buffer if this edit control limits the amount of text 02733 * the user can add to the window rect. This is so that we can undo this 02734 * operation if doing in causes us to exceed the window boundaries. 02735 */ 02736 ECEmptyUndo(ped); 02737 } 02738 #endif 02739 02740 hCursorOld = NtUserSetCursor(LoadCursor(NULL, IDC_WAIT)); 02741 02742 if (!OpenClipboard(ped->hwnd)) 02743 goto PasteExitNoCloseClip; 02744 02745 if (!(hData = GetClipboardData(ped->fAnsi ? CF_TEXT : CF_UNICODETEXT)) || 02746 (GlobalFlags(hData) == GMEM_INVALID_HANDLE)) { 02747 RIPMSG1(RIP_WARNING, "MLPasteText(): couldn't get a valid handle(%x)", hData); 02748 goto PasteExit; 02749 } 02750 02751 /* 02752 * See if any text should be deleted 02753 */ 02754 MLDeleteText(ped); 02755 02756 USERGLOBALLOCK(hData, lpchClip); 02757 if (lpchClip == NULL) { 02758 RIPMSG1(RIP_WARNING, "MLPasteText: USERGLOBALLOCK(%x) failed.", hData); 02759 goto PasteExit; 02760 } 02761 02762 /* 02763 * Get the length of the addition. 02764 */ 02765 if (ped->fAnsi) 02766 cchAdded = strlen(lpchClip); 02767 else 02768 cchAdded = wcslen((LPWSTR)lpchClip); 02769 02770 /* 02771 * Insert the text (MLInsertText checks line length) 02772 */ 02773 cchAdded = MLInsertText(ped, lpchClip, cchAdded, FALSE); 02774 02775 USERGLOBALUNLOCK(hData); 02776 02777 PasteExit: 02778 NtUserCloseClipboard(); 02779 02780 PasteExitNoCloseClip: 02781 NtUserSetCursor(hCursorOld); 02782 02783 return (cchAdded); 02784 } 02785 02786 /***************************************************************************\ 02787 * MLMouseMotion AorW 02788 * 02789 * History: 02790 \***************************************************************************/ 02791 02792 void MLMouseMotion( 02793 PED ped, 02794 UINT message, 02795 UINT virtKeyDown, 02796 LPPOINT mousePt) 02797 { 02798 BOOL fChangedSel = FALSE; 02799 02800 HDC hdc = ECGetEditDC(ped, TRUE); 02801 02802 ICH ichMaxSel = ped->ichMaxSel; 02803 ICH ichMinSel = ped->ichMinSel; 02804 02805 ICH mouseCch; 02806 ICH mouseLine; 02807 int i, j; 02808 LONG ll, lh; 02809 02810 mouseCch = MLMouseToIch(ped, hdc, mousePt, &mouseLine); 02811 02812 /* 02813 * Save for timer 02814 */ 02815 ped->ptPrevMouse = *mousePt; 02816 ped->prevKeys = virtKeyDown; 02817 02818 switch (message) { 02819 case WM_LBUTTONDBLCLK: 02820 /* 02821 * if shift key is down, extend selection to word we double clicked on 02822 * else clear current selection and select word. 02823 */ 02824 // LiZ -- 5/5/93 02825 if (ped->fAnsi && ped->fDBCS) { 02826 LPSTR pText = ECLock(ped); 02827 ECWord(ped,ped->ichCaret, 02828 ECIsDBCSLeadByte(ped, *(pText+(ped->ichCaret))) 02829 ? FALSE : 02830 (ped->ichCaret == ped->chLines[ped->iCaretLine] 02831 ? FALSE : TRUE), &ll, &lh); 02832 ECUnlock(ped); 02833 } else { 02834 ECWord(ped, mouseCch, !(mouseCch == ped->chLines[mouseLine]), &ll, &lh); 02835 } 02836 if (!(virtKeyDown & MK_SHIFT)) { 02837 // If shift key isn't down, move caret to mouse point and clear 02838 // old selection 02839 ichMinSel = ll; 02840 ichMaxSel = ped->ichCaret = lh; 02841 } else { 02842 // Shiftkey is down so we want to maintain the current selection 02843 // (if any) and just extend or reduce it 02844 if (ped->ichMinSel == ped->ichCaret) { 02845 ichMinSel = ped->ichCaret = ll; 02846 ECWord(ped, ichMaxSel, TRUE, &ll, &lh); 02847 } else { 02848 ichMaxSel = ped->ichCaret = lh; 02849 ECWord(ped, ichMinSel, FALSE, &ll, &lh); 02850 } 02851 } 02852 02853 ped->ichStartMinSel = ll; 02854 ped->ichStartMaxSel = lh; 02855 02856 goto InitDragSelect; 02857 02858 case WM_MOUSEMOVE: 02859 if (ped->fMouseDown) { 02860 02861 /* 02862 * Set the system timer to automatically scroll when mouse is 02863 * outside of the client rectangle. Speed of scroll depends on 02864 * distance from window. 02865 */ 02866 i = mousePt->y < 0 ? -mousePt->y : mousePt->y - ped->rcFmt.bottom; 02867 j = gpsi->dtScroll - ((UINT)i << 4); 02868 if (j < 1) 02869 j = 1; 02870 NtUserSetSystemTimer(ped->hwnd, IDSYS_SCROLL, (UINT)j, NULL); 02871 02872 fChangedSel = TRUE; 02873 02874 // Extend selection, move caret right 02875 if (ped->ichStartMinSel || ped->ichStartMaxSel) { 02876 // We're in WORD SELECT mode 02877 BOOL fReverse = (mouseCch <= ped->ichStartMinSel); 02878 ECWord(ped, mouseCch, !fReverse, &ll, &lh); 02879 if (fReverse) { 02880 ichMinSel = ped->ichCaret = ll; 02881 ichMaxSel = ped->ichStartMaxSel; 02882 } else { 02883 ichMinSel = ped->ichStartMinSel; 02884 ichMaxSel = ped->ichCaret = lh; 02885 } 02886 } else if ((ped->ichMinSel == ped->ichCaret) && 02887 (ped->ichMinSel != ped->ichMaxSel)) 02888 // Reduce selection extent 02889 ichMinSel = ped->ichCaret = mouseCch; 02890 else 02891 // Extend selection extent 02892 ichMaxSel = ped->ichCaret = mouseCch; 02893 02894 ped->iCaretLine = mouseLine; 02895 } 02896 break; 02897 02898 case WM_LBUTTONDOWN: 02899 ll = lh = mouseCch; 02900 02901 if (!(virtKeyDown & MK_SHIFT)) { 02902 // If shift key isn't down, move caret to mouse point and clear 02903 // old selection 02904 ichMinSel = ichMaxSel = ped->ichCaret = mouseCch; 02905 } else { 02906 // Shiftkey is down so we want to maintain the current selection 02907 // (if any) and just extend or reduce it 02908 if (ped->ichMinSel == ped->ichCaret) 02909 ichMinSel = ped->ichCaret = mouseCch; 02910 else 02911 ichMaxSel = ped->ichCaret = mouseCch; 02912 } 02913 02914 ped->ichStartMinSel = ped->ichStartMaxSel = 0; 02915 02916 InitDragSelect: 02917 ped->iCaretLine = mouseLine; 02918 02919 ped->fMouseDown = FALSE; 02920 NtUserSetCapture(ped->hwnd); 02921 ped->fMouseDown = TRUE; 02922 fChangedSel = TRUE; 02923 02924 // Set the timer so that we can scroll automatically when the mouse 02925 // is moved outside the window rectangle. 02926 NtUserSetSystemTimer(ped->hwnd, IDSYS_SCROLL, gpsi->dtScroll, NULL); 02927 break; 02928 02929 case WM_LBUTTONUP: 02930 if (ped->fMouseDown) { 02931 02932 /* 02933 * Kill the timer so that we don't do auto mouse moves anymore 02934 */ 02935 NtUserKillSystemTimer(ped->hwnd, IDSYS_SCROLL); 02936 NtUserReleaseCapture(); 02937 MLSetCaretPosition(ped, hdc); 02938 ped->fMouseDown = FALSE; 02939 } 02940 break; 02941 } 02942 02943 02944 if (fChangedSel) { 02945 MLChangeSelection(ped, hdc, ichMinSel, ichMaxSel); 02946 MLEnsureCaretVisible(ped); 02947 } 02948 02949 ECReleaseEditDC(ped, hdc, TRUE); 02950 02951 if (!ped->fFocus && (message == WM_LBUTTONDOWN)) { 02952 02953 /* 02954 * If we don't have the focus yet, get it 02955 */ 02956 NtUserSetFocus(ped->hwnd); 02957 } 02958 } 02959 02960 /***************************************************************************\ 02961 * MLScroll AorW 02962 * 02963 * History: 02964 \***************************************************************************/ 02965 02966 LONG MLScroll( 02967 PED ped, 02968 BOOL fVertical, 02969 int cmd, 02970 int iAmt, 02971 BOOL fRedraw) 02972 { 02973 SCROLLINFO si; 02974 int dx = 0; 02975 int dy = 0; 02976 BOOL fIncludeLeftMargin; 02977 int newPos; 02978 int oldPos; 02979 BOOL fUp = FALSE; 02980 UINT wFlag; 02981 DWORD dwTime = 0; 02982 02983 if (fRedraw && (cmd != ML_REFRESH)) { 02984 UpdateWindow(ped->hwnd); 02985 } 02986 02987 if (ped->pLpkEditCallout && ped->fRtoLReading && !fVertical 02988 && ped->maxPixelWidth > ped->rcFmt.right - ped->rcFmt.left) { 02989 /* 02990 * Horizontal scoll of a right oriented window with a scrollbar. 02991 * Map the logical xOffset to visual coordinates. 02992 */ 02993 oldPos = ped->maxPixelWidth 02994 - ((int)ped->xOffset + ped->rcFmt.right - ped->rcFmt.left); 02995 } else 02996 oldPos = (int) (fVertical ? ped->ichScreenStart : ped->xOffset); 02997 02998 fIncludeLeftMargin = (ped->xOffset == 0); 02999 03000 switch (cmd) { 03001 case ML_REFRESH: 03002 newPos = oldPos; 03003 break; 03004 03005 case EM_GETTHUMB: 03006 return(oldPos); 03007 03008 case SB_THUMBTRACK: 03009 case SB_THUMBPOSITION: 03010 03011 /* 03012 * If the edit contains more than 0xFFFF lines 03013 * it means that the scrolbar can return a position 03014 * that cannot fit in a WORD (16 bits), so use 03015 * GetScrollInfo (which is slower) in this case. 03016 */ 03017 if (ped->cLines < 0xFFFF) { 03018 newPos = iAmt; 03019 } else { 03020 SCROLLINFO si; 03021 03022 si.cbSize = sizeof(SCROLLINFO); 03023 si.fMask = SIF_TRACKPOS; 03024 03025 GetScrollInfo( ped->hwnd, SB_VERT, &si); 03026 03027 newPos = si.nTrackPos; 03028 } 03029 break; 03030 03031 case SB_TOP: // == SB_LEFT 03032 newPos = 0; 03033 break; 03034 03035 case SB_BOTTOM: // == SB_RIGHT 03036 if (fVertical) 03037 newPos = ped->cLines; 03038 else 03039 newPos = ped->maxPixelWidth; 03040 break; 03041 03042 case SB_PAGEUP: // == SB_PAGELEFT 03043 fUp = TRUE; 03044 case SB_PAGEDOWN: // == SB_PAGERIGHT 03045 03046 if (fVertical) 03047 iAmt = ped->ichLinesOnScreen - 1; 03048 else 03049 iAmt = (ped->rcFmt.right - ped->rcFmt.left) - 1; 03050 03051 if (iAmt == 0) 03052 iAmt++; 03053 03054 if (fUp) 03055 iAmt = -iAmt; 03056 goto AddDelta; 03057 03058 case SB_LINEUP: // == SB_LINELEFT 03059 fUp = TRUE; 03060 case SB_LINEDOWN: // == SB_LINERIGHT 03061 03062 dwTime = iAmt; 03063 03064 iAmt = 1; 03065 03066 if (fUp) 03067 iAmt = -iAmt; 03068 03069 // | | 03070 // | FALL THRU | 03071 // V V 03072 03073 case EM_LINESCROLL: 03074 if (!fVertical) 03075 iAmt *= ped->aveCharWidth; 03076 03077 AddDelta: 03078 newPos = oldPos + iAmt; 03079 break; 03080 03081 default: 03082 return(0L); 03083 } 03084 03085 if (fVertical) { 03086 if (si.nMax = ped->cLines) 03087 si.nMax--; 03088 03089 if (!ped->hwndParent || 03090 TestWF(ValidateHwnd(ped->hwndParent), WFWIN40COMPAT)) 03091 si.nPage = ped->ichLinesOnScreen; 03092 else 03093 si.nPage = 0; 03094 03095 wFlag = WFVSCROLL; 03096 } else { 03097 si.nMax = ped->maxPixelWidth; 03098 si.nPage = ped->rcFmt.right - ped->rcFmt.left; 03099 wFlag = WFHSCROLL; 03100 } 03101 03102 if (TestWF(ValidateHwnd(ped->hwnd), wFlag)) { 03103 si.cbSize = sizeof(SCROLLINFO); 03104 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; 03105 si.nMin = 0; 03106 si.nPos = newPos; 03107 newPos = NtUserSetScrollInfo(ped->hwnd, fVertical ? SB_VERT : SB_HORZ, 03108 &si, fRedraw); 03109 } else { 03110 // BOGUS -- this is duped code from ScrollBar code 03111 // but it's for the case when we want to limit the position without 03112 // actually having the scroll bar 03113 int iMaxPos; 03114 03115 // Clip page to 0, range + 1 03116 si.nPage = max(min((int)si.nPage, si.nMax + 1), 0); 03117 03118 03119 iMaxPos = si.nMax - (si.nPage ? si.nPage - 1 : 0); 03120 newPos = min(max(newPos, 0), iMaxPos); 03121 } 03122 03123 oldPos -= newPos; 03124 03125 if (!oldPos) 03126 return(0L); 03127 03128 if (ped->pLpkEditCallout && ped->fRtoLReading && !fVertical 03129 && ped->maxPixelWidth > ped->rcFmt.right - ped->rcFmt.left) { 03130 // Map visual oldPos and newPos back to logical coordinates 03131 newPos = ped->maxPixelWidth 03132 - (newPos + ped->rcFmt.right - ped->rcFmt.left); 03133 oldPos = -oldPos; 03134 if (newPos<0) { 03135 // Compensate for scroll bar returning pos > max-page 03136 oldPos += newPos; 03137 newPos=0; 03138 } 03139 } 03140 03141 if (fVertical) { 03142 ped->ichScreenStart = newPos; 03143 dy = oldPos * ped->lineHeight; 03144 } else { 03145 ped->xOffset = newPos; 03146 dx = oldPos; 03147 } 03148 03149 if (cmd != SB_THUMBTRACK) 03150 // We don't want to notify the parent of thumbtracking since they might 03151 // try to set the thumb position to something bogus. 03152 // NOTEPAD used to be guilty of this -- but I rewrote it so it's not. 03153 // The question is WHO ELSE does this? (jeffbog) 03154 ECNotifyParent(ped, fVertical ? EN_VSCROLL : EN_HSCROLL); 03155 03156 if (fRedraw && _IsWindowVisible(ped->pwnd)) { 03157 RECT rc; 03158 RECT rcUpdate; 03159 RECT rcClipRect; 03160 HDC hdc; 03161 03162 _GetClientRect(ped->pwnd, &rc); 03163 CopyRect(&rcClipRect, &ped->rcFmt); 03164 03165 if (fVertical) { // Is this a vertical scroll? 03166 rcClipRect.left -= ped->wLeftMargin; 03167 rcClipRect.right += ped->wRightMargin; 03168 } 03169 03170 IntersectRect(&rc, &rc, &rcClipRect); 03171 rc.bottom++; 03172 03173 /* 03174 * Chicago has this HideCaret but there doesn't appear to be a 03175 * corresponding ShowCaret, so we lose the Caret under NT when the 03176 * EC scrolls - Johnl 03177 * 03178 * HideCaret(ped->hwnd); 03179 */ 03180 03181 hdc = ECGetEditDC(ped, FALSE); 03182 ECSetEditClip(ped, hdc, fIncludeLeftMargin); 03183 if (ped->hFont) 03184 SelectObject(hdc, ped->hFont); 03185 ECGetBrush(ped, hdc); 03186 03187 if (ped->pLpkEditCallout && !fVertical) { 03188 // Horizontal scroll with complex script support 03189 int xFarOffset = ped->xOffset + ped->rcFmt.right - ped->rcFmt.left; 03190 03191 rc = ped->rcFmt; 03192 if (dwTime != 0) 03193 ScrollWindowEx(ped->hwnd, ped->fRtoLReading ? -dx : dx, dy, NULL, NULL, NULL, 03194 &rcUpdate, MAKELONG(SW_SMOOTHSCROLL | SW_SCROLLCHILDREN, dwTime)); 03195 else 03196 NtUserScrollDC(hdc, ped->fRtoLReading ? -dx : dx, dy, 03197 &rc, &rc, NULL, &rcUpdate); 03198 03199 // Handle margins: Blank if clipped by horizontal scrolling, 03200 // display otherwise. 03201 if (ped->wLeftMargin) { 03202 rc.left = ped->rcFmt.left - ped->wLeftMargin; 03203 rc.right = ped->rcFmt.left; 03204 if ( (ped->format != ES_LEFT) // Always display margin for centred or far-aligned text 03205 || // Display LTR left margin if first character fully visible 03206 (!ped->fRtoLReading && ped->xOffset == 0) 03207 || // Display RTL left margin if last character fully visible 03208 (ped->fRtoLReading && xFarOffset >= ped->maxPixelWidth)) { 03209 UnionRect(&rcUpdate, &rcUpdate, &rc); 03210 } else { 03211 ExtTextOutW(hdc, rc.left, rc.top, 03212 ETO_CLIPPED | ETO_OPAQUE | ETO_GLYPH_INDEX, 03213 &rc, L"", 0, 0L); 03214 } 03215 } 03216 if (ped->wRightMargin) { 03217 rc.left = ped->rcFmt.right; 03218 rc.right = ped->rcFmt.right + ped->wRightMargin; 03219 if ( (ped->format != ES_LEFT) // Always display margin for centred or far-aligned text 03220 || // Display RTL right margin if first character fully visible 03221 (ped->fRtoLReading && ped->xOffset == 0) 03222 || // Display LTR right margin if last character fully visible 03223 (!ped->fRtoLReading && xFarOffset >= ped->maxPixelWidth)) { 03224 UnionRect(&rcUpdate, &rcUpdate, &rc); 03225 } else { 03226 ExtTextOutW(hdc, rc.left, rc.top, 03227 ETO_CLIPPED | ETO_OPAQUE | ETO_GLYPH_INDEX, 03228 &rc, L"", 0, 0L); 03229 } 03230 } 03231 } else { 03232 if (dwTime != 0) 03233 ScrollWindowEx(ped->hwnd, dx, dy, NULL, NULL, NULL, 03234 &rcUpdate, MAKELONG(SW_SMOOTHSCROLL | SW_SCROLLCHILDREN, dwTime)); 03235 else 03236 NtUserScrollDC(hdc, dx, dy, &rc, &rc, NULL, &rcUpdate); 03237 03238 // If we need to wipe out the left margin area 03239 if (ped->wLeftMargin && !fVertical) { 03240 // Calculate the rectangle to be wiped out 03241 rc.right = rc.left; 03242 rc.left = max(0, ped->rcFmt.left - ped->wLeftMargin); 03243 if (rc.left < rc.right) { 03244 if (fIncludeLeftMargin && (ped->xOffset != 0)) { 03245 03246 ExtTextOutW(hdc, rc.left, rc.top, ETO_CLIPPED | ETO_OPAQUE, 03247 &rc, L"", 0, 0L); 03248 } else 03249 if((!fIncludeLeftMargin) && (ped->xOffset == 0)) 03250 UnionRect(&rcUpdate, &rcUpdate, &rc); 03251 } 03252 } 03253 } 03254 MLSetCaretPosition(ped,hdc); 03255 03256 ECReleaseEditDC(ped, hdc, FALSE); 03257 NtUserInvalidateRect(ped->hwnd, &rcUpdate, 03258 ((ped->ichLinesOnScreen + ped->ichScreenStart) >= ped->cLines)); 03259 UpdateWindow(ped->hwnd); 03260 } 03261 03262 return(MAKELONG(-oldPos, 1)); 03263 } 03264 03265 /***************************************************************************\ 03266 * MLSetFocus AorW 03267 * 03268 * Gives the edit control the focus and notifies the parent 03269 * EN_SETFOCUS. 03270 * 03271 * History: 03272 \***************************************************************************/ 03273 03274 void MLSetFocus( 03275 PED ped) 03276 { 03277 HDC hdc; 03278 03279 if (!ped->fFocus) { 03280 ped->fFocus = 1; /* Set focus */ 03281 03282 hdc = ECGetEditDC(ped, TRUE); 03283 03284 /* 03285 * Draw the caret. We need to do this even if the window is hidden 03286 * because in dlg box initialization time we may set the focus to a 03287 * hidden edit control window. If we don't create the caret etc, it will 03288 * never end up showing properly. 03289 */ 03290 if (ped->pLpkEditCallout) { 03291 ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(), ped->lineHeight, 0); 03292 } 03293 else { 03294 NtUserCreateCaret(ped->hwnd, (HBITMAP)NULL, ECGetCaretWidth(), ped->lineHeight); 03295 } 03296 NtUserShowCaret(ped->hwnd); 03297 MLSetCaretPosition(ped, hdc); 03298 03299 /* 03300 * Show the current selection. Only if the selection was hidden when we 03301 * lost the focus, must we invert (show) it. 03302 */ 03303 if (!ped->fNoHideSel && ped->ichMinSel != ped->ichMaxSel && 03304 _IsWindowVisible(ped->pwnd)) 03305 MLDrawText(ped, hdc, ped->ichMinSel, ped->ichMaxSel, TRUE); 03306 03307 ECReleaseEditDC(ped, hdc, TRUE); 03308 03309 } 03310 #if 0 03311 MLEnsureCaretVisible(ped); 03312 #endif 03313 03314 /* 03315 * Notify parent we have the focus 03316 */ 03317 ECNotifyParent(ped, EN_SETFOCUS); 03318 } 03319 03320 /***************************************************************************\ 03321 * MLKillFocus AorW 03322 * 03323 * The edit control loses the focus and notifies the parent via 03324 * EN_KILLFOCUS. 03325 * 03326 * History: 03327 \***************************************************************************/ 03328 03329 void MLKillFocus( 03330 PED ped) 03331 { 03332 HDC hdc; 03333 03334 /* 03335 * Reset the wheel delta count. 03336 */ 03337 gcWheelDelta = 0; 03338 03339 if (ped->fFocus) { 03340 ped->fFocus = 0; /* Clear focus */ 03341 03342 /* 03343 * Do this only if we still have the focus. But we always notify the 03344 * parent that we lost the focus whether or not we originally had the 03345 * focus. 03346 */ 03347 03348 /* 03349 * Hide the current selection if needed 03350 */ 03351 if (!ped->fNoHideSel && ped->ichMinSel != ped->ichMaxSel && 03352 _IsWindowVisible(ped->pwnd)) { 03353 hdc = ECGetEditDC(ped, FALSE); 03354 MLDrawText(ped, hdc, ped->ichMinSel, ped->ichMaxSel, TRUE); 03355 ECReleaseEditDC(ped, hdc, FALSE); 03356 } 03357 03358 /* 03359 * Destroy the caret 03360 */ 03361 NtUserDestroyCaret(); 03362 } 03363 03364 /* 03365 * Notify parent that we lost the focus. 03366 */ 03367 ECNotifyParent(ped, EN_KILLFOCUS); 03368 } 03369 03370 /***************************************************************************\ 03371 * MLEnsureCaretVisible AorW 03372 * 03373 * Scrolls the caret into the visible region. 03374 * Returns TRUE if scrolling was done else return s FALSE. 03375 * 03376 * History: 03377 \***************************************************************************/ 03378 03379 BOOL MLEnsureCaretVisible( 03380 PED ped) 03381 { 03382 UINT iLineMax; 03383 int xposition; 03384 BOOL fPrevLine; 03385 HDC hdc; 03386 BOOL fVScroll = FALSE; 03387 BOOL fHScroll = FALSE; 03388 03389 if (_IsWindowVisible(ped->pwnd)) { 03390 int iAmt; 03391 int iFmtWidth = ped->rcFmt.right - ped->rcFmt.left; 03392 03393 if (ped->fAutoVScroll) { 03394 iLineMax = ped->ichScreenStart + ped->ichLinesOnScreen - 1; 03395 03396 if (fVScroll = (ped->iCaretLine > iLineMax)) 03397 iAmt = iLineMax; 03398 else if (fVScroll = (ped->iCaretLine < ped->ichScreenStart)) 03399 iAmt = ped->ichScreenStart; 03400 03401 if (fVScroll) 03402 MLScroll(ped, TRUE, EM_LINESCROLL, ped->iCaretLine - iAmt, TRUE); 03403 } 03404 03405 if (ped->fAutoHScroll && ((int) ped->maxPixelWidth > iFmtWidth)) { 03406 POINT pt; 03407 /* Get the current position of the caret in pixels */ 03408 if ((UINT) (ped->cLines - 1) != ped->iCaretLine && 03409 ped->ichCaret == ped->chLines[ped->iCaretLine + 1]) 03410 fPrevLine = TRUE; 03411 else 03412 fPrevLine = FALSE; 03413 03414 hdc = ECGetEditDC(ped,TRUE); 03415 MLIchToXYPos(ped, hdc, ped->ichCaret, fPrevLine, &pt); 03416 ECReleaseEditDC(ped, hdc, TRUE); 03417 xposition = pt.x; 03418 03419 // Remember, MLIchToXYPos returns coordinates with respect to the 03420 // top left pixel displayed on the screen. Thus, if xPosition < 0, 03421 // it means xPosition is less than current ped->xOffset. 03422 03423 iFmtWidth /= 3; 03424 if (fHScroll = (xposition < ped->rcFmt.left)) 03425 // scroll to the left 03426 iAmt = ped->rcFmt.left + iFmtWidth; 03427 else if (fHScroll = (xposition > ped->rcFmt.right)) 03428 // scroll to the right 03429 iAmt = ped->rcFmt.right - iFmtWidth; 03430 03431 if (fHScroll) 03432 MLScroll(ped, FALSE, EM_LINESCROLL, (xposition - iAmt) / ped->aveCharWidth, TRUE); 03433 } 03434 } 03435 return(fVScroll); 03436 } 03437 03438 /***************************************************************************\ 03439 * MLEditWndProc 03440 * 03441 * Class procedure for all multi line edit controls. 03442 * Dispatches all messages to the appropriate handlers which are named 03443 * as follows: 03444 * SL (single line) prefixes all single line edit control procedures while 03445 * EC (edit control) prefixes all common handlers. 03446 * 03447 * The MLEditWndProc only handles messages specific to multi line edit 03448 * controls. 03449 * 03450 * WARNING: If you add a message here, add it to gawEditWndProc[] in 03451 * kernel\server.c too, otherwise EditWndProcA/W will send it straight to 03452 * DefWindowProcWorker 03453 * 03454 * History: 03455 \***************************************************************************/ 03456 03457 LRESULT MLEditWndProc( 03458 HWND hwnd, 03459 PED ped, 03460 UINT message, 03461 WPARAM wParam, 03462 LPARAM lParam) 03463 { 03464 HDC hdc; 03465 PAINTSTRUCT ps; 03466 LPRECT lprc; 03467 POINT pt; 03468 DWORD windowstyle; 03469 03470 switch (message) { 03471 03472 case WM_INPUTLANGCHANGE: 03473 if (ped && ped->fFocus && ped->pLpkEditCallout) { 03474 NtUserHideCaret(hwnd); 03475 hdc = ECGetEditDC(ped, TRUE); 03476 NtUserDestroyCaret(); 03477 ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(), ped->lineHeight, (UINT)lParam); 03478 MLSetCaretPosition(ped, hdc); 03479 ECReleaseEditDC(ped, hdc, TRUE); 03480 NtUserShowCaret(hwnd); 03481 } 03482 goto PassToDefaultWindowProc; 03483 03484 03485 case WM_STYLECHANGED: 03486 if (ped && ped->pLpkEditCallout) { 03487 switch (wParam) { 03488 03489 case GWL_STYLE: 03490 ECUpdateFormat(ped, 03491 ((LPSTYLESTRUCT)lParam)->styleNew, 03492 GetWindowLong(ped->hwnd, GWL_EXSTYLE)); 03493 return 1L; 03494 03495 case GWL_EXSTYLE: 03496 ECUpdateFormat(ped, 03497 GetWindowLong(ped->hwnd, GWL_STYLE), 03498 ((LPSTYLESTRUCT)lParam)->styleNew); 03499 return 1L; 03500 } 03501 } 03502 03503 goto PassToDefaultWindowProc; 03504 03505 case WM_CHAR: 03506 03507 /* 03508 * wParam - the value of the key 03509 * lParam - modifiers, repeat count etc (not used) 03510 */ 03511 MLChar(ped, (UINT)wParam, 0); 03512 break; 03513 03514 case WM_ERASEBKGND: { 03515 HBRUSH hbr; 03516 03517 // USE SAME RULES AS IN ECGetBrush() 03518 if (ped->f40Compat && 03519 (ped->fReadOnly || ped->fDisabled)) 03520 hbr = (HBRUSH) CTLCOLOR_STATIC; 03521 else 03522 hbr = (HBRUSH) CTLCOLOR_EDIT; 03523 03524 FillWindow(ped->hwndParent, hwnd, (HDC)wParam, hbr); 03525 } 03526 return ((LONG)TRUE); 03527 03528 case WM_GETDLGCODE: { 03529 LONG code = DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS | DLGC_WANTALLKEYS; 03530 03531 /* 03532 ** !!! JEFFBOG HACK !!! 03533 ** Only set Dialog Box Flag if GETDLGCODE message is generated by 03534 ** IsDialogMessage -- if so, the lParam will be a pointer to the 03535 ** message structure passed to IsDialogMessage; otherwise, lParam 03536 ** will be NULL. Reason for the HACK alert: the wParam & lParam 03537 ** for GETDLGCODE is still not clearly defined and may end up 03538 ** changing in a way that would throw this off 03539 ** 03540 */ 03541 if (lParam) 03542 ped->fInDialogBox = TRUE; // Mark ML edit ctrl as in a dialog box 03543 03544 /* 03545 ** If this is a WM_SYSCHAR message generated by the UNDO keystroke 03546 ** we want this message so we can EAT IT in "case WM_SYSCHAR:" 03547 */ 03548 if (lParam && (((LPMSG)lParam)->message == WM_SYSCHAR) && 03549 ((DWORD)((LPMSG)lParam)->lParam & SYS_ALTERNATE) && 03550 ((WORD)wParam == VK_BACK)) 03551 code |= DLGC_WANTMESSAGE; 03552 return code; 03553 } 03554 03555 case EM_SCROLL: 03556 message = WM_VSCROLL; 03557 03558 /* 03559 * FALL THROUGH 03560 */ 03561 case WM_HSCROLL: 03562 case WM_VSCROLL: 03563 return MLScroll(ped, (message==WM_VSCROLL), LOWORD(wParam), HIWORD(wParam), TRUE); 03564 03565 case WM_MOUSEWHEEL: 03566 /* 03567 * Don't handle zoom and datazoom. 03568 */ 03569 if (wParam & (MK_SHIFT | MK_CONTROL)) { 03570 goto PassToDefaultWindowProc; 03571 } 03572 03573 gcWheelDelta -= (short) HIWORD(wParam); 03574 windowstyle = ped->pwnd->style; 03575 if ( abs(gcWheelDelta) >= WHEEL_DELTA && 03576 gpsi->ucWheelScrollLines > 0 && 03577 (windowstyle & (WS_VSCROLL | WS_HSCROLL))) { 03578 03579 int cLineScroll; 03580 BOOL fVert; 03581 int cPage; 03582 03583 if (windowstyle & WS_VSCROLL) { 03584 fVert = TRUE; 03585 cPage = ped->ichLinesOnScreen; 03586 } else { 03587 fVert = FALSE; 03588 cPage = (ped->rcFmt.right - ped->rcFmt.left) / ped->aveCharWidth; 03589 } 03590 03591 /* 03592 * Limit a roll of one (1) WHEEL_DELTA to scroll one (1) page. 03593 */ 03594 cLineScroll = (int) min( 03595 (UINT) (max(1, (cPage - 1))), 03596 gpsi->ucWheelScrollLines); 03597 03598 cLineScroll *= (gcWheelDelta / WHEEL_DELTA); 03599 UserAssert(cLineScroll != 0); 03600 gcWheelDelta = gcWheelDelta % WHEEL_DELTA; 03601 MLScroll(ped, fVert, EM_LINESCROLL, cLineScroll, TRUE); 03602 } 03603 03604 break; 03605 03606 case WM_KEYDOWN: 03607 03608 /* 03609 * wParam - virt keycode of the given key 03610 * lParam - modifiers such as repeat count etc. (not used) 03611 */ 03612 MLKeyDown(ped, (UINT)wParam, 0); 03613 break; 03614 03615 case WM_KILLFOCUS: 03616 03617 /* 03618 * wParam - handle of the window that receives the input focus 03619 * lParam - not used 03620 */ 03621 MLKillFocus(ped); 03622 break; 03623 03624 case WM_CAPTURECHANGED: 03625 // 03626 // wParam -- unused 03627 // lParam -- hwnd of window gaining capture. 03628 // 03629 if (ped->fMouseDown) { 03630 // 03631 // We don't change the caret pos here. If this is happening 03632 // due to button up, then we'll change the pos in the 03633 // handler after ReleaseCapture(). Otherwise, just end 03634 // gracefully because someone else has stolen capture out 03635 // from under us. 03636 // 03637 03638 ped->fMouseDown = FALSE; 03639 NtUserKillSystemTimer(ped->hwnd, IDSYS_SCROLL); 03640 } 03641 break; 03642 03643 case WM_SYSTIMER: 03644 03645 /* 03646 * This allows us to automatically scroll if the user holds the mouse 03647 * outside the edit control window. We simulate mouse moves at timer 03648 * intervals set in MouseMotionHandler. 03649 */ 03650 if (ped->fMouseDown) 03651 MLMouseMotion(ped, WM_MOUSEMOVE, ped->prevKeys, &ped->ptPrevMouse); 03652 break; 03653 03654 case WM_MBUTTONDOWN: 03655 EnterReaderModeHelper(ped->hwnd); 03656 break; 03657 03658 case WM_MOUSEMOVE: 03659 UserAssert(ped->fMouseDown); 03660 03661 /* 03662 * FALL THROUGH 03663 */ 03664 case WM_LBUTTONDBLCLK: 03665 case WM_LBUTTONDOWN: 03666 case WM_LBUTTONUP: 03667 /* 03668 * wParam - contains a value that indicates which virtual keys are down 03669 lParam - contains x and y coords of the mouse cursor 03670 */ 03671 POINTSTOPOINT(pt, lParam); 03672 MLMouseMotion(ped, message, (UINT)wParam, &pt); 03673 break; 03674 03675 case WM_CREATE: 03676 03677 /* 03678 * wParam - handle to window being created 03679 * lParam - points to a CREATESTRUCT that contains copies of parameters 03680 * passed to the CreateWindow function. 03681 */ 03682 return (MLCreate(ped, (LPCREATESTRUCT)lParam)); 03683 03684 case WM_PRINTCLIENT: 03685 MLPaint(ped, (HDC) wParam, NULL); 03686 break; 03687 03688 case WM_PAINT: 03689 /* 03690 * wParam - can be hdc from subclassed paint 03691 lParam - not used 03692 */ 03693 if (wParam) { 03694 hdc = (HDC) wParam; 03695 lprc = NULL; 03696 } else { 03697 hdc = NtUserBeginPaint(ped->hwnd, &ps); 03698 lprc = &ps.rcPaint; 03699 } 03700 03701 if (_IsWindowVisible(ped->pwnd)) 03702 MLPaint(ped, hdc, lprc); 03703 03704 if (!wParam) 03705 NtUserEndPaint(ped->hwnd, &ps); 03706 break; 03707 03708 case WM_PASTE: 03709 03710 /* 03711 * wParam - not used 03712 lParam - not used 03713 */ 03714 if (!ped->fReadOnly) 03715 MLPasteText(ped); 03716 break; 03717 03718 case WM_SETFOCUS: 03719 03720 /* 03721 * wParam - handle of window that loses the input focus (may be NULL) 03722 lParam - not used 03723 */ 03724 MLSetFocus(ped); 03725 break; 03726 03727 case WM_SIZE: 03728 03729 /* 03730 * wParam - defines the type of resizing fullscreen, sizeiconic, 03731 sizenormal etc. 03732 lParam - new width in LOWORD, new height in HIGHWORD of client area 03733 */ 03734 ECSize(ped, NULL, TRUE); 03735 break; 03736 03737 case EM_FMTLINES: 03738 03739 /* 03740 * wParam - indicates disposition of end-of-line chars. If non 03741 * zero, the chars CR CR LF are placed at the end of a word 03742 * wrapped line. If wParam is zero, the end of line chars are 03743 * removed. This is only done when the user gets a handle (via 03744 * EM_GETHANDLE) to the text. lParam - not used. 03745 */ 03746 if (wParam) 03747 MLInsertCrCrLf(ped); 03748 else 03749 MLStripCrCrLf(ped); 03750 MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL); 03751 return (LONG)(wParam != 0); 03752 03753 case EM_GETHANDLE: 03754 03755 /* 03756 * wParam - not used 03757 lParam - not used 03758 */ 03759 03760 /* 03761 * Returns a handle to the edit control's text. 03762 */ 03763 03764 /* 03765 * Null terminate the string. Note that we are guaranteed to have the 03766 * memory for the NULL since ECInsertText allocates an extra 03767 * WCHAR for the NULL terminator. 03768 */ 03769 03770 if (ped->fAnsi) 03771 *(ECLock(ped) + ped->cch) = 0; 03772 else 03773 *((LPWSTR)ECLock(ped) + ped->cch) = 0; 03774 ECUnlock(ped); 03775 return ((LRESULT)ped->hText); 03776 03777 case EM_GETLINE: 03778 03779 /* 03780 * wParam - line number to copy (0 is first line) 03781 * lParam - buffer to copy text to. First WORD is max # of bytes to 03782 * copy 03783 */ 03784 return MLGetLine(ped, (ICH)wParam, (ICH)*(WORD UNALIGNED *)lParam, (LPSTR)lParam); 03785 03786 case EM_LINEFROMCHAR: 03787 03788 /* 03789 * wParam - Contains the index value for the desired char in the text 03790 * of the edit control. These are 0 based. 03791 * lParam - not used 03792 */ 03793 return (LRESULT)MLIchToLine(ped, (ICH)wParam); 03794 03795 case EM_LINEINDEX: 03796 03797 /* 03798 * wParam - specifies the desired line number where the number of the 03799 * first line is 0. If linenumber = 0, the line with the caret is used. 03800 * lParam - not used. 03801 * This function return s the number of character positions that occur 03802 * preceeding the first char in a given line. 03803 */ 03804 return (LRESULT)MLLineIndex(ped, (ICH)wParam); 03805 03806 case EM_LINELENGTH: 03807 03808 /* 03809 * wParam - specifies the character index of a character in the 03810 specified line, where the first line is 0. If -1, the length 03811 of the current line (with the caret) is return ed not including the 03812 length of any selected text. 03813 lParam - not used 03814 */ 03815 return (LRESULT)MLLineLength(ped, (ICH)wParam); 03816 03817 case EM_LINESCROLL: 03818 03819 /* 03820 * wParam - not used 03821 lParam - Contains the number of lines and char positions to scroll 03822 */ 03823 MLScroll(ped, TRUE, EM_LINESCROLL, (INT)lParam, TRUE); 03824 MLScroll(ped, FALSE, EM_LINESCROLL, (INT)wParam, TRUE); 03825 break; 03826 03827 case EM_REPLACESEL: 03828 03829 /* 03830 * wParam - flag for 4.0+ apps saying whether to clear undo 03831 lParam - Points to a null terminated replacement text. 03832 */ 03833 MLReplaceSel(ped, (LPSTR)lParam); 03834 if (!ped->f40Compat || !wParam) 03835 ECEmptyUndo(Pundo(ped)); 03836 break; 03837 03838 case EM_SETHANDLE: 03839 03840 /* 03841 * wParam - contains a handle to the text buffer 03842 lParam - not used 03843 */ 03844 MLSetHandle(ped, (HANDLE)wParam); 03845 break; 03846 03847 case EM_SETRECT: 03848 case EM_SETRECTNP: 03849 03850 // 03851 // wParamLo -- not used 03852 // lParam -- LPRECT with new formatting area 03853 // 03854 ECSize(ped, (LPRECT) lParam, (message != EM_SETRECTNP)); 03855 break; 03856 03857 case EM_SETSEL: 03858 03859 /* 03860 * wParam - Under 3.1, specifies if we should scroll caret into 03861 * view or not. 0 == scroll into view. 1 == don't scroll 03862 * lParam - starting pos in lowword ending pos in high word 03863 * 03864 * Under Win32, wParam is the starting pos, lParam is the 03865 * ending pos, and the caret is not scrolled into view. 03866 * The message EM_SCROLLCARET forces the caret to be scrolled 03867 * into view. 03868 */ 03869 MLSetSelection(ped, TRUE, (ICH)wParam, (ICH)lParam); 03870 break; 03871 03872 case EM_SCROLLCARET: 03873 03874 /* 03875 * Scroll caret into view 03876 */ 03877 MLEnsureCaretVisible(ped); 03878 break; 03879 03880 case EM_GETFIRSTVISIBLELINE: 03881 03882 /* 03883 * Returns the first visible line for multiline edit controls. 03884 */ 03885 return (LONG)ped->ichScreenStart; 03886 03887 case WM_SYSKEYDOWN: 03888 if (((WORD)wParam == VK_BACK) && ((DWORD)lParam & SYS_ALTERNATE)) { 03889 SendMessage(ped->hwnd, EM_UNDO, 0, 0L); 03890 break; 03891 } 03892 goto PassToDefaultWindowProc; 03893 03894 case WM_UNDO: 03895 case EM_UNDO: 03896 return MLUndo(ped); 03897 03898 case EM_SETTABSTOPS: 03899 03900 /* 03901 * This sets the tab stop positions for multiline edit controls. 03902 * wParam - Number of tab stops 03903 * lParam - Far ptr to a UINT array containing the Tab stop positions 03904 */ 03905 return MLSetTabStops(ped, (int)wParam, (LPINT)lParam); 03906 03907 case EM_POSFROMCHAR: 03908 // 03909 // wParam -- char index in text 03910 // lParam -- not used 03911 // This function returns the (x,y) position of the character 03912 // 03913 case EM_CHARFROMPOS: 03914 // 03915 // wParam -- unused 03916 // lParam -- pt in client coordinates 03917 // This function returns 03918 // LOWORD: the position of the closest character 03919 // to the passed in point. Beware of 03920 // points not actually in the edit client... 03921 // HIWORD: the index of the line the char is on 03922 // 03923 { 03924 LONG xyPos; 03925 LONG line; 03926 03927 hdc = ECGetEditDC(ped, TRUE); 03928 03929 if (message == EM_POSFROMCHAR) { 03930 MLIchToXYPos(ped, hdc, (ICH)wParam, FALSE, &pt); 03931 xyPos = MAKELONG(pt.x, pt.y); 03932 } else { 03933 POINTSTOPOINT(pt, lParam); 03934 xyPos = MLMouseToIch(ped, hdc, &pt, &line); 03935 xyPos = MAKELONG(xyPos, line); 03936 } 03937 03938 ECReleaseEditDC(ped, hdc, TRUE); 03939 return((LRESULT)xyPos); 03940 break; 03941 } 03942 03943 case WM_SETREDRAW: 03944 DefWindowProcWorker(ped->pwnd, message, wParam, lParam, FALSE); 03945 if (wParam) { 03946 03947 /* 03948 * Backwards compatability hack needed so that winraid's edit 03949 * controls work fine. 03950 */ 03951 RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME); 03952 } 03953 break; 03954 03955 #if LATER 03956 case WM_IME_ENDCOMPOSITION: 03957 ECInOutReconversionMode(ped, FALSE); 03958 break; 03959 #endif 03960 03961 default: 03962 PassToDefaultWindowProc: 03963 return DefWindowProcWorker(ped->pwnd, message, wParam, lParam, ped->fAnsi); 03964 } 03965 03966 return 1L; 03967 } /* MLEditWndProc */ 03968 03969 03970 /***************************************************************************\ 03971 * MLDrawText AorW 03972 * 03973 * This function draws all the characters between ichStart and ichEnd for 03974 * the given Multiline Edit Control. 03975 * 03976 * This function divides the block of text between ichStart and ichEnd 03977 * into lines and each line into strips of text based on the selection 03978 * attributes. It calls ECTabTheTextOut() to draw each strip. 03979 * This takes care of the Negative A anc C widths of the current font, if 03980 * it has any, on either side of each strip of text. 03981 * 03982 * NOTE: If the language pack is loaded the text is not divided into strips, 03983 * nor is selection highlighting performed here. Whole lines are passed 03984 * to the language pack to display with tab expansion and selection 03985 * highlighting. (Since the language pack supports scripts with complex 03986 * character re-ordering rules, only it can do this). 03987 * 03988 * History: 03989 \***************************************************************************/ 03990 03991 void MLDrawText( 03992 PED ped, 03993 HDC hdc, 03994 ICH ichStart, 03995 ICH ichEnd, 03996 BOOL fSelChange) 03997 { 03998 DWORD textColorSave; 03999 DWORD bkColorSave; 04000 PSTR pText; 04001 UINT wCurLine; 04002 UINT wEndLine; 04003 int xOffset; 04004 ICH LengthToDraw; 04005 ICH CurStripLength; 04006 ICH ichAttrib, ichNewStart; 04007 ICH ExtraLengthForNegA; 04008 ICH ichT; 04009 int iRemainingLengthInLine; 04010 int xStPos, xClipStPos, xClipEndPos, yPos; 04011 BOOL fFirstLineOfBlock = TRUE; 04012 BOOL fDrawEndOfLineStrip = FALSE; 04013 BOOL fDrawOnSameLine = FALSE; 04014 BOOL fSelected = FALSE; 04015 BOOL fLineBegins = FALSE; 04016 STRIPINFO NegCInfo; 04017 POINT pt; 04018 04019 // 04020 // Just return if nothing to draw 04021 if (!ped->ichLinesOnScreen) 04022 return; 04023 04024 ECGetBrush(ped, hdc); 04025 04026 // 04027 // Adjust the value of ichStart such that we need to draw only those lines 04028 // visible on the screen. 04029 // 04030 if ((UINT)ichStart < (UINT)ped->chLines[ped->ichScreenStart]) { 04031 ichStart = ped->chLines[ped->ichScreenStart]; 04032 if (ichStart > ichEnd) 04033 return; 04034 } 04035 04036 // Adjust the value of ichEnd such that we need to draw only those lines 04037 // visible on the screen. 04038 wCurLine = min(ped->ichScreenStart+ped->ichLinesOnScreen,ped->cLines-1); 04039 ichT = ped->chLines[wCurLine] + MLLine(ped, wCurLine); 04040 ichEnd = min(ichEnd, ichT); 04041 04042 wCurLine = MLIchToLine(ped, ichStart); // Starting line. 04043 wEndLine = MLIchToLine(ped, ichEnd); // Ending line. 04044 04045 UserAssert(ped->chLines[wCurLine] <= ped->cch + 1); 04046 UserAssert(ped->chLines[wEndLine] <= ped->cch + 1); 04047 04048 if (fSelChange && (GetBkMode(hdc) != OPAQUE)) 04049 { 04050 /* 04051 * if changing selection on a transparent edit control, just 04052 * draw those lines from scratch 04053 */ 04054 RECT rcStrip; 04055 CopyRect(&rcStrip, &ped->rcFmt); 04056 rcStrip.left -= ped->wLeftMargin; 04057 if (ped->pLpkEditCallout) { 04058 rcStrip.right += ped->wRightMargin; 04059 } 04060 rcStrip.top += (wCurLine - ped->ichScreenStart) * ped->lineHeight; 04061 rcStrip.bottom = rcStrip.top + ((wEndLine - wCurLine) + 1) * ped->lineHeight; 04062 NtUserInvalidateRect(ped->hwnd, &rcStrip, TRUE); 04063 return; 04064 } 04065 04066 // If it is either centered or right-justified, then draw the whole lines. 04067 // Also draw whole lines if the language pack is handling line layout. 04068 if ((ped->format != ES_LEFT) || (ped->pLpkEditCallout)) { 04069 ichStart = ped->chLines[wCurLine]; 04070 ichEnd = ped->chLines[wEndLine] + MLLine(ped, wEndLine); 04071 } 04072 04073 pText = ECLock(ped); 04074 04075 NtUserHideCaret(ped->hwnd); 04076 04077 // 04078 // If ichStart stays on Second byte of DBCS, we have to 04079 // adjust it. LiZ -- 5/5/93 04080 // 04081 if (ped->fAnsi && ped->fDBCS) { 04082 ichStart = ECAdjustIch( ped, pText, ichStart ); 04083 } 04084 UserAssert(ichStart <= ped->cch); 04085 UserAssert(ichEnd <= ped->cch); 04086 04087 while (ichStart <= ichEnd) { 04088 // Pass whole lines to the language pack to display with selection 04089 // marking and tab expansion. 04090 if (ped->pLpkEditCallout) { 04091 ped->pLpkEditCallout->EditDrawText( 04092 ped, hdc, pText + ped->cbChar*ichStart, 04093 MLLine(ped, wCurLine), 04094 (INT)ped->ichMinSel - (INT)ichStart, (INT)ped->ichMaxSel - (INT)ichStart, 04095 MLIchToYPos(ped, ichStart, FALSE)); 04096 } else { 04097 // xStPos: The starting Position where the string must be drawn. 04098 // xClipStPos: The starting position for the clipping rect for the block. 04099 // xClipEndPos: The ending position for the clipping rect for the block. 04100 04101 // Calculate the xyPos of starting point of the block. 04102 MLIchToXYPos(ped, hdc, ichStart, FALSE, &pt); 04103 xClipStPos = xStPos = pt.x; 04104 yPos = pt.y; 04105 04106 // The attributes of the block is the same as that of ichStart. 04107 ichAttrib = ichStart; 04108 04109 // If the current font has some negative C widths and if this is the 04110 // begining of a block, we must start drawing some characters before the 04111 // block to account for the negative C widths of the strip before the 04112 // current strip; In this case, reset ichStart and xStPos. 04113 04114 if (fFirstLineOfBlock && ped->wMaxNegC) { 04115 fFirstLineOfBlock = FALSE; 04116 ichNewStart = max(((int)(ichStart - ped->wMaxNegCcharPos)), ((int)ped->chLines[wCurLine])); 04117 04118 // If ichStart needs to be changed, then change xStPos also accordingly. 04119 if (ichNewStart != ichStart) { 04120 if (ped->fAnsi && ped->fDBCS) { 04121 // 04122 // Adjust DBCS alignment... 04123 // 04124 ichNewStart = ECAdjustIchNext( ped, pText, ichNewStart ); 04125 } 04126 MLIchToXYPos(ped, hdc, ichStart = ichNewStart, FALSE, &pt); 04127 xStPos = pt.x; 04128 } 04129 } 04130 04131 // Calc the number of characters remaining to be drawn in the current line. 04132 iRemainingLengthInLine = MLLine(ped, wCurLine) - 04133 (ichStart - ped->chLines[wCurLine]); 04134 04135 // If this is the last line of a block, we may not have to draw all the 04136 // remaining lines; We must draw only upto ichEnd. 04137 if (wCurLine == wEndLine) 04138 LengthToDraw = ichEnd - ichStart; 04139 else 04140 LengthToDraw = iRemainingLengthInLine; 04141 04142 // Find out how many pixels we indent the line for non-left-justified 04143 // formats 04144 if (ped->format != ES_LEFT) 04145 xOffset = MLCalcXOffset(ped, hdc, wCurLine); 04146 else 04147 xOffset = -((int)(ped->xOffset)); 04148 04149 // Check if this is the begining of a line. 04150 if (ichAttrib == ped->chLines[wCurLine]) { 04151 fLineBegins = TRUE; 04152 xClipStPos = ped->rcFmt.left - ped->wLeftMargin; 04153 } 04154 04155 // 04156 // The following loop divides this 'wCurLine' into strips based on the 04157 // selection attributes and draw them strip by strip. 04158 do { 04159 // 04160 // If ichStart is pointing at CRLF or CRCRLF, then iRemainingLength 04161 // could have become negative because MLLine does not include 04162 // CR and LF at the end of a line. 04163 // 04164 if (iRemainingLengthInLine < 0) // If Current line is completed, 04165 break; // go on to the next line. 04166 04167 // 04168 // Check if a part of the block is selected and if we need to 04169 // show it with a different attribute. 04170 // 04171 if (!(ped->ichMinSel == ped->ichMaxSel || 04172 ichAttrib >= ped->ichMaxSel || 04173 ichEnd < ped->ichMinSel || 04174 (!ped->fNoHideSel && !ped->fFocus))) { 04175 // 04176 // OK! There is a selection somewhere in this block! 04177 // Check if this strip has selection attribute. 04178 // 04179 if (ichAttrib < ped->ichMinSel) { 04180 fSelected = FALSE; // This strip is not selected 04181 04182 // Calculate the length of this strip with normal attribute. 04183 CurStripLength = min(ichStart+LengthToDraw, ped->ichMinSel)-ichStart; 04184 fLineBegins = FALSE; 04185 } else { 04186 // The current strip has the selection attribute. 04187 if (fLineBegins) { // Is it the first part of a line? 04188 // Then, draw the left margin area with normal attribute. 04189 fSelected = FALSE; 04190 CurStripLength = 0; 04191 xClipStPos = ped->rcFmt.left - ped->wLeftMargin; 04192 fLineBegins = FALSE; 04193 } else { 04194 // Else, draw the strip with selection attribute. 04195 fSelected = TRUE; 04196 CurStripLength = min(ichStart+LengthToDraw, ped->ichMaxSel)-ichStart; 04197 04198 // Select in the highlight colors. 04199 bkColorSave = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); 04200 if (!ped->fDisabled) 04201 textColorSave = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); 04202 } 04203 } 04204 } else { 04205 // The whole strip has no selection attributes. 04206 CurStripLength = LengthToDraw; 04207 } 04208 04209 // 04210 // Other than the current strip, do we still have anything 04211 // left to be drawn in the current line? 04212 // 04213 fDrawOnSameLine = (LengthToDraw != CurStripLength); 04214 04215 // 04216 // When we draw this strip, we need to draw some more characters 04217 // beyond the end of this strip to account for the negative A 04218 // widths of the characters that follow this strip. 04219 // 04220 ExtraLengthForNegA = min(iRemainingLengthInLine-CurStripLength, ped->wMaxNegAcharPos); 04221 04222 // 04223 // The blank strip at the end of the line needs to be drawn with 04224 // normal attribute irrespective of whether the line has selection 04225 // attribute or not. Hence, if the last strip of the line has selection 04226 // attribute, then this blank strip needs to be drawn separately. 04227 // Else, we can draw the blank strip along with the last strip. 04228 // 04229 04230 // Is this the last strip of the current line? 04231 if (iRemainingLengthInLine == (int)CurStripLength) { 04232 if (fSelected) { // Does this strip have selection attribute? 04233 // Then we need to draw the end of line strip separately. 04234 fDrawEndOfLineStrip = TRUE; // Draw the end of line strip. 04235 MLIchToXYPos(ped, hdc, ichStart+CurStripLength, TRUE, &pt); 04236 xClipEndPos = pt.x; 04237 } else { 04238 // 04239 // Set the xClipEndPos to a big value sothat the blank 04240 // strip will be drawn automatically when the last strip 04241 // is drawn. 04242 // 04243 xClipEndPos = MAXCLIPENDPOS; 04244 } 04245 } else { 04246 // 04247 // This is not the last strip of this line; So, set the ending 04248 // clip position accurately. 04249 // 04250 MLIchToXYPos(ped, hdc, ichStart+CurStripLength, FALSE, &pt); 04251 xClipEndPos = pt.x; 04252 } 04253 04254 // 04255 // Draw the current strip starting from xStPos, clipped to the area 04256 // between xClipStPos and xClipEndPos. Obtain "NegCInfo" and use it 04257 // in drawing the next strip. 04258 // 04259 ECTabTheTextOut(hdc, xClipStPos, xClipEndPos, 04260 xStPos, yPos, (LPSTR)(pText+ichStart*ped->cbChar), 04261 CurStripLength+ExtraLengthForNegA, ichStart, ped, 04262 ped->rcFmt.left+xOffset, fSelected ? ECT_SELECTED : ECT_NORMAL, &NegCInfo); 04263 04264 if (fSelected) { 04265 // 04266 // If this strip was selected, then the next strip won't have 04267 // selection attribute 04268 // 04269 fSelected = FALSE; 04270 SetBkColor(hdc, bkColorSave); 04271 if (!ped->fDisabled) 04272 SetTextColor(hdc, textColorSave); 04273 } 04274 04275 // Do we have one more strip to draw on the current line? 04276 if (fDrawOnSameLine || fDrawEndOfLineStrip) { 04277 int iLastDrawnLength; 04278 04279 // 04280 // Next strip's attribute is decided based on the char at ichAttrib 04281 // 04282 ichAttrib = ichStart + CurStripLength; 04283 04284 // 04285 // When drawing the next strip, start at a few chars before 04286 // the actual start to account for the Neg 'C' of the strip 04287 // just drawn. 04288 // 04289 iLastDrawnLength = CurStripLength +ExtraLengthForNegA - NegCInfo.nCount; 04290 // 04291 // Adjust DBCS alignment... 04292 // 04293 if (ped->fAnsi && ped->fDBCS) { 04294 ichNewStart = ECAdjustIch(ped,pText,ichStart+iLastDrawnLength); 04295 iLastDrawnLength = ichNewStart - ichStart; 04296 ichStart = ichNewStart; 04297 } else { 04298 ichStart += iLastDrawnLength; 04299 } 04300 LengthToDraw -= iLastDrawnLength; 04301 iRemainingLengthInLine -= iLastDrawnLength; 04302 04303 // 04304 // The start of clip rect for the next strip. 04305 // 04306 xStPos = NegCInfo.XStartPos; 04307 xClipStPos = xClipEndPos; 04308 } 04309 04310 // Draw the blank strip at the end of line seperately, if required. 04311 if (fDrawEndOfLineStrip) { 04312 ECTabTheTextOut(hdc, xClipStPos, MAXCLIPENDPOS, xStPos, yPos, 04313 (LPSTR)(pText+ichStart*ped->cbChar), LengthToDraw, ichStart, 04314 ped, ped->rcFmt.left+xOffset, ECT_NORMAL, &NegCInfo); 04315 04316 fDrawEndOfLineStrip = FALSE; 04317 } 04318 } 04319 while(fDrawOnSameLine); // do while loop ends here. 04320 } 04321 04322 // Let us move on to the next line of this block to be drawn. 04323 wCurLine++; 04324 if (ped->cLines > wCurLine) 04325 ichStart = ped->chLines[wCurLine]; 04326 else 04327 ichStart = ichEnd+1; // We have reached the end of the text. 04328 } // while loop ends here 04329 04330 ECUnlock(ped); 04331 04332 NtUserShowCaret(ped->hwnd); 04333 MLSetCaretPosition(ped, hdc); 04334 }

Generated on Sat May 15 19:39:48 2004 for test by doxygen 1.3.7