home *** CD-ROM | disk | FTP | other *** search
- // MRCEXT: Micro Focus Extension DLL for MFC 2.1+
- // Copyright (C)1994-5 Micro Focus Inc, 2465 East Bayshore Rd, Palo Alto, CA 94303.
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation. In addition, you may also charge for any
- // application using MRCEXT, and are under no obligation to supply source
- // code. You must accredit Micro Focus Inc in the "About Box", or banner
- // of your application.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should also have received a copy of the GNU General Public License with this
- // software, also indicating additional rights you have when using MRCEXT.
- //
- //
- // DRAGDOCK.CPP
- // $Date: 10 Jan 1996 12:11:18 $
- // $Revision: 1.2 $
- // $Author: MRC $
- // CDragDockContext class
- //
- // This replaces the MFC CDockContext class. It provides the "dragging" user interface,
- // and includes some extra features that try to indicate exactly where a bar will
- // dock.
- //
- // The gateway MFC gives us to work with is:
- // 1) CControlBar::EnableDocking() creates the dock context for the control bar - so it's
- // important to use the CMRC...Frame.. implementation of EnableDocking().
- //
- // 2) Other than the constructor/destructor, the only function access outside this class
- // is to StartDrag(CPoint pt), called when we want to start dragging the control bar.
- //
- // The other important tie-ins are the call to Dock/Float control bar which we need to handle
- // with the same interpretation of parameters as the existing MFC implementation.
-
- #include "mrcstafx.h"
- #include "mrcext.h"
- #include "mrcpriv.h"
- #include "mrcresrc.h"
-
- extern MRC_AUX_DATA afxData;
-
- #define HORZF(dw) (dw & CBRS_ORIENT_HORZ)
- #define VERTF(dw) (dw & CBRS_ORIENT_VERT)
-
- static void AdjustRectangle(CRect& rect, CPoint pt)
- // adjust supplied rectangle, so that point, pt is inside it.
- {
- int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) :
- (pt.x > rect.right) ? (pt.x - rect.right) : 0;
- int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) :
- (pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0;
- rect.OffsetRect(nXOffset, nYOffset);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDragDockContext
- // static members
-
- CDragDockContext::CDragDockContext(CControlBar* pBar) : CDockContext(pBar)
- {
- }
-
-
- CDragDockContext::~CDragDockContext()
- {
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CDragDockContext operations
-
- //---------------------------------------------------------------------------
- void CDragDockContext::StartDrag(CPoint pt)
- // start dragging. This is the only routine exposed externally.
- // pt = mouse position at start of drag (screen co-ords)
- //---------------------------------------------------------------------------
- {
- ASSERT_VALID(m_pBar);
- ASSERT(m_pBar->IsKindOf(RUNTIME_CLASS(CMRCSizeControlBar)));
-
- CMRCSizeControlBar *pSzBar = (CMRCSizeControlBar *) m_pBar;
-
- // get styles from bar
- m_dwDockStyle = m_pBar->m_dwDockStyle;
- m_dwStyle = m_pBar->m_dwStyle & CBRS_ALIGN_ANY;
- ASSERT(m_dwStyle != 0);
-
- // check to see we're not hanging from a CMRCMDIFloatWnd. Disallow dragging if we are...
- if (m_pBar->IsFloating())
- {
- CFrameWnd * pFrameWnd = m_pBar->GetParentFrame();
- ASSERT(pFrameWnd != NULL);
- ASSERT(pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
- if (pFrameWnd->IsKindOf(RUNTIME_CLASS(CMRCMDIFloatWnd)))
- return; // do nothing if floating inside a CMRCMDIFloatWnd
- }
-
- // dragging has started message (only if window will actually dock !)
- if ((m_dwDockStyle & CBRS_ALIGN_ANY) != 0)
- AfxGetMainWnd()->SendMessage(WM_SETMESSAGESTRING, IDS_MRC_STARTDOCKING);
-
- // 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;
- ASSERT(msg.message == WM_PAINT);
- DispatchMessage(&msg);
- }
-
- // initialize drag state
- m_rectLast.SetRectEmpty();
- m_sizeLast.cx = m_sizeLast.cy = 0;
- m_bForceFrame = m_bFlip = m_bDitherLast = FALSE;
-
-
- // get current bar location
- CRect rect;
- m_pBar->GetWindowRect(rect);
- m_ptLast = pt;
- m_ptStart = pt;
- BOOL bHorz = HORZF(m_dwStyle);
-
- // MFC includes code for flipping orientation using the shift key - I wasn't keen
- // on this... (sorry) so I've left it out for now. Some references are still left
- // in for it, in case I decide to implement it.
-
- // Start by working out the possible rectangles that dragging could result in.
- // These are:
- // m_rectFrameDragHorz : floating frame, horizontal orientation
- // m_rectFrameDragVert : floating frame, vertical orientation (not used, 'cos
- // flipping not allowed)
- //
- // m_rectDragHorz : docking horizontally, another bar already on this row
- // m_rectDragVert : docking vertically, another bar already on this row
-
- // m_rectDragHorzAlone : docking horizontally, on a new row
- // m_rectDragVertAlone : docking vertically, on a new row
-
-
- // calculate the size of the docking area, used below
- // FIXME: for now I'm just using the CFrameWnd client area.
- CRect rcFrameClient;
- m_pDockSite->GetClientRect(rcFrameClient);
- m_pDockSite->ClientToScreen(rcFrameClient);
- int nDockAreaWidth = rcFrameClient.Width();
- int nDockAreaHeight = rcFrameClient.Height();
-
- CSize HorzAloneSize(nDockAreaWidth, pSzBar->m_HorzDockSize.cy);
- CSize VertAloneSize(pSzBar->m_VertDockSize.cx, nDockAreaHeight);
-
- m_rectDragHorzAlone = CRect(CPoint(rcFrameClient.left, rect.top), HorzAloneSize);
- m_rectDragVertAlone = CRect(CPoint(rect.left, rcFrameClient.top), VertAloneSize);
-
- // sizes to use when docking into a row that already has some bars.
- // use the stored sizes - unless they are > the max dock area - in which case make a guess.
- if (pSzBar->m_VertDockSize.cy >= nDockAreaHeight - 16)
- VertAloneSize.cy = nDockAreaHeight / 2;
- else
- VertAloneSize.cy = pSzBar->m_VertDockSize.cy;
-
- if (pSzBar->m_HorzDockSize.cx >= nDockAreaWidth - 16)
- HorzAloneSize.cx = nDockAreaWidth / 2;
- else
- HorzAloneSize.cx = pSzBar->m_HorzDockSize.cx;
-
- m_rectDragHorz = CRect(rect.TopLeft(), HorzAloneSize);
- m_rectDragVert = CRect(rect.TopLeft(), VertAloneSize);
-
-
- // rectangle for the floating frame...
- m_rectFrameDragHorz = CRect(rect.TopLeft(), pSzBar->m_FloatSize);
- m_rectFrameDragVert = m_rectFrameDragHorz;
-
- // To work out the size we actually create a floating mini frame, and then see how big
- // it is
- CMiniDockFrameWnd* pFloatFrame =
- m_pDockSite->CreateFloatingFrame(bHorz ? CBRS_ALIGN_TOP : CBRS_ALIGN_LEFT);
- if (pFloatFrame == NULL)
- AfxThrowMemoryException();
- pFloatFrame->CalcWindowRect(&m_rectFrameDragHorz);
- pFloatFrame->CalcWindowRect(&m_rectFrameDragVert);
- m_rectFrameDragHorz.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
- m_rectFrameDragVert.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
- pFloatFrame->DestroyWindow();
-
- // adjust rectangles so that point is inside
- AdjustRectangle(m_rectDragHorz, pt);
- AdjustRectangle(m_rectDragVert, pt);
- AdjustRectangle(m_rectDragHorzAlone, pt);
- AdjustRectangle(m_rectDragVertAlone, pt);
- AdjustRectangle(m_rectFrameDragHorz, pt);
- AdjustRectangle(m_rectFrameDragVert, pt);
-
- // lock window update while dragging
- ASSERT(m_pDC == NULL);
- CWnd* pWnd = CWnd::GetDesktopWindow();
- #ifndef _MAC
- if (pWnd->LockWindowUpdate())
- m_pDC = pWnd->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE);
- else
- #endif
- m_pDC = pWnd->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE);
- ASSERT(m_pDC != NULL);
-
- // initialize tracking state and enter tracking loop
- m_dwOverDockStyle = CanDock();
- Move(pt); // call it here to handle special keys
- Track();
- }
-
-
- void CDragDockContext::Move(CPoint pt)
- {
- CPoint ptOffset = pt - m_ptLast;
-
- #ifdef _MAC
- // prevent dragging the floating window completely under the menu bar
- GDHandle hgd = _AfxFindDevice(pt.x, pt.y);
- if (hgd == NULL || hgd == GetMainDevice() ||
- TestDeviceAttribute(hgd, hasAuxMenuBar))
- {
- CRect rect;
-
- if ((HORZF(m_dwStyle) && !m_bFlip) || (VERTF(m_dwStyle) && m_bFlip))
- rect = m_rectFrameDragHorz;
- else
- rect = m_rectFrameDragVert;
-
- // determine our new position
- rect.OffsetRect(ptOffset);
-
- // keep us on the screen if we were getting too close to the menu bar
- int yMBarBottom = (*hgd)->gdRect.top + GetMBarHeight() + 4;
- if (rect.bottom < yMBarBottom)
- {
- pt.y += yMBarBottom - rect.bottom;
- ptOffset.y += yMBarBottom - rect.bottom;
- }
- }
- #endif
-
- // offset all drag rects to new position
- m_rectDragHorz.OffsetRect(ptOffset);
- m_rectFrameDragHorz.OffsetRect(ptOffset);
- m_rectDragVert.OffsetRect(ptOffset);
- m_rectFrameDragVert.OffsetRect(ptOffset);
-
- // these rectangles only move in 1 direction
- m_rectDragHorzAlone.top += ptOffset.y;
- m_rectDragHorzAlone.bottom += ptOffset.y;
- m_rectDragVertAlone.left += ptOffset.x;
- m_rectDragVertAlone.right += ptOffset.x;
-
- m_rectDragDock.OffsetRect(ptOffset); // new...
- m_ptLast = pt;
-
- // if control key is down don't dock
- m_dwOverDockStyle = m_bForceFrame ? 0 : CanDock();
-
- // update feedback
- DrawFocusRect();
- }
-
-
- void CDragDockContext::OnKey(int nChar, BOOL bDown)
- {
- if (nChar == VK_CONTROL)
- UpdateState(&m_bForceFrame, bDown);
- }
-
-
- void CDragDockContext::EndDrag()
- {
- CancelDrag();
- if (m_ptStart == m_ptLast)
- return;
-
- m_dwOverDockStyle = m_bForceFrame ? 0 : CanDock();
- if (m_dwOverDockStyle != 0)
- {
- CDockBar* pDockBar = GetDockBar();
- ASSERT(pDockBar != NULL);
- // Now we're going to actually dock the window.
-
- // Update the appropriate size in the control bar.
- // Rely on the layout recalculation to spot a window has moved and recalculate
- // the layout. We could perhaps ensure space in the appropriate dockbar at this
- // point, rather than let the layout recalculation behave as default.
- if (HORZF(m_dwOverDockStyle))
- ((CMRCSizeControlBar *) m_pBar)->m_HorzDockSize = m_rectDragDock.Size();
- else
- ((CMRCSizeControlBar *) m_pBar)->m_VertDockSize = m_rectDragDock.Size();
-
- m_pDockSite->DockControlBar(m_pBar, pDockBar, m_rectDragDock);
-
- // if into a sizeable dockbar (always will be, then adjust other bars in the same row
- // to attempt to maintain size
- if (pDockBar->IsKindOf(RUNTIME_CLASS(CSizeDockBar)))
- ((CSizeDockBar *)pDockBar)->AdjustForNewBar(m_pBar);
-
- m_pDockSite->RecalcLayout();
- }
- else
- {
- m_pDockSite->FloatControlBar(m_pBar, m_rectFrameDragHorz.TopLeft(),
- CBRS_ALIGN_TOP | (m_dwDockStyle & CBRS_FLOAT_MULTI));
-
- // set flag to indicate user has moved the bar - done as a style flag on the window.
- CWnd * pFrameWnd = m_pBar->GetParentFrame();
- ASSERT(pFrameWnd->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd)));
- pFrameWnd->ModifyStyle(0, CBRS_MOVED_BY_USER);
- }
-
- }
-
-
- void CDragDockContext::CancelDrag()
- {
- DrawFocusRect(TRUE); // gets rid of focus rect
- ReleaseCapture();
-
- CWnd* pWnd = CWnd::GetDesktopWindow();
- #ifndef _MAC
- pWnd->UnlockWindowUpdate();
- #endif
- if (m_pDC != NULL)
- {
- pWnd->ReleaseDC(m_pDC);
- m_pDC = NULL;
- }
-
- // Tell main window to clear it's status bar
- CWnd *pMainWnd = AfxGetMainWnd();
- ASSERT(pMainWnd != NULL);
- pMainWnd->SendMessage(WM_SETMESSAGESTRING, (WPARAM)AFX_IDS_IDLEMESSAGE);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Implementation
-
- void CDragDockContext::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));
- CBrush* pDitherBrush = CDC::GetHalftoneBrush();
- CBrush* pBrush = pWhiteBrush;
-
- if (m_dwOverDockStyle != 0)
- {
- rect = m_rectDragDock;
- }
- /* if (HORZF(m_dwOverDockStyle))
- rect = m_rectDragHorz;
- else if (VERTF(m_dwOverDockStyle))
- rect = m_rectDragVert; */
- else
- {
- #ifndef _MAC
- // use thick frame instead
- size.cx = GetSystemMetrics(SM_CXFRAME) - CX_BORDER;
- size.cy = GetSystemMetrics(SM_CYFRAME) - CY_BORDER;
- #endif
- rect = m_rectFrameDragHorz;
- pBrush = pDitherBrush;
- }
- if (bRemoveRect)
- size.cx = size.cy = 0;
-
- if ( /*afxData.bWin4 && */
- (HORZF(m_dwOverDockStyle) || VERTF(m_dwOverDockStyle)))
- {
- // looks better one pixel in (makes the bar look pushed down)
- rect.InflateRect(-CX_BORDER, -CY_BORDER);
- }
-
- // draw it and remember last size
- m_pDC->DrawDragRect(&rect, size, &m_rectLast, m_sizeLast,
- pBrush, m_bDitherLast ? pDitherBrush : pWhiteBrush);
- m_rectLast = rect;
- m_sizeLast = size;
- m_bDitherLast = (pBrush == pDitherBrush);
- }
-
-
- void CDragDockContext::UpdateState(BOOL* pFlag, BOOL bNewValue)
- {
- if (*pFlag != bNewValue)
- {
- *pFlag = bNewValue;
- // m_bFlip = (HORZF(m_dwDockStyle) && VERTF(m_dwDockStyle) && m_bFlip); // shift key
- m_dwOverDockStyle = (m_bForceFrame) ? 0 : CanDock();
- DrawFocusRect();
- }
- }
-
-
- DWORD CDragDockContext::CanDock()
- {
- BOOL bStyleHorz;
- DWORD dwDock = 0; // Dock Canidate
- DWORD dwCurr = 0; // Current Orientation
-
- // let's check for something in our current orientation first
- // then if the shift key is not forcing our orientation then
- // check for horizontal or vertical orientations as long
- // as we are close enough
- ASSERT(m_dwStyle != 0);
-
- bStyleHorz = HORZF(m_dwStyle);
-
- m_pTargetDockBar = NULL;
-
- /*
- if (bStyleHorz && HORZF(m_dwDockStyle))
- dwDock = m_pDockSite->CanDock(m_rectDragHorzAlone,
- m_dwDockStyle & ~CBRS_ORIENT_VERT, (CDockBar **)&m_pTargetDockBar);
-
-
- else if (VERTF(m_dwDockStyle))
- dwDock = m_pDockSite->CanDock(m_rectDragVertAlone,
- m_dwDockStyle & ~CBRS_ORIENT_HORZ, (CDockBar **)&m_pTargetDockBar);
- */
- // can simplify this, 'cos most of the rectangles are actually the same
- if (dwDock == 0 && HORZF(m_dwDockStyle) && m_rectDragHorzAlone.PtInRect(m_ptLast))
- {
- dwDock = m_pDockSite->CanDock(m_rectDragHorzAlone,
- m_dwDockStyle & ~CBRS_ORIENT_VERT, (CDockBar **)&m_pTargetDockBar);
- }
- if (dwDock == 0 && VERTF(m_dwDockStyle) && m_rectDragVertAlone.PtInRect(m_ptLast))
- {
- dwDock = m_pDockSite->CanDock(m_rectDragVertAlone,
- m_dwDockStyle & ~CBRS_ORIENT_HORZ, (CDockBar **)&m_pTargetDockBar);
- }
-
- if (dwDock != 0) // will dock somewhere - now look for 1/2 bars on the row...
- {
- if (HORZF(dwDock))
- {
- m_rectDragDock = m_rectDragHorzAlone;
- dwCurr = m_pDockSite->CanDock(m_rectDragHorz,
- m_dwDockStyle & ~CBRS_ORIENT_VERT, (CDockBar **)&m_pTargetDockBar);
- if (dwCurr != 0)
- if (m_pTargetDockBar->BarsOnThisRow (m_pBar, m_rectDragHorzAlone) != 0)
- m_rectDragDock = m_rectDragHorz;
- }
-
- if (VERTF(dwDock))
- {
- m_rectDragDock = m_rectDragVertAlone;
- dwCurr = m_pDockSite->CanDock(m_rectDragVert,
- m_dwDockStyle & ~CBRS_ORIENT_HORZ, (CDockBar **)&m_pTargetDockBar);
- if (dwCurr != 0)
- if (m_pTargetDockBar->BarsOnThisRow (m_pBar, m_rectDragVertAlone) != 0)
- m_rectDragDock = m_rectDragVert;
- }
- }
-
- return dwDock;
- }
-
-
- CDockBar* CDragDockContext::GetDockBar()
- {
- DWORD dw = 0;
- CDockBar* pBar;
- if (HORZF(m_dwOverDockStyle))
- {
- dw = m_pDockSite->CanDock(m_rectDragHorz,
- m_dwOverDockStyle & ~CBRS_ORIENT_VERT, &pBar);
- ASSERT(dw != 0);
- ASSERT(pBar != NULL);
- return pBar;
- }
- if (VERTF(m_dwOverDockStyle))
- {
- dw = m_pDockSite->CanDock(m_rectDragVert,
- m_dwOverDockStyle & ~CBRS_ORIENT_HORZ, &pBar);
- ASSERT(dw != 0);
- ASSERT(pBar != NULL);
- return pBar;
- }
- return NULL;
- }
-
-
- //-------------------------------------------------------------------------------
- BOOL CDragDockContext::Track()
- //-------------------------------------------------------------------------------
- {
- // don't handle if capture already set
- if (::GetCapture() != NULL)
- return FALSE;
-
- // set capture to the window which received this message
- m_pBar->SetCapture();
- ASSERT(m_pBar == CWnd::GetCapture());
-
- // get messages until capture lost or cancelled/accepted
- while(CWnd::GetCapture() == m_pBar)
- {
- MSG msg;
- #ifndef _MAC
- if (!::GetMessage(&msg, NULL, 0, 0))
- #else
- // don't allow yielding while tracking since we don't have LockWindowUpdate
- if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE|PM_NOYIELD))
- continue;
- if (msg.message == WM_QUIT)
- #endif
- {
- AfxPostQuitMessage(msg.wParam);
- break;
- }
-
- switch (msg.message)
- {
- case WM_LBUTTONUP: // drag finished
- EndDrag();
- return TRUE;
-
- case WM_MOUSEMOVE:
- Move(msg.pt);
- break;
-
- case WM_KEYUP:
- OnKey((int)msg.wParam, FALSE);
- break;
-
- case WM_KEYDOWN:
- OnKey((int)msg.wParam, TRUE);
- if (msg.wParam == VK_ESCAPE)
- goto exit_cancel_drag;
- break;
-
- case WM_RBUTTONDOWN:
- goto exit_cancel_drag;
-
- // just dispatch rest of the messages
- default:
- DispatchMessage(&msg);
- break;
- }
- }
-
- exit_cancel_drag: // goto - can't use break as we're inside a switch()
- CancelDrag();
- return FALSE;
- }
-
- IMPLEMENT_DYNAMIC(CSizeDockBar, CDockBar)
-