//+--------------------------------------------------------------------- // // File: tools.cxx // // Notes: Simple tool-tray window base class and derived // trays for PBrush drawing tools // // Classes: // PBToolTray (a window class) // CTray // //------------------------------------------------------------------------ #include #include #include #include #include // the base classes and utilities #include "pbs.hxx" #define MARGIN_X 4 #define MARGIN_Y 4 #define FRAME_X 1 #define FRAME_Y 1 #define TRAY_DEFAULT_WIDTH 64 #define TRAY_DEFAULT_HEIGHT 256 #define LSIZETOOL_HEIGHT 64 #define COLORTRAY_WIDTH 256 #define COLORTRAY_HEIGHT 48 BOOL Tray::_fInit = FALSE; ATOM Tray::_atomClass = 0; COLORREF Tray::crLtGray; COLORREF Tray::crGray; COLORREF Tray::crDkGray; COLORREF Tray::crBlack; HBRUSH Tray::hbrActiveCaption = NULL; HBRUSH Tray::hbrInActiveCaption = NULL; HBRUSH Tray::hbrWindowFrame = NULL; HBRUSH Tray::hbrSysBox = NULL; WORD Tray::wCnt = 0; // // Routines & definitions for creating windows with custom NON-CLIENT areas // #define SetWF(hwnd,wf) SetWindowLong(hwnd, GWL_STYLE, \ GetWindowLong(hwnd,GWL_STYLE) | (wf)) #define ClrWF(hwnd,wf) SetWindowLong(hwnd, GWL_STYLE, \ GetWindowLong(hwnd,GWL_STYLE) &~(wf)) #define TestWF(hwnd,wf) (GetWindowLong(hwnd,GWL_STYLE) & (wf)) // // Window styles used by ncMsgFilter // #define WF_SIZEFRAME WS_THICKFRAME #define WF_SYSMENU WS_SYSMENU #define WF_MINIMIZED WS_MINIMIZE #define WF_SIZEBOX 0x0002 #define WF_ACTIVE 0x0001 //+--------------------------------------------------------------- // // Member: Tray::Create (static) // //--------------------------------------------------------------- LPTRAY Tray::Create(HINSTANCE hinst, HWND hwndParent, HWND hwndNotify, int iChild) { DOUT(L"Tray::Create\r\n"); // //If we haven't yet done our base initialization, do it now // if(_fInit == FALSE) { if(Tray::InitClass(hinst) == 0) return NULL; } LPTRAY pTray; if ((pTray = new Tray(hwndParent, hwndNotify, iChild)) != NULL) { if(NULL == pTray->CreateToolWindow(hinst, hwndParent)) { DOUT(L"Tray::Create Failing!\r\n"); delete pTray; pTray = NULL; } } return pTray; } //+--------------------------------------------------------------- // // Member: Tray::InitClass (static) // //--------------------------------------------------------------- ATOM Tray::InitClass(HINSTANCE hinst) { crLtGray = PALETTEINDEX(7); crGray = PALETTEINDEX(248); crDkGray = PALETTEINDEX(249); crBlack = PALETTEINDEX(0); // // register our window class // WNDCLASS wc; wc.style = CS_NOCLOSE | CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW; wc.lpfnWndProc = TrayWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 4; // for pointer to Tray object wc.hInstance = hinst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = CLASS_NAME_PBTRAY; if((Tray::_atomClass = RegisterClass(&wc)) != 0) { Tray::_fInit = TRUE; } return _atomClass; } //+--------------------------------------------------------------- // // Member: Tray::Tray // //--------------------------------------------------------------- Tray::Tray(HWND hwndParent, HWND hwndNotify, int iChild) { _hwndNotify = hwndNotify; _iChild = iChild; _hwnd = NULL; _cxFrame = FRAME_X; _cyFrame = FRAME_Y; _dxMargin = MARGIN_X; _dyMargin = MARGIN_Y; _xWidth = TRAY_DEFAULT_WIDTH; _yHeight = TRAY_DEFAULT_HEIGHT; } //+--------------------------------------------------------------- // // Member: Tray::~Tray // //--------------------------------------------------------------- Tray::~Tray(void) { if (_hwnd != NULL) { DOUT(L"Tray::~Tray Destroying Window\r\n"); DestroyWindow(_hwnd); } } //+--------------------------------------------------------------- // // Member: Tray::Position // // Notes: The idea for this method is for the derived class // to provide behavior such that it positions itself // in it's "natural" position relative to the x, y parms // //--------------------------------------------------------------- void Tray::Position(int x, int y) { SetWindowPos(_hwnd, 0, x, y, _xWidth, _yHeight, SWP_NOACTIVATE | SWP_NOZORDER); } void Tray::GetToolRect(LPRECT lprc) { GetClientRect(_hwnd, lprc); InflateRect(lprc, -_dxMargin, -_dyMargin); } //+--------------------------------------------------------------- // // Member: Tray::OnCreate // //--------------------------------------------------------------- BOOL Tray::OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct) { return TRUE; } //+--------------------------------------------------------------- // // Member: Tray::OnDestroy // //--------------------------------------------------------------- void Tray::OnDestroy(HWND hwnd) { _hwnd = NULL; } //+--------------------------------------------------------------- // // Member: Tray::OnPaint // //--------------------------------------------------------------- void Tray::OnPaint(HWND hwnd) { PAINTSTRUCT ps; BeginPaint(hwnd, &ps); HBRUSH hbr = (HBRUSH)GetStockBrush(LTGRAY_BRUSH); FillRect(ps.hdc, &ps.rcPaint, hbr); EndPaint(hwnd, &ps); } void Tray::OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo) { lpMinMaxInfo->ptMaxSize.x = _xWidth; lpMinMaxInfo->ptMaxSize.y = _yHeight; lpMinMaxInfo->ptMaxPosition.x = lpMinMaxInfo->ptMaxPosition.y = 0; lpMinMaxInfo->ptMinTrackSize.x = 8; lpMinMaxInfo->ptMinTrackSize.y = 16; lpMinMaxInfo->ptMaxTrackSize.x = 1024; lpMinMaxInfo->ptMaxTrackSize.y = 768; } void Tray::OnWindowPosChanged(HWND hwnd, LPWINDOWPOS lpwpos) { if (lpwpos->flags & SWP_HIDEWINDOW) return; DOUT(L"Tray::OnWindowPosChanged\r\n"); } //+--------------------------------------------------------------- // // Function: TrayWndProc // //--------------------------------------------------------------- extern "C" LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // // get a pointer to the Tray object // if it is NULL, then check for a WM_NCCREATE message // when we get one stash the pointer to our object // LPTRAY pTray = (LPTRAY)GetWindowLong(hwnd, 0); if(pTray == NULL) { if(msg == WM_NCCREATE) { CREATESTRUCT FAR *lpcs = (CREATESTRUCT FAR *)lParam; pTray = (LPTRAY)lpcs->lpCreateParams; SetWindowLong(hwnd, 0, (LONG)pTray); return(pTray->ncMsgFilter(hwnd, msg, wParam, lParam)); } return(DefWindowProc(hwnd, msg, wParam, lParam)); } if(msg == WM_NCDESTROY) { SetWindowLong(hwnd, 0, 0L); return(DefWindowProc(hwnd, msg, wParam, lParam)); } // // handle any window message by passing it to the appropriate // member function... // switch(msg) { HANDLE_MSG(hwnd, WM_CREATE, pTray->OnCreate); HANDLE_MSG(hwnd, WM_DESTROY, pTray->OnDestroy); HANDLE_MSG(hwnd, WM_PAINT, pTray->OnPaint); HANDLE_MSG(hwnd, WM_GETMINMAXINFO, pTray->OnGetMinMaxInfo); HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, pTray->OnWindowPosChanged); } return pTray->ncMsgFilter(hwnd, msg, wParam, lParam); } //+--------------------------------------------------------------- // // Member: Tray::ncCalcRect // //--------------------------------------------------------------- inline void Tray::ncCalcRect(HWND hwnd, LPRECT lprc) { InflateRect(lprc, -_cxFrame, -_cyFrame); } //+--------------------------------------------------------------- // // Member: Tray::ncHitTest // //--------------------------------------------------------------- LONG Tray::ncHitTest(HWND hwnd, POINT pt) { // // If the window is minimized and iconic, return HTCAPTION // if (TestWF(hwnd, WF_MINIMIZED)) return HTCAPTION; // // Get Client and Window rects in screen coordinates // RECT rcWindow; GetWindowRect(hwnd, &rcWindow); RECT rcClient = rcWindow; ncCalcRect(hwnd, &rcClient); // //lie about actual client area: count the margin as NC // InflateRect(&rcClient, -_dxMargin, -_dyMargin); if (PtInRect(&rcClient, pt)) return HTCLIENT; return HTCAPTION; } //+--------------------------------------------------------------- // // Member: Tray::ncDrawFrame // //--------------------------------------------------------------- void Tray::ncDrawFrame(HWND hwnd) { HDC hdc = GetWindowDC(hwnd); RECT rc; GetWindowRect(hwnd, &rc); OffsetRect(&rc, -rc.left, -rc.top); SelectObject(hdc, hbrWindowFrame); // // This works as long as cxFrame and cyFrame are both one // FrameRect(hdc, &rc, hbrWindowFrame); InflateRect(&rc, -_cxFrame, -_cyFrame); rc.bottom = rc.top + _cyFrame; FillRect(hdc, &rc, hbrWindowFrame); ReleaseDC(hwnd, hdc); } //+--------------------------------------------------------------- // // Member: Tray::ncMsgFilter // // // This method handles Windows non-client // messages so that the non-client area of a window is drawn as a low // key floating tool box. The title bar of the window is much smaller // than the standard Windows title bar, and no caption is displayed. // The system menu box is replaced by a small black rectangle. // // When using this method, the following messages must be passed in // order for the window to correctly operate within the Windows // environment: all non-client messages, whose symbolic names begin with // the prefix WM_NC, the WM_SYSCOMMAND, WM_COMMAND, and WM_INITMENU // messages. If the caller also needs to process any of these messages, // the caller must pre-process the message and then call ncMsgFilter. // // If an unrecognized message is passed to ncMsgFilter, // DefWindowProc is called. // //--------------------------------------------------------------- LRESULT Tray::ncMsgFilter(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_NCACTIVATE: // wParam == active state if (wParam) SetWF(hwnd, WF_ACTIVE); else ClrWF(hwnd, WF_ACTIVE); ncDrawFrame(hwnd); return TRUE; case WM_NCCALCSIZE: // lParam == LPRECT of window rect ncCalcRect(hwnd, (LPRECT)lParam); if(wParam) return WVR_REDRAW; return 0L; case WM_NCCREATE: // Sent before WM_CREATE if (wCnt++ == 0) { hbrActiveCaption = CreateSolidBrush( GetSysColor(COLOR_ACTIVECAPTION)); hbrInActiveCaption = CreateSolidBrush( GetSysColor(COLOR_INACTIVECAPTION)); hbrWindowFrame = CreateSolidBrush( GetSysColor(COLOR_WINDOWFRAME)); hbrSysBox = (HBRUSH)GetStockObject(BLACK_BRUSH); } break; case WM_NCDESTROY: // Sent before WM_DESTROY if (wCnt == 0) break; // haven't created one yet - don't delete if (--wCnt == 0) { DeleteObject(hbrActiveCaption); DeleteObject(hbrInActiveCaption); DeleteObject(hbrWindowFrame); } break; case WM_NCHITTEST: // lParam is POINT in screen cords { POINT pt = { LOWORD(lParam), HIWORD(lParam) }; return ncHitTest(hwnd, pt); } case WM_NCPAINT: ncDrawFrame(hwnd); return 0L; // // Dont activate the window when it is clicked on in the CLIENT // area, this is useful for "tool" windows. // // Should this behaviour be controled by a style bit? // case WM_MOUSEACTIVATE: if (LOWORD(lParam) == HTCLIENT) return MA_NOACTIVATE; break; } return DefWindowProc(hwnd, msg, wParam, lParam); } // // Derived Classes //====================== // //+--------------------------------------------------------------- // // ToolTray // //--------------------------------------------------------------- LPTOOLTRAY ToolTray::Create(HINSTANCE hinst, HWND hwndParent, HWND hwndNotify, int iChild) { DOUT(L"ToolTray::Create\r\n"); // //If we haven't yet done our base initialization, do it now // if(Tray::_fInit == FALSE) { if(Tray::InitClass(hinst) == 0) return NULL; } LPTOOLTRAY pTray; if ((pTray = new ToolTray(hwndParent, hwndNotify, iChild)) != NULL) { if(NULL == pTray->CreateToolWindow(hinst, hwndParent)) { DOUT(L"CreateTray::Create Failing!\r\n"); delete pTray; pTray = NULL; } } return pTray; } ToolTray::ToolTray(HWND hwndParent, HWND hwndNotify, int iChild) : Tray(hwndParent, hwndNotify, iChild) { _yOffset = LSIZETOOL_HEIGHT; _xWidth = TRAY_DEFAULT_WIDTH; _yHeight = TRAY_DEFAULT_HEIGHT + _yOffset; } void ToolTray::GetToolRect(LPRECT lprc) { GetClientRect(_hwnd, lprc); InflateRect(lprc, -_dxMargin, -_dyMargin); lprc->bottom -= _yOffset; } void ToolTray::GetLSizeRect(LPRECT lprc) { GetClientRect(_hwnd, lprc); InflateRect(lprc, -_dxMargin, -_dyMargin); lprc->top = lprc->bottom - _yOffset; } void ToolTray::Position(int x, int y) { int yMax = GetSystemMetrics(SM_CYSCREEN); int yHeight = _yHeight + _dyMargin; if(y > yMax - yHeight) y = yMax - yHeight; x -= _xWidth + _dxMargin; if(x < 0) x = 0; Tray::Position(x, y); } void ToolTray::OnWindowPosChanged(HWND hwnd, LPWINDOWPOS lpwpos) { if (lpwpos->flags & SWP_HIDEWINDOW) return; DOUT(L"ToolTray::OnWindowPosChanged\r\n"); GetToolRect(&gprcApp[iTool]); MoveWindow(gpahwndApp[iTool], gprcApp[iTool].left, gprcApp[iTool].top, gprcApp[iTool].right - gprcApp[iTool].left, gprcApp[iTool].bottom - gprcApp[iTool].top, TRUE); UpdateWindow(gpahwndApp[iTool]); GetLSizeRect(&gprcApp[iSize]); MoveWindow(gpahwndApp[iSize], gprcApp[iSize].left, gprcApp[iSize].top, gprcApp[iSize].right - gprcApp[iSize].left, gprcApp[iSize].bottom - gprcApp[iSize].top, TRUE); UpdateWindow(gpahwndApp[iSize]); //InvalidateRect(gpahwndApp[iSize], NULL, TRUE); } //+--------------------------------------------------------------- // // ColorTray // //--------------------------------------------------------------- LPCOLORTRAY ColorTray::Create(HINSTANCE hinst, HWND hwndParent, HWND hwndNotify, int iChild) { DOUT(L"ColorTray::Create\r\n"); // //If we haven't yet done our base initialization, do it now // if(Tray::_fInit == FALSE) { if(Tray::InitClass(hinst) == 0) return NULL; } LPCOLORTRAY pTray; if ((pTray = new ColorTray(hwndParent, hwndNotify, iChild)) != NULL) { if(NULL == pTray->CreateToolWindow(hinst, hwndParent)) { DOUT(L"ColorTray::Create Failing!\r\n"); delete pTray; pTray = NULL; } } return pTray; } ColorTray::ColorTray(HWND hwndParent, HWND hwndNotify, int iChild) : Tray(hwndParent, hwndNotify, iChild) { _xWidth = COLORTRAY_WIDTH; _yHeight = COLORTRAY_HEIGHT; } void ColorTray::GetColorRect(LPRECT lprc) { GetClientRect(_hwnd, lprc); InflateRect(lprc, -_dxMargin, -_dyMargin); } void ColorTray::Position(int x, int y) { int yMax = GetSystemMetrics(SM_CYSCREEN); int yHeight = _yHeight + _dyMargin; if(y > yMax - yHeight) y = yMax - yHeight; x += _dxMargin; y += _dyMargin; Tray::Position(x, y); } void ColorTray::OnWindowPosChanged(HWND hwnd, LPWINDOWPOS lpwpos) { if (lpwpos->flags & SWP_HIDEWINDOW) return; DOUT(L"ColorTray::OnWindowPosChanged\r\n"); GetColorRect(&gprcApp[iColor]); MoveWindow(gpahwndApp[iColor], gprcApp[iColor].left, gprcApp[iColor].top, gprcApp[iColor].right - gprcApp[iColor].left, gprcApp[iColor].bottom - gprcApp[iColor].top, TRUE); UpdateWindow(gpahwndApp[iColor]); }