VIDFRAME.C

/************************************************************************** 
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
* PURPOSE.
*
* Copyright 1992 - 1998 Microsoft Corporation. All Rights Reserved.
*
**************************************************************************/
/****************************************************************************
*
* vidframe.c: Frame for the capture window
*
* Vidcap32 Source code
*
***************************************************************************/

/*
* Window class that provides a frame for the AVICAP window in the
* VidCap capture tool. Responsible for positioning within the
* parent window, handling scrolling and painting a size border if
* there is room.
*/

#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <vfw.h>
#include "vidcap.h"

#include "vidframe.h"

/*
* pixels to move when asked to scroll one line or page
*/
#define LINE_SCROLL10
#define PAGE_SCROLL50

// class name
#define VIDFRAMECLASSNAME "vidframeClass"


/*
* standard brushes
*/
static HBRUSH ghbrBackground = NULL, ghbrFace, ghbrHighlight, ghbrShadow;
static BOOL fhbrBackgroundIsSysObj;


/*
* create brushes to be used in painting
*/
void
vidframeCreateTools(HWND hwnd)
{

vidframeSetBrush(hwnd, gBackColour);

ghbrHighlight = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
ghbrShadow = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
ghbrFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
}

void
vidframeDeleteTools(void)
{
if (ghbrBackground) {
if (!fhbrBackgroundIsSysObj) {
DeleteObject(ghbrBackground);
ghbrBackground = NULL;
}
}

if (ghbrHighlight) {
DeleteObject(ghbrHighlight);
ghbrHighlight = NULL;
}

if (ghbrShadow) {
DeleteObject(ghbrShadow);
ghbrShadow = NULL;
}

if (ghbrFace) {
DeleteObject(ghbrFace);
ghbrFace = NULL;
}
}


/*
* change the background fill brush to be one of-
* IDD_PrefsDefBackground - windows default background colour
* IDD_PrefsLtGrey - light grey
* IDD_PrefsDkGrey - dark grey
* IDD_PrefsBlack - black
*/
void
vidframeSetBrush(HWND hwnd, int iPref)
{
if (ghbrBackground != NULL) {
if (!fhbrBackgroundIsSysObj) {
DeleteObject(ghbrBackground);
ghbrBackground = NULL;
}
}

switch(iPref) {
case IDD_PrefsDefBackground:
ghbrBackground = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
fhbrBackgroundIsSysObj = FALSE;
break;

case IDD_PrefsLtGrey:
ghbrBackground = GetStockObject(LTGRAY_BRUSH);
fhbrBackgroundIsSysObj = TRUE;
break;

case IDD_PrefsDkGrey:
ghbrBackground = GetStockObject(DKGRAY_BRUSH);
fhbrBackgroundIsSysObj = TRUE;
break;

case IDD_PrefsBlack:
ghbrBackground = GetStockObject(BLACK_BRUSH);
fhbrBackgroundIsSysObj = TRUE;
break;

default:
return;
}

if (hwnd != NULL) {
#ifdef _WIN32
SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG) ghbrBackground);
#else
SetClassWord(hwnd, GCW_HBRBACKGROUND, (WORD) ghbrBackground);
#endif
InvalidateRect(hwnd, NULL, TRUE);
}
}




/*
* layout the window - decide if we need scrollbars or
* not, and position the avicap window correctly
*/
void
vidframeLayout(HWND hwnd, HWND hwndCap)
{
RECT rc;
RECT rcCap;
CAPSTATUS cs;
int cx, cy;
POINT ptScroll;


// get the x and y scroll pos so we can reset them
ptScroll.y = GetScrollPos(hwnd, SB_VERT);
ptScroll.x = GetScrollPos(hwnd, SB_HORZ);

GetClientRect(hwnd, &rc);
if (!capGetStatus(hwndCap, &cs, sizeof(cs))) {
// no current window? - make it 0 size
cs.uiImageWidth = 0;
cs.uiImageHeight = 0;

}

SetRect(&rcCap, 0, 0, cs.uiImageWidth, cs.uiImageHeight);

/*
* check which scrollbars we need - note that adding and removing
* scrollbars affects the other dimension - so recheck client rect
*/
if (RECTWIDTH(rcCap) < RECTWIDTH(rc)) {
// fits horz.
SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
} else {
// need horz scrollbar
SetScrollRange(hwnd, SB_HORZ, 0, RECTWIDTH(rcCap) - RECTWIDTH(rc), FALSE);
}

// get client size in case shrunk/expanded
GetClientRect(hwnd, &rc);

// check vert scrollbar
if (RECTHEIGHT(rcCap) < RECTHEIGHT(rc)) {
SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE);
} else {
SetScrollRange(hwnd, SB_VERT, 0, RECTHEIGHT(rcCap) - RECTHEIGHT(rc), FALSE);

// this may have caused the horz scrollbar to be unneeded
GetClientRect(hwnd, &rc);
if (RECTWIDTH(rcCap) < RECTWIDTH(rc)) {
// fits horz.
SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
} else {
// need horz scrollbar
SetScrollRange(hwnd, SB_HORZ, 0, RECTWIDTH(rcCap) - RECTWIDTH(rc), FALSE);
}
}

/*
* be sure we don't leave any underwear showing if we have scrolled
* back or removed the scrollbars
*/
{
int cmax, cmin;

GetScrollRange(hwnd, SB_HORZ, &cmin, &cmax);
if (ptScroll.x > cmax) {
ptScroll.x = cmax;
}
GetScrollRange(hwnd, SB_VERT, &cmin, &cmax);
if (ptScroll.y > cmax) {
ptScroll.y = cmax;
}
SetScrollPos(hwnd, SB_HORZ, ptScroll.x, TRUE);
SetScrollPos(hwnd, SB_VERT, ptScroll.y, TRUE);
capSetScrollPos(hwndCap, &ptScroll);
}

// centre the window if requested and if room
if(gbCentre) {
GetClientRect(hwnd, &rc);
cx = max(0, (RECTWIDTH(rc) - (int) cs.uiImageWidth)/2);
cy = max(0, (RECTHEIGHT(rc) - (int) cs.uiImageHeight)/2);
OffsetRect(&rcCap, cx, cy);
}

// DWORD align the capture window for optimal codec speed
// during preview.
rc = rcCap;
MapWindowPoints (hwnd, NULL, (LPPOINT)&rc, 1);
cx = rc.left - (rc.left & ~3);
OffsetRect(&rcCap, -cx, 0);

MoveWindow(hwndCap,
rcCap.left, rcCap.top,
RECTWIDTH(rcCap), RECTHEIGHT(rcCap),
TRUE);

InvalidateRect(hwnd, NULL, TRUE);
}

/*
* paint the vidframe window. The fill colour is always selected as the
* background brush, so all we need to do here is paint the
* fancy border around the inner window if room.
*/
void
vidframePaint(HWND hwnd, HWND hwndCap)
{
POINT ptInner;
RECT rcCap;
PAINTSTRUCT ps;
HDC hdc;
HBRUSH hbr;
int cx, cy;

hdc = BeginPaint(hwnd, &ps);

/*
* first calculate the location of the upper left corner
* of the avicap window in vidframe-window client co-ordinates
*/
ptInner.x = 0;
ptInner.y = 0;
MapWindowPoints(hwndCap, hwnd, &ptInner, 1);

// width and height of cap window
GetWindowRect(hwndCap, &rcCap);
cx = RECTWIDTH(rcCap);
cy = RECTHEIGHT(rcCap);

// shadow lines
hbr = SelectObject(hdc, ghbrShadow);
PatBlt(hdc, ptInner.x-1, ptInner.y-1, cx + 1, 1, PATCOPY);
PatBlt(hdc, ptInner.x-1, ptInner.y-1, 1, cy + 1, PATCOPY);
PatBlt(hdc, ptInner.x + cx + 4, ptInner.y-5, 1, cy+10, PATCOPY);
PatBlt(hdc, ptInner.x -5, ptInner.y+cy+4, cx+10, 1, PATCOPY);

// hi-light lines
SelectObject(hdc, ghbrHighlight);
PatBlt(hdc, ptInner.x - 5, ptInner.y - 5, 1, cy+9, PATCOPY);
PatBlt(hdc, ptInner.x - 5, ptInner.y - 5, cx+9, 1, PATCOPY);
PatBlt(hdc, ptInner.x+cx, ptInner.y-1, 1, cy+2, PATCOPY);
PatBlt(hdc, ptInner.x-1, ptInner.y+cy, cx, 1, PATCOPY);

// fill bordered area with button face colour
SelectObject(hdc, ghbrFace);
PatBlt(hdc, ptInner.x-4, ptInner.y-4, cx+8, 3, PATCOPY);
PatBlt(hdc, ptInner.x-4, ptInner.y+cy+1, cx+8, 3, PATCOPY);
PatBlt(hdc, ptInner.x-4, ptInner.y-1, 3, cy+2, PATCOPY);
PatBlt(hdc, ptInner.x+cx+1, ptInner.y-1, 3, cy+2, PATCOPY);

SelectObject(hdc, hbr);

EndPaint(hwnd, &ps);

}

