//+--------------------------------------------------------------------- // // File: ipborder.cxx // // Classes: InPlaceBorder // // Notes: Use of this class limits windows to the use // of the non-client region for UIAtive borders // only: Standard (non-control window) scroll bars // are specifically NOT supported. // // History: 14-May-93 CliffG Created. // //------------------------------------------------------------------------ #include "headers.hxx" #pragma hdrstop #define IPB_GRABFACTOR 3 #define SetWF(hwnd,wf) SetWindowLongPtr(hwnd, GWL_STYLE, \ GetWindowLongPtr(hwnd,GWL_STYLE) | (wf)) #define ClrWF(hwnd,wf) SetWindowLongPtr(hwnd, GWL_STYLE, \ GetWindowLongPtr(hwnd,GWL_STYLE) &~(wf)) #define TestWF(hwnd,wf) (GetWindowLongPtr(hwnd,GWL_STYLE) & (wf)) WORD InPlaceBorder::_cUsage = 0; HBRUSH InPlaceBorder::_hbrActiveCaption; HBRUSH InPlaceBorder::_hbrInActiveCaption; //+--------------------------------------------------------------- // // Member: InPlaceBorder::DrawFrame // //--------------------------------------------------------------- void InPlaceBorder::DrawFrame(HWND hwnd) { if(!_fUIActive) return; HDC hdc = GetWindowDC(hwnd); if (!hdc) return; HBRUSH hbr; if(_fParentActive) hbr = _hbrActiveCaption; else hbr = _hbrInActiveCaption; if (hbr) { RECT rcWhole; GetWindowRect(hwnd, &rcWhole); OffsetRect(&rcWhole, -rcWhole.left, -rcWhole.top); RECT rc; //Top rc = rcWhole; rc.bottom = rc.top + _cyFrame; FillRect(hdc, &rc, hbr); //Left rc = rcWhole; rc.right = rc.left + _cxFrame; FillRect(hdc, &rc, hbr); //Bottom rc = rcWhole; rc.top = rc.bottom - _cyFrame; FillRect(hdc, &rc, hbr); //Right rc = rcWhole; rc.left = rc.right - _cxFrame; FillRect(hdc, &rc, hbr); if(TestWF(hwnd, WS_THICKFRAME)) //Resizable window? { // //Draw grab handles at 4 corners of the border... // hbr = (HBRUSH)GetStockObject( BLACK_BRUSH ); //TopLeft rc = rcWhole; rc.right = rc.left + _cxFrame; rc.bottom = rc.top + _cyFrame * IPB_GRABFACTOR; FillRect(hdc, &rc, hbr); rc.bottom = rc.top + _cyFrame; rc.right = rc.left + _cxFrame * IPB_GRABFACTOR; FillRect(hdc, &rc, hbr); //TopRight rc.right = rcWhole.right; rc.left = rc.right - _cxFrame * IPB_GRABFACTOR; FillRect(hdc, &rc, hbr); rc.left = rc.right - _cxFrame; rc.bottom = rc.top + _cyFrame * IPB_GRABFACTOR; FillRect(hdc, &rc, hbr); //BottomLeft rc = rcWhole; rc.top = rc.bottom - _cyFrame * IPB_GRABFACTOR; rc.right = rc.left + _cxFrame; FillRect(hdc, &rc, hbr); rc.top = rc.bottom - _cyFrame; rc.right = rc.left + _cxFrame * IPB_GRABFACTOR; FillRect(hdc, &rc, hbr); //BottomRight rc.right = rcWhole.right; rc.left = rc.right - _cxFrame * IPB_GRABFACTOR; FillRect(hdc, &rc, hbr); rc.right = rcWhole.right; rc.left = rc.right - _cxFrame; rc.top = rc.bottom - _cyFrame * IPB_GRABFACTOR; FillRect(hdc, &rc, hbr); } } ReleaseDC(hwnd, hdc); } //+--------------------------------------------------------------- // // Member: InPlaceBorder::HitTest // //--------------------------------------------------------------- LONG InPlaceBorder::HitTest(HWND hwnd, int x, int y) { POINT pt = { x, y }; RECT rcClient; GetWindowRect(hwnd, &rcClient); CalcClientRect(hwnd, &rcClient); if (PtInRect(&rcClient, pt)) return HTCLIENT; // We're somewhere on the window frame. if (y >= rcClient.bottom) { if (x <= rcClient.left + _cxFrame * IPB_GRABFACTOR) return HTBOTTOMLEFT; if (x >= rcClient.right - _cxFrame * IPB_GRABFACTOR) return HTBOTTOMRIGHT; return HTBOTTOM; } else if (y <= rcClient.top) { if (x <= rcClient.left + _cxFrame * IPB_GRABFACTOR) return(HTTOPLEFT); if (x >= rcClient.right - _cxFrame * IPB_GRABFACTOR) return(HTTOPRIGHT); return HTTOP; } else if (x <= rcClient.left) { if (y <= rcClient.top + _cyFrame * IPB_GRABFACTOR) return HTTOPLEFT; if (y >= rcClient.bottom - _cyFrame * IPB_GRABFACTOR) return HTBOTTOMLEFT; return HTLEFT; } else { if (y <= rcClient.top + _cyFrame * IPB_GRABFACTOR) return HTTOPRIGHT; if (y >= rcClient.bottom - _cyFrame * IPB_GRABFACTOR) return HTBOTTOMRIGHT; return HTRIGHT; } return HTNOWHERE; } //+--------------------------------------------------------------- // // Member: InPlaceBorder::DefWindowProc // //--------------------------------------------------------------- LRESULT InPlaceBorder::DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT lRet = 0L; //REVIEW code assumes an SDI app... if(_hwnd == NULL) return ::DefWindowProc(hwnd,msg,wParam,lParam); switch (msg) { case WM_WINDOWPOSCHANGED: if(_pSite != NULL && _cResizing == 0 && _fUIActive) { ++_cResizing; RECT rc; GetChildWindowRect(hwnd, &rc); InflateRect(&rc,-_cxFrame,-_cyFrame); _pSite->OnPosRectChange(&rc); _cResizing--; } break; case WM_NCCALCSIZE: // lParam == LPRECT of window rect // //Turn off the WS_THICKFRAME style bit during //default processing so we keep ownership of visualization... // if (TestWF(hwnd, WS_THICKFRAME)) { ClrWF(hwnd, WS_THICKFRAME); lRet = ::DefWindowProc(hwnd, msg, wParam,lParam); SetWF(hwnd, WS_THICKFRAME); } CalcClientRect(hwnd, (LPRECT)lParam); return lRet; case WM_NCHITTEST: // lParam is POINT in screen cords return HitTest(hwnd, LOWORD(lParam), HIWORD(lParam)); case WM_NCPAINT: DrawFrame(hwnd); return 0L; case WM_NCLBUTTONDOWN: case WM_NCMOUSEMOVE: case WM_NCLBUTTONUP: case WM_NCLBUTTONDBLCLK: case WM_NCRBUTTONDOWN: case WM_NCRBUTTONUP: case WM_NCRBUTTONDBLCLK: case WM_NCMBUTTONDOWN: case WM_NCMBUTTONUP: case WM_NCMBUTTONDBLCLK: case WM_NCACTIVATE: // wParam == active state case WM_NCCREATE: // Sent before WM_CREATE case WM_NCDESTROY: // Sent before WM_DESTROY break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } //+--------------------------------------------------------------- // // Member: InPlaceBorder::InPlaceBorder // //--------------------------------------------------------------- InPlaceBorder::InPlaceBorder(void) { _fParentActive = TRUE; _fUIActive = FALSE; _hwnd = NULL; _pSite = NULL; _cResizing = 0; _cxFrame = _cyFrame = IPBORDER_THICKNESS; if(_cUsage++ == 0) { // the following could fail and we would be hosed... _hbrActiveCaption = CreateHatchBrush(HS_BDIAGONAL, GetSysColor(COLOR_ACTIVECAPTION)); _hbrInActiveCaption = CreateHatchBrush(HS_BDIAGONAL, GetSysColor(COLOR_WINDOWFRAME)); } } //+--------------------------------------------------------------- // // Member: InPlaceBorder::~InPlaceBorder // //--------------------------------------------------------------- InPlaceBorder::~InPlaceBorder(void) { if(--_cUsage == 0) { DeleteObject(_hbrActiveCaption); _hbrActiveCaption = NULL; DeleteObject(_hbrInActiveCaption); _hbrInActiveCaption = NULL; } } //+--------------------------------------------------------------- // // Member: InPlaceBorder::SetState // //Change the border state: reflected in the nonclient window border //--------------------------------------------------------------- void InPlaceBorder::SetUIActive(BOOL fUIActive) { if(_hwnd == NULL) return; if(_fUIActive != fUIActive) { RECT rcClient; GetChildWindowRect(_hwnd, &rcClient); int cx = rcClient.right - rcClient.left; int cy = rcClient.bottom - rcClient.top; int x = rcClient.left; int y = rcClient.top; BOOL fResize = FALSE; if (fUIActive) { fResize = TRUE; cx += _cxFrame * 2; cy += _cyFrame * 2; x -= _cxFrame; y -= _cyFrame; } else if (_fUIActive) { fResize = TRUE; cx -= _cxFrame * 2; cy -= _cyFrame * 2; x += _cxFrame; y += _cyFrame; } if (fResize) { // //Set our state member up so CalcClientRect generates correct values, //then move the window (keeping client area same size and position) // _fUIActive = fUIActive; ++_cResizing; SetWindowPos( _hwnd, NULL, x, y, cx, cy, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER); RedrawFrame(); _cResizing--; } else { InvalidateFrame(); } } _fUIActive = fUIActive; } //+--------------------------------------------------------------- // // Member: InPlaceBorder::SetSize // //--------------------------------------------------------------- void InPlaceBorder::SetSize(HWND hwnd, RECT& rc) { int cx = rc.right - rc.left; int cy = rc.bottom - rc.top; int x = rc.left; int y = rc.top; if(_fUIActive) { cx += _cxFrame * 2; cy += _cyFrame * 2; x -= _cxFrame; y -= _cyFrame; } ++_cResizing; MoveWindow(hwnd, x, y, cx, cy, TRUE); _cResizing--; } //+--------------------------------------------------------------- // // Member: InPlaceBorder::Erase // // Force border state to non-UIActive, managing the coresponding // change in border appearance // //--------------------------------------------------------------- void InPlaceBorder::Erase(void) { if(_hwnd == NULL) return; SetUIActive(FALSE); _fParentActive = TRUE; InvalidateFrame(); RedrawFrame(); } //+--------------------------------------------------------------- // // Member: InPlaceBorder::SetBorderSize // //--------------------------------------------------------------- void InPlaceBorder::SetBorderSize( int cx, int cy ) { if(cx < 0) cx = 0; if(cy < 0) cy = 0; _cxFrame = cx; _cyFrame = cy; InvalidateFrame(); RedrawFrame(); } //+--------------------------------------------------------------- // // Member: InPlaceBorder::GetBorderSize // //--------------------------------------------------------------- void InPlaceBorder::GetBorderSize( LPINT pcx, LPINT pcy ) { *pcx = _cxFrame; *pcy = _cyFrame; } //+--------------------------------------------------------------- // // Member: InPlaceBorder::Attach // //--------------------------------------------------------------- void InPlaceBorder::Attach(HWND hwnd, BOOL fUIActive) { if((_hwnd = hwnd) != NULL) { SetUIActive(fUIActive); InvalidateFrame(); //force first-time NCCALC } } void InPlaceBorder::Bind(LPOLEINPLACESITE pSite, HWND hwnd, BOOL fUIActive) { _pSite = NULL; if((_hwnd = hwnd) != NULL && (_pSite = pSite) != NULL) { SetUIActive(fUIActive); InvalidateFrame(); //force first-time NCCALC } }