File:  [OS/2 SDKs] / pmsdk / samples / browse / avbrowse / avio.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:28:31 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: pmsdk-1989, HEAD
Microsoft OS/2 SDK PM 02-24-1989

/*
    avio.c -- AVIO action routines

    Implements scrollbars, sets up an AVIO Presentation Space
*/
#define  INCL_AVIO
#define	 INCL_DEV
#define  INCL_VIO
#define  INCL_WINWINDOWMGR
#define  INCL_WINSYS
#define  INCL_WINMESSAGEMGR
#define  INCL_WINTRACKRECT
#define  INCL_WINFRAMEMGR
#define  INCL_WINSCROLLBARS
#include <os2.h>
#include <string.h>	/* One strlen() call in the Blast() macro */
#include "avio.h"	/* Get Avio-prefixed routine prototypes   */
/*
    Constants
*/
char	Blank[2] = { 0x20, 0x07 };	/* <Space> + EGA white attribute */
/*
    Macros to make the code more readable
*/
/* Upper and Lower Bound Calculations */
#define	Abs(a)		(((a) > 0) ? (a) : (-(a)))
#define	Min(a,b)	(((a) < (b)) ? (a) : (b))
#define	Max(a,b)	(((a) > (b)) ? (a) : (b))
#define LowerBound(pos, disp, lbound) Max(pos - disp, lbound)
#define UpperBound(pos, disp, ubound) Min(pos + disp, ubound)

/* Scroll Bar Abbreviations */
#define DisableSB(hSB)	WinSetParent(hSB, HWND_OBJECT, TRUE)
#define EnableSB(hSB) 	WinSetParent(hSB, hWndFrame,   TRUE)
#define SetScroll(h, pos, max) \
    WinSendMsg(h, SBM_SETSCROLLBAR, MPFROM2SHORT(pos, 0), MPFROM2SHORT(0, max))

/* Scrollbar redraw macros */
#define UpdateOn(c, hsb)	if (!(++c)) WinEnableWindowUpdate(hsb, TRUE)
#define UpdateOff(c, hsb)	if (!(c--)) WinEnableWindowUpdate(hsb, FALSE)
#define	UpdateFrame(sb)	\
	WinSendMsg(hWndFrame, WM_UPDATEFRAME, MPFROMLONG(sb), 0L)

/* Scrolling Macros */
#define ClearScreen()	ScrollUp(-1)	/* Scroll up an "infinite" # lines */
#define ScrollDown(n)	VioScrollDn(0, 0, -1, -1, n, Blank, hVPS)
#define ScrollUp(n)	VioScrollUp(0, 0, -1, -1, n, Blank, hVPS)

/* RectL -> SWP conversion macros */
#define	lcx(r)		((r.xRight - r.xLeft) + 1)
#define	lcy(r)		((r.yTop - r.yBottom) + 1)

/* Miscellaneous macros */
#define Blast(l, x, y)	VioWrtCharStr(l, Min(strlen(l), cxChScreen), x, y, hVPS)
#define CalcChars(sPg, sCh) \
    ((sCh) ? (Max(((sPg) / (sCh)), 0)) : 0)
