/************************************************************/ /* Windows Write, Copyright 1985-1992 Microsoft Corporation */ /************************************************************/ /* insert.c -- MW insertion routines */ #define NOCLIPBOARD #define NOGDICAPMASKS #define NOCTLMGR #define NOWINSTYLES #define NOSYSMETRICS #define NOMENUS #define NOKEYSTATE #define NOHDC #define NORASTEROPS #define NOSYSCOMMANDS #define NOSHOWWINDOW #define NOCOLOR //#define NOATOM #define NOICON #define NOBRUSH #define NOCREATESTRUCT #define NOMB #define NOFONT #define NOOPENFILE #define NOPEN #define NOREGION #define NOSCROLL #define NOSOUND #define NOWH #define NOWINOFFSETS #define NOWNDCLASS #define NOCOMM #include #include "mw.h" #include "docdefs.h" #include "editdefs.h" #include "cmddefs.h" #include "dispdefs.h" #include "wwdefs.h" #include "filedefs.h" #define NOSTRERRORS #include "str.h" #include "propdefs.h" #include "fmtdefs.h" #include "fkpdefs.h" #include "ch.h" #include "winddefs.h" #include "fontdefs.h" #include "debug.h" #if defined(OLE) #include "obj.h" #endif #ifdef DBCS #include "dbcs.h" #endif #ifdef JAPAN //T-HIROYN Win3.1 #include "kanji.h" int changeKanjiftc = FALSE; int newKanjiftc = ftcNil; #endif /* E X T E R N A L S */ extern HWND vhWnd; /* WINDOWS: Handle of the current document display window*/ extern MSG vmsgLast; /* WINDOWS: last message gotten */ extern HWND hParentWw; /* WINDOWS: Handle for parent (MENU) window */ extern int vfSysFull; extern int vfOutOfMemory; extern int vxpIns; extern int vdlIns; extern struct PAP vpapAbs; extern struct UAB vuab; extern struct CHP vchpNormal; extern int vfSeeSel; extern int vfInsLast; extern struct FCB (**hpfnfcb)[]; extern typeCP vcpLimParaCache; extern typeCP vcpFirstParaCache; extern typeCP CpMax(); extern typeCP CpMin(); extern CHAR rgchInsert[cchInsBlock]; /* Temporary insert buffer */ extern typeCP cpInsert; /* Beginning cp of insert block */ extern int ichInsert; /* Number of chars used in rgchInsert */ extern struct CHP vchpInsert; extern int vfSelHidden; extern struct FKPD vfkpdParaIns; extern struct FKPD vfkpdCharIns; extern struct PAP vpapPrevIns; extern typeFC fcMacPapIns; extern typeFC fcMacChpIns; extern struct CHP vchpSel; extern struct FLI vfli; extern struct PAP *vppapNormal; extern typeCP cpMinCur; extern typeCP cpMacCur; extern struct SEL selCur; extern int docCur; extern struct WWD rgwwd[]; extern struct DOD (**hpdocdod)[]; extern int wwCur; extern struct CHP vchpFetch; extern struct SEP vsepAbs; extern int vfCommandKey; extern int vfShiftKey; extern int vfOptionKey; extern int vfInsEnd; extern typeCP cpWall; extern int vfDidSearch; extern int vdocParaCache; extern typeCP vcpFetch; extern int vccpFetch; extern CHAR *vpchFetch; extern struct CHP vchpFetch; extern int ferror; extern BOOL vfInvalid; extern int docUndo; extern struct EDL *vpedlAdjustCp; extern int wwMac; extern int vfFocus; extern int vkMinus; #ifdef CASHMERE extern int vfVisiMode; /* Whether "show fmt marks" mode is on */ extern int vwwCursLine; /* Window containing cursor */ #endif extern int vfLastCursor; /* Whether up/down arrow xp goal position is valid */ /* state of the cursor line */ extern int vxpCursLine; extern int vypCursLine; extern int vdypCursLine; extern int vfInsertOn; /* G L O B A L S */ /* The following used to be defined here */ extern int vcchBlted; /* # chars blted to screen, before line update */ extern int vidxpInsertCache; /* current index of insertion into char width cache */ extern int vdlIns; extern int vxpIns; extern int vfTextBltValid; extern int vfSuperIns; extern int vdypLineSize; extern int vdypCursLineIns; extern int vdypBase; extern int vypBaseIns; extern int vxpMacIns; extern int vdypAfter; extern struct FMI vfmiScreen; #ifdef DEBUG #define STATIC #else #define STATIC static #endif /* Used in this module only */ typeCP cpStart; /* Start cp of the replacement operation that an Insert is */ typeCP cpLimInserted; /* Last cp inserted */ typeCP cpLimDeleted; /* Last cp deleted */ /* Enumerated type telling what to update */ /* Ordering is such that larger numbers mean that there is more to update */ #define mdInsUpdNothing 0 #define mdInsUpdNextChar 1 #define mdInsUpdOneLine 2 #define mdInsUpdLines 3 #define mdInsUpdWhole 4 void NEAR FormatInsLine(); void NEAR DelChars( typeCP, int ); void NEAR EndInsert(); int NEAR XpValidateInsertCache( int * ); int NEAR FBeginInsert(); #ifdef DBCS CHAR near GetDBCSsecond(); BOOL FOptAdmitCh(CHAR, CHAR); int NEAR MdInsUpdInsertW( WORD, WORD, RECT *); #else int NEAR MdInsUpdInsertCh( CHAR, CHAR, RECT *); #endif /* ifdef DBCS */ #ifdef KOREA int IsInterim = 0; int WasInterim = 0; BOOL fInterim = FALSE; // MSCH bklee 12/22/94 #endif #ifdef DEBUG int vTune = 0; #endif /* AlphaMode -- Handler for insertion, backspace, and forward delete Alpha mode works by inserting a block of cchInsBlock cp's at the insertion point. The inserted piece has fn == fnInsert, cpMin == 0. We AdjustCp for this block as though it contained cchInsBlock cp's, even though it is initially "empty". When a character is typed, it is inserted at rgchInsert[ ichInsert++ ]. When rgchInsert is full, it is written to the scratch file, and Replace'd with a new insertion block. AlphaMode exits when it encounters a key or event that it cannot handle (e.g. cursor keys, mouse hits). It then cleans up, writing the insertion block to the scratch file, and returns "Fast Insert" is achieved by writing characters directly to the screen and scrolling the rest of the line out of the way. The line is not updated until it is necessary (or until we fall through the delay in KcInputNextKey). During "Fast Insert" (or fast backspace or fast delete), it is important that ValidateTextBlt will usually NOT be called unless the line containing the insertion point has been made valid. Otherwise, ValidateTextBlt will fail to find a valid vdlIns, and call CpBeginLine, which forces an update of the entire screen. */ #ifdef KOREA /* global to MdUpIns 90.12.28 */ int dxpCh; #endif /* A L P H A M O D E */ AlphaMode( kc ) int kc; /* Keyboard Character */ { int rgdxp[ ichMaxLine ]; int chShow, dlT, fGraphics; int mdInsUpd; int fDocDirty = (**hpdocdod) [docCur].fDirty; register struct EDL *pedl; int xpInsLineMac; int fGotKey = fFalse; int kcNext; int fScrollPending = fFalse; int dxpPending; int fDelPending = fFalse; typeCP cpPending; int cchPending; int mdInsUpdPending = mdInsUpdNothing; #ifdef DBCS BOOL fResetMdInsUpd = TRUE; /* To avoid the blinking cursor at beg. doc or eod. */ CHAR chDBCS2 = '\0'; /* Used to hold the second byte of a DBCS character */ #endif /* DBCS */ #ifdef JAPAN //T-HIROYN Win3.1 RetryAlpha: if(changeKanjiftc) { changeKanjiftc = FALSE; ApplyCLooks(&vchpSel, sprmCFtc, newKanjiftc); } changeKanjiftc = FALSE; #endif #ifdef DBCS /* was in JAPAN */ if( kc == 0x000d ) kc = 0x000a; #endif if (!FWriteOk( fwcReplace )) { /* Not OK to write on docCur (read-only OR out of memory) */ _beep(); return; } /* Shut down the caret blink timer -- we don't want its messages or its cost */ #ifndef DBCS /* was in JAPAN */ KillTimer( vhWnd, tidCaret ); #endif #ifdef OLDBACKSPACE /* Backspace in Win 3.0 has been changed to function identically like the Delete key ..pault 6/20/89 */ /* Handle BACKSPACE when there's a selection. DELETE with selection has already been filtered out by KcAlphaKeyMessage */ if (kc == kcDelPrev) /* Make a selection at selection-start preparatory to deleting previous char, which is accomplished in the loop. */ Select( selCur.cpFirst, selCur.cpFirst ); #endif /* Set up initial limits for UNDO */ cpStart = selCur.cpFirst; /* Starting cp for insertion */ cpLimDeleted = selCur.cpLim; /* Last cp Deleted */ /* Delete the selection, and make an insert point selection in its stead */ /* Insert point selection inherits the properties of the deleted text */ if (selCur.cpFirst < selCur.cpLim) { struct CHP chp; typeCP cpT; fDocDirty = TRUE; cpT = selCur.cpFirst; /* Get properties of the deleted text */ FetchCp(docCur, cpT, 0, fcmProps); blt( &vchpFetch, &chp, cwCHP ); if (fnClearEdit(OBJ_INSERTING)) goto Abort; UpdateWw( wwCur, FALSE ); if (ferror) goto Abort; Select(cpT, cpT); blt( &chp, &vchpSel, cwCHP ); } else { /* Current selection is 0 chars wide, no need to delete */ /* Set up UNDO */ noUndo: NoUndo(); /* Don't combine adjacent operations or vuab.cp = cp in DelChars will be wrong */ SetUndo( uacDelNS, docCur, cpStart, cp0, docNil, cpNil, cp0, 0); } fGraphics = FBeginInsert(); Scribble( 7, (vfSuperIns ? 'S' : 'I') ); vfSelHidden = false; vfTextBltValid = FALSE; if (ferror) /* Ran out of memory trying to insert */ goto Abort; if (fGraphics) { selCur.cpFirst = selCur.cpLim = cpInsert + cchInsBlock; /* this is to display the paragraph that has been automatically inserted by edit in FBeginInsert */ UpdateWw(wwCur, fFalse); if (kc == kcReturn) kc = kcNil; } for ( ; ; (fGotKey ? (fGotKey = fFalse, kc = kcNext) : (kc = KcInputNextKey())) ) { /* Loop til we get a command key we can't handle */ /* KcInputNextKey will return kcNil if a nonkey */ /* event occurs */ RECT rc; #ifndef KOREA /* has been defined globally */ int dxpCh; #endif typeCP cpFirstEdit=cpInsert + ichInsert; chShow = kc; mdInsUpd = mdInsUpdNothing; /* Force exit from loop if out of heap or disk space */ if (vfSysFull || vfOutOfMemory) kc = kcNil; #ifdef DBCS if (kc != kcDelPrev && kc != kcDelNext) { fResetMdInsUpd = TRUE; } #endif /* DBCS */ if (!vfTextBltValid) ValidateTextBlt(); Assert( vdlIns >= 0 ); pedl = &(**wwdCurrentDoc.hdndl) [vdlIns]; FreezeHp(); SetRect( (LPRECT)&rc, vxpIns+1, pedl->yp - pedl->dyp, wwdCurrentDoc.xpMac, min(pedl->yp, wwdCurrentDoc.ypMac)); vfli.doc = docNil; /* this is a speeder-upper of the switch below */ if (kc <= 0) switch (kc) { /********************************************************************* ********** START OF BACKSPACE/FORWARD DELETE CODE ******************* *********************************************************************/ CHAR chDelete; /* Variables for Backspace/Delete */ typeCP cpDelete; int cchDelete; int idxpDelete; int fCatchUp; #ifdef DBCS typeCP cpT; case kcDelNext: /* Delete following character */ cpT = selCur.cpFirst; if (fDelPending) { cpT += cchPending; } if (cpT >= cpMacCur) { _beep(); MeltHp(); if (fResetMdInsUpd) { mdInsUpd = mdInsUpdOneLine; fResetMdInsUpd = FALSE; } goto DoReplace; /* Clean up pending replace ops */ } cpDelete = CpFirstSty(cpT, styChar); cchDelete = CpLimSty(cpDelete, styChar) - cpDelete; goto DeleteChars; case kcDelPrev: /* Delete previous char */ /* To reflect the state of cpPending and cchPending so that */ /* CpFirstSty( , styChar) is called with a proper cp. */ cpT = cpFirstEdit - 1; if (fDelPending) { cpT -= cchPending; } if (cpT < cpMinCur) { _beep(); MeltHp(); if (fResetMdInsUpd) { mdInsUpd = mdInsUpdOneLine; fResetMdInsUpd = FALSE; } goto DoReplace; } cpDelete = CpFirstSty(cpT, styChar); cchDelete = CpLimSty(cpDelete, styChar) - cpDelete; #if defined(NEED_FOR_NT351_TAIWAN) //Removed by bklee //solve BkSp single byte (>0x80) infinite loop problem, MSTC - pisuih, 2/24/93 if ( cchDelete > 1 && (cpDelete + cchDelete + cchInsBlock) > cpMacCur ) cchDelete = 1; #endif TAIWAN #else case kcDelNext: /* Delete following character */ cpDelete = selCur.cpFirst; if (fDelPending) cpDelete += cchPending; if (cpDelete >= cpMacCur) { _beep(); MeltHp(); goto DoReplace; /* Clean up pending replace ops */ } FetchCp( docCur, cpDelete, 0, fcmChars ); chDelete = *vpchFetch; cchDelete = 1; #ifdef CRLF if ((chDelete == chReturn) && (*(vpchFetch+1) == chEol) ) { cchDelete++; chDelete = chEol; } #endif goto DeleteChars; case kcDelPrev: /* Delete previous char */ /* Decide what char, cp we're deleting */ cpDelete = cpFirstEdit - 1; if (fDelPending) cpDelete -= cchPending; if (cpDelete < cpMinCur) { _beep(); MeltHp(); goto DoReplace; /* Clean up pending replace ops */ } FetchCp( docCur, cpDelete, 0, fcmChars ); chDelete = *vpchFetch; cchDelete = 1; #ifdef CRLF if ( (chDelete == chEol) && (cpDelete > cpMinCur) ) { FetchCp( docCur, cpDelete - 1, 0, fcmChars ); if (*vpchFetch == chReturn) { cchDelete++; cpDelete--; } } #endif #endif /* DBCS */ DeleteChars: #ifdef DBCS /* They expect chDelete as well as cpDelete and cchDelete */ FetchCp(docCur, cpDelete, 0, fcmChars); chDelete = *vpchFetch; #endif /* Here we have cpDelete, cchDelete */ /* Also cchPending and cpPending if fDelPending is TRUE */ /* Also dxpPending if fScrollPending is TRUE */ if ( CachePara( docCur, cpDelete ), vpapAbs.fGraphics) { /* Trying to del over picture, illegal case */ _beep(); MeltHp(); goto DoReplace; /* Clean up pending replace ops */ } /* Insert properties are now the properties of the deleted char(s) */ FetchCp( docCur, cpDelete, 0, fcmProps ); vchpFetch.fSpecial = FALSE; NewChpIns( &vchpFetch ); /* Pending replace operation <-- union of any pending replace operations with the current one */ if (fDelPending) { if (cpPending >= cchDelete) { cchPending += cchDelete; if (kc == kcDelPrev) cpPending -= cchDelete; } else Assert( FALSE ); } else { cpPending = cpDelete; cchPending = cchDelete; fDelPending = TRUE; } /* Determine whether the screen update for the current deletion can be accomplished by scrolling. We can scroll if: (1) we are still on the line vdlIns, (2) we are not deleting eol or chsect, (3) our width cache is good OR vdlIns is valid, so we can validate the cache w/o redisplaying the line */ mdInsUpd = mdInsUpdOneLine; if ((idxpDelete = (int) (cpDelete - pedl->cpMin)) < 0) { mdInsUpd = mdInsUpdLines; } else if ((chDelete != chEol) && (chDelete != chSect) && (vidxpInsertCache != -1 || pedl->fValid) && (mdInsUpdPending < mdInsUpdOneLine)) { /* OK to scroll -- do all pending scrolls */ int fDlAtEndMark; int fCatchUp; MeltHp(); /* Re-entrant heap movement */ fCatchUp = FImportantMsgPresent(); if (vidxpInsertCache == -1) { /* Width cache is invalid, update it */ xpInsLineMac = XpValidateInsertCache( rgdxp ); /* HM */ } pedl = &(**wwdCurrentDoc.hdndl) [vdlIns]; FreezeHp(); /* Obtain display width of character to delete */ if ((vcchBlted > 0) && (kc == kcDelPrev)) { /* Deleted char was blted in superins mode onto a line that has not been updated */ vcchBlted--; /* Because chDelete is always 1 byte quantity by itself or the 1st byte of the DBCS character it is OK. */ dxpCh = DxpFromCh( chDelete, FALSE ); } else { int idxpT = idxpDelete + cchDelete; #ifdef DBCS /* For the following segment of code to work, an element in rgdxp corresponding to the second byte of a DBCS character must contain 0. */ int *pdxpT; int cchT; for (dxpCh = 0, pdxpT = &rgdxp[idxpDelete], cchT = 0; cchT < cchDelete; dxpCh += *pdxpT++, cchT++); #else dxpCh = rgdxp[ idxpDelete ]; #endif /* Adjust the character width cache to eliminate width entries for deleted chars */ if ((vidxpInsertCache >= 0) && (idxpDelete >= 0) && (idxpT <= pedl->dcpMac) ) { blt( &rgdxp[ idxpT ], &rgdxp[ idxpDelete ], ichMaxLine - idxpT ); if (vidxpInsertCache > idxpDelete) /* Deleted behind insert point, adjust index */ vidxpInsertCache -= cchDelete; } else vidxpInsertCache = -1; } /* pending scroll op <-- current scroll op merged with pending scroll op */ if (fScrollPending) { dxpPending += dxpCh; } else { dxpPending = dxpCh; fScrollPending = fTrue; } /* See if we should postpone the scroll */ if (fCatchUp) { MeltHp(); Assert( !fGotKey ); fGotKey = TRUE; if ((kcNext = KcInputNextKey()) == kc) { /* Next key is same as this key, process NOW */ continue; } FreezeHp(); } /* Perform all pending scrolls */ fScrollPending = fFalse; if (dxpPending > 0) { ClearInsertLine(); if (kc == kcDelPrev) { /* Backspace */ vxpCursLine = (vxpIns -= dxpPending); rc.left -= dxpPending; } ScrollCurWw( &rc, -dxpPending, 0 ); DrawInsertLine(); xpInsLineMac -= dxpPending; } /* See if we can get away without updating the screen (and without invalidating the insert cache) */ #define cchGetMore 4 #define dxpGetMore ((unsigned)dxpCh << 3) /* Check for running out of chars ahead of the cursor */ fDlAtEndMark = (pedl->cpMin + pedl->dcpMac >= cpMacCur); if ( (kc != kcDelNext && fDlAtEndMark) || ((idxpDelete + cchGetMore < pedl->dcpMac) && ( (int) (xpInsLineMac - vxpIns) > dxpGetMore) )) { mdInsUpd = mdInsUpdNothing; } /* Special check to avoid two end marks: see if the dl after the ins line is dirty and beyond the doc's end */ if (fDlAtEndMark && (vdlIns < wwdCurrentDoc.dlMac - 1) && !(pedl+1)->fValid) { mdInsUpd = mdInsUpdLines; } } /* End of "if OK to scroll" */ /* See if we should postpone the replace */ MeltHp(); /* Re-entrant Heap Movement */ if (FImportantMsgPresent() && !fGotKey) { fGotKey = TRUE; if ((kcNext = KcInputNextKey()) == kc) { /* Next key is same as this key, process NOW */ if (mdInsUpd > mdInsUpdPending) { /* Mark screen update as pending */ mdInsUpdPending = mdInsUpd; vidxpInsertCache = -1; } continue; } } /* Handle actual replacement of chars */ DoReplace: if (fDelPending) { DelChars( cpPending, cchPending ); /* HM */ fDelPending = fFalse; } /* Set up screen update based on present & pending needs */ if (mdInsUpdPending > mdInsUpd) mdInsUpd = mdInsUpdPending; if (mdInsUpd >= mdInsUpdOneLine) /* If we're updating at least a line, assume we're handling all necessary pending screen update */ mdInsUpdPending = mdInsUpdNothing; /* Adjust vdlIns's dcpMac. vdlIns is invalid anyway, and this allows us to catch the case in which we run out of visible characters to scroll in the forward delete case. See update test after the scroll above */ (**wwdCurrentDoc.hdndl) [vdlIns].dcpMac -= cchPending; /* this is here to compensate for RemoveDelFtnText */ selCur.cpFirst = selCur.cpLim = cpInsert + (typeCP)cchInsBlock; cpFirstEdit = cpPending; goto LInvalIns; /* Skip ahead to update the screen */ /********************************************************************* ************ END OF BACKSPACE/FORWARD DELETE CODE ******************* *********************************************************************/ case kcReturn: /* Substitute EOL for return key */ /* Also add a return if CRLF is on */ MeltHp(); #ifdef CRLF #ifdef DBCS MdInsUpdInsertW( MAKEWORD(0, chReturn), MAKEWORD(0, chReturn), &rc ); #else MdInsUpdInsertCh( chReturn, chReturn, &rc ); #endif /* DBCS */ #endif FreezeHp(); kc = chEol; break; #ifdef CASHMERE /* These key codes are omitted from MEMO */ case kcNonReqHyphen: /* Substitute for non-required hyphen */ kc = chNRHFile; chShow = chHyphen; break; case kcNonBrkSpace: /* Substitute for non-breaking space */ kc = chNBSFile; chShow = chSpace; break; case kcNLEnter: /* Substitute for non-para return */ kc = chNewLine; break; #endif #ifdef PRINTMERGE case kcLFld: /* Substitite for Left PRINT MERGE bracket */ chShow = kc = chLFldFile; break; case kcRFld: /* Substitute for Right PRINT MERGE bracket */ chShow = kc = chRFldFile; break; #endif case kcPageBreak: kc = chSect; /* Page break (no section) */ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter) { /* Page breaks prohibited in header/footer */ BadKey: _beep(); MeltHp(); continue; } break; case kcTab: /* Tab */ kc = chTab; break; default: #if WINVER >= 0x300 if (kc == kcNonReqHyphen) /* Substitute for non-required hyphen */ { /* no longer a const so can't be directly in switch */ kc = chNRHFile; chShow = chHyphen; break; } #endif /* AlphaMode Exit point: Found key or event that we don't know how to handle */ MeltHp(); goto EndAlphaMode; } /* end of if kc < 0 switch (kc) */ MeltHp(); #ifdef DBCS if (IsDBCSLeadByte(kc)) { /* We are dealing with the first byte of the DBCS character. */ /* In case of DBCS letter, wInsert is equal to wShow. */ #ifdef JAPAN //T-HIROYN Win3.1 if( ftcNil != (newKanjiftc = GetKanjiFtc(&vchpInsert)) ) { //(menu.c) changeKanjiftc = TRUE; goto EndAlphaMode; } #endif if ((chDBCS2 = GetDBCSsecond()) != '\0') { mdInsUpd = MdInsUpdInsertW( MAKEWORD(kc, chDBCS2), MAKEWORD(kc, chDBCS2), &rc ); } } else { #ifdef JAPAN //T-HIROYN Win3.1 if (FKana(kc)) { if( ftcNil != (newKanjiftc = GetKanjiFtc(&vchpInsert)) ) { changeKanjiftc = TRUE; goto EndAlphaMode; } } #endif mdInsUpd = MdInsUpdInsertW( MAKEWORD(0, kc), MAKEWORD(0, chShow), &rc); } #else /* Insert character kc into the document. Show character chShow (which is equal to kc except for cases such as non-breaking space, etc. */ mdInsUpd = MdInsUpdInsertCh( kc, chShow, &rc ); #endif /* DBCS */ /* common for insert and backspace: invalidate line and previous line if dependency warrants it */ /* have vdlIns from ValidateTextBlt */ LInvalIns: pedl = &(**wwdCurrentDoc.hdndl) [vdlIns]; pedl->fValid = fFalse; wwdCurrentDoc.fDirty = fTrue; Assert( vdlIns >= 0 ); if ((dlT = vdlIns) == 0) { /* Editing in first line of window */ if ( wwdCurrentDoc.fCpBad || (wwdCurrentDoc.cpFirst + wwdCurrentDoc.dcpDepend > cpFirstEdit) ) { /* Edit affects ww's first cp; recompute it */ CtrBackDypCtr( 0, 0 ); (**wwdCurrentDoc.hdndl) [vdlIns].cpMin = CpMax( wwdCurrentDoc.cpMin, wwdCurrentDoc.cpFirst ); mdInsUpd = mdInsUpdLines; } } else { /* If the edit affects the line prior to vdlIns, invalidate it */ --pedl; #ifdef DBCS if (!IsDBCSLeadByte(kc)) { chDBCS2 = kc; kc = '\0'; } #endif /* DBCS */ if ((pedl->cpMin + pedl->dcpMac + pedl->dcpDepend > cpFirstEdit)) { pedl->fValid = fFalse; dlT--; } #ifdef DBCS /* was in JAPAN; KenjiK '90-11-03 */ // deal with the character beyond end of the line. else #ifdef KOREA /* protect from displaying picture abnormally */ if(((pedl+1)->cpMin == cpFirstEdit && FOptAdmitCh(kc, chDBCS2)) && !pedl->fGraphics) #else if ((pedl+1)->cpMin == cpFirstEdit && FOptAdmitCh(kc, chDBCS2)) #endif { /* We do exactly the same as above, except setting mdInsUpd, because the one returned by MdInsUpdInsertW() does not reflect this condition. */ pedl->fValid = fFalse; dlT--; mdInsUpd = mdInsUpdOneLine; } #endif else pedl++; } #ifdef ENABLE /* We now support end-of-line cursor while inserting because of typing before splats */ if (vfInsEnd) { /* forget about special end-of-line cursor */ vfInsEnd = fFalse; ClearInsertLine(); } #endif #ifdef KOREA /* 90.12.28 sangl */ { BOOL UpNext=FALSE; screenup: #endif switch (mdInsUpd) { default: case mdInsUpdNothing: case mdInsUpdNextChar: break; case mdInsUpdLines: case mdInsUpdOneLine: ClearInsertLine(); if ( FUpdateOneDl( dlT ) ) { /* Next line affected */ struct EDL *pedl; if ( (mdInsUpd == mdInsUpdLines) || /* Re-entrant heap movement */ !FImportantMsgPresent() || (pedl = &(**wwdCurrentDoc.hdndl) [dlT], (selCur.cpFirst >= pedl->cpMin + pedl->dcpMac))) { FUpdateOneDl( dlT + 1 ); } } #ifdef KOREA /* 90.12.28 sangl */ else if (UpNext && ((dlT+1) < wwdCurrentDoc.dlMac)) FUpdateOneDl(dlT + 1); #endif ToggleSel(selCur.cpFirst, selCur.cpLim, fTrue); break; case mdInsUpdWhole: ClearInsertLine(); UpdateWw(wwCur, fFalse); ToggleSel(selCur.cpFirst, selCur.cpLim, fTrue); break; } /* end switch (mdInsUpd) */ #ifdef KOREA /* 90.12.28 sangl */ if (IsInterim) { if (mdInsUpd>=mdInsUpdOneLine) { ClearInsertLine(); vxpCursLine -= dxpCh; DrawInsertLine(); } // while ( ((kc=KcInputNextHan()) < 0xA1) || (kc>0xFE) ); while ( (((kc=KcInputNextHan()) < 0x81) || (kc>0xFE)) && (kc != VK_MENU)); // MSCH bklee 12/22/94 if(kc == VK_MENU) { // MSCH bklee 12/22/94 fInterim = IsInterim = 0; ichInsert -= 2; goto nextstep; } chDBCS2 = GetDBCSsecond(); mdInsUpd = MdInsUpdInsertW(MAKEWORD(kc, chDBCS2), MAKEWORD(kc, chDBCS2), &rc); if (vfSuperIns) goto LInvalIns; /* This is for large size, when 1st interim becomes final (ex, consonants) */ else { UpNext = TRUE; /* For italic, try to FUpdateOneDl for current line */ goto screenup; /* 90.12.28 sangl */ } } /* ex: all consonants */ } /* For screenup: 90.12.28 sangl */ nextstep : // MSCH bklee 12/22/94 /* if(IsInterim && kc == VK_MENU) { // MSCH bklee 12/22/94 ClearInsertLine(); UpdateWw(wwCur, fFalse); goto EndAlphaMode; } */ if (WasInterim) { MSG msg; int wp; if (PeekMessage ((LPMSG)&msg, vhWnd, WM_KEYDOWN, WM_KEYUP, PM_NOYIELD | PM_NOREMOVE) ) { if( msg.message==WM_KEYDOWN && ( (wp=msg.wParam)==VK_LEFT || wp==VK_UP || wp==VK_RIGHT || wp==VK_DOWN || wp==VK_DELETE) ) goto EndAlphaMode; } WasInterim = 0; } #endif /* KOREA */ } /* end for */ EndAlphaMode: Scribble( 7, 'N' ); EndInsert(); /* Clean Up Insertion Block */ #ifdef CASHMERE UpdateOtherWws(fFalse); #endif if (cpLimInserted != cpStart) { /* We inserted some characters */ SetUndo( uacInsert, docCur, cpStart, cpLimInserted - cpStart, docNil, cpNil, cp0, 0 ); SetUndoMenuStr(IDSTRUndoTyping); } else if (cpLimDeleted == cpStart) /* This AlphaMode invocation had no net effect */ { Abort: NoUndo(); if (!fDocDirty) /* The doc was clean when we started, & we didn't change it, so it's still clean */ (**hpdocdod) [docCur].fDirty = FALSE; } vfLastCursor = fFalse; /* Tells MoveUpDown to recalc its xp seek position */ if (vfFocus) { /* Restore the caret blink timer */ SetTimer( vhWnd, tidCaret, GetCaretBlinkTime(), (FARPROC)NULL ); } else { ClearInsertLine(); } /* Backspaces/deletes may have changed vchpSel -- update it */ blt( &vchpInsert, &vchpSel, cwCHP ); #ifdef KOREA if (WasInterim) { MoveLeftRight(kcLeft); WasInterim = 0; vfSeeSel = TRUE; } else vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */ #else vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */ #endif #ifdef JAPAN //T-HIROYN Win3.1 if(changeKanjiftc) { goto RetryAlpha; } #endif } /* F B E G I N I N S E R T */ /* Prepare for start of insertion */ /* returns true iff inserting in front of a pic */ int NEAR FBeginInsert() { int fGraphics; typeCP cp = selCur.cpFirst; typeCP cpFirstPara; cpInsert = cp; /* We expect the caller to have deleted the selection already */ Assert (selCur.cpLim == selCur.cpFirst); /* Use super-fast text insertion unless we are inserting italics */ CachePara(docCur, cp); cpFirstPara = vcpFirstParaCache; fGraphics = vpapAbs.fGraphics; vfSuperIns = !vchpSel.fItalic; vchpSel.fSpecial = fFalse; NewChpIns(&vchpSel); ichInsert = 0; /* Must Set this BEFORE calling Replace */ /* Insert the speeder-upper QD insert block. Note: we invalidate since there will be a character inserted anyway, plus to make sure that the line length gets updated ("Invalidate" refers to the choice of Replace() over the Repl1/AdjustCp/!vfInvalid mechanism used in EndInsert, in which the insert dl is not made invalid). It would be possible to optimize by NOT invalidating here (thus being able to blt the first char typed), but one would have to account for the case in which the cpMin of the insert dl is changed by AdjustCp, or FUpdateOneDl will get messed up. Currently this case is covered by an implicit UpdateWw, which occurs in AlphaMode->ValidateTextBlt->CpBeginLine because we have invalidated vdlIns. */ Replace(docCur, cpInsert, cp0, fnInsert, fc0, (typeFC) cchInsBlock); cpLimInserted = cpInsert + cchInsBlock; vidxpInsertCache = -1; /* Char width cache for insert line is initially empty */ /* Blank the mouse cursor so it doesn't make the display look ugly or slow us down trying to keep it up to date */ SetCursor( (HANDLE) NULL ); return fGraphics; } /* E N D I N S E R T */ void NEAR EndInsert() { /* Clean up from quick insert mode */ int dcp = cchInsBlock - ichInsert; typeFC fc; #ifdef CASHMERE UpdateOtherWws(fTrue); #endif fc = FcWScratch(rgchInsert, ichInsert); #if WINVER >= 0x300 if (!vfSysFull) /* The "tape dispenser bug replication method" has shown that holding down a key for 64k presses will cause FcWScratch() to run out of scratch-file space and fail. If we go ahead with the Replacement we'll corrupt the piece table, so we delicately avoid that problem 3/14/90..pault */ #endif { Repl1(docCur, cpInsert, (typeCP) cchInsBlock, fnScratch, fc, (typeFC) ichInsert); cpLimInserted -= (cchInsBlock - ichInsert); /* adjust separately, since first ichInsert characters have not changed at all */ vfInvalid = fFalse; vpedlAdjustCp = (struct EDL *)0; AdjustCp(docCur, cpInsert + ichInsert, (typeCP) dcp, (typeFC) 0); /* if the line is not made invalid, the length of the line must be maintained. */ if (vpedlAdjustCp) vpedlAdjustCp->dcpMac -= dcp; } vfInvalid = fTrue; cpWall = selCur.cpLim; vfDidSearch = fFalse; if (!vfInsertOn) DrawInsertLine(); } /* N E W C H P I N S */ NewChpIns(pchp) struct CHP *pchp; { /* Make forthcoming inserted characters have the look in pchp */ if (CchDiffer(&vchpInsert, pchp, cchCHP) != 0) { /* Add the run for the previous insertion; our looks differ. */ typeFC fcMac = (**hpfnfcb)[fnScratch].fcMac; if (fcMac != fcMacChpIns) { AddRunScratch(&vfkpdCharIns, &vchpInsert, &vchpNormal, cchCHP, fcMac); fcMacChpIns = fcMac; } blt(pchp, &vchpInsert, cwCHP); } } #ifdef DBCS int NEAR MdInsUpdInsertW(wInsert, wShow, prcScroll) WORD wInsert; /* Char or 2 char's to insert into document */ WORD wShow; /* Char or 2 char's to be shown on screen (SuperIns mode only) */ RECT *prcScroll; /* Rect to scroll for SuperIns */ #else int NEAR MdInsUpdInsertCh( chInsert, chShow, prcScroll ) CHAR chInsert; /* Char to insert into document */ CHAR chShow; /* Char to show on screen (SuperIns mode only) */ RECT *prcScroll; /* Rect to scroll for SuperIns */ #endif /* DBCS */ { /* Insert character ch into the document. Show char chShow. */ /* Flush the insert buffer to the scratch file if it fills up */ /* Return: mdInsUpdWhole - Must do an UpdateWw mdInsUpdNextChar - Update not mandatory, char waiting mdInsUpdLines - Must update vdlIns and maybe following mdInsUpdNothing - No update needed & no char waiting mdInsUpdOneLine - Update vdlIns; only update following if there's no char waiting */ extern int vfInsFontTooTall; void NEAR FlushInsert(); int mdInsUpd; #ifndef KOREA /* has been defined globally */ int dxpCh; #endif int dl; #ifdef DBCS CHAR chInsert; CHAR chShow; BOOL fDBCSChar; int ichInsertSave; int dcchBlted; #endif /* DBCS */ #ifdef KOREA if (IsInterim) ichInsert -= 2; #endif #ifdef DIAG { char rgch[200]; wsprintf(rgch, "MdInsUpdInsertCh: ichInsert %d cpInsert %lu\n\r ",ichInsert, cpInsert); CommSz(rgch); } #endif Assert(ichInsert <= cchInsBlock); if (ichInsert >= cchInsBlock) /* Should never be >, but... */ FlushInsert(); #ifdef DBCS ichInsertSave = ichInsert; if (HIBYTE(wInsert) != '\0') { fDBCSChar = TRUE; #ifdef KOREA /* 90.12.28 sangl */ // if (LOBYTE(HIWORD(vmsgLast.lParam)) == 0xF0) if (fInterim || LOBYTE(HIWORD(vmsgLast.lParam)) == 0xF0) // MSCH bklee 12/22/94 { if (IsInterim == 0) dxpCh = DxpFromCh( wInsert, FALSE ); // fix bug #5382 IsInterim ++; } else { WasInterim = IsInterim; IsInterim = 0; } #endif if (ichInsert + 1 >= cchInsBlock) { /* Not enough room in the insertion block */ FlushInsert(); #ifdef KOREA ichInsertSave = ichInsert; /* After flush, need to init ichInsertSave */ #endif } rgchInsert[ichInsert++] = chInsert = HIBYTE(wInsert); chShow = HIBYTE(wShow); } else { fDBCSChar = FALSE; chInsert = LOBYTE(wInsert); chShow = LOBYTE(wShow); } rgchInsert [ ichInsert++ ] = LOBYTE(wInsert); #else rgchInsert [ ichInsert++ ] = chInsert; #endif /* DBCS */ /* NOTE: we only affect the para cache if the char inserted is Eol/chSect. We explicitly invalidate in this case below; otherwise, no invalidation is necessary */ /* The following test works because chEol and chSect is not in the DBCS range. */ if ( (chInsert == chEol) || (chInsert == chSect) ) { /* Add a paragraph run to the scratch file */ struct PAP papT; /* Must invalidate the caches */ vdocParaCache = vfli.doc = docNil; #ifdef DBCS Assert(!fDBCSChar); /* Of course, you can't be too careful */ #endif /* DBCS */ /* Get props for new para mark */ /* NOTE: Under the new world, CachePara does not expect to ever */ /* see an Eol in the insertion piece */ ichInsert--; CachePara( docCur, cpInsert + cchInsBlock ); papT = vpapAbs; ichInsert++; #ifdef DEBUG if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter) { Assert( papT.rhc != 0 ); } #endif /* Write insert buf out to the scratch file */ EndInsert(); /* Add run for new para properties to the scratch file */ AddRunScratch( &vfkpdParaIns, &papT, vppapNormal, ((CchDiffer( &papT, &vpapPrevIns, cchPAP ) == 0) && (vfkpdParaIns.brun != 0)) ? -cchPAP : cchPAP, fcMacPapIns = (**hpfnfcb)[fnScratch].fcMac ); blt( &papT, &vpapPrevIns, cwPAP ); /* Add a new insertion piece to the doc and we're ready to go again */ InvalidateCaches( docCur ); FBeginInsert(); mdInsUpd = mdInsUpdWhole; /* Must update the whole screen */ } else if ( vfSuperIns && (chInsert != chNewLine) && (chInsert != chTab) && (chInsert != chNRHFile ) && (chInsert != chReturn) && !vfInsFontTooTall ) { /* We can do a superfast insert of this char */ ClearInsertLine(); #ifdef DBCS /* Because chShow contains the first byte of a DBCS character, even when it is a DBCS character, the following call to DxpFromCh() is OK. */ #ifdef KOREA if (fDBCSChar) dxpCh = DxpFromCh(wShow, FALSE); else dxpCh = DxpFromCh(chShow, FALSE); #else dxpCh = DxpFromCh( chShow, FALSE ); #endif if( dxpCh > 0 ){ // Maybe it's no need so marked off, by chienho #if defined(TAIWAN) || defined(KOREA) || defined(PRC) // dxpCh *= IsDBCSLeadByte(chShow) ? 2 : 1; #else dxpCh *= IsDBCSLeadByte(chShow) ? 2 : 1; #endif ScrollCurWw( prcScroll, dxpCh, 0 ); } TextOut( wwdCurrentDoc.hDC, vxpIns + 1, vypBaseIns - vfmiScreen.dypBaseline, (LPSTR) &rgchInsert[ichInsertSave], dcchBlted = fDBCSChar ? 2 : 1 ); #ifdef KOREA /* 90.12.28 sangl */ if ( IsInterim ) { unsigned kc; int dxpdiff; SetBkMode( wwdCurrentDoc.hDC, 2); /* Set to OPAQUR mode */ do { DrawInsertLine(); // while ( ((kc=KcInputNextHan()) < 0xA1) || (kc>0xFE) ); while ( (((kc=KcInputNextHan()) < 0x81) || (kc>0xFE)) && (kc != VK_MENU)); // MSCH bklee 12/22/94 if(kc == VK_MENU) return mdInsUpdLines; rgchInsert[ichInsertSave] = kc; rgchInsert[ichInsertSave+1] = GetDBCSsecond(); ClearInsertLine(); wShow = (kc<<8) + rgchInsert[ichInsertSave+1]; prcScroll->left += dxpCh; /* New left start of rect */ dxpdiff = -dxpCh; /* Save last dxpCh to go back */ dxpCh = DxpFromCh(wShow, FALSE); /* Get dxpCh of curr interim */ dxpdiff += dxpCh; if (dxpdiff < 0) prcScroll->left += dxpdiff; ScrollCurWw(prcScroll, dxpdiff, 0); TextOut( wwdCurrentDoc.hDC, vxpIns + 1, vypBaseIns - vfmiScreen.dypBaseline, (LPSTR)&rgchInsert[ichInsertSave], 2); // } while (LOBYTE(HIWORD(vmsgLast.lParam))==0xF0); /* End of If Hangeul */ } while (fInterim || LOBYTE(HIWORD(vmsgLast.lParam))==0xF0); // MSCH bklee 12/22/94 WasInterim = 1; IsInterim = 0; SetBkMode(wwdCurrentDoc.hDC, 1); /* Reset to TRANS mode */ } #endif /* KOREA */ vcchBlted += dcchBlted; #else /* Because chShow contains the first byte of a DBCS character, even when it is a DBCS character, the following call to DxpFromCh() is OK. */ if ((dxpCh = DxpFromCh( chShow, FALSE )) > 0) ScrollCurWw( prcScroll, dxpCh, 0 ); TextOut( wwdCurrentDoc.hDC, vxpIns + 1, vypBaseIns - vfmiScreen.dypBaseline, (LPSTR) &chShow, 1 ); vcchBlted++; #endif /* DBCS */ vxpCursLine = (vxpIns += dxpCh); DrawInsertLine(); /* Decide whether we have affected the next dl with this insertion */ if ( vxpIns >= vxpMacIns ) mdInsUpd = mdInsUpdLines; else if (!FImportantMsgPresent()) { /* No chars waiting; check for optional line update (word wrap) */ if ((dl = vdlIns) < wwdCurrentDoc.dlMac - 1) { vfli.doc = docNil; FormatInsLine(); /* Update vfli for vdlIns */ mdInsUpd = (vfli.cpMac != (**wwdCurrentDoc.hdndl) [dl + 1].cpMin) ? (FImportantMsgPresent() ? mdInsUpdNextChar : mdInsUpdOneLine) : mdInsUpdNothing; } } else /* Don't update; pay attention to the next character */ mdInsUpd = mdInsUpdNextChar; } else if (vfSuperIns) { /* In SuperInsMode but have a char we can't handle in SuperIns mode */ mdInsUpd = (vfInsFontTooTall) ? mdInsUpdWhole : mdInsUpdLines; } else { /* Non-superfast insertion; update line if we have to */ vfli.doc = docNil; FormatInsLine(); /* Update vfli for vdlIns */ /* Do the update only if: (1) the selection is no longer on the current line OR (2) No char is waiting */ #ifdef KOREA mdInsUpd = mdInsUpdLines; #else mdInsUpd = ( (selCur.cpFirst < vfli.cpMin) || (selCur.cpFirst >= vfli.cpMac) || !FImportantMsgPresent() ) ? mdInsUpdLines : mdInsUpdNextChar; #endif } Scribble( 10, mdInsUpd + '0' ); return mdInsUpd; } void NEAR FlushInsert() { /* Flush the insert buffer to the scratch file. Insert a piece (ahead of the QD insertion piece) that points to the characters flushed to the scratch file. Adjust CP's for the addition of the new scratch file piece. */ #ifdef DBCS /* The DBCS version of FlushInsert() is almost identical to the regular version, except it allows to insert an insertion block with one byte less than full. This allows us to assume that the piece boundary aligns with the DBCS boundary. */ typeFC fc = FcWScratch( rgchInsert, ichInsert ); int dcpDel; #if WINVER >= 0x300 if (!vfSysFull) /* The "tape dispenser bug replication method" has shown that holding down a key for 64k presses will cause FcWScratch() to run out of scratch-file space and fail. If we go ahead with the Replacement we'll corrupt the piece table, so we delicately avoid that problem 3/14/90..pault */ #endif { Assert( cchInsBlock - ichInsert <= 1); Repl1( docCur, cpInsert, (typeCP) 0, fnScratch, fc, (typeFC) ichInsert ); cpLimInserted += ichInsert; vfInvalid = fFalse; vpedlAdjustCp = (struct EDL *) 0; AdjustCp( docCur, cpInsert += ichInsert, (typeCP) (dcpDel = cchInsBlock - ichInsert), (typeCP) cchInsBlock ); if (vpedlAdjustCp) vpedlAdjustCp->dcpMac += (cchInsBlock - dcpDel); } #else typeFC fc = FcWScratch( rgchInsert, cchInsBlock ); #if WINVER >= 0x300 if (!vfSysFull) /* The "tape dispenser bug replication method" has shown that holding down a key for 64k presses will cause FcWScratch() to run out of scratch-file space and fail. If we go ahead with the Replacement we'll corrupt the piece table, so we delicately avoid that problem 3/14/90..pault */ #endif { Assert( ichInsert == cchInsBlock ); Repl1( docCur, cpInsert, (typeCP) 0, fnScratch, fc, (typeFC) cchInsBlock ); cpLimInserted += cchInsBlock; vfInvalid = fFalse; vpedlAdjustCp = (struct EDL *) 0; AdjustCp( docCur, cpInsert += cchInsBlock, (typeCP) 0, (typeFC) cchInsBlock ); if (vpedlAdjustCp) vpedlAdjustCp->dcpMac += cchInsBlock; } #endif /* DBCS */ vfInvalid = fTrue; ichInsert = 0; } int NEAR XpValidateInsertCache( rgdxp ) int *rgdxp; { /* Validate the contents of the insert width cache, consisting of: (parm) rgdxp: table of widths of chars on the current insert line (vdlIns) as last DisplayFli'd (global) vidxpInsertCache: -1 if invalid, index of current insert point otherwise (return value) xpMac: Mac pixel used on the insert line */ int xpMac; Assert( vidxpInsertCache == -1 ); vfli.doc = docNil; /* Force FormatLine to act */ /* Assert that FormatLine results will match screen contents */ Assert( (**wwdCurrentDoc.hdndl)[vdlIns].fValid ); /* Build vfli from insert line, extract cache info */ FormatInsLine(); blt( vfli.rgdxp, rgdxp, ichMaxLine ); xpMac = umin( vfli.xpRight + xpSelBar, wwdCurrentDoc.xpMac ); Assert( vcchBlted == 0); vidxpInsertCache = (int) (cpInsert + ichInsert - vfli.cpMin); Assert( vidxpInsertCache >= 0 && vidxpInsertCache < vfli.cpMac - vfli.cpMin); return xpMac; } void NEAR DelChars( cp, cch ) typeCP cp; int cch; { /* Delete cch characters at cp in docCur. We expect the request to be as results from repeated backspaces or forward deletes (not both); that is, the whole range extends backwards from (cpInsert + ichInsert) (non-inclusive) or forward from (cpInsert + cchInsBlock) (inclusive). We do not mark the vfli cache invalid, for speed. The Fast insert stuff will mark it invalid when it needs to. */ int cchNotInQD; typeCP cpUndoAdd; int cchNewDel=0; Assert( (cp == cpInsert + cchInsBlock) || /* Fwd Deletes */ (cp + cch == cpInsert + ichInsert)); /* Backsp */ cchNotInQD = cch - ichInsert; if (cp + cchNotInQD == cpInsert) { /* BACKSPACE */ if (cchNotInQD <= 0) { /* All deleted chars were in the QD buffer */ ichInsert -= cch; /* Do not mark the para cache invalid -- we have not affected the para cache world, since there are never chSect/chEol in the QD buffer, and we have not adjusted cp's */ return; } else { /* Backspacing before the QD buffer */ ichInsert = 0; if (cpStart > cp) { cpUndoAdd = cp0; cchNewDel = cpStart - cp; vuab.cp = cpStart = cp; /* cpStart has moved, and the count of cp's inserted has not changed -- we must adjust cpLimInserted */ cpLimInserted -= cchNewDel; } cpInsert -= cchNotInQD; } } /* End of if backspacing */ else { /* FORWARD DELETE */ typeCP dcpFrontier = (cp + cch - cpLimInserted); if (dcpFrontier > 0) { cpUndoAdd = CpMacText( docUndo ); cchNewDel = (int) dcpFrontier; cpLimDeleted += dcpFrontier; } cchNotInQD = cch; } /* Now we have: cchNewDel - chars deleted beyond previous limits (cpStart to cpLimDeleted) cpUndoAdd - where to add deleted chars to Undo doc (only set if cchNewDel > 0) cchNotInQD - chars deleted outside QD buffer */ if (cchNotInQD > cchNewDel) /* Deleting chars previously inserted during this AlphaMode session */ cpLimInserted -= (cchNotInQD - cchNewDel); /* Add the newly deleted stuff to the UNDO document. We find the { fn, fc } of the deleted char(s) so we can take advantage of Replace's optimizations wrt combining adjacent pieces (if the deletion is all one piece). */ if (cchNewDel > 0) { struct PCTB **hpctb=(**hpdocdod)[ docCur ].hpctb; int ipcd=IpcdFromCp( *hpctb, cp ); struct PCD *ppcd=&(*hpctb)->rgpcd [ipcd]; int fn=ppcd->fn; typeFC fc=ppcd->fc; Assert( ppcd->fn != fnNil && (ppcd+1)->cpMin >= cp ); if (bPRMNIL(ppcd->prm) && (cchNewDel <= (ppcd+1)->cpMin - cp)) { /* Deletion is all within one piece */ Replace( docUndo, cpUndoAdd, cp0, fn, fc + (cp - ppcd->cpMin), (typeFC) cchNewDel ); } else { ReplaceCps( docUndo, cpUndoAdd, cp0, docCur, cp, (typeCP) cchNewDel ); } switch ( vuab.uac ) { default: Assert( FALSE ); break; case uacDelNS: vuab.dcp += cchNewDel; break; case uacReplNS: vuab.dcp2 += cchNewDel; break; } } /* Remove deleted chars from the doc */ Replace( docCur, cp, (typeCP) cchNotInQD, fnNil, fc0, fc0 ); } FUpdateOneDl( dl ) int dl; { /* Update the display line dl. Mark dl+1 as invalid if, in the process formatting dl, we discover that there is not a clean cp or yp transition between the two lines (i.e. the ending yp or cp of dl do not match the starting ones of dl+1). Return TRUE iff we marked dl+1 invalid; FALSE otherwise Starting cp & yp of dl+1 are adjusted as necessary */ register struct EDL *pedl=&(**(wwdCurrentDoc.hdndl))[dl]; int fUpdate=fFalse; RECT rc; vfli.doc = docNil; FormatLine(docCur, pedl->cpMin, 0, wwdCurrentDoc.cpMac, flmSandMode); pedl = &(**wwdCurrentDoc.hdndl) [dl + 1]; /* next line is invalid if it exists (fValid || (pedl->cpMin != vfli.cpMac) || (pedl->yp - pedl->dyp != (pedl-1)->yp))) { pedl->fValid = fFalse; pedl->cpMin = vfli.cpMac; pedl->yp = (pedl-1)->yp + pedl->dyp; fUpdate = fTrue; } else { /* state is clean. Do not clear window dirty because more than one line may have been made invalid earlier */ /* Tell Windows we made this region valid */ #if WINVER >= 0x300 /* Only actually USE pedl if it's be valid! ..pault 2/21/90 */ if (dl + 1 < wwdCurrentDoc.dlMac) #endif { SetRect( (LPRECT) &rc, 0, wwdCurrentDoc.xpMac, pedl->yp - pedl->dyp, pedl->yp ); ValidateRect( wwdCurrentDoc.wwptr, (LPRECT) &rc ); } (--pedl)->fValid = fTrue; } DisplayFli(wwCur, dl, fFalse); return fUpdate; } void NEAR FormatInsLine() { /* Format line containing insertion point, using vdlIns as a basis Assume vdlIns's cpMin has not changed */ FormatLine( docCur, (**wwdCurrentDoc.hdndl) [vdlIns].cpMin, 0, wwdCurrentDoc.cpMac, flmSandMode ); /* Compensate for LoadFont calls in FormatLine so we don't have to set vfTextBltValid to FALSE */ LoadFont( docCur, &vchpInsert, mdFontChk ); } #ifdef DBCS /* Get the second byte of a DBCS character using a busy loop. */ CHAR near GetDBCSsecond() { int kc; CHAR chDBCS2; BOOL fGotKey; extern MSG vmsgLast; fGotKey = FALSE; do { if ( FImportantMsgPresent() ) { fGotKey = TRUE; if ((kc=KcAlphaKeyMessage( &vmsgLast )) != kcNil) { chDBCS2 = kc; if (vmsgLast.message == WM_KEYDOWN) { switch (kc) { default: GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 ); break; case kcAlphaVirtual: /* This means we can't anticipate the key's meaning before translation */ chDBCS2 = '\0'; if (!FNonAlphaKeyMessage(&vmsgLast, FALSE)) { GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 ); TranslateMessage( &vmsgLast ); } break; } } else { if (kc < 0) { chDBCS2 = '\0'; } GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 ); } } else { chDBCS2 = '\0'; } } } while (!fGotKey); /* As long as we go through the DBCS conversion window, this should not happen. */ Assert(chDBCS2 != '\0'); return chDBCS2; } #endif /* DBCS */