/* -*- 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; }