⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 menubar.cpp

📁 一个多窗口的浏览器的程序benbrowse
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/////////////////////////////////////////////////////////////////////////////
// MenuBar.cpp: implementation of the CMenuBar class.
//
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001 by Nikolay Denisov. All rights reserved.
//
// This code is free for personal and commercial use, providing this 
// notice remains intact in the source files and all eventual changes are
// clearly marked with comments.
//
// You must obtain the author's consent before you can include this code
// in a software library.
//
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Please email bug reports, bug fixes, enhancements, requests and
// comments to: nick@actor.ru
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CommonRes.h"
#include "MenuBar.h"
#include "SizableReBar.h"
#include "WinAppEx.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/////////////////////////////////////////////////////////////////////////////
// CMenuBarButton

CMenuBarButton::CMenuBarButton()
{
    m_bHidden = true;
    m_bPushed = false;

    SetMDIChild( 0 );
    SetMenuBarRect( 0 );
}

bool CMenuBarButton::HitTest( CPoint pt ) const
{
    return ( IsVisible() && GetButtonRect().PtInRect( pt ) );
}

void CMenuBarButton::SetMDIChild( HWND hWndMDIChild )
{
    m_hWndMDIChild = hWndMDIChild;
}

void CMenuBarButton::SetMenuBarRect( LPCRECT lpRect )
{
    if ( lpRect != 0 )
    {
        m_rcMenuBar = *lpRect;
    }
    else
    {
        m_rcMenuBar.SetRectEmpty();
    }
}

DWORD CMenuBarButton::GetMDIChildStyle() const
{
    return ( DWORD )::GetWindowLong( m_hWndMDIChild, GWL_STYLE );
}

bool CMenuBarButton::IsEnabled() const
{
    return true;
}

bool CMenuBarButton::IsVisible() const
{
    return ( !m_bHidden && ::IsWindow( m_hWndMDIChild ) && ( GetMDIChildStyle() & WS_SYSMENU ) );
}

bool CMenuBarButton::IsPushed() const
{
    return m_bPushed;
}

bool CMenuBarButton::HideButton( bool bHide )
{
    bool bWasHidden = m_bHidden;
    m_bHidden = bHide;
    return bWasHidden;
}

bool CMenuBarButton::PushButton( bool bPush )
{
    bool bWasPushed = m_bPushed;
    m_bPushed = bPush;
    return bWasPushed;
}

CSize CMenuBarButton::GetButtonSize()
{
    // Sys-menu icon and caption buttons are all inside
    // a rectangle of the following size:
    const NONCLIENTMETRICS& info = CWinAppEx::GetInstance()->GetNonClientMetrics();
    return CSize(
        info.iMenuWidth,     //::GetSystemMetrics( SM_CXMENUSIZE ),
        info.iMenuHeight );  //::GetSystemMetrics( SM_CYMENUSIZE ) );
}

void CMenuBarButton::DrawButton( CDC* pDC )
{
    if ( IsVisible() )
    {
        UINT nState;
        switch ( GetSysCommandID() )
        {
            case SC_CLOSE:
                nState = DFCS_CAPTIONCLOSE;
                break;
            case SC_MINIMIZE:
                nState = DFCS_CAPTIONMIN;
                break;
            case SC_MAXIMIZE:
                nState = DFCS_CAPTIONMAX;
                break;
            case SC_RESTORE:
                nState = DFCS_CAPTIONRESTORE;
                break;
            default:
                ASSERT( false );
                return;
        }

        CRect rc = GetButtonRect();
        VERIFY( pDC->DrawFrameControl( rc, DFC_CAPTION, nState |
            ( IsPushed() ? DFCS_PUSHED : 0 ) |
            ( IsEnabled() ? 0 : DFCS_INACTIVE ) ) );
    }
}

/////////////////////////////////////////////////////////////////////////////
// CMenuBarButtonMin

