1678 lines
50 KiB
C
1678 lines
50 KiB
C
/************************************************************/
|
||
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
|
||
/************************************************************/
|
||
|
||
/* This file contains the routines for creating, displaying, and manipulating
|
||
the ruler for Memo. */
|
||
|
||
#define NOGDICAPMASKS
|
||
#define NOVIRTUALKEYCODES
|
||
#define NOWINMESSAGES
|
||
#define NOMENUS
|
||
#define NOICON
|
||
#define NOKEYSTATE
|
||
#define NOSYSCOMMANDS
|
||
#define NOATOM
|
||
#define NOBRUSH
|
||
#define NOCLIPBOARD
|
||
#define NOCOLOR
|
||
#define NOCREATESTRUCT
|
||
#define NOCTLMGR
|
||
#define NODRAWTEXT
|
||
#define NOMB
|
||
#define NOMEMMGR
|
||
#define NOMENUS
|
||
#define NOMETAFILE
|
||
#define NOMSG
|
||
#define NOOPENFILE
|
||
#define NOREGION
|
||
#define NOSCROLL
|
||
#define NOSOUND
|
||
#define NOWH
|
||
#define NOWINOFFSETS
|
||
#define NOWNDCLASS
|
||
#define NOCOMM
|
||
#include <windows.h>
|
||
|
||
#include "mw.h"
|
||
#include "cmddefs.h"
|
||
#include "wwdefs.h"
|
||
#include "rulerdef.h"
|
||
#include "propdefs.h"
|
||
#include "prmdefs.h"
|
||
#include "docdefs.h"
|
||
#include "bitmaps.h"
|
||
|
||
#define MERGEMARK 0x00990066
|
||
|
||
extern HWND hParentWw;
|
||
extern HANDLE hMmwModInstance;
|
||
extern HCURSOR vhcIBeam;
|
||
extern struct DOD (**hpdocdod)[];
|
||
extern struct WWD *pwwdCur;
|
||
extern struct PAP vpapAbs;
|
||
extern struct SEP vsepAbs;
|
||
extern struct SEL selCur;
|
||
extern typeCP cpMacCur;
|
||
extern int docCur;
|
||
extern int vdocParaCache;
|
||
extern int dypRuler;
|
||
extern int dxpLogInch;
|
||
extern int dypLogInch;
|
||
extern int dxpLogCm;
|
||
extern int dypLogCm;
|
||
extern int xpSelBar;
|
||
extern HWND vhWndRuler;
|
||
extern int vdxaTextRuler;
|
||
extern int mprmkdxa[rmkMARGMAX];
|
||
extern int vfTabsChanged;
|
||
extern int vfMargChanged;
|
||
extern struct WWD rgwwd[];
|
||
extern long rgbBkgrnd;
|
||
extern long rgbText;
|
||
extern HBRUSH hbrBkgrnd;
|
||
extern long ropErase;
|
||
extern BOOL vfMonochrome;
|
||
extern BOOL vfEraseWw;
|
||
extern int vfIconic;
|
||
|
||
#ifdef RULERALSO
|
||
extern HWND vhDlgIndent;
|
||
#endif /* RULERALSO */
|
||
|
||
HDC vhDCRuler = NULL;
|
||
HDC hMDCBitmap = NULL;
|
||
HDC hMDCScreen = NULL;
|
||
HBITMAP hbmBtn = NULL;
|
||
HBITMAP hbmMark = NULL;
|
||
HBITMAP hbmNullRuler = NULL;
|
||
int dxpRuler;
|
||
|
||
int viBmRuler = -1; /* Index into [CGA/EGA/VGA/8514] bitmaps (see
|
||
WRITE.RC). Set appropriately in FCreateRuler(). */
|
||
|
||
static RECT rgrcRulerBtn[btnMaxUsed];
|
||
static int mprlcbtnDown[rlcBTNMAX] = {btnNIL, btnNIL, btnNIL};
|
||
static struct TBD rgtbdRuler[itbdMax];
|
||
static int xpMinCur;
|
||
static int dxpMark;
|
||
static int dypMark;
|
||
static int btnTabSave = btnLTAB;
|
||
|
||
|
||
near UpdateRulerBtn(int, int);
|
||
BOOL near FCreateRuler(void);
|
||
int near DestroyRuler(void);
|
||
int near RulerStateFromPt(POINT, int *, int *);
|
||
int near MergeRulerMark(int, int, BOOL);
|
||
BOOL near FPointNear(unsigned, unsigned);
|
||
unsigned near XaQuantize(int);
|
||
int near DeleteRulerTab(struct TBD *);
|
||
int near InsertRulerTab(struct TBD *);
|
||
BOOL near FCloseXa(unsigned, unsigned);
|
||
#ifdef KINTL
|
||
unsigned near XaKickBackXa(unsigned);
|
||
near XpKickBackXp(int);
|
||
unsigned near XaQuantizeXa(unsigned);
|
||
#endif /* KINTL */
|
||
|
||
fnShowRuler()
|
||
{
|
||
/* This routine toggles the creation and the destruction of the ruler
|
||
window. */
|
||
|
||
StartLongOp();
|
||
if (pwwdCur->fRuler)
|
||
{
|
||
/* Take down the existing ruler. */
|
||
DestroyRuler();
|
||
SetRulerMenu(TRUE);
|
||
}
|
||
else
|
||
{
|
||
/* There is no ruler, bring one up. */
|
||
if (FCreateRuler())
|
||
{
|
||
SetRulerMenu(FALSE);
|
||
}
|
||
}
|
||
EndLongOp(vhcIBeam);
|
||
}
|
||
|
||
|
||
BOOL near FCreateRuler()
|
||
{
|
||
/* This routine creates the ruler child window and positions it on the
|
||
screen. */
|
||
|
||
extern CHAR szRulerClass[];
|
||
int xpMac = pwwdCur->xpMac;
|
||
int ypMac = pwwdCur->ypMac;
|
||
LOGFONT lf;
|
||
HFONT hf;
|
||
int dyp;
|
||
HPEN hpen;
|
||
RECT rc;
|
||
TEXTMETRIC tmSys;
|
||
HDC hdcSys;
|
||
|
||
|
||
/* Create the ruler window. */
|
||
if ((vhWndRuler = CreateWindow((LPSTR)szRulerClass, (LPSTR)NULL,
|
||
WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0, hParentWw, NULL, hMmwModInstance,
|
||
(LPSTR)NULL)) == NULL)
|
||
{
|
||
goto Error2;
|
||
}
|
||
|
||
/* Save the DC and the memory DC. */
|
||
if ((vhDCRuler = GetDC(vhWndRuler)) == NULL || (hMDCBitmap =
|
||
CreateCompatibleDC(vhDCRuler)) == NULL || (hMDCScreen =
|
||
CreateCompatibleDC(vhDCRuler)) == NULL)
|
||
{
|
||
goto Error1;
|
||
}
|
||
|
||
/* Create a null bitmap for the ruler. */
|
||
if ((hbmNullRuler = CreateBitmap(1, 1, 1, 1, (LPSTR)NULL)) == NULL)
|
||
{
|
||
goto Error1;
|
||
}
|
||
|
||
/* New for Write 3.0: we have a variety of bitmaps for the ruler buttons
|
||
and marks -- loaded depending on the resolution of the user's display.
|
||
All we really want to do here is set viBmRuler, which indexes into the
|
||
appropriate bitmaps (see bitmaps.h) ..pault 7/13/89 */
|
||
|
||
if (viBmRuler < 0)
|
||
{
|
||
/* This idea of passing NULL to GetDC borrowed from WinWord ..pt */
|
||
if ((hdcSys = GetDC(NULL)) == NULL)
|
||
goto Error1;
|
||
else
|
||
{
|
||
int tmHeight;
|
||
|
||
GetTextMetrics(hdcSys, (LPTEXTMETRIC) &tmSys);
|
||
tmHeight = tmSys.tmHeight;
|
||
ReleaseDC(NULL, hdcSys);
|
||
|
||
viBmRuler = 0;
|
||
if (tmHeight > 8)
|
||
viBmRuler++;
|
||
if (tmHeight > 12)
|
||
viBmRuler++;
|
||
if (tmHeight > 16)
|
||
viBmRuler++;
|
||
}
|
||
|
||
Diag(CommSzNum("FCreateRuler: index into [CGA/EGA/VGA/8514] bitmaps==", viBmRuler));
|
||
Assert(idBmBtns + viBmRuler < idBmBtnsMax);
|
||
Assert(idBmMarks + viBmRuler < idBmMarksMax);
|
||
}
|
||
|
||
/* Get the bitmaps for the ruler buttons and the ruler marks. */
|
||
if (hbmBtn == NULL || SelectObject(hMDCBitmap, hbmBtn) == NULL)
|
||
{
|
||
if (NULL == (hbmBtn = LoadBitmap(hMmwModInstance,
|
||
MAKEINTRESOURCE(idBmBtns+viBmRuler))))
|
||
{
|
||
goto Error1;
|
||
}
|
||
}
|
||
if (hbmMark == NULL || SelectObject(hMDCBitmap, hbmMark) == NULL)
|
||
{
|
||
if (NULL == (hbmMark = LoadBitmap(hMmwModInstance,
|
||
MAKEINTRESOURCE(idBmMarks+viBmRuler))))
|
||
{
|
||
goto Error1;
|
||
}
|
||
}
|
||
|
||
/* Get the font for labelling the ruler ticks. */
|
||
bltbc(&lf, 0, sizeof(LOGFONT));
|
||
lf.lfHeight = -MultDiv(czaPoint * 8, dypLogInch, czaInch);
|
||
if ((hf = CreateFontIndirect(&lf)) != NULL)
|
||
{
|
||
if (SelectObject(vhDCRuler, hf) == NULL)
|
||
{
|
||
DeleteObject(hf);
|
||
}
|
||
}
|
||
|
||
/* If this is the first time the ruler is created, then initialize the
|
||
static variables. */
|
||
if (dypRuler == 0)
|
||
{
|
||
int dxpMajor;
|
||
int dxpMinor;
|
||
BITMAP bm;
|
||
int xp;
|
||
int dxpBtn;
|
||
int btn;
|
||
PRECT prc;
|
||
TEXTMETRIC tm;
|
||
|
||
/* Initialize the starting position of the buttons. */
|
||
dxpMinor = (dxpMajor = dxpLogInch >> 1) >> 2;
|
||
xp = xpSelBar + dxpMajor + (dxpMajor >> 1);
|
||
|
||
/* Get the width and height of the buttons. */
|
||
GetObject(hbmBtn, sizeof(BITMAP), (LPSTR)&bm);
|
||
/* Factor of 2 since we have positive and negative images
|
||
of each button embedded in the bitmap now ..pault */
|
||
dxpBtn = bm.bmWidth / (btnMaxReal*2);
|
||
dypRuler = bm.bmHeight;
|
||
|
||
/* Position the buttons. */
|
||
for (prc = &rgrcRulerBtn[btn = btnMIN]; btn < btnMaxUsed; btn++, prc++)
|
||
{
|
||
prc->left = xp;
|
||
prc->top = 1;
|
||
prc->right = (xp += dxpBtn);
|
||
prc->bottom = bm.bmHeight + 1;
|
||
xp += (btn == btnTABMAX || btn == btnSPACEMAX) ? dxpMajor :
|
||
dxpMinor;
|
||
}
|
||
|
||
/* Get the width and height of the tab marks. */
|
||
GetObject(hbmMark, sizeof(BITMAP), (LPSTR)&bm);
|
||
dxpMark = bm.bmWidth / rmkMAX;
|
||
dypMark = bm.bmHeight;
|
||
|
||
/* Lastly, initialize the height of the ruler. (Four is for the two
|
||
lines at the bottom of the ruler plus two blank lines.) */
|
||
GetTextMetrics(vhDCRuler, (LPTEXTMETRIC)&tm);
|
||
dypRuler += dypMark + (tm.tmAscent - tm.tmInternalLeading) + 4;
|
||
}
|
||
|
||
/* Move the document window to make room for the ruler. */
|
||
pwwdCur->fRuler = TRUE;
|
||
dyp = dypRuler - (pwwdCur->ypMin - 1);
|
||
MoveWindow(wwdCurrentDoc.wwptr, 0, dyp, xpMac, ypMac - dyp, FALSE);
|
||
|
||
/* Erase the top of the document window. */
|
||
PatBlt(wwdCurrentDoc.hDC, 0, 0, xpMac, wwdCurrentDoc.ypMin, ropErase);
|
||
rc.left = rc.top = 0;
|
||
rc.right = xpMac;
|
||
rc.bottom = wwdCurrentDoc.ypMin;
|
||
ValidateRect(wwdCurrentDoc.wwptr, (LPRECT)&rc);
|
||
UpdateWindow(wwdCurrentDoc.wwptr);
|
||
|
||
/* Move the ruler into position. */
|
||
MoveWindow(vhWndRuler, 0, 0, xpMac, dypRuler, FALSE);
|
||
BringWindowToTop(vhWndRuler);
|
||
|
||
/* Set the DC to transparent mode. */
|
||
SetBkMode(vhDCRuler, TRANSPARENT);
|
||
|
||
/* Set the background and foreground colors for the ruler. */
|
||
SetBkColor(vhDCRuler, rgbBkgrnd);
|
||
SetTextColor(vhDCRuler, rgbText);
|
||
|
||
/* Set the brush and the pen for the ruler. */
|
||
SelectObject(vhDCRuler, hbrBkgrnd);
|
||
if ((hpen = CreatePen(0, 0, rgbText)) == NULL)
|
||
{
|
||
hpen = GetStockObject(BLACK_PEN);
|
||
}
|
||
SelectObject(vhDCRuler, hpen);
|
||
|
||
/* Lastly, ensure that the ruler is painted. */
|
||
ShowWindow(vhWndRuler, SHOW_OPENWINDOW);
|
||
UpdateWindow(vhWndRuler);
|
||
return (TRUE);
|
||
|
||
Error1:
|
||
DestroyWindow(vhWndRuler);
|
||
vhWndRuler = NULL;
|
||
Error2:
|
||
WinFailure();
|
||
return (FALSE);
|
||
}
|
||
|
||
|
||
near DestroyRuler()
|
||
{
|
||
/* This routine destroys the ruler window and refreshes the screen. */
|
||
|
||
/* First, erase the ruler. */
|
||
PatBlt(vhDCRuler, 0, 0, dxpRuler, dypRuler, ropErase);
|
||
|
||
/* Clean up the ruler window. */
|
||
DestroyWindow(vhWndRuler);
|
||
vhWndRuler = NULL;
|
||
ResetRuler();
|
||
|
||
/* Move the document window back to the top of the window. */
|
||
pwwdCur->fRuler = FALSE;
|
||
vfEraseWw = TRUE;
|
||
MoveWindow(wwdCurrentDoc.wwptr, 0, 0, dxpRuler, wwdCurrentDoc.ypMac +
|
||
dypRuler - (wwdCurrentDoc.ypMin - 1), FALSE);
|
||
vfEraseWw = FALSE;
|
||
|
||
/* Validate the area in the document window above the text. */
|
||
PatBlt(wwdCurrentDoc.hDC, 0, 0, dxpRuler, wwdCurrentDoc.ypMin, ropErase);
|
||
ValidateRect(hParentWw, (LPRECT)NULL);
|
||
}
|
||
|
||
|
||
UpdateRuler()
|
||
{
|
||
/* This routine will redraw as much of the ruler as necessary to reflect the
|
||
current selection. */
|
||
|
||
/* Only repaint the ruler if it exists and it is not currently being
|
||
changed. */
|
||
if (vhWndRuler != NULL)
|
||
{
|
||
RulerPaint(FALSE, FALSE, FALSE);
|
||
}
|
||
}
|
||
|
||
ReframeRuler()
|
||
{
|
||
/* This routine will cause the ruler window to be redrawn,
|
||
when units change - leave update out, since dialog box
|
||
will repaint */
|
||
|
||
/* Only repaint the ruler if it exists . */
|
||
if (vhWndRuler != NULL)
|
||
{
|
||
InvalidateRect(vhWndRuler, (LPRECT)NULL, FALSE);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
ResetRuler()
|
||
{
|
||
/* Reset the values of the ruler buttons and the ruler margins and tabs so
|
||
they redrawn during the next paint message. */
|
||
if ((btnTabSave = mprlcbtnDown[rlcTAB]) == btnNIL)
|
||
{
|
||
btnTabSave = btnLTAB;
|
||
}
|
||
|
||
/* Reset the buttons. */
|
||
if (vfIconic)
|
||
{
|
||
/* All we have to do is reset our internal state. */
|
||
bltc(mprlcbtnDown, btnNIL, rlcBTNMAX);
|
||
}
|
||
else
|
||
{
|
||
/* We had best reset the buttons on the screen as well. */
|
||
UpdateRulerBtn(rlcTAB, btnNIL);
|
||
UpdateRulerBtn(rlcSPACE, btnNIL);
|
||
UpdateRulerBtn(rlcJUST, btnNIL);
|
||
}
|
||
|
||
/* Reset the margins and the tabs. */
|
||
bltc(mprmkdxa, -1, rmkMARGMAX);
|
||
bltc(rgtbdRuler, 0, cwTBD * itbdMax);
|
||
}
|
||
|
||
|
||
ResetTabBtn()
|
||
{
|
||
/* This routine resets the tab button on the ruler to the left tab button.
|
||
*/
|
||
if (mprlcbtnDown[rlcTAB] != btnLTAB)
|
||
{
|
||
UpdateRulerBtn(rlcTAB, btnLTAB);
|
||
}
|
||
}
|
||
|
||
|
||
RulerPaint(fContentsOnly, fFrameOnly, fInit)
|
||
BOOL fContentsOnly;
|
||
BOOL fInit;
|
||
{
|
||
/* This routine draws the ruler in the ruler window. If fContentsOnly is
|
||
set, then only the tabs as they currently exist in rgtbdRuler, and the
|
||
button settings are drawn. If fFrameOnly is set, then only the ruler frame
|
||
is redrawn. If fInit is set, then the portion of the ruler to be redrawn
|
||
(tabs, frame or all) is redrawn from scratch. */
|
||
|
||
|
||
int xpMin = pwwdCur->xpMin;
|
||
HBITMAP hbm;
|
||
|
||
/* If fContentsOnly is set, then skip most of this stuff and draw only the
|
||
tabs and the button settings. */
|
||
if (!fContentsOnly)
|
||
{
|
||
/* We only need to draw the physical ruler itself when the window has
|
||
scrolled horizontally. */
|
||
if (fInit || xpMinCur != xpMin)
|
||
{
|
||
register int xp;
|
||
TEXTMETRIC tm;
|
||
int dypTick;
|
||
int ypTickEnd;
|
||
int ypTickStart;
|
||
int ypTick;
|
||
int iLevel;
|
||
CHAR rgchInch[3];
|
||
int dxpLogUnitInc;
|
||
int dcNextTick;
|
||
int dxpLine;
|
||
|
||
|
||
extern int utCur;
|
||
#define cDivisionMax 8 /* max divisions per ruler unit. e.g. 8 per inch */
|
||
int rgypTick[cDivisionMax];
|
||
int cxpExtra;
|
||
int cDivision;
|
||
int dxpLogUnit;
|
||
int dxpMeas;
|
||
int ypT;
|
||
|
||
/* Initialize the y-coordinate of the ticks. */
|
||
GetTextMetrics(vhDCRuler, (LPTEXTMETRIC)&tm);
|
||
ypTickEnd = dypRuler - dypMark - 2;
|
||
ypTickStart = ypTick = ypTickEnd - (dypTick = tm.tmAscent -
|
||
tm.tmInternalLeading);
|
||
|
||
/* set up measurements for the ruler based on current unit -
|
||
note that only inch and cm are handled in this version */
|
||
|
||
if (utCur == utInch)
|
||
{
|
||
dxpLogUnit = dxpLogUnitInc = dxpLogInch;
|
||
cDivision = 8; /* # of divisions */
|
||
dxpMeas = dxpLogUnit >> 3; /* 1/8" units */
|
||
/* get extra pixels to distribute if not even multiple */
|
||
/* note - mod done by hand */
|
||
cxpExtra = dxpLogUnit - (dxpMeas << 3);
|
||
dcNextTick = 1;
|
||
/* fill table of tick lengths */
|
||
rgypTick[0] = ypT = ypTick;
|
||
rgypTick[4] = ypT += (dypTick >> 2);
|
||
rgypTick[2] = rgypTick[6] = ypT += (dypTick >> 2);
|
||
rgypTick[1] = rgypTick[3] = rgypTick[5] = rgypTick[7] =
|
||
ypT += (dypTick >> 2);
|
||
}
|
||
else
|
||
/* default to cm */
|
||
{
|
||
dxpLogUnit = dxpLogUnitInc = dxpLogCm;
|
||
cDivision = 2; /* # of divisions */
|
||
dxpMeas = dxpLogUnit >> 1; /* 1/2 cm units */
|
||
/* get extra pixels to distribute if not even multiple */
|
||
cxpExtra = dxpLogUnit - (dxpMeas << 1);
|
||
dcNextTick = 1;
|
||
/* fill table of tick lengths */
|
||
rgypTick[0] = ypTick;
|
||
rgypTick[1] = ypTick + (dypTick >> 1);
|
||
}
|
||
|
||
if (fInit)
|
||
{
|
||
/* Erase the area where the ruler will be drawn. */
|
||
PatBlt(vhDCRuler, 0, 0, dxpRuler, dypRuler, ropErase);
|
||
|
||
/* Draw a line across the bottom of the ruler. */
|
||
MoveTo(vhDCRuler, xpSelBar, dypRuler - 1);
|
||
LineTo(vhDCRuler, dxpRuler, dypRuler - 1);
|
||
|
||
/* Draw the base of the ruler. */
|
||
MoveTo(vhDCRuler, xpSelBar, ypTickEnd);
|
||
LineTo(vhDCRuler, dxpRuler, ypTickEnd);
|
||
}
|
||
else
|
||
{
|
||
/* Erase the old tick marks. */
|
||
PatBlt(vhDCRuler, 0, ypTickStart, dxpRuler, ypTickEnd -
|
||
ypTickStart, ropErase);
|
||
}
|
||
|
||
/* Set the clip region to be only the ruler. */
|
||
iLevel = SaveDC(vhDCRuler);
|
||
IntersectClipRect(vhDCRuler, xpSelBar, 0, dxpRuler, dypRuler);
|
||
|
||
/* Draw the ticks at the each division mark. */
|
||
/* iDivision is the current division with in a unit. It is
|
||
used to determine when extra pixels are distributed and
|
||
which tick mark to use */
|
||
{
|
||
register int iDivision = 0;
|
||
|
||
for (xp = (xpSelBar - xpMin); xp < dxpRuler; xp +=
|
||
dxpMeas)
|
||
{
|
||
/* distribute extra pixels at front */
|
||
if (iDivision < cxpExtra)
|
||
xp++;
|
||
|
||
MoveTo(vhDCRuler, xp, rgypTick[iDivision]);
|
||
LineTo(vhDCRuler, xp, ypTickEnd);
|
||
|
||
if (++iDivision == cDivision)
|
||
iDivision = 0;
|
||
}
|
||
}
|
||
|
||
|
||
/* Label the tick marks. */
|
||
dxpLine = GetSystemMetrics(SM_CXBORDER);
|
||
rgchInch[0] = rgchInch[1] = rgchInch[2] = '0';
|
||
for (xp = xpSelBar - xpMin;
|
||
xp < dxpRuler;
|
||
xp += dxpLogUnitInc, rgchInch[2] += dcNextTick)
|
||
{
|
||
int isz;
|
||
int dxpsz;
|
||
|
||
if (rgchInch[2] > '9')
|
||
{
|
||
rgchInch[1]++;
|
||
rgchInch[2] = '0' + (rgchInch[2] - (CHAR) ('9' + 1));
|
||
}
|
||
if (rgchInch[1] > '9')
|
||
{
|
||
rgchInch[0]++;
|
||
rgchInch[1] = '0' + (rgchInch[1] - (CHAR) ('9' + 1));
|
||
}
|
||
isz = rgchInch[0] == '0' ?
|
||
(rgchInch[1] == '0' ? 2 : 1):
|
||
0;
|
||
dxpsz = LOWORD(GetTextExtent(vhDCRuler,
|
||
(LPSTR)&rgchInch[isz],
|
||
3 - isz));
|
||
if (dxpsz + dxpLine >= dxpMeas)
|
||
{
|
||
PatBlt(vhDCRuler, xp + dxpLine, ypTickStart,
|
||
dxpsz, ypTickEnd - ypTickStart, ropErase);
|
||
}
|
||
TextOut(vhDCRuler, xp + dxpLine, ypTickStart -
|
||
tm.tmInternalLeading, (LPSTR)&rgchInch[isz],
|
||
3 - isz);
|
||
}
|
||
|
||
|
||
/* Set the clip region back. */
|
||
RestoreDC(vhDCRuler, iLevel);
|
||
}
|
||
|
||
/* Draw the buttons on the ruler. */
|
||
if (fInit)
|
||
{
|
||
register PRECT prc = &rgrcRulerBtn[btnMIN];
|
||
int btn;
|
||
|
||
/* Ensure that we have the bitmap for the buttons. */
|
||
if (SelectObject(hMDCBitmap, hbmBtn) == NULL)
|
||
{
|
||
if (NULL == (hbmBtn = LoadBitmap(hMmwModInstance,
|
||
MAKEINTRESOURCE(idBmBtns+viBmRuler)))
|
||
|| SelectObject(hMDCBitmap, hbmBtn) == NULL)
|
||
{
|
||
WinFailure();
|
||
goto NoBtns;
|
||
}
|
||
}
|
||
|
||
/* Now, draw the buttons. */
|
||
for (btn = btnMIN; btn < btnMaxUsed; btn++)
|
||
{
|
||
int dxpBtn = prc->right - prc->left;
|
||
|
||
BitBlt(vhDCRuler, prc->left, prc->top, dxpBtn, prc->bottom -
|
||
prc->top, hMDCBitmap, (btn - btnMIN) * dxpBtn, 0, vfMonochrome
|
||
? MERGEMARK : SRCCOPY);
|
||
prc++;
|
||
}
|
||
SelectObject(hMDCBitmap, hbmNullRuler);
|
||
NoBtns:;
|
||
}
|
||
}
|
||
|
||
/* If fFrame only is set, then we're finished. */
|
||
if (!fFrameOnly)
|
||
{
|
||
/* Lastly, draw the button settings, the margins and the tabs. */
|
||
TSV rgtsv[itsvparaMax];
|
||
register struct TBD *ptbd1;
|
||
int rmk;
|
||
int xpMarkMin = xpSelBar - (dxpMark >> 1);
|
||
int dxpMarkMax = dxpRuler - xpSelBar - (dxpMark >> 1);
|
||
unsigned dxa;
|
||
|
||
if (mprlcbtnDown[rlcTAB] == btnNIL)
|
||
{
|
||
/* Initalize the tab button to be left tab. */
|
||
UpdateRulerBtn(rlcTAB, btnTabSave);
|
||
}
|
||
|
||
/* Now for the spacing and justification. */
|
||
GetRgtsvPapSel(rgtsv);
|
||
UpdateRulerBtn(rlcSPACE, (rgtsv[itsvSpacing].fGray != 0) ? btnNIL :
|
||
(rgtsv[itsvSpacing].wTsv - czaLine) / (czaLine / 2) + btnSINGLE);
|
||
UpdateRulerBtn(rlcJUST, (rgtsv[itsvJust].fGray != 0) ? btnNIL :
|
||
(rgtsv[itsvJust].wTsv - jcLeft) + btnLEFT);
|
||
|
||
/* The margins and the tabs are based off of the first cp of the
|
||
selection. */
|
||
CacheSect(docCur, selCur.cpFirst);
|
||
CachePara(docCur, selCur.cpFirst);
|
||
|
||
/* If the window has scrolled horizontally or become wider, we must
|
||
redraw the margins and the tabs. */
|
||
if (!fInit && xpMinCur == xpMin)
|
||
{
|
||
/* Compare to see if the margins have changed. */
|
||
if (mprmkdxa[rmkINDENT] != vpapAbs.dxaLeft + vpapAbs.dxaLeft1)
|
||
{
|
||
goto DrawMargins;
|
||
}
|
||
if (mprmkdxa[rmkLMARG] != vpapAbs.dxaLeft)
|
||
{
|
||
goto DrawMargins;
|
||
}
|
||
if (mprmkdxa[rmkRMARG] != vsepAbs.dxaText - vpapAbs.dxaRight)
|
||
{
|
||
goto DrawMargins;
|
||
}
|
||
|
||
/* Compare to see if the tabs has changed. */
|
||
{
|
||
register struct TBD *ptbd2;
|
||
|
||
for (ptbd1 = &rgtbdRuler[0], ptbd2 = &vpapAbs.rgtbd[0];
|
||
ptbd1->dxa == ptbd2->dxa; ptbd1++, ptbd2++)
|
||
{
|
||
/* If the end of the list of tabs, then the lists are equal.
|
||
*/
|
||
if (ptbd1->dxa == 0)
|
||
{
|
||
goto SkipTabs;
|
||
}
|
||
|
||
/* The justification codes must match if they are decimal
|
||
tabs (everything else collaspes to left tabs). */
|
||
if (ptbd1->jc != ptbd2->jc && (ptbd1->jc == (jcTabDecimal
|
||
- jcTabMin) || (ptbd2->jc == (jcTabDecimal - jcTabMin))))
|
||
{
|
||
goto DrawMargins;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
DrawMargins:
|
||
#ifdef KINTL
|
||
/* This is really an extra. xpMinCur will get updated later on.
|
||
But, we need this variable set up right for the MergeRulerMark()
|
||
to draw a mark at the right place.... Oh well. */
|
||
xpMinCur = xpMin;
|
||
#endif /* ifdef KINTL */
|
||
|
||
/* Redraw the margins from scratch. Set up the bitmap for hMDCScreen,
|
||
the ruler bar in monochrome format. */
|
||
if ((hbm = CreateBitmap(dxpRuler + dxpMark, dypMark, 1, 1,
|
||
(LPSTR)NULL)) == NULL)
|
||
{
|
||
WinFailure();
|
||
goto SkipTabs;
|
||
}
|
||
DeleteObject(SelectObject(hMDCScreen, hbm));
|
||
PatBlt(hMDCScreen, 0, 0, dxpRuler + dxpMark, dypMark, vfMonochrome ?
|
||
ropErase : WHITENESS);
|
||
PatBlt(vhDCRuler, 0, dypRuler - dypMark - 1, dxpRuler + dxpMark,
|
||
dypMark, ropErase);
|
||
|
||
/* Determine the margin positions. */
|
||
mprmkdxa[rmkINDENT] = vpapAbs.dxaLeft + vpapAbs.dxaLeft1;
|
||
mprmkdxa[rmkLMARG] = vpapAbs.dxaLeft;
|
||
mprmkdxa[rmkRMARG] = (vdxaTextRuler = vsepAbs.dxaText) -
|
||
vpapAbs.dxaRight;
|
||
|
||
/* Draw the margins marks. */
|
||
for (rmk = rmkMARGMIN; rmk < rmkMARGMAX; rmk++)
|
||
{
|
||
register int dxp = MultDiv(mprmkdxa[rmk], dxpLogInch, czaInch) -
|
||
xpMin;
|
||
|
||
/* If the margin mark would not appear on the ruler, scrolled off to
|
||
either end, then don't try to draw it. */
|
||
if (dxp >= 0 && dxp < dxpMarkMax)
|
||
{
|
||
MergeRulerMark(rmk, xpMarkMin + dxp, FALSE);
|
||
}
|
||
}
|
||
|
||
/* Redraw the tabs. */
|
||
ptbd1 = &rgtbdRuler[0];
|
||
if (!fInit)
|
||
{
|
||
/* If fInit is set, then rgtbdRuler is not changed. */
|
||
blt(vpapAbs.rgtbd, ptbd1, cwTBD * itbdMax);
|
||
}
|
||
while ((dxa = ptbd1->dxa) != 0)
|
||
{
|
||
register int dxp = MultDiv(dxa, dxpLogInch, czaInch) - xpMin;
|
||
|
||
/* If the tab mark would not appear on the ruler, scrolled off to
|
||
either end, then don't try to draw it. */
|
||
if (dxp >= 0 && dxp < dxpMarkMax)
|
||
{
|
||
MergeRulerMark(ptbd1->jc == (jcTabDecimal - jcTabMin) ? rmkDTAB
|
||
: rmkLTAB, xpMarkMin + dxp, FALSE);
|
||
}
|
||
ptbd1++;
|
||
}
|
||
SkipTabs:;
|
||
}
|
||
|
||
/* Record the edges of the current window. */
|
||
xpMinCur = xpMin;
|
||
}
|
||
|
||
|
||
RulerMouse(pt)
|
||
POINT pt;
|
||
{
|
||
/* Process all mouse messages from a down-click at point pt until the
|
||
corresponding mouse up-click. */
|
||
|
||
int btn;
|
||
int rlc;
|
||
int rlcCur;
|
||
int rmkCur;
|
||
int xp;
|
||
int xpCur;
|
||
unsigned xa;
|
||
struct TBD *ptbd;
|
||
struct TBD tbd;
|
||
BOOL fMarkMove = FALSE;
|
||
BOOL fDeleteMark = FALSE;
|
||
BOOL fBtnChanged = FALSE;
|
||
|
||
if (!FWriteOk(fwcNil))
|
||
{
|
||
return;
|
||
}
|
||
|
||
/* Translate the point into a button group and a button. */
|
||
RulerStateFromPt(pt, &rlcCur, &btn);
|
||
|
||
/* Down clicking on the tab rule is a special case. */
|
||
if (rlcCur == rlcRULER)
|
||
{
|
||
unsigned dxa = MultDiv(pt.x - xpSelBar + xpMinCur, czaInch, dxpLogInch);
|
||
int rmk;
|
||
int itbd;
|
||
|
||
/* Have we moused down on a margin? */
|
||
for (rmk = rmkMARGMIN; rmk < rmkMARGMAX; rmk++)
|
||
{
|
||
#ifdef KINTL
|
||
if (FPointNear(mprmkdxa[rmk], dxa - XaKickBackXa(dxa)))
|
||
#else
|
||
if (FPointNear(mprmkdxa[rmk], dxa))
|
||
#endif /* if-else-def KINTL */
|
||
{
|
||
int xpT;
|
||
|
||
/* Remember this mark and its position. */
|
||
rmkCur = rmk;
|
||
xpCur = xpSelBar + MultDiv(mprmkdxa[rmk], dxpLogInch, czaInch) -
|
||
(dxpMark >> 1) - xpMinCur;
|
||
|
||
InvertMark:
|
||
#ifdef KINTL
|
||
/* Adjust for the kick-backs. */
|
||
/* But don't modify the xpCur. */
|
||
xpT = xpCur + XpKickBackXp(xpCur);
|
||
#else
|
||
xpT = xpCur;
|
||
#endif /* if-else-def KINTL */
|
||
|
||
/* Time to invert the selected mark. */
|
||
PatBlt(vhDCRuler, xpT, dypRuler - dypMark - 1, dxpMark,
|
||
dypMark, DSTINVERT);
|
||
goto GotMark;
|
||
}
|
||
}
|
||
|
||
/* Have we moused down on an existing tab? */
|
||
for (itbd = 0, ptbd = &rgtbdRuler[0]; ; itbd++, ptbd++)
|
||
{
|
||
/* The end of the tabs have been found. */
|
||
if (ptbd->dxa == 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
/* Have we moused down on this tab? */
|
||
#ifdef KINTL
|
||
if (FPointNear(ptbd->dxa, dxa - XaKickBackXa(dxa)))
|
||
#else
|
||
if (FPointNear(ptbd->dxa, dxa))
|
||
#endif /* if-else-def KANJI */
|
||
{
|
||
/* Save this tab descriptor and its location. */
|
||
tbd = *ptbd;
|
||
rmkCur = (tbd.jc + jcTabMin) == jcTabDecimal ? rmkDTAB :
|
||
rmkLTAB;
|
||
xpCur = xpSelBar + MultDiv(tbd.dxa, dxpLogInch, czaInch) -
|
||
(dxpMark >> 1) - xpMinCur;
|
||
goto InvertMark;
|
||
}
|
||
}
|
||
|
||
/* If one more tab would be too many, then beep and return. */
|
||
if (itbd >= itbdMax - 1)
|
||
{
|
||
_beep();
|
||
return;
|
||
}
|
||
|
||
/* Create a tab descriptor for this new tab. */
|
||
bltc(&tbd, 0, cwTBD);
|
||
tbd.dxa = XaQuantize(pt.x);
|
||
tbd.jc = (mprlcbtnDown[rlcTAB] == btnLTAB ? jcTabLeft : jcTabDecimal) -
|
||
jcTabMin;
|
||
rmkCur = (mprlcbtnDown[rlcTAB] - btnLTAB) + rmkLTAB;
|
||
|
||
/* A mark for the new tab needs to be drawn. */
|
||
MergeRulerMark(rmkCur, xpCur = xpSelBar + MultDiv(tbd.dxa, dxpLogInch,
|
||
czaInch) - (dxpMark >> 1) - xpMinCur, TRUE);
|
||
|
||
/* Inserting a tab is like moving an existing tab. */
|
||
fMarkMove = TRUE;
|
||
|
||
GotMark:;
|
||
|
||
#ifdef RULERALSO
|
||
/* Update dialog box */
|
||
if (vhDlgIndent && rmkCur < rmkMARGMAX)
|
||
{
|
||
SetIndentText(rmkCur, dxa);
|
||
}
|
||
#endif /* RULERALSO */
|
||
|
||
}
|
||
else if (rlcCur != rlcNIL)
|
||
{
|
||
/* Otherwise, if a button has been selected, the reflect the change on
|
||
the ruler. */
|
||
UpdateRulerBtn(rlcCur, btn);
|
||
}
|
||
else
|
||
{
|
||
/* The user has moused down on nothing of importance. */
|
||
return;
|
||
}
|
||
|
||
/* Get all of the mouse events until further notice. */
|
||
SetCapture(vhWndRuler);
|
||
|
||
/* Process all of the mouse move messages. */
|
||
while (FStillDown(&pt))
|
||
{
|
||
/* Movement on the tab ruler must be handled special. */
|
||
if (rlcCur == rlcRULER)
|
||
{
|
||
#ifdef KINTL
|
||
unsigned xaT;
|
||
#endif /* ifdef KINTL */
|
||
|
||
/* Guarantee that xp is in the range xpSelBar <= xp <= dxpRuler. */
|
||
if ((xp = pt.x) > dxpRuler)
|
||
{
|
||
xp = dxpRuler;
|
||
}
|
||
else if (xp < xpSelBar)
|
||
{
|
||
xp = xpSelBar;
|
||
}
|
||
|
||
/* Convert the mouse position to twips. */
|
||
#ifdef KINTL
|
||
if ((xa = XaQuantize(xp)) > (xaT = XaQuantizeXa(vdxaTextRuler))
|
||
#else
|
||
if ((xa = XaQuantize(xp)) > vdxaTextRuler
|
||
#endif /* if-else-def KINTL */
|
||
&& rmkCur < rmkMARGMAX)
|
||
{
|
||
/* Margins are confined to the page. */
|
||
#ifdef KINTL
|
||
xa = xaT;
|
||
#else
|
||
xa = vdxaTextRuler;
|
||
#endif
|
||
}
|
||
|
||
/* If the cursor is on the ruler, then we may move a tab, but we
|
||
always move the margins. */
|
||
if ((rmkCur < rmkMARGMAX) || (pt.y >= 0 && pt.y < dypRuler + dypMark
|
||
&& xa != 0))
|
||
{
|
||
/* If the current mark has not moved, then there is nothing to
|
||
do. */
|
||
if (fDeleteMark || xa != XaQuantize(xpCur + (dxpMark >> 1)))
|
||
{
|
||
/* Indicate that the mark has moved. */
|
||
fMarkMove = TRUE;
|
||
|
||
/* Restore the screen under the current mark. */
|
||
if (!fDeleteMark)
|
||
{
|
||
MergeRulerMark(rmkCur, xpCur, FALSE);
|
||
}
|
||
|
||
/* Draw the mark at the new location. */
|
||
MergeRulerMark(rmkCur, xpCur = MultDiv(xa, dxpLogInch,
|
||
czaInch) + xpSelBar - xpMinCur - (dxpMark >> 1), TRUE);
|
||
|
||
/* Show this is a valid mark. */
|
||
fDeleteMark = FALSE;
|
||
|
||
#ifdef RULERALSO
|
||
/* Update dialog box */
|
||
if (vhDlgIndent && rmkCur < rmkMARGMAX)
|
||
{
|
||
SetIndentText(rmkCur, xa);
|
||
}
|
||
#endif /* RULERALSO */
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Restore the screen under the current mark. */
|
||
if (!fDeleteMark)
|
||
{
|
||
MergeRulerMark(rmkCur, xpCur, FALSE);
|
||
}
|
||
|
||
/* This mark is being deleted. */
|
||
fDeleteMark = TRUE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* If the mouse is on a button within the same button group, then
|
||
reflect the change. */
|
||
RulerStateFromPt(pt, &rlc, &btn);
|
||
if (rlc == rlcCur)
|
||
{
|
||
UpdateRulerBtn(rlc, btn);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* We are capturing all mouse events; we can now release them. */
|
||
ReleaseCapture();
|
||
|
||
/* Up-clicking on the tab ruler is a special case. */
|
||
if (rlcCur == rlcRULER)
|
||
{
|
||
if (!fDeleteMark)
|
||
{
|
||
/* Restore the screen under the current mark. */
|
||
MergeRulerMark(rmkCur, xpCur, FALSE);
|
||
}
|
||
|
||
if (fMarkMove)
|
||
{
|
||
/* Guarantee that xp is in the range xpSelBar <= xp <= dxpRuler. */
|
||
if ((xp = pt.x) > dxpRuler)
|
||
{
|
||
xp = dxpRuler;
|
||
}
|
||
else if (xp < xpSelBar)
|
||
{
|
||
xp = xpSelBar;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
xp = xpCur + (dxpMark >> 1);
|
||
}
|
||
|
||
/* Convert the mouse position to twips. */
|
||
if ((xa = XaQuantize(xp)) > vdxaTextRuler && rmkCur < rmkMARGMAX)
|
||
{
|
||
/* Margins are confined to the page. */
|
||
xa = vdxaTextRuler;
|
||
}
|
||
|
||
/* If the cursor is on the ruler then we may insert/move a tab, but we
|
||
always move the margins. */
|
||
if ((rmkCur < rmkMARGMAX) || (pt.y >= 0 && pt.y < dypRuler + dypMark &&
|
||
xa != 0))
|
||
{
|
||
/* Draw the mark at the new location. */
|
||
MergeRulerMark(rmkCur, MultDiv(xa, dxpLogInch, czaInch) + xpSelBar -
|
||
xpMinCur - (dxpMark >> 1), FALSE);
|
||
|
||
/* We are moving one of the margins. */
|
||
if (rmkCur < rmkMARGMAX)
|
||
{
|
||
if (vfMargChanged = mprmkdxa[rmkCur] != xa)
|
||
{
|
||
mprmkdxa[rmkCur] = xa;
|
||
}
|
||
|
||
#ifdef RULERALSO
|
||
/* Update dialog box */
|
||
if (vhDlgIndent)
|
||
{
|
||
SetIndentText(rmkCur, xa);
|
||
}
|
||
#endif /* RULERALSO */
|
||
|
||
}
|
||
|
||
/* It is a tab we are inserting/deleting. */
|
||
else
|
||
{
|
||
tbd.dxa = xa;
|
||
|
||
/* Is this a new tab? */
|
||
if (ptbd->dxa == 0)
|
||
{
|
||
/* Insert the new tab. */
|
||
InsertRulerTab(&tbd);
|
||
}
|
||
|
||
/* We are moving a tab; if it hasn't really moved, then do
|
||
nothing. */
|
||
else if (!FCloseXa(ptbd->dxa, xa))
|
||
{
|
||
DeleteRulerTab(ptbd);
|
||
InsertRulerTab(&tbd);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* We are deleting the tab; if its a new, there's nothing to do. */
|
||
else if (ptbd->dxa != 0)
|
||
{
|
||
DeleteRulerTab(ptbd);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* If the mouse is on a button within the same button group, then
|
||
reflect the change. */
|
||
|
||
int btnT;
|
||
|
||
RulerStateFromPt(pt, &rlc, &btnT);
|
||
if (rlc == rlcCur)
|
||
{
|
||
UpdateRulerBtn(rlc, btn = btnT);
|
||
}
|
||
fBtnChanged = btn != mprlcbtnDown[btn];
|
||
}
|
||
|
||
/* Do the format only if a button changed */
|
||
if ((fBtnChanged && rlcCur != rlcTAB) || vfMargChanged || vfTabsChanged)
|
||
{
|
||
struct SEL selSave;
|
||
typeCP dcp;
|
||
typeCP dcp2;
|
||
CHAR rgb[1 + cchINT];
|
||
CHAR *pch;
|
||
int sprm;
|
||
int val;
|
||
struct TBD (**hgtbd)[];
|
||
|
||
/* Set the selection to cover all of the paragraphs selected. */
|
||
ExpandCurSel(&selSave);
|
||
dcp2 = (dcp = selCur.cpLim - selCur.cpFirst) - (selCur.cpLim > cpMacCur
|
||
? ccpEol : 0);
|
||
SetUndo(uacRulerChange, docCur, selCur.cpFirst, (rlcCur != rlcRULER ||
|
||
rmkCur < rmkMARGMAX) ? dcp : dcp2, docNil, cpNil, dcp2, 0);
|
||
|
||
/* Set the sprm and it's value for the ruler change. */
|
||
switch (rlcCur)
|
||
{
|
||
case rlcSPACE:
|
||
sprm = sprmPDyaLine;
|
||
val = (mprlcbtnDown[rlcSPACE] - btnSINGLE) * (czaLine / 2) +
|
||
czaLine;
|
||
break;
|
||
|
||
case rlcJUST:
|
||
sprm = sprmPJc;
|
||
val = mprlcbtnDown[rlcJUST] - btnLEFT + jcLeft;
|
||
break;
|
||
|
||
case rlcRULER:
|
||
switch (rmkCur)
|
||
{
|
||
case rmkINDENT:
|
||
sprm = sprmPFIndent;
|
||
val = mprmkdxa[rmkINDENT] - mprmkdxa[rmkLMARG];
|
||
break;
|
||
|
||
case rmkLMARG:
|
||
/* Changing the left margin changes the first indent as well.
|
||
First, the indent... */
|
||
val = mprmkdxa[rmkINDENT] - mprmkdxa[rmkLMARG];
|
||
pch = &rgb[0];
|
||
*pch++ = sprmPFIndent;
|
||
bltbyte(&val, pch, cchINT);
|
||
AddOneSprm(rgb, FALSE);
|
||
|
||
/* Now for the left margin... */
|
||
sprm = sprmPLMarg;
|
||
val = mprmkdxa[rmkLMARG];
|
||
break;
|
||
|
||
case rmkRMARG:
|
||
sprm = sprmPRMarg;
|
||
val = vdxaTextRuler - mprmkdxa[rmkRMARG];
|
||
break;
|
||
|
||
case rmkLTAB:
|
||
case rmkDTAB:
|
||
/* Tabs are different. The change is made by blting the new tab
|
||
table on top of the old. */
|
||
vfTabsChanged = FALSE;
|
||
if ((hgtbd = (**hpdocdod)[docCur].hgtbd) == NULL)
|
||
{
|
||
if (FNoHeap(hgtbd = (struct TBD (**)[])HAllocate(itbdMax *
|
||
cwTBD)))
|
||
{
|
||
return;
|
||
}
|
||
(**hpdocdod)[docCur].hgtbd = hgtbd;
|
||
}
|
||
blt(rgtbdRuler, *hgtbd, itbdMax * cwTBD);
|
||
|
||
/* Changing the tabs makes everything dirty. */
|
||
(**hpdocdod)[docCur].fDirty = TRUE;
|
||
vdocParaCache = docNil;
|
||
TrashAllWws();
|
||
goto ChangeMade;
|
||
}
|
||
|
||
/* Indicate that the margins have been set. */
|
||
vfMargChanged = FALSE;
|
||
}
|
||
|
||
/* Now, lets set the sprm to the new value. */
|
||
pch = &rgb[0];
|
||
*pch++ = sprm;
|
||
bltbyte(&val, pch, cchINT);
|
||
AddOneSprm(rgb, FALSE);
|
||
|
||
ChangeMade:
|
||
/* Reset the selection to it's old value. */
|
||
EndLookSel(&selSave, TRUE);
|
||
}
|
||
}
|
||
|
||
|
||
near RulerStateFromPt(pt, prlc, pbtn)
|
||
POINT pt;
|
||
int *prlc;
|
||
int *pbtn;
|
||
{
|
||
/* This routine return in *prlc and *pbtn, the button group and the button
|
||
at point pt. The only button in group rlcRULER is btnNIL. */
|
||
|
||
int btn;
|
||
|
||
/* First check if the point is in a button. */
|
||
for (btn = btnMIN; btn < btnMaxUsed; btn++)
|
||
{
|
||
if (PtInRect((LPRECT)&rgrcRulerBtn[btn], pt))
|
||
{
|
||
goto ButtonFound;
|
||
}
|
||
}
|
||
|
||
/* The point is either on the tab ruler or nowhere of any interest. */
|
||
*prlc = (pt.y >= dypRuler - dypMark - 2 && pt.x > xpSelBar - (dxpMark >> 1)
|
||
&& pt.x < dxpRuler + (dxpMark >> 1)) ? rlcRULER : rlcNIL;
|
||
*pbtn = btnNIL;
|
||
return;
|
||
|
||
ButtonFound:
|
||
/* The point is in a button, we just have to decide which button group. */
|
||
switch (btn)
|
||
{
|
||
case btnLTAB:
|
||
case btnDTAB:
|
||
*prlc = rlcTAB;
|
||
break;
|
||
|
||
case btnSINGLE:
|
||
case btnSP15:
|
||
case btnDOUBLE:
|
||
*prlc = rlcSPACE;
|
||
break;
|
||
|
||
case btnLEFT:
|
||
case btnCENTER:
|
||
case btnRIGHT:
|
||
case btnJUST:
|
||
*prlc = rlcJUST;
|
||
break;
|
||
}
|
||
*pbtn = btn;
|
||
}
|
||
|
||
|
||
void near HighlightButton(fOn, btn)
|
||
BOOL fOn; /* true if we should highlight this button, false = unhighlight */
|
||
int btn;
|
||
{
|
||
register PRECT prc = &rgrcRulerBtn[btn];
|
||
int dxpBtn = prc->right - prc->left;
|
||
|
||
/* If we're highlighting, then get the black-on-white button from
|
||
the right group; otherwise copy the white-on-black button ..pt */
|
||
int btnFromBM = btn - btnMIN + (fOn ? btnMaxReal : 0);
|
||
|
||
/* Ensure that we have the bitmap for the buttons. */
|
||
if (SelectObject(hMDCBitmap, hbmBtn) == NULL)
|
||
{
|
||
if ((hbmBtn = LoadBitmap(hMmwModInstance, MAKEINTRESOURCE(idBmBtns+viBmRuler))) ==
|
||
NULL || SelectObject(hMDCBitmap, hbmBtn) == NULL)
|
||
{
|
||
WinFailure();
|
||
goto NoBtns;
|
||
}
|
||
}
|
||
|
||
BitBlt(vhDCRuler, prc->left, prc->top, dxpBtn, prc->bottom - prc->top,
|
||
hMDCBitmap, btnFromBM * dxpBtn, 0, SRCCOPY);
|
||
|
||
SelectObject(hMDCBitmap, hbmNullRuler);
|
||
NoBtns:;
|
||
}
|
||
|
||
|
||
near UpdateRulerBtn(rlc, btn)
|
||
int rlc;
|
||
int btn;
|
||
{
|
||
/* This routine turns off the currently selected button in button group rlc
|
||
and turns on button btn. It is assumed that rlc is neither rlcNIL nor
|
||
rlcRULER, since neither group has buttons to update. */
|
||
|
||
int *pbtnOld = &mprlcbtnDown[rlc];
|
||
int btnOld = *pbtnOld;
|
||
|
||
Assert(rlc != rlcNIL && rlc != rlcRULER);
|
||
|
||
/* If the button hasn't changed, then there is nothing to do. */
|
||
if (btn != btnOld)
|
||
{
|
||
if (vhDCRuler != NULL)
|
||
{
|
||
/* Invert the old button (back to normal), and then invert the new
|
||
button. */
|
||
if (btnOld != btnNIL)
|
||
{
|
||
/* If there is no old button, then, of course, we can't invert
|
||
it. */
|
||
HighlightButton(fFalse, btnOld);
|
||
}
|
||
|
||
if (btn != btnNIL)
|
||
{
|
||
/* If the new button is not btnNIL, then invert it. */
|
||
HighlightButton(fTrue, btn);
|
||
}
|
||
}
|
||
|
||
/* Record whic button is now set. */
|
||
*pbtnOld = btn;
|
||
}
|
||
}
|
||
|
||
#ifdef KINTL
|
||
/* Given xa for a mouse position in a ruler, return the amount of xa for
|
||
a display adjustment. */
|
||
unsigned near XaKickBackXa(xa)
|
||
unsigned xa;
|
||
{
|
||
extern int utCur;
|
||
extern int dxaAdjustPerCm;
|
||
int cCm, cCh;
|
||
|
||
switch (utCur) {
|
||
case utCm:
|
||
cCm = xa / czaCm;
|
||
return (dxaAdjustPerCm * cCm);
|
||
case utInch:
|
||
return (0);
|
||
default:
|
||
Assert(FALSE);
|
||
return (0);
|
||
}
|
||
}
|
||
|
||
near XpKickBackXp(xp)
|
||
int xp;
|
||
{
|
||
/* Computes the amount of a necessary kick-back in xp, if
|
||
a ruler marker is to be drawn at a given xp. */
|
||
extern int utCur;
|
||
extern int dxaAdjustPerCm;
|
||
|
||
int cCm, cCh;
|
||
|
||
switch (utCur) {
|
||
case utInch:
|
||
return 0;
|
||
case utCm:
|
||
/* For every cm, we are off by dxaAdjustPerCm twips. */
|
||
cCm = (xp - xpSelBar + xpMinCur + (dxpMark >> 1)) / dxpLogCm;
|
||
return (MultDiv(dxaAdjustPerCm * cCm, dxpLogInch, czaInch));
|
||
default:
|
||
Assert(FALSE);
|
||
return 0;
|
||
}
|
||
}
|
||
#endif /* ifdef KINTL */
|
||
|
||
|
||
near MergeRulerMark(rmk, xpMark, fHighlight)
|
||
int rmk;
|
||
int xpMark;
|
||
BOOL fHighlight;
|
||
{
|
||
/* This routine merges the ruler mark, rmk, with the contents of the ruler
|
||
bar at xpMark. To accomodate color, the merging of the mark with the
|
||
background must be done first in a monochrome memory bitmap, then converted
|
||
back to color. The mark is highlighed if fHighlight is set. */
|
||
|
||
int ypMark = dypRuler - dypMark - 1;
|
||
|
||
/* Ensure that we have the bitmap for the ruler marks. */
|
||
if (SelectObject(hMDCBitmap, hbmMark) == NULL)
|
||
{
|
||
if ((hbmMark = LoadBitmap(hMmwModInstance, MAKEINTRESOURCE(idBmMarks+viBmRuler))) == NULL
|
||
|| SelectObject(hMDCBitmap, hbmMark) == NULL)
|
||
{
|
||
WinFailure();
|
||
return;
|
||
}
|
||
}
|
||
|
||
#ifdef KINTL
|
||
/* Adjust for the kick back */
|
||
xpMark += XpKickBackXp(xpMark);
|
||
#endif /* ifdef KINTL */
|
||
|
||
/* Merge the mark into the monochrome bitmap. */
|
||
BitBlt(hMDCScreen, xpMark, 0, dxpMark, dypMark, hMDCBitmap, (rmk - rmkMIN) *
|
||
dxpMark, 0, MERGEMARK);
|
||
|
||
/* Display the bitmap on the ruler bar. */
|
||
BitBlt(vhDCRuler, xpMark, ypMark, dxpMark, dypMark, hMDCScreen, xpMark, 0,
|
||
fHighlight ? NOTSRCCOPY : SRCCOPY);
|
||
|
||
SelectObject(hMDCBitmap, hbmNullRuler);
|
||
}
|
||
|
||
|
||
BOOL near FPointNear(xaTarget, xaProbe)
|
||
unsigned xaTarget;
|
||
unsigned xaProbe;
|
||
{
|
||
/* This routine returns TRUE if and only if xaProbe is sufficiently close to
|
||
xaTarget for selection purposes. */
|
||
|
||
int dxa;
|
||
|
||
if ((dxa = xaTarget - xaProbe) < 0)
|
||
{
|
||
dxa = -dxa;
|
||
}
|
||
return (dxa < MultDiv(dxpMark, czaInch, dxpLogInch) >> 1);
|
||
}
|
||
|
||
|
||
unsigned near XaQuantize(xp)
|
||
int xp;
|
||
{
|
||
#ifdef KINTL
|
||
/* This routine converts an x-coordinate from the ruler to twips
|
||
rounding it to the nearest sixteenth of an inch if utCur = utInch,
|
||
or to the nearest eighth of a centimeter if utCur = utCm. */
|
||
unsigned xa = MultDiv(xp - xpSelBar + xpMinCur, czaInch, dxpLogInch);
|
||
return (XaQuantizeXa(xa));
|
||
#else
|
||
/* This routine converts an x-coordinate from the ruler to twips rounding it
|
||
to the nearest sixteenth of an inch. */
|
||
|
||
unsigned xa = MultDiv(xp - xpSelBar + xpMinCur, czaInch, dxpLogInch);
|
||
|
||
/* NOTE: This code has been simplified because we "know" czaInch is a
|
||
multiple of 32. */
|
||
return ((xa + czaInch / 32) / (czaInch / 16) * (czaInch / 16));
|
||
#endif /* not KINTL */
|
||
}
|
||
|
||
#ifdef KINTL
|
||
unsigned near XaQuantizeXa(xa)
|
||
unsigned xa;
|
||
{
|
||
extern int utCur;
|
||
long xaL;
|
||
|
||
switch (utCur) {
|
||
case utInch:
|
||
/* NOTE: This code has been simplified because we "know" czaInch is a
|
||
multiple of 32. */
|
||
return ((xa + czaInch / 32) / (czaInch / 16) * (czaInch / 16));
|
||
case utCm:
|
||
/* NOTE: Actually, we are calculating:
|
||
(xa + czaCm / 16) / (czaCm / 8) * (czaCm / 8)
|
||
but calculated in 16*twips, so that there will
|
||
be the least rounding error. */
|
||
xaL = ((long) xa) << 4;
|
||
xaL = (xaL + czaCm) / (czaCm << 1) * (czaCm << 1);
|
||
/* Kick back is adjusted in MergeRulerMark. */
|
||
return ((unsigned) (xaL >> 4));
|
||
default:
|
||
Assert(FALSE);
|
||
return (xa); /* Heck, it's better than nothing. */
|
||
}
|
||
}
|
||
#endif /* KINTL */
|
||
|
||
|
||
near DeleteRulerTab(ptbd)
|
||
struct TBD *ptbd;
|
||
{
|
||
/* This routine removes the tab at ptbd from its table. */
|
||
|
||
vfTabsChanged = TRUE;
|
||
do
|
||
{
|
||
*ptbd = *(ptbd + 1);
|
||
}
|
||
while ((ptbd++)->dxa != 0);
|
||
}
|
||
|
||
|
||
near InsertRulerTab(ptbd)
|
||
struct TBD *ptbd;
|
||
{
|
||
/* This routine inserts the tab *ptbd into rgtbdRuler unless there is one
|
||
close to it already. */
|
||
|
||
register struct TBD *ptbdT;
|
||
unsigned dxa = ptbd->dxa;
|
||
unsigned dxaT;
|
||
|
||
/* Search the table for a tab that is close to the tab to be inserted. */
|
||
for (ptbdT = &rgtbdRuler[0]; ptbdT->dxa != 0; ptbdT++)
|
||
{
|
||
if (FCloseXa(ptbdT->dxa, dxa))
|
||
{
|
||
/* Overwrite the old tab iff the tab has changed. */
|
||
if (ptbdT->jc != ptbd->jc)
|
||
{
|
||
*ptbdT = *ptbd;
|
||
vfTabsChanged = TRUE;
|
||
}
|
||
|
||
/* Clean up the ruler and exit. */
|
||
RulerPaint(TRUE, FALSE, TRUE);
|
||
return;
|
||
}
|
||
}
|
||
|
||
vfTabsChanged = TRUE;
|
||
|
||
/* Insert the tab at the correctly sorted place. */
|
||
for (ptbdT = &rgtbdRuler[0]; (dxaT = ptbdT->dxa) != 0; ptbdT++)
|
||
{
|
||
if (dxa <= dxaT)
|
||
{
|
||
/* Insert the tab in front of ptbdT and move the remaining tabs up
|
||
one slot. The last tab will be overwritten to avoid table overflow.
|
||
*/
|
||
blt(ptbdT, ptbdT + 1, ((&rgtbdRuler[0] - ptbdT) + (itbdMax - 2)) *
|
||
cwTBD);
|
||
*ptbdT = *ptbd;
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* Insert the tab at the end of the table unless the table is full. */
|
||
if (ptbdT - &rgtbdRuler[0] < itbdMax - 1)
|
||
{
|
||
*ptbdT = *ptbd;
|
||
(ptbdT + 1)->dxa = 0;
|
||
}
|
||
}
|
||
|
||
|
||
BOOL near FCloseXa(xa1, xa2)
|
||
unsigned xa1;
|
||
unsigned xa2;
|
||
{
|
||
#ifdef KINTL
|
||
/* This function returns TRUE if xa1 is "close" to xa2;
|
||
FALSE otherwise. Threshold is determined by utCur. */
|
||
int dxa;
|
||
int dxaThreshold;
|
||
|
||
extern int utCur;
|
||
|
||
if ((dxa = xa1 - xa2) < 0)
|
||
{
|
||
dxa = -dxa;
|
||
}
|
||
switch (utCur) {
|
||
case utInch:
|
||
dxaThreshold = czaInch / 16;
|
||
break;
|
||
case utCm:
|
||
dxaThreshold = czaCm / 8;
|
||
break;
|
||
default:
|
||
Assert(FALSE);
|
||
dxaThreshold = 0; /* Heck. It doesn't matter at this point. */
|
||
break;
|
||
}
|
||
return (dxa < dxaThreshold);
|
||
#else /* not KINTL */
|
||
/* This function returns TRUE if xa1 is "close" to xa2; FALSE otherwise. */
|
||
|
||
int dxa;
|
||
|
||
if ((dxa = xa1 - xa2) < 0)
|
||
{
|
||
dxa = -dxa;
|
||
}
|
||
return (dxa < czaInch / 16);
|
||
#endif /* not KINTL */
|
||
}
|
||
|
||
|
||
|
||
#ifdef DEBUG
|
||
RulerMarquee()
|
||
{
|
||
/* This routine displays and scrolls the "marquee" message in the ruler mark
|
||
area. */
|
||
|
||
static CHAR szMarquee[] = "Dz}w|d`3Dazgv3{r`3qvv}3qa|ft{g3g|3j|f3qj3Q|q?3Q|q?3Qajr}?3P{z>P{fv}?3r}w3Crg";
|
||
LOGFONT lf;
|
||
HFONT hf;
|
||
HFONT hfOld;
|
||
|
||
/* Decode the marquee message. */
|
||
if (szMarquee[0] == 'D')
|
||
{
|
||
int ich;
|
||
|
||
for (ich = 0; ich < sizeof(szMarquee) - 1; ich++)
|
||
{
|
||
szMarquee[ich] ^= 0x13;
|
||
}
|
||
}
|
||
|
||
/* Get a logical font that will fit in the ruler mark area. */
|
||
bltbc(&lf, 0, sizeof(LOGFONT));
|
||
lf.lfHeight = -dypMark;
|
||
lf.lfPitchAndFamily = FIXED_PITCH;
|
||
|
||
/* Can we create such a font. */
|
||
if ((hf = CreateFontIndirect(&lf)) != NULL)
|
||
{
|
||
if ((hfOld = SelectObject(vhDCRuler, hf)) != NULL)
|
||
{
|
||
int xp;
|
||
int yp = dypRuler - dypMark - 1;
|
||
int dxp = LOWORD(GetTextExtent(vhDCRuler, (LPSTR)szMarquee,
|
||
sizeof(szMarquee) - 1));
|
||
int dxpScroll = MultDiv(GetSystemMetrics(SM_CXSCREEN), dypMark,
|
||
2048);
|
||
int iLevel;
|
||
TEXTMETRIC tm;
|
||
|
||
/* Erase what is in the ruler mark area. */
|
||
PatBlt(vhDCRuler, 0, yp, dxpRuler, dypMark, ropErase);
|
||
|
||
/* Scroll the marquee across the screen. */
|
||
iLevel = SaveDC(vhDCRuler);
|
||
IntersectClipRect(vhDCRuler, xpSelBar, yp, dxpRuler, dypRuler - 1);
|
||
GetTextMetrics(vhDCRuler, (LPTEXTMETRIC)&tm);
|
||
for (xp = dxpRuler; xp > xpSelBar - dxp; xp -= dxpScroll)
|
||
{
|
||
BitBlt(vhDCRuler, xp, yp, min(dxpRuler - (xp + dxpScroll), dxp),
|
||
dypMark, vhDCRuler, xp + dxpScroll, yp, SRCCOPY);
|
||
PatBlt(vhDCRuler, min(dxpRuler - dxpScroll, xp + dxp), yp,
|
||
dxpScroll, dypMark, ropErase);
|
||
if (xp + dxp >= dxpRuler)
|
||
{
|
||
int dxpch = (dxpRuler - xp) % tm.tmAveCharWidth;
|
||
int ich = (dxpRuler - xp) / tm.tmAveCharWidth;
|
||
|
||
if (dxpch == 0 && xp < dxpRuler)
|
||
{
|
||
dxpch = tm.tmAveCharWidth;
|
||
ich--;
|
||
}
|
||
TextOut(vhDCRuler, dxpRuler - dxpch, yp -
|
||
tm.tmInternalLeading, (LPSTR)&szMarquee[ich], 1);
|
||
}
|
||
}
|
||
RestoreDC(vhDCRuler, iLevel);
|
||
|
||
/* Cleanup the font and the screen. */
|
||
SelectObject(vhDCRuler, hfOld);
|
||
RulerPaint(TRUE, FALSE, TRUE);
|
||
}
|
||
DeleteObject(hf);
|
||
}
|
||
}
|
||
#endif
|
||
|