Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/source/window/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 40 kB image not shown  

Quelle  menubarwindow.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include "menubarwindow.hxx"
#include "menuitemlist.hxx"
#include "menufloatingwindow.hxx"

#include <vcl/dockingarea.hxx>
#include <vcl/settings.hxx>
#include <vcl/taskpanelist.hxx>
#include <sal/log.hxx>

#include <salframe.hxx>
#include <salmenu.hxx>
#include <svdata.hxx>
#include <strings.hrc>
#include <bitmaps.hlst>
#include <window.h>
#include "bufferdevice.hxx"
#include <menubarvalue.hxx>

// document closing button
#define IID_DOCUMENTCLOSE 1

DecoToolBox::DecoToolBox( vcl::Window* pParent ) :
    ToolBox( pParent, 0 ),
    lastSize(-1)
{
    calcMinSize();
}

void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt )
{
    Window::DataChanged( rDCEvt );

    if ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE )
    {
        calcMinSize();
        SetBackground();
        SetImages( 0, true);
    }
}

void DecoToolBox::calcMinSize()
{
    ScopedVclPtrInstance<ToolBox> aTbx( GetParent() );
    if( GetItemCount() == 0 )
    {
        aTbx->InsertItem(ToolBoxItemId(IID_DOCUMENTCLOSE), Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC));
    }
    else
    {
        ImplToolItems::size_type nItems = GetItemCount();
        for( ImplToolItems::size_type i = 0; i < nItems; i++ )
        {
            ToolBoxItemId nId = GetItemId( i );
            aTbx->InsertItem( nId, GetItemImage( nId ) );
        }
    }
    maMinSize = aTbx->CalcWindowSizePixel();

    aTbx.disposeAndClear();
}

void DecoToolBox::SetImages( tools::Long nMaxHeight, bool bForce )
{
    tools::Long border = getMinSize().Height() - maImage.GetSizePixel().Height();

    if( !nMaxHeight && lastSize != -1 )
        nMaxHeight = lastSize + border; // don't change anything if called with 0

    if( nMaxHeight < getMinSize().Height() )
        nMaxHeight = getMinSize().Height();

    if( (lastSize == nMaxHeight - border) && !bForce )
        return;

    lastSize = nMaxHeight - border;

    Color       aEraseColor( ColorTransparency, 255, 255, 255, 255 );
    BitmapEx    aBmpExDst( maImage.GetBitmapEx() );
    BitmapEx    aBmpExSrc( aBmpExDst );

    aEraseColor.SetAlpha( 0 );
    aBmpExDst.Erase( aEraseColor );
    aBmpExDst.Scale( Size( lastSize, lastSize ) );

    tools::Rectangle aSrcRect( Point(0,0), maImage.GetSizePixel() );
    tools::Rectangle aDestRect( Point((lastSize - maImage.GetSizePixel().Width())/2,
                            (lastSize - maImage.GetSizePixel().Height())/2 ),
                        maImage.GetSizePixel() );

    aBmpExDst.CopyPixel( aDestRect, aSrcRect, aBmpExSrc );
    SetItemImage( ToolBoxItemId(IID_DOCUMENTCLOSE), Image( aBmpExDst ) );

}

MenuBarWindow::MenuBarWindow( vcl::Window* pParent ) :
    Window( pParent, 0 ),
    m_aCloseBtn(VclPtr<DecoToolBox>::Create(this)),
    m_aFloatBtn(VclPtr<PushButton>::Create(this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE)),
    m_aHideBtn(VclPtr<PushButton>::Create(this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE))
{
    SetType(WindowType::MENUBARWINDOW);
    m_pMenu = nullptr;
    m_pActivePopup = nullptr;
    m_nHighlightedItem = ITEMPOS_INVALID;
    m_nRolloveredItem = ITEMPOS_INVALID;
    mbAutoPopup = true;
    m_bIgnoreFirstMove = true;
    SetMBWHideAccel(ImplGetSVData()->maNWFData.mbAutoAccel);
    SetMBWMenuKey(false);

    m_aCloseBtn->maImage = Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC);

    m_aCloseBtn->SetBackground();
    m_aCloseBtn->SetPaintTransparent(true);
    m_aCloseBtn->SetParentClipMode(ParentClipMode::NoClip);

    m_aCloseBtn->InsertItem(ToolBoxItemId(IID_DOCUMENTCLOSE), m_aCloseBtn->maImage);
    m_aCloseBtn->SetSelectHdl(LINK(this, MenuBarWindow, CloseHdl));
    m_aCloseBtn->AddEventListener(LINK(this, MenuBarWindow, ToolboxEventHdl));
    m_aCloseBtn->SetQuickHelpText(ToolBoxItemId(IID_DOCUMENTCLOSE), VclResId(SV_HELPTEXT_CLOSEDOCUMENT));

    m_aFloatBtn->SetSymbol( SymbolType::FLOAT );
    m_aFloatBtn->SetQuickHelpText(VclResId(SV_HELPTEXT_RESTORE));

    m_aHideBtn->SetSymbol( SymbolType::HIDE );
    m_aHideBtn->SetQuickHelpText(VclResId(SV_HELPTEXT_MINIMIZE));

    ImplInitStyleSettings();

    AddEventListener(LINK(this, MenuBarWindow, ShowHideListener));
}

MenuBarWindow::~MenuBarWindow()
{
    disposeOnce();
}

void MenuBarWindow::dispose()
{
    m_aCloseBtn->RemoveEventListener(LINK(this, MenuBarWindow, ToolboxEventHdl));
    RemoveEventListener(LINK(this, MenuBarWindow, ShowHideListener));

    mpParentPopup.disposeAndClear();
    m_aHideBtn.disposeAndClear();
    m_aFloatBtn.disposeAndClear();
    m_aCloseBtn.disposeAndClear();
    m_pMenu.reset();
    m_pActivePopup.reset();
    m_xSaveFocusId.reset();

    Window::dispose();
}

void MenuBarWindow::SetMenu( MenuBar* pMen )
{
    m_pMenu = pMen;
    KillActivePopup();
    m_nHighlightedItem = ITEMPOS_INVALID;
    if (pMen)
    {
        m_aCloseBtn->ShowItem(ToolBoxItemId(IID_DOCUMENTCLOSE), pMen->HasCloseButton());
        m_aCloseBtn->Show(pMen->HasCloseButton() || !m_aAddButtons.empty());
        m_aFloatBtn->Show(pMen->HasFloatButton());
        m_aHideBtn->Show(pMen->HasHideButton());
    }
    Invalidate();

    // show and connect native menubar
    if( m_pMenu && m_pMenu->ImplGetSalMenu() )
    {
        if( m_pMenu->ImplGetSalMenu()->VisibleMenuBar() )
            ImplGetFrame()->SetMenu( m_pMenu->ImplGetSalMenu() );

        m_pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
        m_pMenu->ImplGetSalMenu()->ShowMenuBar(true);
    }
}

void MenuBarWindow::SetHeight(tools::Long nHeight)
{
    setPosSizePixel(0, 0, 0, nHeight, PosSizeFlags::Height);
}

void MenuBarWindow::ShowButtons( bool bClose, bool bFloat, bool bHide )
{
    m_aCloseBtn->ShowItem(ToolBoxItemId(IID_DOCUMENTCLOSE), bClose);
    m_aCloseBtn->Show(bClose || !m_aAddButtons.empty());
    if (m_pMenu->mpSalMenu)
        m_pMenu->mpSalMenu->ShowCloseButton(bClose);
    m_aFloatBtn->Show( bFloat );
    m_aHideBtn->Show( bHide );
    Resize();
}

Size const & MenuBarWindow::MinCloseButtonSize() const
{
    return m_aCloseBtn->getMinSize();
}

IMPL_LINK_NOARG(MenuBarWindow, CloseHdl, ToolBox *, void)
{
    if( ! m_pMenu )
        return;

    if( m_aCloseBtn->GetCurItemId() == ToolBoxItemId(IID_DOCUMENTCLOSE) )
    {
        // #i106052# call close hdl asynchronously to ease handler implementation
        // this avoids still being in the handler while the DecoToolBox already
        // gets destroyed
        Application::PostUserEvent(m_pMenu->GetCloseButtonClickHdl());
    }
    else
    {
        std::map<sal_uInt16,AddButtonEntry>::iterator it = m_aAddButtons.find(sal_uInt16(m_aCloseBtn->GetCurItemId()));
        if( it != m_aAddButtons.end() )
        {
            MenuBarButtonCallbackArg aArg;
            aArg.nId = it->first;
            aArg.bHighlight = (sal_uInt16(m_aCloseBtn->GetHighlightItemId()) == it->first);
            it->second.m_aSelectLink.Call( aArg );
        }
    }
}

IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent&, rEvent, void )
{
    if( ! m_pMenu )
        return;

    MenuBarButtonCallbackArg aArg;
    aArg.nId = 0xffff;
    aArg.bHighlight = (rEvent.GetId() == VclEventId::ToolboxHighlight);
    if( rEvent.GetId() == VclEventId::ToolboxHighlight )
        aArg.nId =sal_uInt16(m_aCloseBtn->GetHighlightItemId());
    else if( rEvent.GetId() == VclEventId::ToolboxHighlightOff )
    {
        auto nPos = static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rEvent.GetData()));
        aArg.nId = sal_uInt16(m_aCloseBtn->GetItemId(nPos));
    }
    std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId );
    if( it != m_aAddButtons.end() )
    {
        it->second.m_aHighlightLink.Call( aArg );
    }
}

IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent&, rEvent, void )
{
    if( ! m_pMenu )
        return;

    if( rEvent.GetId() == VclEventId::WindowShow )
        m_pMenu->ImplCallEventListeners( VclEventId::MenuShow, ITEMPOS_INVALID );
    else if( rEvent.GetId() == VclEventId::WindowHide )
        m_pMenu->ImplCallEventListeners( VclEventId::MenuHide, ITEMPOS_INVALID );
}

void MenuBarWindow::ImplCreatePopup( bool bPreSelectFirst )
{
    MenuItemData* pItemData = m_pMenu ? m_pMenu->GetItemList()->GetDataFromPos( m_nHighlightedItem ) : nullptr;
    if ( !pItemData )
        return;

    m_bIgnoreFirstMove = true;
    if ( m_pActivePopup && ( m_pActivePopup != pItemData->pSubMenu ) )
    {
        KillActivePopup();
    }
    if ( !(pItemData->bEnabled && pItemData->pSubMenu && ( m_nHighlightedItem != ITEMPOS_INVALID ) &&
         ( pItemData->pSubMenu != m_pActivePopup )) )
        return;

    m_pActivePopup = pItemData->pSubMenu.get();
    tools::Long nX = 0;
    MenuItemData* pData = nullptr;
    for ( sal_uLong n = 0; n < m_nHighlightedItem; n++ )
    {
        pData = m_pMenu->GetItemList()->GetDataFromPos( n );
        nX += pData->aSz.Width();
    }
    pData = m_pMenu->pItemList->GetDataFromPos( m_nHighlightedItem );
    Point aItemTopLeft( nX, 0 );
    Point aItemBottomRight( aItemTopLeft );
    aItemBottomRight.AdjustX(pData->aSz.Width() );

    if (pData->bHiddenOnGUI)
    {
        mpParentPopup.disposeAndClear();
        mpParentPopup = VclPtr<PopupMenu>::Create();
        m_pActivePopup = mpParentPopup.get();

        for (sal_uInt16 i = m_nHighlightedItem; i < m_pMenu->GetItemCount(); ++i)
        {
            sal_uInt16 nId = m_pMenu->GetItemId(i);

            MenuItemData* pParentItemData = m_pMenu->GetItemList()->GetData(nId);
            assert(pParentItemData);
            mpParentPopup->InsertItem(nId, pParentItemData->aText, pParentItemData->nBits, pParentItemData->sIdent);
            mpParentPopup->SetHelpId(nId, pParentItemData->aHelpId);
            mpParentPopup->SetHelpText(nId, pParentItemData->aHelpText);
            mpParentPopup->SetAccelKey(nId, pParentItemData->aAccelKey);
            mpParentPopup->SetItemCommand(nId, pParentItemData->aCommandStr);
            mpParentPopup->SetHelpCommand(nId, pParentItemData->aHelpCommandStr);

            PopupMenu* pPopup = m_pMenu->GetPopupMenu(nId);
            mpParentPopup->SetPopupMenu(nId, pPopup);
        }
    }
    // the menu bar could have height 0 in fullscreen mode:
    // so do not use always WindowHeight, as ItemHeight < WindowHeight.
    if ( GetSizePixel().Height() )
    {
        // #107747# give menuitems the height of the menubar
        aItemBottomRight.AdjustY(GetOutputSizePixel().Height()-1 );
    }

    // ImplExecute is not modal...
    // #99071# do not grab the focus, otherwise it will be restored to the menubar
    // when the frame is reactivated later
    //GrabFocus();
    m_pActivePopup->ImplExecute( this, tools::Rectangle( aItemTopLeft, aItemBottomRight ), FloatWinPopupFlags::Down | FloatWinPopupFlags::NoHorzPlacement, m_pMenu, bPreSelectFirst );
    // does not have a window, if aborted before or if there are no entries
    if ( m_pActivePopup->ImplGetFloatingWindow() )
        m_pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this );
    else
        m_pActivePopup = nullptr;
}

void MenuBarWindow::KillActivePopup()
{
    if ( !m_pActivePopup )
        return;

    FloatingWindow* pFloatWin = m_pActivePopup->ImplGetFloatingWindow();
    if (pFloatWin && pFloatWin->IsInCleanUp())
        return// kill it later

    if ( m_pActivePopup->bInCallback )
        m_pActivePopup->bCanceled = true;

    m_pActivePopup->bInCallback = true;
    m_pActivePopup->Deactivate();
    m_pActivePopup->bInCallback = false;
    // check for pActivePopup, if stopped by deactivate...
    if (m_pActivePopup->GetWindow())
    {
        if (mpParentPopup)
        {
            for (sal_uInt16 i = 0; i < mpParentPopup->GetItemCount(); ++i)
            {
                sal_uInt16 nId = mpParentPopup->GetItemId(i);
                MenuItemData* pParentItemData = mpParentPopup->GetItemList()->GetData(nId);
                assert(pParentItemData);
                pParentItemData->pSubMenu = nullptr;
            }
        }
        m_pActivePopup->ImplGetFloatingWindow()->StopExecute();
        m_pActivePopup->ImplGetFloatingWindow()->doShutdown();
        m_pActivePopup->m_pWindow.disposeAndClear();
    }
    m_pActivePopup = nullptr;
}

void MenuBarWindow::PopupClosed( Menu const * pPopup )
{
    if ( pPopup == m_pActivePopup )
    {
        KillActivePopup();
        ChangeHighlightItem( ITEMPOS_INVALID, false, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, false );
    }
}

void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt )
{
    mbAutoPopup = true;
    SetMBWMenuKey(false);
    sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
    if ( ( nEntry != ITEMPOS_INVALID ) && !m_pActivePopup )
    {
        ChangeHighlightItem( nEntry, false );
    }
    else
    {
        KillActivePopup();
        ChangeHighlightItem( ITEMPOS_INVALID, false );
    }
}

void MenuBarWindow::MouseButtonUp( const MouseEvent& )
{
}

void MenuBarWindow::MouseMove( const MouseEvent& rMEvt )
{
    if ( rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
        return;

    if ( rMEvt.IsLeaveWindow() )
    {
        if ( m_nRolloveredItem != ITEMPOS_INVALID && m_nRolloveredItem != m_nHighlightedItem )
        {
            // there is a spurious MouseMove generated after a menu is launched from the keyboard, hence this...
            if (m_nHighlightedItem != ITEMPOS_INVALID)
            {
                bool hide = GetMBWHideAccel();
                SetMBWHideAccel(ImplGetSVData()->maNWFData.mbAutoAccel);
                Invalidate(); //HighlightItem( nRolloveredItem, false );
                SetMBWHideAccel(hide);
            }
            else
                Invalidate(); //HighlightItem( nRolloveredItem, false );
        }

        m_nRolloveredItem = ITEMPOS_INVALID;
        return;
    }

    sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
    if ( m_nHighlightedItem == ITEMPOS_INVALID )
    {
        if ( m_nRolloveredItem != nEntry  )
        {
            if ( m_nRolloveredItem != ITEMPOS_INVALID )
                Invalidate(); //HighlightItem( nRolloveredItem, false );

            m_nRolloveredItem = nEntry;
            Invalidate(); //HighlightItem( nRolloveredItem, true );
        }
        return;
    }
    m_nRolloveredItem = nEntry;

    if( m_bIgnoreFirstMove )
    {
        m_bIgnoreFirstMove = false;
        return;
    }

    if ( ( nEntry != ITEMPOS_INVALID )
       && ( nEntry != m_nHighlightedItem ) )
        ChangeHighlightItem( nEntry, false );
}

void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n, bool bSelectEntry, bool bAllowRestoreFocus, bool bDefaultToDocument)
{
    if( ! m_pMenu )
        return;

    if (n == ITEMPOS_INVALID)
        SetMBWHideAccel(ImplGetSVData()->maNWFData.mbAutoAccel);

    // #57934# close active popup if applicable, as TH's background storage works.
    MenuItemData* pNextData = m_pMenu->pItemList->GetDataFromPos( n );
    if (m_pActivePopup && m_pActivePopup->GetWindow() && (!pNextData || (m_pActivePopup != pNextData->pSubMenu)))
        KillActivePopup(); // pActivePopup when applicable without pWin, if Rescheduled in  Activate()

    // activate menubar only ones per cycle...
    bool bJustActivated = false;
    if ( ( m_nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) )
    {
        ImplGetSVData()->mpWinData->mbNoDeactivate = true;
        // #105406# avoid saving the focus when we already have the focus
        bool bNoSaveFocus = (this == ImplGetSVData()->mpWinData->mpFocusWin.get());

        if( m_xSaveFocusId != nullptr )
        {
            if (!ImplGetSVData()->mpWinData->mbNoSaveFocus)
            {
                 m_xSaveFocusId = nullptr;
                 if( !bNoSaveFocus )
                    m_xSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
            }
            else {
                ; // do nothing: we 're activated again from taskpanelist, focus was already saved
            }
        }
        else
        {
            if( !bNoSaveFocus )
                m_xSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
        }
        m_pMenu->bInCallback = true;  // set here if Activate overridden
        m_pMenu->Activate();
        m_pMenu->bInCallback = false;
        bJustActivated = true;
    }
    else if ( ( m_nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) )
    {
        m_pMenu->bInCallback = true;
        m_pMenu->Deactivate();
        m_pMenu->bInCallback = false;
        ImplGetSVData()->mpWinData->mbNoDeactivate = false;
        if (!ImplGetSVData()->mpWinData->mbNoSaveFocus)
        {
            VclPtr<vcl::Window> xTempFocusId;
            if (m_xSaveFocusId && !m_xSaveFocusId->isDisposed())
                xTempFocusId = m_xSaveFocusId;
            m_xSaveFocusId = nullptr;

            if (bAllowRestoreFocus)
            {
                // tdf#115227 the popup is already killed, so temporarily set us as the
                // focus window, so we could avoid sending superfluous activate events
                // to top window listeners.
                if (xTempFocusId || bDefaultToDocument)
                    ImplGetSVData()->mpWinData->mpFocusWin = this;

                // #105406# restore focus to document if we could not save focus before
                if (!xTempFocusId && bDefaultToDocument)
                    GrabFocusToDocument();
                else
                    Window::EndSaveFocus(xTempFocusId);
            }
        }
    }

    if ( m_nHighlightedItem != ITEMPOS_INVALID )
    {
        if ( m_nHighlightedItem != m_nRolloveredItem )
            Invalidate(); //HighlightItem( nHighlightedItem, false );

        m_pMenu->ImplCallEventListeners( VclEventId::MenuDehighlight, m_nHighlightedItem );
    }

    m_nHighlightedItem = n;
    SAL_WARN_IF( ( m_nHighlightedItem != ITEMPOS_INVALID ) && !m_pMenu->ImplIsVisible( m_nHighlightedItem ), "vcl""ChangeHighlightItem: Not visible!" );
    if ( m_nHighlightedItem != ITEMPOS_INVALID )
        Invalidate(); //HighlightItem( nHighlightedItem, true );
    else if ( m_nRolloveredItem != ITEMPOS_INVALID )
        Invalidate(); //HighlightItem( nRolloveredItem, true );
    m_pMenu->ImplCallHighlight(m_nHighlightedItem);

    if( mbAutoPopup )
        ImplCreatePopup( bSelectEntry );

    // #58935# #73659# Focus, if no popup underneath...
    if ( bJustActivated && !m_pActivePopup )
        GrabFocus();
}

