807 lines
22 KiB
C
807 lines
22 KiB
C
|
/************************************************************/
|
|||
|
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
|
|||
|
/************************************************************/
|
|||
|
|
|||
|
/* select.c -- MW selection routines */
|
|||
|
|
|||
|
#define NOCLIPBOARD
|
|||
|
#define NOGDICAPMASKS
|
|||
|
#define NOCTLMGR
|
|||
|
#define NOVIRTUALKEYCODES
|
|||
|
#define NOWINMESSAGES
|
|||
|
#define NOWINSTYLES
|
|||
|
#define NOSYSMETRICS
|
|||
|
#define NOMENUS
|
|||
|
#define NOSOUND
|
|||
|
#define NOCOMM
|
|||
|
#define NOPEN
|
|||
|
#define NOWNDCLASS
|
|||
|
#define NOICON
|
|||
|
#define NORASTEROPS
|
|||
|
#define NOSHOWWINDOW
|
|||
|
#define NOATOM
|
|||
|
#define NOKEYSTATE
|
|||
|
#define NOSYSCOMMANDS
|
|||
|
#define NOBITMAP
|
|||
|
#define NOBRUSH
|
|||
|
#define NOCOLOR
|
|||
|
#define NODRAWTEXT
|
|||
|
#define NOMB
|
|||
|
#define NOPOINT
|
|||
|
#define NOMSG
|
|||
|
#include <windows.h>
|
|||
|
#include "mw.h"
|
|||
|
#include "toolbox.h"
|
|||
|
#include "docdefs.h"
|
|||
|
#include "editdefs.h"
|
|||
|
#include "dispdefs.h"
|
|||
|
#include "cmddefs.h"
|
|||
|
#include "wwdefs.h"
|
|||
|
#include "ch.h"
|
|||
|
#include "fmtdefs.h"
|
|||
|
#include "propdefs.h"
|
|||
|
#ifdef DBCS
|
|||
|
#include "DBCS.h"
|
|||
|
#endif
|
|||
|
|
|||
|
extern int vfSeeSel;
|
|||
|
extern typeCP vcpFirstParaCache;
|
|||
|
extern typeCP vcpLimParaCache;
|
|||
|
extern typeCP vcpFetch;
|
|||
|
extern CHAR *vpchFetch;
|
|||
|
extern int vccpFetch;
|
|||
|
extern typeCP cpMinCur;
|
|||
|
extern typeCP cpMacCur;
|
|||
|
extern struct SEL selCur;
|
|||
|
extern int docCur;
|
|||
|
extern struct FLI vfli;
|
|||
|
extern struct WWD rgwwd[];
|
|||
|
extern int vfSelHidden;
|
|||
|
extern int wwCur;
|
|||
|
extern struct CHP vchpFetch;
|
|||
|
extern struct PAP vpapAbs;
|
|||
|
extern struct WWD *pwwdCur;
|
|||
|
extern int vfInsEnd;
|
|||
|
extern typeCP CpBeginLine();
|
|||
|
extern int vfPictSel;
|
|||
|
extern int vfSizeMode;
|
|||
|
extern struct CHP vchpNormal;
|
|||
|
extern int vfInsertOn;
|
|||
|
extern struct CHP vchpSel; /* Holds the props when the selection
|
|||
|
is an insert point */
|
|||
|
extern int vfMakeInsEnd;
|
|||
|
extern typeCP vcpSelect;
|
|||
|
extern int vfSelAtPara;
|
|||
|
/* true iff the last selection was made by an Up/Down cursor key */
|
|||
|
extern int vfLastCursor;
|
|||
|
extern int vfDidSearch;
|
|||
|
extern typeCP cpWall;
|
|||
|
|
|||
|
|
|||
|
/* C P L I M S T Y */
|
|||
|
typeCP CpLimSty(cp, sty)
|
|||
|
typeCP cp;
|
|||
|
int sty;
|
|||
|
{ /* Return the first cp which is not part of the same sty unit */
|
|||
|
typeCP CpLastStyChar(), CpLimStySpecial();
|
|||
|
int wb, ch, ich;
|
|||
|
struct EDL *pedl;
|
|||
|
|
|||
|
if (cp >= cpMacCur)
|
|||
|
{ /* Endmark is own unit */
|
|||
|
return cpMacCur;
|
|||
|
}
|
|||
|
|
|||
|
if (cp < cpMinCur)
|
|||
|
cp = cpMinCur;
|
|||
|
|
|||
|
switch (sty)
|
|||
|
{
|
|||
|
int dl;
|
|||
|
default:
|
|||
|
Assert( FALSE );
|
|||
|
case styNil:
|
|||
|
return cp;
|
|||
|
|
|||
|
case styPara:
|
|||
|
CachePara(docCur, cp);
|
|||
|
if (vcpLimParaCache > cpMacCur)
|
|||
|
{ /* No EOL at end of doc */
|
|||
|
return cpMacCur;
|
|||
|
}
|
|||
|
return vcpLimParaCache;
|
|||
|
case styChar:
|
|||
|
/* Because CpLastStyChar() could be returning cpMacCur already. */
|
|||
|
cp = CpLastStyChar( cp ) + 1;
|
|||
|
return ((cp <= cpMacCur) ? cp : cpMacCur);
|
|||
|
#ifdef BOGUS
|
|||
|
/* This portion never gets executed... Why is it in here! */
|
|||
|
CachePara(docCur, cp);
|
|||
|
if (vpapAbs.fGraphics /* && cp > vcpFirstParaCache */)
|
|||
|
return vcpLimParaCache;
|
|||
|
#ifdef CRLF
|
|||
|
FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
|
|||
|
return *vpchFetch == chReturn ? cp + 2 : cp + 1;
|
|||
|
#else /* not CRLF */
|
|||
|
return cp + 1;
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
case styLine:
|
|||
|
CpBeginLine(&dl, cp); /* Scrolls cp vertically into view */
|
|||
|
pedl = &(**wwdCurrentDoc.hdndl) [dl];
|
|||
|
return CpMin(pedl->cpMin + pedl->dcpMac, cpMacCur);
|
|||
|
case styDoc:
|
|||
|
return cpMacCur;
|
|||
|
case styWord:
|
|||
|
case stySent:
|
|||
|
#ifdef DBCS
|
|||
|
return CpLimStySpecial( CpFirstSty(cp, styChar), sty );
|
|||
|
#else
|
|||
|
return CpLimStySpecial( cp, sty );
|
|||
|
#endif /* DBCS */
|
|||
|
}
|
|||
|
|
|||
|
Assert( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
typeCP CpLastStyChar( cp )
|
|||
|
typeCP cp;
|
|||
|
{ /* Return the last cp of the styChar containing cp */
|
|||
|
/* This will be == cp except for pictures & CR-LF */
|
|||
|
/* And the second byte of DBCS char's. */
|
|||
|
|
|||
|
#ifdef DBCS
|
|||
|
typeCP CpFirstSty();
|
|||
|
CHAR chRetained;
|
|||
|
#endif
|
|||
|
|
|||
|
if (cp >= cpMacCur)
|
|||
|
/* Endmark is own unit */
|
|||
|
return cpMacCur;
|
|||
|
|
|||
|
if (cp < cpMinCur)
|
|||
|
cp = cpMinCur;
|
|||
|
|
|||
|
/* Check for picture */
|
|||
|
CachePara(docCur, cp);
|
|||
|
if (vpapAbs.fGraphics)
|
|||
|
return vcpLimParaCache-1;
|
|||
|
|
|||
|
/* Check for CR-LF */
|
|||
|
/* This checking for CR-LF first based on the carriage return */
|
|||
|
/* works only becasue the chReturn is outside of the DBCS */
|
|||
|
/* range. */
|
|||
|
#ifdef CRLF
|
|||
|
FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
|
|||
|
#ifdef DBCS
|
|||
|
if ((chRetained = *vpchFetch) == chReturn) {
|
|||
|
return cp + 1;
|
|||
|
}
|
|||
|
else {
|
|||
|
if (CpFirstSty(cp, styChar) != cp) {
|
|||
|
return cp; /* cp is pointing to the second byte of DBCS. */
|
|||
|
}
|
|||
|
else {
|
|||
|
/* First byte of DBCS or a regular ASCII char. */
|
|||
|
return (IsDBCSLeadByte(chRetained) ? cp + 1 : cp);
|
|||
|
}
|
|||
|
}
|
|||
|
#else
|
|||
|
return *vpchFetch == chReturn ? cp + 1 : cp;
|
|||
|
#endif /* DBCS */
|
|||
|
#else
|
|||
|
return cp;
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* C P F I R S T S T Y */
|
|||
|
typeCP CpFirstSty(cp, sty)
|
|||
|
typeCP cp;
|
|||
|
int sty;
|
|||
|
{ /* Return the first cp of this sty unit. */
|
|||
|
typeCP CpFirstStySpecial();
|
|||
|
typeCP cpBegin;
|
|||
|
int wb, ch, dcpChunk;
|
|||
|
typeCP cpSent;
|
|||
|
CHAR rgch[dcpAvgSent];
|
|||
|
int ich;
|
|||
|
typeCP cpT;
|
|||
|
|
|||
|
if (cp <= cpMinCur)
|
|||
|
return cpMinCur;
|
|||
|
else if (cp >= cpMacCur)
|
|||
|
switch(sty)
|
|||
|
{
|
|||
|
case styNil:
|
|||
|
case styChar:
|
|||
|
return cpMacCur; /* Endmark is own unit */
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
CachePara( docCur, cp );
|
|||
|
|
|||
|
switch (sty)
|
|||
|
{
|
|||
|
default:
|
|||
|
Assert( FALSE );
|
|||
|
case styNil:
|
|||
|
return cp;
|
|||
|
case styPara:
|
|||
|
return vcpFirstParaCache;
|
|||
|
case styChar:
|
|||
|
if (vpapAbs.fGraphics)
|
|||
|
return vcpFirstParaCache;
|
|||
|
#ifdef CRLF
|
|||
|
{
|
|||
|
typeCP cpCheckReturn;
|
|||
|
typeCP cpMinScan;
|
|||
|
|
|||
|
cpCheckReturn = CpMax( cp, (typeCP) 1) - 1;
|
|||
|
#ifdef DBCS
|
|||
|
/* Save vcpFirstParaCache, because it could be changed
|
|||
|
by FetchCp() */
|
|||
|
cpMinScan = vcpFirstParaCache;
|
|||
|
#endif /* DBCS */
|
|||
|
FetchCp( docCur, cpCheckReturn, 0, fcmChars + fcmNoExpand );
|
|||
|
#ifdef DBCS
|
|||
|
/* This works because chReturn is outside of DBCS range. */
|
|||
|
if (*vpchFetch == chReturn) {
|
|||
|
return cpCheckReturn;
|
|||
|
}
|
|||
|
else {
|
|||
|
typeCP cpT;
|
|||
|
typeCP cpRgMin;
|
|||
|
int ichMacRgch;
|
|||
|
BOOL fBreakFound;
|
|||
|
int fkCur;
|
|||
|
|
|||
|
cpT = cp;
|
|||
|
do {
|
|||
|
cpRgMin = CpMax( cpT - dcpAvgSent, cpMinScan);
|
|||
|
FetchRgch(&ichMacRgch, rgch, docCur, cpRgMin, cpT,
|
|||
|
dcpAvgSent);
|
|||
|
ich = ichMacRgch - 1;
|
|||
|
fBreakFound = FALSE;
|
|||
|
while (ich >= 0 && !fBreakFound) {
|
|||
|
if (!IsDBCSLeadByte(rgch[ich])) {
|
|||
|
fBreakFound = TRUE;
|
|||
|
}
|
|||
|
else {
|
|||
|
ich--;
|
|||
|
}
|
|||
|
}
|
|||
|
cpT = cpRgMin;
|
|||
|
} while (!fBreakFound && cpRgMin > cpMinScan);
|
|||
|
if (fBreakFound) {
|
|||
|
ich++;
|
|||
|
}
|
|||
|
else {
|
|||
|
ich = 0;
|
|||
|
}
|
|||
|
fkCur = fkNonDBCS;
|
|||
|
cpT = cpRgMin + ichMacRgch;
|
|||
|
do {
|
|||
|
while (ich < ichMacRgch) {
|
|||
|
if (fkCur == fkDBCS1) {
|
|||
|
/* Last rgch[] ended with the first byte
|
|||
|
of a DBCS character. */
|
|||
|
fkCur = fkNonDBCS;
|
|||
|
}
|
|||
|
else if (IsDBCSLeadByte(rgch[ich])) {
|
|||
|
if (ich + 1 < ichMacRgch) {
|
|||
|
fkCur = fkNonDBCS;
|
|||
|
ich++;
|
|||
|
}
|
|||
|
else {
|
|||
|
fkCur = fkDBCS1;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
fkCur = fkNonDBCS;
|
|||
|
}
|
|||
|
ich++;
|
|||
|
}
|
|||
|
cpRgMin = cpT;
|
|||
|
cpT += dcpAvgSent;
|
|||
|
if (cpT <= cp) { /* Saves some time. */
|
|||
|
FetchRgch(&ichMacRgch, rgch, docCur, cpRgMin, cpT,
|
|||
|
dcpAvgSent);
|
|||
|
ich = 0;
|
|||
|
}
|
|||
|
} while (cpT <= cp);
|
|||
|
|
|||
|
if (fkCur == fkDBCS1) {
|
|||
|
Assert(cp - 1 <= cpMacCur);
|
|||
|
return (cp - 1);
|
|||
|
}
|
|||
|
else {
|
|||
|
Assert(cp <= cpMacCur);
|
|||
|
return (cp);
|
|||
|
}
|
|||
|
}
|
|||
|
#else
|
|||
|
return *vpchFetch == chReturn ? cpCheckReturn : cp;
|
|||
|
#endif /* DBCS */
|
|||
|
}
|
|||
|
#else
|
|||
|
return cp;
|
|||
|
#endif
|
|||
|
case styDoc:
|
|||
|
return cpMinCur;
|
|||
|
case styLine:
|
|||
|
{
|
|||
|
int dlJunk;
|
|||
|
|
|||
|
return CpBeginLine( &dlJunk, cp );
|
|||
|
}
|
|||
|
case styWord:
|
|||
|
case stySent:
|
|||
|
#ifdef DBCS
|
|||
|
return CpFirstStySpecial( CpFirstSty(cp, styChar), sty );
|
|||
|
#else
|
|||
|
return CpFirstStySpecial( cp, sty );
|
|||
|
#endif /* DBCS */
|
|||
|
}
|
|||
|
Assert( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* S E L E C T */
|
|||
|
/* used to make a selection from a cp-interval, for example after a find. */
|
|||
|
Select(cpFirst, cpLim)
|
|||
|
typeCP cpFirst, cpLim;
|
|||
|
{ /* Make a selection */
|
|||
|
typeCP cpFirstOld = selCur.cpFirst;
|
|||
|
typeCP cpLimOld = selCur.cpLim;
|
|||
|
int fOldCursorLine;
|
|||
|
|
|||
|
if (cpFirst > cpLim)
|
|||
|
/* The only time this condition should be true is when we have
|
|||
|
run out of memory. The following is a senario where
|
|||
|
such is the case (and actually, the reason for this code change).
|
|||
|
Let us suppose that we have cut, pasted to the end of the
|
|||
|
document, and are now executing a "command a" (repeat last
|
|||
|
operation). The procedure CmdAgain is invoked. CmdAgain first
|
|||
|
calls replace in order to add the text to the document. Now it
|
|||
|
must position the cursor properly by calling select.
|
|||
|
A SetUndo operation called by the prior paste gave us the
|
|||
|
number of bytes that were added to the document. In its call
|
|||
|
to Select, CmdAgain assumes that where it wants to position the
|
|||
|
cursor is at the old last char position plus the SetUndo quantity
|
|||
|
mentioned above. But, if the replace operation failed (due to
|
|||
|
lack of memory), CmdAgain may be trying to place the cursor beyond
|
|||
|
the physical end of the document.
|
|||
|
Other fixes of this problem, at the caller level (CmdAgain)
|
|||
|
instead of within Select, are probably "better" in the sense of
|
|||
|
programming clarity. The chosen solution has the one advantage
|
|||
|
of programming expediency. */
|
|||
|
cpFirst = cpLim;
|
|||
|
/* This statement replaces "Assert(cpFirst <= cpLim);" */
|
|||
|
|
|||
|
vfInsEnd = fFalse;
|
|||
|
/* notation: + add highlight
|
|||
|
- remove highlight
|
|||
|
.. leave alone
|
|||
|
00 common portion
|
|||
|
*/
|
|||
|
if (!vfSelHidden)
|
|||
|
{
|
|||
|
if (cpFirst < cpFirstOld)
|
|||
|
{ /* +++... */
|
|||
|
if (cpLim <= cpFirstOld)
|
|||
|
{ /* +++ --- */
|
|||
|
goto SeparateSels;
|
|||
|
}
|
|||
|
else
|
|||
|
{ /* +++000... */
|
|||
|
ToggleSel(cpFirst, cpFirstOld, true);
|
|||
|
if (cpLim < cpLimOld)
|
|||
|
{ /* +++000--- */
|
|||
|
ToggleSel(cpLim, cpLimOld, false);
|
|||
|
}
|
|||
|
else if (cpLim > cpLimOld)
|
|||
|
{ /* +++000+++ */
|
|||
|
ToggleSel(cpLimOld, cpLim, true);
|
|||
|
}
|
|||
|
/* Handle the case when old selection was an insert bar */
|
|||
|
if (cpFirstOld == cpLimOld)
|
|||
|
ToggleSel(cpFirstOld, cpLimOld, false);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{ /* ---... */
|
|||
|
if (cpLimOld <= cpFirst)
|
|||
|
{ /* --- +++ */
|
|||
|
SeparateSels:
|
|||
|
fOldCursorLine = cpFirstOld == cpLimOld;
|
|||
|
/* prevent flashing if insert point which is ON is repeatedly selected */
|
|||
|
/* conditions are: not repeated, not insert point, not ON, not at desired end of line */
|
|||
|
vfInsEnd = vfMakeInsEnd;
|
|||
|
if ( cpFirst != cpFirstOld || cpLim != cpLimOld ||
|
|||
|
!fOldCursorLine || !vfInsertOn ||
|
|||
|
selCur.fEndOfLine != vfMakeInsEnd)
|
|||
|
{
|
|||
|
selCur.fEndOfLine = vfMakeInsEnd;
|
|||
|
if (fOldCursorLine)
|
|||
|
ClearInsertLine();
|
|||
|
/* old selection is off if it was a cursor line */
|
|||
|
ToggleSel(cpFirst, cpLim, fTrue);
|
|||
|
/* otherwise the old selection is turned off AFTER the new one is made to
|
|||
|
make it look faster */
|
|||
|
if (!fOldCursorLine)
|
|||
|
ToggleSel(cpFirstOld, cpLimOld, fFalse);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{ /* ---000... */
|
|||
|
if (cpLimOld < cpLim)
|
|||
|
{ /* ---000+++ */
|
|||
|
ToggleSel(cpLimOld, cpLim, true);
|
|||
|
}
|
|||
|
else if (cpLimOld > cpLim)
|
|||
|
{ /* ---000--- */
|
|||
|
ToggleSel(cpLim, cpLimOld, false);
|
|||
|
}
|
|||
|
ToggleSel(cpFirstOld, cpFirst, false);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
selCur.cpFirst = cpFirst;
|
|||
|
selCur.cpLim = cpLim;
|
|||
|
selCur.fForward = cpFirst != cpMacCur;
|
|||
|
if (cpFirst == cpLim)
|
|||
|
{
|
|||
|
GetInsPtProps(cpFirst);
|
|||
|
vfDidSearch = FALSE; /* reestablish for searching */
|
|||
|
cpWall = cpLim;
|
|||
|
}
|
|||
|
vfLastCursor = vfSizeMode = vfPictSel = vfMakeInsEnd = false;
|
|||
|
|
|||
|
/* Set vfPictSel iff the selection is exactly one picture */
|
|||
|
|
|||
|
CachePara( docCur, selCur.cpFirst );
|
|||
|
if (vpapAbs.fGraphics && selCur.cpLim == vcpLimParaCache)
|
|||
|
vfPictSel = TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* G E T I N S P T P R O P S */
|
|||
|
GetInsPtProps(cp)
|
|||
|
typeCP cp;
|
|||
|
{ /* determine properties of the insertion point */
|
|||
|
|
|||
|
if (cpMacCur != cpMinCur)
|
|||
|
{
|
|||
|
CachePara(docCur, cp);
|
|||
|
if (vcpFirstParaCache == cpMacCur)
|
|||
|
{
|
|||
|
/* cp is in the last para--use preceding para props */
|
|||
|
CachePara(docCur, vcpFirstParaCache - 1);
|
|||
|
if (vpapAbs.fGraphics)
|
|||
|
{ /* Yet another 10 point kludge -- get default props
|
|||
|
when typing after a picture at doc end */
|
|||
|
|
|||
|
goto Default;
|
|||
|
}
|
|||
|
}
|
|||
|
if (vpapAbs.fGraphics)
|
|||
|
/* 10 point kludge: make typing before picture non-vchpNormal */
|
|||
|
goto Default;
|
|||
|
|
|||
|
FetchCp(docCur, CpMax(vcpFirstParaCache, cp - 1), 0, fcmProps);
|
|||
|
blt(&vchpFetch, &vchpSel, cwCHP);
|
|||
|
if (vchpFetch.fSpecial && vchpFetch.hpsPos != 0)
|
|||
|
{ /* if this char is a footnote or page marker, then ignore */
|
|||
|
vchpSel.hpsPos = 0; /* super/subscript stuff. */
|
|||
|
vchpSel.hps = HpsAlter(vchpSel.hps, 1);
|
|||
|
}
|
|||
|
vchpSel.fSpecial = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Default:
|
|||
|
/* force default character properties, font size to be 10 point */
|
|||
|
blt(&vchpNormal, &vchpSel, cwCHP);
|
|||
|
vchpSel.hps = hpsDefault;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* C H A N G E S E L */
|
|||
|
ChangeSel(cp, sty)
|
|||
|
typeCP cp;
|
|||
|
int sty;
|
|||
|
{ /* Make selCur move, expand or contract to cp */
|
|||
|
/* sty is unit to keep in case of movement or flipped selection */
|
|||
|
/* styChar is not supported; it is munged to styNil */
|
|||
|
/* This is because the Write/Word user interface never asks us to */
|
|||
|
/* pivot the selection around a single character, we pivot around */
|
|||
|
/* an insertion point ("styNil") instead */
|
|||
|
int fNullSelection = (selCur.cpFirst == selCur.cpLim);
|
|||
|
typeCP cpFirst = selCur.cpFirst;
|
|||
|
typeCP cpLim = selCur.cpLim;
|
|||
|
int fForward = selCur.fForward;
|
|||
|
typeCP cpOffFirst, cpOffLim, cpOnFirst, cpOnLim;
|
|||
|
|
|||
|
if (sty == styChar)
|
|||
|
sty = styNil;
|
|||
|
|
|||
|
if (cp == cpMinCur - 1 || cp > cpMacCur)
|
|||
|
{ /* Trying to flip off the beginning or end */
|
|||
|
_beep();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
cpOffFirst = cpOffLim = cpOnFirst = cpOnLim = cpNil;
|
|||
|
|
|||
|
if (cp <= cpFirst)
|
|||
|
{ /* Extend backwards */
|
|||
|
if (cp == cpLim)
|
|||
|
return;
|
|||
|
if (fForward && !fNullSelection)
|
|||
|
{ /* Selection flipped */
|
|||
|
if (vfPictSel)
|
|||
|
/* stuck this in to 'correct' behaviour when select pict and
|
|||
|
drag up. Don't want to unselect first pict (4.22.91) v-dougk */
|
|||
|
{
|
|||
|
cpOnFirst = CpFirstSty( cp, sty);
|
|||
|
cpOffFirst = cpOffLim = cpLim;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cpOffFirst = selCur.cpLim = CpMin(cpLim, CpLimSty(cpFirst, sty));
|
|||
|
cpOnFirst = CpFirstSty( cp, sty);
|
|||
|
cpOffLim = cpLim;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ( fNullSelection )
|
|||
|
cpOffLim = cpOffFirst = selCur.cpFirst;
|
|||
|
cpOnFirst = CpFirstSty( cp, styChar );
|
|||
|
if (cpFirst == cpOnFirst)
|
|||
|
return;
|
|||
|
}
|
|||
|
selCur.fForward = false;
|
|||
|
|
|||
|
cpOnLim = cpFirst;
|
|||
|
selCur.cpFirst = cpOnFirst;
|
|||
|
}
|
|||
|
else if (cp >= cpLim)
|
|||
|
{ /* Extend forwards */
|
|||
|
if (cp == cpFirst)
|
|||
|
return;
|
|||
|
if (!fForward && !fNullSelection)
|
|||
|
{ /* Selection flipped */
|
|||
|
cpOffLim = selCur.cpFirst =
|
|||
|
CpMax( cpFirst, CpFirstSty( (sty ==styNil) ? cpLim : cpLim-1,
|
|||
|
sty ));
|
|||
|
cpOnLim = CpLimSty(cp, sty);
|
|||
|
cpOffFirst = cpFirst;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ( fNullSelection )
|
|||
|
cpOffLim = cpOffFirst = selCur.cpFirst;
|
|||
|
cpOnLim = cp;
|
|||
|
if (cpLim == cpOnLim)
|
|||
|
return;
|
|||
|
}
|
|||
|
selCur.fForward = true;
|
|||
|
|
|||
|
cpOnFirst = cpLim;
|
|||
|
selCur.cpLim = cpOnLim;
|
|||
|
if (cpOnLim == cpLim && cpOffLim != cpLim)
|
|||
|
cpOnLim = cpNil;
|
|||
|
}
|
|||
|
else if (fForward)
|
|||
|
{ /* Shrink a forward selection */
|
|||
|
cpOffFirst = cp;
|
|||
|
if (selCur.cpLim == cpOffFirst)
|
|||
|
return;
|
|||
|
selCur.cpLim = cpOffFirst;
|
|||
|
cpOffLim = cpLim;
|
|||
|
}
|
|||
|
else
|
|||
|
{ /* Shrink a backward selection */
|
|||
|
cpOffLim = cp;
|
|||
|
if (selCur.cpFirst == cpOffLim)
|
|||
|
return;
|
|||
|
selCur.cpFirst = cpOffLim;
|
|||
|
cpOffFirst = cpFirst;
|
|||
|
}
|
|||
|
|
|||
|
ToggleSel(cpOnFirst, cpOnLim, true);
|
|||
|
ToggleSel(cpOffFirst, cpOffLim, false);
|
|||
|
|
|||
|
/* Check for a stray insert point */
|
|||
|
|
|||
|
if (selCur.cpFirst != selCur.cpLim)
|
|||
|
ClearInsertLine();
|
|||
|
|
|||
|
/* Set vfPictSel iff the selection is exactly one picture */
|
|||
|
|
|||
|
CachePara( docCur, selCur.cpFirst );
|
|||
|
vfPictSel = vpapAbs.fGraphics && (selCur.cpLim == vcpLimParaCache);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* S E L E C T D L X P */
|
|||
|
SelectDlXp(dl, xp, sty, fDrag)
|
|||
|
int dl, xp, sty;
|
|||
|
int fDrag;
|
|||
|
{ /* Move cursor to the nearest valid CP and select unit */
|
|||
|
typeCP cp;
|
|||
|
typeCP cpFirst;
|
|||
|
typeCP cpLim;
|
|||
|
register struct EDL *pedl;
|
|||
|
int xpStart = xpSelBar - wwdCurrentDoc.xpMin;
|
|||
|
int itcMin, itcLim;
|
|||
|
int xpLeft;
|
|||
|
int xpPos;
|
|||
|
int fPictInsertPoint=FALSE; /* Setting an insert point before a pict */
|
|||
|
|
|||
|
UpdateWw(wwCur, false); /* Synchronize cursor & text */
|
|||
|
|
|||
|
xp = max(0, xp - xpStart);
|
|||
|
dl = min( wwdCurrentDoc.dlMax - 1, dl );
|
|||
|
|
|||
|
pedl = &(**wwdCurrentDoc.hdndl) [dl];
|
|||
|
cp = pedl->cpMin;
|
|||
|
|
|||
|
/* At or Below EMark */
|
|||
|
if (cp >= cpMacCur)
|
|||
|
{
|
|||
|
cp = cpMacCur;
|
|||
|
goto FoundCp;
|
|||
|
}
|
|||
|
|
|||
|
if (pedl->fGraphics)
|
|||
|
{ /*
|
|||
|
Special kludge for selecting a picture:
|
|||
|
Select the whole picture (if the hit is inside or to the
|
|||
|
right of the picture)
|
|||
|
Select an insert point just before the picture if the hit
|
|||
|
is to the left of the picture OR in the selection bar
|
|||
|
when the picture is left-justified) */
|
|||
|
if ( (xp < pedl->xpLeft) || (sty == styLine && xp == 0) )
|
|||
|
fPictInsertPoint = TRUE;
|
|||
|
|
|||
|
goto FoundCp;
|
|||
|
}
|
|||
|
|
|||
|
if (sty >= styPara)
|
|||
|
{ /* Selecting a paragraph, line, doc */
|
|||
|
goto FoundCp;
|
|||
|
}
|
|||
|
|
|||
|
/* Must Format to figure out the right cp */
|
|||
|
|
|||
|
FormatLine(docCur, cp, pedl->ichCpMin, cpMacCur, flmSandMode); /*HM*/
|
|||
|
|
|||
|
CachePara(docCur, cp);
|
|||
|
pedl = &(**wwdCurrentDoc.hdndl) [dl];
|
|||
|
|
|||
|
if (vfli.fSplat) /* Selecting in division/page break */
|
|||
|
{
|
|||
|
cp = vfli.cpMin;
|
|||
|
goto FoundCp;
|
|||
|
}
|
|||
|
|
|||
|
xpLeft = pedl->xpLeft;
|
|||
|
|
|||
|
if (vfli.xpLeft != xpLeft)
|
|||
|
/* This indicates that we are in lo memory conditions; in trouble */
|
|||
|
return;
|
|||
|
/* Assert (vfli.xpLeft == xpLeft); May not be true in lo memory */
|
|||
|
|
|||
|
if (xp <= xpLeft)
|
|||
|
{
|
|||
|
itcMin = 0;
|
|||
|
goto FoundCp;
|
|||
|
}
|
|||
|
|
|||
|
/* Out of bounds right */
|
|||
|
if (xp >= pedl->xpMac)
|
|||
|
{
|
|||
|
itcMin = vfli.cpMac - cp - 1;
|
|||
|
cp = vfli.cpMac - 1;
|
|||
|
goto CheckPastPara;
|
|||
|
}
|
|||
|
|
|||
|
/* Search through the line for the cp at position xp */
|
|||
|
xpPos = xpLeft;
|
|||
|
itcMin = 0;
|
|||
|
itcLim = vfli.cpMac - cp;
|
|||
|
|
|||
|
while (itcMin < itcLim && xpPos < xp)
|
|||
|
xpPos += vfli.rgdxp[itcMin++];
|
|||
|
|
|||
|
if (itcMin >= 1)
|
|||
|
/* This may not be true if we are so low on memory that
|
|||
|
FormatLine could not do its job */
|
|||
|
itcMin--;
|
|||
|
|
|||
|
cp += itcMin;
|
|||
|
|
|||
|
CachePara(docCur, cp);
|
|||
|
if ((xpPos < xp + vfli.rgdxp[itcMin] / 2) &&
|
|||
|
(sty == styChar /* || !fDrag */) )
|
|||
|
{ /* Actually selecting next character */
|
|||
|
CheckPastPara:
|
|||
|
if (cp + 1 == vcpLimParaCache && !vpapAbs.fGraphics &&
|
|||
|
(vfSelAtPara || vcpSelect == cpNil))
|
|||
|
/* Return insert point before paragraph mark */
|
|||
|
{
|
|||
|
if (vcpSelect == cpNil)
|
|||
|
vfSelAtPara = true;
|
|||
|
goto FoundCp;
|
|||
|
}
|
|||
|
itcMin++;
|
|||
|
cp++;
|
|||
|
}
|
|||
|
//T-HIROYN sync win3.0
|
|||
|
#ifdef DBCS
|
|||
|
/* if itcMin point the second char of kanji, increment itcMin */
|
|||
|
if (itcMin < itcLim && vfli.rgdxp[itcMin]==0)
|
|||
|
goto CheckPastPara; /* Select next character */
|
|||
|
#endif /* DBCS */
|
|||
|
|
|||
|
FoundCp:
|
|||
|
/* Set up selection limits */
|
|||
|
cpFirst = CpFirstSty( cp, sty );
|
|||
|
cpLim = CpLimSty( cp, sty );
|
|||
|
|
|||
|
if (sty == styChar)
|
|||
|
{
|
|||
|
if ( !pedl->fGraphics || fPictInsertPoint )
|
|||
|
/* In text or before a pic: don't extend to end of styChar */
|
|||
|
cpLim = cpFirst;
|
|||
|
|
|||
|
if ( vcpSelect == cpNil )
|
|||
|
{ /* First time through, remember where we started */
|
|||
|
|
|||
|
/* Set if we want to kludge the insert point at the end of *pedl */
|
|||
|
|
|||
|
vfMakeInsEnd = (cp == pedl->cpMin + pedl->dcpMac &&
|
|||
|
cp <= cpMacCur &&
|
|||
|
!pedl->fGraphics &&
|
|||
|
!pedl->fSplat);
|
|||
|
vcpSelect = cpFirst;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (fDrag)
|
|||
|
ChangeSel( selCur.fForward ? cpLim : cpFirst, sty );
|
|||
|
else
|
|||
|
Select( cpFirst, cpLim );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
typeCP CpEdge()
|
|||
|
{ /* Return edge of selection */
|
|||
|
return selCur.fForward ?
|
|||
|
CpMax( CpFirstSty( selCur.cpLim - 1, styChar ), selCur.cpFirst ) :
|
|||
|
selCur.cpFirst;
|
|||
|
}
|
|||
|
|