1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "menubarwindow.hxx"
21 #include "menuitemlist.hxx"
22 #include "menufloatingwindow.hxx"
24 #include <vcl/dockingarea.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/taskpanelist.hxx>
28 #include <salframe.hxx>
29 #include <salmenu.hxx>
34 // document closing button
35 #define IID_DOCUMENTCLOSE 1
37 DecoToolBox::DecoToolBox( vcl::Window
* pParent
) :
38 ToolBox( pParent
, 0 ),
44 void DecoToolBox::DataChanged( const DataChangedEvent
& rDCEvt
)
46 Window::DataChanged( rDCEvt
);
48 if ( rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)
56 void DecoToolBox::calcMinSize()
58 ScopedVclPtrInstance
<ToolBox
> aTbx( GetParent() );
59 if( GetItemCount() == 0 )
61 ResMgr
* pResMgr
= ImplGetResMgr();
65 aBitmap
= Bitmap( ResId( SV_RESID_BITMAP_CLOSEDOC
, *pResMgr
) );
66 aTbx
->InsertItem( IID_DOCUMENTCLOSE
, Image( aBitmap
) );
70 sal_uInt16 nItems
= GetItemCount();
71 for( sal_uInt16 i
= 0; i
< nItems
; i
++ )
73 sal_uInt16 nId
= GetItemId( i
);
74 aTbx
->InsertItem( nId
, GetItemImage( nId
) );
77 aTbx
->SetOutStyle( TOOLBOX_STYLE_FLAT
);
78 maMinSize
= aTbx
->CalcWindowSizePixel();
80 aTbx
.disposeAndClear();
83 void DecoToolBox::SetImages( long nMaxHeight
, bool bForce
)
85 long border
= getMinSize().Height() - maImage
.GetSizePixel().Height();
87 if( !nMaxHeight
&& lastSize
!= -1 )
88 nMaxHeight
= lastSize
+ border
; // don't change anything if called with 0
90 if( nMaxHeight
< getMinSize().Height() )
91 nMaxHeight
= getMinSize().Height();
93 if( (lastSize
!= nMaxHeight
- border
) || bForce
)
95 lastSize
= nMaxHeight
- border
;
97 Color
aEraseColor( 255, 255, 255, 255 );
98 BitmapEx
aBmpExDst( maImage
.GetBitmapEx() );
99 BitmapEx
aBmpExSrc( aBmpExDst
);
101 aEraseColor
.SetTransparency( 255 );
102 aBmpExDst
.Erase( aEraseColor
);
103 aBmpExDst
.SetSizePixel( Size( lastSize
, lastSize
) );
105 Rectangle
aSrcRect( Point(0,0), maImage
.GetSizePixel() );
106 Rectangle
aDestRect( Point((lastSize
- maImage
.GetSizePixel().Width())/2,
107 (lastSize
- maImage
.GetSizePixel().Height())/2 ),
108 maImage
.GetSizePixel() );
110 aBmpExDst
.CopyPixel( aDestRect
, aSrcRect
, &aBmpExSrc
);
111 SetItemImage( IID_DOCUMENTCLOSE
, Image( aBmpExDst
) );
115 MenuBarWindow::MenuBarWindow( vcl::Window
* pParent
) :
116 Window( pParent
, 0 ),
117 aCloseBtn(VclPtr
<DecoToolBox
>::Create(this)),
118 aFloatBtn(VclPtr
<PushButton
>::Create(this, WB_NOPOINTERFOCUS
| WB_SMALLSTYLE
| WB_RECTSTYLE
)),
119 aHideBtn(VclPtr
<PushButton
>::Create(this, WB_NOPOINTERFOCUS
| WB_SMALLSTYLE
| WB_RECTSTYLE
))
121 SetType(WINDOW_MENUBARWINDOW
);
123 pActivePopup
= nullptr;
124 nHighlightedItem
= ITEMPOS_INVALID
;
125 nRolloveredItem
= ITEMPOS_INVALID
;
127 bIgnoreFirstMove
= true;
128 SetMBWHideAccel(true);
129 SetMBWMenuKey(false);
131 ResMgr
* pResMgr
= ImplGetResMgr();
135 BitmapEx
aBitmap(ResId(SV_RESID_BITMAP_CLOSEDOC
, *pResMgr
));
136 aCloseBtn
->maImage
= Image(aBitmap
);
138 aCloseBtn
->SetOutStyle(TOOLBOX_STYLE_FLAT
);
139 aCloseBtn
->SetBackground();
140 aCloseBtn
->SetPaintTransparent(true);
141 aCloseBtn
->SetParentClipMode(ParentClipMode::NoClip
);
143 aCloseBtn
->InsertItem(IID_DOCUMENTCLOSE
, aCloseBtn
->maImage
);
144 aCloseBtn
->SetSelectHdl(LINK(this, MenuBarWindow
, CloseHdl
));
145 aCloseBtn
->AddEventListener(LINK(this, MenuBarWindow
, ToolboxEventHdl
));
146 aCloseBtn
->SetQuickHelpText(IID_DOCUMENTCLOSE
, ResId(SV_HELPTEXT_CLOSEDOCUMENT
, *pResMgr
).toString());
148 aFloatBtn
->SetSymbol( SymbolType::FLOAT
);
149 aFloatBtn
->SetQuickHelpText( ResId(SV_HELPTEXT_RESTORE
, *pResMgr
).toString() );
151 aHideBtn
->SetSymbol( SymbolType::HIDE
);
152 aHideBtn
->SetQuickHelpText( ResId(SV_HELPTEXT_MINIMIZE
, *pResMgr
).toString() );
155 ImplInitStyleSettings();
157 AddEventListener(LINK(this, MenuBarWindow
, ShowHideListener
));
160 MenuBarWindow::~MenuBarWindow()
165 void MenuBarWindow::dispose()
167 aCloseBtn
->RemoveEventListener(LINK(this, MenuBarWindow
, ToolboxEventHdl
));
168 RemoveEventListener(LINK(this, MenuBarWindow
, ShowHideListener
));
170 aHideBtn
.disposeAndClear();
171 aFloatBtn
.disposeAndClear();
172 aCloseBtn
.disposeAndClear();
174 pActivePopup
.clear();
175 xSaveFocusId
.clear();
180 void MenuBarWindow::SetMenu( MenuBar
* pMen
)
184 nHighlightedItem
= ITEMPOS_INVALID
;
187 aCloseBtn
->ShowItem(IID_DOCUMENTCLOSE
, pMen
->HasCloseButton());
188 aCloseBtn
->Show(pMen
->HasCloseButton() || !m_aAddButtons
.empty());
189 aFloatBtn
->Show(pMen
->HasFloatButton());
190 aHideBtn
->Show(pMen
->HasHideButton());
194 // show and connect native menubar
195 if( pMenu
&& pMenu
->ImplGetSalMenu() )
197 if( pMenu
->ImplGetSalMenu()->VisibleMenuBar() )
198 ImplGetFrame()->SetMenu( pMenu
->ImplGetSalMenu() );
200 pMenu
->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
204 void MenuBarWindow::SetHeight(long nHeight
)
206 setPosSizePixel(0, 0, 0, nHeight
, PosSizeFlags::Height
);
209 void MenuBarWindow::ShowButtons( bool bClose
, bool bFloat
, bool bHide
)
211 aCloseBtn
->ShowItem(IID_DOCUMENTCLOSE
, bClose
);
212 aCloseBtn
->Show(bClose
|| !m_aAddButtons
.empty());
213 if (pMenu
->mpSalMenu
)
214 pMenu
->mpSalMenu
->ShowCloseButton(bClose
);
215 aFloatBtn
->Show( bFloat
);
216 aHideBtn
->Show( bHide
);
220 Size
MenuBarWindow::MinCloseButtonSize()
222 return aCloseBtn
->getMinSize();
225 IMPL_LINK_NOARG(MenuBarWindow
, CloseHdl
, ToolBox
*, void)
230 if( aCloseBtn
->GetCurItemId() == IID_DOCUMENTCLOSE
)
232 // #i106052# call close hdl asynchronously to ease handler implementation
233 // this avoids still being in the handler while the DecoToolBox already
235 Application::PostUserEvent(static_cast<MenuBar
*>(pMenu
.get())->GetCloseButtonClickHdl());
239 std::map
<sal_uInt16
,AddButtonEntry
>::iterator it
= m_aAddButtons
.find(aCloseBtn
->GetCurItemId());
240 if( it
!= m_aAddButtons
.end() )
242 MenuBar::MenuBarButtonCallbackArg aArg
;
243 aArg
.nId
= it
->first
;
244 aArg
.bHighlight
= (aCloseBtn
->GetHighlightItemId() == it
->first
);
245 aArg
.pMenuBar
= dynamic_cast<MenuBar
*>(pMenu
.get());
246 it
->second
.m_aSelectLink
.Call( aArg
);
251 IMPL_LINK( MenuBarWindow
, ToolboxEventHdl
, VclWindowEvent
&, rEvent
, void )
256 MenuBar::MenuBarButtonCallbackArg aArg
;
258 aArg
.bHighlight
= (rEvent
.GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT
);
259 aArg
.pMenuBar
= dynamic_cast<MenuBar
*>(pMenu
.get());
260 if( rEvent
.GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT
)
261 aArg
.nId
= aCloseBtn
->GetHighlightItemId();
262 else if( rEvent
.GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF
)
264 sal_uInt16 nPos
= static_cast< sal_uInt16
>(reinterpret_cast<sal_IntPtr
>(rEvent
.GetData()));
265 aArg
.nId
= aCloseBtn
->GetItemId(nPos
);
267 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( aArg
.nId
);
268 if( it
!= m_aAddButtons
.end() )
270 it
->second
.m_aHighlightLink
.Call( aArg
);
274 IMPL_LINK( MenuBarWindow
, ShowHideListener
, VclWindowEvent
&, rEvent
, void )
279 if( rEvent
.GetId() == VCLEVENT_WINDOW_SHOW
)
280 pMenu
->ImplCallEventListeners( VCLEVENT_MENU_SHOW
, ITEMPOS_INVALID
);
281 else if( rEvent
.GetId() == VCLEVENT_WINDOW_HIDE
)
282 pMenu
->ImplCallEventListeners( VCLEVENT_MENU_HIDE
, ITEMPOS_INVALID
);
285 void MenuBarWindow::ImplCreatePopup( bool bPreSelectFirst
)
287 MenuItemData
* pItemData
= pMenu
? pMenu
->GetItemList()->GetDataFromPos( nHighlightedItem
) : nullptr;
290 bIgnoreFirstMove
= true;
291 if ( pActivePopup
&& ( pActivePopup
!= pItemData
->pSubMenu
) )
295 if ( pItemData
->bEnabled
&& pItemData
->pSubMenu
&& ( nHighlightedItem
!= ITEMPOS_INVALID
) &&
296 ( pItemData
->pSubMenu
!= pActivePopup
) )
298 pActivePopup
= static_cast<PopupMenu
*>(pItemData
->pSubMenu
.get());
300 MenuItemData
* pData
= nullptr;
301 for ( sal_uLong n
= 0; n
< nHighlightedItem
; n
++ )
303 pData
= pMenu
->GetItemList()->GetDataFromPos( n
);
304 nX
+= pData
->aSz
.Width();
306 pData
= pMenu
->pItemList
->GetDataFromPos( nHighlightedItem
);
307 Point
aItemTopLeft( nX
, 0 );
308 Point
aItemBottomRight( aItemTopLeft
);
309 aItemBottomRight
.X() += pData
->aSz
.Width();
311 // the menu bar could have height 0 in fullscreen mode:
312 // so do not use always WindowHeight, as ItemHeight < WindowHeight.
313 if ( GetSizePixel().Height() )
315 // #107747# give menuitems the height of the menubar
316 aItemBottomRight
.Y() += GetOutputSizePixel().Height()-1;
319 // ImplExecute is not modal...
320 // #99071# do not grab the focus, otherwise it will be restored to the menubar
321 // when the frame is reactivated later
323 pActivePopup
->ImplExecute( this, Rectangle( aItemTopLeft
, aItemBottomRight
), FloatWinPopupFlags::Down
| FloatWinPopupFlags::NoHorzPlacement
, pMenu
, bPreSelectFirst
);
324 // does not have a window, if aborted before or if there are no entries
325 if ( pActivePopup
->ImplGetFloatingWindow() )
326 pActivePopup
->ImplGetFloatingWindow()->AddPopupModeWindow( this );
328 pActivePopup
= nullptr;
333 void MenuBarWindow::KillActivePopup()
337 if( pActivePopup
->pWindow
)
338 if( static_cast<FloatingWindow
*>(pActivePopup
->pWindow
.get())->IsInCleanUp() )
339 return; // kill it later
341 if ( pActivePopup
->bInCallback
)
342 pActivePopup
->bCanceled
= true;
344 pActivePopup
->bInCallback
= true;
345 pActivePopup
->Deactivate();
346 pActivePopup
->bInCallback
= false;
347 // check for pActivePopup, if stopped by deactivate...
348 if ( pActivePopup
->ImplGetWindow() )
350 pActivePopup
->ImplGetFloatingWindow()->StopExecute();
351 pActivePopup
->ImplGetFloatingWindow()->doShutdown();
352 pActivePopup
->pWindow
->doLazyDelete();
353 pActivePopup
->pWindow
= nullptr;
355 pActivePopup
= nullptr;
359 void MenuBarWindow::PopupClosed( Menu
* pPopup
)
361 if ( pPopup
== pActivePopup
)
364 ChangeHighlightItem( ITEMPOS_INVALID
, false, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus
, false );
368 void MenuBarWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
371 SetMBWMenuKey(false);
372 sal_uInt16 nEntry
= ImplFindEntry( rMEvt
.GetPosPixel() );
373 if ( ( nEntry
!= ITEMPOS_INVALID
) && !pActivePopup
)
375 ChangeHighlightItem( nEntry
, false );
380 ChangeHighlightItem( ITEMPOS_INVALID
, false );
384 void MenuBarWindow::MouseButtonUp( const MouseEvent
& )
388 void MenuBarWindow::MouseMove( const MouseEvent
& rMEvt
)
390 if ( rMEvt
.IsSynthetic() || rMEvt
.IsEnterWindow() )
393 if ( rMEvt
.IsLeaveWindow() )
395 if ( nRolloveredItem
!= ITEMPOS_INVALID
&& nRolloveredItem
!= nHighlightedItem
)
397 // there is a spurious MouseMove generated after a menu is launched from the keyboard, hence this...
398 if (nHighlightedItem
!= ITEMPOS_INVALID
)
400 bool hide
= GetMBWHideAccel();
401 SetMBWHideAccel(true);
402 Invalidate(); //HighlightItem( nRolloveredItem, false );
403 SetMBWHideAccel(hide
);
406 Invalidate(); //HighlightItem( nRolloveredItem, false );
409 nRolloveredItem
= ITEMPOS_INVALID
;
413 sal_uInt16 nEntry
= ImplFindEntry( rMEvt
.GetPosPixel() );
414 if ( nHighlightedItem
== ITEMPOS_INVALID
)
416 if ( nRolloveredItem
!= nEntry
)
418 if ( nRolloveredItem
!= ITEMPOS_INVALID
)
419 Invalidate(); //HighlightItem( nRolloveredItem, false );
421 nRolloveredItem
= nEntry
;
422 Invalidate(); //HighlightItem( nRolloveredItem, true );
426 nRolloveredItem
= nEntry
;
428 if( bIgnoreFirstMove
)
430 bIgnoreFirstMove
= false;
434 if ( ( nEntry
!= ITEMPOS_INVALID
)
435 && ( nEntry
!= nHighlightedItem
) )
436 ChangeHighlightItem( nEntry
, false );
439 void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n
, bool bSelectEntry
, bool bAllowRestoreFocus
, bool bDefaultToDocument
)
444 // always hide accelerators when updating the menu bar...
445 SetMBWHideAccel(true);
447 // #57934# close active popup if applicable, as TH's background storage works.
448 MenuItemData
* pNextData
= pMenu
->pItemList
->GetDataFromPos( n
);
449 if ( pActivePopup
&& pActivePopup
->ImplGetWindow() && ( !pNextData
|| ( pActivePopup
!= pNextData
->pSubMenu
) ) )
450 KillActivePopup(); // pActivePopup when applicable without pWin, if Rescheduled in Activate()
452 // activate menubar only ones per cycle...
453 bool bJustActivated
= false;
454 if ( ( nHighlightedItem
== ITEMPOS_INVALID
) && ( n
!= ITEMPOS_INVALID
) )
456 ImplGetSVData()->maWinData
.mbNoDeactivate
= true;
457 // #105406# avoid saving the focus when we already have the focus
458 bool bNoSaveFocus
= (this == ImplGetSVData()->maWinData
.mpFocusWin
.get() );
460 if( xSaveFocusId
!= nullptr )
462 if( !ImplGetSVData()->maWinData
.mbNoSaveFocus
)
464 xSaveFocusId
= nullptr;
466 xSaveFocusId
= Window::SaveFocus(); // only save focus when initially activated
469 ; // do nothing: we 're activated again from taskpanelist, focus was already saved
475 xSaveFocusId
= Window::SaveFocus(); // only save focus when initially activated
477 pMenu
->bInCallback
= true; // set here if Activate overridden
479 pMenu
->bInCallback
= false;
480 bJustActivated
= true;
482 else if ( ( nHighlightedItem
!= ITEMPOS_INVALID
) && ( n
== ITEMPOS_INVALID
) )
484 pMenu
->bInCallback
= true;
486 pMenu
->bInCallback
= false;
487 ImplGetSVData()->maWinData
.mbNoDeactivate
= false;
488 if( !ImplGetSVData()->maWinData
.mbNoSaveFocus
)
490 VclPtr
<vcl::Window
> xTempFocusId
= xSaveFocusId
;
491 xSaveFocusId
= nullptr;
492 if (bAllowRestoreFocus
)
493 Window::EndSaveFocus(xTempFocusId
);
494 // #105406# restore focus to document if we could not save focus before
495 if (bDefaultToDocument
&& xTempFocusId
== nullptr && bAllowRestoreFocus
)
496 GrabFocusToDocument();
500 if ( nHighlightedItem
!= ITEMPOS_INVALID
)
502 if ( nHighlightedItem
!= nRolloveredItem
)
503 Invalidate(); //HighlightItem( nHighlightedItem, false );
505 pMenu
->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT
, nHighlightedItem
);
508 nHighlightedItem
= (sal_uInt16
)n
;
509 SAL_WARN_IF( ( nHighlightedItem
!= ITEMPOS_INVALID
) && !pMenu
->ImplIsVisible( nHighlightedItem
), "vcl", "ChangeHighlightItem: Not visible!" );
510 if ( nHighlightedItem
!= ITEMPOS_INVALID
)
511 Invalidate(); //HighlightItem( nHighlightedItem, true );
512 else if ( nRolloveredItem
!= ITEMPOS_INVALID
)
513 Invalidate(); //HighlightItem( nRolloveredItem, true );
514 pMenu
->ImplCallHighlight(nHighlightedItem
);
517 ImplCreatePopup( bSelectEntry
);
519 // #58935# #73659# Focus, if no popup underneath...
520 if ( bJustActivated
&& !pActivePopup
)
524 static int ImplGetTopDockingAreaHeight( vcl::Window
*pWindow
)
526 // find docking area that is top aligned and return its height
527 // note: dockingareas are direct children of the SystemWindow
528 if( pWindow
->ImplGetFrameWindow() )
530 vcl::Window
*pWin
= pWindow
->ImplGetFrameWindow()->GetWindow( GetWindowType::FirstChild
); //mpWindowImpl->mpFirstChild;
533 if( pWin
->IsSystemWindow() )
535 vcl::Window
*pChildWin
= pWin
->GetWindow( GetWindowType::FirstChild
); //mpWindowImpl->mpFirstChild;
538 DockingAreaWindow
*pDockingArea
= nullptr;
539 if ( pChildWin
->GetType() == WINDOW_DOCKINGAREA
)
540 pDockingArea
= static_cast< DockingAreaWindow
* >( pChildWin
);
542 if( pDockingArea
&& pDockingArea
->GetAlign() == WindowAlign::Top
&&
543 pDockingArea
->IsVisible() && pDockingArea
->GetOutputSizePixel().Height() != 0 )
545 return pDockingArea
->GetOutputSizePixel().Height();
548 pChildWin
= pChildWin
->GetWindow( GetWindowType::Next
); //mpWindowImpl->mpNext;
553 pWin
= pWin
->GetWindow( GetWindowType::Next
); //mpWindowImpl->mpNext;
559 static void ImplAddNWFSeparator(vcl::RenderContext
& rRenderContext
, const Size
& rSize
, const MenubarValue
& rMenubarValue
)
561 // add a separator if
562 // - we have an adjacent docking area
563 // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
564 if (rMenubarValue
.maTopDockingAreaHeight
565 && !ImplGetSVData()->maNWFData
.mbDockingAreaSeparateTB
566 && !ImplGetSVData()->maNWFData
.mbDockingAreaAvoidTBFrames
)
568 // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
570 rRenderContext
.SetLineColor(rRenderContext
.GetSettings().GetStyleSettings().GetSeparatorColor());
572 Rectangle
aRect(aPt
, rSize
);
573 rRenderContext
.DrawLine(aRect
.BottomLeft(), aRect
.BottomRight());
577 void MenuBarWindow::HighlightItem(vcl::RenderContext
& rRenderContext
, sal_uInt16 nPos
)
583 size_t nCount
= pMenu
->pItemList
->size();
584 for (size_t n
= 0; n
< nCount
; n
++)
586 MenuItemData
* pData
= pMenu
->pItemList
->GetDataFromPos( n
);
589 if (pData
->eType
!= MenuItemType::SEPARATOR
)
591 // #107747# give menuitems the height of the menubar
592 Rectangle aRect
= Rectangle(Point(nX
, 1), Size(pData
->aSz
.Width(), GetOutputSizePixel().Height() - 2));
593 rRenderContext
.Push(PushFlags::CLIPREGION
);
594 rRenderContext
.IntersectClipRegion(aRect
);
595 bool bRollover
, bHighlight
;
596 if (!ImplGetSVData()->maNWFData
.mbRolloverMenubar
)
599 bRollover
= nPos
!= nHighlightedItem
;
603 bRollover
= nPos
== nRolloveredItem
;
604 bHighlight
= nPos
== nHighlightedItem
;
606 if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::MenuItem
) &&
607 rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
609 // draw background (transparency)
610 MenubarValue aControlValue
;
611 aControlValue
.maTopDockingAreaHeight
= ImplGetTopDockingAreaHeight( this );
613 if (!Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() )
614 Erase(rRenderContext
);
617 Rectangle
aBgRegion(Point(), GetOutputSizePixel());
618 rRenderContext
.DrawNativeControl(ControlType::Menubar
, ControlPart::Entire
, aBgRegion
,
619 ControlState::ENABLED
, aControlValue
, OUString());
622 ImplAddNWFSeparator(rRenderContext
, GetOutputSizePixel(), aControlValue
);
624 // draw selected item
625 ControlState nState
= ControlState::ENABLED
;
627 nState
|= ControlState::ROLLOVER
;
629 nState
|= ControlState::SELECTED
;
630 rRenderContext
.DrawNativeControl(ControlType::Menubar
, ControlPart::MenuItem
,
631 aRect
, nState
, aControlValue
, OUString() );
636 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetMenuBarRolloverColor());
638 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetMenuHighlightColor());
639 rRenderContext
.SetLineColor();
640 rRenderContext
.DrawRect(aRect
);
642 rRenderContext
.Pop();
643 pMenu
->ImplPaint(rRenderContext
, 0, 0, pData
, bHighlight
, false, bRollover
);
648 nX
+= pData
->aSz
.Width();
652 Rectangle
MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos
)
658 size_t nCount
= pMenu
->pItemList
->size();
659 for ( size_t n
= 0; n
< nCount
; n
++ )
661 MenuItemData
* pData
= pMenu
->pItemList
->GetDataFromPos( n
);
664 if ( pData
->eType
!= MenuItemType::SEPARATOR
)
665 // #107747# give menuitems the height of the menubar
666 aRect
= Rectangle( Point( nX
, 1 ), Size( pData
->aSz
.Width(), GetOutputSizePixel().Height()-2 ) );
670 nX
+= pData
->aSz
.Width();
676 void MenuBarWindow::KeyInput( const KeyEvent
& rKEvent
)
678 if ( !HandleKeyEvent( rKEvent
) )
679 Window::KeyInput( rKEvent
);
682 bool MenuBarWindow::HandleKeyEvent( const KeyEvent
& rKEvent
, bool bFromMenu
)
687 if (pMenu
->bInCallback
)
688 return true; // swallow
691 sal_uInt16 nCode
= rKEvent
.GetKeyCode().GetCode();
695 if( GetParent()->GetWindow( GetWindowType::Client
)->IsSystemWindow() )
697 SystemWindow
*pSysWin
= static_cast<SystemWindow
*>(GetParent()->GetWindow( GetWindowType::Client
));
698 if( pSysWin
->GetTaskPaneList() )
699 if( pSysWin
->GetTaskPaneList()->HandleKeyEvent( rKEvent
) )
704 if ( nCode
== KEY_MENU
&& !rKEvent
.GetKeyCode().IsShift() ) // only F10, not Shift-F10
706 mbAutoPopup
= ImplGetSVData()->maNWFData
.mbOpenMenuOnF10
;
707 if ( nHighlightedItem
== ITEMPOS_INVALID
)
709 ChangeHighlightItem( 0, false );
714 ChangeHighlightItem( ITEMPOS_INVALID
, false );
715 xSaveFocusId
= nullptr;
719 else if ( bFromMenu
)
721 if ( ( nCode
== KEY_LEFT
) || ( nCode
== KEY_RIGHT
) ||
722 ( nCode
== KEY_HOME
) || ( nCode
== KEY_END
) )
724 sal_uInt16 n
= nHighlightedItem
;
725 if ( n
== ITEMPOS_INVALID
)
727 if ( nCode
== KEY_LEFT
)
730 n
= pMenu
->GetItemCount()-1;
733 // handling gtk like (aka mbOpenMenuOnF10)
734 // do not highlight an item when opening a sub menu
735 // unless there already was a higlighted sub menu item
736 bool bWasHighlight
= false;
739 MenuFloatingWindow
* pSubWindow
= dynamic_cast<MenuFloatingWindow
*>(pActivePopup
->ImplGetWindow());
741 bWasHighlight
= (pSubWindow
->GetHighlightedItem() != ITEMPOS_INVALID
);
744 sal_uInt16 nLoop
= n
;
746 if( nCode
== KEY_HOME
)
747 { n
= (sal_uInt16
)-1; nLoop
= n
+1; }
748 if( nCode
== KEY_END
)
749 { n
= pMenu
->GetItemCount(); nLoop
= n
-1; }
753 if ( nCode
== KEY_LEFT
|| nCode
== KEY_END
)
758 n
= pMenu
->GetItemCount()-1;
760 if ( nCode
== KEY_RIGHT
|| nCode
== KEY_HOME
)
763 if ( n
>= pMenu
->GetItemCount() )
767 MenuItemData
* pData
= pMenu
->GetItemList()->GetDataFromPos( n
);
768 if ( ( pData
->eType
!= MenuItemType::SEPARATOR
) && pMenu
->ImplIsVisible( n
) )
770 bool bDoSelect
= true;
771 if( ImplGetSVData()->maNWFData
.mbOpenMenuOnF10
)
772 bDoSelect
= bWasHighlight
;
773 ChangeHighlightItem( n
, bDoSelect
);
776 } while ( n
!= nLoop
);
779 else if ( nCode
== KEY_RETURN
)
781 if( pActivePopup
) KillActivePopup();
785 ImplCreatePopup( true );
790 else if ( ( nCode
== KEY_UP
) || ( nCode
== KEY_DOWN
) )
794 ImplCreatePopup( true );
799 else if ( nCode
== KEY_ESCAPE
|| ( nCode
== KEY_F6
&& rKEvent
.GetKeyCode().IsMod1() ) )
803 // hide the menu and remove the focus...
808 ChangeHighlightItem( ITEMPOS_INVALID
, false );
810 if( nCode
== KEY_F6
&& rKEvent
.GetKeyCode().IsMod1() )
812 // put focus into document
813 GrabFocusToDocument();
820 bool accel
= ImplGetSVData()->maNWFData
.mbEnableAccel
;
821 bool autoacc
= ImplGetSVData()->maNWFData
.mbAutoAccel
;
823 if ( !bDone
&& ( bFromMenu
|| (rKEvent
.GetKeyCode().IsMod2() && accel
) ) )
825 sal_Unicode nCharCode
= rKEvent
.GetCharCode();
828 sal_uInt16 nEntry
, nDuplicates
;
829 MenuItemData
* pData
= pMenu
->GetItemList()->SearchItem( nCharCode
, rKEvent
.GetKeyCode(), nEntry
, nDuplicates
, nHighlightedItem
);
830 if ( pData
&& (nEntry
!= ITEMPOS_INVALID
) )
833 ChangeHighlightItem( nEntry
, true );
839 const bool bShowAccels
= nCode
!= KEY_ESCAPE
;
840 if (GetMBWMenuKey() != bShowAccels
)
842 SetMBWMenuKey(bShowAccels
);
843 SetMBWHideAccel(!bShowAccels
);
844 if (accel
&& autoacc
)
845 Invalidate(InvalidateFlags::Update
);
851 void MenuBarWindow::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
&)
856 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
858 // no VCL paint if native menus
859 if (pMenu
->ImplGetSalMenu() && pMenu
->ImplGetSalMenu()->VisibleMenuBar())
861 ImplGetFrame()->DrawMenuBar();
865 if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
867 MenubarValue aMenubarValue
;
868 aMenubarValue
.maTopDockingAreaHeight
= ImplGetTopDockingAreaHeight(this);
870 if (!rStyleSettings
.GetPersonaHeader().IsEmpty())
871 Erase(rRenderContext
);
875 Rectangle
aCtrlRegion( aPt
, GetOutputSizePixel() );
877 rRenderContext
.DrawNativeControl(ControlType::Menubar
, ControlPart::Entire
, aCtrlRegion
,
878 ControlState::ENABLED
, aMenubarValue
, OUString());
881 ImplAddNWFSeparator(rRenderContext
, GetOutputSizePixel(), aMenubarValue
);
883 rRenderContext
.SetFillColor(rStyleSettings
.GetMenuColor());
885 pMenu
->ImplPaint(rRenderContext
, 0);
886 if (nHighlightedItem
!= ITEMPOS_INVALID
)
887 HighlightItem(rRenderContext
, nHighlightedItem
);
888 else if (ImplGetSVData()->maNWFData
.mbRolloverMenubar
&& nRolloveredItem
!= ITEMPOS_INVALID
)
889 HighlightItem(rRenderContext
, nRolloveredItem
);
891 // in high contrast mode draw a separating line on the lower edge
892 if (!rRenderContext
.IsNativeControlSupported( ControlType::Menubar
, ControlPart::Entire
) &&
893 rStyleSettings
.GetHighContrastMode())
895 rRenderContext
.Push(PushFlags::LINECOLOR
| PushFlags::MAPMODE
);
896 rRenderContext
.SetLineColor(Color(COL_WHITE
));
897 rRenderContext
.SetMapMode(MapMode(MapUnit::MapPixel
));
898 Size aSize
= GetSizePixel();
899 rRenderContext
.DrawLine(Point(0, aSize
.Height() - 1),
900 Point(aSize
.Width() - 1, aSize
.Height() - 1));
901 rRenderContext
.Pop();
905 void MenuBarWindow::Resize()
907 Size aOutSz
= GetOutputSizePixel();
908 long n
= aOutSz
.Height()-4;
909 long nX
= aOutSz
.Width()-3;
912 if ( aCloseBtn
->IsVisible() )
915 aCloseBtn
->SetImages(n
);
916 Size
aTbxSize( aCloseBtn
->CalcWindowSizePixel() );
917 nX
-= aTbxSize
.Width();
918 long nTbxY
= (aOutSz
.Height() - aTbxSize
.Height())/2;
919 aCloseBtn
->setPosSizePixel(nX
, nTbxY
, aTbxSize
.Width(), aTbxSize
.Height());
923 if ( aFloatBtn
->IsVisible() )
926 aFloatBtn
->setPosSizePixel( nX
, nY
, n
, n
);
928 if ( aHideBtn
->IsVisible() )
931 aHideBtn
->setPosSizePixel( nX
, nY
, n
, n
);
934 aFloatBtn
->SetSymbol( SymbolType::FLOAT
);
935 aHideBtn
->SetSymbol( SymbolType::HIDE
);
940 sal_uInt16
MenuBarWindow::ImplFindEntry( const Point
& rMousePos
) const
945 size_t nCount
= pMenu
->pItemList
->size();
946 for ( size_t n
= 0; n
< nCount
; n
++ )
948 MenuItemData
* pData
= pMenu
->pItemList
->GetDataFromPos( n
);
949 if ( pMenu
->ImplIsVisible( n
) )
951 nX
+= pData
->aSz
.Width();
952 if ( nX
> rMousePos
.X() )
953 return (sal_uInt16
)n
;
957 return ITEMPOS_INVALID
;
960 void MenuBarWindow::RequestHelp( const HelpEvent
& rHEvt
)
962 sal_uInt16 nId
= nHighlightedItem
;
963 if ( rHEvt
.GetMode() & (HelpEventMode::CONTEXT
| HelpEventMode::EXTENDED
) )
964 ChangeHighlightItem( ITEMPOS_INVALID
, true );
966 Rectangle
aHighlightRect( ImplGetItemRect( nHighlightedItem
) );
967 if( !ImplHandleHelpEvent( this, pMenu
, nId
, rHEvt
, aHighlightRect
) )
968 Window::RequestHelp( rHEvt
);
971 void MenuBarWindow::StateChanged( StateChangedType nType
)
973 Window::StateChanged( nType
);
975 if (nType
== StateChangedType::ControlForeground
||
976 nType
== StateChangedType::ControlBackground
)
978 ApplySettings(*this);
981 else if (nType
== StateChangedType::Enable
)
987 pMenu
->ImplKillLayoutData();
991 void MenuBarWindow::LayoutChanged()
996 ApplySettings(*this);
998 // if the font was changed.
999 long nHeight
= pMenu
->ImplCalcSize(this).Height();
1001 // depending on the native implementation or the displayable flag
1002 // the menubar windows is suppressed (ie, height=0)
1003 if (!static_cast<MenuBar
*>(pMenu
.get())->IsDisplayable() ||
1004 (pMenu
->ImplGetSalMenu() && pMenu
->ImplGetSalMenu()->VisibleMenuBar()))
1008 setPosSizePixel(0, 0, 0, nHeight
, PosSizeFlags::Height
);
1009 GetParent()->Resize();
1013 pMenu
->ImplKillLayoutData();
1016 void MenuBarWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
1018 Window::ApplySettings(rRenderContext
);
1019 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1021 SetPointFont(rRenderContext
, rStyleSettings
.GetMenuFont());
1023 const BitmapEx
& rPersonaBitmap
= Application::GetSettings().GetStyleSettings().GetPersonaHeader();
1024 if (!rPersonaBitmap
.IsEmpty())
1026 Wallpaper
aWallpaper(rPersonaBitmap
);
1027 aWallpaper
.SetStyle(WallpaperStyle::TopRight
);
1028 aWallpaper
.SetColor(Application::GetSettings().GetStyleSettings().GetWorkspaceColor());
1030 rRenderContext
.SetBackground(aWallpaper
);
1031 SetPaintTransparent(false);
1032 SetParentClipMode();
1034 else if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
1036 rRenderContext
.SetBackground(); // background will be drawn by NWF
1040 Wallpaper aWallpaper
;
1041 aWallpaper
.SetStyle(WallpaperStyle::ApplicationGradient
);
1042 rRenderContext
.SetBackground(aWallpaper
);
1043 SetPaintTransparent(false);
1044 SetParentClipMode();
1047 rRenderContext
.SetTextColor(rStyleSettings
.GetMenuBarTextColor());
1048 rRenderContext
.SetTextFillColor();
1049 rRenderContext
.SetLineColor();
1052 void MenuBarWindow::ImplInitStyleSettings()
1054 if (IsNativeControlSupported(ControlType::Menubar
, ControlPart::MenuItem
) &&
1055 IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
1057 AllSettings
aSettings(GetSettings());
1058 ImplGetFrame()->UpdateSettings(aSettings
); // to update persona
1059 StyleSettings
aStyle(aSettings
.GetStyleSettings());
1060 Color aHighlightTextColor
= ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
;
1061 if (aHighlightTextColor
!= Color(COL_TRANSPARENT
))
1063 aStyle
.SetMenuHighlightTextColor(aHighlightTextColor
);
1065 aSettings
.SetStyleSettings(aStyle
);
1066 OutputDevice::SetSettings(aSettings
);
1070 void MenuBarWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
1072 Window::DataChanged( rDCEvt
);
1074 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1075 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1076 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1077 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1079 ApplySettings(*this);
1080 ImplInitStyleSettings();
1085 void MenuBarWindow::LoseFocus()
1087 if ( !HasChildPathFocus( true ) )
1088 ChangeHighlightItem( ITEMPOS_INVALID
, false, false );
1091 void MenuBarWindow::GetFocus()
1093 SalMenu
*pNativeMenu
= pMenu
? pMenu
->ImplGetSalMenu() : nullptr;
1094 if (pNativeMenu
&& pNativeMenu
->TakeFocus())
1097 if ( nHighlightedItem
== ITEMPOS_INVALID
)
1099 mbAutoPopup
= false; // do not open menu when activated by focus handling like taskpane cycling
1100 ChangeHighlightItem( 0, false );
1104 css::uno::Reference
<css::accessibility::XAccessible
> MenuBarWindow::CreateAccessible()
1106 css::uno::Reference
<css::accessibility::XAccessible
> xAcc
;
1109 xAcc
= pMenu
->GetAccessible();
1114 sal_uInt16
MenuBarWindow::AddMenuBarButton( const Image
& i_rImage
, const Link
<MenuBar::MenuBarButtonCallbackArg
&,bool>& i_rLink
, const OUString
& i_rToolTip
)
1116 // find first free button id
1117 sal_uInt16 nId
= IID_DOCUMENTCLOSE
;
1118 std::map
< sal_uInt16
, AddButtonEntry
>::const_iterator it
;
1122 it
= m_aAddButtons
.find( nId
);
1123 } while( it
!= m_aAddButtons
.end() && nId
< 128 );
1124 SAL_WARN_IF( nId
>= 128, "vcl", "too many addbuttons in menubar" );
1125 AddButtonEntry
& rNewEntry
= m_aAddButtons
[nId
];
1126 rNewEntry
.m_nId
= nId
;
1127 rNewEntry
.m_aSelectLink
= i_rLink
;
1128 aCloseBtn
->InsertItem(nId
, i_rImage
, ToolBoxItemBits::NONE
, 0);
1129 aCloseBtn
->calcMinSize();
1130 ShowButtons(aCloseBtn
->IsItemVisible(IID_DOCUMENTCLOSE
), aFloatBtn
->IsVisible(), aHideBtn
->IsVisible());
1133 if( pMenu
->mpSalMenu
)
1134 pMenu
->mpSalMenu
->AddMenuBarButton( SalMenuButtonItem( nId
, i_rImage
, i_rToolTip
) );
1139 void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId
, const Link
<MenuBar::MenuBarButtonCallbackArg
&,bool>& rLink
)
1141 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( nId
);
1142 if( it
!= m_aAddButtons
.end() )
1143 it
->second
.m_aHighlightLink
= rLink
;
1146 Rectangle
MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId
)
1149 if( m_aAddButtons
.find( nId
) != m_aAddButtons
.end() )
1151 if( pMenu
->mpSalMenu
)
1153 aRect
= pMenu
->mpSalMenu
->GetMenuBarButtonRectPixel( nId
, ImplGetWindowImpl()->mpFrame
);
1154 if( aRect
== Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
1156 // system menu button is somewhere but location cannot be determined
1161 if( aRect
.IsEmpty() )
1163 aRect
= aCloseBtn
->GetItemRect(nId
);
1164 Point aOffset
= aCloseBtn
->OutputToScreenPixel(Point());
1165 aRect
.Move( aOffset
.X(), aOffset
.Y() );
1171 void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId
)
1173 sal_uInt16 nPos
= aCloseBtn
->GetItemPos(nId
);
1174 aCloseBtn
->RemoveItem(nPos
);
1175 m_aAddButtons
.erase( nId
);
1176 aCloseBtn
->calcMinSize();
1179 if( pMenu
->mpSalMenu
)
1180 pMenu
->mpSalMenu
->RemoveMenuBarButton( nId
);
1183 bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId
)
1185 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( i_nButtonId
);
1186 if( it
!= m_aAddButtons
.end() )
1188 MenuBar::MenuBarButtonCallbackArg aArg
;
1189 aArg
.nId
= it
->first
;
1190 aArg
.bHighlight
= true;
1191 aArg
.pMenuBar
= dynamic_cast<MenuBar
*>(pMenu
.get());
1192 return it
->second
.m_aSelectLink
.Call( aArg
);
1197 bool MenuBarWindow::CanGetFocus() const
1199 /* #i83908# do not use the menubar if it is native or invisible
1200 this relies on MenuBar::ImplCreate setting the height of the menubar
1203 SalMenu
*pNativeMenu
= pMenu
? pMenu
->ImplGetSalMenu() : nullptr;
1204 if (pNativeMenu
&& pNativeMenu
->VisibleMenuBar())
1205 return pNativeMenu
->CanGetFocus();
1206 return GetSizePixel().Height() > 0;
1209 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */