Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

609 lines
17 KiB

/****************************************************************************\
* 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;
}