static int ImplGetTopDockingAreaHeight( vcl::Window const *pWindow )
{
    // find docking area that is top aligned and return its height
    // note: dockingareas are direct children of the SystemWindow
    if( pWindow->ImplGetFrameWindow() )
    {
        vcl::Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( GetWindowType::FirstChild ); //mpWindowImpl->mpFirstChild;
        while( pWin )
        {
            if( pWin->IsSystemWindow() )
            {
                vcl::Window *pChildWin = pWin->GetWindow( GetWindowType::FirstChild ); //mpWindowImpl->mpFirstChild;
                while( pChildWin )
                {
                    DockingAreaWindow *pDockingArea = nullptr;
                    if ( pChildWin->GetType() == WindowType::DOCKINGAREA )
                        pDockingArea = static_cast< DockingAreaWindow* >( pChildWin );

                    if( pDockingArea && pDockingArea->GetAlign() == WindowAlign::Top &&
                        pDockingArea->IsVisible() && pDockingArea->GetOutputSizePixel().Height() != 0 )
                    {
                        return pDockingArea->GetOutputSizePixel().Height();
                    }

                    pChildWin = pChildWin->GetWindow( GetWindowType::Next ); //mpWindowImpl->mpNext;
                }

            }

            pWin = pWin->GetWindow( GetWindowType::Next ); //mpWindowImpl->mpNext;
        }
    }
    return 0;
}

static void ImplAddNWFSeparator(vcl::RenderContext& rRenderContext, const Size&&nbsp;rSize, const MenubarValue& rMenubarValue)
{
    // add a separator if
    // - we have an adjacent docking area
    // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
    if (rMenubarValue.maTopDockingAreaHeight
      && !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB
      && !ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames)
    {
        // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area

        rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetSeparatorColor());
        tools::Rectangle aRect(Point(), rSize);
        rRenderContext.DrawLine(aRect.BottomLeft(), aRect.BottomRight());
    }
}

void MenuBarWindow::HighlightItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos)
{
    if (!m_pMenu)
        return;

    tools::Long nX = 0;
    size_t nCount = m_pMenu->pItemList->size();

    Size aOutputSize = GetOutputSizePixel();
    aOutputSize.AdjustWidth( -(m_aCloseBtn->GetSizePixel().Width()) );

    for (size_t n = 0; n < nCount; n++)
    {
        MenuItemData* pData = m_pMenu->pItemList->GetDataFromPos( n );
        if (n == nPos)
        {
            if (pData->eType != MenuItemType::SEPARATOR)
            {
                // #107747# give menuitems the height of the menubar
                tools::Rectangle aRect(Point(nX, 1), Size(pData->aSz.Width(), aOutputSize.Height() - 2));
                rRenderContext.Push(vcl::PushFlags::CLIPREGION);
                rRenderContext.IntersectClipRegion(aRect);
                bool bRollover, bHighlight;
                if (!ImplGetSVData()->maNWFData.mbRolloverMenubar)
                {
                    bHighlight = true;
                    bRollover = nPos != m_nHighlightedItem;
                }
                else
                {
                    bRollover = nPos == m_nRolloveredItem;
                    bHighlight = nPos == m_nHighlightedItem;
                }
                if (rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::MenuItem) &&
                    rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire))
                {
                    // draw background (transparency)
                    MenubarValue aControlValue;
                    aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );

                    tools::Rectangle aBgRegion(Point(), aOutputSize);
                    rRenderContext.DrawNativeControl(ControlType::Menubar, ControlPart::Entire, aBgRegion,
                                                     ControlState::ENABLED, aControlValue, OUString());

                    ImplAddNWFSeparator(rRenderContext, aOutputSize, aControlValue);

                    // draw selected item
                    ControlState nState = ControlState::ENABLED;
                    if (bRollover)
                        nState |= ControlState::ROLLOVER;
                    else
                        nState |= ControlState::SELECTED;
                    rRenderContext.DrawNativeControl(ControlType::Menubar, ControlPart::MenuItem,
                                                     aRect, nState, aControlValue, OUString() );
                }
                else
                {
                    if (bRollover)
                        rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetMenuBarRolloverColor());
                    else
                        rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetMenuHighlightColor());
                    rRenderContext.SetLineColor();
                    rRenderContext.DrawRect(aRect);
                }
                rRenderContext.Pop();

                m_pMenu->ImplPaint(rRenderContext, aOutputSize, 0, 0, pData, bHighlight, false, bRollover);
            }
            return;
        }

        nX += pData->aSz.Width();
    }
}

tools::Rectangle MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos ) const
{
    tools::Rectangle aRect;
    if( m_pMenu )
    {
        tools::Long nX = 0;
        size_t nCount = m_pMenu->pItemList->size();
        for ( size_t n = 0; n < nCount; n++ )
        {
            MenuItemData* pData = m_pMenu->pItemList->GetDataFromPos( n );
            if ( n == nPos )
            {
                if ( pData->eType != MenuItemType::SEPARATOR )
                    // #107747# give menuitems the height of the menubar
                    aRect = tools::Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
                break;
            }

            nX += pData->aSz.Width();
        }
    }
    return aRect;
}

void MenuBarWindow::KeyInput( const KeyEvent& rKEvent )
{
    if ( !HandleKeyEvent( rKEvent ) )
        Window::KeyInput( rKEvent );
}

bool MenuBarWindow::HandleKeyEvent( const KeyEvent& rKEvent, bool bFromMenu )
{
    if (!m_pMenu)
        return false;

    if (m_pMenu->bInCallback)
        return true;    // swallow

    bool bDone = false;
    sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();

    if( GetParent() )
    {
        if( GetParent()->GetWindow( GetWindowType::Client )->IsSystemWindow() )
        {
            SystemWindow *pSysWin = static_cast<SystemWindow*>(GetParent()->GetWindow( GetWindowType::Client ));
            if( pSysWin->GetTaskPaneList() )
                if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) )
                    return true;
        }
    }

    // no key events if native menus
    if (m_pMenu->ImplGetSalMenu() && m_pMenu->ImplGetSalMenu()->VisibleMenuBar())
    {
        return false;
    }

    if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10
    {
        mbAutoPopup = false;
        if ( m_nHighlightedItem == ITEMPOS_INVALID )
        {
            ChangeHighlightItem( 0, false );
            GrabFocus();
        }
        else
        {
            ChangeHighlightItem( ITEMPOS_INVALID, false );
            m_xSaveFocusId = nullptr;
        }
        bDone = true;
    }
    else if ( bFromMenu )
    {
        if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ||
            ( nCode == KEY_HOME ) || ( nCode == KEY_END ) )
        {
            sal_uInt16 n = m_nHighlightedItem;
            if ( n == ITEMPOS_INVALID )
            {
                if ( nCode == KEY_LEFT)
                    n = 0;
                else
                    n = m_pMenu->GetItemCount()-1;
            }

            sal_uInt16 nLoop = n;

            if (nCode == KEY_HOME)
            {
                n = ITEMPOS_INVALID;
                nLoop = 0;
            }
            else if (nCode == KEY_END)
            {
                n = m_pMenu->GetItemCount();
                nLoop = n-1;
            }

            do
            {
                if ( nCode == KEY_LEFT || nCode == KEY_END )
                {
                    if ( n )
                        n--;
                    else
                        n = m_pMenu->GetItemCount()-1;
                }
                if ( nCode == KEY_RIGHT || nCode == KEY_HOME )
                {
                    n = (n == ITEMPOS_INVALID) ? 0 : n + 1;
                    if ( n >= m_pMenu->GetItemCount() )
                        n = 0;
                }

                MenuItemData* pData = m_pMenu->GetItemList()->GetDataFromPos( n );
                if (pData->eType != MenuItemType::SEPARATOR &&
                    m_pMenu->ImplIsVisible(n) &&
                    !m_pMenu->ImplCurrentlyHiddenOnGUI(n))
                {
                    ChangeHighlightItem( n, true );
                    break;
                }
            } while ( n != nLoop );
            bDone = true;
        }
        else if ( nCode == KEY_RETURN )
        {
            if( m_pActivePopup ) KillActivePopup();
            else
                if ( !mbAutoPopup )
                {
                    ImplCreatePopup( true );
                    mbAutoPopup = true;
                }
            bDone = true;
        }
        else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) )
        {
            if ( !mbAutoPopup )
            {
                ImplCreatePopup( true );
                mbAutoPopup = true;
            }
            bDone = true;
        }
        else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) )
        {
            if( m_pActivePopup )
            {
                // hide the menu and remove the focus...
                mbAutoPopup = false;
                KillActivePopup();
            }

            ChangeHighlightItem( ITEMPOS_INVALID, false );

            if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() )
            {
                // put focus into document
                GrabFocusToDocument();
            }

            bDone = true;
        }
    }

    if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) )
    {
        sal_Unicode nCharCode = rKEvent.GetCharCode();
        if ( nCharCode )
        {
            size_t nEntry, nDuplicates;
            MenuItemData* pData = m_pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, m_nHighlightedItem );
            if ( pData && (nEntry != ITEMPOS_INVALID) )
            {
                mbAutoPopup = true;
                ChangeHighlightItem( nEntry, true );
                bDone = true;
            }
        }
    }

    return bDone;
}

void MenuBarWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    if (!m_pMenu)
        return;

    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();

    Size aOutputSize = GetOutputSizePixel();

    // no VCL paint if native menus
    if (m_pMenu->ImplGetSalMenu() && m_pMenu->ImplGetSalMenu()->VisibleMenuBar())
        return;

    // Make sure that all actual rendering happens in one go to avoid flicker.
    vcl::BufferDevice pBuffer(this, rRenderContext);

    if (rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire))
    {
        MenubarValue aMenubarValue;
        aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight(this);

        tools::Rectangle aCtrlRegion( Point(), aOutputSize );

        pBuffer->DrawNativeControl(ControlType::Menubar, ControlPart::Entire, aCtrlRegion,
                                   ControlState::ENABLED, aMenubarValue, OUString());

        ImplAddNWFSeparator(*pBuffer, aOutputSize, aMenubarValue);
    }

    // shrink the area of the buttons
    aOutputSize.AdjustWidth( -(m_aCloseBtn->GetSizePixel().Width()) );

    pBuffer->SetFillColor(rStyleSettings.GetMenuColor());
    m_pMenu->ImplPaint(*pBuffer, aOutputSize, 0);

    if (m_nHighlightedItem != ITEMPOS_INVALID && m_pMenu && !m_pMenu->GetItemList()->GetDataFromPos(m_nHighlightedItem)->bHiddenOnGUI)
        HighlightItem(*pBuffer, m_nHighlightedItem);
    else if (m_nRolloveredItem != ITEMPOS_INVALID)
        HighlightItem(*pBuffer, m_nRolloveredItem);

    // in high contrast mode draw a separating line on the lower edge
    if (!rRenderContext.IsNativeControlSupported( ControlType::Menubar, ControlPart::Entire) &&
        rStyleSettings.GetHighContrastMode())
    {
        pBuffer->Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::MAPMODE);
        pBuffer->SetLineColor(COL_WHITE);
        pBuffer->SetMapMode(MapMode(MapUnit::MapPixel));
        Size aSize = GetSizePixel();
        pBuffer->DrawLine(Point(0, aSize.Height() - 1),
                          Point(aSize.Width() - 1, aSize.Height() - 1));
        pBuffer->Pop();
    }
}

void MenuBarWindow::Resize()
{
    Size aOutSz = GetOutputSizePixel();
    tools::Long n      = aOutSz.Height()-4;
    tools::Long nX     = aOutSz.Width()-3;
    tools::Long nY     = 2;

    if ( m_aCloseBtn->IsVisible() )
    {
        m_aCloseBtn->Hide();
        m_aCloseBtn->SetImages(n);
        Size aTbxSize( m_aCloseBtn->CalcWindowSizePixel() );
        nX -= aTbxSize.Width();
        tools::Long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2;
        m_aCloseBtn->setPosSizePixel(nX, nTbxY, aTbxSize.Width(), aTbxSize.Height());
        nX -= 3;
        m_aCloseBtn->Show();
    }
    if ( m_aFloatBtn->IsVisible() )
    {
        nX -= n;
        m_aFloatBtn->setPosSizePixel( nX, nY, n, n );
    }
    if ( m_aHideBtn->IsVisible() )
    {
        nX -= n;
        m_aHideBtn->setPosSizePixel( nX, nY, n, n );
    }

    m_aFloatBtn->SetSymbol( SymbolType::FLOAT );
    m_aHideBtn->SetSymbol( SymbolType::HIDE );

    Invalidate();
}

sal_uInt16 MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const
{
    if( m_pMenu )
    {
        tools::Long nX = 0;
        size_t nCount = m_pMenu->pItemList->size();
        for ( size_t n = 0; n < nCount; n++ )
        {
            MenuItemData* pData = m_pMenu->pItemList->GetDataFromPos( n );
            if ( m_pMenu->ImplIsVisible( n ) )
            {
                nX += pData->aSz.Width();
                if ( nX > rMousePos.X() )
                    return static_cast<sal_uInt16>(n);
            }
        }
    }
    return ITEMPOS_INVALID;
}

void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt )
{
    sal_uInt16 nId = m_nHighlightedItem;
    if ( rHEvt.GetMode() & HelpEventMode::CONTEXT )
        ChangeHighlightItem( ITEMPOS_INVALID, true );

    tools::Rectangle aHighlightRect( ImplGetItemRect( m_nHighlightedItem ) );
    if( !ImplHandleHelpEvent( this, m_pMenu, nId, rHEvt, aHighlightRect ) )
        Window::RequestHelp( rHEvt );
}

void MenuBarWindow::StateChanged( StateChangedType nType )
{
    Window::StateChanged( nType );

    if (nType == StateChangedType::ControlForeground ||
        nType == StateChangedType::ControlBackground)
    {
        ApplySettings(*GetOutDev());
        Invalidate();
    }
    else if (nType == StateChangedType::Enable)
    {
        Invalidate();
    }
    else if(m_pMenu)
    {
        m_pMenu->ImplKillLayoutData();
    }
}

void MenuBarWindow::LayoutChanged()
{
    if (!m_pMenu)
        return;

    ApplySettings(*GetOutDev());

    // if the font was changed.
    tools::Long nHeight = m_pMenu->ImplCalcSize(this).Height();

    // depending on the native implementation or the displayable flag
    // the menubar windows is suppressed (ie, height=0)
    if (!m_pMenu->IsDisplayable() ||
        (m_pMenu->ImplGetSalMenu() && m_pMenu->ImplGetSalMenu()->VisibleMenuBar()))
    {
        nHeight = 0;
    }
    setPosSizePixel(0, 0, 0, nHeight, PosSizeFlags::Height);
    GetParent()->Resize();
    Invalidate();
    Resize();

    m_pMenu->ImplKillLayoutData();
}

void MenuBarWindow::ApplySettings(vcl::RenderContext& rRenderContext)
{
    Window::ApplySettings(rRenderContext);
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();

    SetPointFont(rRenderContext, rStyleSettings.GetMenuFont());

    if (rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire))
    {
        rRenderContext.SetBackground(); // background will be drawn by NWF
    }
    else
    {
        Wallpaper aWallpaper;
        aWallpaper.SetStyle(WallpaperStyle::ApplicationGradient);
        rRenderContext.SetBackground(aWallpaper);
        SetPaintTransparent(false);
        SetParentClipMode();
    }

    rRenderContext.SetTextColor(rStyleSettings.GetMenuBarTextColor());
    rRenderContext.SetTextFillColor();
    rRenderContext.SetLineColor();
}

void MenuBarWindow::ImplInitStyleSettings()
{
    if (!(IsNativeControlSupported(ControlType::Menubar, ControlPart::MenuItem) &&
        IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire)))
        return;

    AllSettings aSettings(GetSettings());
    ImplGetFrame()->UpdateSettings(aSettings); // to update persona
    StyleSettings aStyle(aSettings.GetStyleSettings());
    Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor;
    if (aHighlightTextColor != COL_TRANSPARENT)
    {
        aStyle.SetMenuHighlightTextColor(aHighlightTextColor);
    }
    aSettings.SetStyleSettings(aStyle);
    GetOutDev()->SetSettings(aSettings);
}

void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt )
{
    Window::DataChanged( rDCEvt );

    if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
         (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
         ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
    {
        ApplySettings(*GetOutDev());
        ImplInitStyleSettings();
        LayoutChanged();
    }
}

void MenuBarWindow::LoseFocus()
{
    if ( !HasChildPathFocus( true ) )
        ChangeHighlightItem( ITEMPOS_INVALID, falsefalse );
}

void MenuBarWindow::GetFocus()
{
    SalMenu *pNativeMenu = m_pMenu ? m_pMenu->ImplGetSalMenu() : nullptr;
    if (pNativeMenu && pNativeMenu->TakeFocus())
        return;

    if ( m_nHighlightedItem == ITEMPOS_INVALID )
    {
        mbAutoPopup = false;    // do not open menu when activated by focus handling like taskpane cycling
        ChangeHighlightItem( 0, false );
    }
}

css::uno::Reference<css::accessibility::XAccessible> MenuBarWindow::CreateAccessible()
{
    css::uno::Reference<css::accessibility::XAccessible> xAcc;

    if (m_pMenu)
        xAcc = m_pMenu->GetAccessible();

    return xAcc;
}

sal_uInt16 MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link<MenuBarButtonCallbackArg&,bool>& i_rLink, const OUString& i_rToolTip )
{
    // find first free button id
    sal_uInt16 nId = IID_DOCUMENTCLOSE;
    std::map< sal_uInt16, AddButtonEntry >::const_iterator it;
    do
    {
        nId++;
        it = m_aAddButtons.find( nId );
    } while( it != m_aAddButtons.end() && nId < 128 );
    SAL_WARN_IF( nId >= 128, "vcl""too many addbuttons in menubar" );
    AddButtonEntry& rNewEntry = m_aAddButtons[nId];
    rNewEntry.m_aSelectLink = i_rLink;
    m_aCloseBtn->InsertItem(ToolBoxItemId(nId), i_rImage, ToolBoxItemBits::NONE, 0);
    m_aCloseBtn->calcMinSize();
    ShowButtons(m_aCloseBtn->IsItemVisible(ToolBoxItemId(IID_DOCUMENTCLOSE)), m_aFloatBtn->IsVisible(), m_aHideBtn->IsVisible());
    LayoutChanged();

    if( m_pMenu->mpSalMenu )
        m_pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) );

    return nId;
}

void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link<MenuBarButtonCallbackArg&,bool>& rLink )
{
    std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( nId );
    if( it != m_aAddButtons.end() )
        it->second.m_aHighlightLink = rLink;
}

tools::Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId )
{
    tools::Rectangle aRect;
    if( m_aAddButtons.find( nId ) != m_aAddButtons.end() )
    {
        if( m_pMenu->mpSalMenu )
        {
            aRect = m_pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame );
            if( aRect == tools::Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
            {
                // system menu button is somewhere but location cannot be determined
                return tools::Rectangle();
            }
        }

        if( aRect.IsEmpty() )
        {
            aRect = m_aCloseBtn->GetItemRect(ToolBoxItemId(nId));
            Point aOffset = m_aCloseBtn->OutputToScreenPixel(Point());
            aRect.Move( aOffset.X(), aOffset.Y() );
        }
    }
    return aRect;
}

void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId )
{
    ToolBox::ImplToolItems::size_type nPos = m_aCloseBtn->GetItemPos(ToolBoxItemId(nId));
    m_aCloseBtn->RemoveItem(nPos);
    m_aAddButtons.erase( nId );
    m_aCloseBtn->calcMinSize();
    LayoutChanged();

    if( m_pMenu->mpSalMenu )
        m_pMenu->mpSalMenu->RemoveMenuBarButton( nId );
}

bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId )
{
    std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId );
    if( it != m_aAddButtons.end() )
    {
        MenuBarButtonCallbackArg aArg;
        aArg.nId = it->first;
        aArg.bHighlight = true;
        return it->second.m_aSelectLink.Call( aArg );
    }
    return false;
}

bool MenuBarWindow::CanGetFocus() const
{
    /* #i83908# do not use the menubar if it is native or invisible
       this relies on MenuBar::ImplCreate setting the height of the menubar
       to 0 in this case
    */

    SalMenu *pNativeMenu = m_pMenu ? m_pMenu->ImplGetSalMenu() : nullptr;
    if (pNativeMenu && pNativeMenu->VisibleMenuBar())
        return pNativeMenu->CanGetFocus();
    return GetSizePixel().Height() > 0;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=97 G=94

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.