436 lines
12 KiB
C++
436 lines
12 KiB
C++
//+---------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
}
|
|
}
|
|
|