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>
27 #include <sal/log.hxx>
29 #include <salframe.hxx>
30 #include <salmenu.hxx>
32 #include <strings.hrc>
33 #include <bitmaps.hlst>
35 #include "bufferdevice.hxx"
36 #include <menubarvalue.hxx>
38 // document closing button
39 #define IID_DOCUMENTCLOSE 1
41 DecoToolBox::DecoToolBox( vcl::Window
* pParent
) :
42 ToolBox( pParent
, 0 ),
48 void DecoToolBox::DataChanged( const DataChangedEvent
& rDCEvt
)
50 Window::DataChanged( rDCEvt
);
52 if ( rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)
60 void DecoToolBox::calcMinSize()
62 ScopedVclPtrInstance
<ToolBox
> aTbx( GetParent() );
63 if( GetItemCount() == 0 )
65 aTbx
->InsertItem(ToolBoxItemId(IID_DOCUMENTCLOSE
), Image(StockImage::Yes
, SV_RESID_BITMAP_CLOSEDOC
));
69 ImplToolItems::size_type nItems
= GetItemCount();
70 for( ImplToolItems::size_type i
= 0; i
< nItems
; i
++ )
72 ToolBoxItemId nId
= GetItemId( i
);
73 aTbx
->InsertItem( nId
, GetItemImage( nId
) );
76 maMinSize
= aTbx
->CalcWindowSizePixel();
78 aTbx
.disposeAndClear();
81 void DecoToolBox::SetImages( tools::Long nMaxHeight
, bool bForce
)
83 tools::Long border
= getMinSize().Height() - maImage
.GetSizePixel().Height();
85 if( !nMaxHeight
&& lastSize
!= -1 )
86 nMaxHeight
= lastSize
+ border
; // don't change anything if called with 0
88 if( nMaxHeight
< getMinSize().Height() )
89 nMaxHeight
= getMinSize().Height();
91 if( (lastSize
== nMaxHeight
- border
) && !bForce
)
94 lastSize
= nMaxHeight
- border
;
96 Color
aEraseColor( ColorTransparency
, 255, 255, 255, 255 );
97 BitmapEx
aBmpExDst( maImage
.GetBitmapEx() );
98 BitmapEx
aBmpExSrc( aBmpExDst
);
100 aEraseColor
.SetAlpha( 0 );
101 aBmpExDst
.Erase( aEraseColor
);
102 aBmpExDst
.Scale( Size( lastSize
, lastSize
) );
104 tools::Rectangle
aSrcRect( Point(0,0), maImage
.GetSizePixel() );
105 tools::Rectangle
aDestRect( Point((lastSize
- maImage
.GetSizePixel().Width())/2,
106 (lastSize
- maImage
.GetSizePixel().Height())/2 ),
107 maImage
.GetSizePixel() );
109 aBmpExDst
.CopyPixel( aDestRect
, aSrcRect
, &aBmpExSrc
);
110 SetItemImage( ToolBoxItemId(IID_DOCUMENTCLOSE
), Image( aBmpExDst
) );
114 MenuBarWindow::MenuBarWindow( vcl::Window
* pParent
) :
115 Window( pParent
, 0 ),
116 m_aCloseBtn(VclPtr
<DecoToolBox
>::Create(this)),
117 m_aFloatBtn(VclPtr
<PushButton
>::Create(this, WB_NOPOINTERFOCUS
| WB_SMALLSTYLE
| WB_RECTSTYLE
)),
118 m_aHideBtn(VclPtr
<PushButton
>::Create(this, WB_NOPOINTERFOCUS
| WB_SMALLSTYLE
| WB_RECTSTYLE
))
120 SetType(WindowType::MENUBARWINDOW
);
122 m_pActivePopup
= nullptr;
123 m_nHighlightedItem
= ITEMPOS_INVALID
;
124 m_nRolloveredItem
= ITEMPOS_INVALID
;
126 m_bIgnoreFirstMove
= true;
128 m_aCloseBtn
->maImage
= Image(StockImage::Yes
, SV_RESID_BITMAP_CLOSEDOC
);
130 m_aCloseBtn
->SetBackground();
131 m_aCloseBtn
->SetPaintTransparent(true);
132 m_aCloseBtn
->SetParentClipMode(ParentClipMode::NoClip
);
134 m_aCloseBtn
->InsertItem(ToolBoxItemId(IID_DOCUMENTCLOSE
), m_aCloseBtn
->maImage
);
135 m_aCloseBtn
->SetSelectHdl(LINK(this, MenuBarWindow
, CloseHdl
));
136 m_aCloseBtn
->AddEventListener(LINK(this, MenuBarWindow
, ToolboxEventHdl
));
137 m_aCloseBtn
->SetQuickHelpText(ToolBoxItemId(IID_DOCUMENTCLOSE
), VclResId(SV_HELPTEXT_CLOSEDOCUMENT
));
139 m_aFloatBtn
->SetSymbol( SymbolType::FLOAT
);
140 m_aFloatBtn
->SetQuickHelpText(VclResId(SV_HELPTEXT_RESTORE
));
142 m_aHideBtn
->SetSymbol( SymbolType::HIDE
);
143 m_aHideBtn
->SetQuickHelpText(VclResId(SV_HELPTEXT_MINIMIZE
));
145 ImplInitStyleSettings();
147 AddEventListener(LINK(this, MenuBarWindow
, ShowHideListener
));
150 MenuBarWindow::~MenuBarWindow()
155 void MenuBarWindow::dispose()
157 m_aCloseBtn
->RemoveEventListener(LINK(this, MenuBarWindow
, ToolboxEventHdl
));
158 RemoveEventListener(LINK(this, MenuBarWindow
, ShowHideListener
));
160 mpParentPopup
.disposeAndClear();
161 m_aHideBtn
.disposeAndClear();
162 m_aFloatBtn
.disposeAndClear();
163 m_aCloseBtn
.disposeAndClear();
165 m_pActivePopup
.clear();
166 m_xSaveFocusId
.clear();
171 void MenuBarWindow::SetMenu( MenuBar
* pMen
)
175 m_nHighlightedItem
= ITEMPOS_INVALID
;
178 m_aCloseBtn
->ShowItem(ToolBoxItemId(IID_DOCUMENTCLOSE
), pMen
->HasCloseButton());
179 m_aCloseBtn
->Show(pMen
->HasCloseButton() || !m_aAddButtons
.empty());
180 m_aFloatBtn
->Show(pMen
->HasFloatButton());
181 m_aHideBtn
->Show(pMen
->HasHideButton());
185 // show and connect native menubar
186 if( m_pMenu
&& m_pMenu
->ImplGetSalMenu() )
188 if( m_pMenu
->ImplGetSalMenu()->VisibleMenuBar() )
189 ImplGetFrame()->SetMenu( m_pMenu
->ImplGetSalMenu() );
191 m_pMenu
->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
192 m_pMenu
->ImplGetSalMenu()->ShowMenuBar(true);
196 void MenuBarWindow::SetHeight(tools::Long nHeight
)
198 setPosSizePixel(0, 0, 0, nHeight
, PosSizeFlags::Height
);
201 void MenuBarWindow::ShowButtons( bool bClose
, bool bFloat
, bool bHide
)
203 m_aCloseBtn
->ShowItem(ToolBoxItemId(IID_DOCUMENTCLOSE
), bClose
);
204 m_aCloseBtn
->Show(bClose
|| !m_aAddButtons
.empty());
205 if (m_pMenu
->mpSalMenu
)
206 m_pMenu
->mpSalMenu
->ShowCloseButton(bClose
);
207 m_aFloatBtn
->Show( bFloat
);
208 m_aHideBtn
->Show( bHide
);
212 Size
const & MenuBarWindow::MinCloseButtonSize() const
214 return m_aCloseBtn
->getMinSize();
217 IMPL_LINK_NOARG(MenuBarWindow
, CloseHdl
, ToolBox
*, void)
222 if( m_aCloseBtn
->GetCurItemId() == ToolBoxItemId(IID_DOCUMENTCLOSE
) )
224 // #i106052# call close hdl asynchronously to ease handler implementation
225 // this avoids still being in the handler while the DecoToolBox already
227 Application::PostUserEvent(static_cast<MenuBar
*>(m_pMenu
.get())->GetCloseButtonClickHdl());
231 std::map
<sal_uInt16
,AddButtonEntry
>::iterator it
= m_aAddButtons
.find(sal_uInt16(m_aCloseBtn
->GetCurItemId()));
232 if( it
!= m_aAddButtons
.end() )
234 MenuBarButtonCallbackArg aArg
;
235 aArg
.nId
= it
->first
;
236 aArg
.bHighlight
= (sal_uInt16(m_aCloseBtn
->GetHighlightItemId()) == it
->first
);
237 it
->second
.m_aSelectLink
.Call( aArg
);
242 IMPL_LINK( MenuBarWindow
, ToolboxEventHdl
, VclWindowEvent
&, rEvent
, void )
247 MenuBarButtonCallbackArg aArg
;
249 aArg
.bHighlight
= (rEvent
.GetId() == VclEventId::ToolboxHighlight
);
250 if( rEvent
.GetId() == VclEventId::ToolboxHighlight
)
251 aArg
.nId
=sal_uInt16(m_aCloseBtn
->GetHighlightItemId());
252 else if( rEvent
.GetId() == VclEventId::ToolboxHighlightOff
)
254 auto nPos
= static_cast<ToolBox::ImplToolItems::size_type
>(reinterpret_cast<sal_IntPtr
>(rEvent
.GetData()));
255 aArg
.nId
= sal_uInt16(m_aCloseBtn
->GetItemId(nPos
));
257 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( aArg
.nId
);
258 if( it
!= m_aAddButtons
.end() )
260 it
->second
.m_aHighlightLink
.Call( aArg
);
264 IMPL_LINK( MenuBarWindow
, ShowHideListener
, VclWindowEvent
&, rEvent
, void )
269 if( rEvent
.GetId() == VclEventId::WindowShow
)
270 m_pMenu
->ImplCallEventListeners( VclEventId::MenuShow
, ITEMPOS_INVALID
);
271 else if( rEvent
.GetId() == VclEventId::WindowHide
)
272 m_pMenu
->ImplCallEventListeners( VclEventId::MenuHide
, ITEMPOS_INVALID
);
275 void MenuBarWindow::ImplCreatePopup( bool bPreSelectFirst
)
277 MenuItemData
* pItemData
= m_pMenu
? m_pMenu
->GetItemList()->GetDataFromPos( m_nHighlightedItem
) : nullptr;
281 m_bIgnoreFirstMove
= true;
282 if ( m_pActivePopup
&& ( m_pActivePopup
!= pItemData
->pSubMenu
) )
286 if ( !(pItemData
->bEnabled
&& pItemData
->pSubMenu
&& ( m_nHighlightedItem
!= ITEMPOS_INVALID
) &&
287 ( pItemData
->pSubMenu
!= m_pActivePopup
)) )
290 m_pActivePopup
= static_cast<PopupMenu
*>(pItemData
->pSubMenu
.get());
292 MenuItemData
* pData
= nullptr;
293 for ( sal_uLong n
= 0; n
< m_nHighlightedItem
; n
++ )
295 pData
= m_pMenu
->GetItemList()->GetDataFromPos( n
);
296 nX
+= pData
->aSz
.Width();
298 pData
= m_pMenu
->pItemList
->GetDataFromPos( m_nHighlightedItem
);
299 Point
aItemTopLeft( nX
, 0 );
300 Point
aItemBottomRight( aItemTopLeft
);
301 aItemBottomRight
.AdjustX(pData
->aSz
.Width() );
303 if (pData
->bHiddenOnGUI
)
305 mpParentPopup
.disposeAndClear();
306 mpParentPopup
= VclPtr
<PopupMenu
>::Create();
307 m_pActivePopup
= mpParentPopup
.get();
309 for (sal_uInt16 i
= m_nHighlightedItem
; i
< m_pMenu
->GetItemCount(); ++i
)
311 sal_uInt16 nId
= m_pMenu
->GetItemId(i
);
313 MenuItemData
* pParentItemData
= m_pMenu
->GetItemList()->GetData(nId
);
314 assert(pParentItemData
);
315 mpParentPopup
->InsertItem(nId
, pParentItemData
->aText
, pParentItemData
->nBits
, pParentItemData
->sIdent
);
316 mpParentPopup
->SetHelpId(nId
, pParentItemData
->aHelpId
);
317 mpParentPopup
->SetHelpText(nId
, pParentItemData
->aHelpText
);
318 mpParentPopup
->SetAccelKey(nId
, pParentItemData
->aAccelKey
);
319 mpParentPopup
->SetItemCommand(nId
, pParentItemData
->aCommandStr
);
320 mpParentPopup
->SetHelpCommand(nId
, pParentItemData
->aHelpCommandStr
);
322 PopupMenu
* pPopup
= m_pMenu
->GetPopupMenu(nId
);
323 mpParentPopup
->SetPopupMenu(nId
, pPopup
);
326 // the menu bar could have height 0 in fullscreen mode:
327 // so do not use always WindowHeight, as ItemHeight < WindowHeight.
328 if ( GetSizePixel().Height() )
330 // #107747# give menuitems the height of the menubar
331 aItemBottomRight
.AdjustY(GetOutputSizePixel().Height()-1 );
334 // ImplExecute is not modal...
335 // #99071# do not grab the focus, otherwise it will be restored to the menubar
336 // when the frame is reactivated later
338 m_pActivePopup
->ImplExecute( this, tools::Rectangle( aItemTopLeft
, aItemBottomRight
), FloatWinPopupFlags::Down
| FloatWinPopupFlags::NoHorzPlacement
, m_pMenu
, bPreSelectFirst
);
339 // does not have a window, if aborted before or if there are no entries
340 if ( m_pActivePopup
->ImplGetFloatingWindow() )
341 m_pActivePopup
->ImplGetFloatingWindow()->AddPopupModeWindow( this );
343 m_pActivePopup
= nullptr;
346 void MenuBarWindow::KillActivePopup()
348 if ( !m_pActivePopup
)
351 if( m_pActivePopup
->pWindow
)
352 if( static_cast<FloatingWindow
*>(m_pActivePopup
->pWindow
.get())->IsInCleanUp() )
353 return; // kill it later
355 if ( m_pActivePopup
->bInCallback
)
356 m_pActivePopup
->bCanceled
= true;
358 m_pActivePopup
->bInCallback
= true;
359 m_pActivePopup
->Deactivate();
360 m_pActivePopup
->bInCallback
= false;
361 // check for pActivePopup, if stopped by deactivate...
362 if ( m_pActivePopup
->ImplGetWindow() )
366 for (sal_uInt16 i
= 0; i
< mpParentPopup
->GetItemCount(); ++i
)
368 sal_uInt16 nId
= mpParentPopup
->GetItemId(i
);
369 MenuItemData
* pParentItemData
= mpParentPopup
->GetItemList()->GetData(nId
);
370 assert(pParentItemData
);
371 pParentItemData
->pSubMenu
= nullptr;
374 m_pActivePopup
->ImplGetFloatingWindow()->StopExecute();
375 m_pActivePopup
->ImplGetFloatingWindow()->doShutdown();
376 m_pActivePopup
->pWindow
.disposeAndClear();
378 m_pActivePopup
= nullptr;
381 void MenuBarWindow::PopupClosed( Menu
const * pPopup
)
383 if ( pPopup
== m_pActivePopup
)
386 ChangeHighlightItem( ITEMPOS_INVALID
, false, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus
, false );
390 void MenuBarWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
393 sal_uInt16 nEntry
= ImplFindEntry( rMEvt
.GetPosPixel() );
394 if ( ( nEntry
!= ITEMPOS_INVALID
) && !m_pActivePopup
)
396 ChangeHighlightItem( nEntry
, false );
401 ChangeHighlightItem( ITEMPOS_INVALID
, false );
405 void MenuBarWindow::MouseButtonUp( const MouseEvent
& )
409 void MenuBarWindow::MouseMove( const MouseEvent
& rMEvt
)
411 if ( rMEvt
.IsSynthetic() || rMEvt
.IsEnterWindow() )
414 if ( rMEvt
.IsLeaveWindow() )
416 if ( m_nRolloveredItem
!= ITEMPOS_INVALID
&& m_nRolloveredItem
!= m_nHighlightedItem
)
417 Invalidate(); //HighlightItem( nRolloveredItem, false );
419 m_nRolloveredItem
= ITEMPOS_INVALID
;
423 sal_uInt16 nEntry
= ImplFindEntry( rMEvt
.GetPosPixel() );
424 if ( m_nHighlightedItem
== ITEMPOS_INVALID
)
426 if ( m_nRolloveredItem
!= nEntry
)
428 if ( m_nRolloveredItem
!= ITEMPOS_INVALID
)
429 Invalidate(); //HighlightItem( nRolloveredItem, false );
431 m_nRolloveredItem
= nEntry
;
432 Invalidate(); //HighlightItem( nRolloveredItem, true );
436 m_nRolloveredItem
= nEntry
;
438 if( m_bIgnoreFirstMove
)
440 m_bIgnoreFirstMove
= false;
444 if ( ( nEntry
!= ITEMPOS_INVALID
)
445 && ( nEntry
!= m_nHighlightedItem
) )
446 ChangeHighlightItem( nEntry
, false );
449 void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n
, bool bSelectEntry
, bool bAllowRestoreFocus
, bool bDefaultToDocument
)
454 // #57934# close active popup if applicable, as TH's background storage works.
455 MenuItemData
* pNextData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
456 if ( m_pActivePopup
&& m_pActivePopup
->ImplGetWindow() && ( !pNextData
|| ( m_pActivePopup
!= pNextData
->pSubMenu
) ) )
457 KillActivePopup(); // pActivePopup when applicable without pWin, if Rescheduled in Activate()
459 // activate menubar only ones per cycle...
460 bool bJustActivated
= false;
461 if ( ( m_nHighlightedItem
== ITEMPOS_INVALID
) && ( n
!= ITEMPOS_INVALID
) )
463 ImplGetSVData()->mpWinData
->mbNoDeactivate
= true;
464 // #105406# avoid saving the focus when we already have the focus
465 bool bNoSaveFocus
= (this == ImplGetSVData()->mpWinData
->mpFocusWin
.get());
467 if( m_xSaveFocusId
!= nullptr )
469 if (!ImplGetSVData()->mpWinData
->mbNoSaveFocus
)
471 m_xSaveFocusId
= nullptr;
473 m_xSaveFocusId
= Window::SaveFocus(); // only save focus when initially activated
476 ; // do nothing: we 're activated again from taskpanelist, focus was already saved
482 m_xSaveFocusId
= Window::SaveFocus(); // only save focus when initially activated
484 m_pMenu
->bInCallback
= true; // set here if Activate overridden
486 m_pMenu
->bInCallback
= false;
487 bJustActivated
= true;
489 else if ( ( m_nHighlightedItem
!= ITEMPOS_INVALID
) && ( n
== ITEMPOS_INVALID
) )
491 m_pMenu
->bInCallback
= true;
492 m_pMenu
->Deactivate();
493 m_pMenu
->bInCallback
= false;
494 ImplGetSVData()->mpWinData
->mbNoDeactivate
= false;
495 if (!ImplGetSVData()->mpWinData
->mbNoSaveFocus
)
497 VclPtr
<vcl::Window
> xTempFocusId
;
498 if (m_xSaveFocusId
&& !m_xSaveFocusId
->isDisposed())
499 xTempFocusId
= m_xSaveFocusId
;
500 m_xSaveFocusId
= nullptr;
502 if (bAllowRestoreFocus
)
504 // tdf#115227 the popup is already killed, so temporarily set us as the
505 // focus window, so we could avoid sending superfluous activate events
506 // to top window listeners.
507 if (xTempFocusId
|| bDefaultToDocument
)
508 ImplGetSVData()->mpWinData
->mpFocusWin
= this;
510 // #105406# restore focus to document if we could not save focus before
511 if (!xTempFocusId
&& bDefaultToDocument
)
512 GrabFocusToDocument();
514 Window::EndSaveFocus(xTempFocusId
);
519 if ( m_nHighlightedItem
!= ITEMPOS_INVALID
)
521 if ( m_nHighlightedItem
!= m_nRolloveredItem
)
522 Invalidate(); //HighlightItem( nHighlightedItem, false );
524 m_pMenu
->ImplCallEventListeners( VclEventId::MenuDehighlight
, m_nHighlightedItem
);
527 m_nHighlightedItem
= n
;
528 SAL_WARN_IF( ( m_nHighlightedItem
!= ITEMPOS_INVALID
) && !m_pMenu
->ImplIsVisible( m_nHighlightedItem
), "vcl", "ChangeHighlightItem: Not visible!" );
529 if ( m_nHighlightedItem
!= ITEMPOS_INVALID
)
530 Invalidate(); //HighlightItem( nHighlightedItem, true );
531 else if ( m_nRolloveredItem
!= ITEMPOS_INVALID
)
532 Invalidate(); //HighlightItem( nRolloveredItem, true );
533 m_pMenu
->ImplCallHighlight(m_nHighlightedItem
);
536 ImplCreatePopup( bSelectEntry
);
538 // #58935# #73659# Focus, if no popup underneath...
539 if ( bJustActivated
&& !m_pActivePopup
)
543 static int ImplGetTopDockingAreaHeight( vcl::Window
const *pWindow
)
545 // find docking area that is top aligned and return its height
546 // note: dockingareas are direct children of the SystemWindow
547 if( pWindow
->ImplGetFrameWindow() )
549 vcl::Window
*pWin
= pWindow
->ImplGetFrameWindow()->GetWindow( GetWindowType::FirstChild
); //mpWindowImpl->mpFirstChild;
552 if( pWin
->IsSystemWindow() )
554 vcl::Window
*pChildWin
= pWin
->GetWindow( GetWindowType::FirstChild
); //mpWindowImpl->mpFirstChild;
557 DockingAreaWindow
*pDockingArea
= nullptr;
558 if ( pChildWin
->GetType() == WindowType::DOCKINGAREA
)
559 pDockingArea
= static_cast< DockingAreaWindow
* >( pChildWin
);
561 if( pDockingArea
&& pDockingArea
->GetAlign() == WindowAlign::Top
&&
562 pDockingArea
->IsVisible() && pDockingArea
->GetOutputSizePixel().Height() != 0 )
564 return pDockingArea
->GetOutputSizePixel().Height();
567 pChildWin
= pChildWin
->GetWindow( GetWindowType::Next
); //mpWindowImpl->mpNext;
572 pWin
= pWin
->GetWindow( GetWindowType::Next
); //mpWindowImpl->mpNext;
578 static void ImplAddNWFSeparator(vcl::RenderContext
& rRenderContext
, const Size
& rSize
, const MenubarValue
& rMenubarValue
)
580 // add a separator if
581 // - we have an adjacent docking area
582 // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
583 if (rMenubarValue
.maTopDockingAreaHeight
584 && !ImplGetSVData()->maNWFData
.mbDockingAreaSeparateTB
585 && !ImplGetSVData()->maNWFData
.mbDockingAreaAvoidTBFrames
)
587 // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
589 rRenderContext
.SetLineColor(rRenderContext
.GetSettings().GetStyleSettings().GetSeparatorColor());
590 tools::Rectangle
aRect(Point(), rSize
);
591 rRenderContext
.DrawLine(aRect
.BottomLeft(), aRect
.BottomRight());
595 void MenuBarWindow::HighlightItem(vcl::RenderContext
& rRenderContext
, sal_uInt16 nPos
)
601 size_t nCount
= m_pMenu
->pItemList
->size();
603 Size aOutputSize
= GetOutputSizePixel();
604 aOutputSize
.AdjustWidth( -(m_aCloseBtn
->GetSizePixel().Width()) );
606 for (size_t n
= 0; n
< nCount
; n
++)
608 MenuItemData
* pData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
611 if (pData
->eType
!= MenuItemType::SEPARATOR
)
613 // #107747# give menuitems the height of the menubar
614 tools::Rectangle
aRect(Point(nX
, 1), Size(pData
->aSz
.Width(), aOutputSize
.Height() - 2));
615 rRenderContext
.Push(vcl::PushFlags::CLIPREGION
);
616 rRenderContext
.IntersectClipRegion(aRect
);
617 bool bRollover
, bHighlight
;
618 if (!ImplGetSVData()->maNWFData
.mbRolloverMenubar
)
621 bRollover
= nPos
!= m_nHighlightedItem
;
625 bRollover
= nPos
== m_nRolloveredItem
;
626 bHighlight
= nPos
== m_nHighlightedItem
;
628 if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::MenuItem
) &&
629 rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
631 // draw background (transparency)
632 MenubarValue aControlValue
;
633 aControlValue
.maTopDockingAreaHeight
= ImplGetTopDockingAreaHeight( this );
635 if (!Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() )
636 Erase(rRenderContext
);
639 tools::Rectangle
aBgRegion(Point(), aOutputSize
);
640 rRenderContext
.DrawNativeControl(ControlType::Menubar
, ControlPart::Entire
, aBgRegion
,
641 ControlState::ENABLED
, aControlValue
, OUString());
644 ImplAddNWFSeparator(rRenderContext
, aOutputSize
, aControlValue
);
646 // draw selected item
647 ControlState nState
= ControlState::ENABLED
;
649 nState
|= ControlState::ROLLOVER
;
651 nState
|= ControlState::SELECTED
;
652 rRenderContext
.DrawNativeControl(ControlType::Menubar
, ControlPart::MenuItem
,
653 aRect
, nState
, aControlValue
, OUString() );
658 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetMenuBarRolloverColor());
660 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetMenuHighlightColor());
661 rRenderContext
.SetLineColor();
662 rRenderContext
.DrawRect(aRect
);
664 rRenderContext
.Pop();
666 m_pMenu
->ImplPaint(rRenderContext
, aOutputSize
, 0, 0, pData
, bHighlight
, false, bRollover
);
671 nX
+= pData
->aSz
.Width();
675 tools::Rectangle
MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos
) const
677 tools::Rectangle aRect
;
681 size_t nCount
= m_pMenu
->pItemList
->size();
682 for ( size_t n
= 0; n
< nCount
; n
++ )
684 MenuItemData
* pData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
687 if ( pData
->eType
!= MenuItemType::SEPARATOR
)
688 // #107747# give menuitems the height of the menubar
689 aRect
= tools::Rectangle( Point( nX
, 1 ), Size( pData
->aSz
.Width(), GetOutputSizePixel().Height()-2 ) );
693 nX
+= pData
->aSz
.Width();
699 void MenuBarWindow::KeyInput( const KeyEvent
& rKEvent
)
701 if ( !HandleKeyEvent( rKEvent
) )
702 Window::KeyInput( rKEvent
);
705 bool MenuBarWindow::HandleKeyEvent( const KeyEvent
& rKEvent
, bool bFromMenu
)
710 if (m_pMenu
->bInCallback
)
711 return true; // swallow
714 sal_uInt16 nCode
= rKEvent
.GetKeyCode().GetCode();
718 if( GetParent()->GetWindow( GetWindowType::Client
)->IsSystemWindow() )
720 SystemWindow
*pSysWin
= static_cast<SystemWindow
*>(GetParent()->GetWindow( GetWindowType::Client
));
721 if( pSysWin
->GetTaskPaneList() )
722 if( pSysWin
->GetTaskPaneList()->HandleKeyEvent( rKEvent
) )
727 // no key events if native menus
728 if (m_pMenu
->ImplGetSalMenu() && m_pMenu
->ImplGetSalMenu()->VisibleMenuBar())
733 if ( nCode
== KEY_MENU
&& !rKEvent
.GetKeyCode().IsShift() ) // only F10, not Shift-F10
736 if ( m_nHighlightedItem
== ITEMPOS_INVALID
)
738 ChangeHighlightItem( 0, false );
743 ChangeHighlightItem( ITEMPOS_INVALID
, false );
744 m_xSaveFocusId
= nullptr;
748 else if ( bFromMenu
)
750 if ( ( nCode
== KEY_LEFT
) || ( nCode
== KEY_RIGHT
) ||
751 ( nCode
== KEY_HOME
) || ( nCode
== KEY_END
) )
753 sal_uInt16 n
= m_nHighlightedItem
;
754 if ( n
== ITEMPOS_INVALID
)
756 if ( nCode
== KEY_LEFT
)
759 n
= m_pMenu
->GetItemCount()-1;
762 sal_uInt16 nLoop
= n
;
764 if( nCode
== KEY_HOME
)
765 { n
= sal_uInt16(-1); nLoop
= n
+1; }
766 if( nCode
== KEY_END
)
767 { n
= m_pMenu
->GetItemCount(); nLoop
= n
-1; }
771 if ( nCode
== KEY_LEFT
|| nCode
== KEY_END
)
776 n
= m_pMenu
->GetItemCount()-1;
778 if ( nCode
== KEY_RIGHT
|| nCode
== KEY_HOME
)
781 if ( n
>= m_pMenu
->GetItemCount() )
785 MenuItemData
* pData
= m_pMenu
->GetItemList()->GetDataFromPos( n
);
786 if (pData
->eType
!= MenuItemType::SEPARATOR
&&
787 m_pMenu
->ImplIsVisible(n
) &&
788 !m_pMenu
->ImplCurrentlyHiddenOnGUI(n
))
790 ChangeHighlightItem( n
, true );
793 } while ( n
!= nLoop
);
796 else if ( nCode
== KEY_RETURN
)
798 if( m_pActivePopup
) KillActivePopup();
802 ImplCreatePopup( true );
807 else if ( ( nCode
== KEY_UP
) || ( nCode
== KEY_DOWN
) )
811 ImplCreatePopup( true );
816 else if ( nCode
== KEY_ESCAPE
|| ( nCode
== KEY_F6
&& rKEvent
.GetKeyCode().IsMod1() ) )
820 // hide the menu and remove the focus...
825 ChangeHighlightItem( ITEMPOS_INVALID
, false );
827 if( nCode
== KEY_F6
&& rKEvent
.GetKeyCode().IsMod1() )
829 // put focus into document
830 GrabFocusToDocument();
837 if ( !bDone
&& ( bFromMenu
|| rKEvent
.GetKeyCode().IsMod2() ) )
839 sal_Unicode nCharCode
= rKEvent
.GetCharCode();
842 size_t nEntry
, nDuplicates
;
843 MenuItemData
* pData
= m_pMenu
->GetItemList()->SearchItem( nCharCode
, rKEvent
.GetKeyCode(), nEntry
, nDuplicates
, m_nHighlightedItem
);
844 if ( pData
&& (nEntry
!= ITEMPOS_INVALID
) )
847 ChangeHighlightItem( nEntry
, true );
856 void MenuBarWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
861 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
863 Size aOutputSize
= GetOutputSizePixel();
865 // no VCL paint if native menus
866 if (m_pMenu
->ImplGetSalMenu() && m_pMenu
->ImplGetSalMenu()->VisibleMenuBar())
869 // Make sure that all actual rendering happens in one go to avoid flicker.
870 vcl::BufferDevice
pBuffer(this, rRenderContext
);
872 if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
874 MenubarValue aMenubarValue
;
875 aMenubarValue
.maTopDockingAreaHeight
= ImplGetTopDockingAreaHeight(this);
877 if (!rStyleSettings
.GetPersonaHeader().IsEmpty())
881 tools::Rectangle
aCtrlRegion( Point(), aOutputSize
);
883 pBuffer
->DrawNativeControl(ControlType::Menubar
, ControlPart::Entire
, aCtrlRegion
,
884 ControlState::ENABLED
, aMenubarValue
, OUString());
887 ImplAddNWFSeparator(*pBuffer
, aOutputSize
, aMenubarValue
);
890 // shrink the area of the buttons
891 aOutputSize
.AdjustWidth( -(m_aCloseBtn
->GetSizePixel().Width()) );
893 pBuffer
->SetFillColor(rStyleSettings
.GetMenuColor());
894 m_pMenu
->ImplPaint(*pBuffer
, aOutputSize
, 0);
896 if (m_nHighlightedItem
!= ITEMPOS_INVALID
&& m_pMenu
&& !m_pMenu
->GetItemList()->GetDataFromPos(m_nHighlightedItem
)->bHiddenOnGUI
)
897 HighlightItem(*pBuffer
, m_nHighlightedItem
);
898 else if (m_nRolloveredItem
!= ITEMPOS_INVALID
)
899 HighlightItem(*pBuffer
, m_nRolloveredItem
);
901 // in high contrast mode draw a separating line on the lower edge
902 if (!rRenderContext
.IsNativeControlSupported( ControlType::Menubar
, ControlPart::Entire
) &&
903 rStyleSettings
.GetHighContrastMode())
905 pBuffer
->Push(vcl::PushFlags::LINECOLOR
| vcl::PushFlags::MAPMODE
);
906 pBuffer
->SetLineColor(COL_WHITE
);
907 pBuffer
->SetMapMode(MapMode(MapUnit::MapPixel
));
908 Size aSize
= GetSizePixel();
909 pBuffer
->DrawLine(Point(0, aSize
.Height() - 1),
910 Point(aSize
.Width() - 1, aSize
.Height() - 1));
915 void MenuBarWindow::Resize()
917 Size aOutSz
= GetOutputSizePixel();
918 tools::Long n
= aOutSz
.Height()-4;
919 tools::Long nX
= aOutSz
.Width()-3;
922 if ( m_aCloseBtn
->IsVisible() )
925 m_aCloseBtn
->SetImages(n
);
926 Size
aTbxSize( m_aCloseBtn
->CalcWindowSizePixel() );
927 nX
-= aTbxSize
.Width();
928 tools::Long nTbxY
= (aOutSz
.Height() - aTbxSize
.Height())/2;
929 m_aCloseBtn
->setPosSizePixel(nX
, nTbxY
, aTbxSize
.Width(), aTbxSize
.Height());
933 if ( m_aFloatBtn
->IsVisible() )
936 m_aFloatBtn
->setPosSizePixel( nX
, nY
, n
, n
);
938 if ( m_aHideBtn
->IsVisible() )
941 m_aHideBtn
->setPosSizePixel( nX
, nY
, n
, n
);
944 m_aFloatBtn
->SetSymbol( SymbolType::FLOAT
);
945 m_aHideBtn
->SetSymbol( SymbolType::HIDE
);
950 sal_uInt16
MenuBarWindow::ImplFindEntry( const Point
& rMousePos
) const
955 size_t nCount
= m_pMenu
->pItemList
->size();
956 for ( size_t n
= 0; n
< nCount
; n
++ )
958 MenuItemData
* pData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
959 if ( m_pMenu
->ImplIsVisible( n
) )
961 nX
+= pData
->aSz
.Width();
962 if ( nX
> rMousePos
.X() )
963 return static_cast<sal_uInt16
>(n
);
967 return ITEMPOS_INVALID
;
970 void MenuBarWindow::RequestHelp( const HelpEvent
& rHEvt
)
972 sal_uInt16 nId
= m_nHighlightedItem
;
973 if ( rHEvt
.GetMode() & HelpEventMode::CONTEXT
)
974 ChangeHighlightItem( ITEMPOS_INVALID
, true );
976 tools::Rectangle
aHighlightRect( ImplGetItemRect( m_nHighlightedItem
) );
977 if( !ImplHandleHelpEvent( this, m_pMenu
, nId
, rHEvt
, aHighlightRect
) )
978 Window::RequestHelp( rHEvt
);
981 void MenuBarWindow::StateChanged( StateChangedType nType
)
983 Window::StateChanged( nType
);
985 if (nType
== StateChangedType::ControlForeground
||
986 nType
== StateChangedType::ControlBackground
)
988 ApplySettings(*GetOutDev());
991 else if (nType
== StateChangedType::Enable
)
997 m_pMenu
->ImplKillLayoutData();
1001 void MenuBarWindow::LayoutChanged()
1006 ApplySettings(*GetOutDev());
1008 // if the font was changed.
1009 tools::Long nHeight
= m_pMenu
->ImplCalcSize(this).Height();
1011 // depending on the native implementation or the displayable flag
1012 // the menubar windows is suppressed (ie, height=0)
1013 if (!static_cast<MenuBar
*>(m_pMenu
.get())->IsDisplayable() ||
1014 (m_pMenu
->ImplGetSalMenu() && m_pMenu
->ImplGetSalMenu()->VisibleMenuBar()))
1018 setPosSizePixel(0, 0, 0, nHeight
, PosSizeFlags::Height
);
1019 GetParent()->Resize();
1023 m_pMenu
->ImplKillLayoutData();
1026 void MenuBarWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
1028 Window::ApplySettings(rRenderContext
);
1029 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1031 SetPointFont(rRenderContext
, rStyleSettings
.GetMenuFont());
1033 const BitmapEx
& rPersonaBitmap
= Application::GetSettings().GetStyleSettings().GetPersonaHeader();
1034 SalMenu
*pNativeMenu
= m_pMenu
? m_pMenu
->ImplGetSalMenu() : nullptr;
1036 pNativeMenu
->ApplyPersona();
1037 if (!rPersonaBitmap
.IsEmpty())
1039 Wallpaper
aWallpaper(rPersonaBitmap
);
1040 aWallpaper
.SetStyle(WallpaperStyle::TopRight
);
1041 aWallpaper
.SetColor(Application::GetSettings().GetStyleSettings().GetWorkspaceColor());
1043 rRenderContext
.SetBackground(aWallpaper
);
1044 SetPaintTransparent(false);
1045 SetParentClipMode();
1047 else if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
1049 rRenderContext
.SetBackground(); // background will be drawn by NWF
1053 Wallpaper aWallpaper
;
1054 aWallpaper
.SetStyle(WallpaperStyle::ApplicationGradient
);
1055 rRenderContext
.SetBackground(aWallpaper
);
1056 SetPaintTransparent(false);
1057 SetParentClipMode();
1060 rRenderContext
.SetTextColor(rStyleSettings
.GetMenuBarTextColor());
1061 rRenderContext
.SetTextFillColor();
1062 rRenderContext
.SetLineColor();
1065 void MenuBarWindow::ImplInitStyleSettings()
1067 if (!(IsNativeControlSupported(ControlType::Menubar
, ControlPart::MenuItem
) &&
1068 IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
)))
1071 AllSettings
aSettings(GetSettings());
1072 ImplGetFrame()->UpdateSettings(aSettings
); // to update persona
1073 StyleSettings
aStyle(aSettings
.GetStyleSettings());
1074 Color aHighlightTextColor
= ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
;
1075 if (aHighlightTextColor
!= COL_TRANSPARENT
)
1077 aStyle
.SetMenuHighlightTextColor(aHighlightTextColor
);
1079 aSettings
.SetStyleSettings(aStyle
);
1080 GetOutDev()->SetSettings(aSettings
);
1083 void MenuBarWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
1085 Window::DataChanged( rDCEvt
);
1087 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1088 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1089 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1090 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1092 ApplySettings(*GetOutDev());
1093 ImplInitStyleSettings();
1098 void MenuBarWindow::LoseFocus()
1100 if ( !HasChildPathFocus( true ) )
1101 ChangeHighlightItem( ITEMPOS_INVALID
, false, false );
1104 void MenuBarWindow::GetFocus()
1106 SalMenu
*pNativeMenu
= m_pMenu
? m_pMenu
->ImplGetSalMenu() : nullptr;
1107 if (pNativeMenu
&& pNativeMenu
->TakeFocus())
1110 if ( m_nHighlightedItem
== ITEMPOS_INVALID
)
1112 mbAutoPopup
= false; // do not open menu when activated by focus handling like taskpane cycling
1113 ChangeHighlightItem( 0, false );
1117 css::uno::Reference
<css::accessibility::XAccessible
> MenuBarWindow::CreateAccessible()
1119 css::uno::Reference
<css::accessibility::XAccessible
> xAcc
;
1122 xAcc
= m_pMenu
->GetAccessible();
1127 sal_uInt16
MenuBarWindow::AddMenuBarButton( const Image
& i_rImage
, const Link
<MenuBarButtonCallbackArg
&,bool>& i_rLink
, const OUString
& i_rToolTip
)
1129 // find first free button id
1130 sal_uInt16 nId
= IID_DOCUMENTCLOSE
;
1131 std::map
< sal_uInt16
, AddButtonEntry
>::const_iterator it
;
1135 it
= m_aAddButtons
.find( nId
);
1136 } while( it
!= m_aAddButtons
.end() && nId
< 128 );
1137 SAL_WARN_IF( nId
>= 128, "vcl", "too many addbuttons in menubar" );
1138 AddButtonEntry
& rNewEntry
= m_aAddButtons
[nId
];
1139 rNewEntry
.m_aSelectLink
= i_rLink
;
1140 m_aCloseBtn
->InsertItem(ToolBoxItemId(nId
), i_rImage
, ToolBoxItemBits::NONE
, 0);
1141 m_aCloseBtn
->calcMinSize();
1142 ShowButtons(m_aCloseBtn
->IsItemVisible(ToolBoxItemId(IID_DOCUMENTCLOSE
)), m_aFloatBtn
->IsVisible(), m_aHideBtn
->IsVisible());
1145 if( m_pMenu
->mpSalMenu
)
1146 m_pMenu
->mpSalMenu
->AddMenuBarButton( SalMenuButtonItem( nId
, i_rImage
, i_rToolTip
) );
1151 void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId
, const Link
<MenuBarButtonCallbackArg
&,bool>& rLink
)
1153 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( nId
);
1154 if( it
!= m_aAddButtons
.end() )
1155 it
->second
.m_aHighlightLink
= rLink
;
1158 tools::Rectangle
MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId
)
1160 tools::Rectangle aRect
;
1161 if( m_aAddButtons
.find( nId
) != m_aAddButtons
.end() )
1163 if( m_pMenu
->mpSalMenu
)
1165 aRect
= m_pMenu
->mpSalMenu
->GetMenuBarButtonRectPixel( nId
, ImplGetWindowImpl()->mpFrame
);
1166 if( aRect
== tools::Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
1168 // system menu button is somewhere but location cannot be determined
1169 return tools::Rectangle();
1173 if( aRect
.IsEmpty() )
1175 aRect
= m_aCloseBtn
->GetItemRect(ToolBoxItemId(nId
));
1176 Point aOffset
= m_aCloseBtn
->OutputToScreenPixel(Point());
1177 aRect
.Move( aOffset
.X(), aOffset
.Y() );
1183 void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId
)
1185 ToolBox::ImplToolItems::size_type nPos
= m_aCloseBtn
->GetItemPos(ToolBoxItemId(nId
));
1186 m_aCloseBtn
->RemoveItem(nPos
);
1187 m_aAddButtons
.erase( nId
);
1188 m_aCloseBtn
->calcMinSize();
1191 if( m_pMenu
->mpSalMenu
)
1192 m_pMenu
->mpSalMenu
->RemoveMenuBarButton( nId
);
1195 bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId
)
1197 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( i_nButtonId
);
1198 if( it
!= m_aAddButtons
.end() )
1200 MenuBarButtonCallbackArg aArg
;
1201 aArg
.nId
= it
->first
;
1202 aArg
.bHighlight
= true;
1203 return it
->second
.m_aSelectLink
.Call( aArg
);
1208 bool MenuBarWindow::CanGetFocus() const
1210 /* #i83908# do not use the menubar if it is native or invisible
1211 this relies on MenuBar::ImplCreate setting the height of the menubar
1214 SalMenu
*pNativeMenu
= m_pMenu
? m_pMenu
->ImplGetSalMenu() : nullptr;
1215 if (pNativeMenu
&& pNativeMenu
->VisibleMenuBar())
1216 return pNativeMenu
->CanGetFocus();
1217 return GetSizePixel().Height() > 0;
1220 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */