diff options
Diffstat (limited to 'vcl/source/window/menubarwindow.cxx')
-rw-r--r-- | vcl/source/window/menubarwindow.cxx | 1156 |
1 files changed, 1156 insertions, 0 deletions
diff --git a/vcl/source/window/menubarwindow.cxx b/vcl/source/window/menubarwindow.cxx new file mode 100644 index 000000000000..b265517067d4 --- /dev/null +++ b/vcl/source/window/menubarwindow.cxx @@ -0,0 +1,1156 @@ +/* -*- 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 <salframe.hxx> +#include <salmenu.hxx> +#include <svdata.hxx> +#include <svids.hrc> +#include <window.h> + +// document closing button +#define IID_DOCUMENTCLOSE 1 + +DecoToolBox::DecoToolBox( Window* pParent, WinBits nStyle ) : + ToolBox( pParent, nStyle ) +{ + ImplInit(); +} + +void DecoToolBox::ImplInit() +{ + lastSize = -1; + calcMinSize(); +} + +void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( rDCEvt.GetFlags() & SETTINGS_STYLE ) + { + calcMinSize(); + SetBackground(); + SetImages( 0, true); + } +} + +void DecoToolBox::calcMinSize() +{ + ToolBox aTbx( GetParent() ); + if( GetItemCount() == 0 ) + { + ResMgr* pResMgr = ImplGetResMgr(); + + Bitmap aBitmap; + if( pResMgr ) + aBitmap = Bitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) ); + aTbx.InsertItem( IID_DOCUMENTCLOSE, Image( aBitmap ) ); + } + else + { + sal_uInt16 nItems = GetItemCount(); + for( sal_uInt16 i = 0; i < nItems; i++ ) + { + sal_uInt16 nId = GetItemId( i ); + aTbx.InsertItem( nId, GetItemImage( nId ) ); + } + } + aTbx.SetOutStyle( TOOLBOX_STYLE_FLAT ); + maMinSize = aTbx.CalcWindowSizePixel(); +} + +void DecoToolBox::SetImages( long nMaxHeight, bool bForce ) +{ + 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 ) + { + lastSize = nMaxHeight - border; + + Color aEraseColor( 255, 255, 255, 255 ); + BitmapEx aBmpExDst( maImage.GetBitmapEx() ); + BitmapEx aBmpExSrc( aBmpExDst ); + + aEraseColor.SetTransparency( 255 ); + aBmpExDst.Erase( aEraseColor ); + aBmpExDst.SetSizePixel( Size( lastSize, lastSize ) ); + + Rectangle aSrcRect( Point(0,0), maImage.GetSizePixel() ); + Rectangle aDestRect( Point((lastSize - maImage.GetSizePixel().Width())/2, + (lastSize - maImage.GetSizePixel().Height())/2 ), + maImage.GetSizePixel() ); + + aBmpExDst.CopyPixel( aDestRect, aSrcRect, &aBmpExSrc ); + SetItemImage( IID_DOCUMENTCLOSE, Image( aBmpExDst ) ); + } +} + +MenuBarWindow::MenuBarWindow( Window* pParent ) : + Window( pParent, 0 ), + aCloser( this ), + aFloatBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ), + aHideBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ) +{ + SetType( WINDOW_MENUBARWINDOW ); + pMenu = NULL; + pActivePopup = NULL; + nSaveFocusId = 0; + nHighlightedItem = ITEMPOS_INVALID; + nRolloveredItem = ITEMPOS_INVALID; + mbAutoPopup = true; + nSaveFocusId = 0; + bIgnoreFirstMove = true; + bStayActive = false; + + ResMgr* pResMgr = ImplGetResMgr(); + + if( pResMgr ) + { + BitmapEx aBitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) ); + aCloser.maImage = Image( aBitmap ); + + aCloser.SetOutStyle( TOOLBOX_STYLE_FLAT ); + aCloser.SetBackground(); + aCloser.SetPaintTransparent( true ); + aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP ); + + aCloser.InsertItem( IID_DOCUMENTCLOSE, aCloser.maImage, 0 ); + aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) ); + aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) ); + aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, ResId(SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr).toString() ); + + aFloatBtn.SetClickHdl( LINK( this, MenuBarWindow, FloatHdl ) ); + aFloatBtn.SetSymbol( SYMBOL_FLOAT ); + aFloatBtn.SetQuickHelpText( ResId(SV_HELPTEXT_RESTORE, *pResMgr).toString() ); + + aHideBtn.SetClickHdl( LINK( this, MenuBarWindow, HideHdl ) ); + aHideBtn.SetSymbol( SYMBOL_HIDE ); + aHideBtn.SetQuickHelpText( ResId(SV_HELPTEXT_MINIMIZE, *pResMgr).toString() ); + } + + ImplInitStyleSettings(); + + AddEventListener( LINK( this, MenuBarWindow, ShowHideListener ) ); +} + +MenuBarWindow::~MenuBarWindow() +{ + aCloser.RemoveEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) ); + RemoveEventListener( LINK( this, MenuBarWindow, ShowHideListener ) ); +} + +void MenuBarWindow::SetMenu( MenuBar* pMen ) +{ + pMenu = pMen; + KillActivePopup(); + nHighlightedItem = ITEMPOS_INVALID; + ImplInitMenuWindow( this, true, true ); + if ( pMen ) + { + aCloser.ShowItem( IID_DOCUMENTCLOSE, pMen->HasCloser() ); + aCloser.Show( pMen->HasCloser() || !m_aAddButtons.empty() ); + aFloatBtn.Show( pMen->HasFloatButton() ); + aHideBtn.Show( pMen->HasHideButton() ); + } + Invalidate(); + + // show and connect native menubar + if( pMenu && pMenu->ImplGetSalMenu() ) + { + if( pMenu->ImplGetSalMenu()->VisibleMenuBar() ) + ImplGetFrame()->SetMenu( pMenu->ImplGetSalMenu() ); + + pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() ); + } +} + +void MenuBarWindow::ShowButtons( bool bClose, bool bFloat, bool bHide ) +{ + aCloser.ShowItem( IID_DOCUMENTCLOSE, bClose ); + aCloser.Show( bClose || ! m_aAddButtons.empty() ); + aFloatBtn.Show( bFloat ); + aHideBtn.Show( bHide ); + Resize(); +} + +Size MenuBarWindow::MinCloseButtonSize() +{ + return aCloser.getMinSize(); +} + +IMPL_LINK_NOARG(MenuBarWindow, CloserHdl) +{ + if( ! pMenu ) + return 0; + + if( aCloser.GetCurItemId() == 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( ((MenuBar*)pMenu)->GetCloserHdl(), pMenu ); + } + else + { + std::map<sal_uInt16,AddButtonEntry>::iterator it = m_aAddButtons.find( aCloser.GetCurItemId() ); + if( it != m_aAddButtons.end() ) + { + MenuBar::MenuBarButtonCallbackArg aArg; + aArg.nId = it->first; + aArg.bHighlight = (aCloser.GetHighlightItemId() == it->first); + aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu); + return it->second.m_aSelectLink.Call( &aArg ); + } + } + return 0; +} + +IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent*, pEvent ) +{ + if( ! pMenu ) + return 0; + + MenuBar::MenuBarButtonCallbackArg aArg; + aArg.nId = 0xffff; + aArg.bHighlight = (pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT); + aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu); + if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT ) + aArg.nId = aCloser.GetHighlightItemId(); + else if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF ) + { + sal_uInt16 nPos = static_cast< sal_uInt16 >(reinterpret_cast<sal_IntPtr>(pEvent->GetData())); + aArg.nId = aCloser.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 ); + } + return 0; +} + +IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent*, pEvent ) +{ + if( ! pMenu ) + return 0; + + if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID ); + else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID ); + return 0; +} + +IMPL_LINK_NOARG(MenuBarWindow, FloatHdl) +{ + return pMenu ? ((MenuBar*)pMenu)->GetFloatButtonClickHdl().Call( pMenu ) : 0; +} + +IMPL_LINK_NOARG(MenuBarWindow, HideHdl) +{ + return pMenu ? ((MenuBar*)pMenu)->GetHideButtonClickHdl().Call( pMenu ) : 0; +} + +void MenuBarWindow::ImplCreatePopup( bool bPreSelectFirst ) +{ + MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL; + if ( pItemData ) + { + bIgnoreFirstMove = true; + if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) ) + { + KillActivePopup(); + } + if ( pItemData->bEnabled && pItemData->pSubMenu && ( nHighlightedItem != ITEMPOS_INVALID ) && ( pItemData->pSubMenu != pActivePopup ) ) + { + pActivePopup = (PopupMenu*)pItemData->pSubMenu; + long nX = 0; + MenuItemData* pData = 0; + for ( sal_uLong n = 0; n < nHighlightedItem; n++ ) + { + pData = pMenu->GetItemList()->GetDataFromPos( n ); + nX += pData->aSz.Width(); + } + pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem ); + Point aItemTopLeft( nX, 0 ); + Point aItemBottomRight( aItemTopLeft ); + aItemBottomRight.X() += pData->aSz.Width(); + + // 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.Y() += 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(); + pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_NOHORZPLACEMENT, pMenu, bPreSelectFirst ); + if ( pActivePopup ) + { + // does not have a window, if aborted before or if there are no entries + if ( pActivePopup->ImplGetFloatingWindow() ) + pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this ); + else + pActivePopup = NULL; + } + } + } +} + +void MenuBarWindow::KillActivePopup() +{ + if ( pActivePopup ) + { + if( pActivePopup->pWindow != NULL ) + if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() ) + return; // kill it later + + if ( pActivePopup->bInCallback ) + pActivePopup->bCanceled = true; + + pActivePopup->bInCallback = true; + pActivePopup->Deactivate(); + pActivePopup->bInCallback = false; + // check for pActivePopup, if stopped by deactivate... + if ( pActivePopup->ImplGetWindow() ) + { + pActivePopup->ImplGetFloatingWindow()->StopExecute(); + pActivePopup->ImplGetFloatingWindow()->doShutdown(); + pActivePopup->pWindow->doLazyDelete(); + pActivePopup->pWindow = NULL; + } + pActivePopup = 0; + } +} + +void MenuBarWindow::PopupClosed( Menu* pPopup ) +{ + if ( pPopup == pActivePopup ) + { + KillActivePopup(); + ChangeHighlightItem( ITEMPOS_INVALID, false, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, false ); + } +} + +void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + mbAutoPopup = true; + sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() ); + if ( ( nEntry != ITEMPOS_INVALID ) && !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 ( nRolloveredItem != ITEMPOS_INVALID && nRolloveredItem != nHighlightedItem ) + HighlightItem( nRolloveredItem, false ); + + nRolloveredItem = ITEMPOS_INVALID; + return; + } + + sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() ); + if ( nHighlightedItem == ITEMPOS_INVALID ) + { + if ( nRolloveredItem != nEntry ) + { + if ( nRolloveredItem != ITEMPOS_INVALID ) + HighlightItem( nRolloveredItem, false ); + + nRolloveredItem = nEntry; + HighlightItem( nRolloveredItem, true ); + } + return; + } + nRolloveredItem = nEntry; + + if( bIgnoreFirstMove ) + { + bIgnoreFirstMove = false; + return; + } + + if ( ( nEntry != ITEMPOS_INVALID ) + && ( nEntry != nHighlightedItem ) ) + ChangeHighlightItem( nEntry, false ); +} + +void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n, bool bSelectEntry, bool bAllowRestoreFocus, bool bDefaultToDocument) +{ + if( ! pMenu ) + return; + + // #57934# close active popup if applicable, as TH's background storage works. + MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n ); + if ( pActivePopup && pActivePopup->ImplGetWindow() && ( !pNextData || ( pActivePopup != pNextData->pSubMenu ) ) ) + KillActivePopup(); // pActivePopup when applicable without pWin, if Rescheduled in Activate() + + // activate menubar only ones per cycle... + bool bJustActivated = false; + if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) ) + { + ImplGetSVData()->maWinData.mbNoDeactivate = true; + if( !bStayActive ) + { + // #105406# avoid saving the focus when we already have the focus + bool bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin ); + + if( nSaveFocusId ) + { + if( !ImplGetSVData()->maWinData.mbNoSaveFocus ) + { + // we didn't clean up last time + Window::EndSaveFocus( nSaveFocusId, false ); // clean up + nSaveFocusId = 0; + if( !bNoSaveFocus ) + nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated + } + else { + ; // do nothing: we 're activated again from taskpanelist, focus was already saved + } + } + else + { + if( !bNoSaveFocus ) + nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated + } + } + else + bStayActive = false; + pMenu->bInCallback = true; // set here if Activate overloaded + pMenu->Activate(); + pMenu->bInCallback = false; + bJustActivated = true; + } + else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) ) + { + pMenu->bInCallback = true; + pMenu->Deactivate(); + pMenu->bInCallback = false; + ImplGetSVData()->maWinData.mbNoDeactivate = false; + if( !ImplGetSVData()->maWinData.mbNoSaveFocus ) + { + sal_uLong nTempFocusId = nSaveFocusId; + nSaveFocusId = 0; + Window::EndSaveFocus( nTempFocusId, bAllowRestoreFocus ); + // #105406# restore focus to document if we could not save focus before + if( bDefaultToDocument && !nTempFocusId && bAllowRestoreFocus ) + GrabFocusToDocument(); + } + } + + if ( nHighlightedItem != ITEMPOS_INVALID ) + { + if ( nHighlightedItem != nRolloveredItem ) + HighlightItem( nHighlightedItem, false ); + + pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem ); + } + + nHighlightedItem = (sal_uInt16)n; + DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" ); + if ( nHighlightedItem != ITEMPOS_INVALID ) + HighlightItem( nHighlightedItem, true ); + else if ( nRolloveredItem != ITEMPOS_INVALID ) + HighlightItem( nRolloveredItem, true ); + pMenu->SetHighlightItem(nHighlightedItem); + pMenu->ImplCallHighlight(nHighlightedItem); + + if( mbAutoPopup ) + ImplCreatePopup( bSelectEntry ); + + // #58935# #73659# Focus, if no popup underneath... + if ( bJustActivated && !pActivePopup ) + GrabFocus(); +} + +static int ImplGetTopDockingAreaHeight( Window *pWindow ) +{ + // find docking area that is top aligned and return its height + // note: dockingareas are direct children of the SystemWindow + if( pWindow->ImplGetFrameWindow() ) + { + Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( WINDOW_FIRSTCHILD ); //mpWindowImpl->mpFirstChild; + while( pWin ) + { + if( pWin->IsSystemWindow() ) + { + Window *pChildWin = pWin->GetWindow( WINDOW_FIRSTCHILD ); //mpWindowImpl->mpFirstChild; + while( pChildWin ) + { + DockingAreaWindow *pDockingArea = NULL; + if ( pChildWin->GetType() == WINDOW_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( WINDOW_NEXT ); //mpWindowImpl->mpNext; + } + + } + + pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext; + } + } + return 0; +} + +static void ImplAddNWFSeparator( Window *pThis, 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 + + pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetSeparatorColor() ); + Point aPt; + Rectangle aRect( aPt, pThis->GetOutputSizePixel() ); + pThis->DrawLine( aRect.BottomLeft(), aRect.BottomRight() ); + } +} + +void MenuBarWindow::HighlightItem( sal_uInt16 nPos, bool bHighlight ) +{ + if( ! pMenu ) + return; + + long nX = 0; + size_t nCount = pMenu->pItemList->size(); + for ( size_t n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( n == nPos ) + { + if ( pData->eType != MENUITEM_SEPARATOR ) + { + // #107747# give menuitems the height of the menubar + Rectangle aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) ); + Push( PUSH_CLIPREGION ); + IntersectClipRegion( aRect ); + bool bRollover = bHighlight && nPos != nHighlightedItem; + if ( bHighlight ) + { + if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) && + IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) ) + { + // draw background (transparency) + MenubarValue aControlValue; + aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this ); + + if ( !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() ) + Erase(); + else + { + Point tmp(0,0); + Rectangle aBgRegion( tmp, GetOutputSizePixel() ); + DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, + aBgRegion, + CTRL_STATE_ENABLED, + aControlValue, + OUString() ); + } + + ImplAddNWFSeparator( this, aControlValue ); + + // draw selected item + ControlState nState = CTRL_STATE_ENABLED; + if ( bRollover ) + nState |= CTRL_STATE_ROLLOVER; + else + nState |= CTRL_STATE_SELECTED; + DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM, + aRect, + nState, + aControlValue, + OUString() ); + } + else + { + if ( bRollover ) + SetFillColor( GetSettings().GetStyleSettings().GetMenuBarRolloverColor() ); + else + SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + SetLineColor(); + DrawRect( aRect ); + } + } + else + { + if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) ) + { + MenubarValue aMenubarValue; + aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this ); + + if ( !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() ) + Erase( aRect ); + else + { + // use full window size to get proper gradient + // but clip accordingly + Point aPt; + Rectangle aCtrlRect( aPt, GetOutputSizePixel() ); + + DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, aMenubarValue, OUString() ); + } + + ImplAddNWFSeparator( this, aMenubarValue ); + } + else + Erase( aRect ); + } + Pop(); + pMenu->ImplPaint( this, 0, 0, pData, bHighlight, false, bRollover ); + } + return; + } + + nX += pData->aSz.Width(); + } +} + +Rectangle MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos ) +{ + Rectangle aRect; + if( pMenu ) + { + long nX = 0; + size_t nCount = pMenu->pItemList->size(); + for ( size_t n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( n == nPos ) + { + if ( pData->eType != MENUITEM_SEPARATOR ) + // #107747# give menuitems the height of the menubar + aRect = 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 ( !ImplHandleKeyEvent( rKEvent ) ) + Window::KeyInput( rKEvent ); +} + +bool MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, bool bFromMenu ) +{ + if( ! pMenu ) + return false; + + if ( pMenu->bInCallback ) + return true; // swallow + + bool bDone = false; + sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode(); + + if( GetParent() ) + { + if( GetParent()->GetWindow( WINDOW_CLIENT )->IsSystemWindow() ) + { + SystemWindow *pSysWin = (SystemWindow*)GetParent()->GetWindow( WINDOW_CLIENT ); + if( pSysWin->GetTaskPaneList() ) + if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) ) + return true; + } + } + + if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10 + { + mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10; + if ( nHighlightedItem == ITEMPOS_INVALID ) + { + ChangeHighlightItem( 0, false ); + GrabFocus(); + } + else + { + ChangeHighlightItem( ITEMPOS_INVALID, false ); + nSaveFocusId = 0; + } + bDone = true; + } + else if ( bFromMenu ) + { + if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) || + ( nCode == KEY_HOME ) || ( nCode == KEY_END ) ) + { + sal_uInt16 n = nHighlightedItem; + if ( n == ITEMPOS_INVALID ) + { + if ( nCode == KEY_LEFT) + n = 0; + else + n = pMenu->GetItemCount()-1; + } + + // handling gtk like (aka mbOpenMenuOnF10) + // do not highlight an item when opening a sub menu + // unless there already was a higlighted sub menu item + bool bWasHighlight = false; + if( pActivePopup ) + { + MenuFloatingWindow* pSubWindow = dynamic_cast<MenuFloatingWindow*>(pActivePopup->ImplGetWindow()); + if( pSubWindow ) + bWasHighlight = (pSubWindow->GetHighlightedItem() != ITEMPOS_INVALID); + } + + sal_uInt16 nLoop = n; + + if( nCode == KEY_HOME ) + { n = (sal_uInt16)-1; nLoop = n+1; } + if( nCode == KEY_END ) + { n = pMenu->GetItemCount(); nLoop = n-1; } + + do + { + if ( nCode == KEY_LEFT || nCode == KEY_END ) + { + if ( n ) + n--; + else + n = pMenu->GetItemCount()-1; + } + if ( nCode == KEY_RIGHT || nCode == KEY_HOME ) + { + n++; + if ( n >= pMenu->GetItemCount() ) + n = 0; + } + + MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n ); + if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) ) + { + bool bDoSelect = true; + if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 ) + bDoSelect = bWasHighlight; + ChangeHighlightItem( n, bDoSelect ); + break; + } + } while ( n != nLoop ); + bDone = true; + } + else if ( nCode == KEY_RETURN ) + { + if( 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( pActivePopup ) + { + // bring focus to menu bar without any open popup + mbAutoPopup = false; + sal_uInt16 n = nHighlightedItem; + nHighlightedItem = ITEMPOS_INVALID; + bStayActive = true; + ChangeHighlightItem( n, false ); + bStayActive = false; + KillActivePopup(); + GrabFocus(); + } + else + 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 ) + { + sal_uInt16 nEntry, nDuplicates; + MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem ); + if ( pData && (nEntry != ITEMPOS_INVALID) ) + { + mbAutoPopup = true; + ChangeHighlightItem( nEntry, true ); + bDone = true; + } + } + } + return bDone; +} + +void MenuBarWindow::Paint( const Rectangle& ) +{ + if( ! pMenu ) + return; + + // no VCL paint if native menus + if( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) + { + ImplGetFrame()->DrawMenuBar(); + return; + } + + if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) ) + { + MenubarValue aMenubarValue; + aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this ); + + if ( !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() ) + Erase(); + else + { + Point aPt; + Rectangle aCtrlRegion( aPt, GetOutputSizePixel() ); + + DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aMenubarValue, OUString() ); + } + + ImplAddNWFSeparator( this, aMenubarValue ); + } + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + pMenu->ImplPaint( this, 0 ); + if ( nHighlightedItem != ITEMPOS_INVALID ) + HighlightItem( nHighlightedItem, true ); + + // in high contrast mode draw a separating line on the lower edge + if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) && + GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + Push( PUSH_LINECOLOR | PUSH_MAPMODE ); + SetLineColor( Color( COL_WHITE ) ); + SetMapMode( MapMode( MAP_PIXEL ) ); + Size aSize = GetSizePixel(); + DrawLine( Point( 0, aSize.Height()-1 ), Point( aSize.Width()-1, aSize.Height()-1 ) ); + Pop(); + } + +} + +void MenuBarWindow::Resize() +{ + Size aOutSz = GetOutputSizePixel(); + long n = aOutSz.Height()-4; + long nX = aOutSz.Width()-3; + long nY = 2; + + if ( aCloser.IsVisible() ) + { + aCloser.Hide(); + aCloser.SetImages( n ); + Size aTbxSize( aCloser.CalcWindowSizePixel() ); + nX -= aTbxSize.Width(); + long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2; + aCloser.setPosSizePixel( nX, nTbxY, aTbxSize.Width(), aTbxSize.Height() ); + nX -= 3; + aCloser.Show(); + } + if ( aFloatBtn.IsVisible() ) + { + nX -= n; + aFloatBtn.setPosSizePixel( nX, nY, n, n ); + } + if ( aHideBtn.IsVisible() ) + { + nX -= n; + aHideBtn.setPosSizePixel( nX, nY, n, n ); + } + + aFloatBtn.SetSymbol( SYMBOL_FLOAT ); + aHideBtn.SetSymbol( SYMBOL_HIDE ); + //aCloser.SetSymbol( SYMBOL_CLOSE ); //is a toolbox now + + Invalidate(); +} + +sal_uInt16 MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const +{ + if( pMenu ) + { + long nX = 0; + size_t nCount = pMenu->pItemList->size(); + for ( size_t n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( pMenu->ImplIsVisible( n ) ) + { + nX += pData->aSz.Width(); + if ( nX > rMousePos.X() ) + return (sal_uInt16)n; + } + } + } + return ITEMPOS_INVALID; +} + +void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + sal_uInt16 nId = nHighlightedItem; + if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) ) + ChangeHighlightItem( ITEMPOS_INVALID, true ); + + Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) ); + if( !ImplHandleHelpEvent( this, pMenu, nId, rHEvt, aHighlightRect ) ) + Window::RequestHelp( rHEvt ); +} + +void MenuBarWindow::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || + ( nType == STATE_CHANGE_CONTROLBACKGROUND ) ) + { + ImplInitMenuWindow( this, false, true ); + Invalidate(); + } + else if( pMenu ) + pMenu->ImplKillLayoutData(); + +} + +void MenuBarWindow::ImplLayoutChanged() +{ + if( pMenu ) + { + ImplInitMenuWindow( this, true, true ); + // if the font was changed. + long nHeight = pMenu->ImplCalcSize( this ).Height(); + + // depending on the native implementation or the displayable flag + // the menubar windows is suppressed (ie, height=0) + if( !((MenuBar*) pMenu)->IsDisplayable() || + ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) ) + nHeight = 0; + + setPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT ); + GetParent()->Resize(); + Invalidate(); + Resize(); + if( pMenu ) + pMenu->ImplKillLayoutData(); + } +} + +void MenuBarWindow::ImplInitStyleSettings() +{ + if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) && + IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) ) + { + AllSettings aSettings( GetSettings() ); + ImplGetFrame()->UpdateSettings( aSettings ); // to update persona + StyleSettings aStyle( aSettings.GetStyleSettings() ); + Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor; + if( aHighlightTextColor != Color( COL_TRANSPARENT ) ) + { + aStyle.SetMenuHighlightTextColor( aHighlightTextColor ); + } + aSettings.SetStyleSettings( aStyle ); + OutputDevice::SetSettings( aSettings ); + } +} + +void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + ImplInitStyleSettings(); + ImplLayoutChanged(); + } +} + +void MenuBarWindow::LoseFocus() +{ + if ( !HasChildPathFocus( true ) ) + ChangeHighlightItem( ITEMPOS_INVALID, false, false ); +} + +void MenuBarWindow::GetFocus() +{ + if ( nHighlightedItem == ITEMPOS_INVALID ) + { + mbAutoPopup = false; // do not open menu when activated by focus handling like taskpane cycling + ChangeHighlightItem( 0, false ); + } +} + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuBarWindow::CreateAccessible() +{ + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc; + + if ( pMenu ) + xAcc = pMenu->GetAccessible(); + + return xAcc; +} + +sal_uInt16 MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const OUString& i_rToolTip, sal_uInt16 i_nPos ) +{ + // find first free button id + sal_uInt16 nId = IID_DOCUMENTCLOSE; + std::map< sal_uInt16, AddButtonEntry >::const_iterator it; + if( i_nPos > m_aAddButtons.size() ) + i_nPos = static_cast<sal_uInt16>(m_aAddButtons.size()); + do + { + nId++; + it = m_aAddButtons.find( nId ); + } while( it != m_aAddButtons.end() && nId < 128 ); + DBG_ASSERT( nId < 128, "too many addbuttons in menubar" ); + AddButtonEntry& rNewEntry = m_aAddButtons[nId]; + rNewEntry.m_nId = nId; + rNewEntry.m_aSelectLink = i_rLink; + aCloser.InsertItem( nId, i_rImage, 0, 0 ); + aCloser.calcMinSize(); + ShowButtons( aCloser.IsItemVisible( IID_DOCUMENTCLOSE ), + aFloatBtn.IsVisible(), + aHideBtn.IsVisible() ); + ImplLayoutChanged(); + + if( pMenu->mpSalMenu ) + pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) ); + + return nId; +} + +void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link& rLink ) +{ + std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( nId ); + if( it != m_aAddButtons.end() ) + it->second.m_aHighlightLink = rLink; +} + +Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId ) +{ + Rectangle aRect; + if( m_aAddButtons.find( nId ) != m_aAddButtons.end() ) + { + if( pMenu->mpSalMenu ) + { + aRect = pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame ); + if( aRect == Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) ) + { + // system menu button is somewhere but location cannot be determined + return Rectangle(); + } + } + + if( aRect.IsEmpty() ) + { + aRect = aCloser.GetItemRect( nId ); + Point aOffset = aCloser.OutputToScreenPixel( Point() ); + aRect.Move( aOffset.X(), aOffset.Y() ); + } + } + return aRect; +} + +void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId ) +{ + sal_uInt16 nPos = aCloser.GetItemPos( nId ); + aCloser.RemoveItem( nPos ); + m_aAddButtons.erase( nId ); + aCloser.calcMinSize(); + ImplLayoutChanged(); + + if( pMenu->mpSalMenu ) + 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() ) + { + MenuBar::MenuBarButtonCallbackArg aArg; + aArg.nId = it->first; + aArg.bHighlight = true; + aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu); + return it->second.m_aSelectLink.Call( &aArg ); + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |