903 lines
23 KiB
C++
903 lines
23 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) 1996-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
hatchwnd.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Implementation of the CHatchWin class. CHatchWin when used
|
||
|
as a parent window creates a thin hatch border around
|
||
|
the child window.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <oleidl.h>
|
||
|
#include "hatchwnd.h"
|
||
|
#include "resource.h"
|
||
|
#include "globals.h"
|
||
|
|
||
|
// Hit codes for computing handle code (Y_CODE + 3 * X_CODE)
|
||
|
#define Y_TOP 0
|
||
|
#define Y_MIDDLE 1
|
||
|
#define Y_BOTTOM 2
|
||
|
#define X_LEFT 0
|
||
|
#define X_MIDDLE 1
|
||
|
#define X_RIGHT 2
|
||
|
#define NO_HIT -1
|
||
|
|
||
|
// Sizing flags
|
||
|
#define SIZING_TOP 0x0001
|
||
|
#define SIZING_BOTTOM 0x0002
|
||
|
#define SIZING_LEFT 0x0004
|
||
|
#define SIZING_RIGHT 0x0008
|
||
|
#define SIZING_ALL 0x0010
|
||
|
|
||
|
// Sizing flags lookup (indexed by handle code)
|
||
|
static UINT uSizingTable[9] = {
|
||
|
SIZING_LEFT | SIZING_TOP, SIZING_TOP, SIZING_RIGHT | SIZING_TOP,
|
||
|
SIZING_LEFT, SIZING_ALL, SIZING_RIGHT,
|
||
|
SIZING_LEFT | SIZING_BOTTOM, SIZING_BOTTOM, SIZING_BOTTOM | SIZING_RIGHT };
|
||
|
|
||
|
// Cursor ID lookup (indexed by handle code)
|
||
|
static UINT uCursIDTable[9] = {
|
||
|
IDC_CURS_NWSE, IDC_CURS_NS, IDC_CURS_NESW,
|
||
|
IDC_CURS_WE, IDC_CURS_MOVE, IDC_CURS_WE,
|
||
|
IDC_CURS_NESW, IDC_CURS_NS, IDC_CURS_NWSE };
|
||
|
|
||
|
// Cursors (indexed by cursor ID)
|
||
|
static HCURSOR hCursTable[IDC_CURS_MAX - IDC_CURS_MIN + 1];
|
||
|
|
||
|
#define IDTIMER_DEBOUNCE 1
|
||
|
#define MIN_SIZE 8
|
||
|
|
||
|
// Brush patterns
|
||
|
static WORD wHatchBmp[]={0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88};
|
||
|
static WORD wGrayBmp[]={0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
|
||
|
|
||
|
static HBRUSH hBrHatch;
|
||
|
static HBRUSH hBrGray;
|
||
|
|
||
|
// System parameters
|
||
|
static INT iBorder;
|
||
|
static INT iDragMinDist;
|
||
|
static INT iDragDelay;
|
||
|
|
||
|
static INT fLocalInit = FALSE;
|
||
|
|
||
|
// Forward refs
|
||
|
void DrawShading(HDC, LPRECT);
|
||
|
void DrawHandles (HDC, LPRECT);
|
||
|
void DrawDragRgn (HWND, HRGN);
|
||
|
HRGN CreateDragRgn(LPRECT);
|
||
|
|
||
|
TCHAR szHatchWinClassName[] = TEXT("Hatchwin") ;
|
||
|
|
||
|
/*
|
||
|
* CHatchWin:CHatchWin
|
||
|
* CHatchWin::~CHatchWin
|
||
|
*
|
||
|
* Constructor Parameters:
|
||
|
* hInst HINSTANCE of the application we're in.
|
||
|
*/
|
||
|
|
||
|
CHatchWin::CHatchWin(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
m_hWnd = NULL;
|
||
|
m_hWndParent = NULL;
|
||
|
m_hWndKid = NULL;
|
||
|
m_hWndAssociate = NULL;
|
||
|
m_hRgnDrag = NULL;
|
||
|
|
||
|
m_iBorder = 0;
|
||
|
m_uID = 0;
|
||
|
m_uDragMode = DRAG_IDLE;
|
||
|
m_bResizeInProgress = FALSE;
|
||
|
SetRect(&m_rcPos, 0, 0, 0, 0);
|
||
|
SetRect(&m_rcClip, 0, 0, 0, 0);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
CHatchWin::~CHatchWin(void)
|
||
|
{
|
||
|
|
||
|
if (NULL != m_hWnd)
|
||
|
DestroyWindow(m_hWnd);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CHatchWin::Init
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Instantiates a hatch window within a given parent with a
|
||
|
* default rectangle. This is not initially visible.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* hWndParent HWND of the parent of this window
|
||
|
* uID UINT identifier for this window (send in
|
||
|
* notifications to associate window).
|
||
|
* hWndAssoc HWND of the initial associate.
|
||
|
*
|
||
|
* Return Value:
|
||
|
* BOOL TRUE if the function succeeded, FALSE otherwise.
|
||
|
*/
|
||
|
|
||
|
BOOL CHatchWin::Init(HWND hWndParent, UINT uID, HWND hWndAssoc)
|
||
|
{
|
||
|
INT i;
|
||
|
HBITMAP hBM;
|
||
|
WNDCLASS wc;
|
||
|
LONG_PTR lptrID = 0;
|
||
|
|
||
|
BEGIN_CRITICAL_SECTION
|
||
|
|
||
|
// If first time through
|
||
|
if (pstrRegisteredClasses[HATCH_WNDCLASS] == NULL) {
|
||
|
|
||
|
// Register the hatch window class
|
||
|
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
|
||
|
wc.hInstance = g_hInstance;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.lpfnWndProc = (WNDPROC)HatchWndProc;
|
||
|
wc.cbWndExtra = CBHATCHWNDEXTRA;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.hCursor = NULL;
|
||
|
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
||
|
wc.lpszMenuName = NULL;
|
||
|
wc.lpszClassName = szHatchWinClassName;
|
||
|
|
||
|
if (RegisterClass(&wc)) {
|
||
|
|
||
|
// Save class name for later unregistering
|
||
|
pstrRegisteredClasses[HATCH_WNDCLASS] = szHatchWinClassName;
|
||
|
|
||
|
// Get system metrics
|
||
|
iBorder = GetProfileInt(TEXT("windows"),
|
||
|
TEXT("OleInPlaceBorderWidth"), 4);
|
||
|
iDragMinDist = GetProfileInt(TEXT("windows"),
|
||
|
TEXT("DragMinDist"), DD_DEFDRAGMINDIST);
|
||
|
iDragDelay = GetProfileInt(TEXT("windows"),
|
||
|
TEXT("DragDelay"), DD_DEFDRAGDELAY);
|
||
|
|
||
|
// Load the arrow cursors
|
||
|
for (i = IDC_CURS_MIN; i <= IDC_CURS_MAX; i++) {
|
||
|
hCursTable[i - IDC_CURS_MIN] = LoadCursor(g_hInstance, MAKEINTRESOURCE(i));
|
||
|
}
|
||
|
|
||
|
// Create brushes for hatching and drag region
|
||
|
hBM = CreateBitmap(8, 8, 1, 1, wHatchBmp);
|
||
|
if ( NULL != hBM ) {
|
||
|
hBrHatch = CreatePatternBrush(hBM);
|
||
|
DeleteObject(hBM);
|
||
|
}
|
||
|
|
||
|
hBM = CreateBitmap(8, 8, 1, 1, wGrayBmp);
|
||
|
if ( NULL != hBM ) {
|
||
|
hBrGray = CreatePatternBrush(hBM);
|
||
|
DeleteObject(hBM);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
END_CRITICAL_SECTION
|
||
|
|
||
|
if (pstrRegisteredClasses[HATCH_WNDCLASS] == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
lptrID = uID;
|
||
|
|
||
|
m_hWnd = CreateWindowEx(
|
||
|
WS_EX_NOPARENTNOTIFY,
|
||
|
szHatchWinClassName,
|
||
|
szHatchWinClassName,
|
||
|
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||
|
0,
|
||
|
0,
|
||
|
100,
|
||
|
100,
|
||
|
hWndParent,
|
||
|
(HMENU)lptrID,
|
||
|
g_hInstance,
|
||
|
this);
|
||
|
|
||
|
m_uID = uID;
|
||
|
m_hWndAssociate = hWndAssoc;
|
||
|
m_hWndParent = hWndParent;
|
||
|
|
||
|
|
||
|
return (NULL != m_hWnd);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CHatchWin::HwndAssociateSet
|
||
|
* CHatchWin::HwndAssociateGet
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Sets (Set) or retrieves (Get) the associate window of the
|
||
|
* hatch window.
|
||
|
*
|
||
|
* Parameters: (Set only)
|
||
|
* hWndAssoc HWND to set as the associate.
|
||
|
*
|
||
|
* Return Value:
|
||
|
* HWND Previous (Set) or current (Get) associate
|
||
|
* window.
|
||
|
*/
|
||
|
|
||
|
HWND CHatchWin::HwndAssociateSet(HWND hWndAssoc)
|
||
|
{
|
||
|
HWND hWndT = m_hWndAssociate;
|
||
|
|
||
|
m_hWndAssociate = hWndAssoc;
|
||
|
return hWndT;
|
||
|
}
|
||
|
|
||
|
HWND CHatchWin::HwndAssociateGet(void)
|
||
|
{
|
||
|
return m_hWndAssociate;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* CHatchWin::RectsSet
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Changes the size and position of the hatch window and the child
|
||
|
* window within it using a position rectangle for the child and
|
||
|
* a clipping rectangle for the hatch window and child. The hatch
|
||
|
* window occupies prcPos expanded by the hatch border and clipped
|
||
|
* by prcClip. The child window is fit to prcPos to give the
|
||
|
* proper scaling, but it clipped to the hatch window which
|
||
|
* therefore clips it to prcClip without affecting the scaling.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* prcPos LPRECT providing the position rectangle.
|
||
|
* prcClip LPRECT providing the clipping rectangle.
|
||
|
*
|
||
|
* Return Value:
|
||
|
* None
|
||
|
*/
|
||
|
|
||
|
void CHatchWin::RectsSet(LPRECT prcPos, LPRECT prcClip)
|
||
|
{
|
||
|
RECT rc;
|
||
|
RECT rcPos;
|
||
|
UINT uPosFlags = SWP_NOZORDER | SWP_NOACTIVATE;
|
||
|
BOOL bChanged = TRUE;
|
||
|
|
||
|
// If new rectangles, save them
|
||
|
if (prcPos != NULL) {
|
||
|
|
||
|
bChanged = !EqualRect ( prcPos, &m_rcPos );
|
||
|
|
||
|
m_rcPos = *prcPos;
|
||
|
|
||
|
// If clipping rect supplied, use it
|
||
|
// else just use the position rect again
|
||
|
if (prcClip != NULL) {
|
||
|
if ( !bChanged )
|
||
|
bChanged = !EqualRect ( prcClip, &m_rcClip );
|
||
|
m_rcClip = *prcClip;
|
||
|
} else {
|
||
|
m_rcClip = m_rcPos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( bChanged ) {
|
||
|
|
||
|
// Expand position rect to include hatch border
|
||
|
rcPos = m_rcPos;
|
||
|
InflateRect(&rcPos, m_iBorder, m_iBorder);
|
||
|
|
||
|
// Clip with clipping rect to get actual window rect
|
||
|
IntersectRect(&rc, &rcPos, &m_rcClip);
|
||
|
|
||
|
// Save hatch wnd origin relative to clipped window
|
||
|
m_ptHatchOrg.x = rcPos.left - rc.left;
|
||
|
m_ptHatchOrg.y = rcPos.top - rc.top;
|
||
|
|
||
|
// Set flag to avoid reentrant call from window proc
|
||
|
m_bResizeInProgress = TRUE;
|
||
|
|
||
|
// Offset child window from hatch rect by border width
|
||
|
// (maintaining its original size)
|
||
|
SetWindowPos(m_hWndKid, NULL, m_ptHatchOrg.x + m_iBorder, m_ptHatchOrg.y + m_iBorder,
|
||
|
m_rcPos.right - m_rcPos.left, m_rcPos.bottom - m_rcPos.top, uPosFlags);
|
||
|
|
||
|
// Position the hatch window
|
||
|
SetWindowPos(m_hWnd, NULL, rc.left, rc.top, rc.right - rc.left,
|
||
|
rc.bottom - rc.top, uPosFlags);
|
||
|
|
||
|
m_bResizeInProgress = FALSE;
|
||
|
}
|
||
|
|
||
|
// This is here to ensure that the control background gets redrawn
|
||
|
// On a UI deactivate, the VC test container erases the control window
|
||
|
// between the WM_ERASEBKGND and WM_PAINT, so the background ends up
|
||
|
// the container color instead of the control color
|
||
|
if (m_iBorder == 0)
|
||
|
InvalidateRect(m_hWndKid, NULL, TRUE);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* CHatchWin::ChildSet
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Assigns a child window to this hatch window.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* hWndKid HWND of the child window.
|
||
|
*
|
||
|
* Return Value:
|
||
|
* None
|
||
|
*/
|
||
|
|
||
|
void CHatchWin::ChildSet(HWND hWndKid)
|
||
|
{
|
||
|
m_hWndKid = hWndKid;
|
||
|
|
||
|
if (NULL != hWndKid)
|
||
|
{
|
||
|
SetParent(hWndKid, m_hWnd);
|
||
|
|
||
|
//Insure this is visible when the hatch window becomes visible.
|
||
|
ShowWindow(hWndKid, SW_SHOW);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CHatchWin::OnLeftDown(INT x, INT y)
|
||
|
{
|
||
|
m_ptDown.x = x;
|
||
|
m_ptDown.y = y;
|
||
|
|
||
|
SetCapture(m_hWnd);
|
||
|
|
||
|
m_uDragMode = DRAG_PENDING;
|
||
|
|
||
|
SetTimer(m_hWnd, IDTIMER_DEBOUNCE, iDragDelay, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CHatchWin::OnLeftUp(void)
|
||
|
{
|
||
|
switch (m_uDragMode) {
|
||
|
|
||
|
case DRAG_PENDING:
|
||
|
|
||
|
KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
|
||
|
ReleaseCapture();
|
||
|
break;
|
||
|
|
||
|
case DRAG_ACTIVE:
|
||
|
|
||
|
// Erase and release drag region
|
||
|
if ( NULL != m_hRgnDrag ) {
|
||
|
DrawDragRgn(m_hWndParent, m_hRgnDrag);
|
||
|
DeleteObject(m_hRgnDrag);
|
||
|
m_hRgnDrag = NULL;
|
||
|
}
|
||
|
|
||
|
ReleaseCapture();
|
||
|
|
||
|
// Inform associated window of change
|
||
|
if ( !EqualRect(&m_rectNew, &m_rcPos) ) {
|
||
|
SendMessage(m_hWndAssociate, WM_COMMAND,
|
||
|
MAKEWPARAM(m_uID, HWN_RESIZEREQUESTED),
|
||
|
(LPARAM)&m_rectNew);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
m_uDragMode = DRAG_IDLE;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CHatchWin::OnMouseMove(INT x, INT y)
|
||
|
{
|
||
|
INT dx, dy;
|
||
|
HRGN hRgnNew, hRgnDiff;
|
||
|
UINT uResizeFlags;
|
||
|
|
||
|
INT iWidth, iHeight;
|
||
|
INT xHit, yHit;
|
||
|
|
||
|
static INT xPrev, yPrev;
|
||
|
|
||
|
|
||
|
if (x == xPrev && y == yPrev)
|
||
|
return;
|
||
|
|
||
|
xPrev = x;
|
||
|
yPrev = y;
|
||
|
|
||
|
switch (m_uDragMode)
|
||
|
{
|
||
|
|
||
|
case DRAG_IDLE:
|
||
|
|
||
|
// Adjust to hatch window coordinates
|
||
|
x -= m_ptHatchOrg.x;
|
||
|
y -= m_ptHatchOrg.y;
|
||
|
|
||
|
iWidth = m_rcPos.right - m_rcPos.left + 2 * m_iBorder;
|
||
|
iHeight = m_rcPos.bottom - m_rcPos.top + 2 * m_iBorder;
|
||
|
|
||
|
// Determine if x is within a handle
|
||
|
if (x <= m_iBorder)
|
||
|
xHit = X_LEFT;
|
||
|
else if (x >= iWidth - m_iBorder)
|
||
|
xHit = X_RIGHT;
|
||
|
else if (x >= (iWidth - m_iBorder)/2 && x <= (iWidth + m_iBorder)/2)
|
||
|
xHit = X_MIDDLE;
|
||
|
else
|
||
|
xHit = NO_HIT;
|
||
|
|
||
|
// Determine is y within a handle
|
||
|
if (y <= m_iBorder)
|
||
|
yHit = Y_TOP;
|
||
|
else if (y >= iHeight - m_iBorder)
|
||
|
yHit = Y_BOTTOM;
|
||
|
else if (y > (iHeight - m_iBorder)/2 && y < (iHeight + m_iBorder)/2)
|
||
|
yHit = Y_MIDDLE;
|
||
|
else
|
||
|
yHit = NO_HIT;
|
||
|
|
||
|
// Compute handle code
|
||
|
// if no handle hit, set to 4 (drag full object)
|
||
|
if (xHit != NO_HIT && yHit != NO_HIT)
|
||
|
m_uHdlCode = xHit + 3 * yHit;
|
||
|
else
|
||
|
m_uHdlCode = 4;
|
||
|
|
||
|
// Set cursor to match handle
|
||
|
SetCursor(hCursTable[uCursIDTable[m_uHdlCode] - IDC_CURS_MIN]);
|
||
|
break;
|
||
|
|
||
|
case DRAG_PENDING:
|
||
|
|
||
|
// Start resize if movement threshold exceeded
|
||
|
dx = (x >= m_ptDown.x) ? (x - m_ptDown.x) : (m_ptDown.x - x);
|
||
|
dy = (y >= m_ptDown.y) ? (y - m_ptDown.y) : (m_ptDown.y - y);
|
||
|
|
||
|
if (dx > iDragMinDist || dy > iDragMinDist) {
|
||
|
KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
|
||
|
|
||
|
// Create and display initial drag region
|
||
|
m_hRgnDrag = CreateDragRgn(&m_rcPos);
|
||
|
|
||
|
if ( NULL != m_hRgnDrag ) {
|
||
|
DrawDragRgn(m_hWndParent, m_hRgnDrag);
|
||
|
|
||
|
// Initialize new rect
|
||
|
m_rectNew = m_rcPos;
|
||
|
|
||
|
m_uDragMode = DRAG_ACTIVE;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DRAG_ACTIVE:
|
||
|
|
||
|
dx = x - m_ptDown.x;
|
||
|
dy = y - m_ptDown.y;
|
||
|
|
||
|
// Compute new rect by applying deltas to selected edges
|
||
|
// of original position rect
|
||
|
uResizeFlags = uSizingTable[m_uHdlCode];
|
||
|
|
||
|
if (uResizeFlags & SIZING_ALL) {
|
||
|
m_rectNew.left = m_rcPos.left + dx;
|
||
|
m_rectNew.top = m_rcPos.top + dy;
|
||
|
m_rectNew.right = m_rcPos.right + dx;
|
||
|
m_rectNew.bottom = m_rcPos.bottom + dy;
|
||
|
} else {
|
||
|
if (uResizeFlags & SIZING_TOP) {
|
||
|
m_rectNew.top = m_rcPos.top + dy;
|
||
|
|
||
|
if (m_rectNew.bottom - m_rectNew.top < MIN_SIZE)
|
||
|
m_rectNew.top = m_rectNew.bottom - MIN_SIZE;
|
||
|
}
|
||
|
|
||
|
if (uResizeFlags & SIZING_BOTTOM) {
|
||
|
m_rectNew.bottom = m_rcPos.bottom + dy;
|
||
|
|
||
|
if (m_rectNew.bottom - m_rectNew.top < MIN_SIZE)
|
||
|
m_rectNew.bottom = m_rectNew.top + MIN_SIZE;
|
||
|
}
|
||
|
|
||
|
if (uResizeFlags & SIZING_LEFT) {
|
||
|
m_rectNew.left = m_rcPos.left + dx;
|
||
|
|
||
|
if (m_rectNew.right - m_rectNew.left < MIN_SIZE)
|
||
|
m_rectNew.left = m_rectNew.right - MIN_SIZE;
|
||
|
}
|
||
|
|
||
|
if (uResizeFlags & SIZING_RIGHT) {
|
||
|
m_rectNew.right = m_rcPos.right + dx;
|
||
|
|
||
|
if (m_rectNew.right - m_rectNew.left < MIN_SIZE)
|
||
|
m_rectNew.right = m_rectNew.left + MIN_SIZE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Compute new drag region
|
||
|
hRgnNew = CreateDragRgn(&m_rectNew);
|
||
|
|
||
|
if ( NULL != hRgnNew ) {
|
||
|
// Repaint difference between old and new regions (No Flicker!)
|
||
|
hRgnDiff = CreateRectRgn(0,0,0,0);
|
||
|
if ( NULL != m_hRgnDrag
|
||
|
&& NULL != hRgnDiff ) {
|
||
|
CombineRgn(hRgnDiff, m_hRgnDrag, hRgnNew, RGN_XOR);
|
||
|
DrawDragRgn(m_hWndParent, hRgnDiff);
|
||
|
} else {
|
||
|
DrawDragRgn(m_hWndParent, hRgnNew);
|
||
|
}
|
||
|
|
||
|
if ( NULL != hRgnDiff ) {
|
||
|
DeleteObject ( hRgnDiff );
|
||
|
}
|
||
|
// Update current region
|
||
|
if ( NULL != m_hRgnDrag ) {
|
||
|
DeleteObject(m_hRgnDrag);
|
||
|
}
|
||
|
m_hRgnDrag = hRgnNew;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void CHatchWin::OnTimer()
|
||
|
{
|
||
|
if ( DRAG_PENDING == m_uDragMode ) {
|
||
|
KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
|
||
|
// Create and display initial drag region
|
||
|
m_hRgnDrag = CreateDragRgn(&m_rcPos);
|
||
|
|
||
|
if ( NULL != m_hRgnDrag ) {
|
||
|
DrawDragRgn(m_hWndParent, m_hRgnDrag);
|
||
|
// Initialize new rect
|
||
|
m_rectNew = m_rcPos;
|
||
|
|
||
|
m_uDragMode = DRAG_ACTIVE;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CHatchWin::OnPaint()
|
||
|
{
|
||
|
HDC hDC;
|
||
|
RECT rc;
|
||
|
PAINTSTRUCT ps;
|
||
|
INT iWidth, iHeight;
|
||
|
|
||
|
hDC = BeginPaint(m_hWnd, &ps);
|
||
|
|
||
|
// setup hatch rect in window's coord system
|
||
|
iWidth = m_rcPos.right - m_rcPos.left + 2 * m_iBorder;
|
||
|
iHeight = m_rcPos.bottom - m_rcPos.top + 2 * m_iBorder;
|
||
|
|
||
|
SetRect(&rc, m_ptHatchOrg.x, m_ptHatchOrg.y,
|
||
|
m_ptHatchOrg.x + iWidth,
|
||
|
m_ptHatchOrg.y + iHeight);
|
||
|
|
||
|
DrawShading(hDC, &rc);
|
||
|
DrawHandles(hDC, &rc);
|
||
|
|
||
|
EndPaint(m_hWnd, &ps);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CHatchWin::ShowHatch
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Turns hatching on and off; turning the hatching off changes
|
||
|
* the size of the window to be exactly that of the child, leaving
|
||
|
* everything else the same. The result is that we don't have
|
||
|
* to turn off drawing because our own WM_PAINT will never be
|
||
|
* called.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* fHatch BOOL indicating to show (TRUE) or hide (FALSE)
|
||
|
the hatching.
|
||
|
*
|
||
|
* Return Value:
|
||
|
* None
|
||
|
*/
|
||
|
|
||
|
void CHatchWin::ShowHatch(BOOL fHatch)
|
||
|
{
|
||
|
/*
|
||
|
* All we have to do is set the border to zero and
|
||
|
* call SetRects again with the last rectangles the
|
||
|
* child sent to us.
|
||
|
*/
|
||
|
|
||
|
m_iBorder = fHatch ? iBorder : 0;
|
||
|
RectsSet(NULL, NULL);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* CHatchWin::Window
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Returns the window handle associated with this object.
|
||
|
*
|
||
|
* Return Value:
|
||
|
* HWND Window handle for this object
|
||
|
*/
|
||
|
|
||
|
HWND CHatchWin::Window(void)
|
||
|
{
|
||
|
return m_hWnd;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* HatchWndProc
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Standard window procedure for the Hatch Window
|
||
|
*/
|
||
|
|
||
|
LRESULT APIENTRY HatchWndProc(HWND hWnd, UINT iMsg
|
||
|
, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
PCHatchWin phw;
|
||
|
|
||
|
phw = (PCHatchWin)GetWindowLongPtr(hWnd, HWWL_STRUCTURE);
|
||
|
|
||
|
switch (iMsg)
|
||
|
{
|
||
|
case WM_CREATE:
|
||
|
phw = (PCHatchWin)((LPCREATESTRUCT)lParam)->lpCreateParams;
|
||
|
SetWindowLongPtr(hWnd, HWWL_STRUCTURE, (INT_PTR)phw);
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
phw->m_hWnd = NULL;
|
||
|
break;
|
||
|
|
||
|
case WM_PAINT:
|
||
|
phw->OnPaint();
|
||
|
break;
|
||
|
|
||
|
case WM_SIZE:
|
||
|
// If this resize is not due to RectsSet then forward it
|
||
|
// to adjust our internal control window
|
||
|
if (!phw->m_bResizeInProgress)
|
||
|
{
|
||
|
RECT rc;
|
||
|
POINT pt;
|
||
|
|
||
|
// Get new rect in container coords
|
||
|
GetWindowRect(hWnd, &rc);
|
||
|
|
||
|
// Convert to parent client coords
|
||
|
pt.x = pt.y = 0;
|
||
|
ClientToScreen(GetParent(hWnd), &pt);
|
||
|
OffsetRect(&rc,-pt.x, -pt.y);
|
||
|
|
||
|
// Resize control
|
||
|
phw->RectsSet(&rc, NULL);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_MOUSEMOVE:
|
||
|
phw->OnMouseMove((short)LOWORD(lParam),(short)HIWORD(lParam));
|
||
|
break;
|
||
|
|
||
|
case WM_LBUTTONDOWN:
|
||
|
phw->OnLeftDown((short)LOWORD(lParam),(short)HIWORD(lParam));
|
||
|
break;
|
||
|
|
||
|
case WM_LBUTTONUP:
|
||
|
phw->OnLeftUp();
|
||
|
break;
|
||
|
|
||
|
case WM_TIMER:
|
||
|
phw->OnTimer();
|
||
|
break;
|
||
|
|
||
|
case WM_SETFOCUS:
|
||
|
//We need this since the container will SetFocus to us.
|
||
|
if (NULL != phw->m_hWndKid)
|
||
|
SetFocus(phw->m_hWndKid);
|
||
|
break;
|
||
|
|
||
|
case WM_LBUTTONDBLCLK:
|
||
|
/*
|
||
|
* If the double click was within m_dBorder of an
|
||
|
* edge, send the HWN_BORDERDOUBLECLICKED notification.
|
||
|
*
|
||
|
* Because we're always sized just larger than our child
|
||
|
* window by the border width, we can only *get* this
|
||
|
* message when the mouse is on the border. So we can
|
||
|
* just send the notification.
|
||
|
*/
|
||
|
|
||
|
if (NULL!=phw->m_hWndAssociate)
|
||
|
{
|
||
|
SendMessage(phw->m_hWndAssociate, WM_COMMAND,
|
||
|
MAKEWPARAM(phw->m_uID,HWN_BORDERDOUBLECLICKED),
|
||
|
(LPARAM)hWnd);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return DefWindowProc(hWnd, iMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return 0L;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRGN CreateDragRgn(LPRECT pRect)
|
||
|
{
|
||
|
HRGN hRgnIn;
|
||
|
HRGN hRgnOut;
|
||
|
HRGN hRgnRet = NULL;
|
||
|
|
||
|
if ( NULL != pRect ) {
|
||
|
|
||
|
hRgnRet = CreateRectRgn(0,0,0,0);
|
||
|
|
||
|
hRgnIn = CreateRectRgn(pRect->left, pRect->top,pRect->right, pRect->bottom);
|
||
|
hRgnOut = CreateRectRgn(pRect->left - iBorder, pRect->top - iBorder,
|
||
|
pRect->right + iBorder, pRect->bottom + iBorder);
|
||
|
|
||
|
if ( NULL != hRgnOut
|
||
|
&& NULL != hRgnIn
|
||
|
&& NULL != hRgnRet ) {
|
||
|
CombineRgn(hRgnRet, hRgnOut, hRgnIn, RGN_DIFF);
|
||
|
}
|
||
|
if ( NULL != hRgnIn ) {
|
||
|
DeleteObject(hRgnIn);
|
||
|
}
|
||
|
if ( NULL != hRgnOut ) {
|
||
|
DeleteObject(hRgnOut);
|
||
|
}
|
||
|
}
|
||
|
return hRgnRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
void DrawDragRgn(HWND hWnd, HRGN hRgn)
|
||
|
{
|
||
|
LONG lWndStyle;
|
||
|
INT iMapMode;
|
||
|
HDC hDC;
|
||
|
RECT rc;
|
||
|
HBRUSH hBr;
|
||
|
COLORREF crText;
|
||
|
|
||
|
// Turn off clipping by children
|
||
|
lWndStyle = GetWindowLong(hWnd, GWL_STYLE);
|
||
|
SetWindowLong(hWnd, GWL_STYLE, lWndStyle & ~WS_CLIPCHILDREN);
|
||
|
|
||
|
// Prepare DC
|
||
|
hDC = GetDC(hWnd);
|
||
|
|
||
|
if ( NULL != hDC ) {
|
||
|
iMapMode = SetMapMode(hDC, MM_TEXT);
|
||
|
hBr = (HBRUSH)SelectObject(hDC, hBrGray);
|
||
|
crText = SetTextColor(hDC, RGB(255, 255, 255));
|
||
|
|
||
|
SelectClipRgn(hDC, hRgn);
|
||
|
GetClipBox(hDC, &rc);
|
||
|
|
||
|
PatBlt(hDC, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATINVERT);
|
||
|
|
||
|
// Restore DC
|
||
|
SelectObject(hDC, hBr);
|
||
|
SetTextColor(hDC, crText);
|
||
|
SetMapMode(hDC, iMapMode);
|
||
|
SelectClipRgn(hDC, NULL);
|
||
|
ReleaseDC(hWnd, hDC);
|
||
|
}
|
||
|
|
||
|
SetWindowLong(hWnd, GWL_STYLE, lWndStyle);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* DrawShading
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Draw a hatch border ourside the rectable given.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* prc LPRECT containing the rectangle.
|
||
|
* hDC HDC on which to draw.
|
||
|
* cWidth UINT width of the border to draw. Ignored
|
||
|
* if dwFlags has UI_SHADE_FULLRECT.
|
||
|
*
|
||
|
* Return Value:
|
||
|
* None
|
||
|
*/
|
||
|
|
||
|
void DrawShading(HDC hDC, LPRECT prc)
|
||
|
{
|
||
|
HBRUSH hBROld;
|
||
|
RECT rc;
|
||
|
UINT cx, cy;
|
||
|
COLORREF crText;
|
||
|
COLORREF crBk;
|
||
|
const DWORD dwROP = 0x00A000C9L; //DPa
|
||
|
|
||
|
if (NULL==prc || NULL==hDC)
|
||
|
return;
|
||
|
|
||
|
hBROld = (HBRUSH)SelectObject(hDC, hBrHatch);
|
||
|
|
||
|
rc = *prc;
|
||
|
cx = rc.right - rc.left;
|
||
|
cy = rc.bottom - rc.top;
|
||
|
|
||
|
crText = SetTextColor(hDC, RGB(255, 255, 255));
|
||
|
crBk = SetBkColor(hDC, RGB(0, 0, 0));
|
||
|
|
||
|
PatBlt(hDC, rc.left, rc.top, cx, iBorder, dwROP);
|
||
|
PatBlt(hDC, rc.left, rc.top, iBorder, cy, dwROP);
|
||
|
PatBlt(hDC, rc.right-iBorder, rc.top, iBorder, cy, dwROP);
|
||
|
PatBlt(hDC, rc.left, rc.bottom-iBorder, cx, iBorder, dwROP);
|
||
|
|
||
|
SetTextColor(hDC, crText);
|
||
|
SetBkColor(hDC, crBk);
|
||
|
SelectObject(hDC, hBROld);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void DrawHandles (HDC hDC, LPRECT prc)
|
||
|
{
|
||
|
HPEN hPenOld;
|
||
|
HBRUSH hBROld;
|
||
|
INT left,right,top,bottom;
|
||
|
|
||
|
#define DrawHandle(x,y) Rectangle(hDC, x, y, (x) + iBorder + 1, (y) + iBorder + 1)
|
||
|
|
||
|
hPenOld = (HPEN)SelectObject(hDC, (HPEN)GetStockObject(BLACK_PEN));
|
||
|
hBROld = (HBRUSH)SelectObject(hDC, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
||
|
|
||
|
left = prc->left;
|
||
|
right = prc->right - iBorder;
|
||
|
top = prc->top;
|
||
|
bottom = prc->bottom - iBorder;
|
||
|
|
||
|
DrawHandle(left, top);
|
||
|
DrawHandle(left, (top + bottom)/2);
|
||
|
DrawHandle(left, bottom);
|
||
|
|
||
|
DrawHandle(right, top);
|
||
|
DrawHandle(right, (top + bottom)/2);
|
||
|
DrawHandle(right, bottom);
|
||
|
|
||
|
DrawHandle((left + right)/2, top);
|
||
|
DrawHandle((left + right)/2, bottom);
|
||
|
|
||
|
SelectObject(hDC, hPenOld);
|
||
|
SelectObject(hDC, hBROld);
|
||
|
}
|