/*
* respond to a scrollbar message by moving the current scroll
* position horizontally
*/
void
vidframeHScroll(HWND hwnd, HWND hwndCap, int code, int pos)
{
POINT pt;
int cmax, cmin;

pt.x = GetScrollPos(hwnd, SB_HORZ);
pt.y = GetScrollPos(hwnd, SB_VERT);
GetScrollRange(hwnd, SB_HORZ, &cmin, &cmax);


switch(code) {
case SB_LINEUP:
pt.x -= LINE_SCROLL;
break;

case SB_LINEDOWN:
pt.x += LINE_SCROLL;
break;

case SB_PAGEUP:
pt.x -= PAGE_SCROLL;
break;

case SB_PAGEDOWN:
pt.x += PAGE_SCROLL;
break;

case SB_THUMBTRACK:
case SB_THUMBPOSITION:
pt.x = pos;
break;
}

if (pt.x < cmin) {
pt.x = cmin;
} else if (pt.x > cmax) {
pt.x = cmax;
}
SetScrollPos(hwnd, SB_HORZ, pt.x, TRUE);
capSetScrollPos(hwndCap, &pt);

}


/*
* respond to a scrollbar message by moving the current scroll
* position vertically
*/
void
vidframeVScroll(HWND hwnd, HWND hwndCap, int code, int pos)
{
POINT pt;
int cmax, cmin;

pt.x = GetScrollPos(hwnd, SB_HORZ);
pt.y = GetScrollPos(hwnd, SB_VERT);
GetScrollRange(hwnd, SB_VERT, &cmin, &cmax);


switch(code) {
case SB_LINEUP:
pt.y -= LINE_SCROLL;
break;

case SB_LINEDOWN:
pt.y += LINE_SCROLL;
break;

case SB_PAGEUP:
pt.y -= PAGE_SCROLL;
break;

case SB_PAGEDOWN:
pt.y += PAGE_SCROLL;
break;

case SB_THUMBTRACK:
case SB_THUMBPOSITION:
pt.y = pos;
break;
}

if (pt.y < cmin) {
pt.y = cmin;
} else if (pt.y > cmax) {
pt.y = cmax;
}
SetScrollPos(hwnd, SB_VERT, pt.y, TRUE);
capSetScrollPos(hwndCap, &pt);
}



LONG FAR PASCAL
vidframeProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

switch(message) {

case WM_MOVE:
case WM_SIZE:
if (ghWndCap) {
vidframeLayout(hwnd, ghWndCap);
}
break;

case WM_SYSCOLORCHANGE:
// re-get brushes - we will be sent a paint message
vidframeDeleteTools();
vidframeCreateTools(hwnd);
return(TRUE);


case WM_PALETTECHANGED:
case WM_QUERYNEWPALETTE:
// allow the avicap window to handle this
if (ghWndCap) {
return SendMessage(ghWndCap, message, wParam, lParam) ;
}

case WM_PAINT:
if (ghWndCap) {
vidframePaint(hwnd, ghWndCap);
}
break;

case WM_HSCROLL:
if (ghWndCap) {
vidframeHScroll(hwnd, ghWndCap,
GET_WM_HSCROLL_CODE(wParam, lParam),
GET_WM_HSCROLL_POS(wParam, lParam)
);
}
break;

case WM_VSCROLL:
if (ghWndCap) {
vidframeVScroll(hwnd, ghWndCap,
GET_WM_VSCROLL_CODE(wParam, lParam),
GET_WM_VSCROLL_POS(wParam, lParam)
);
}
break;

case WM_DESTROY:
vidframeDeleteTools();
break;

default:
return(DefWindowProc(hwnd, message, wParam, lParam));

}
return(0);
}



/*
* create a frame window and child capture window at the
* given location. Initialise the class if this is the
* first time through.
*
* returns the window handle of the frame window
* (or NULL if failure). returns the window handle of the AVICAP window
* via phwndCap.
*/
HWND
vidframeCreate(
HWND hwndParent,
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
int x,
int y,
int cx,
int cy,
HWND FAR * phwndCap
)
{
HWND hwnd, hwndCap;
static BOOL bInitDone = FALSE;

if (!bInitDone) {
WNDCLASS wc;

vidframeCreateTools(NULL);

if (!hPrevInstance) {
// If it's the first instance, register the window class
wc.lpszClassName = VIDFRAMECLASSNAME;
wc.hInstance = hInstance;
wc.lpfnWndProc = vidframeProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.hbrBackground = ghbrBackground;
wc.style = CS_HREDRAW | CS_VREDRAW ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;

if(!RegisterClass(&wc)) {
return(NULL);
}
}
bInitDone = TRUE;
}

hwnd = CreateWindowEx(
gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0,
VIDFRAMECLASSNAME,
NULL,
WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|WS_CLIPCHILDREN,
x, y, cx, cy,
hwndParent,
(HMENU) 0,
hInstance,
NULL);

if (hwnd == NULL) {
return(NULL);
}


/*
* create an AVICAP window within this window. Leave vidframeLayout
* to do the layout
*/
hwndCap = capCreateCaptureWindow(
NULL,
WS_CHILD | WS_VISIBLE,
0, 0, 160, 120,
hwnd, // parent window
1 // child window id
);


if (hwndCap == NULL) {
return(NULL);
}

*phwndCap = hwndCap;
return(hwnd);
}