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

edmlrare.c

Go to the documentation of this file.
00001 /****************************************************************************\ 00002 * edmlRare.c - Edit controls Routines Called rarely are to be 00003 * put in a seperate segment _EDMLRare. This file contains 00004 * these routines. 00005 * 00006 * Copyright (c) 1985 - 1999, Microsoft Corporation 00007 * 00008 * Multi-Line Support Routines called Rarely 00009 \****************************************************************************/ 00010 00011 #include "precomp.h" 00012 #pragma hdrstop 00013 00014 /***************************************************************************\ 00015 * MLInsertCrCrLf AorW 00016 * 00017 * Inserts CR CR LF characters into the text at soft (word-wrap) line 00018 * breaks. CR LF (hard) line breaks are unaffected. Assumes that the text 00019 * has already been formatted ie. ped->chLines is where we want the line 00020 * breaks to occur. Note that ped->chLines is not updated to reflect the 00021 * movement of text by the addition of CR CR LFs. Returns TRUE if successful 00022 * else notify parent and return FALSE if the memory couldn't be allocated. 00023 * 00024 * History: 00025 \***************************************************************************/ 00026 00027 BOOL MLInsertCrCrLf( 00028 PED ped) 00029 { 00030 ICH dch; 00031 ICH li; 00032 ICH lineSize; 00033 unsigned char *pchText; 00034 unsigned char *pchTextNew; 00035 00036 if (!ped->fWrap || !ped->cch) { 00037 00038 /* 00039 * There are no soft line breaks if word-wrapping is off or if no chars 00040 */ 00041 return TRUE; 00042 } 00043 00044 /* 00045 * Calc an upper bound on the number of additional characters we will be 00046 * adding to the text when we insert CR CR LFs. 00047 */ 00048 dch = 3 * ped->cLines; 00049 00050 if (!LOCALREALLOC(ped->hText, (ped->cch + dch) * ped->cbChar, 0, ped->hInstance, NULL)) { 00051 ECNotifyParent(ped, EN_ERRSPACE); 00052 return FALSE; 00053 } 00054 00055 ped->cchAlloc = ped->cch + dch; 00056 00057 /* 00058 * Move the text up dch bytes and then copy it back down, inserting the CR 00059 * CR LF's as necessary. 00060 */ 00061 pchTextNew = pchText = ECLock(ped); 00062 pchText += dch * ped->cbChar; 00063 00064 /* 00065 * We will use dch to keep track of how many chars we add to the text 00066 */ 00067 dch = 0; 00068 00069 /* 00070 * Copy the text up dch bytes to pchText. This will shift all indices in 00071 * ped->chLines up by dch bytes. 00072 */ 00073 memmove(pchText, pchTextNew, ped->cch * ped->cbChar); 00074 00075 /* 00076 * Now copy chars from pchText down to pchTextNew and insert CRCRLF at soft 00077 * line breaks. 00078 */ 00079 if (ped->fAnsi) { 00080 for (li = 0; li < ped->cLines - 1; li++) { 00081 lineSize = ped->chLines[li + 1] - ped->chLines[li]; 00082 memmove(pchTextNew, pchText, lineSize); 00083 pchTextNew += lineSize; 00084 pchText += lineSize; 00085 00086 /* 00087 * If last character in newly copied line is not a line feed, then we 00088 * need to add the CR CR LF triple to the end 00089 */ 00090 if (*(pchTextNew - 1) != 0x0A) { 00091 *pchTextNew++ = 0x0D; 00092 *pchTextNew++ = 0x0D; 00093 *pchTextNew++ = 0x0A; 00094 dch += 3; 00095 } 00096 } 00097 00098 /* 00099 * Now move the last line up. It won't have any line breaks in it... 00100 */ 00101 memmove(pchTextNew, pchText, ped->cch - ped->chLines[ped->cLines - 1]); 00102 } else { 00103 LPWSTR pwchTextNew = (LPWSTR)pchTextNew; 00104 00105 for (li = 0; li < ped->cLines - 1; li++) { 00106 lineSize = ped->chLines[li + 1] - ped->chLines[li]; 00107 memmove(pwchTextNew, pchText, lineSize * sizeof(WCHAR)); 00108 pwchTextNew += lineSize; 00109 pchText += lineSize * sizeof(WCHAR); 00110 00111 /* 00112 * If last character in newly copied line is not a line feed, then we 00113 * need to add the CR CR LF triple to the end 00114 */ 00115 if (*(pwchTextNew - 1) != 0x0A) { 00116 *pwchTextNew++ = 0x0D; 00117 *pwchTextNew++ = 0x0D; 00118 *pwchTextNew++ = 0x0A; 00119 dch += 3; 00120 } 00121 } 00122 00123 /* 00124 * Now move the last line up. It won't have any line breaks in it... 00125 */ 00126 memmove(pwchTextNew, pchText, 00127 (ped->cch - ped->chLines[ped->cLines - 1]) * sizeof(WCHAR)); 00128 } 00129 00130 ECUnlock(ped); 00131 00132 if (dch) { 00133 /* 00134 * Update number of characters in text handle 00135 */ 00136 ped->cch += dch; 00137 00138 /* 00139 * So that the next time we do anything with the text, we can strip the 00140 * CRCRLFs 00141 */ 00142 ped->fStripCRCRLF = TRUE; 00143 return TRUE; 00144 } 00145 00146 return FALSE; 00147 } 00148 00149 /***************************************************************************\ 00150 * MLStripCrCrLf AorW 00151 * 00152 * Strips the CR CR LF character combination from the text. This 00153 * shows the soft (word wrapped) line breaks. CR LF (hard) line breaks are 00154 * unaffected. 00155 * 00156 * History: 00157 \***************************************************************************/ 00158 00159 void MLStripCrCrLf( 00160 PED ped) 00161 { 00162 if (ped->cch) { 00163 if (ped->fAnsi) { 00164 unsigned char *pchSrc; 00165 unsigned char *pchDst; 00166 unsigned char *pchLast; 00167 00168 pchSrc = pchDst = ECLock(ped); 00169 pchLast = pchSrc + ped->cch; 00170 while (pchSrc < pchLast) { 00171 if ( (pchSrc[0] == 0x0D) 00172 && (pchSrc[1] == 0x0D) 00173 && (pchSrc[2] == 0x0A) 00174 ) { 00175 pchSrc += 3; 00176 ped->cch -= 3; 00177 } else { 00178 *pchDst++ = *pchSrc++; 00179 } 00180 } 00181 } else { // !fAnsi 00182 LPWSTR pwchSrc; 00183 LPWSTR pwchDst; 00184 LPWSTR pwchLast; 00185 00186 pwchSrc = pwchDst = (LPWSTR)ECLock(ped); 00187 pwchLast = pwchSrc + ped->cch; 00188 while (pwchSrc < pwchLast) { 00189 if ( (pwchSrc[0] == 0x0D) 00190 && (pwchSrc[1] == 0x0D) 00191 && (pwchSrc[2] == 0x0A) 00192 ) { 00193 pwchSrc += 3; 00194 ped->cch -= 3; 00195 } else { 00196 *pwchDst++ = *pwchSrc++; 00197 } 00198 } 00199 } 00200 ECUnlock(ped); 00201 00202 /* 00203 * Make sure we don't have any values past the last character 00204 */ 00205 if (ped->ichCaret > ped->cch) 00206 ped->ichCaret = ped->cch; 00207 if (ped->ichMinSel > ped->cch) 00208 ped->ichMinSel = ped->cch; 00209 if (ped->ichMaxSel > ped->cch) 00210 ped->ichMaxSel = ped->cch; 00211 } 00212 } 00213 00214 /***************************************************************************\ 00215 * MLSetHandle AorW 00216 * 00217 * Sets the ped to contain the given handle. 00218 * 00219 * History: 00220 \***************************************************************************/ 00221 00222 void MLSetHandle( 00223 PED ped, 00224 HANDLE hNewText) 00225 { 00226 ICH newCch; 00227 00228 ped->cch = ped->cchAlloc = 00229 LOCALSIZE(ped->hText = hNewText, ped->hInstance) / ped->cbChar; 00230 ped->fEncoded = FALSE; 00231 00232 if (ped->cch) { 00233 00234 /* 00235 * We have to do it this way in case the app gives us a zero size handle 00236 */ 00237 if (ped->fAnsi) 00238 ped->cch = strlen(ECLock(ped)); 00239 else 00240 ped->cch = wcslen((LPWSTR)ECLock(ped)); 00241 ECUnlock(ped); 00242 } 00243 00244 newCch = (ICH)(ped->cch + CCHALLOCEXTRA); 00245 00246 /* 00247 * We do this LocalReAlloc in case the app changed the size of the handle 00248 */ 00249 if (LOCALREALLOC(ped->hText, newCch*ped->cbChar, 0, ped->hInstance, NULL)) 00250 ped->cchAlloc = newCch; 00251 00252 ECResetTextInfo(ped); 00253 } 00254 00255 /***************************************************************************\ 00256 * MLGetLine AorW 00257 * 00258 * Copies maxCchToCopy bytes of line lineNumber to the buffer 00259 * lpBuffer. The string is not zero terminated. 00260 * 00261 * Returns number of characters copied 00262 * 00263 * History: 00264 \***************************************************************************/ 00265 00266 LONG MLGetLine( 00267 PED ped, 00268 ICH lineNumber, //WASDWORD 00269 ICH maxCchToCopy, 00270 LPSTR lpBuffer) 00271 { 00272 PSTR pText; 00273 ICH cchLen; 00274 00275 if (lineNumber > ped->cLines - 1) { 00276 RIPERR1(ERROR_INVALID_PARAMETER, 00277 RIP_WARNING, 00278 "Invalid parameter \"lineNumber\" (%ld) to MLGetLine", 00279 lineNumber); 00280 00281 return 0L; 00282 } 00283 00284 cchLen = MLLine(ped, lineNumber); 00285 maxCchToCopy = min(cchLen, maxCchToCopy); 00286 00287 if (maxCchToCopy) { 00288 pText = ECLock(ped) + 00289 ped->chLines[lineNumber] * ped->cbChar; 00290 memmove(lpBuffer, pText, maxCchToCopy*ped->cbChar); 00291 ECUnlock(ped); 00292 } 00293 00294 return maxCchToCopy; 00295 } 00296 00297 /***************************************************************************\ 00298 * MLLineIndex AorW 00299 * 00300 * This function return s the number of character positions that occur 00301 * preceeding the first char in a given line. 00302 * 00303 * History: 00304 \***************************************************************************/ 00305 00306 ICH MLLineIndex( 00307 PED ped, 00308 ICH iLine) //WASINT 00309 { 00310 if (iLine == -1) 00311 iLine = ped->iCaretLine; 00312 if (iLine < ped->cLines) { 00313 return ped->chLines[iLine]; 00314 } else { 00315 RIPERR1(ERROR_INVALID_PARAMETER, 00316 RIP_WARNING, 00317 "Invalid parameter \"iLine\" (%ld) to MLLineIndex", 00318 iLine); 00319 00320 return (ICH)-1; 00321 } 00322 } 00323 00324 /***************************************************************************\ 00325 * MLLineLength AorW 00326 * 00327 * if ich = -1, return the length of the lines containing the current 00328 * selection but not including the selection. Otherwise, return the length of 00329 * the line containing ich. 00330 * 00331 * History: 00332 \***************************************************************************/ 00333 00334 ICH MLLineLength( 00335 PED ped, 00336 ICH ich) 00337 { 00338 ICH il1, il2; 00339 ICH temp; 00340 00341 if (ich != 0xFFFFFFFF) 00342 return (MLLine(ped, MLIchToLine(ped, ich))); 00343 00344 /* 00345 * Find length of lines corresponding to current selection 00346 */ 00347 il1 = MLIchToLine(ped, ped->ichMinSel); 00348 il2 = MLIchToLine(ped, ped->ichMaxSel); 00349 if (il1 == il2) 00350 return (MLLine(ped, il1) - (ped->ichMaxSel - ped->ichMinSel)); 00351 00352 temp = ped->ichMinSel - ped->chLines[il1]; 00353 temp += MLLine(ped, il2); 00354 temp -= (ped->ichMaxSel - ped->chLines[il2]); 00355 00356 return temp; 00357 } 00358 00359 /***************************************************************************\ 00360 * MLSetSelection AorW 00361 * 00362 * Sets the selection to the points given and puts the cursor at 00363 * ichMaxSel. 00364 * 00365 * History: 00366 \***************************************************************************/ 00367 00368 void MLSetSelection( 00369 PED ped, 00370 BOOL fDoNotScrollCaret, 00371 ICH ichMinSel, 00372 ICH ichMaxSel) 00373 { 00374 HDC hdc; 00375 00376 if (ichMinSel == 0xFFFFFFFF) { 00377 00378 /* 00379 * Set no selection if we specify -1 00380 */ 00381 ichMinSel = ichMaxSel = ped->ichCaret; 00382 } 00383 00384 /* 00385 * Since these are unsigned, we don't check if they are greater than 0. 00386 */ 00387 ichMinSel = min(ped->cch, ichMinSel); 00388 ichMaxSel = min(ped->cch, ichMaxSel); 00389 00390 #ifdef FE_SB // MLSetSelectionHander() 00391 // 00392 // To avoid position to half of DBCS, check and ajust position if necessary 00393 // 00394 // We check ped->fDBCS and ped->fAnsi though ECAdjustIch checks these bits 00395 // at first. We're worrying about the overhead of ECLock and ECUnlock. 00396 // 00397 if ( ped->fDBCS && ped->fAnsi ) { 00398 00399 PSTR pText; 00400 00401 pText = ECLock(ped); 00402 ichMinSel = ECAdjustIch( ped, pText, ichMinSel ); 00403 ichMaxSel = ECAdjustIch( ped, pText, ichMaxSel ); 00404 ECUnlock(ped); 00405 } 00406 #endif // FE_SB 00407 00408 /* 00409 * Set the caret's position to be at ichMaxSel. 00410 */ 00411 ped->ichCaret = ichMaxSel; 00412 ped->iCaretLine = MLIchToLine(ped, ped->ichCaret); 00413 00414 hdc = ECGetEditDC(ped, FALSE); 00415 MLChangeSelection(ped, hdc, ichMinSel, ichMaxSel); 00416 00417 MLSetCaretPosition(ped, hdc); 00418 ECReleaseEditDC(ped, hdc, FALSE); 00419 00420 #ifdef FE_SB // MLSetSelectionHander() 00421 if (!fDoNotScrollCaret) 00422 MLEnsureCaretVisible(ped); 00423 /* 00424 * #ifdef KOREA is history, with FE_SB (FarEast Single Binary). 00425 */ 00426 #else 00427 #ifdef KOREA 00428 /* 00429 * Extra parameter specified interim character mode 00430 */ 00431 MLEnsureCaretVisible(ped,NULL); 00432 #else 00433 if (!fDoNotScrollCaret) 00434 MLEnsureCaretVisible(ped); 00435 #endif 00436 #endif // FE_SB 00437 } 00438 00439 /***************************************************************************\ 00440 * MLSetTabStops AorW 00441 * 00442 * 00443 * MLSetTabStops(ped, nTabPos, lpTabStops) 00444 * 00445 * This sets the tab stop positions set by the App by sending 00446 * a EM_SETTABSTOPS message. 00447 * 00448 * nTabPos : Number of tab stops set by the caller 00449 * lpTabStops: array of tab stop positions in Dialog units. 00450 * 00451 * Returns: 00452 * TRUE if successful 00453 * FALSE if memory allocation error. 00454 * 00455 * History: 00456 \***************************************************************************/ 00457 00458 BOOL MLSetTabStops( 00459 PED ped, 00460 int nTabPos, 00461 LPINT lpTabStops) 00462 { 00463 int *pTabStops; 00464 00465 /* 00466 * Check if tab positions already exist 00467 */ 00468 if (!ped->pTabStops) { 00469 00470 /* 00471 * Check if the caller wants the new tab positions 00472 */ 00473 if (nTabPos) { 00474 00475 /* 00476 * Allocate the array of tab stops 00477 */ 00478 if (!(pTabStops = (LPINT)UserLocalAlloc(HEAP_ZERO_MEMORY, (nTabPos + 1) * sizeof(int)))) { 00479 return FALSE; 00480 } 00481 } else { 00482 return TRUE; /* No stops then and no stops now! */ 00483 } 00484 } else { 00485 00486 /* 00487 * Check if the caller wants the new tab positions 00488 */ 00489 if (nTabPos) { 00490 00491 /* 00492 * Check if the number of tab positions is different 00493 */ 00494 if (ped->pTabStops[0] != nTabPos) { 00495 00496 /* 00497 * Yes! So ReAlloc to new size 00498 */ 00499 if (!(pTabStops = (LPINT)UserLocalReAlloc(ped->pTabStops, 00500 (nTabPos + 1) * sizeof(int), 0))) 00501 return FALSE; 00502 } else { 00503 pTabStops = ped->pTabStops; 00504 } 00505 } else { 00506 00507 /* 00508 * Caller wants to remove all the tab stops; So, release 00509 */ 00510 if (!UserLocalFree(ped->pTabStops)) 00511 return FALSE; /* Failure */ 00512 ped->pTabStops = NULL; 00513 goto RedrawAndReturn; 00514 } 00515 } 00516 00517 /* 00518 * Copy the new tab stops onto the tab stop array after converting the 00519 * dialog co-ordinates into the pixel co-ordinates 00520 */ 00521 ped->pTabStops = pTabStops; 00522 *pTabStops++ = nTabPos; /* First element contains the count */ 00523 while (nTabPos--) { 00524 00525 /* 00526 * aveCharWidth must be used instead of cxSysCharWidth. 00527 * Fix for Bug #3871 --SANKAR-- 03/14/91 00528 */ 00529 *pTabStops++ = MultDiv(*lpTabStops++, ped->aveCharWidth, 4); 00530 } 00531 00532 RedrawAndReturn: 00533 // Because the tabstops have changed, we need to recompute the 00534 // maxPixelWidth. Otherwise, horizontal scrolls will have problems. 00535 // Fix for Bug #6042 - 3/15/94 00536 MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL); 00537 00538 // Caret may have changed line by the line recalc above. 00539 MLUpdateiCaretLine(ped); 00540 00541 MLEnsureCaretVisible(ped); 00542 00543 // Also, we need to redraw the whole window. 00544 NtUserInvalidateRect(ped->hwnd, NULL, TRUE); 00545 return TRUE; 00546 } 00547 00548 /***************************************************************************\ 00549 * MLUndo AorW 00550 * 00551 * Handles Undo for multiline edit controls. 00552 * 00553 * History: 00554 \***************************************************************************/ 00555 00556 BOOL MLUndo( 00557 PED ped) 00558 { 00559 HANDLE hDeletedText = ped->hDeletedText; 00560 BOOL fDelete = (BOOL)(ped->undoType & UNDO_DELETE); 00561 ICH cchDeleted = ped->cchDeleted; 00562 ICH ichDeleted = ped->ichDeleted; 00563 00564 if (ped->undoType == UNDO_NONE) { 00565 00566 /* 00567 * No undo... 00568 */ 00569 return FALSE; 00570 } 00571 00572 ped->hDeletedText = NULL; 00573 ped->cchDeleted = 0; 00574 ped->ichDeleted = (ICH)-1; 00575 ped->undoType &= ~UNDO_DELETE; 00576 00577 if (ped->undoType == UNDO_INSERT) { 00578 ped->undoType = UNDO_NONE; 00579 00580 /* 00581 * Set the selection to the inserted text 00582 */ 00583 MLSetSelection(ped, FALSE, ped->ichInsStart, ped->ichInsEnd); 00584 ped->ichInsStart = ped->ichInsEnd = (ICH)-1; 00585 00586 /* 00587 * Now send a backspace to delete and save it in the undo buffer... 00588 */ 00589 SendMessage(ped->hwnd, WM_CHAR, (WPARAM)VK_BACK, 0L); 00590 } 00591 00592 if (fDelete) { 00593 00594 /* 00595 * Insert deleted chars 00596 */ 00597 00598 /* 00599 * Set the selection to the inserted text 00600 */ 00601 MLSetSelection(ped, FALSE, ichDeleted, ichDeleted); 00602 MLInsertText(ped, hDeletedText, cchDeleted, FALSE); 00603 00604 UserGlobalFree(hDeletedText); 00605 MLSetSelection(ped, FALSE, ichDeleted, ichDeleted + cchDeleted); 00606 } 00607 00608 return TRUE; 00609 }

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