|
|
/****************************************************************************\
* edmlRare.c - Edit controls Routines Called rarely are to be * put in a seperate segment _EDMLRare. This file contains * these routines. * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Multi-Line Support Routines called Rarely \****************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* MLInsertCrCrLf AorW * * Inserts CR CR LF characters into the text at soft (word-wrap) line * breaks. CR LF (hard) line breaks are unaffected. Assumes that the text * has already been formatted ie. ped->chLines is where we want the line * breaks to occur. Note that ped->chLines is not updated to reflect the * movement of text by the addition of CR CR LFs. Returns TRUE if successful * else notify parent and return FALSE if the memory couldn't be allocated. * * History: \***************************************************************************/
BOOL MLInsertCrCrLf( PED ped) { ICH dch; ICH li; ICH lineSize; unsigned char *pchText; unsigned char *pchTextNew;
if (!ped->fWrap || !ped->cch) {
/*
* There are no soft line breaks if word-wrapping is off or if no chars */ return TRUE; }
/*
* Calc an upper bound on the number of additional characters we will be * adding to the text when we insert CR CR LFs. */ dch = 3 * ped->cLines;
if (!LOCALREALLOC(ped->hText, (ped->cch + dch) * ped->cbChar, 0, ped->hInstance, NULL)) { ECNotifyParent(ped, EN_ERRSPACE); return FALSE; }
ped->cchAlloc = ped->cch + dch;
/*
* Move the text up dch bytes and then copy it back down, inserting the CR * CR LF's as necessary. */ pchTextNew = pchText = ECLock(ped); pchText += dch * ped->cbChar;
/*
* We will use dch to keep track of how many chars we add to the text */ dch = 0;
/*
* Copy the text up dch bytes to pchText. This will shift all indices in * ped->chLines up by dch bytes. */ memmove(pchText, pchTextNew, ped->cch * ped->cbChar);
/*
* Now copy chars from pchText down to pchTextNew and insert CRCRLF at soft * line breaks. */ if (ped->fAnsi) { for (li = 0; li < ped->cLines - 1; li++) { lineSize = ped->chLines[li + 1] - ped->chLines[li]; memmove(pchTextNew, pchText, lineSize); pchTextNew += lineSize; pchText += lineSize;
/*
* If last character in newly copied line is not a line feed, then we * need to add the CR CR LF triple to the end */ if (*(pchTextNew - 1) != 0x0A) { *pchTextNew++ = 0x0D; *pchTextNew++ = 0x0D; *pchTextNew++ = 0x0A; dch += 3; } }
/*
* Now move the last line up. It won't have any line breaks in it... */ memmove(pchTextNew, pchText, ped->cch - ped->chLines[ped->cLines - 1]); } else { //!fAnsi
LPWSTR pwchTextNew = (LPWSTR)pchTextNew;
for (li = 0; li < ped->cLines - 1; li++) { lineSize = ped->chLines[li + 1] - ped->chLines[li]; memmove(pwchTextNew, pchText, lineSize * sizeof(WCHAR)); pwchTextNew += lineSize; pchText += lineSize * sizeof(WCHAR);
/*
* If last character in newly copied line is not a line feed, then we * need to add the CR CR LF triple to the end */ if (*(pwchTextNew - 1) != 0x0A) { *pwchTextNew++ = 0x0D; *pwchTextNew++ = 0x0D; *pwchTextNew++ = 0x0A; dch += 3; } }
/*
* Now move the last line up. It won't have any line breaks in it... */ memmove(pwchTextNew, pchText, (ped->cch - ped->chLines[ped->cLines - 1]) * sizeof(WCHAR)); }
ECUnlock(ped);
if (dch) { /*
* Update number of characters in text handle */ ped->cch += dch;
/*
* So that the next time we do anything with the text, we can strip the * CRCRLFs */ ped->fStripCRCRLF = TRUE; return TRUE; }
return FALSE; }
/***************************************************************************\
* MLStripCrCrLf AorW * * Strips the CR CR LF character combination from the text. This * shows the soft (word wrapped) line breaks. CR LF (hard) line breaks are * unaffected. * * History: \***************************************************************************/
void MLStripCrCrLf( PED ped) { if (ped->cch) { if (ped->fAnsi) { unsigned char *pchSrc; unsigned char *pchDst; unsigned char *pchLast;
pchSrc = pchDst = ECLock(ped); pchLast = pchSrc + ped->cch; while (pchSrc < pchLast) { if ( (pchSrc[0] == 0x0D) && (pchSrc[1] == 0x0D) && (pchSrc[2] == 0x0A) ) { pchSrc += 3; ped->cch -= 3; } else { *pchDst++ = *pchSrc++; } } } else { // !fAnsi
LPWSTR pwchSrc; LPWSTR pwchDst; LPWSTR pwchLast;
pwchSrc = pwchDst = (LPWSTR)ECLock(ped); pwchLast = pwchSrc + ped->cch; while (pwchSrc < pwchLast) { if ( (pwchSrc[0] == 0x0D) && (pwchSrc[1] == 0x0D) && (pwchSrc[2] == 0x0A) ) { pwchSrc += 3; ped->cch -= 3; } else { *pwchDst++ = *pwchSrc++; } } } ECUnlock(ped);
/*
* Make sure we don't have any values past the last character */ if (ped->ichCaret > ped->cch) ped->ichCaret = ped->cch; if (ped->ichMinSel > ped->cch) ped->ichMinSel = ped->cch; if (ped->ichMaxSel > ped->cch) ped->ichMaxSel = ped->cch; } }
/***************************************************************************\
* MLSetHandle AorW * * Sets the ped to contain the given handle. * * History: \***************************************************************************/
void MLSetHandle( PED ped, HANDLE hNewText) { ICH newCch;
ped->cch = ped->cchAlloc = LOCALSIZE(ped->hText = hNewText, ped->hInstance) / ped->cbChar; ped->fEncoded = FALSE;
if (ped->cch) {
/*
* We have to do it this way in case the app gives us a zero size handle */ if (ped->fAnsi) ped->cch = strlen(ECLock(ped)); else ped->cch = wcslen((LPWSTR)ECLock(ped)); ECUnlock(ped); }
newCch = (ICH)(ped->cch + CCHALLOCEXTRA);
/*
* We do this LocalReAlloc in case the app changed the size of the handle */ if (LOCALREALLOC(ped->hText, newCch*ped->cbChar, 0, ped->hInstance, NULL)) ped->cchAlloc = newCch;
ECResetTextInfo(ped); }
/***************************************************************************\
* MLGetLine AorW * * Copies maxCchToCopy bytes of line lineNumber to the buffer * lpBuffer. The string is not zero terminated. * * Returns number of characters copied * * History: \***************************************************************************/
LONG MLGetLine( PED ped, ICH lineNumber, //WASDWORD
ICH maxCchToCopy, LPSTR lpBuffer) { PSTR pText; ICH cchLen;
if (lineNumber > ped->cLines - 1) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid parameter \"lineNumber\" (%ld) to MLGetLine", lineNumber);
return 0L; }
cchLen = MLLine(ped, lineNumber); maxCchToCopy = min(cchLen, maxCchToCopy);
if (maxCchToCopy) { pText = ECLock(ped) + ped->chLines[lineNumber] * ped->cbChar; memmove(lpBuffer, pText, maxCchToCopy*ped->cbChar); ECUnlock(ped); }
return maxCchToCopy; }
/***************************************************************************\
* MLLineIndex AorW * * This function return s the number of character positions that occur * preceeding the first char in a given line. * * History: \***************************************************************************/
ICH MLLineIndex( PED ped, ICH iLine) //WASINT
{ if (iLine == -1) iLine = ped->iCaretLine; if (iLine < ped->cLines) { return ped->chLines[iLine]; } else { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid parameter \"iLine\" (%ld) to MLLineIndex", iLine);
return (ICH)-1; } }
/***************************************************************************\
* MLLineLength AorW * * if ich = -1, return the length of the lines containing the current * selection but not including the selection. Otherwise, return the length of * the line containing ich. * * History: \***************************************************************************/
ICH MLLineLength( PED ped, ICH ich) { ICH il1, il2; ICH temp;
if (ich != 0xFFFFFFFF) return (MLLine(ped, MLIchToLine(ped, ich)));
/*
* Find length of lines corresponding to current selection */ il1 = MLIchToLine(ped, ped->ichMinSel); il2 = MLIchToLine(ped, ped->ichMaxSel); if (il1 == il2) return (MLLine(ped, il1) - (ped->ichMaxSel - ped->ichMinSel));
temp = ped->ichMinSel - ped->chLines[il1]; temp += MLLine(ped, il2); temp -= (ped->ichMaxSel - ped->chLines[il2]);
return temp; }
/***************************************************************************\
* MLSetSelection AorW * * Sets the selection to the points given and puts the cursor at * ichMaxSel. * * History: \***************************************************************************/
void MLSetSelection( PED ped, BOOL fDoNotScrollCaret, ICH ichMinSel, ICH ichMaxSel) { HDC hdc;
if (ichMinSel == 0xFFFFFFFF) {
/*
* Set no selection if we specify -1 */ ichMinSel = ichMaxSel = ped->ichCaret; }
/*
* Since these are unsigned, we don't check if they are greater than 0. */ ichMinSel = min(ped->cch, ichMinSel); ichMaxSel = min(ped->cch, ichMaxSel);
#ifdef FE_SB // MLSetSelectionHander()
//
// To avoid position to half of DBCS, check and ajust position if necessary
//
// We check ped->fDBCS and ped->fAnsi though ECAdjustIch checks these bits
// at first. We're worrying about the overhead of ECLock and ECUnlock.
//
if ( ped->fDBCS && ped->fAnsi ) {
PSTR pText;
pText = ECLock(ped); ichMinSel = ECAdjustIch( ped, pText, ichMinSel ); ichMaxSel = ECAdjustIch( ped, pText, ichMaxSel ); ECUnlock(ped); } #endif // FE_SB
/*
* Set the caret's position to be at ichMaxSel. */ ped->ichCaret = ichMaxSel; ped->iCaretLine = MLIchToLine(ped, ped->ichCaret);
hdc = ECGetEditDC(ped, FALSE); MLChangeSelection(ped, hdc, ichMinSel, ichMaxSel);
MLSetCaretPosition(ped, hdc); ECReleaseEditDC(ped, hdc, FALSE);
#ifdef FE_SB // MLSetSelectionHander()
if (!fDoNotScrollCaret) MLEnsureCaretVisible(ped); /*
* #ifdef KOREA is history, with FE_SB (FarEast Single Binary). */ #else
#ifdef KOREA
/*
* Extra parameter specified interim character mode */ MLEnsureCaretVisible(ped,NULL); #else
if (!fDoNotScrollCaret) MLEnsureCaretVisible(ped); #endif
#endif // FE_SB
}
/***************************************************************************\
* MLSetTabStops AorW * * * MLSetTabStops(ped, nTabPos, lpTabStops) * * This sets the tab stop positions set by the App by sending * a EM_SETTABSTOPS message. * * nTabPos : Number of tab stops set by the caller * lpTabStops: array of tab stop positions in Dialog units. * * Returns: * TRUE if successful * FALSE if memory allocation error. * * History: \***************************************************************************/
BOOL MLSetTabStops( PED ped, int nTabPos, LPINT lpTabStops) { int *pTabStops;
/*
* Check if tab positions already exist */ if (!ped->pTabStops) {
/*
* Check if the caller wants the new tab positions */ if (nTabPos) {
/*
* Allocate the array of tab stops */ if (!(pTabStops = (LPINT)UserLocalAlloc(HEAP_ZERO_MEMORY, (nTabPos + 1) * sizeof(int)))) { return FALSE; } } else { return TRUE; /* No stops then and no stops now! */ } } else {
/*
* Check if the caller wants the new tab positions */ if (nTabPos) {
/*
* Check if the number of tab positions is different */ if (ped->pTabStops[0] != nTabPos) {
/*
* Yes! So ReAlloc to new size */ if (!(pTabStops = (LPINT)UserLocalReAlloc(ped->pTabStops, (nTabPos + 1) * sizeof(int), 0))) return FALSE; } else { pTabStops = ped->pTabStops; } } else {
/*
* Caller wants to remove all the tab stops; So, release */ if (!UserLocalFree(ped->pTabStops)) return FALSE; /* Failure */ ped->pTabStops = NULL; goto RedrawAndReturn; } }
/*
* Copy the new tab stops onto the tab stop array after converting the * dialog co-ordinates into the pixel co-ordinates */ ped->pTabStops = pTabStops; *pTabStops++ = nTabPos; /* First element contains the count */ while (nTabPos--) {
/*
* aveCharWidth must be used instead of cxSysCharWidth. * Fix for Bug #3871 --SANKAR-- 03/14/91 */ *pTabStops++ = MultDiv(*lpTabStops++, ped->aveCharWidth, 4); }
RedrawAndReturn: // Because the tabstops have changed, we need to recompute the
// maxPixelWidth. Otherwise, horizontal scrolls will have problems.
// Fix for Bug #6042 - 3/15/94
MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL);
// Caret may have changed line by the line recalc above.
MLUpdateiCaretLine(ped);
MLEnsureCaretVisible(ped);
// Also, we need to redraw the whole window.
NtUserInvalidateRect(ped->hwnd, NULL, TRUE); return TRUE; }
/***************************************************************************\
* MLUndo AorW * * Handles Undo for multiline edit controls. * * History: \***************************************************************************/
BOOL MLUndo( PED ped) { HANDLE hDeletedText = ped->hDeletedText; BOOL fDelete = (BOOL)(ped->undoType & UNDO_DELETE); ICH cchDeleted = ped->cchDeleted; ICH ichDeleted = ped->ichDeleted;
if (ped->undoType == UNDO_NONE) {
/*
* No undo... */ return FALSE; }
ped->hDeletedText = NULL; ped->cchDeleted = 0; ped->ichDeleted = (ICH)-1; ped->undoType &= ~UNDO_DELETE;
if (ped->undoType == UNDO_INSERT) { ped->undoType = UNDO_NONE;
/*
* Set the selection to the inserted text */ MLSetSelection(ped, FALSE, ped->ichInsStart, ped->ichInsEnd); ped->ichInsStart = ped->ichInsEnd = (ICH)-1;
/*
* Now send a backspace to delete and save it in the undo buffer... */ SendMessage(ped->hwnd, WM_CHAR, (WPARAM)VK_BACK, 0L); }
if (fDelete) {
/*
* Insert deleted chars */
/*
* Set the selection to the inserted text */ MLSetSelection(ped, FALSE, ichDeleted, ichDeleted); MLInsertText(ped, hDeletedText, cchDeleted, FALSE);
UserGlobalFree(hDeletedText); MLSetSelection(ped, FALSE, ichDeleted, ichDeleted + cchDeleted); }
return TRUE; }
|