Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

548 lines
16 KiB

/*****************************************************************************
*
* frextern.c
* Copyright (C) Microsoft Corporation 1990.
* All Rights reserved.
*
******************************************************************************
*
* This file contains many of the API routines for the Help 3.0 layout
* manager.
*
* The layout manager handles the layout and display of text and other
* objects within a rectangle. It provides calls for creating, manipulating,
* and displaying the layout within that rectangle. It relies heavily on the
* FC manager, and on the Help layer.
*
* The layout manager maintains a number of variables within the DE:
* INT wLayoutMagic; This is set to wLayMagicValue when the layout
* manager is started, and is cleared when it is
* discarded.
* MLI mli; This contains a number of layout flags, all of
* which are handled by the layout code.
* INT xScrolled; Handled by layout code.
* INT xScrollMax; Handled by layout code.
* MRD mrdFCM; MRD containing FCMs for the current layout.
* Created when the DE is initialized by the layout
* manager, destroyed when it is deinitialized.
* MR mrFr; MR used for storing FRs during layout. Each FC
* builds its FRs in this space, and then transfers
* them to a new block of memory. The mrFr is built
* and discarded with the layout manager.
* MRD mrdHot; MRD used for storing a list of all current MHIs
* (used for keeping track of hotspots). This MRD is
* allocated and discarded with the layout manager.
* INT imhiSelected; imhi of the currently selected hotspot. FOO_NIL
* if no hotspot is currently selected.
* INT imhiHit; imhi of the last activated hotspot. Used for
* calculating the size of a glossary window.
* DWORD lHotID; Seed number for uniquely identifying hotspots.
* Set to 0 when the layout manager is initialized.
*
*****************************************************************************/
#include "help.h"
#pragma hdrstop
_subsystem (frame);
#include "inc\frstuff.h"
static int STDCALL IcursTrackFC(QFCM qfcm, POINT pt);
static void STDCALL HitHotspot(QDE qde, int imhi);
INLINE static void STDCALL VerifyHotspot(QDE qde);
INLINE int STDCALL IcursTrackText(QFR qfr);
/*-------------------------------------------------------------------------
| FInitLayout(qde) |
| |
| Purpose: This initializes the layout manager for a DE. It must be |
| called before any other layout manager routines are called. |
-------------------------------------------------------------------------*/
BOOL STDCALL FInitLayout(QDE qde)
{
#if defined(_DEBUG)
qde->wLayoutMagic = wLayMagicValue;
#endif
InitMRD((QMRD) &qde->mrdFCM, sizeof(FCM));
InitMR((QMR) &qde->mrFr, sizeof(FR));
InitMR((QMR) &qde->mrTWS, sizeof(TWS));
InitMRD((QMRD) &qde->mrdHot, sizeof(MHI));
InitMRD((QMRD) &qde->mrdLSM, sizeof(LSM));
qde->wStyleTM = wStyleNil;
qde->lHotID = 0;
qde->xScrolled = 0;
qde->xScrollMax = 0;
qde->xScrollMaxSoFar = 0;
qde->fSelectionFlags = 0;
qde->imhiSelected = FOO_NIL;
qde->imhiHit = FOO_NIL;
qde->vaStartMark.dword = vaNil;
qde->vaEndMark.dword = vaNil;
qde->lichStartMark = -1;
qde->lichEndMark = -1;
return(TRUE);
}
/*-------------------------------------------------------------------------
| DptScrollLayout(qde, dpt) |
| |
| Purpose: This routine performs a logical scroll of the layout area. |
| It does not perform a screen scroll, nor does it generate a |
| draw even for the affected region. |
-------------------------------------------------------------------------*/
POINT STDCALL DptScrollLayout(QDE qde, POINT dpt)
{
POINT ptReturn;
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom)
{
ptReturn.x = ptReturn.y = 0;
return(ptReturn);
}
AccessMRD(((QMRD)&qde->mrdFCM));
AccessMRD(((QMRD)&qde->mrdLSM));
qde->wStyleDraw = wStyleNil;
ptReturn.x = ptReturn.y = 0;
if (dpt.y != 0)
{
ptReturn.y = DyFinishLayout(qde, dpt.y, FALSE);
VerifyHotspot(qde);
}
if (dpt.x != 0)
{
if (qde->xScrolled > qde->xScrollMax)
{
ptReturn.x = qde->xScrolled - qde->xScrollMax;
qde->xScrolled = qde->xScrollMax;
}
if (dpt.x > 0) /* Horizontal scroll left */
{
ptReturn.x += min(qde->xScrolled, dpt.x);
qde->xScrolled = max(0, qde->xScrolled - dpt.x);
}
else { // Horizontal scroll right
ptReturn.x -= min(qde->xScrollMax - qde->xScrolled, -dpt.x);
qde->xScrolled = min(qde->xScrollMax, qde->xScrolled - dpt.x);
}
}
ReviseScrollBar(qde);
#ifdef UNIMPLEMENTED
/* This is a layout routine which sees if there are next and previous
* hidden matches in the current topic. We keep a browse state table:
* Match Next, Match Prev, Topic Next, Topic Prev
* Topic flags are updated upon any topic jump. We check if there
* are any hits in the topic. If so, we update the internal cursor
* pos to point to this topic in the hit list.
* Topic Next implies Match Next, Topic Prev implies Match Prev
* else we must look closer.
*/
#endif
DeAccessMRD(((QMRD)&qde->mrdLSM));
DeAccessMRD(((QMRD)&qde->mrdFCM));
return(ptReturn);
}
/*-------------------------------------------------------------------------
| DrawLayout(qde, qrctTarget) |
| |
| Purpose: DrawLayout renders the current layout. |
| Params: qrctTarget: This should point to the smallest rectangle |
| to render. It is used only for speed- the |
| caller must handle any desired clipping. |
-------------------------------------------------------------------------*/
void STDCALL DrawLayout(QDE qde, LPRECT qrctTarget)
{
IFCM ifcm;
QFCM qfcm;
POINT pt;
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom)
return;
AccessMRD(((QMRD)&qde->mrdFCM));
AccessMRD(((QMRD)&qde->mrdLSM));
qde->wStyleDraw = wStyleNil;
pt.x = qde->rct.left - qde->xScrolled;
pt.y = qde->rct.top;
for (ifcm = IFooFirstMRD(((QMRD)&qde->mrdFCM)); ifcm != FOO_NIL;
ifcm = IFooNextMRD(((QMRD) &qde->mrdFCM), sizeof(FCM), ifcm)) {
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), ifcm);
DrawIfcm(qde, ifcm, pt, qrctTarget, 0, qfcm->cfr, FALSE);
}
/*
* gross ugly bug #1173 hack After drawing the layout is complete, we
* report back to the results dialog whether we saw the first or last
* search hit which determines whether to disable the next or prev
* buttons.
*/
#ifdef RAWHIDE
if (qde->deType != dePrint)
ResultsButtonsEnd(qde);
#endif
}
/*-------------------------------------------------------------------------
| IcursTrackLayout(qde, pt) |
| |
| Purpose: Find the appropriate shape for the cursor when it's over the |
| layout area. |
| Returns: icurs corresponding to the appropriate cursor shape, or |
| icurNil if the cursor is outside the layout area. |
| Method: -Return icurNil if the cursor is outside the layout area. |
| -Find the FC under the cursor |
| -Call IcursTrackFC to determine the appropriate shape. |
-------------------------------------------------------------------------*/
int STDCALL IcursTrackLayout(QDE qde, POINT pt)
{
IFCM ifcm;
QFCM qfcm;
int icurReturn;
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom)
return(icurARROW);
if (!PtInRect(&qde->rct, pt))
return(icurNil);
AccessMRD(((QMRD) &qde->mrdFCM));
pt.x -= (qde->rct.left - qde->xScrolled);
pt.y -= qde->rct.top;
for (ifcm = IFooFirstMRD(((QMRD) &qde->mrdFCM)); ifcm != FOO_NIL;
ifcm = IFooNextMRD(((QMRD) &qde->mrdFCM), sizeof(FCM), ifcm)) {
qfcm = (QFCM) QFooInMRD(((QMRD) &qde->mrdFCM), sizeof(FCM), ifcm);
if (pt.y >= qfcm->yPos && pt.y <= qfcm->yPos + qfcm->dySize) {
// BUGBUG: IcursTrackFC expects a QDE not a QFCM
if ((icurReturn = IcursTrackFC(qfcm, pt)) != icurNil) {
DeAccessMRD(((QMRD) &qde->mrdFCM));
return icurReturn;
}
DeAccessMRD(((QMRD) &qde->mrdFCM));
return(icurARROW);
}
}
DeAccessMRD(((QMRD) &qde->mrdFCM));
return icurARROW;
}
/*-------------------------------------------------------------------------
| IcursTrackFC(qfcm, pt) |
| |
| Purpose: return the cursor shape appropriate to the current mouse |
| position. |
| Params: pt Offset between FC space and display space. |
-------------------------------------------------------------------------*/
static int STDCALL IcursTrackFC( QFCM qfcm, PT pt)
{
QFR qfr;
int xNew, yNew, ifr;
ASSERT(!qfcm->fExport);
qfr = (QFR) PtrFromGh(qfcm->hfr);
xNew = pt.x - qfcm->xPos;
yNew = pt.y - qfcm->yPos;
for (ifr = 0; ifr < qfcm->cfr; ifr++, qfr++) {
if (qfr->rgf.fHot && xNew >= qfr->xPos && xNew <= qfr->xPos + qfr->dxSize
&& yNew >= qfr->yPos && yNew <= qfr->yPos + qfr->dySize) {
switch(qfr->bType) {
case bFrTypeText:
return(IcursTrackText(qfr));
case bFrTypeAnno:
case bFrTypeBitmap:
case bFrTypeHotspot:
return(icurHAND);
#ifdef _DEBUG
default:
ASSERT(FALSE);
#endif
}
}
}
return(icurNil);
}
INLINE int STDCALL IcursTrackText(QFR qfr)
{
if (qfr->libHotBinding == libHotNil)
return(icurARROW);
return(icurHAND);
}
/*-------------------------------------------------------------------------
| ClickLayout(qde, pt) |
| |
| Purpose: Handle the effects of a mouse click on the layout area. |
-------------------------------------------------------------------------*/
BOOL STDCALL ClickLayout(QDE qde, POINT pt)
{
IFCM ifcm;
QFCM qfcm;
BOOL fReturn = FALSE;
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom)
return fReturn;
AccessMRD(((QMRD)&qde->mrdFCM));
qde->wStyleDraw = wStyleNil;
pt.x -= (qde->rct.left - qde->xScrolled);
pt.y -= qde->rct.top;
for (ifcm = IFooFirstMRD(((QMRD)&qde->mrdFCM));
ifcm != FOO_NIL;
ifcm = IFooNextMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), ifcm)) {
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), ifcm);
if (pt.y >= qfcm->yPos && pt.y <= qfcm->yPos + qfcm->dySize) {
fReturn = ClickFC(qde, ifcm, pt);
break;
}
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
return fReturn;
}
/*-------------------------------------------------------------------------
| FHitCurrentHotspot(qde) |
| |
| Purpose: Act as though the currently selected hotspot had been clicked |
| on. If no hotspot is currently selected, the first visible |
| hotspot will be chosen. This will normally be called in |
| response to the return key being pressed- it should optimally |
| be called when the key is released rather than when it is |
| pressed. |
| Returns: TRUE if successful, FALSE if there are no hotspots to hit |
| in this DE. |
-------------------------------------------------------------------------*/
BOOL STDCALL FHitCurrentHotspot(QDE qde)
{
BOOL fRet;
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom)
return FALSE;
AccessMRD(((QMRD)&qde->mrdFCM));
qde->wStyleDraw = wStyleNil;
if (qde->imhiSelected == FOO_NIL) {
fRet = FHiliteNextHotspot(qde, TRUE);
}
else
fRet = TRUE;
if (fRet) {
// Hit, then turn off the currently selected hotspot
HitHotspot(qde, qde->imhiSelected);
FSelectHotspot(qde, FOO_NIL);
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
return(fRet);
}
/*-------------------------------------------------------------------------
| DiscardLayout(qde) |
| |
| Purpose: Discard all memory structures associated with the layout |
| manager. |
-------------------------------------------------------------------------*/
void STDCALL DiscardLayout(QDE qde)
{
ASSERT(qde->wLayoutMagic == wLayMagicValue);
AccessMRD(((QMRD) &qde->mrdFCM));
AccessMRD(((QMRD) &qde->mrdLSM));
FreeLayout(qde);
DeAccessMRD(((QMRD) &qde->mrdLSM));
DeAccessMRD(((QMRD) &qde->mrdFCM));
FreeMRD(((QMRD) &qde->mrdFCM));
FreeMR(((QMR) &qde->mrFr));
FreeMR(((QMR) &qde->mrTWS));
FreeMRD(((QMRD) &qde->mrdHot));
FreeMRD(((QMRD) &qde->mrdLSM));
#if defined(_DEBUG)
qde->wLayoutMagic = wLayMagicValue + 1;
#endif // DEBUG
}
/*-------------------------------------------------------------------------
| PtGetLayoutSize(qde) |
| |
| Purpose: Returns the size of the current layout. Note that this |
| returns only the size of currently loaded FCs. It is |
| intended only for use with pop-up glossary windows, and will |
| return meaningless values for large topics. |
-------------------------------------------------------------------------*/
POINT STDCALL PtGetLayoutSize(QDE qde)
{
IFCM ifcm;
QFCM qfcm;
POINT ptReturn;
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom) {
ptReturn.x = ptReturn.y = 0;
return(ptReturn);
}
AccessMRD(((QMRD)&qde->mrdFCM));
ptReturn.x = ptReturn.y = 0;
for (ifcm = IFooFirstMRD(((QMRD)&qde->mrdFCM)); ifcm != FOO_NIL;
ifcm = IFooNextMRD(((QMRD) &qde->mrdFCM), sizeof(FCM), ifcm)) {
qfcm = (QFCM) QFooInMRD(((QMRD) &qde->mrdFCM), sizeof(FCM), ifcm);
if (qfcm->xPos + qfcm->dxSize > ptReturn.x)
ptReturn.x = qfcm->xPos + qfcm->dxSize;
if (qfcm->yPos + qfcm->dySize > ptReturn.y)
ptReturn.y = qfcm->yPos + qfcm->dySize;
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
return (ptReturn);
}
/*-------------------------------------------------------------------------
| DyCleanLayoutHeight(qde) |
| |
| Purpose: Returns the recommended maximum amount of the current page |
| that should be rendered in order to avoid splitting a line |
| in half. |
| DANGER: The return value of this function is only an approximation. |
| There are certain degenerate cases where the return value may |
| be negative, or unacceptably small. It is up to the caller |
| to identify these cases and handle them appropriately. |
| Method: - Set dyReturn to the current page height |
| - Find the FC which is split by the bottom of the page (if |
| there is one). |
| - Check each frame in this FC to see if it is split by the |
| bottom of the page. If it is, set dyReturn to indicate the |
| top of this frame. |
-------------------------------------------------------------------------*/
int STDCALL DyCleanLayoutHeight(QDE qde)
{
IFCM ifcm;
QFCM qfcm;
QFR qfr;
int dyReturn, ifr, yFrTop, dyMax;
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom)
return 0;
AccessMRD(((QMRD)&qde->mrdFCM));
dyReturn = dyMax = (qde->rct.bottom - qde->rct.top);
for (ifcm = IFooFirstMRD(((QMRD)&qde->mrdFCM)); ifcm != FOO_NIL;
ifcm = IFooNextMRD(((QMRD) &qde->mrdFCM), sizeof(FCM), ifcm)) {
qfcm = (QFCM) QFooInMRD(((QMRD) &qde->mrdFCM), sizeof(FCM), ifcm);
if (qfcm->yPos > dyMax)
break;
if (qfcm->yPos + qfcm->dySize > dyMax) {
qfr = (QFR) PtrFromGh(qfcm->hfr);
for (ifr = 0; ifr < qfcm->cfr; ifr++, qfr++) {
yFrTop = qfcm->yPos + qfr->yPos;
if (yFrTop < dyReturn && yFrTop + qfr->dySize > dyMax)
dyReturn = yFrTop;
}
}
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
return (dyReturn);
}
/*-------------------------------------------------------------------------
| ClickFrame(qde, ifcm, ifr) |
| |
| Purpose: Handles a click on a particular frame |
-------------------------------------------------------------------------*/
void STDCALL ClickFrame(QDE qde, IFCM ifcm, int ifr)
{
QFCM qfcm;
QFR qfr;
TO to;
int imhi;
MHI mhi;
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), ifcm);
qfr = (QFR) PtrFromGh(qfcm->hfr) + ifr;
ASSERT(qfr->rgf.fHot);
AccessMRD(((QMRD)&qde->mrdHot));
for (imhi = IFooFirstMRD(((QMRD)&qde->mrdHot));
imhi != FOO_NIL;
imhi = IFooNextMRD(((QMRD) &qde->mrdHot), sizeof(MHI), imhi)) {
mhi = *((QMHI)QFooInMRD(((QMRD)&qde->mrdHot), sizeof(MHI), imhi));
if (mhi.lHotID == qfr->lHotID)
break;
}
DeAccessMRD(((QMRD)&qde->mrdHot));
ASSERT(imhi != FOO_NIL);
qde->imhiHit = imhi;
// REVIEW: Do we want to deal with window frames?
switch(qfr->bType) {
case bFrTypeText:
ClickText(qde, qfcm, qfr);
break;
case bFrTypeAnno:
to.va = qde->tlp.va;
to.ich = 0L;
JumpButton(&to.ich, bAnnoHotspot, qde);
break;
case bFrTypeBitmap:
ClickBitmap(qde, qfcm, qfr);
break;
case bFrTypeHotspot:
ClickHotspot(qde, qfr);
break;
}
}
static void STDCALL HitHotspot(QDE qde, int imhi)
{
MHI mhi;
if (imhi == FOO_NIL)
return;
AccessMRD(((QMRD)&qde->mrdHot));
mhi = *((QMHI)QFooInMRD(((QMRD)&qde->mrdHot), sizeof(MHI), imhi));
ClickFrame(qde, mhi.ifcm, mhi.ifrFirst);
DeAccessMRD(((QMRD)&qde->mrdHot));
}
INLINE static void STDCALL VerifyHotspot(QDE qde)
{
if (qde->imhiSelected != FOO_NIL) {
if (!FHotspotVisible(qde, qde->imhiSelected))
qde->imhiSelected = FOO_NIL;
}
}