/* * vidframe.c * * 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 #include #include #include #include "mmreg.h" #include "msvideo.h" #include "avicap.h" #include "vidcap.h" #include "vidframe.h" /* * pixels to move when asked to scroll one line or page */ #define LINE_SCROLL 10 #define PAGE_SCROLL 50 // class name #define VIDFRAMECLASSNAME "vidframeClass" /* * standard brushes */ static HBRUSH ghbrBackground = NULL, ghbrFace, ghbrHighlight, ghbrShadow; /* * 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) { 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) { DeleteObject(ghbrBackground); } switch(iPref) { case IDD_PrefsDefBackground: ghbrBackground = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); break; case IDD_PrefsLtGrey: ghbrBackground = GetStockObject(LTGRAY_BRUSH); break; case IDD_PrefsDkGrey: ghbrBackground = GetStockObject(DKGRAY_BRUSH); break; case IDD_PrefsBlack: ghbrBackground = GetStockObject(BLACK_BRUSH); 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); } 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) { // the avicap window is the child id 1 HWND hwndCap = GetDlgItem(hwnd, 1); switch(message) { case WM_MOVE: case WM_SIZE: vidframeLayout(hwnd, hwndCap); 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 return SendMessage(ghWndCap, message, wParam, lParam) ; case WM_PAINT: vidframePaint(hwnd, hwndCap); break; case WM_HSCROLL: vidframeHScroll(hwnd, hwndCap, GET_WM_HSCROLL_CODE(wParam, lParam), GET_WM_HSCROLL_POS(wParam, lParam) ); break; case WM_VSCROLL: vidframeVScroll(hwnd, hwndCap, 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 = CreateWindow( 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); }