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;
127 SetMBWHideAccel(ImplGetSVData()->maNWFData
.mbAutoAccel
);
128 SetMBWMenuKey(false);
130 m_aCloseBtn
->maImage
= Image(StockImage::Yes
, SV_RESID_BITMAP_CLOSEDOC
);
132 m_aCloseBtn
->SetBackground();
133 m_aCloseBtn
->SetPaintTransparent(true);
134 m_aCloseBtn
->SetParentClipMode(ParentClipMode::NoClip
);
136 m_aCloseBtn
->InsertItem(ToolBoxItemId(IID_DOCUMENTCLOSE
), m_aCloseBtn
->maImage
);
137 m_aCloseBtn
->SetSelectHdl(LINK(this, MenuBarWindow
, CloseHdl
));
138 m_aCloseBtn
->AddEventListener(LINK(this, MenuBarWindow
, ToolboxEventHdl
));
139 m_aCloseBtn
->SetQuickHelpText(ToolBoxItemId(IID_DOCUMENTCLOSE
), VclResId(SV_HELPTEXT_CLOSEDOCUMENT
));
141 m_aFloatBtn
->SetSymbol( SymbolType::FLOAT
);
142 m_aFloatBtn
->SetQuickHelpText(VclResId(SV_HELPTEXT_RESTORE
));
144 m_aHideBtn
->SetSymbol( SymbolType::HIDE
);
145 m_aHideBtn
->SetQuickHelpText(VclResId(SV_HELPTEXT_MINIMIZE
));
147 ImplInitStyleSettings();
149 AddEventListener(LINK(this, MenuBarWindow
, ShowHideListener
));
152 MenuBarWindow::~MenuBarWindow()
157 void MenuBarWindow::dispose()
159 m_aCloseBtn
->RemoveEventListener(LINK(this, MenuBarWindow
, ToolboxEventHdl
));
160 RemoveEventListener(LINK(this, MenuBarWindow
, ShowHideListener
));
162 mpParentPopup
.disposeAndClear();
163 m_aHideBtn
.disposeAndClear();
164 m_aFloatBtn
.disposeAndClear();
165 m_aCloseBtn
.disposeAndClear();
167 m_pActivePopup
.clear();
168 m_xSaveFocusId
.clear();
173 void MenuBarWindow::SetMenu( MenuBar
* pMen
)
177 m_nHighlightedItem
= ITEMPOS_INVALID
;
180 m_aCloseBtn
->ShowItem(ToolBoxItemId(IID_DOCUMENTCLOSE
), pMen
->HasCloseButton());
181 m_aCloseBtn
->Show(pMen
->HasCloseButton() || !m_aAddButtons
.empty());
182 m_aFloatBtn
->Show(pMen
->HasFloatButton());
183 m_aHideBtn
->Show(pMen
->HasHideButton());
187 // show and connect native menubar
188 if( m_pMenu
&& m_pMenu
->ImplGetSalMenu() )
190 if( m_pMenu
->ImplGetSalMenu()->VisibleMenuBar() )
191 ImplGetFrame()->SetMenu( m_pMenu
->ImplGetSalMenu() );
193 m_pMenu
->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
194 m_pMenu
->ImplGetSalMenu()->ShowMenuBar(true);
198 void MenuBarWindow::SetHeight(tools::Long nHeight
)
200 setPosSizePixel(0, 0, 0, nHeight
, PosSizeFlags::Height
);
203 void MenuBarWindow::ShowButtons( bool bClose
, bool bFloat
, bool bHide
)
205 m_aCloseBtn
->ShowItem(ToolBoxItemId(IID_DOCUMENTCLOSE
), bClose
);
206 m_aCloseBtn
->Show(bClose
|| !m_aAddButtons
.empty());
207 if (m_pMenu
->mpSalMenu
)
208 m_pMenu
->mpSalMenu
->ShowCloseButton(bClose
);
209 m_aFloatBtn
->Show( bFloat
);
210 m_aHideBtn
->Show( bHide
);
214 Size
const & MenuBarWindow::MinCloseButtonSize() const
216 return m_aCloseBtn
->getMinSize();
219 IMPL_LINK_NOARG(MenuBarWindow
, CloseHdl
, ToolBox
*, void)
224 if( m_aCloseBtn
->GetCurItemId() == ToolBoxItemId(IID_DOCUMENTCLOSE
) )
226 // #i106052# call close hdl asynchronously to ease handler implementation
227 // this avoids still being in the handler while the DecoToolBox already
229 Application::PostUserEvent(m_pMenu
->GetCloseButtonClickHdl());
233 std::map
<sal_uInt16
,AddButtonEntry
>::iterator it
= m_aAddButtons
.find(sal_uInt16(m_aCloseBtn
->GetCurItemId()));
234 if( it
!= m_aAddButtons
.end() )
236 MenuBarButtonCallbackArg aArg
;
237 aArg
.nId
= it
->first
;
238 aArg
.bHighlight
= (sal_uInt16(m_aCloseBtn
->GetHighlightItemId()) == it
->first
);
239 it
->second
.m_aSelectLink
.Call( aArg
);
244 IMPL_LINK( MenuBarWindow
, ToolboxEventHdl
, VclWindowEvent
&, rEvent
, void )
249 MenuBarButtonCallbackArg aArg
;
251 aArg
.bHighlight
= (rEvent
.GetId() == VclEventId::ToolboxHighlight
);
252 if( rEvent
.GetId() == VclEventId::ToolboxHighlight
)
253 aArg
.nId
=sal_uInt16(m_aCloseBtn
->GetHighlightItemId());
254 else if( rEvent
.GetId() == VclEventId::ToolboxHighlightOff
)
256 auto nPos
= static_cast<ToolBox::ImplToolItems::size_type
>(reinterpret_cast<sal_IntPtr
>(rEvent
.GetData()));
257 aArg
.nId
= sal_uInt16(m_aCloseBtn
->GetItemId(nPos
));
259 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( aArg
.nId
);
260 if( it
!= m_aAddButtons
.end() )
262 it
->second
.m_aHighlightLink
.Call( aArg
);
266 IMPL_LINK( MenuBarWindow
, ShowHideListener
, VclWindowEvent
&, rEvent
, void )
271 if( rEvent
.GetId() == VclEventId::WindowShow
)
272 m_pMenu
->ImplCallEventListeners( VclEventId::MenuShow
, ITEMPOS_INVALID
);
273 else if( rEvent
.GetId() == VclEventId::WindowHide
)
274 m_pMenu
->ImplCallEventListeners( VclEventId::MenuHide
, ITEMPOS_INVALID
);
277 void MenuBarWindow::ImplCreatePopup( bool bPreSelectFirst
)
279 MenuItemData
* pItemData
= m_pMenu
? m_pMenu
->GetItemList()->GetDataFromPos( m_nHighlightedItem
) : nullptr;
283 m_bIgnoreFirstMove
= true;
284 if ( m_pActivePopup
&& ( m_pActivePopup
!= pItemData
->pSubMenu
) )
288 if ( !(pItemData
->bEnabled
&& pItemData
->pSubMenu
&& ( m_nHighlightedItem
!= ITEMPOS_INVALID
) &&
289 ( pItemData
->pSubMenu
!= m_pActivePopup
)) )
292 m_pActivePopup
= pItemData
->pSubMenu
.get();
294 MenuItemData
* pData
= nullptr;
295 for ( sal_uLong n
= 0; n
< m_nHighlightedItem
; n
++ )
297 pData
= m_pMenu
->GetItemList()->GetDataFromPos( n
);
298 nX
+= pData
->aSz
.Width();
300 pData
= m_pMenu
->pItemList
->GetDataFromPos( m_nHighlightedItem
);
301 Point
aItemTopLeft( nX
, 0 );
302 Point
aItemBottomRight( aItemTopLeft
);
303 aItemBottomRight
.AdjustX(pData
->aSz
.Width() );
305 if (pData
->bHiddenOnGUI
)
307 mpParentPopup
.disposeAndClear();
308 mpParentPopup
= VclPtr
<PopupMenu
>::Create();
309 m_pActivePopup
= mpParentPopup
.get();
311 for (sal_uInt16 i
= m_nHighlightedItem
; i
< m_pMenu
->GetItemCount(); ++i
)
313 sal_uInt16 nId
= m_pMenu
->GetItemId(i
);
315 MenuItemData
* pParentItemData
= m_pMenu
->GetItemList()->GetData(nId
);
316 assert(pParentItemData
);
317 mpParentPopup
->InsertItem(nId
, pParentItemData
->aText
, pParentItemData
->nBits
, pParentItemData
->sIdent
);
318 mpParentPopup
->SetHelpId(nId
, pParentItemData
->aHelpId
);
319 mpParentPopup
->SetHelpText(nId
, pParentItemData
->aHelpText
);
320 mpParentPopup
->SetAccelKey(nId
, pParentItemData
->aAccelKey
);
321 mpParentPopup
->SetItemCommand(nId
, pParentItemData
->aCommandStr
);
322 mpParentPopup
->SetHelpCommand(nId
, pParentItemData
->aHelpCommandStr
);
324 PopupMenu
* pPopup
= m_pMenu
->GetPopupMenu(nId
);
325 mpParentPopup
->SetPopupMenu(nId
, pPopup
);
328 // the menu bar could have height 0 in fullscreen mode:
329 // so do not use always WindowHeight, as ItemHeight < WindowHeight.
330 if ( GetSizePixel().Height() )
332 // #107747# give menuitems the height of the menubar
333 aItemBottomRight
.AdjustY(GetOutputSizePixel().Height()-1 );
336 // ImplExecute is not modal...
337 // #99071# do not grab the focus, otherwise it will be restored to the menubar
338 // when the frame is reactivated later
340 m_pActivePopup
->ImplExecute( this, tools::Rectangle( aItemTopLeft
, aItemBottomRight
), FloatWinPopupFlags::Down
| FloatWinPopupFlags::NoHorzPlacement
, m_pMenu
, bPreSelectFirst
);
341 // does not have a window, if aborted before or if there are no entries
342 if ( m_pActivePopup
->ImplGetFloatingWindow() )
343 m_pActivePopup
->ImplGetFloatingWindow()->AddPopupModeWindow( this );
345 m_pActivePopup
= nullptr;
348 void MenuBarWindow::KillActivePopup()
350 if ( !m_pActivePopup
)
353 FloatingWindow
* pFloatWin
= m_pActivePopup
->ImplGetFloatingWindow();
354 if (pFloatWin
&& pFloatWin
->IsInCleanUp())
355 return; // kill it later
357 if ( m_pActivePopup
->bInCallback
)
358 m_pActivePopup
->bCanceled
= true;
360 m_pActivePopup
->bInCallback
= true;
361 m_pActivePopup
->Deactivate();
362 m_pActivePopup
->bInCallback
= false;
363 // check for pActivePopup, if stopped by deactivate...
364 if (m_pActivePopup
->GetWindow())
368 for (sal_uInt16 i
= 0; i
< mpParentPopup
->GetItemCount(); ++i
)
370 sal_uInt16 nId
= mpParentPopup
->GetItemId(i
);
371 MenuItemData
* pParentItemData
= mpParentPopup
->GetItemList()->GetData(nId
);
372 assert(pParentItemData
);
373 pParentItemData
->pSubMenu
= nullptr;
376 m_pActivePopup
->ImplGetFloatingWindow()->StopExecute();
377 m_pActivePopup
->ImplGetFloatingWindow()->doShutdown();
378 m_pActivePopup
->m_pWindow
.disposeAndClear();
380 m_pActivePopup
= nullptr;
383 void MenuBarWindow::PopupClosed( Menu
const * pPopup
)
385 if ( pPopup
== m_pActivePopup
)
388 ChangeHighlightItem( ITEMPOS_INVALID
, false, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus
, false );
392 void MenuBarWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
395 SetMBWMenuKey(false);
396 sal_uInt16 nEntry
= ImplFindEntry( rMEvt
.GetPosPixel() );
397 if ( ( nEntry
!= ITEMPOS_INVALID
) && !m_pActivePopup
)
399 ChangeHighlightItem( nEntry
, false );
404 ChangeHighlightItem( ITEMPOS_INVALID
, false );
408 void MenuBarWindow::MouseButtonUp( const MouseEvent
& )
412 void MenuBarWindow::MouseMove( const MouseEvent
& rMEvt
)
414 if ( rMEvt
.IsSynthetic() || rMEvt
.IsEnterWindow() )
417 if ( rMEvt
.IsLeaveWindow() )
419 if ( m_nRolloveredItem
!= ITEMPOS_INVALID
&& m_nRolloveredItem
!= m_nHighlightedItem
)
421 // there is a spurious MouseMove generated after a menu is launched from the keyboard, hence this...
422 if (m_nHighlightedItem
!= ITEMPOS_INVALID
)
424 bool hide
= GetMBWHideAccel();
425 SetMBWHideAccel(ImplGetSVData()->maNWFData
.mbAutoAccel
);
426 Invalidate(); //HighlightItem( nRolloveredItem, false );
427 SetMBWHideAccel(hide
);
430 Invalidate(); //HighlightItem( nRolloveredItem, false );
433 m_nRolloveredItem
= ITEMPOS_INVALID
;
437 sal_uInt16 nEntry
= ImplFindEntry( rMEvt
.GetPosPixel() );
438 if ( m_nHighlightedItem
== ITEMPOS_INVALID
)
440 if ( m_nRolloveredItem
!= nEntry
)
442 if ( m_nRolloveredItem
!= ITEMPOS_INVALID
)
443 Invalidate(); //HighlightItem( nRolloveredItem, false );
445 m_nRolloveredItem
= nEntry
;
446 Invalidate(); //HighlightItem( nRolloveredItem, true );
450 m_nRolloveredItem
= nEntry
;
452 if( m_bIgnoreFirstMove
)
454 m_bIgnoreFirstMove
= false;
458 if ( ( nEntry
!= ITEMPOS_INVALID
)
459 && ( nEntry
!= m_nHighlightedItem
) )
460 ChangeHighlightItem( nEntry
, false );
463 void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n
, bool bSelectEntry
, bool bAllowRestoreFocus
, bool bDefaultToDocument
)
468 if (n
== ITEMPOS_INVALID
)
469 SetMBWHideAccel(ImplGetSVData()->maNWFData
.mbAutoAccel
);
471 // #57934# close active popup if applicable, as TH's background storage works.
472 MenuItemData
* pNextData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
473 if (m_pActivePopup
&& m_pActivePopup
->GetWindow() && (!pNextData
|| (m_pActivePopup
!= pNextData
->pSubMenu
)))
474 KillActivePopup(); // pActivePopup when applicable without pWin, if Rescheduled in Activate()
476 // activate menubar only ones per cycle...
477 bool bJustActivated
= false;
478 if ( ( m_nHighlightedItem
== ITEMPOS_INVALID
) && ( n
!= ITEMPOS_INVALID
) )
480 ImplGetSVData()->mpWinData
->mbNoDeactivate
= true;
481 // #105406# avoid saving the focus when we already have the focus
482 bool bNoSaveFocus
= (this == ImplGetSVData()->mpWinData
->mpFocusWin
.get());
484 if( m_xSaveFocusId
!= nullptr )
486 if (!ImplGetSVData()->mpWinData
->mbNoSaveFocus
)
488 m_xSaveFocusId
= nullptr;
490 m_xSaveFocusId
= Window::SaveFocus(); // only save focus when initially activated
493 ; // do nothing: we 're activated again from taskpanelist, focus was already saved
499 m_xSaveFocusId
= Window::SaveFocus(); // only save focus when initially activated
501 m_pMenu
->bInCallback
= true; // set here if Activate overridden
503 m_pMenu
->bInCallback
= false;
504 bJustActivated
= true;
506 else if ( ( m_nHighlightedItem
!= ITEMPOS_INVALID
) && ( n
== ITEMPOS_INVALID
) )
508 m_pMenu
->bInCallback
= true;
509 m_pMenu
->Deactivate();
510 m_pMenu
->bInCallback
= false;
511 ImplGetSVData()->mpWinData
->mbNoDeactivate
= false;
512 if (!ImplGetSVData()->mpWinData
->mbNoSaveFocus
)
514 VclPtr
<vcl::Window
> xTempFocusId
;
515 if (m_xSaveFocusId
&& !m_xSaveFocusId
->isDisposed())
516 xTempFocusId
= m_xSaveFocusId
;
517 m_xSaveFocusId
= nullptr;
519 if (bAllowRestoreFocus
)
521 // tdf#115227 the popup is already killed, so temporarily set us as the
522 // focus window, so we could avoid sending superfluous activate events
523 // to top window listeners.
524 if (xTempFocusId
|| bDefaultToDocument
)
525 ImplGetSVData()->mpWinData
->mpFocusWin
= this;
527 // #105406# restore focus to document if we could not save focus before
528 if (!xTempFocusId
&& bDefaultToDocument
)
529 GrabFocusToDocument();
531 Window::EndSaveFocus(xTempFocusId
);
536 if ( m_nHighlightedItem
!= ITEMPOS_INVALID
)
538 if ( m_nHighlightedItem
!= m_nRolloveredItem
)
539 Invalidate(); //HighlightItem( nHighlightedItem, false );
541 m_pMenu
->ImplCallEventListeners( VclEventId::MenuDehighlight
, m_nHighlightedItem
);
544 m_nHighlightedItem
= n
;
545 SAL_WARN_IF( ( m_nHighlightedItem
!= ITEMPOS_INVALID
) && !m_pMenu
->ImplIsVisible( m_nHighlightedItem
), "vcl", "ChangeHighlightItem: Not visible!" );
546 if ( m_nHighlightedItem
!= ITEMPOS_INVALID
)
547 Invalidate(); //HighlightItem( nHighlightedItem, true );
548 else if ( m_nRolloveredItem
!= ITEMPOS_INVALID
)
549 Invalidate(); //HighlightItem( nRolloveredItem, true );
550 m_pMenu
->ImplCallHighlight(m_nHighlightedItem
);
553 ImplCreatePopup( bSelectEntry
);
555 // #58935# #73659# Focus, if no popup underneath...
556 if ( bJustActivated
&& !m_pActivePopup
)
560 static int ImplGetTopDockingAreaHeight( vcl::Window
const *pWindow
)
562 // find docking area that is top aligned and return its height
563 // note: dockingareas are direct children of the SystemWindow
564 if( pWindow
->ImplGetFrameWindow() )
566 vcl::Window
*pWin
= pWindow
->ImplGetFrameWindow()->GetWindow( GetWindowType::FirstChild
); //mpWindowImpl->mpFirstChild;
569 if( pWin
->IsSystemWindow() )
571 vcl::Window
*pChildWin
= pWin
->GetWindow( GetWindowType::FirstChild
); //mpWindowImpl->mpFirstChild;
574 DockingAreaWindow
*pDockingArea
= nullptr;
575 if ( pChildWin
->GetType() == WindowType::DOCKINGAREA
)
576 pDockingArea
= static_cast< DockingAreaWindow
* >( pChildWin
);
578 if( pDockingArea
&& pDockingArea
->GetAlign() == WindowAlign::Top
&&
579 pDockingArea
->IsVisible() && pDockingArea
->GetOutputSizePixel().Height() != 0 )
581 return pDockingArea
->GetOutputSizePixel().Height();
584 pChildWin
= pChildWin
->GetWindow( GetWindowType::Next
); //mpWindowImpl->mpNext;
589 pWin
= pWin
->GetWindow( GetWindowType::Next
); //mpWindowImpl->mpNext;
595 static void ImplAddNWFSeparator(vcl::RenderContext
& rRenderContext
, const Size
& rSize
, const MenubarValue
& rMenubarValue
)
597 // add a separator if
598 // - we have an adjacent docking area
599 // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx)
600 if (rMenubarValue
.maTopDockingAreaHeight
601 && !ImplGetSVData()->maNWFData
.mbDockingAreaSeparateTB
602 && !ImplGetSVData()->maNWFData
.mbDockingAreaAvoidTBFrames
)
604 // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
606 rRenderContext
.SetLineColor(rRenderContext
.GetSettings().GetStyleSettings().GetSeparatorColor());
607 tools::Rectangle
aRect(Point(), rSize
);
608 rRenderContext
.DrawLine(aRect
.BottomLeft(), aRect
.BottomRight());
612 void MenuBarWindow::HighlightItem(vcl::RenderContext
& rRenderContext
, sal_uInt16 nPos
)
618 size_t nCount
= m_pMenu
->pItemList
->size();
620 Size aOutputSize
= GetOutputSizePixel();
621 aOutputSize
.AdjustWidth( -(m_aCloseBtn
->GetSizePixel().Width()) );
623 for (size_t n
= 0; n
< nCount
; n
++)
625 MenuItemData
* pData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
628 if (pData
->eType
!= MenuItemType::SEPARATOR
)
630 // #107747# give menuitems the height of the menubar
631 tools::Rectangle
aRect(Point(nX
, 1), Size(pData
->aSz
.Width(), aOutputSize
.Height() - 2));
632 rRenderContext
.Push(vcl::PushFlags::CLIPREGION
);
633 rRenderContext
.IntersectClipRegion(aRect
);
634 bool bRollover
, bHighlight
;
635 if (!ImplGetSVData()->maNWFData
.mbRolloverMenubar
)
638 bRollover
= nPos
!= m_nHighlightedItem
;
642 bRollover
= nPos
== m_nRolloveredItem
;
643 bHighlight
= nPos
== m_nHighlightedItem
;
645 if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::MenuItem
) &&
646 rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
648 // draw background (transparency)
649 MenubarValue aControlValue
;
650 aControlValue
.maTopDockingAreaHeight
= ImplGetTopDockingAreaHeight( this );
652 tools::Rectangle
aBgRegion(Point(), aOutputSize
);
653 rRenderContext
.DrawNativeControl(ControlType::Menubar
, ControlPart::Entire
, aBgRegion
,
654 ControlState::ENABLED
, aControlValue
, OUString());
656 ImplAddNWFSeparator(rRenderContext
, aOutputSize
, aControlValue
);
658 // draw selected item
659 ControlState nState
= ControlState::ENABLED
;
661 nState
|= ControlState::ROLLOVER
;
663 nState
|= ControlState::SELECTED
;
664 rRenderContext
.DrawNativeControl(ControlType::Menubar
, ControlPart::MenuItem
,
665 aRect
, nState
, aControlValue
, OUString() );
670 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetMenuBarRolloverColor());
672 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetMenuHighlightColor());
673 rRenderContext
.SetLineColor();
674 rRenderContext
.DrawRect(aRect
);
676 rRenderContext
.Pop();
678 m_pMenu
->ImplPaint(rRenderContext
, aOutputSize
, 0, 0, pData
, bHighlight
, false, bRollover
);
683 nX
+= pData
->aSz
.Width();
687 tools::Rectangle
MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos
) const
689 tools::Rectangle aRect
;
693 size_t nCount
= m_pMenu
->pItemList
->size();
694 for ( size_t n
= 0; n
< nCount
; n
++ )
696 MenuItemData
* pData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
699 if ( pData
->eType
!= MenuItemType::SEPARATOR
)
700 // #107747# give menuitems the height of the menubar
701 aRect
= tools::Rectangle( Point( nX
, 1 ), Size( pData
->aSz
.Width(), GetOutputSizePixel().Height()-2 ) );
705 nX
+= pData
->aSz
.Width();
711 void MenuBarWindow::KeyInput( const KeyEvent
& rKEvent
)
713 if ( !HandleKeyEvent( rKEvent
) )
714 Window::KeyInput( rKEvent
);
717 bool MenuBarWindow::HandleKeyEvent( const KeyEvent
& rKEvent
, bool bFromMenu
)
722 if (m_pMenu
->bInCallback
)
723 return true; // swallow
726 sal_uInt16 nCode
= rKEvent
.GetKeyCode().GetCode();
730 if( GetParent()->GetWindow( GetWindowType::Client
)->IsSystemWindow() )
732 SystemWindow
*pSysWin
= static_cast<SystemWindow
*>(GetParent()->GetWindow( GetWindowType::Client
));
733 if( pSysWin
->GetTaskPaneList() )
734 if( pSysWin
->GetTaskPaneList()->HandleKeyEvent( rKEvent
) )
739 // no key events if native menus
740 if (m_pMenu
->ImplGetSalMenu() && m_pMenu
->ImplGetSalMenu()->VisibleMenuBar())
745 if ( nCode
== KEY_MENU
&& !rKEvent
.GetKeyCode().IsShift() ) // only F10, not Shift-F10
748 if ( m_nHighlightedItem
== ITEMPOS_INVALID
)
750 ChangeHighlightItem( 0, false );
755 ChangeHighlightItem( ITEMPOS_INVALID
, false );
756 m_xSaveFocusId
= nullptr;
760 else if ( bFromMenu
)
762 if ( ( nCode
== KEY_LEFT
) || ( nCode
== KEY_RIGHT
) ||
763 ( nCode
== KEY_HOME
) || ( nCode
== KEY_END
) )
765 sal_uInt16 n
= m_nHighlightedItem
;
766 if ( n
== ITEMPOS_INVALID
)
768 if ( nCode
== KEY_LEFT
)
771 n
= m_pMenu
->GetItemCount()-1;
774 sal_uInt16 nLoop
= n
;
776 if (nCode
== KEY_HOME
)
781 else if (nCode
== KEY_END
)
783 n
= m_pMenu
->GetItemCount();
789 if ( nCode
== KEY_LEFT
|| nCode
== KEY_END
)
794 n
= m_pMenu
->GetItemCount()-1;
796 if ( nCode
== KEY_RIGHT
|| nCode
== KEY_HOME
)
798 n
= (n
== ITEMPOS_INVALID
) ? 0 : n
+ 1;
799 if ( n
>= m_pMenu
->GetItemCount() )
803 MenuItemData
* pData
= m_pMenu
->GetItemList()->GetDataFromPos( n
);
804 if (pData
->eType
!= MenuItemType::SEPARATOR
&&
805 m_pMenu
->ImplIsVisible(n
) &&
806 !m_pMenu
->ImplCurrentlyHiddenOnGUI(n
))
808 ChangeHighlightItem( n
, true );
811 } while ( n
!= nLoop
);
814 else if ( nCode
== KEY_RETURN
)
816 if( m_pActivePopup
) KillActivePopup();
820 ImplCreatePopup( true );
825 else if ( ( nCode
== KEY_UP
) || ( nCode
== KEY_DOWN
) )
829 ImplCreatePopup( true );
834 else if ( nCode
== KEY_ESCAPE
|| ( nCode
== KEY_F6
&& rKEvent
.GetKeyCode().IsMod1() ) )
838 // hide the menu and remove the focus...
843 ChangeHighlightItem( ITEMPOS_INVALID
, false );
845 if( nCode
== KEY_F6
&& rKEvent
.GetKeyCode().IsMod1() )
847 // put focus into document
848 GrabFocusToDocument();
855 if ( !bDone
&& ( bFromMenu
|| rKEvent
.GetKeyCode().IsMod2() ) )
857 sal_Unicode nCharCode
= rKEvent
.GetCharCode();
860 size_t nEntry
, nDuplicates
;
861 MenuItemData
* pData
= m_pMenu
->GetItemList()->SearchItem( nCharCode
, rKEvent
.GetKeyCode(), nEntry
, nDuplicates
, m_nHighlightedItem
);
862 if ( pData
&& (nEntry
!= ITEMPOS_INVALID
) )
865 ChangeHighlightItem( nEntry
, true );
874 void MenuBarWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
879 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
881 Size aOutputSize
= GetOutputSizePixel();
883 // no VCL paint if native menus
884 if (m_pMenu
->ImplGetSalMenu() && m_pMenu
->ImplGetSalMenu()->VisibleMenuBar())
887 // Make sure that all actual rendering happens in one go to avoid flicker.
888 vcl::BufferDevice
pBuffer(this, rRenderContext
);
890 if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
892 MenubarValue aMenubarValue
;
893 aMenubarValue
.maTopDockingAreaHeight
= ImplGetTopDockingAreaHeight(this);
895 tools::Rectangle
aCtrlRegion( Point(), aOutputSize
);
897 pBuffer
->DrawNativeControl(ControlType::Menubar
, ControlPart::Entire
, aCtrlRegion
,
898 ControlState::ENABLED
, aMenubarValue
, OUString());
900 ImplAddNWFSeparator(*pBuffer
, aOutputSize
, aMenubarValue
);
903 // shrink the area of the buttons
904 aOutputSize
.AdjustWidth( -(m_aCloseBtn
->GetSizePixel().Width()) );
906 pBuffer
->SetFillColor(rStyleSettings
.GetMenuColor());
907 m_pMenu
->ImplPaint(*pBuffer
, aOutputSize
, 0);
909 if (m_nHighlightedItem
!= ITEMPOS_INVALID
&& m_pMenu
&& !m_pMenu
->GetItemList()->GetDataFromPos(m_nHighlightedItem
)->bHiddenOnGUI
)
910 HighlightItem(*pBuffer
, m_nHighlightedItem
);
911 else if (m_nRolloveredItem
!= ITEMPOS_INVALID
)
912 HighlightItem(*pBuffer
, m_nRolloveredItem
);
914 // in high contrast mode draw a separating line on the lower edge
915 if (!rRenderContext
.IsNativeControlSupported( ControlType::Menubar
, ControlPart::Entire
) &&
916 rStyleSettings
.GetHighContrastMode())
918 pBuffer
->Push(vcl::PushFlags::LINECOLOR
| vcl::PushFlags::MAPMODE
);
919 pBuffer
->SetLineColor(COL_WHITE
);
920 pBuffer
->SetMapMode(MapMode(MapUnit::MapPixel
));
921 Size aSize
= GetSizePixel();
922 pBuffer
->DrawLine(Point(0, aSize
.Height() - 1),
923 Point(aSize
.Width() - 1, aSize
.Height() - 1));
928 void MenuBarWindow::Resize()
930 Size aOutSz
= GetOutputSizePixel();
931 tools::Long n
= aOutSz
.Height()-4;
932 tools::Long nX
= aOutSz
.Width()-3;
935 if ( m_aCloseBtn
->IsVisible() )
938 m_aCloseBtn
->SetImages(n
);
939 Size
aTbxSize( m_aCloseBtn
->CalcWindowSizePixel() );
940 nX
-= aTbxSize
.Width();
941 tools::Long nTbxY
= (aOutSz
.Height() - aTbxSize
.Height())/2;
942 m_aCloseBtn
->setPosSizePixel(nX
, nTbxY
, aTbxSize
.Width(), aTbxSize
.Height());
946 if ( m_aFloatBtn
->IsVisible() )
949 m_aFloatBtn
->setPosSizePixel( nX
, nY
, n
, n
);
951 if ( m_aHideBtn
->IsVisible() )
954 m_aHideBtn
->setPosSizePixel( nX
, nY
, n
, n
);
957 m_aFloatBtn
->SetSymbol( SymbolType::FLOAT
);
958 m_aHideBtn
->SetSymbol( SymbolType::HIDE
);
963 sal_uInt16
MenuBarWindow::ImplFindEntry( const Point
& rMousePos
) const
968 size_t nCount
= m_pMenu
->pItemList
->size();
969 for ( size_t n
= 0; n
< nCount
; n
++ )
971 MenuItemData
* pData
= m_pMenu
->pItemList
->GetDataFromPos( n
);
972 if ( m_pMenu
->ImplIsVisible( n
) )
974 nX
+= pData
->aSz
.Width();
975 if ( nX
> rMousePos
.X() )
976 return static_cast<sal_uInt16
>(n
);
980 return ITEMPOS_INVALID
;
983 void MenuBarWindow::RequestHelp( const HelpEvent
& rHEvt
)
985 sal_uInt16 nId
= m_nHighlightedItem
;
986 if ( rHEvt
.GetMode() & HelpEventMode::CONTEXT
)
987 ChangeHighlightItem( ITEMPOS_INVALID
, true );
989 tools::Rectangle
aHighlightRect( ImplGetItemRect( m_nHighlightedItem
) );
990 if( !ImplHandleHelpEvent( this, m_pMenu
, nId
, rHEvt
, aHighlightRect
) )
991 Window::RequestHelp( rHEvt
);
994 void MenuBarWindow::StateChanged( StateChangedType nType
)
996 Window::StateChanged( nType
);
998 if (nType
== StateChangedType::ControlForeground
||
999 nType
== StateChangedType::ControlBackground
)
1001 ApplySettings(*GetOutDev());
1004 else if (nType
== StateChangedType::Enable
)
1010 m_pMenu
->ImplKillLayoutData();
1014 void MenuBarWindow::LayoutChanged()
1019 ApplySettings(*GetOutDev());
1021 // if the font was changed.
1022 tools::Long nHeight
= m_pMenu
->ImplCalcSize(this).Height();
1024 // depending on the native implementation or the displayable flag
1025 // the menubar windows is suppressed (ie, height=0)
1026 if (!m_pMenu
->IsDisplayable() ||
1027 (m_pMenu
->ImplGetSalMenu() && m_pMenu
->ImplGetSalMenu()->VisibleMenuBar()))
1031 setPosSizePixel(0, 0, 0, nHeight
, PosSizeFlags::Height
);
1032 GetParent()->Resize();
1036 m_pMenu
->ImplKillLayoutData();
1039 void MenuBarWindow::ApplySettings(vcl::RenderContext
& rRenderContext
)
1041 Window::ApplySettings(rRenderContext
);
1042 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1044 SetPointFont(rRenderContext
, rStyleSettings
.GetMenuFont());
1046 if (rRenderContext
.IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
))
1048 rRenderContext
.SetBackground(); // background will be drawn by NWF
1052 Wallpaper aWallpaper
;
1053 aWallpaper
.SetStyle(WallpaperStyle::ApplicationGradient
);
1054 rRenderContext
.SetBackground(aWallpaper
);
1055 SetPaintTransparent(false);
1056 SetParentClipMode();
1059 rRenderContext
.SetTextColor(rStyleSettings
.GetMenuBarTextColor());
1060 rRenderContext
.SetTextFillColor();
1061 rRenderContext
.SetLineColor();
1064 void MenuBarWindow::ImplInitStyleSettings()
1066 if (!(IsNativeControlSupported(ControlType::Menubar
, ControlPart::MenuItem
) &&
1067 IsNativeControlSupported(ControlType::Menubar
, ControlPart::Entire
)))
1070 AllSettings
aSettings(GetSettings());
1071 ImplGetFrame()->UpdateSettings(aSettings
); // to update persona
1072 StyleSettings
aStyle(aSettings
.GetStyleSettings());
1073 Color aHighlightTextColor
= ImplGetSVData()->maNWFData
.maMenuBarHighlightTextColor
;
1074 if (aHighlightTextColor
!= COL_TRANSPARENT
)
1076 aStyle
.SetMenuHighlightTextColor(aHighlightTextColor
);
1078 aSettings
.SetStyleSettings(aStyle
);
1079 GetOutDev()->SetSettings(aSettings
);
1082 void MenuBarWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
1084 Window::DataChanged( rDCEvt
);
1086 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1087 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1088 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1089 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1091 ApplySettings(*GetOutDev());
1092 ImplInitStyleSettings();
1097 void MenuBarWindow::LoseFocus()
1099 if ( !HasChildPathFocus( true ) )
1100 ChangeHighlightItem( ITEMPOS_INVALID
, false, false );
1103 void MenuBarWindow::GetFocus()
1105 SalMenu
*pNativeMenu
= m_pMenu
? m_pMenu
->ImplGetSalMenu() : nullptr;
1106 if (pNativeMenu
&& pNativeMenu
->TakeFocus())
1109 if ( m_nHighlightedItem
== ITEMPOS_INVALID
)
1111 mbAutoPopup
= false; // do not open menu when activated by focus handling like taskpane cycling
1112 ChangeHighlightItem( 0, false );
1116 css::uno::Reference
<css::accessibility::XAccessible
> MenuBarWindow::CreateAccessible()
1118 css::uno::Reference
<css::accessibility::XAccessible
> xAcc
;
1121 xAcc
= m_pMenu
->GetAccessible();
1126 sal_uInt16
MenuBarWindow::AddMenuBarButton( const Image
& i_rImage
, const Link
<MenuBarButtonCallbackArg
&,bool>& i_rLink
, const OUString
& i_rToolTip
)
1128 // find first free button id
1129 sal_uInt16 nId
= IID_DOCUMENTCLOSE
;
1130 std::map
< sal_uInt16
, AddButtonEntry
>::const_iterator it
;
1134 it
= m_aAddButtons
.find( nId
);
1135 } while( it
!= m_aAddButtons
.end() && nId
< 128 );
1136 SAL_WARN_IF( nId
>= 128, "vcl", "too many addbuttons in menubar" );
1137 AddButtonEntry
& rNewEntry
= m_aAddButtons
[nId
];
1138 rNewEntry
.m_aSelectLink
= i_rLink
;
1139 m_aCloseBtn
->InsertItem(ToolBoxItemId(nId
), i_rImage
, ToolBoxItemBits::NONE
, 0);
1140 m_aCloseBtn
->calcMinSize();
1141 ShowButtons(m_aCloseBtn
->IsItemVisible(ToolBoxItemId(IID_DOCUMENTCLOSE
)), m_aFloatBtn
->IsVisible(), m_aHideBtn
->IsVisible());
1144 if( m_pMenu
->mpSalMenu
)
1145 m_pMenu
->mpSalMenu
->AddMenuBarButton( SalMenuButtonItem( nId
, i_rImage
, i_rToolTip
) );
1150 void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId
, const Link
<MenuBarButtonCallbackArg
&,bool>& rLink
)
1152 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( nId
);
1153 if( it
!= m_aAddButtons
.end() )
1154 it
->second
.m_aHighlightLink
= rLink
;
1157 tools::Rectangle
MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId
)
1159 tools::Rectangle aRect
;
1160 if( m_aAddButtons
.find( nId
) != m_aAddButtons
.end() )
1162 if( m_pMenu
->mpSalMenu
)
1164 aRect
= m_pMenu
->mpSalMenu
->GetMenuBarButtonRectPixel( nId
, ImplGetWindowImpl()->mpFrame
);
1165 if( aRect
== tools::Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
1167 // system menu button is somewhere but location cannot be determined
1168 return tools::Rectangle();
1172 if( aRect
.IsEmpty() )
1174 aRect
= m_aCloseBtn
->GetItemRect(ToolBoxItemId(nId
));
1175 Point aOffset
= m_aCloseBtn
->OutputToScreenPixel(Point());
1176 aRect
.Move( aOffset
.X(), aOffset
.Y() );
1182 void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId
)
1184 ToolBox::ImplToolItems::size_type nPos
= m_aCloseBtn
->GetItemPos(ToolBoxItemId(nId
));
1185 m_aCloseBtn
->RemoveItem(nPos
);
1186 m_aAddButtons
.erase( nId
);
1187 m_aCloseBtn
->calcMinSize();
1190 if( m_pMenu
->mpSalMenu
)
1191 m_pMenu
->mpSalMenu
->RemoveMenuBarButton( nId
);
1194 bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId
)
1196 std::map
< sal_uInt16
, AddButtonEntry
>::iterator it
= m_aAddButtons
.find( i_nButtonId
);
1197 if( it
!= m_aAddButtons
.end() )
1199 MenuBarButtonCallbackArg aArg
;
1200 aArg
.nId
= it
->first
;
1201 aArg
.bHighlight
= true;
1202 return it
->second
.m_aSelectLink
.Call( aArg
);
1207 bool MenuBarWindow::CanGetFocus() const
1209 /* #i83908# do not use the menubar if it is native or invisible
1210 this relies on MenuBar::ImplCreate setting the height of the menubar
1213 SalMenu
*pNativeMenu
= m_pMenu
? m_pMenu
->ImplGetSalMenu() : nullptr;
1214 if (pNativeMenu
&& pNativeMenu
->VisibleMenuBar())
1215 return pNativeMenu
->CanGetFocus();
1216 return GetSizePixel().Height() > 0;
1219 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */