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.
1574 lines
49 KiB
1574 lines
49 KiB
/************************************************************/
|
|
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
|
|
/************************************************************/
|
|
|
|
/* disp.c -- MW display routines */
|
|
|
|
#define NOKEYSTATE
|
|
#define NOSYSCOMMANDS
|
|
#define NOSHOWWINDOW
|
|
//#define NOATOM
|
|
#define NOCLIPBOARD
|
|
#define NOGDICAPMASKS
|
|
#define NOCTLMGR
|
|
#define NOWINSTYLES
|
|
//#define NOVIRTUALKEYCODES
|
|
#define NOSYSMETRICS
|
|
#define NOMENUS
|
|
#define NOSOUND
|
|
#define NOCOMM
|
|
#define NOOPENFILE
|
|
#define NOWH
|
|
#define NOWINOFFSETS
|
|
#define NOMETAFILE
|
|
#define NOMB
|
|
#define NODRAWTEXT
|
|
#include <windows.h>
|
|
|
|
#define NOUAC
|
|
#include "mw.h"
|
|
#include "debug.h"
|
|
#include "cmddefs.h"
|
|
#include "dispdefs.h"
|
|
#include "wwdefs.h"
|
|
#define NOKCCODES /* Removes all kc code defines */
|
|
#include "ch.h"
|
|
#include "docdefs.h"
|
|
#include "fmtdefs.h"
|
|
#include "propdefs.h"
|
|
#include "macro.h"
|
|
#include "printdef.h"
|
|
#include "fontdefs.h"
|
|
#if defined(OLE)
|
|
#include "obj.h"
|
|
#endif
|
|
#ifdef DBCS
|
|
#include "dbcs.h"
|
|
#endif
|
|
|
|
#ifdef CASHMERE /* No VisiMode in WinMemo */
|
|
extern int vfVisiMode;
|
|
#endif /* CASHMERE */
|
|
|
|
extern int vcchBlted;
|
|
extern int vidxpInsertCache;
|
|
extern int vdlIns;
|
|
extern int vfInsLast;
|
|
extern struct PAP vpapAbs;
|
|
extern struct SEP vsepAbs;
|
|
extern int rgval[];
|
|
extern struct DOD (**hpdocdod)[];
|
|
extern typeCP cpMacCur;
|
|
extern int vfSelHidden;
|
|
extern struct WWD rgwwd[];
|
|
extern int wwCur, wwMac;
|
|
extern struct FLI vfli;
|
|
extern struct SEL selCur;
|
|
extern struct WWD *pwwdCur;
|
|
extern int docCur;
|
|
extern struct CHP (**vhgchpFormat)[];
|
|
extern int vichpFormat;
|
|
extern typeCP cpMinCur;
|
|
extern typeCP cpMinDocument;
|
|
extern int vfInsertOn;
|
|
extern int vfTextBltValid;
|
|
extern typeCP vcpFirstParaCache;
|
|
extern typeCP vcpLimParaCache;
|
|
extern unsigned vpgn;
|
|
extern struct SEP vsepAbs;
|
|
extern CHAR stBuf[];
|
|
extern typeCP CpEdge();
|
|
extern typeCP CpMacText();
|
|
extern int vdocPageCache;
|
|
extern int vfPictSel;
|
|
extern int vfAwfulNoise;
|
|
extern int vfSkipNextBlink;
|
|
extern int dypMax;
|
|
extern HDC vhMDC;
|
|
extern HWND vhWndPageInfo;
|
|
extern struct FMI vfmiScreen;
|
|
extern int docScrap;
|
|
extern long rgbBkgrnd;
|
|
extern long ropErase;
|
|
extern BOOL vfMonochrome;
|
|
extern int dxpbmMDC;
|
|
extern int dypbmMDC;
|
|
extern HBITMAP hbmNull;
|
|
extern int vfOutOfMemory;
|
|
extern int vfSeeSel;
|
|
extern int vfInsEnd; /* Is insert point at end-of-line? */
|
|
extern int vipgd;
|
|
extern typeCP vcpMinPageCache;
|
|
extern typeCP vcpMacPageCache;
|
|
/* actual position of the cursor line */
|
|
extern int vxpCursLine;
|
|
extern int vypCursLine;
|
|
|
|
extern int vdypCursLine;
|
|
extern int vfScrollInval; /* means scroll did not take and UpdateWw must be repeated */
|
|
extern BOOL vfDead;
|
|
extern HRGN vhrgnClip;
|
|
|
|
|
|
/* G L O B A L S
|
|
int dlsMac = 0;*/
|
|
#ifdef DBCS
|
|
int donteat = 0; /* propagate not to eat message */
|
|
#endif
|
|
|
|
|
|
/* D I S P L A Y F L I */
|
|
/* Display formatted line in window ww at line dl */
|
|
|
|
|
|
DisplayFli(ww, dl, fDontDisplay)
|
|
int ww;
|
|
int dl;
|
|
int fDontDisplay; /* True if we set up dl info but don't display */
|
|
{
|
|
#ifdef KOREA // jinwoo: 92, 9, 28
|
|
/* process Subscript separatedly from descent */
|
|
#ifdef NODESC
|
|
extern int isSubs;
|
|
#endif
|
|
#endif
|
|
typeCP dcp;
|
|
typeCP dcpMac;
|
|
struct WWD *pwwd = &rgwwd[ww];
|
|
HDC hDC = pwwd->hDC;
|
|
int xp; /* Current xp to write text */
|
|
int yp; /* Current yp to write text */
|
|
int xpMin = pwwd->xpMin; /* Minimum xp in window */
|
|
int xpMac = pwwd->xpMac; /* Maximum xp in window */
|
|
int ypLine; /* Screen yp for current line */
|
|
int dxp; /* Width of current run */
|
|
int dyp; /* Line height */
|
|
int dxpExtra; /* Width of pad for each space */
|
|
typeCP cpMin;
|
|
typeCP cpMac;
|
|
int xpSel; /* xp of the start of the selection */
|
|
int dxpSel = 0; /* Width of the selection. */
|
|
CHAR chMark = '\0'; /* style character */
|
|
struct CHP *pchp;
|
|
BOOL fTabsKludge = (vfli.ichLastTab >= 0);
|
|
BOOL fInsertOn = FALSE;
|
|
int cBreakRun; /* break characters in run (no relation to Dick or Jane) */
|
|
|
|
#ifdef SMFONT
|
|
RECT rcOpaque;
|
|
#endif /* SMFONT */
|
|
|
|
#ifdef DDISP
|
|
CommSzNumNum(" DisplayFli: dl/fDontDisplay ", dl, fDontDisplay);
|
|
#endif
|
|
Assert(ww >= 0 && ww < wwMax);
|
|
#ifdef SMFONT
|
|
Assert(!fDontDisplay || vfli.fGraphics)
|
|
#endif /* SMFONT */
|
|
Scribble(5,'D');
|
|
|
|
/* Fill up EDL and set some useful locals */
|
|
{
|
|
register struct EDL *pedl = &(**pwwd->hdndl)[dl];
|
|
|
|
if (dl == vdlIns)
|
|
{
|
|
/* Overwriting chars blted during fast insert; reset blt count */
|
|
vcchBlted = 0;
|
|
vidxpInsertCache = -1;
|
|
}
|
|
|
|
pedl->xpLeft = vfli.xpLeft;
|
|
pedl->xpMac = vfli.xpReal;
|
|
cpMin = pedl->cpMin = vfli.cpMin;
|
|
pedl->dcpMac = (cpMac = vfli.cpMac) - cpMin;
|
|
dyp = pedl->dyp = vfli.dypLine;
|
|
pedl->ichCpMin = vfli.ichCpMin;
|
|
pedl->dcpDepend = (cpMin == cpMac) ? 0xff : vfli.dcpDepend;
|
|
pedl->fValid = TRUE;
|
|
pedl->fGraphics = vfli.fGraphics;
|
|
pedl->fSplat = vfli.fSplat;
|
|
|
|
/* The position of current line equals the position of the previous line
|
|
+ height of this line. */
|
|
#ifdef SMFONT
|
|
pedl->yp = rcOpaque.bottom = dyp + (ypLine = rcOpaque.top = (dl == 0 ?
|
|
pwwd->ypMin : (pedl - 1)->yp));
|
|
#else /* not SMFONT */
|
|
pedl->yp = dyp + (ypLine = (dl == 0 ? pwwd->ypMin :
|
|
(pedl - 1)->yp));
|
|
#endif /* SMFONT */
|
|
|
|
if (pedl->fIchCpIncr = (vfli.ichCpMac != 0))
|
|
{
|
|
/* Look at final text column */
|
|
++cpMac;
|
|
|
|
/* Since this is true, we can compress pedl->ichCpMac to 1 bit. */
|
|
Assert(vfli.ichCpMac == pedl->ichCpMin + 1);
|
|
}
|
|
}
|
|
|
|
if (vfli.doc == docNil)
|
|
{
|
|
/* This is the space beyond the end mark. */
|
|
PatBlt(hDC, 0, ypLine, xpMac, dyp, ropErase);
|
|
goto Finished;
|
|
}
|
|
|
|
/* Is there a character in the "style bar"? */
|
|
if (cpMin != cpMac)
|
|
{
|
|
|
|
#ifdef CASHMERE
|
|
/* This line is not completely empty (not after the end mark); check for
|
|
painting marks on the style bar. */
|
|
if (cpMin == vcpFirstParaCache && vpapAbs.rhc != 0)
|
|
{
|
|
/* This is a running-head. */
|
|
chMark = chStatRH;
|
|
}
|
|
else if ((**hpdocdod)[vfli.doc].hpgtb != 0)
|
|
#else /* not CASHMERE */
|
|
if (vpapAbs.rhc == 0 && (**hpdocdod)[vfli.doc].hpgtb != 0)
|
|
#endif /* CASHMERE */
|
|
|
|
{
|
|
if (vdocPageCache != vfli.doc || cpMac > vcpMacPageCache || cpMac <=
|
|
vcpMinPageCache)
|
|
{
|
|
CachePage(vfli.doc, cpMac - 1);
|
|
}
|
|
|
|
/* We are now guaranteed that cpMac is within the cached page. */
|
|
if (cpMin <= vcpMinPageCache && (!vfli.fGraphics || vfli.ichCpMin ==
|
|
0))
|
|
{
|
|
/* This is the first line of new page; show page mark. */
|
|
chMark = chStatPage;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef SMFONT
|
|
#ifdef DDISP
|
|
/* black out this line to test how efficiently/correctly we
|
|
overwrite pixels from previously-resident lines of text */
|
|
PatBlt(hDC, 0, ypLine, xpMac, dyp, BLACKNESS);
|
|
{ long int i; for (i=0; i < 500000; i++) ; }
|
|
#endif
|
|
|
|
/* Calculate dcpMac now, so we might be able to know how much to erase. */
|
|
dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal;
|
|
|
|
/* Erase any character that might be in the style bar. */
|
|
dxp = xpSelBar + 1;
|
|
if (!vfli.fGraphics)
|
|
{
|
|
dxp = xpMac; // clear the whole line
|
|
}
|
|
PatBlt(hDC, 0, ypLine, dxp, dyp, ropErase);
|
|
|
|
/* If this is graphics then go draw any characters in the style bar. */
|
|
if (vfli.fGraphics)
|
|
{
|
|
goto DrawMark;
|
|
}
|
|
|
|
/* If there are no "real" characters on this line then we can skip alot of
|
|
this. */
|
|
if (dcpMac == 0)
|
|
{
|
|
goto EndLine2;
|
|
}
|
|
#else /* not SMFONT */
|
|
if (vfli.fGraphics || fDontDisplay)
|
|
{
|
|
/* Erase any character that might be in the style bar. */
|
|
PatBlt(hDC, 0, ypLine, xpSelBar, dyp, ropErase);
|
|
goto DrawMark;
|
|
}
|
|
#endif /* SMFONT */
|
|
|
|
ValidateMemoryDC();
|
|
if (vhMDC == NULL)
|
|
{
|
|
Error:
|
|
/* Notify the user that an error has occured and simply erase this line.
|
|
*/
|
|
WinFailure();
|
|
PatBlt(hDC, xpSelBar, ypLine, xpMac - xpSelBar, dyp, ropErase);
|
|
goto Finished;
|
|
}
|
|
|
|
#ifndef SMFONT
|
|
/* Create a new bitmap for the memory DC if the current bitmap is not big
|
|
enough. */
|
|
if (xpMac > dxpbmMDC || dyp > dypbmMDC)
|
|
{
|
|
HBITMAP hbm;
|
|
|
|
/* If there is an old bitmap, then delete it. */
|
|
if (dxpbmMDC != 0 || dypbmMDC != 0)
|
|
{
|
|
DeleteObject(SelectObject(vhMDC, hbmNull));
|
|
}
|
|
|
|
/* Create the new bitmap and select it in. */
|
|
if ((hbm = CreateBitmap(dxpbmMDC = xpMac, dypbmMDC = dyp, 1, 1,
|
|
(LPSTR)NULL)) == NULL)
|
|
{
|
|
/* There should be a graceful way to recover if the bitmap is ever
|
|
NULL (e.g we don't have enough memory for it). */
|
|
dxpbmMDC = dypbmMDC = 0;
|
|
goto Error;
|
|
}
|
|
SelectObject(vhMDC, hbm);
|
|
}
|
|
|
|
/* Erase the are of the bitmap we are going to use. */
|
|
PatBlt(vhMDC, xpSelBar, 0, xpMac, dyp, vfMonochrome ? ropErase : WHITENESS);
|
|
#endif /* not SMFONT */
|
|
|
|
/* Initialize some of the variables we'll need. */
|
|
pchp = &(**vhgchpFormat)[0];
|
|
#ifdef SMFONT
|
|
xp = rcOpaque.left = rcOpaque.right = vfli.xpLeft + xpSelBar - xpMin + 1;
|
|
#else /* not SMFONT */
|
|
dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal;
|
|
xp = vfli.xpLeft + xpSelBar - xpMin + 1;
|
|
#endif /* SMFONT */
|
|
dxpExtra = fTabsKludge ? 0 : vfli.dxpExtra;
|
|
|
|
#ifdef SMFONT
|
|
/* If we are horizontally scrolled, then set the clip area to the area
|
|
outside of the selection bar. */
|
|
if (xpMin != 0)
|
|
{
|
|
IntersectClipRect(hDC, xpSelBar, rcOpaque.top, xpMac, rcOpaque.bottom);
|
|
}
|
|
#endif /* SMFONT */
|
|
|
|
for (dcp = 0; dcp < dcpMac; pchp++)
|
|
{
|
|
/* For all runs do: */
|
|
int ichFirst; /* First character in the current run */
|
|
int cchRun; /* Number of characters in the current run */
|
|
|
|
dcp = ichFirst = pchp->ichRun;
|
|
dcp += pchp->cchRun;
|
|
if (dcp > dcpMac)
|
|
{
|
|
dcp = dcpMac;
|
|
}
|
|
cchRun = dcp - ichFirst;
|
|
|
|
/* Compute dxp = sum of width of characters in current run (formerly
|
|
DxaFromIcpDcp). */
|
|
{
|
|
register int *pdxp;
|
|
register int cchT = cchRun;
|
|
PCH pch = vfli.rgch + ichFirst;
|
|
|
|
dxp = cBreakRun = 0;
|
|
pdxp = &vfli.rgdxp[ichFirst];
|
|
while (cchT-- > 0)
|
|
{
|
|
dxp += *pdxp++;
|
|
if (*pch++ == chSpace)
|
|
++cBreakRun;
|
|
}
|
|
#ifdef DDISP
|
|
CommSzNum(" dxp=",dxp);
|
|
#endif
|
|
}
|
|
|
|
if (dxp > 0)
|
|
{
|
|
int cchDone;
|
|
PCH pch = &vfli.rgch[ichFirst];
|
|
|
|
#ifdef KOREA //920525 KDLEE; jinwoo: 92, 9, 28
|
|
#ifdef NODESC
|
|
TEXTMETRIC tm;
|
|
#endif
|
|
#endif //KOREA
|
|
LoadFont(vfli.doc, pchp, mdFontScreen);
|
|
#ifdef KOREA //KDLEE 920525; jinwoo: 92, 9, 28
|
|
#ifdef NODESC
|
|
GetTextMetrics (vhMDC, (LPTEXTMETRIC)&tm);
|
|
|
|
if (tm.tmCharSet==HANGEUL_CHARSET)
|
|
yp = dyp - (vfli.dypBase/3) -((pchp->hpsPos != 0 ? (pchp->hpsPos <
|
|
hpsNegMin ? ypSubSuper : -ypSubSuper) : 0)) -
|
|
vfmiScreen.dypBaseline - (isSubs ? ypSubSuper : 0);
|
|
else
|
|
yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos <
|
|
hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) -
|
|
vfmiScreen.dypBaseline - (isSubs ? ypSubSuper : 0);
|
|
#else /* NODESC */
|
|
yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos <
|
|
hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) -
|
|
vfmiScreen.dypBaseline;
|
|
#endif /* NODESC */
|
|
#else /* KOREA */
|
|
|
|
yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos <
|
|
hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) -
|
|
vfmiScreen.dypBaseline;
|
|
#endif // KOREA jinwoo: 92, 9, 28
|
|
|
|
|
|
/* Note: tabs and other special characters are guaranteed to come at
|
|
the start of a run. */
|
|
SetTextJustification(vhMDC, dxpExtra * cBreakRun, cBreakRun);
|
|
#ifdef SMFONT
|
|
SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
|
|
#endif /* SMFONT */
|
|
cchDone = 0;
|
|
while (cchDone < cchRun)
|
|
{
|
|
int cch;
|
|
|
|
/* Does the wide-space zone begin in this run? */
|
|
if (vfli.fAdjSpace && (vfli.ichFirstWide < ichFirst + cchRun) &&
|
|
(ichFirst + cchDone <= vfli.ichFirstWide))
|
|
{
|
|
int cchDoneT = cchDone;
|
|
|
|
/* Is this the beginning of the wide-space zone? */
|
|
if (ichFirst + cchDone == vfli.ichFirstWide)
|
|
{
|
|
/* Reset the width of the spaces. */
|
|
SetTextJustification(vhMDC, ++dxpExtra * cBreakRun, cBreakRun);
|
|
#ifdef SMFONT
|
|
SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
|
|
#endif /* SMFONT */
|
|
cch = cchRun - cchDone;
|
|
cchDone = cchRun;
|
|
}
|
|
else
|
|
{
|
|
cchDone = cch = vfli.ichFirstWide - ichFirst;
|
|
}
|
|
|
|
/* This run is cut short because of a wide space, so we need
|
|
to calculate a new width. */
|
|
{
|
|
register int *pdxp;
|
|
register int cchT = cch;
|
|
PCH pch = &vfli.rgch[ichFirst + cchDoneT];
|
|
|
|
dxp = 0;
|
|
pdxp = &vfli.rgdxp[ichFirst + cchDoneT];
|
|
while (cchT-- > 0)
|
|
{
|
|
dxp += *pdxp++;
|
|
if (*pch++ == chSpace)
|
|
++cBreakRun;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cchDone = cch = cchRun;
|
|
}
|
|
|
|
while (cch > 0)
|
|
{
|
|
switch (*pch)
|
|
{
|
|
CHAR ch;
|
|
int dxpT;
|
|
|
|
case chTab:
|
|
|
|
#ifdef CASHMERE
|
|
/* chLeader contains tab leader character (see
|
|
FormatLine) */
|
|
if ((ch = pchp->chLeader) != chSpace)
|
|
{
|
|
int cxpTab;
|
|
CHAR rgch[32];
|
|
int dxpLeader = CharWidth(ch);
|
|
int xpT = xp;
|
|
int iLevelT = SaveDC(vhMDC);
|
|
|
|
SetBytes(&rgch[0], ch, 32);
|
|
dxpT = vfli.rgdxp[ichFirst];
|
|
cxpTab = ((dxpT + dxpLeader - 1) / dxpLeader + 31)
|
|
>> 5;
|
|
|
|
xp += dxpT;
|
|
|
|
while (cxpTab-- > 0)
|
|
{
|
|
TextOut(vhMDC, xpT, yp, (LPSTR)rgch, 32);
|
|
xpT += dxpLeader << 5;
|
|
}
|
|
RestoreDC(vhMDC, iLevelT);
|
|
}
|
|
else
|
|
#endif /* CASHMERE */
|
|
|
|
{
|
|
#ifdef SMFONT
|
|
/* Expand the opaque rectangle to include the tab.
|
|
*/
|
|
rcOpaque.right += vfli.rgdxp[ichFirst];
|
|
#endif /* SMFONT */
|
|
xp += vfli.rgdxp[ichFirst];
|
|
}
|
|
|
|
if (fTabsKludge && ichFirst >= vfli.ichLastTab)
|
|
{
|
|
SetTextJustification(vhMDC, (dxpExtra =
|
|
vfli.dxpExtra) * cBreakRun, cBreakRun);
|
|
#ifdef SMFONT
|
|
SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
|
|
#endif /* SMFONT */
|
|
fTabsKludge = FALSE;
|
|
}
|
|
dxp -= vfli.rgdxp[ichFirst];
|
|
pch++;
|
|
cch--;
|
|
goto EndLoop;
|
|
|
|
#ifdef CASHMERE
|
|
case schPage:
|
|
if (!pchp->fSpecial)
|
|
{
|
|
goto EndLoop;
|
|
}
|
|
stBuf[0] = CchExpPgn(&stBuf[1], vpgn, vsepAbs.nfcPgn,
|
|
flmSandMode, ichMaxLine);
|
|
goto DrawSpecial;
|
|
|
|
case schFootnote:
|
|
if (!pchp->fSpecial)
|
|
{
|
|
goto EndLoop;
|
|
}
|
|
stBuf[0] = CchExpFtn(&stBuf[1], cpMin + ichFirst,
|
|
flmSandMode, ichMaxLine);
|
|
DrawSpecial:
|
|
#else /* not CASHMERE */
|
|
case schPage:
|
|
case schFootnote:
|
|
if (!pchp->fSpecial)
|
|
{
|
|
goto EndLoop;
|
|
}
|
|
stBuf[0] = *pch == schPage && (wwdCurrentDoc.fEditHeader
|
|
|| wwdCurrentDoc.fEditFooter) ? CchExpPgn(&stBuf[1],
|
|
vpgn, 0, flmSandMode, ichMaxLine) :
|
|
CchExpUnknown(&stBuf[1], flmSandMode, ichMaxLine);
|
|
#endif /* not CASHMERE */
|
|
|
|
#ifdef SMFONT
|
|
/* Calculate the opaque rectangle. */
|
|
rcOpaque.right += vfli.rgdxp[ichFirst] +
|
|
vfmiScreen.dxpOverhang;
|
|
|
|
TextOut(hDC, xp, ypLine+yp, &stBuf[1], stBuf[0]);
|
|
#else /* not SMFONT */
|
|
TextOut(vhMDC, xp, yp, (LPSTR)&stBuf[1], stBuf[0]);
|
|
#endif /* SMFONT */
|
|
break;
|
|
|
|
default:
|
|
goto EndLoop;
|
|
}
|
|
|
|
dxp -= vfli.rgdxp[ichFirst];
|
|
#ifdef SMFONT
|
|
/* End the line if no more will fit into the window. */
|
|
if ((xp += vfli.rgdxp[ichFirst++]) >= xpMac) {
|
|
goto EndLine;
|
|
}
|
|
rcOpaque.left = (rcOpaque.right = xp) +
|
|
vfmiScreen.dxpOverhang;
|
|
#else /* not SMFONT */
|
|
xp += vfli.rgdxp[ichFirst++];
|
|
#endif /* SMFONT */
|
|
pch++;
|
|
cch--;
|
|
}
|
|
EndLoop:
|
|
|
|
#ifdef SMFONT
|
|
if (cch == 0)
|
|
{
|
|
Assert(dxp == 0);
|
|
}
|
|
else
|
|
{
|
|
/* Calculate the opaque rectangle. */
|
|
rcOpaque.right += dxp + vfmiScreen.dxpOverhang;
|
|
|
|
#if 0
|
|
{
|
|
char msg[180];
|
|
wsprintf(msg,"putting out %d characters\n\r",cch);
|
|
OutputDebugString(msg);
|
|
}
|
|
#endif
|
|
/* Output cch characters starting at pch */
|
|
TextOut(hDC, xp, ypLine+yp, pch, cch);
|
|
|
|
/* End the line if no more will fit into the window. */
|
|
if ((xp += dxp) >= xpMac)
|
|
{
|
|
goto EndLine;
|
|
}
|
|
rcOpaque.left = (rcOpaque.right = xp) +
|
|
vfmiScreen.dxpOverhang;
|
|
pch += cch;
|
|
}
|
|
#else /* not SMFONT */
|
|
/* Output cch characters starting at pch */
|
|
TextOut(vhMDC, xp, yp, (LPSTR)pch, cch);
|
|
xp += dxp;
|
|
pch += cch;
|
|
#endif /* SMFONT */
|
|
} /* end while (cchDone<cchRun) */
|
|
} /* end if (dxp>0) */
|
|
} /* end for dcp=0..dcpMac */
|
|
|
|
#ifdef SMFONT
|
|
EndLine:
|
|
/* Restore the clip region if need be. */
|
|
if (xpMin != 0)
|
|
{
|
|
SelectClipRgn(hDC, NULL);
|
|
}
|
|
EndLine2:
|
|
#endif /* SMFONT */
|
|
|
|
#ifdef CASHMERE
|
|
if (vfVisiMode)
|
|
{
|
|
AddVisiSpaces(ww, &(**pwwd->hdndl)[dl], vfli.dypBase, vfli.dypAfter +
|
|
vfli.dypFont);
|
|
}
|
|
#endif /* CASHMERE */
|
|
|
|
vfTextBltValid = FALSE;
|
|
|
|
if ((ww == wwCur) && (pwwd->doc != docScrap) && !vfSelHidden &&
|
|
(selCur.cpLim >= cpMin))
|
|
{
|
|
if (selCur.cpFirst <= cpMac)
|
|
{
|
|
/* Show selection */
|
|
int xpFirst;
|
|
int xpLim;
|
|
|
|
#ifdef ENABLE
|
|
if (vfli.fSplatNext && selCur.cpFirst == selCur.cpLim &&
|
|
selCur.cpFirst == cpMac)
|
|
{
|
|
vfInsEnd = TRUE;
|
|
ClearInsertLine();
|
|
}
|
|
vfInsertOn = FALSE;
|
|
#endif /* ENABLE */
|
|
|
|
if (selCur.cpFirst <= cpMin && selCur.cpLim >= cpMac)
|
|
{
|
|
xpFirst = vfli.xpLeft;
|
|
xpLim = vfli.xpReal;
|
|
}
|
|
else if (selCur.cpFirst < cpMac || (selCur.cpLim == cpMac &&
|
|
vfInsEnd))
|
|
{
|
|
typeCP cpBegin = CpMax(cpMin, selCur.cpFirst);
|
|
typeCP cpEnd = CpMin(cpMac, selCur.cpLim);
|
|
|
|
dxp = DxpDiff((int)(cpBegin - cpMin), (int)(cpEnd - cpBegin),
|
|
&xpFirst);
|
|
xpLim = min(xpMin + vfli.xpReal, xpFirst + dxp);
|
|
}
|
|
else
|
|
{
|
|
goto DidntHighlight;
|
|
}
|
|
|
|
xpSel = xpSelBar + max(xpFirst - xpMin, 0);
|
|
if (xpLim > xpFirst)
|
|
{
|
|
/* Set highlighting at desired screen position. */
|
|
dxpSel = max(xpLim - max(xpFirst, xpMin), 0);
|
|
}
|
|
else if (selCur.cpFirst == selCur.cpLim && ((selCur.cpLim != cpMac)
|
|
^ vfInsEnd))
|
|
{
|
|
vfInsertOn = FALSE; /* Because we redisplayed insert pt line */
|
|
|
|
#ifdef CASHMERE
|
|
vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter);
|
|
vypCursLine = ypLine + dyp - vfli.dypAfter;
|
|
#else /* not CASHMERE */
|
|
vdypCursLine = vfli.dypFont;
|
|
vypCursLine = ypLine + dyp;
|
|
#endif /* not CASHMERE */
|
|
|
|
vxpCursLine = xpSel;
|
|
|
|
/* Start blinking in a while */
|
|
vfSkipNextBlink = TRUE;
|
|
|
|
fInsertOn = xpFirst >= xpMin;
|
|
}
|
|
|
|
DidntHighlight:;
|
|
}
|
|
}
|
|
|
|
#ifdef SMFONT
|
|
/* Invert the selection */
|
|
if (dxpSel != 0) {
|
|
PatBlt(hDC, xpSel, ypLine, dxpSel, dyp, DSTINVERT);
|
|
}
|
|
#else /* not SMFONT */
|
|
/* Blt the line of text onto the screen. */
|
|
PatBlt(vhMDC, 0, 0, xpSelBar, dyp, vfMonochrome ? ropErase : WHITENESS);
|
|
if (dxpSel == 0)
|
|
{
|
|
BitBlt(hDC, 0, ypLine, xpMac, dyp, vhMDC, 0, 0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
BitBlt(hDC, 0, ypLine, xpSel, dyp, vhMDC, 0, 0, SRCCOPY);
|
|
BitBlt(hDC, xpSel, ypLine, dxpSel, dyp, vhMDC, xpSel, 0, NOTSRCCOPY);
|
|
xpSel += dxpSel;
|
|
BitBlt(hDC, xpSel, ypLine, xpMac - xpSel, dyp, vhMDC, xpSel, 0,
|
|
SRCCOPY);
|
|
}
|
|
#endif /* SMFONT */
|
|
|
|
/* Draw the insertion bar if necessary. */
|
|
if (fInsertOn)
|
|
{
|
|
DrawInsertLine();
|
|
}
|
|
|
|
DrawMark:
|
|
/* Draw the character in the style bar if necessary. */
|
|
if (chMark != '\0')
|
|
{
|
|
#ifdef SYSENDMARK
|
|
struct CHP chpT;
|
|
extern struct CHP vchpNormal;
|
|
|
|
blt(&vchpNormal, &chpT, cwCHP);
|
|
chpT.ftc = ftcSystem;
|
|
chpT.ftcXtra = 0;
|
|
chpT.hps = hpsDefault;
|
|
|
|
/* Draw the style character in the standard font. */
|
|
LoadFont(vfli.doc, &chpT, mdFontScreen);
|
|
|
|
TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline,
|
|
(LPSTR)&chMark, 1);
|
|
#else /* ifdef SYSENDMARK */
|
|
/* Draw the style character in the standard font. */
|
|
LoadFont(vfli.doc, NULL, mdFontScreen);
|
|
TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline,
|
|
(LPSTR)&chMark, 1);
|
|
#endif /* if-else-def SYSENDMARK */
|
|
}
|
|
|
|
if (vfli.fGraphics)
|
|
{
|
|
DisplayGraphics(ww, dl, fDontDisplay);
|
|
}
|
|
|
|
Finished:
|
|
Scribble(5,' ');
|
|
}
|
|
|
|
|
|
/* D X P D I F F */
|
|
DxpDiff(dcpFirst, dcp, pdxpFirst)
|
|
int dcpFirst;
|
|
int dcp;
|
|
int *pdxpFirst;
|
|
{
|
|
#if 1
|
|
register int *pdxp = &vfli.rgdxp[0];
|
|
register int cch;
|
|
int dxp = vfli.xpLeft;
|
|
#ifdef ENABLE /* Not used */
|
|
int ichLim = dcpFirst + dcp;
|
|
#endif
|
|
|
|
|
|
if (dcp > vfli.ichMac - dcpFirst)
|
|
{ /* This should not be, but is when we have a CR */
|
|
//Assert( dcpFirst < vfli.ichMac );
|
|
dcp = vfli.ichMac - dcpFirst;
|
|
}
|
|
|
|
for (cch = 0; cch < dcpFirst; ++cch)
|
|
{
|
|
dxp += *pdxp++;
|
|
}
|
|
*pdxpFirst = dxp;
|
|
dxp = 0;
|
|
for (cch = 0; cch < dcp; ++cch)
|
|
{
|
|
dxp += *pdxp++;
|
|
}
|
|
return dxp;
|
|
#else
|
|
|
|
int dxp;
|
|
if (dcp > vfli.ichMac - dcpFirst)
|
|
{ /* This should not be, but is when we have a CR */
|
|
Assert( dcpFirst < vfli.ichMac );
|
|
dcp = vfli.ichMac - dcpFirst;
|
|
}
|
|
|
|
/* first get space up to first character */
|
|
*pdxpFirst = LOWORD(GetTextExtent(hDC,vfli.rgch,dcpFirst)) + vfli.xpLeft;
|
|
|
|
/* now get space between first and first+dcp */
|
|
dxp = LOWORD(GetTextExtent(hDC,vfli.rgch+dcpFirst,dcp));
|
|
return dxp;
|
|
#endif
|
|
}
|
|
|
|
|
|
UpdateDisplay(fAbortOK)
|
|
int fAbortOK;
|
|
{
|
|
int ww;
|
|
|
|
if (wwMac <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef CASHMERE
|
|
for (ww = 0; ww < wwMac; ww++)
|
|
if ( rgwwd[ww].doc != docScrap )
|
|
{
|
|
UpdateWw(ww, fAbortOK);
|
|
if (rgwwd[ww].fDirty || vfOutOfMemory)
|
|
{
|
|
return; /* update has been interrupted */
|
|
}
|
|
}
|
|
#else /* not CASHMERE */
|
|
UpdateWw(wwDocument, fAbortOK);
|
|
if (wwdCurrentDoc.fDirty || vfOutOfMemory)
|
|
{
|
|
/* Update has been interrupted */
|
|
return;
|
|
}
|
|
#endif /* not CASHMERE */
|
|
|
|
if (wwdCurrentDoc.fRuler)
|
|
{
|
|
UpdateRuler();
|
|
}
|
|
}
|
|
|
|
|
|
/* U P D A T E W W */
|
|
UpdateWw(ww, fAbortOK)
|
|
int ww, fAbortOK;
|
|
{ /* Redisplay ww as necessary */
|
|
extern int vfWholePictInvalid;
|
|
register struct WWD *pwwd = &rgwwd[ww];
|
|
int dlMac;
|
|
int dlOld, dlNew;
|
|
int doc;
|
|
int ichCp;
|
|
struct EDL *pedlNew;
|
|
register struct EDL *pedl;
|
|
struct EDL (**hdndl)[]=pwwd->hdndl;
|
|
int dypDiff;
|
|
int ypTop;
|
|
int ypFirstInval;
|
|
int dr;
|
|
int fLastNotShown;
|
|
typeCP cp, cpMacWw;
|
|
|
|
if (!pwwd->fDirty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!((**hpdocdod)[pwwd->doc].fDisplayable))
|
|
return;
|
|
|
|
if (fAbortOK && FImportantMsgPresent())
|
|
return;
|
|
|
|
#if 0 // how to get first and last cp's in invalid rect?
|
|
#if defined(OLE)
|
|
/*
|
|
Load visible objects. Do it now rather than in DisplayGraphics()
|
|
because here it has less chance of disrupting the state variables
|
|
upon which UpdateWw depends.
|
|
*/
|
|
ObjEnumInRange(docCur,cpMinCur,cpMacCur,ObjLoadObjectInDoc);
|
|
#endif
|
|
#endif
|
|
|
|
dlMac = pwwd->dlMac;
|
|
ypTop = pwwd->ypMin;
|
|
|
|
Assert( ww >= 0 && ww < wwMax );
|
|
vfli.doc = docNil; /* An aid to Fast Insert */
|
|
|
|
UpdateInvalid(); /* InvalBand for what Windows considers to be invalid */
|
|
ypFirstInval = pwwd->ypFirstInval;
|
|
|
|
#ifndef CASHMERE
|
|
Assert( ww == wwCur ); /* A MEMO-only assumption */
|
|
#endif /* CASHMERE */
|
|
|
|
Scribble(5, 'U');
|
|
|
|
ValidateMemoryDC(); /* to do any update, we need a good memory DC */
|
|
if (vhMDC == NULL)
|
|
{
|
|
WinFailure();
|
|
return;
|
|
}
|
|
|
|
doc = pwwd->doc;
|
|
vfli.doc = docNil;
|
|
|
|
if (pwwd->fCpBad)
|
|
{
|
|
/* cp first displayed has not been blessed */
|
|
|
|
#ifdef CASHMERE /* Must do this if ww != wwCur assertion is FALSE */
|
|
int wwT = wwCur;
|
|
if (ww != wwCur && wwCur >= 0)
|
|
/* CtrBackTrs cache is only good for wwCur. Treat != case */
|
|
{
|
|
if (pwwdCur->fDirty) /* Do wwCur first, saving cache */
|
|
UpdateWw(wwCur, fAbortOK);
|
|
|
|
if (fAbortOK && FImportantMsgPresent())
|
|
return;
|
|
|
|
ChangeWw(ww, false);
|
|
CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */
|
|
ChangeWw(wwT, false);
|
|
}
|
|
else
|
|
#endif /* CASHMERE */
|
|
|
|
{
|
|
if (fAbortOK && FImportantMsgPresent())
|
|
return;
|
|
|
|
CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */
|
|
}
|
|
}
|
|
|
|
/* check for cpMin accessible in this ww */
|
|
RestartUpdate:
|
|
vfWholePictInvalid = fTrue; /* Tells DisplayGraphics to
|
|
abandon accumulated partial pict rect */
|
|
fLastNotShown = fFalse;
|
|
cp = CpMax(pwwd->cpMin, pwwd->cpFirst);
|
|
cpMacWw = pwwd->cpMac;
|
|
ichCp = pwwd->ichCpFirst;
|
|
|
|
/* Note test for dlNew==0 that guarantees that there will be at least
|
|
one dl -- this was added for WRITE because we do not have
|
|
the ability to enforce a minimum window size */
|
|
|
|
for (dlNew = dlOld = 0; ypTop < pwwd->ypMac || (dlNew == 0) ; dlNew++)
|
|
/* we have: cp, ichCP: pints to text desired on the coming line dlNew
|
|
ypTop: desired position for top of dlNew -1
|
|
dlOld: next line to be considered for re-use
|
|
*/
|
|
/* check for having to extend dndl array */
|
|
{
|
|
if (dlNew >= (int)pwwd->dlMax)
|
|
{
|
|
/* extend the array with uninitialized dl's, increment max, break if no space.
|
|
We assume that dlMac(Old) was <= dlMax, so the dl's will not be looked at
|
|
but used only to store new lines */
|
|
#define ddlIncr 5
|
|
|
|
if (!FChngSizeH(hdndl, (pwwd->dlMax + ddlIncr) * cwEDL, fFalse))
|
|
break;
|
|
pwwd->dlMax += ddlIncr;
|
|
}
|
|
/* discard unusable dl's */
|
|
for (; dlOld < dlMac; dlOld++)
|
|
{ /* Set dlOld and pedl to the next good dl */
|
|
int ypTopOld, ypOld;
|
|
|
|
/* Re-entrant Heap Movement */
|
|
if (fAbortOK && !fLastNotShown && FImportantMsgPresent())
|
|
goto RetInval;
|
|
|
|
pedl = &(**hdndl)[dlOld];
|
|
ypOld = pedl->yp;
|
|
|
|
/* loop if: invalid, passed over in cp space, passed over in dl space,
|
|
passed over in yp space,
|
|
in invalid band, passed over in ich space */
|
|
if (!pedl->fValid || dlOld < dlNew || pedl->cpMin < cp
|
|
|| (ypTopOld = (ypOld - pedl->dyp)) < ypTop
|
|
|| (ypOld >= ypFirstInval && ypTopOld <= pwwd->ypLastInval)
|
|
|| (pedl->cpMin == cp && pedl->ichCpMin < ichCp))
|
|
continue;
|
|
/* now we have dlOld, an acceptable if not necessarily useful dl.
|
|
now compute dlNew either from scratch or by re-using dlOld. To be
|
|
re-useable, dlOld must have right cp/ichCp pair, plus be totally on screen
|
|
or, if it is a partial line, it must stay still or move down - not up */
|
|
if (pedl->cpMin == cp && pedl->ichCpMin == ichCp &&
|
|
(ypOld <= pwwd->ypMac || ypTopOld <= ypTop))
|
|
{
|
|
/* Re-use this dl */
|
|
int yp = ypTop;
|
|
if (fLastNotShown)
|
|
{
|
|
/* HEAP MOVEMENT */
|
|
DisplayFli(ww, dlNew - 1, fLastNotShown = fFalse);
|
|
pedl = &(**hdndl)[dlOld];
|
|
}
|
|
|
|
cp = pedl->cpMin + pedl->dcpMac;
|
|
ichCp = pedl->fIchCpIncr ? pedl->ichCpMin + 1 : 0;
|
|
ypTop += pedl->dyp;
|
|
if (dlOld != dlNew || ypTopOld != yp)
|
|
{
|
|
DypScroll(ww, dlOld, dlNew - dlOld, yp);
|
|
if (vfScrollInval)
|
|
{
|
|
/* There was a popup; invalid region might have changed */
|
|
/* fLastNotShown test is for interrupting picture display */
|
|
/* before we've really displayed it */
|
|
|
|
(**hdndl) [dlOld].fValid = fFalse;
|
|
goto Restart1;
|
|
}
|
|
dlMac += dlNew - dlOld;
|
|
}
|
|
dlOld = dlNew + 1;
|
|
goto NextDlNew;
|
|
}
|
|
break;
|
|
}
|
|
/* cpMin > cp, the line is not anywhere so it will have to be formatted
|
|
from scratch */
|
|
|
|
if (fAbortOK && !fLastNotShown && FImportantMsgPresent())
|
|
goto RetInval;
|
|
|
|
FormatLine(doc, cp, ichCp, cpMacWw, flmSandMode); /* Creates vfli */
|
|
|
|
if (vfOutOfMemory)
|
|
goto RetInval;
|
|
|
|
ichCp = vfli.ichCpMac;
|
|
cp = vfli.cpMac;
|
|
/* advance invalid band so that update can resume after an interruption */
|
|
pwwd->ypFirstInval = (ypTop += vfli.dypLine);
|
|
pedl = &(**hdndl)[dlOld];
|
|
if (dlOld < dlMac && pedl->cpMin == cp && pedl->ichCpMin == ichCp)
|
|
{
|
|
int dlT = dlOld;
|
|
|
|
/* line at dlOld is a valid, existing line that will abutt the line just about
|
|
to be displayed. */
|
|
if (dlOld == dlNew && pedl->yp - pedl->dyp <= ypTop)
|
|
/* the line about to be overwritten will be re-used in the next loop.
|
|
Hence, it is worthwhile to save this line and its dl */
|
|
DypScroll(ww, dlOld++, 1, ypTop);
|
|
else
|
|
/* Move the next line to its abutting position. We know that it has not yet been
|
|
overwritten (yp, dlOld all > than ypTop, dlNew) */
|
|
DypScroll(ww, dlOld, 0, ypTop);
|
|
|
|
if (vfScrollInval)
|
|
{
|
|
/* There was a popup; invalid region might have changed */
|
|
/* fLastNotShown test is for interrupting picture display */
|
|
/* before we've really displayed it */
|
|
|
|
(**hdndl) [dlT].fValid = fFalse;
|
|
Restart1:
|
|
if (fLastNotShown)
|
|
{
|
|
pwwd->ypFirstInval = pwwd->ypMin;
|
|
}
|
|
|
|
ypFirstInval = pwwd->ypFirstInval;
|
|
ypTop = pwwd->ypMin;
|
|
goto RestartUpdate;
|
|
}
|
|
}
|
|
|
|
/* true in 3rd param means put off picture redisplay till later */
|
|
/* condition: graphics & not last in picture & not last in y space and
|
|
not in front of a invalid or valid transition in the picture */
|
|
DisplayFli(ww, dlNew, fLastNotShown =
|
|
(vfli.fGraphics && vfli.ichCpMac!=0 && ypTop < pwwd->ypMac));
|
|
NextDlNew:;
|
|
}
|
|
Break1:
|
|
pwwd->dlMac = dlNew;
|
|
|
|
#ifdef CASHMERE
|
|
/* condition is here to avoid swapping */
|
|
if (pwwd->fSplit && rgwwd[pwwd->ww].fFtn)
|
|
CalcFtnLimits(pwwd);
|
|
#endif /* CASHMERE */
|
|
|
|
SetCurWwVScrollPos(); /* Set Scroll bar position */
|
|
vfTextBltValid = false;
|
|
|
|
/* reset invalid indications */
|
|
pwwd->fDirty = false;
|
|
pwwd->ypFirstInval = ypMaxAll;
|
|
pwwd->ypLastInval = 0; /* so that max in InvalBand will work */
|
|
Scribble(5, ' ');
|
|
goto Validate;
|
|
|
|
/* Before returning from an interrupt, invalidate lines that were overwritten
|
|
within the present update. */
|
|
RetInval:
|
|
Scribble(5, ' ');
|
|
for (; dlOld < dlMac; dlOld++)
|
|
{
|
|
pedl = &(**hdndl)[dlOld];
|
|
if ((pedl->yp - pedl->dyp) < ypTop)
|
|
pedl->fValid = fFalse;
|
|
else
|
|
break;
|
|
}
|
|
Validate: ;
|
|
|
|
#ifdef ENABLE /* We will let UpdateInvalid handle this in case
|
|
further invalidation occurred during the update */
|
|
|
|
{ /* Tell Windows that the part we updated is valid */
|
|
RECT rc;
|
|
|
|
rc.left = 0;
|
|
rc.top = pwwd->ypMin;
|
|
rc.right = pwwd->xpMac;
|
|
rc.bottom = imin( pwwd->ypMac, ypTop );
|
|
ValidateRect( pwwd->wwptr, (LPRECT)&rc );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
/* D Y P S C R O L L */
|
|
DypScroll(ww, dlFirst, ddl, ypTo)
|
|
int ww, dlFirst, ddl, ypTo;
|
|
{
|
|
/* Scroll dl's in a window, from dlFirst to end, down ddl lines (or up -ddl).
|
|
Bitmap is moved from top of dlFirst to ypTo. The yp's of the dl's are updated.
|
|
Returns the amount scrolled. (positive means down). */
|
|
|
|
register struct WWD *pwwd = &rgwwd[ww];
|
|
int dlMac;
|
|
int dlT;
|
|
int ypFrom;
|
|
int dypChange;
|
|
int cdlBelow;
|
|
struct EDL *pedl;
|
|
struct EDL *pedlT;
|
|
|
|
/* Do not call procedures while dndl is loaded up to avoid heap movement */
|
|
struct EDL *dndl = &(**(pwwd->hdndl))[0];
|
|
|
|
Assert( ww >= 0 && ww < wwMax );
|
|
|
|
vfScrollInval = fFalse;
|
|
|
|
/* Number of dl's below (and including) the first one to be scrolled */
|
|
cdlBelow = pwwd->dlMac - dlFirst;
|
|
pwwd->dlMac = min(pwwd->dlMac + ddl, pwwd->dlMax);
|
|
cdlBelow = max(0, min(cdlBelow, pwwd->dlMac - ddl - dlFirst));
|
|
|
|
pedlT = &dndl[dlFirst];
|
|
ypFrom = pedlT->yp - pedlT->dyp;
|
|
|
|
/* Length of area to be moved */
|
|
dypChange = ypTo - ypFrom;
|
|
|
|
if (cdlBelow > 0)
|
|
{
|
|
int dlTo = dlFirst + ddl;
|
|
int ypMac = pwwd->ypMac;
|
|
|
|
pedlT = &dndl[dlTo];
|
|
if (ddl != 0)
|
|
{
|
|
blt(&dndl[dlFirst], pedlT, cwEDL * cdlBelow);
|
|
}
|
|
|
|
for (dlT = dlTo; dlT < pwwd->dlMac; ++dlT, ++pedlT)
|
|
{
|
|
if (dypChange < 0 && pedlT->yp > ypMac)
|
|
{
|
|
/* Invalidate dl's that are pulled in from the ozone below ypMac
|
|
*/
|
|
pedlT->fValid = fFalse;
|
|
}
|
|
else
|
|
{
|
|
pedlT->yp += dypChange;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dypChange != 0)
|
|
{
|
|
RECT rc;
|
|
|
|
SetRect( (LPRECT)&rc, 0, min(ypFrom, ypTo),
|
|
pwwd->xpMac, pwwd->ypMac );
|
|
Assert( ww == wwCur ); /* A MEMO-only assumption */
|
|
ScrollCurWw( &rc, 0, dypChange );
|
|
}
|
|
|
|
return dypChange;
|
|
}
|
|
|
|
|
|
|
|
|
|
FImportantMsgPresent()
|
|
{
|
|
/* If the next message is important enough to interrupt a screen update, we
|
|
return TRUE; if it can wait, we return FALSE */
|
|
|
|
BOOL fToggledKey;
|
|
extern MSG vmsgLast;
|
|
|
|
#ifdef DEBUG
|
|
unsigned wHeapVal = *(pLocalHeap + 1);
|
|
|
|
Assert( wHeapVal == 0 ); /* Heap should not be frozen */
|
|
#endif
|
|
|
|
#ifdef DBCS
|
|
if( donteat )
|
|
return TRUE;
|
|
#endif
|
|
|
|
while (PeekMessage((LPMSG) &vmsgLast, NULL, NULL, NULL, PM_NOREMOVE))
|
|
{
|
|
|
|
if (((vmsgLast.wParam == VK_MENU) || (vmsgLast.wParam == VK_CONTROL)))
|
|
{
|
|
if (vmsgLast.wParam == VK_CONTROL)
|
|
{
|
|
GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
|
|
SetShiftFlags();
|
|
}
|
|
return TRUE;
|
|
}
|
|
/* Filter uninteresting or easily handled events */
|
|
else if (fToggledKey = FCheckToggleKeyMessage(&vmsgLast) ||
|
|
(vmsgLast.message == WM_KEYUP && vmsgLast.hwnd == wwdCurrentDoc.wwptr))
|
|
{
|
|
|
|
/* This is so the Windows keyboard interface mechanism will see toggle
|
|
key and key-up transitions */
|
|
GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
|
|
#ifdef WIN30
|
|
/* PeekMessage has been changed in Win 3.0 so that GetKeyState()
|
|
called from FCheckToggleKeyMessage() is really only valid if
|
|
you've done a PeekMessage(...,PM_REMOVE) or GetMessage() first.
|
|
That is, while the FCheckToggleKeyMessage() call might succeed
|
|
above, it will NOT have set the vfShiftKey/vfCommandKey flags
|
|
correctly -- so we do it here ..pault */
|
|
if (fToggledKey)
|
|
FCheckToggleKeyMessage(&vmsgLast);
|
|
#endif
|
|
if (vmsgLast.hwnd != wwdCurrentDoc.wwptr)
|
|
{
|
|
/* Just in case a modeless dialog's window proc cares */
|
|
TranslateMessage((LPMSG)&vmsgLast);
|
|
DispatchMessage((LPMSG)&vmsgLast);
|
|
}
|
|
#ifdef DBCS
|
|
#ifdef KOREA /* 90.12.23 by sangl */ // jinwoo: 92, 9, 28
|
|
if (vmsgLast.message == WM_CHAR || vmsgLast.message == WM_KEYDOWN
|
|
|| vmsgLast.message == WM_INTERIM) {
|
|
#else /* KOREA */
|
|
if (vmsgLast.message == WM_CHAR || vmsgLast.message == WM_KEYDOWN ) {
|
|
#endif //KOREA 920525 KDLEE; jinwoo: 92, 9, 28
|
|
donteat = TRUE;
|
|
return( TRUE );
|
|
} /* else Ok, you are KEYUP message. do normal */
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
switch (vmsgLast.message)
|
|
{
|
|
case WM_MOUSEMOVE:
|
|
/* Process mouse move messages immediately; they are not really
|
|
important. NOTE: This assumes that we have not captured all mouse
|
|
events; in which case, they are important. */
|
|
DispatchMessage((LPMSG)&vmsgLast);
|
|
|
|
case WM_TIMER:
|
|
case WM_SYSTIMER:
|
|
/* Remove timer and mouse move messages from the queue. */
|
|
GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
|
|
break;
|
|
|
|
default:
|
|
Assert( *(pLocalHeap+1) == 0 ); /* Heap should still not be frozen */
|
|
return (TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Assert( *(pLocalHeap + 1) == 0 ); /* Heap should still not be frozen */
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/* C P B E G I N L I N E */
|
|
typeCP CpBeginLine(pdl, cp)
|
|
int *pdl;
|
|
typeCP cp;
|
|
{ /* return the cp and dl containing cp */
|
|
int dlMin, dlLim;
|
|
typeCP cpGuess;
|
|
struct EDL *dndl;
|
|
|
|
do
|
|
{
|
|
UpdateWw(wwCur, false);
|
|
PutCpInWwVert(cp); /* Ensure cp on screen */
|
|
} while (pwwdCur->fDirty && !vfOutOfMemory);
|
|
|
|
dndl = &(**(pwwdCur->hdndl))[0];
|
|
dlMin = 0;
|
|
dlLim = pwwdCur->dlMac;
|
|
while (dlMin + 1 < dlLim)
|
|
{ /* Binary search the ww */
|
|
int dlGuess = (dlMin + dlLim) >> 1;
|
|
struct EDL *pedl = &dndl[dlGuess];
|
|
if ((cpGuess = pedl->cpMin) <= cp && (cpGuess != cp || pedl->ichCpMin == 0))
|
|
{ /* guess is low or right */
|
|
dlMin = dlGuess;
|
|
if (cp == cpGuess && pedl->cpMin + pedl->dcpMac != cp)
|
|
break; /* Got it right */
|
|
}
|
|
else /* Guess is high */
|
|
dlLim = dlGuess;
|
|
}
|
|
*pdl = dlMin;
|
|
return dndl[dlMin].cpMin;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* T O G G L E S E L */
|
|
ToggleSel(cpFirst, cpLim, fOn)
|
|
typeCP cpFirst, cpLim; /* selection bounds */
|
|
int fOn;
|
|
{ /* Flip selection highlighting on and off */
|
|
extern int vfPMS;
|
|
struct EDL *pedl;
|
|
int dlT;
|
|
int xpMin;
|
|
int dxpRoom;
|
|
int xpFirst;
|
|
int xpLim;
|
|
int fInsertPoint = (cpFirst == cpLim);
|
|
|
|
if (vfSelHidden || cpFirst > cpLim || cpLim < /*cp0*/ cpMinCur || vfDead)
|
|
return;
|
|
|
|
if ( vfPictSel && vfPMS &&
|
|
(CachePara( docCur, cpFirst ), vpapAbs.fGraphics) &&
|
|
(vcpLimParaCache == cpLim) )
|
|
{ /* Don't show inversion if we're moving or sizing a picture */
|
|
return;
|
|
}
|
|
|
|
dxpRoom = pwwdCur->xpMac - xpSelBar;
|
|
xpMin = pwwdCur->xpMin;
|
|
|
|
for (dlT = 0; dlT < pwwdCur->dlMac; dlT++)
|
|
{
|
|
typeCP cpMin, cpMac; /* line bounds */
|
|
pedl = &(**(pwwdCur->hdndl))[dlT];
|
|
if (!pedl->fValid)
|
|
continue;
|
|
cpMin = pedl->cpMin;
|
|
if (cpMin > cpLim || cpMin > cpMacCur || (cpMin == cpLim && cpLim != cpFirst))
|
|
break;
|
|
cpMac = cpMin + pedl->dcpMac;
|
|
if (cpFirst <= cpMin && cpLim >= cpMac)
|
|
{
|
|
/* entire line is highlighted */
|
|
xpFirst = pedl->xpLeft;
|
|
if (pedl->fGraphics && cpLim == cpMac && cpMin == cpMac)
|
|
/* Special kludge for graphics paras */
|
|
xpLim = xpFirst;
|
|
else
|
|
xpLim = pedl->xpMac;
|
|
}
|
|
else if (fInsertPoint && cpFirst == cpMac && vfInsEnd)
|
|
{ /* Special kludge for an insert point at the end of a line */
|
|
xpLim = xpFirst = pedl->xpMac;
|
|
}
|
|
else if (cpFirst < cpMac)
|
|
{
|
|
/* Bite the bullet */
|
|
int dxp;
|
|
typeCP cpBegin = CpMax(cpMin, cpFirst);
|
|
typeCP cpEnd = CpMin(cpMac, cpLim);
|
|
|
|
FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode);
|
|
dxp = DxpDiff((int) (cpBegin - cpMin),
|
|
(int) (cpEnd - cpBegin), &xpFirst);
|
|
xpLim = xpFirst + dxp;
|
|
/* reload pedl because procedures were called */
|
|
pedl = &(**(pwwdCur->hdndl))[dlT];
|
|
}
|
|
else
|
|
continue;
|
|
/* now we have: pedl valid, xpFirst, xpLast describe highlight */
|
|
/* xpFirst = max(xpFirst, xpMin); */
|
|
xpLim = min(xpLim, xpMin + pedl->xpMac);
|
|
if (xpLim > xpFirst)
|
|
{
|
|
if (xpLim > xpMin)
|
|
{
|
|
RECT rc;
|
|
rc.top = pedl->yp - pedl->dyp;
|
|
rc.left = xpSelBar + max(xpFirst - xpMin, 0);
|
|
rc.bottom = pedl->yp;
|
|
rc.right = xpSelBar + xpLim - xpMin;
|
|
InvertRect( wwdCurrentDoc.hDC, (LPRECT)&rc);
|
|
}
|
|
}
|
|
/* ToggleSel modified 7/28/85 -- added explicit check for fInsertPoint, since
|
|
the xpLim == xpFirst test sometimes succeeded bogusly when a selection
|
|
was extended backwards. BL */
|
|
else if (fInsertPoint && (xpLim == xpFirst)) /* Insertion point */
|
|
{
|
|
/* vfli should usually be cached already, so will be fast. */
|
|
int yp = pedl->yp;
|
|
FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode);
|
|
if (fOn ^ vfInsertOn)
|
|
{
|
|
if (!vfInsertOn)
|
|
{
|
|
vxpCursLine = xpSelBar + xpFirst - xpMin;
|
|
vypCursLine = yp - vfli.dypAfter;
|
|
vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter);
|
|
|
|
/* Start blinking in a while */
|
|
vfSkipNextBlink = TRUE;
|
|
}
|
|
DrawInsertLine();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/* T R A S H W W */
|
|
TrashWw(ww)
|
|
{ /* Invalidate all dl's in ww */
|
|
Assert( ww >= 0 && ww < wwMax );
|
|
InvalBand(&rgwwd[ww], 0, ypMaxAll);
|
|
}
|
|
|
|
|
|
|
|
|
|
/* I N V A L B A N D */
|
|
/* invalidate the band ypFirst, ypLast inclusive */
|
|
InvalBand(pwwd, ypFirst, ypLast)
|
|
struct WWD *pwwd; int ypFirst, ypLast;
|
|
{
|
|
/* this covers some peculiar rects received from update event after a
|
|
window resize by 1 pixel. CS */
|
|
if (ypLast < 0 || ypFirst == ypLast) return;
|
|
|
|
pwwd->fDirty = true;
|
|
pwwd->ypFirstInval = min(pwwd->ypFirstInval, ypFirst);
|
|
pwwd->ypLastInval = max(ypLast, pwwd->ypLastInval);
|
|
}
|
|
|
|
|
|
|
|
|
|
/* T R A S H A L L W W S */
|
|
TrashAllWws()
|
|
{ /* trash them all */
|
|
int ww;
|
|
|
|
#ifdef CASHMERE
|
|
for (ww = 0; ww < wwMac; ++ww)
|
|
TrashWw(ww);
|
|
#else
|
|
TrashWw( wwDocument );
|
|
#endif
|
|
vfli.doc = docNil; /* Mark vfli invalid */
|
|
}
|
|
|
|
|
|
/* T U R N O F F S E L */
|
|
TurnOffSel()
|
|
{ /* Remove sel highlighting from screen */
|
|
/* HideSel has no effect */
|
|
if (!vfSelHidden)
|
|
{
|
|
ToggleSel(selCur.cpFirst, selCur.cpLim, false);
|
|
vfSelHidden = true;
|
|
}
|
|
}
|
|
|
|
|
|
/* D R A W I N S E R T L I N E */
|
|
DrawInsertLine()
|
|
{ /* Draw (in Xor mode) a vertical bar at screen position v*CursLine */
|
|
/* Toggles both the display and the vfInsertOn flag */
|
|
/* Adjustments in cursor draw must be reflected in DisplayFli, above */
|
|
|
|
/* Last-minute correction for a bug: assure that the insert line
|
|
does not extend above ypMin */
|
|
if (!vfInsertOn && vdypCursLine > vypCursLine - wwdCurrentDoc.ypMin)
|
|
vdypCursLine = vypCursLine - wwdCurrentDoc.ypMin;
|
|
|
|
/* Tell GDI to invert the caret line */
|
|
PatBlt( wwdCurrentDoc.hDC, vxpCursLine, vypCursLine - vdypCursLine,
|
|
2, vdypCursLine , DSTINVERT );
|
|
vfInsertOn = 1 - vfInsertOn;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* C L E A R I N S E R T L I N E */
|
|
ClearInsertLine()
|
|
{
|
|
if ( vfInsertOn) DrawInsertLine();
|
|
}
|
|
|