pjs/cmd/winfe/dragbar.cpp

411 строки
9.7 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "stdafx.h"
#include "dragbar.h"
#include "navfram.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define CX_BORDER 2
#define CY_BORDER 2
CDragBar::CDragBar(CRect& crRect, CNSNavFrame* pDockFrame)
{
// Set our members.
m_bDragging = FALSE;
m_crTracker = crRect;
m_dockedFrame = pDockFrame;
m_bInDeskCoord = FALSE;
}
CDragBar::~CDragBar()
{
// If we were tracking, then let our clipped region go, etc.
if(m_bDragging == TRUE) {
// Release the bounds established on the mouse.
::ClipCursor(NULL);
}
}
void CDragBar::PostNcDestroy( )
{
delete this;
}
void CDragBar::OnDestroy()
{
CWnd::OnDestroy();
}
BEGIN_MESSAGE_MAP(CDragBar, CWnd)
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_SETCURSOR()
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_WM_DESTROY()
ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()
void CDragBar::SetRect(CRect& rect, BOOL inDeskCoord)
{
m_crTracker = rect;
m_bInDeskCoord = FALSE;
MoveWindow(rect);
}
void CDragBar::GetRect(CRect& rect)
{
rect = m_crTracker;
if (m_bInDeskCoord) {
GetDesktopWindow()->MapWindowPoints( m_parentView, &rect);
}
}
void CDragBar::InitLoop()
{
// handle pending WM_PAINT messages
MSG msg;
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
{
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
return;
DispatchMessage(&msg);
}
m_bDitherLast = FALSE;
m_rectLast.SetRectEmpty();
CWnd* pWnd = CWnd::GetDesktopWindow();
if (pWnd->LockWindowUpdate())
m_pDC = pWnd->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE);
else
m_pDC = pWnd->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE);
ASSERT(m_pDC != NULL);
}
void CDragBar::CancelLoop()
{
DrawFocusRect(TRUE); // gets rid of focus rect
ReleaseCapture();
CWnd* pWnd = CWnd::GetDesktopWindow();
#ifdef XP_WIN32
pWnd->UnlockWindowUpdate();
#else
ASSERT(::IsWindow(m_hWnd));
::LockWindowUpdate(NULL);
#endif
if (m_pDC != NULL)
{
pWnd->ReleaseDC(m_pDC);
m_pDC = NULL;
}
}
void CDragBar::DrawFocusRect(BOOL bRemoveRect)
{
ASSERT(m_pDC != NULL);
// default to thin frame
CSize size(CX_BORDER, CY_BORDER);
// determine new rect and size
CRect rect;
CBrush* pWhiteBrush = CBrush::FromHandle((HBRUSH)::GetStockObject(WHITE_BRUSH));
if (bRemoveRect)
size.cx = size.cy = 0;
#ifdef XP_WIN32
CBrush *pBrush = CDC::GetHalftoneBrush();
HBRUSH hOldBrush = NULL;
if(pBrush != NULL) {
hOldBrush = (HBRUSH)SelectObject(m_pDC->m_hDC, pBrush->m_hObject);
}
m_pDC->PatBlt(m_crTracker.left, m_crTracker.top,
m_crTracker.Width(), m_crTracker.Height(), PATINVERT);
if(hOldBrush != NULL) {
SelectObject(m_pDC->m_hDC, hOldBrush);
}
#else
m_pDC->PatBlt(m_crTracker.left, m_crTracker.top, m_crTracker.Width(),
m_crTracker.Height(), DSTINVERT);
#endif
m_rectLast = rect;
m_sizeLast = size;
}
void CDragBar::OnLButtonDown(UINT nFlags, CPoint point)
{
if (!m_dockedFrame->IsTreeVisible())
return;
// Capture mouse events.
InitLoop();
// Mark the point at which the mouse went down.
// This can be used to calculate the relative distance of the movement of the tracker.
m_cpLBDown = point;
// Set tracking state.
m_bDragging = TRUE;
CPoint cursorPt(point);
MapWindowPoints( m_parentView, &cursorPt, 1 );
m_parentView->MapWindowPoints( GetDesktopWindow(), &cursorPt, 1 );
m_ptLast = cursorPt;
CRect parentRect;
CalcClientArea(&parentRect);
::ClientToScreen(m_parentView->GetSafeHwnd(), &parentRect.TopLeft());
::ClientToScreen(m_parentView->GetSafeHwnd(), &parentRect.BottomRight());
::ClipCursor(parentRect);
if (!m_bInDeskCoord) {
m_parentView->MapWindowPoints( GetDesktopWindow(), &m_crTracker);
m_bInDeskCoord = TRUE;
}
// Invert the tracker.
Move(cursorPt); // call it here to handle special keys
Track();
}
void CDragBar::OnRButtonDown(UINT nFlags, CPoint point)
{
m_dockedFrame->CollapseWindow();
}
void CDragBar::EndDrag()
{
CancelLoop();
::ClipCursor(NULL);
// Set that we are no longer tracking.
m_bDragging = FALSE;
CRect tempRect(m_crTracker);
GetDesktopWindow()->MapWindowPoints( m_parentView, &tempRect);
MoveWindow(tempRect);
Invalidate();
m_dockedFrame->m_pSelector->Invalidate();
m_parentView->RecalcLayout();
}
void CDragBar::Move( CPoint point )
{
CPoint ptOffset = point - m_ptLast;
// If we're currently tracking, simply update the coords.
if(m_bDragging == TRUE) {
// Turn off the tracker.
DrawFocusRect();
if (m_orientation == DOCKSTYLE_VERTLEFT ||
(m_orientation == DOCKSTYLE_VERTRIGHT)) {
ptOffset.y = 0;
}
else {
ptOffset.x = 0;
}
m_crTracker.OffsetRect(ptOffset);
// Turn on the tracker.
DrawFocusRect();
m_ptLast = point;
return;
}
}
void CDragBar::OnMouseMove( UINT nFlags, CPoint point )
{
if(m_bDragging == TRUE) return;
if (!m_dockedFrame->IsTreeVisible()) // Cannot drag when tree is closed.
return;
static HCURSOR hcurLast = NULL;
static HCURSOR hcurDestroy = NULL;
static UINT uLastCursorID = 0;
UINT uCursorID;
// Decide which cursor we want to load.
if (m_orientation == DOCKSTYLE_HORZTOP ||
m_orientation == DOCKSTYLE_HORZBOTTOM) {
// Horizontal.
uCursorID = AFX_IDC_VSPLITBAR;
}
else {
// Vertical.
uCursorID = AFX_IDC_HSPLITBAR;
}
// Only if not already loaded.
HCURSOR hcurToDestroy = NULL;
if(uCursorID != uLastCursorID) {
HINSTANCE hInst =
#ifdef _AFXDLL
AfxFindResourceHandle(MAKEINTRESOURCE(uCursorID), RT_GROUP_CURSOR);
#else
AfxGetResourceHandle();
#endif
// Load in another cursor.
hcurToDestroy = hcurDestroy;
hcurDestroy = hcurLast = ::LoadCursor(hInst, MAKEINTRESOURCE(uCursorID));
uLastCursorID = uCursorID;
}
// Set the cursor.
::SetCursor(hcurLast);
// Destroy the previous cursor if need be.
if(hcurToDestroy != NULL) {
::DestroyCursor(hcurToDestroy);
}
}
BOOL CDragBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (nHitTest == HTCLIENT && pWnd == this && !m_bDragging) {
return TRUE; // we will handle it in the mouse move
}
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CDragBar::OnPaint()
{
CPaintDC dc(this); // device context for painting
// The area we're drawing.
CRect crRect;
GetClientRect(crRect);
// Draw it as the button face if no other color available.
WFE_FillSolidRect((CDC *)&dc, crRect, sysInfo.m_clrBtnFace);
#ifndef XP_WIN32
short dockStyle = m_dockedFrame->GetDockStyle();
WFE_FillSolidRect((CDC *)&dc, crRect, RGB(255, 255, 255));
HDC hdc = dc.GetSafeHdc();
::SelectObject(hdc, ::GetStockObject(BLACK_PEN));
if ((dockStyle == DOCKSTYLE_VERTLEFT) || (dockStyle == DOCKSTYLE_VERTRIGHT)) {
::MoveTo(hdc,crRect.left, crRect.top);
::LineTo(hdc,crRect.left, crRect.bottom);
::MoveTo(hdc,crRect.right-1, crRect.top);
::LineTo(hdc,crRect.right-1, crRect.bottom);
}
else {
::MoveTo(hdc,crRect.left, crRect.bottom);
::LineTo(hdc,crRect.right, crRect.bottom);
::MoveTo(hdc,crRect.left, crRect.top);
::LineTo(hdc,crRect.right, crRect.top);
}
#endif
}
void CDragBar::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// Treat same as button down.
OnLButtonDown(nFlags, point);
}
void CDragBar::CalcClientArea(RECT* lpRectClient)
{
AFX_SIZEPARENTPARAMS layout;
#ifdef XP_WIN32
layout.bStretch = FALSE;
layout.sizeTotal.cx = layout.sizeTotal.cy = 0;
#endif
m_parentView->GetClientRect(&layout.rect); // starting rect comes from client rect
CWnd *pView = m_parentView->GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);
HWND hWnd = pView->GetSafeHwnd();
layout.hDWP = NULL; // not actually doing layout
for (HWND hWndChild = ::GetTopWindow(m_parentView->GetSafeHwnd()); hWndChild != NULL;
hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
{
if (hWndChild != hWnd && hWndChild != GetSafeHwnd() && hWndChild != m_dockedFrame->GetSafeHwnd())
::SendMessage(hWndChild, WM_SIZEPARENT, 0, (LPARAM)&layout);
}
short dockStyle = m_dockedFrame->GetDockStyle();
lpRectClient->left = layout.rect.left;
lpRectClient->right = layout.rect.right;
lpRectClient->top = layout.rect.top;
lpRectClient->bottom = layout.rect.bottom;
if (dockStyle == DOCKSTYLE_VERTLEFT)
lpRectClient->left += MIN_CATEGORY_WIDTH;
else if (dockStyle == DOCKSTYLE_VERTRIGHT)
lpRectClient->right -= MIN_CATEGORY_WIDTH;
else if (dockStyle == DOCKSTYLE_HORZTOP)
lpRectClient->top += MIN_CATEGORY_HEIGHT;
else if (dockStyle == DOCKSTYLE_HORZBOTTOM)
lpRectClient->bottom -= MIN_CATEGORY_HEIGHT;
}
BOOL CDragBar::Track()
{
// don't handle if capture already set
if (::GetCapture() != NULL)
return FALSE;
// set capture to the window which received this message
SetCapture();
// get messages until capture lost or cancelled/accepted
while (CWnd::GetCapture() == this) {
MSG msg;
if (!::GetMessage(&msg, NULL, 0, 0))
{
#ifdef XP_WIN32
AfxPostQuitMessage(msg.wParam);
#endif
break;
}
switch (msg.message)
{
case WM_LBUTTONUP:
if (m_bDragging)
m_bDragging = FALSE;
EndDrag();
return TRUE;
case WM_MOUSEMOVE:
if (m_bDragging)
Move(msg.pt);
break;
case WM_RBUTTONDOWN:
CancelLoop();
return FALSE;
// just dispatch rest of the messages
default:
DispatchMessage(&msg);
break;
}
}
CancelLoop();
return FALSE;
}