|
|
/*--------------------------------------------------------------------------*
* * Microsoft Windows * Copyright (C) Microsoft Corporation, 1992 - 1999 * * File: mdiuisim.cpp * * Contents: Implementation file for CMDIMenuDecoration * * History: 17-Nov-97 jeffro Created * *--------------------------------------------------------------------------*/
#include "stdafx.h"
#include "amc.h"
#include "mdiuisim.h"
struct MDIDataMap { DWORD dwStyle; int nCommand; };
const int cMapEntries = 4;
const MDIDataMap anMDIDataMap[cMapEntries] = { { MMDS_CLOSE, SC_CLOSE }, // DFCS_CAPTIONCLOSE
{ MMDS_MINIMIZE, SC_MINIMIZE }, // DFCS_CAPTIONMIN
{ MMDS_MAXIMIZE, SC_MAXIMIZE }, // DFCS_CAPTIONMAX
{ MMDS_RESTORE, SC_RESTORE }, // DFCS_CAPTIONRESTORE
};
// this array is in the order the decorations are drawn, left-to-right
const int anDrawOrder[cMapEntries] = { DFCS_CAPTIONMIN, DFCS_CAPTIONRESTORE, DFCS_CAPTIONMAX, DFCS_CAPTIONCLOSE };
/*--------------------------------------------------------------------------*
* DrawCaptionControl * * *--------------------------------------------------------------------------*/
static void DrawCaptionControl ( CDC * pdc, LPCRECT pRect, int nIndex, bool fPushed) { const int cxInflate = -1; const int cyInflate = -2; CRect rectDraw = pRect;
rectDraw.InflateRect (cxInflate, cyInflate); rectDraw.OffsetRect ((nIndex == DFCS_CAPTIONMIN) ? 1 : -1, 0);
if (fPushed) nIndex |= DFCS_PUSHED;
pdc->DrawFrameControl (rectDraw, DFC_CAPTION, nIndex); }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::CMouseTrackContext::CMouseTrackContext * * *--------------------------------------------------------------------------*/
CMDIMenuDecoration::CMouseTrackContext::CMouseTrackContext ( CMDIMenuDecoration* pMenuDec, CPoint point) : m_fHotButtonPressed (false), m_pMenuDec (pMenuDec) { ASSERT_VALID (m_pMenuDec);
// set up hit testing rectangles for each button
int cxButton = GetSystemMetrics (SM_CXMENUSIZE); int cyButton = GetSystemMetrics (SM_CYMENUSIZE); DWORD dwStyle = m_pMenuDec->GetStyle (); CRect rectT (0, 0, cxButton, cyButton); for (int i = 0; i < cMapEntries; i++) { int nDataIndex = anDrawOrder[i];
if (dwStyle & anMDIDataMap[nDataIndex].dwStyle) { m_rectButton[nDataIndex] = rectT; rectT.OffsetRect (cxButton, 0); } else m_rectButton[nDataIndex].SetRectEmpty(); }
m_nHotButton = HitTest (point); ASSERT (m_nHotButton != -1);
// if the user clicked on a disbled button, we don't want to track -- punt!
if (!m_pMenuDec->IsSysCommandEnabled (anMDIDataMap[m_nHotButton].nCommand)) AfxThrowUserException ();
// press the hot button initially
ToggleHotButton ();
// capture the mouse
m_pMenuDec->SetCapture (); }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::CMouseTrackContext::~CMouseTrackContext * * *--------------------------------------------------------------------------*/
CMDIMenuDecoration::CMouseTrackContext::~CMouseTrackContext () { ReleaseCapture();
if (m_fHotButtonPressed) ToggleHotButton (); }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::CMouseTrackContext::Track * * *--------------------------------------------------------------------------*/
void CMDIMenuDecoration::CMouseTrackContext::Track (CPoint point) { int nButton = HitTest (point);
/*-----------------------------------------------------*/ /* if we're over the hot button and it's not pressed, */ /* or we're not over the hot button and it is pressed, */ /* toggle the state of the hot button */ /*-----------------------------------------------------*/ if (((nButton != m_nHotButton) && m_fHotButtonPressed) || ((nButton == m_nHotButton) && !m_fHotButtonPressed)) { ToggleHotButton (); } }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::CMouseTrackContext::ToggleHotButton * * *--------------------------------------------------------------------------*/
void CMDIMenuDecoration::CMouseTrackContext::ToggleHotButton () { DrawCaptionControl (&CClientDC (m_pMenuDec), m_rectButton[m_nHotButton], m_nHotButton, m_fHotButtonPressed = !m_fHotButtonPressed); }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::CMouseTrackContext::HitTest * * *--------------------------------------------------------------------------*/
int CMDIMenuDecoration::CMouseTrackContext::HitTest (CPoint point) const { for (int i = 0; i < countof (m_rectButton); i++) { if (m_rectButton[i].PtInRect (point)) return (i); }
return (-1); }
/////////////////////////////////////////////////////////////////////////////
// CMDIMenuDecoration
CMDIMenuDecoration::CMDIMenuDecoration() { // anMDIDataMap is indexed by these values
ASSERT (DFCS_CAPTIONCLOSE == 0); ASSERT (DFCS_CAPTIONMIN == 1); ASSERT (DFCS_CAPTIONMAX == 2); ASSERT (DFCS_CAPTIONRESTORE == 3); }
CMDIMenuDecoration::~CMDIMenuDecoration() { }
BEGIN_MESSAGE_MAP(CMDIMenuDecoration, CWnd) //{{AFX_MSG_MAP(CMDIMenuDecoration)
ON_WM_PAINT() ON_WM_WINDOWPOSCHANGING() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMDIMenuDecoration message handlers
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::OnPaint * * WM_PAINT handler for CMDIMenuDecoration. *--------------------------------------------------------------------------*/
void CMDIMenuDecoration::OnPaint() { CPaintDC dcPaint (this);
//#define DRAW_OFF_SCREEN
#ifndef DRAW_OFF_SCREEN
CDC& dc = dcPaint; #else
CRect rect; GetClientRect (rect); const int cx = rect.Width(); const int cy = rect.Height();
CDC dcMem; CDC& dc = dcMem; dcMem.CreateCompatibleDC (&dcPaint);
CBitmap bmMem; bmMem.CreateCompatibleBitmap (&dcPaint, cx, cy);
CBitmap* pbmOld = dcMem.SelectObject (&bmMem); #endif
if (dcPaint.m_ps.fErase) dc.FillRect (&dcPaint.m_ps.rcPaint, AMCGetSysColorBrush (COLOR_BTNFACE));
int cxButton = GetSystemMetrics (SM_CXMENUSIZE); int cyButton = GetSystemMetrics (SM_CYMENUSIZE); DWORD dwStyle = GetStyle ();
CRect rectDraw (0, 0, cxButton, cyButton);
// make sure we don't have both the maximize and restore styles
ASSERT ((dwStyle & (MMDS_MAXIMIZE | MMDS_RESTORE)) != (MMDS_MAXIMIZE | MMDS_RESTORE));
// we shouldn't get here if we're tracking
ASSERT (m_spTrackCtxt.get() == NULL);
CMenu* pSysMenu = GetActiveSystemMenu ();
for (int i = 0; i < cMapEntries; i++) { int nDataIndex = anDrawOrder[i];
if (dwStyle & anMDIDataMap[nDataIndex].dwStyle) { int nState = nDataIndex;
if (!IsSysCommandEnabled (anMDIDataMap[nDataIndex].nCommand, pSysMenu)) nState |= DFCS_INACTIVE;
DrawCaptionControl (&dc, rectDraw, nState, false); rectDraw.OffsetRect (cxButton, 0); } }
#ifdef DRAW_OFF_SCREEN
dcPaint.BitBlt (0, 0, cx, cy, &dcMem, 0, 0, SRCCOPY); dcMem.SelectObject (pbmOld); #endif
}
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::OnWindowPosChanging * * WM_WINDOWPOSCHANGING handler for CMDIMenuDecoration. *--------------------------------------------------------------------------*/
void CMDIMenuDecoration::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) { DWORD dwStyle = GetStyle ();
if (dwStyle & MMDS_AUTOSIZE) { int cxButton = GetSystemMetrics (SM_CXMENUSIZE); int cyButton = GetSystemMetrics (SM_CYMENUSIZE);
lpwndpos->cx = 0; lpwndpos->cy = cyButton;
dwStyle &= MMDS_BTNSTYLES;
while (dwStyle != 0) { if (dwStyle & 1) lpwndpos->cx += cxButton;
dwStyle >>= 1; } }
else CWnd::OnWindowPosChanging(lpwndpos); }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::OnLButtonDown * * WM_LBUTTONDOWN handler for CMDIMenuDecoration. *--------------------------------------------------------------------------*/
// this routine needs placement new syntax --
// temporarily remove MFC's incompatible placement new definition
#ifdef _DEBUG
#undef new
#endif
void CMDIMenuDecoration::OnLButtonDown(UINT nFlags, CPoint point) { typedef std::auto_ptr<char> CharPtr;
CWnd::OnLButtonDown(nFlags, point);
try { /*------------------------------------------------------------------*/ /* This looks ugly. We'd like to write: */ /* */ /* m_spTrackCtxt = CMouseTrackContextPtr ( */ /* new CMouseTrackContext (this, point)); */ /* */ /* but CMouseTrackContext's ctor might throw an exception. If it */ /* does, the smart pointer won't yet have been initialized so the */ /* CMouseTrackContext won't be deleted. */ /* */ /* To get around it, we'll create a smart pointer pointing to a */ /* dynamically-allocated buffer of the right size. That buffer */ /* will not leak with an exception. We can then use a placement */ /* new to initialize a CMouseTrackContext in the hunk of memory. */ /* It's now not a problem if the CMouseTrackContext throws, because */ /* the buffer is still protected it's own smart pointer. Once */ /* the placement new completes successfully, we can transfer */ /* ownership of the object to a CMouseTrackContext smart pointer */ /* and we're golden. */ /*------------------------------------------------------------------*/ // allocate a hunk of memory and construct a CMouseTrackContext in it
CharPtr spchBuffer = CharPtr (new char[sizeof (CMouseTrackContext)]); CMouseTrackContext* pNewCtxt = new (spchBuffer.get()) CMouseTrackContext (this, point);
// if we get here, the CMouseTrackContext initialized properly,
// so we can transfer ownership to the CMouseTrackContext smart pointer
spchBuffer.release (); m_spTrackCtxt = CMouseTrackContextPtr (pNewCtxt); } catch (CUserException* pe) { // do nothing, just eat the exception
pe->Delete(); } }
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::OnLButtonUp * * WM_LBUTTONUP handler for CMDIMenuDecoration. *--------------------------------------------------------------------------*/
void CMDIMenuDecoration::OnLButtonUp(UINT nFlags, CPoint point) { if (m_spTrackCtxt.get() != NULL) { const int nHotButton = m_spTrackCtxt->m_nHotButton; const int nHitButton = m_spTrackCtxt->HitTest (point);
// delete the track context
m_spTrackCtxt = CMouseTrackContextPtr (NULL);
if (nHitButton == nHotButton) { int cmd = anMDIDataMap[nHotButton].nCommand;
// make sure the command looks like a valid sys command
ASSERT (cmd >= 0xF000);
ClientToScreen (&point); GetOwner()->SendMessage (WM_SYSCOMMAND, cmd, MAKELPARAM (point.x, point.y)); }
} }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::OnMouseMove * * WM_MOUSEMOVE handler for CMDIMenuDecoration. *--------------------------------------------------------------------------*/
void CMDIMenuDecoration::OnMouseMove(UINT nFlags, CPoint point) { if (m_spTrackCtxt.get() != NULL) m_spTrackCtxt->Track (point); }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::GetActiveSystemMenu * * *--------------------------------------------------------------------------*/
CMenu* CMDIMenuDecoration::GetActiveSystemMenu () { CFrameWnd* pwndFrame = GetParentFrame()->GetActiveFrame(); ASSERT (pwndFrame != NULL);
CMenu* pSysMenu = pwndFrame->GetSystemMenu (FALSE); ASSERT (pSysMenu != NULL);
return (pSysMenu); }
/*--------------------------------------------------------------------------*
* CMDIMenuDecoration::IsSysCommandEnabled * * *--------------------------------------------------------------------------*/
bool CMDIMenuDecoration::IsSysCommandEnabled (int nSysCommand, CMenu* pSysMenu) { if (pSysMenu == NULL) pSysMenu = GetActiveSystemMenu ();
int nState = pSysMenu->GetMenuState (nSysCommand, MF_BYCOMMAND); ASSERT (nState != 0xFFFFFFFF);
return ((nState & MF_GRAYED) == 0); }
|