477 lines
14 KiB
C++
477 lines
14 KiB
C++
|
/*--------------------------------------------------------------------------*
|
|||
|
*
|
|||
|
* 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);
|
|||
|
}
|