#define	SetCellSize(h,w) VioSetDeviceCellSize(h, w, hVPS)
#define	Value(value)	WinQuerySysValue(HWND_DESKTOP, value)
/*
    File-Local Variables
*/
HDC	hDC;		/* Device Context */
HVPS	hVPS;		/* Virtual PS */
int	iTopLine;	/* PS Line of window corner */
int	iCurCol; 	/* Current column of window corner */
int	cxChPage;	/* Width and height of our window, in characters */
int	cyChPage;
int	iMaxHorz;	/* Scroll bar upper bounds */
int	iMaxVert;	
BOOL	fNeedHorz;	/* Do we need the scroll bars or not? */
BOOL	fNeedVert;
HWND	hWndHorzSB;	/* Window handles of ScrollBar windows */
HWND	hWndVertSB;
extern	HWND	hWndFrame;	/* Client, frame windows */
extern	HWND	hWndClient;
PFNWP	pfnOldClient;	/* Old Client Window Procedure pointer */
PFNWP	pfnOldFrame;	/* Old Frame  Window Procedure pointer */
SHORT	cyChPS;		/* Number of rows in AVIO PS */
SHORT	cxChPS;		/* Number of cols in AVIO PS */
SHORT	cyChScreen;		/* Number of rows in display space */
SHORT	cxChScreen;		/* Number of cols in display space */
PFNQL	pfnQueryLine;
/*
    Measurements used to help make the window look nice
*/
LONG	cxConstant, cyConstant;			/* Miscellaneous frame lens */
int	cxMaxFrame, cyMaxFrame;			/* Maximum frame widths */
LONG	lChWidth,   lChHeight;
SHORT	cxMaxClient, cyMaxClient;		/* Client area bounds  */
BOOL	fCreatedPS;				/* AVIO PS created */
int	cHUpdate = -1;				/* Keep track of updates */
int	cVUpdate = -1;
/*
   Local prototypes
*/
void FixScroll(BOOL, BOOL, HWND, ULONG, int *, int, int *);
void UpdateScrollBars(RECTL);
void Refresh(void);
void Update(USHORT, USHORT, USHORT);
/*
    The actual routines
*/
void AvioInit(PLBINFO plbi) {
/*
    Initialize Presentation Space, Device Context, Scroll Bars
*/
    VIOCURSORINFO vci;
    /*
	Initialize the line buffer info 
    */
    cyChScreen	= plbi->sRows;
    cxChScreen	= plbi->sCols;
    cyChPS	= plbi->sPSrows;
    cxChPS	= plbi->sPScols;
    pfnQueryLine = plbi->pfnQL;
    /*
	One Time Initializations...
    */
    if (!fCreatedPS) {
	/*
	   Create the AVIO Presentation Space, with one attribute byte
	*/
	hDC = WinOpenWindowDC(hWndClient);	/* Open the device context */
	VioCreatePS(&hVPS, cyChPS, cxChPS + 1, 0, 1, 0);
	VioAssociate(hDC, hVPS);		/* Link the PS with the DC */
	/*
	    Turn off the cursor (set invisible attribute)
	*/
	VioGetCurType(&vci, hVPS);
	vci.attr = -1;
	VioSetCurType(&vci, hVPS);
	/*
	    Measure the frame components
	*/
	cxConstant = 0;
	cyConstant = Value(SV_CYTITLEBAR) + Value(SV_CYMENU);
        /*
	    Snag scroll bar info
	*/
	hWndHorzSB	= WinWindowFromID(hWndFrame,  FID_HORZSCROLL);
	hWndVertSB	= WinWindowFromID(hWndFrame,  FID_VERTSCROLL);
	fNeedHorz	= fNeedVert	= TRUE;
	/*
	    Setup the Client and Frame routines
	*/
	pfnOldFrame	= WinSubclassWindow(hWndFrame,  AvioFrameWndProc);
	pfnOldClient	= WinSubclassWindow(hWndClient, AvioClientWndProc);
	fCreatedPS	= TRUE;
    }
    /*
	Repaint the screen
    */
    iTopLine = iCurCol = 0;
    AvioStartup(plbi->fLargeFont);
}

void AvioStartup(BOOL fLargeFont) {
/*
    Clear the screen, set the font, redraw the area
*/
    RECTL rclFrame;

    ClearScreen();
    AvioLargeFont(fLargeFont);
    WinQueryWindowRect(hWndFrame, &rclFrame);
    UpdateScrollBars(rclFrame);
    Update(0, cyChPS, 0);
}

void AvioScroll(USHORT SB_Command, USHORT Position, BOOL Horizontal) {
/*
    Process the scroll bar messages

    These routines are symmetric; in fact, SB_LINELEFT = SB_LINEUP, etc...
    so one might note that this could be condensed.  It's left expanded for
    speed and clarity.  The scrollbar values are bounded to stay inside
    the Presentation Space.
*/
    if (Horizontal) {  /* Horizontal Scroll Bar */
	switch (SB_Command) {
	    case SB_LINELEFT:
		iCurCol = LowerBound(iCurCol, 1, 0); break;
	    case SB_LINERIGHT:
		iCurCol = UpperBound(iCurCol, 1, iMaxHorz); break;
	    case SB_PAGELEFT:
		iCurCol = LowerBound(iCurCol, cxChPage, 0); break;
	    case SB_PAGERIGHT:
		iCurCol = UpperBound(iCurCol, cxChPage, iMaxHorz); break;
	    case SB_SLIDERTRACK:
		iCurCol = (SHORT) Position;
	    default: break;
	}
	if (SB_Command != SB_SLIDERTRACK)
	    SetScroll(hWndHorzSB, iCurCol, iMaxHorz);

    } else { /* Vertical Scroll Bar */
	switch (SB_Command) {
	    case SB_LINEUP:
		iTopLine = LowerBound(iTopLine, 1, 0); break;
	    case SB_LINEDOWN:
		iTopLine = UpperBound(iTopLine, 1, iMaxVert); break;
	    case SB_PAGEUP:
		iTopLine = LowerBound(iTopLine, cyChPage, 0); break;
	    case SB_PAGEDOWN:
		iTopLine = UpperBound(iTopLine, cyChPage, iMaxVert);break;
	    case SB_SLIDERTRACK:
		iTopLine = (SHORT) Position;
	    default: break;
	}
	if (SB_Command != SB_SLIDERTRACK)
	    SetScroll(hWndVertSB, iTopLine, iMaxVert);
    }
    Refresh();
}

MRESULT AvioSize(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2) {
/*
    Do the default AVIO sizing, and kyfe a few values
*/
    RECTL rclFrame;

    if (!fCreatedPS) return 0L;
    /*
	Update the scroll bars, and the screen
    */
    WinQueryWindowRect(hWndFrame, &rclFrame);
    UpdateScrollBars(rclFrame);
    /*
	Now, do the normal AVIO processing
    */
    return WinDefAVioWindowProc(hWnd, msg, mp1, mp2);
}

void Update(USHORT usLineNum, USHORT usHowMany, USHORT usStartLine) {
/*
    Updates N lines starting from START line on screen.
    Starts at saved line LINENUM.
*/
    USHORT	i;				/* Loop index variable */
    USHORT	usWhichLine = usLineNum;	/* Line number to be queried */
    char	*szLine;

    for (i = usStartLine; i < (usStartLine + usHowMany); i++) {
	szLine = (*pfnQueryLine)(usWhichLine++);	/* Get the line */
	if (szLine) Blast(szLine, i, 0);		/* Print it out */
    }
}

void Refresh(void) {
/*
    Do the origin shifting and screen updating
*/
    SHORT  Delta;
    int static iOldTopLine = 0;

    VioSetOrg(0, iCurCol, hVPS); /* Get the free AVIO horizontal shift */
    Delta = iTopLine - iOldTopLine; /* Compute vertical shift */
    if (Abs(Delta) < cyChPS) {
	if (Delta < 0) { 	/* Scroll Up -- make Delta positive*/
	    ScrollDown(-Delta);
	    Update(iTopLine, -Delta, 0);
	} else {		/* Scroll Down by Delta */
	    ScrollUp(Delta);
	    Update(iTopLine + cyChPS - Delta, Delta, cyChPS - Delta);
	}
    } else AvioRedraw();	/* Redo the entire screen */
    iOldTopLine = iTopLine;
}

void AvioClose(void) {
/*
    Termination routines
*/
    /*
	Destroy the Presentation Space
    */
    VioAssociate(NULL, hVPS);
    VioDestroyPS(hVPS);
    fCreatedPS = FALSE;
}

void AvioPaint(HWND hWnd) {
/*
    Paint the AVIO presentation space by telling it to show itself.
    A possible optimization here is to repaint only the update region.
*/
    static HPS	 hPS;
    static RECTL RectL;

    hPS = WinBeginPaint(hWnd, (HPS) NULL, &RectL);
    VioShowPS(cyChPS, cxChPS, 0, hVPS);
    WinEndPaint(hPS);
} 

MRESULT AvioMinMax(PSWP pSWP) {
/*
    Handle WM_MINMAX messages, to make sure frame doesn't get too big
*/
    if (pSWP->fs & (SWP_MAXIMIZE | SWP_RESTORE)) {
	if (pSWP->fs & SWP_MAXIMIZE) {
	    /*
		Save cx, cy values for later origin displacement
	    */
	    int Oldcx = pSWP->cx;
	    int Oldcy = pSWP->cy;
	    /*
		Displace, and change to maximum size
	    */
	    pSWP->x += (Oldcx -
		(pSWP->cx = cxMaxFrame + (int) (Value(SV_CXSIZEBORDER) << 1)));
	    pSWP->y += (Oldcy -
		(pSWP->cy = cyMaxFrame + (int) (Value(SV_CYSIZEBORDER) << 1)));
	}
	/*
	    Now, fix the scroll bars
	*/
	AvioAdjustFramePos(pSWP);
	return TRUE;
    }
    return FALSE;
}

void AvioClear(void) { ClearScreen(); }

void AvioAdjustFramePos(PSWP pSWP) {
/*
    Trap WM_ADJUSTWINDOWPOS messages to the frame with this routine.
    Keep the window sized right, and control scrollbar visibility.
*/
    RECTL rclFrame;

    if (!(pSWP->cx && pSWP->cy)) return; 	/* Null area... */
    if (pSWP->fs & SWP_MINIMIZE) return;	/* Iconic... */
    /*
	Make sure the dimensions are in range
    */
    pSWP->cx = Min(pSWP->cx, (cxMaxFrame + (SHORT)(Value(SV_CXSIZEBORDER)<<1)));
    pSWP->cy = Min(pSWP->cy, (cyMaxFrame + (SHORT)(Value(SV_CYSIZEBORDER)<<1)));
    /*
	Update the scroll bars
    */
    rclFrame.xLeft	= (LONG) pSWP->x;
    rclFrame.xRight	= (LONG) (pSWP->x + pSWP->cx - 1);
    rclFrame.yBottom	= (LONG) pSWP->y;
    rclFrame.yTop	= (LONG) (pSWP->y + pSWP->cy - 1);
    UpdateScrollBars(rclFrame);

    return; 
}

void AvioTrackFrame(HWND hWnd, MPARAM mpTrackFlags) {
/*
    Takes action on WM_TRACKFRAME message
*/
    static TRACKINFO tiTrackInfo;
    /*
	Get the tracking information in the TrackInfo structure
    */
    WinSendMsg(hWnd, WM_QUERYTRACKINFO, mpTrackFlags, &tiTrackInfo);
    WinTrackRect(hWnd, NULL, &tiTrackInfo);
}

void AvioQueryTrackInfo(PTRACKINFO pTI) {
/*
    Routine which processes WM_QUERYTRACKINFO messages to the frame.
    Call this routine after the default one to change various parameters.

    Note:  In reality, since we have a menu bar, we should make the
    minimum width of the window something such that it does not "fold."
*/
    BOOL fMove;
    /*
	Get the grid set up for byte alignment (unless moving)

	cxGrid is set to half character width so that arrow keys
	will function when sizing (they try to size by half a
	character)
    */
    fMove = ((pTI->fs & TF_MOVE) == TF_MOVE);
    pTI->fs     |= TF_GRID;
    pTI->cxGrid  = (fMove) ? 1 : ((SHORT) (lChWidth >> 1));
    pTI->cyGrid  = (fMove) ? 1 : ((SHORT) lChHeight);
    /*
	Bound the frame.
	Maximum:	Sizing Border, Scrollbars, Title, Menus, client region
    */
    pTI->ptlMaxTrackSize.x = (LONG) (pTI->cxBorder << 1) + (LONG) cxMaxFrame;
    pTI->ptlMaxTrackSize.y = (LONG) (pTI->cyBorder << 1) + (LONG) cyMaxFrame;
}

void AvioRedraw(void) {
/*
    Clear, then redraw the entire Presentation Space
*/
    ClearScreen();
    Update(iTopLine, cyChPS, 0);
}

MRESULT CALLBACK AvioClientWndProc
	(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2) {
/*
     Window Procedure which traps messages to the Client area
*/
     switch (msg) {
	  case WM_PAINT:		/* Paint the AVIO way! */
		AvioPaint(hWnd);
		break;

	  case WM_SIZE:			/* Size the AVIO way!  */
		return AvioSize(hWnd, msg, mp1, mp2);
		break;

	  case WM_HSCROLL:
		AvioScroll(HIUSHORT(mp2), LOUSHORT(mp2), TRUE);
		break;

	  case WM_VSCROLL:
		AvioScroll(HIUSHORT(mp2), LOUSHORT(mp2), FALSE);
		break;

	  case WM_ERASEBACKGROUND:
		break;

	  case WM_TRACKFRAME:
		AvioTrackFrame(hWnd, mp1);
		break;

	  case WM_MINMAXFRAME:		/* Limit Maximized window size */
		AvioMinMax((PSWP) mp1);

		/* fall through */

	  default: return (*pfnOldClient)(hWnd, msg, mp1, mp2);
     }
     return 0;
}

MRESULT CALLBACK AvioFrameWndProc(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2)
/*
    Force the frame to stay small enough (no larger than the PS)
*/
{
    BOOL rc;		/* Return code from WM_QUERYTRACKINFO */

    switch(msg) {
	case WM_ADJUSTWINDOWPOS:	/* Calculate scroll bar adjustments */
	    AvioAdjustFramePos(mp1);
	    break;

	case WM_QUERYTRACKINFO:		/* Get default, then process message */
	    rc = (BOOL) (*pfnOldFrame)(hWnd, msg, mp1, mp2);
            AvioQueryTrackInfo((PTRACKINFO) mp2);
	    return rc;

	default: break;
    }
    return (*pfnOldFrame)(hWnd, msg, mp1, mp2);
}

void UpdateScrollBars(RECTL rclClient) {
/*
    This routine fixes up the scroll bars when the window is resized, or
    when the font size is changed.

    Parameters:	The dimensions of the frame window
    Result:	Updates the scrollbars, enabling/disabling as needed
*/
    BOOL    fNeededHorz = fNeedHorz;  /* Did we need the scrollbars then? */
    BOOL    fNeededVert = fNeedVert;
    /*
	Compute the client rectangle, without the scrollbars
    */
    WinCalcFrameRect(hWndFrame, &rclClient, TRUE);
    /*
	Compute page width -- do we need the horizontal scroll bar?
    */
    cxChPage	 = (int) CalcChars(lcx(rclClient), lChWidth);
    fNeedHorz = ((iMaxHorz = Max(cxChScreen - cxChPage,  0)) > 0);
    /*
	Compute page height -- do we need the vertical scroll bar?
    */
    cyChPage	 = (int) CalcChars(lcy(rclClient), lChHeight);
    fNeedVert = ((iMaxVert = Max(cyChScreen - cyChPage, 0)) > 0);
    /*
	Maintain scrollbar integrity
    */
    iCurCol	= Min(iCurCol, iMaxHorz);
    iTopLine	= Min(iTopLine, iMaxVert);
    /*
	Now, update the scrollbars as necessary
    */
    FixScroll(fNeededHorz, fNeedHorz, hWndHorzSB,
	      FCF_HORZSCROLL, &iCurCol, iMaxHorz, &cHUpdate);

    FixScroll(fNeededVert, fNeedVert, hWndVertSB,
	      FCF_VERTSCROLL, &iTopLine, iMaxVert, &cVUpdate);
    /*
	Now, update the screen to be visually consistent
    */
    Refresh();
}

void FixScroll(fNeeded, fNeed, hWnd, flScroll, piPos, iMax, pc)
/*
    This routine makes the necessary scrollbar adjustments, and
    also enables/disables them.
*/
BOOL	fNeeded;	    /* Whether we used to need the scrollbar */
BOOL	fNeed;		    /* Whether we need the scrollbar now */
HWND	hWnd;		    /* Handle to the scrollbar window */
ULONG	flScroll;	    /* FCF_xxxxSCROLL flag (for the scrollbar) */
int	*piPos; 	    /* Current location of scrollbar thumb */
int	iMax;		    /* New maximum for the scrollbar */
int	*pc;		    /* Counter for WinEnableWindowUpdate recursion */
{
    if (fNeed) {    /* Enable the scroll bar -- we didn't need it before */
	if (!fNeeded) {
	    EnableSB(hWnd);
	    UpdateOff((*pc), hWnd);
	    UpdateFrame(flScroll);
	    UpdateOn((*pc), hWnd);
	}
	SetScroll(hWnd, (*piPos) = Min((*piPos), iMax), iMax);
    } else {	    /* Disable the scroll bar, we no longer need it */
	if (fNeeded) {
	    DisableSB(hWnd);
	    UpdateOff((*pc), hWnd);
	    UpdateFrame(flScroll);
	    UpdateOn((*pc), hWnd);
	}
    }
}

void AvioLargeFont(BOOL fLargeFont) {
    static BOOL fFirst = TRUE;				    // Need to init?
    static LONG lSmallHt, lSmallWd, lLargeHt, lLargeWd;     // Font sizes
    SWP swp;

    if (fFirst) {
	/*
	    The first time through, get the small and large font sizes
	*/
	DevQueryCaps(hDC, CAPS_CHAR_HEIGHT,		1L, &lLargeHt);
	DevQueryCaps(hDC, CAPS_CHAR_WIDTH,		1L, &lLargeWd);
	DevQueryCaps(hDC, CAPS_SMALL_CHAR_HEIGHT,	1L, &lSmallHt);
	DevQueryCaps(hDC, CAPS_SMALL_CHAR_WIDTH,	1L, &lSmallWd);
	fFirst = FALSE;
    }
    /*
	Set the character size with VioSetDeviceCellSize
    */
    SetCellSize( (SHORT) (lChHeight = ((fLargeFont) ? lLargeHt : lSmallHt)),
		 (SHORT) (lChWidth  = ((fLargeFont) ? lLargeWd : lSmallWd)) );
    /*
	Compute maximum size of client area
    */
    cxMaxClient	= (cxChPS * (SHORT) lChWidth);
    cxMaxFrame	= cxMaxClient + (SHORT) cxConstant;
    cyMaxClient = (cyChPS * (SHORT) lChHeight);
    cyMaxFrame  = cyMaxClient + (SHORT) cyConstant;
    /*
	Send a WM_ADJUSTFRAMEPOS message
    */
    WinQueryWindowPos(hWndFrame, &swp);
    if (swp.fs & SWP_MAXIMIZE) {
	AvioMinMax(&swp);
	WinSetMultWindowPos(hWndFrame, &swp, 1);
    } else {
	swp.fs = SWP_ACTIVATE | SWP_MOVE | SWP_SHOW | SWP_SIZE;
	WinSetWindowPos(hWndFrame, NULL, swp.x, swp.y,
	    Min(cxMaxFrame, swp.cx), Min(cyMaxFrame, swp.cy), swp.fs);
    }
    AvioAdjustFramePos(&swp);		/* Fix up the frame, scroll bars */
    AvioPaint(hWndClient);		/* Repaint with new characters   */
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.