windows-nt/Source/XPSP1/NT/base/mvdm/wow16/write/insert.c
2020-09-26 16:20:57 +08:00

1799 lines
57 KiB
C

/************************************************************/
/* 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 <windows.h>
#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 (<dlMac) and
not following in cp space or not following in yp space
*/
if ( (dl + 1 < wwdCurrentDoc.dlMac) &&
(!pedl->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 */