CRect CMenuBarButtonMin::GetButtonRect() const
{
    // Minimize box has 2 pixel border on all sides but right
    CSize szButton = GetButtonSize();
    szButton.cx -= 2;
    szButton.cy -= 4;

    CPoint ptTopLeft;
    ptTopLeft.x = m_rcMenuBar.right - ( szButton.cx + 2 ) * 3 + 2;
    ptTopLeft.y = m_rcMenuBar.top + ( m_rcMenuBar.Height() - szButton.cy ) / 2;

    return CRect( ptTopLeft, szButton );
}

UINT CMenuBarButtonMin::GetSysCommandID() const
{
    return ::IsIconic( m_hWndMDIChild ) ? SC_RESTORE : SC_MINIMIZE;
}

bool CMenuBarButtonMin::IsEnabled() const
{
    return ( ( GetMDIChildStyle() & WS_MINIMIZEBOX ) != 0 );
}

bool CMenuBarButtonMin::IsVisible() const
{
    return CMenuBarButton::IsVisible() &&
        ( ( GetMDIChildStyle() & ( WS_MINIMIZEBOX | WS_MAXIMIZEBOX ) ) != 0 );
}

/////////////////////////////////////////////////////////////////////////////
// CMenuBarButtonMax

CRect CMenuBarButtonMax::GetButtonRect() const
{
    // Max box has a 2 pixel border on all sides but left, which is zero
    CSize szButton = GetButtonSize();
    szButton.cx -= 2;
    szButton.cy -= 4;

    CPoint ptTopLeft;
    ptTopLeft.x = m_rcMenuBar.right - ( szButton.cx + 2 ) * 2;
    ptTopLeft.y = m_rcMenuBar.top + ( m_rcMenuBar.Height() - szButton.cy ) / 2;

    return CRect( ptTopLeft, szButton );
}

UINT CMenuBarButtonMax::GetSysCommandID() const
{
    return ::IsZoomed( m_hWndMDIChild ) ? SC_RESTORE : SC_MAXIMIZE;
}

bool CMenuBarButtonMax::IsEnabled() const
{
    return ( ( GetMDIChildStyle() & WS_MAXIMIZEBOX ) != 0 );
}

bool CMenuBarButtonMax::IsVisible() const
{
    return CMenuBarButton::IsVisible() &&
        ( ( GetMDIChildStyle() & ( WS_MINIMIZEBOX | WS_MAXIMIZEBOX ) ) != 0 );
}

/////////////////////////////////////////////////////////////////////////////
// CMenuBarButtonClose

CRect CMenuBarButtonClose::GetButtonRect() const
{
    // Close box has a 2 pixel border on all sides but left, which is zero
    CSize szButton = GetButtonSize();
    szButton.cx -= 2;
    szButton.cy -= 4;

    CPoint ptTopLeft;
    ptTopLeft.x = m_rcMenuBar.right - ( szButton.cx + 2 );
    ptTopLeft.y = m_rcMenuBar.top + ( m_rcMenuBar.Height() - szButton.cy ) / 2;

    return CRect( ptTopLeft, szButton );
}

UINT CMenuBarButtonClose::GetSysCommandID() const
{
    return SC_CLOSE;
}

/////////////////////////////////////////////////////////////////////////////
// CMenuBar

#define IDBUTTON_FIRST      65000
#define IDBUTTON_SYSMENU    65000
#define IDBUTTON_LAST       65100

// Static member variables
HHOOK     CMenuBar::m_hMsgHook = 0;
CMenuBar* CMenuBar::m_pMenuBar = 0;

IMPLEMENT_DYNAMIC( CMenuBar, CToolBar )

CMenuBar::CMenuBar()
{
    m_hWndMDIChild   = 0;
    m_hWndOldFocus   = 0;
    m_hMenu          = 0;
    m_hMenuTracking  = 0;
    m_bItemTracking  = false;
    m_bItemDropped   = false;
    m_bButtonCapture = false;
    m_bFrameActive   = true;

    // Create menu bar buttons
    m_aMenuBarButtons.Add( new CMenuBarButtonMin   );
    m_aMenuBarButtons.Add( new CMenuBarButtonMax   );
    m_aMenuBarButtons.Add( new CMenuBarButtonClose );
}

CMenuBar::~CMenuBar()
{
    if ( m_fontMenu.GetSafeHandle() != 0 )
    {
        VERIFY( m_fontMenu.DeleteObject() );
    }

    for ( int nIndex = 0; nIndex <= m_aMenuBarButtons.GetUpperBound(); nIndex++ )
    {
        delete m_aMenuBarButtons[ nIndex ];
    }

    m_aMenuBarButtons.RemoveAll();
}

/////////////////////////////////////////////////////////////////////////////
// Operations

bool CMenuBar::SetMenu( HMENU hMenu )
{
    // Delete old buttons
    while ( m_nCount > 0 )
    {
        VERIFY( GetToolBarCtrl().DeleteButton( --m_nCount ) );
    }

    CMenu* pMenu = CMenu::FromHandle( hMenu );
    if ( pMenu != 0 )
    {
        // Allocate space for buttons
        UINT nItems = pMenu->GetMenuItemCount();
        VERIFY( SetButtons( 0, nItems + 1 ) );

        // Add sys-menu button which is the leftmost
        SetButtonInfo( 0, IDBUTTON_SYSMENU,
            TBBS_BUTTON | TBBS_DROPDOWN | TBBS_NOPREFIX, 0 );

        // Add all other buttons
        for ( UINT nIndex = 0; nIndex < nItems; nIndex++ )
        {
            UINT nID    = pMenu->GetMenuItemID( nIndex );
            UINT nStyle = TBBS_BUTTON | TBBS_AUTOSIZE | TBBS_DROPDOWN;

            switch ( nID )
            {
                case -1:
                    nID = IDBUTTON_SYSMENU + 1 + nIndex;
                    break;
                case 0:
                    nStyle = TBBS_SEPARATOR;
                    break;
                default:
                    nStyle ^= TBBS_DROPDOWN;
                    ASSERT( false );    // not supported yet
                    break;
            }

            CString strMenu;
            pMenu->GetMenuString( nIndex, strMenu, MF_BYPOSITION );

            SetButtonInfo( nIndex + 1, nID, nStyle, 0 /*-2=I_IMAGENONE*/ );
            VERIFY( SetButtonText( nIndex + 1, strMenu ) );
        }
    }

    UpdateMenuBar();

    m_hMenu = hMenu;
    return true;
}

HMENU CMenuBar::GetMenu() const
{
    return m_hMenu;
}

/////////////////////////////////////////////////////////////////////////////
// Implementation

CReBarCtrl& CMenuBar::GetParentReBarCtrl() const
{
    return STATIC_DOWNCAST( CReBar, GetParent() )->GetReBarCtrl();
}

int CMenuBar::GetParentBandIndex() const
{
	CReBarCtrl *ass=(CReBarCtrl *)&GetParentReBarCtrl();
	int nBand = GetParentReBarCtrl().IDToIndex( ( UINT )GetDlgCtrlID() );
    ASSERT( nBand != -1 );
    return nBand;
}

void CMenuBar::SetButtonWidth( UINT nID, int nWidth )
{
    TBBUTTONINFO tbbi;
    tbbi.cbSize = sizeof( tbbi );
    tbbi.dwMask = TBIF_SIZE;
    tbbi.cx     = ( WORD )nWidth;

    VERIFY( GetToolBarCtrl().SetButtonInfo( nID, &tbbi ) );
}

void CMenuBar::UpdateMenuBar()
{
    // Set new font
    if ( m_fontMenu.GetSafeHandle() != 0 )
    {
        VERIFY( m_fontMenu.DeleteObject() );
    }

    VERIFY( m_fontMenu.CreateFontIndirect(
        &CWinAppEx::GetInstance()->GetNonClientMetrics().lfMenuFont ) );
    SetFont( &m_fontMenu, TRUE );

    // Calc row height
    int cyMenu = ::GetSystemMetrics( SM_CYMENU );
    int cyRow  = cyMenu + HIWORD( SendMessage( TB_GETPADDING ) );

    CToolBarCtrl& tbCtrl = GetToolBarCtrl();
    VERIFY( tbCtrl.SetBitmapSize( CSize( 0, cyMenu ) ) );

    // Adjust appearance of sys-menu button
    bool bSysMenu = ( m_hWndMDIChild != 0 );
    int cxButton = bSysMenu ? CMenuBarButton::GetButtonSize().cx : 0;
    if ( GetCount() > 0 )
    {
        VERIFY( tbCtrl.HideButton( IDBUTTON_SYSMENU, !bSysMenu ) );
        if ( bSysMenu )
        {
            // Adjust sys-menu button width
            SetButtonWidth( IDBUTTON_SYSMENU, cxButton );
        }
    }

    // Calc minimal and ideal width of the menu bar
    int cxIdeal = cxButton * 3;
    for ( int nIndex = 0; nIndex < GetCount(); nIndex++ )
    {
        CRect rcItem;
        if ( tbCtrl.GetItemRect( nIndex, rcItem ) )
        {
            cxIdeal += rcItem.Width();
        }
    }

    // Our parent must be a re-bar control by design.
    // So, minimal and ideal width as well as minimal height of
    // the parent band should also be adjusted accordingly.
    REBARBANDINFO rbbi;
    rbbi.cbSize     = sizeof( rbbi );
    rbbi.fMask      = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
    rbbi.cxMinChild = cxButton;
    rbbi.cyMinChild = cyRow;
    rbbi.cxIdeal    = cxIdeal;
    VERIFY( GetParentReBarCtrl().SetBandInfo( GetParentBandIndex(), &rbbi ) );

    CRect rcMenuBar;
    GetClientRect( rcMenuBar );
    RepositionSysButtons( rcMenuBar );
}

void CMenuBar::RepositionSysButtons( CRect rcMenuBar )
{
    CRect rcItem;
    GetToolBarCtrl().GetItemRect( GetCount() - 1, rcItem );

    int cxAvailable = ( rcMenuBar.right - rcItem.right );
    int cxNeeded    = ( CMenuBarButton::GetButtonSize().cx * 3 );
    if ( cxAvailable < cxNeeded )
    {
        // Without this sys-buttons would overlap menu items
        rcMenuBar.right = rcItem.right + cxNeeded;
    }

    for ( int nIndex = 0; nIndex <= m_aMenuBarButtons.GetUpperBound(); nIndex++ )
    {
        CMenuBarButton* pButton = m_aMenuBarButtons[ nIndex ];
        pButton->SetMenuBarRect( rcMenuBar );
        pButton->HideButton( m_hWndMDIChild == 0 );
    }

    Invalidate();
}

void CMenuBar::EnterTrackingMode( int nItem )
{
    if ( !m_bItemTracking )
    {
        m_bItemTracking = true;
        m_hWndOldFocus  = 0;

        // Gain focus
        if ( GetFocus() != this )
        {
            m_hWndOldFocus = SetFocus()->GetSafeHwnd();
        }

        // Capture mouse
        if ( GetCapture() != this )
        {
            SetCapture();
            SendMessage( WM_SETCURSOR, ( WPARAM )m_hWnd, MAKELPARAM( HTCLIENT, 0 ) );
        }

        GetToolBarCtrl().SetHotItem( nItem );
    }
}

void CMenuBar::TrackChevronMenu( CRect& rcChevron, int nItem )
{
    ExitTrackingMode();

    CMenu* pMenu = CMenu::FromHandle( m_hMenu );
    if ( pMenu != 0 )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -