xref: /core/vcl/source/window/menubarwindow.cxx (revision f0977206)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include "menubarwindow.hxx"
21 #include "menuitemlist.hxx"
22 #include "menufloatingwindow.hxx"
23 
24 #include <vcl/dockingarea.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/taskpanelist.hxx>
27 #include <sal/log.hxx>
28 
29 #include <salframe.hxx>
30 #include <salmenu.hxx>
31 #include <svdata.hxx>
32 #include <strings.hrc>
33 #include <bitmaps.hlst>
34 #include <window.h>
35 #include "bufferdevice.hxx"
36 #include <menubarvalue.hxx>
37 
38 // document closing button
39 #define IID_DOCUMENTCLOSE 1
40 
DecoToolBox(vcl::Window * pParent)41 DecoToolBox::DecoToolBox( vcl::Window* pParent ) :
42     ToolBox( pParent, 0 ),
43     lastSize(-1)
44 {
45     calcMinSize();
46 }
47 
DataChanged(const DataChangedEvent & rDCEvt)48 void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt )
49 {
50     Window::DataChanged( rDCEvt );
51 
52     if ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE )
53     {
54         calcMinSize();
55         SetBackground();
56         SetImages( 0, true);
57     }
58 }
59 
calcMinSize()60 void DecoToolBox::calcMinSize()
61 {
62     ScopedVclPtrInstance<ToolBox> aTbx( GetParent() );
63     if( GetItemCount() == 0 )
64     {
65         aTbx->InsertItem(ToolBoxItemId(IID_DOCUMENTCLOSE), Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC));
66     }
67     else
68     {
69         ImplToolItems::size_type nItems = GetItemCount();
70         for( ImplToolItems::size_type i = 0; i < nItems; i++ )
71         {
72             ToolBoxItemId nId = GetItemId( i );
73             aTbx->InsertItem( nId, GetItemImage( nId ) );
74         }
75     }
76     maMinSize = aTbx->CalcWindowSizePixel();
77 
78     aTbx.disposeAndClear();
79 }
80 
SetImages(tools::Long nMaxHeight,bool bForce)81 void DecoToolBox::SetImages( tools::Long nMaxHeight, bool bForce )
82 {
83     tools::Long border = getMinSize().Height() - maImage.GetSizePixel().Height();
84 
85     if( !nMaxHeight && lastSize != -1 )
86         nMaxHeight = lastSize + border; // don't change anything if called with 0
87 
88     if( nMaxHeight < getMinSize().Height() )
89         nMaxHeight = getMinSize().Height();
90 
91     if( (lastSize == nMaxHeight - border) && !bForce )
92         return;
93 
94     lastSize = nMaxHeight - border;
95 
96     Color       aEraseColor( ColorTransparency, 255, 255, 255, 255 );
97     BitmapEx    aBmpExDst( maImage.GetBitmapEx() );
98     BitmapEx    aBmpExSrc( aBmpExDst );
99 
100     aEraseColor.SetAlpha( 0 );
101     aBmpExDst.Erase( aEraseColor );
102     aBmpExDst.Scale( Size( lastSize, lastSize ) );
103 
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() );
108 
109     aBmpExDst.CopyPixel( aDestRect, aSrcRect, aBmpExSrc );
110     SetItemImage( ToolBoxItemId(IID_DOCUMENTCLOSE), Image( aBmpExDst ) );
111 
112 }
113 
MenuBarWindow(vcl::Window * pParent)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))
119 {
120     SetType(WindowType::MENUBARWINDOW);
121     m_pMenu = nullptr;
122     m_pActivePopup = nullptr;
123     m_nHighlightedItem = ITEMPOS_INVALID;
124     m_nRolloveredItem = ITEMPOS_INVALID;
125     mbAutoPopup = true;
126     m_bIgnoreFirstMove = true;
127     SetMBWHideAccel(ImplGetSVData()->maNWFData.mbAutoAccel);
128     SetMBWMenuKey(false);
129 
130     m_aCloseBtn->maImage = Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC);
131 
132     m_aCloseBtn->SetBackground();
133     m_aCloseBtn->SetPaintTransparent(true);
134     m_aCloseBtn->SetParentClipMode(ParentClipMode::NoClip);
135 
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));
140 
141     m_aFloatBtn->SetSymbol( SymbolType::FLOAT );
142     m_aFloatBtn->SetQuickHelpText(VclResId(SV_HELPTEXT_RESTORE));
143 
144     m_aHideBtn->SetSymbol( SymbolType::HIDE );
145     m_aHideBtn->SetQuickHelpText(VclResId(SV_HELPTEXT_MINIMIZE));
146 
147     ImplInitStyleSettings();
148 
149     AddEventListener(LINK(this, MenuBarWindow, ShowHideListener));
150 }
151 
~MenuBarWindow()152 MenuBarWindow::~MenuBarWindow()
153 {
154     disposeOnce();
155 }
156 
dispose()157 void MenuBarWindow::dispose()
158 {
159     m_aCloseBtn->RemoveEventListener(LINK(this, MenuBarWindow, ToolboxEventHdl));
160     RemoveEventListener(LINK(this, MenuBarWindow, ShowHideListener));
161 
162     mpParentPopup.disposeAndClear();
163     m_aHideBtn.disposeAndClear();
164     m_aFloatBtn.disposeAndClear();
165     m_aCloseBtn.disposeAndClear();
166     m_pMenu.clear();
167     m_pActivePopup.clear();
168     m_xSaveFocusId.clear();
169 
170     Window::dispose();
171 }
172 
SetMenu(MenuBar * pMen)173 void MenuBarWindow::SetMenu( MenuBar* pMen )
174 {
175     m_pMenu = pMen;
176     KillActivePopup();
177     m_nHighlightedItem = ITEMPOS_INVALID;
178     if (pMen)
179     {
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());
184     }
185     Invalidate();
186 
187     // show and connect native menubar
188     if( m_pMenu && m_pMenu->ImplGetSalMenu() )
189     {
190         if( m_pMenu->ImplGetSalMenu()->VisibleMenuBar() )
191             ImplGetFrame()->SetMenu( m_pMenu->ImplGetSalMenu() );
192 
193         m_pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() );
194         m_pMenu->ImplGetSalMenu()->ShowMenuBar(true);
195     }
196 }
197 
SetHeight(tools::Long nHeight)198 void MenuBarWindow::SetHeight(tools::Long nHeight)
199 {
200     setPosSizePixel(0, 0, 0, nHeight, PosSizeFlags::Height);
201 }
202 
ShowButtons(bool bClose,bool bFloat,bool bHide)203 void MenuBarWindow::ShowButtons( bool bClose, bool bFloat, bool bHide )
204 {
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 );
211     Resize();
212 }
213 
MinCloseButtonSize() const214 Size const & MenuBarWindow::MinCloseButtonSize() const
215 {
216     return m_aCloseBtn->getMinSize();
217 }
218 
IMPL_LINK_NOARG(MenuBarWindow,CloseHdl,ToolBox *,void)219 IMPL_LINK_NOARG(MenuBarWindow, CloseHdl, ToolBox *, void)
220 {
221     if( ! m_pMenu )
222         return;
223 
224     if( m_aCloseBtn->GetCurItemId() == ToolBoxItemId(IID_DOCUMENTCLOSE) )
225     {
226         // #i106052# call close hdl asynchronously to ease handler implementation
227         // this avoids still being in the handler while the DecoToolBox already
228         // gets destroyed
229         Application::PostUserEvent(m_pMenu->GetCloseButtonClickHdl());
230     }
231     else
232     {
233         std::map<sal_uInt16,AddButtonEntry>::iterator it = m_aAddButtons.find(sal_uInt16(m_aCloseBtn->GetCurItemId()));
234         if( it != m_aAddButtons.end() )
235         {
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 );
240         }
241     }
242 }
243 
IMPL_LINK(MenuBarWindow,ToolboxEventHdl,VclWindowEvent &,rEvent,void)244 IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent&, rEvent, void )
245 {
246     if( ! m_pMenu )
247         return;
248 
249     MenuBarButtonCallbackArg aArg;
250     aArg.nId = 0xffff;
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 )
255     {
256         auto nPos = static_cast<ToolBox::ImplToolItems::size_type>(reinterpret_cast<sal_IntPtr>(rEvent.GetData()));
257         aArg.nId = sal_uInt16(m_aCloseBtn->GetItemId(nPos));
258     }
259     std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId );
260     if( it != m_aAddButtons.end() )
261     {
262         it->second.m_aHighlightLink.Call( aArg );
263     }
264 }
265 
IMPL_LINK(MenuBarWindow,ShowHideListener,VclWindowEvent &,rEvent,void)266 IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent&, rEvent, void )
267 {
268     if( ! m_pMenu )
269         return;
270 
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 );
275 }
276 
ImplCreatePopup(bool bPreSelectFirst)277 void MenuBarWindow::ImplCreatePopup( bool bPreSelectFirst )
278 {
279     MenuItemData* pItemData = m_pMenu ? m_pMenu->GetItemList()->GetDataFromPos( m_nHighlightedItem ) : nullptr;
280     if ( !pItemData )
281         return;
282 
283     m_bIgnoreFirstMove = true;
284     if ( m_pActivePopup && ( m_pActivePopup != pItemData->pSubMenu ) )
285     {
286         KillActivePopup();
287     }
288     if ( !(pItemData->bEnabled && pItemData->pSubMenu && ( m_nHighlightedItem != ITEMPOS_INVALID ) &&
289          ( pItemData->pSubMenu != m_pActivePopup )) )
290         return;
291 
292     m_pActivePopup = pItemData->pSubMenu.get();
293     tools::Long nX = 0;
294     MenuItemData* pData = nullptr;
295     for ( sal_uLong n = 0; n < m_nHighlightedItem; n++ )
296     {
297         pData = m_pMenu->GetItemList()->GetDataFromPos( n );
298         nX += pData->aSz.Width();
299     }
300     pData = m_pMenu->pItemList->GetDataFromPos( m_nHighlightedItem );
301     Point aItemTopLeft( nX, 0 );
302     Point aItemBottomRight( aItemTopLeft );
303     aItemBottomRight.AdjustX(pData->aSz.Width() );
304 
305     if (pData->bHiddenOnGUI)
306     {
307         mpParentPopup.disposeAndClear();
308         mpParentPopup = VclPtr<PopupMenu>::Create();
309         m_pActivePopup = mpParentPopup.get();
310 
311         for (sal_uInt16 i = m_nHighlightedItem; i < m_pMenu->GetItemCount(); ++i)
312         {
313             sal_uInt16 nId = m_pMenu->GetItemId(i);
314 
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);
323 
324             PopupMenu* pPopup = m_pMenu->GetPopupMenu(nId);
325             mpParentPopup->SetPopupMenu(nId, pPopup);
326         }
327     }
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() )
331     {
332         // #107747# give menuitems the height of the menubar
333         aItemBottomRight.AdjustY(GetOutputSizePixel().Height()-1 );
334     }
335 
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
339     //GrabFocus();
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 );
344     else
345         m_pActivePopup = nullptr;
346 }
347 
KillActivePopup()348 void MenuBarWindow::KillActivePopup()
349 {
350     if ( !m_pActivePopup )
351         return;
352 
353     if( m_pActivePopup->pWindow )
354         if( static_cast<FloatingWindow *>(m_pActivePopup->pWindow.get())->IsInCleanUp() )
355             return; // kill it later
356 
357     if ( m_pActivePopup->bInCallback )
358         m_pActivePopup->bCanceled = true;
359 
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->ImplGetWindow() )
365     {
366         if (mpParentPopup)
367         {
368             for (sal_uInt16 i = 0; i < mpParentPopup->GetItemCount(); ++i)
369             {
370                 sal_uInt16 nId = mpParentPopup->GetItemId(i);
371                 MenuItemData* pParentItemData = mpParentPopup->GetItemList()->GetData(nId);
372                 assert(pParentItemData);
373                 pParentItemData->pSubMenu = nullptr;
374             }
375         }
376         m_pActivePopup->ImplGetFloatingWindow()->StopExecute();
377         m_pActivePopup->ImplGetFloatingWindow()->doShutdown();
378         m_pActivePopup->pWindow.disposeAndClear();
379     }
380     m_pActivePopup = nullptr;
381 }
382 
PopupClosed(Menu const * pPopup)383 void MenuBarWindow::PopupClosed( Menu const * pPopup )
384 {
385     if ( pPopup == m_pActivePopup )
386     {
387         KillActivePopup();
388         ChangeHighlightItem( ITEMPOS_INVALID, false, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, false );
389     }
390 }
391 
MouseButtonDown(const MouseEvent & rMEvt)392 void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt )
393 {
394     mbAutoPopup = true;
395     SetMBWMenuKey(false);
396     sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
397     if ( ( nEntry != ITEMPOS_INVALID ) && !m_pActivePopup )
398     {
399         ChangeHighlightItem( nEntry, false );
400     }
401     else
402     {
403         KillActivePopup();
404         ChangeHighlightItem( ITEMPOS_INVALID, false );
405     }
406 }
407 
MouseButtonUp(const MouseEvent &)408 void MenuBarWindow::MouseButtonUp( const MouseEvent& )
409 {
410 }
411 
MouseMove(const MouseEvent & rMEvt)412 void MenuBarWindow::MouseMove( const MouseEvent& rMEvt )
413 {
414     if ( rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() )
415         return;
416 
417     if ( rMEvt.IsLeaveWindow() )
418     {
419         if ( m_nRolloveredItem != ITEMPOS_INVALID && m_nRolloveredItem != m_nHighlightedItem )
420         {
421             // there is a spurious MouseMove generated after a menu is launched from the keyboard, hence this...
422             if (m_nHighlightedItem != ITEMPOS_INVALID)
423             {
424                 bool hide = GetMBWHideAccel();
425                 SetMBWHideAccel(ImplGetSVData()->maNWFData.mbAutoAccel);
426                 Invalidate(); //HighlightItem( nRolloveredItem, false );
427                 SetMBWHideAccel(hide);
428             }
429             else
430                 Invalidate(); //HighlightItem( nRolloveredItem, false );
431         }
432 
433         m_nRolloveredItem = ITEMPOS_INVALID;
434         return;
435     }
436 
437     sal_uInt16 nEntry = ImplFindEntry( rMEvt.GetPosPixel() );
438     if ( m_nHighlightedItem == ITEMPOS_INVALID )
439     {
440         if ( m_nRolloveredItem != nEntry  )
441         {
442             if ( m_nRolloveredItem != ITEMPOS_INVALID )
443                 Invalidate(); //HighlightItem( nRolloveredItem, false );
444 
445             m_nRolloveredItem = nEntry;
446             Invalidate(); //HighlightItem( nRolloveredItem, true );
447         }
448         return;
449     }
450     m_nRolloveredItem = nEntry;
451 
452     if( m_bIgnoreFirstMove )
453     {
454         m_bIgnoreFirstMove = false;
455         return;
456     }
457 
458     if ( ( nEntry != ITEMPOS_INVALID )
459        && ( nEntry != m_nHighlightedItem ) )
460         ChangeHighlightItem( nEntry, false );
461 }
462 
ChangeHighlightItem(sal_uInt16 n,bool bSelectEntry,bool bAllowRestoreFocus,bool bDefaultToDocument)463 void MenuBarWindow::ChangeHighlightItem( sal_uInt16 n, bool bSelectEntry, bool bAllowRestoreFocus, bool bDefaultToDocument)
464 {
465     if( ! m_pMenu )
466         return;
467 
468     if (n == ITEMPOS_INVALID)
469         SetMBWHideAccel(ImplGetSVData()->maNWFData.mbAutoAccel);
470 
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->ImplGetWindow() && ( !pNextData || ( m_pActivePopup != pNextData->pSubMenu ) ) )
474         KillActivePopup(); // pActivePopup when applicable without pWin, if Rescheduled in  Activate()
475 
476     // activate menubar only ones per cycle...
477     bool bJustActivated = false;
478     if ( ( m_nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) )
479     {
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());
483 
484         if( m_xSaveFocusId != nullptr )
485         {
486             if (!ImplGetSVData()->mpWinData->mbNoSaveFocus)
487             {
488                  m_xSaveFocusId = nullptr;
489                  if( !bNoSaveFocus )
490                     m_xSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
491             }
492             else {
493                 ; // do nothing: we 're activated again from taskpanelist, focus was already saved
494             }
495         }
496         else
497         {
498             if( !bNoSaveFocus )
499                 m_xSaveFocusId = Window::SaveFocus(); // only save focus when initially activated
500         }
501         m_pMenu->bInCallback = true;  // set here if Activate overridden
502         m_pMenu->Activate();
503         m_pMenu->bInCallback = false;
504         bJustActivated = true;
505     }
506     else if ( ( m_nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) )
507     {
508         m_pMenu->bInCallback = true;
509         m_pMenu->Deactivate();
510         m_pMenu->bInCallback = false;
511         ImplGetSVData()->mpWinData->mbNoDeactivate = false;
512         if (!ImplGetSVData()->mpWinData->mbNoSaveFocus)
513         {
514             VclPtr<vcl::Window> xTempFocusId;
515             if (m_xSaveFocusId && !m_xSaveFocusId->isDisposed())
516                 xTempFocusId = m_xSaveFocusId;
517             m_xSaveFocusId = nullptr;
518 
519             if (bAllowRestoreFocus)
520             {
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;
526 
527                 // #105406# restore focus to document if we could not save focus before
528                 if (!xTempFocusId && bDefaultToDocument)
529                     GrabFocusToDocument();
530                 else
531                     Window::EndSaveFocus(xTempFocusId);
532             }
533         }
534     }
535 
536     if ( m_nHighlightedItem != ITEMPOS_INVALID )
537     {
538         if ( m_nHighlightedItem != m_nRolloveredItem )
539             Invalidate(); //HighlightItem( nHighlightedItem, false );
540 
541         m_pMenu->ImplCallEventListeners( VclEventId::MenuDehighlight, m_nHighlightedItem );
542     }
543 
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);
551 
552     if( mbAutoPopup )
553         ImplCreatePopup( bSelectEntry );
554 
555     // #58935# #73659# Focus, if no popup underneath...
556     if ( bJustActivated && !m_pActivePopup )
557         GrabFocus();
558 }
559 
ImplGetTopDockingAreaHeight(vcl::Window const * pWindow)560 static int ImplGetTopDockingAreaHeight( vcl::Window const *pWindow )
561 {
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() )
565     {
566         vcl::Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( GetWindowType::FirstChild ); //mpWindowImpl->mpFirstChild;
567         while( pWin )
568         {
569             if( pWin->IsSystemWindow() )
570             {
571                 vcl::Window *pChildWin = pWin->GetWindow( GetWindowType::FirstChild ); //mpWindowImpl->mpFirstChild;
572                 while( pChildWin )
573                 {
574                     DockingAreaWindow *pDockingArea = nullptr;
575                     if ( pChildWin->GetType() == WindowType::DOCKINGAREA )
576                         pDockingArea = static_cast< DockingAreaWindow* >( pChildWin );
577 
578                     if( pDockingArea && pDockingArea->GetAlign() == WindowAlign::Top &&
579                         pDockingArea->IsVisible() && pDockingArea->GetOutputSizePixel().Height() != 0 )
580                     {
581                         return pDockingArea->GetOutputSizePixel().Height();
582                     }
583 
584                     pChildWin = pChildWin->GetWindow( GetWindowType::Next ); //mpWindowImpl->mpNext;
585                 }
586 
587             }
588 
589             pWin = pWin->GetWindow( GetWindowType::Next ); //mpWindowImpl->mpNext;
590         }
591     }
592     return 0;
593 }
594 
ImplAddNWFSeparator(vcl::RenderContext & rRenderContext,const Size & rSize,const MenubarValue & rMenubarValue)595 static void ImplAddNWFSeparator(vcl::RenderContext& rRenderContext, const Size& rSize, const MenubarValue& rMenubarValue)
596 {
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)
603     {
604         // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area
605 
606         rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetSeparatorColor());
607         tools::Rectangle aRect(Point(), rSize);
608         rRenderContext.DrawLine(aRect.BottomLeft(), aRect.BottomRight());
609     }
610 }
611 
HighlightItem(vcl::RenderContext & rRenderContext,sal_uInt16 nPos)612 void MenuBarWindow::HighlightItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos)
613 {
614     if (!m_pMenu)
615         return;
616 
617     tools::Long nX = 0;
618     size_t nCount = m_pMenu->pItemList->size();
619 
620     Size aOutputSize = GetOutputSizePixel();
621     aOutputSize.AdjustWidth( -(m_aCloseBtn->GetSizePixel().Width()) );
622 
623     for (size_t n = 0; n < nCount; n++)
624     {
625         MenuItemData* pData = m_pMenu->pItemList->GetDataFromPos( n );
626         if (n == nPos)
627         {
628             if (pData->eType != MenuItemType::SEPARATOR)
629             {
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)
636                 {
637                     bHighlight = true;
638                     bRollover = nPos != m_nHighlightedItem;
639                 }
640                 else
641                 {
642                     bRollover = nPos == m_nRolloveredItem;
643                     bHighlight = nPos == m_nHighlightedItem;
644                 }
645                 if (rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::MenuItem) &&
646                     rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire))
647                 {
648                     // draw background (transparency)
649                     MenubarValue aControlValue;
650                     aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
651 
652                     if (!Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty() )
653                          Erase(rRenderContext);
654                     else
655                     {
656                         tools::Rectangle aBgRegion(Point(), aOutputSize);
657                         rRenderContext.DrawNativeControl(ControlType::Menubar, ControlPart::Entire, aBgRegion,
658                                                          ControlState::ENABLED, aControlValue, OUString());
659                     }
660 
661                     ImplAddNWFSeparator(rRenderContext, aOutputSize, aControlValue);
662 
663                     // draw selected item
664                     ControlState nState = ControlState::ENABLED;
665                     if (bRollover)
666                         nState |= ControlState::ROLLOVER;
667                     else
668                         nState |= ControlState::SELECTED;
669                     rRenderContext.DrawNativeControl(ControlType::Menubar, ControlPart::MenuItem,
670                                                      aRect, nState, aControlValue, OUString() );
671                 }
672                 else
673                 {
674                     if (bRollover)
675                         rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetMenuBarRolloverColor());
676                     else
677                         rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetMenuHighlightColor());
678                     rRenderContext.SetLineColor();
679                     rRenderContext.DrawRect(aRect);
680                 }
681                 rRenderContext.Pop();
682 
683                 m_pMenu->ImplPaint(rRenderContext, aOutputSize, 0, 0, pData, bHighlight, false, bRollover);
684             }
685             return;
686         }
687 
688         nX += pData->aSz.Width();
689     }
690 }
691 
ImplGetItemRect(sal_uInt16 nPos) const692 tools::Rectangle MenuBarWindow::ImplGetItemRect( sal_uInt16 nPos ) const
693 {
694     tools::Rectangle aRect;
695     if( m_pMenu )
696     {
697         tools::Long nX = 0;
698         size_t nCount = m_pMenu->pItemList->size();
699         for ( size_t n = 0; n < nCount; n++ )
700         {
701             MenuItemData* pData = m_pMenu->pItemList->GetDataFromPos( n );
702             if ( n == nPos )
703             {
704                 if ( pData->eType != MenuItemType::SEPARATOR )
705                     // #107747# give menuitems the height of the menubar
706                     aRect = tools::Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) );
707                 break;
708             }
709 
710             nX += pData->aSz.Width();
711         }
712     }
713     return aRect;
714 }
715 
KeyInput(const KeyEvent & rKEvent)716 void MenuBarWindow::KeyInput( const KeyEvent& rKEvent )
717 {
718     if ( !HandleKeyEvent( rKEvent ) )
719         Window::KeyInput( rKEvent );
720 }
721 
HandleKeyEvent(const KeyEvent & rKEvent,bool bFromMenu)722 bool MenuBarWindow::HandleKeyEvent( const KeyEvent& rKEvent, bool bFromMenu )
723 {
724     if (!m_pMenu)
725         return false;
726 
727     if (m_pMenu->bInCallback)
728         return true;    // swallow
729 
730     bool bDone = false;
731     sal_uInt16 nCode = rKEvent.GetKeyCode().GetCode();
732 
733     if( GetParent() )
734     {
735         if( GetParent()->GetWindow( GetWindowType::Client )->IsSystemWindow() )
736         {
737             SystemWindow *pSysWin = static_cast<SystemWindow*>(GetParent()->GetWindow( GetWindowType::Client ));
738             if( pSysWin->GetTaskPaneList() )
739                 if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) )
740                     return true;
741         }
742     }
743 
744     // no key events if native menus
745     if (m_pMenu->ImplGetSalMenu() && m_pMenu->ImplGetSalMenu()->VisibleMenuBar())
746     {
747         return false;
748     }
749 
750     if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10
751     {
752         mbAutoPopup = false;
753         if ( m_nHighlightedItem == ITEMPOS_INVALID )
754         {
755             ChangeHighlightItem( 0, false );
756             GrabFocus();
757         }
758         else
759         {
760             ChangeHighlightItem( ITEMPOS_INVALID, false );
761             m_xSaveFocusId = nullptr;
762         }
763         bDone = true;
764     }
765     else if ( bFromMenu )
766     {
767         if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ||
768             ( nCode == KEY_HOME ) || ( nCode == KEY_END ) )
769         {
770             sal_uInt16 n = m_nHighlightedItem;
771             if ( n == ITEMPOS_INVALID )
772             {
773                 if ( nCode == KEY_LEFT)
774                     n = 0;
775                 else
776                     n = m_pMenu->GetItemCount()-1;
777             }
778 
779             sal_uInt16 nLoop = n;
780 
781             if( nCode == KEY_HOME )
782                 { n = sal_uInt16(-1); nLoop = n+1; }
783             if( nCode == KEY_END )
784                 { n = m_pMenu->GetItemCount(); nLoop = n-1; }
785 
786             do
787             {
788                 if ( nCode == KEY_LEFT || nCode == KEY_END )
789                 {
790                     if ( n )
791                         n--;
792                     else
793                         n = m_pMenu->GetItemCount()-1;
794                 }
795                 if ( nCode == KEY_RIGHT || nCode == KEY_HOME )
796                 {
797                     n++;
798                     if ( n >= m_pMenu->GetItemCount() )
799                         n = 0;
800                 }
801 
802                 MenuItemData* pData = m_pMenu->GetItemList()->GetDataFromPos( n );
803                 if (pData->eType != MenuItemType::SEPARATOR &&
804                     m_pMenu->ImplIsVisible(n) &&
805                     !m_pMenu->ImplCurrentlyHiddenOnGUI(n))
806                 {
807                     ChangeHighlightItem( n, true );
808                     break;
809                 }
810             } while ( n != nLoop );
811             bDone = true;
812         }
813         else if ( nCode == KEY_RETURN )
814         {
815             if( m_pActivePopup ) KillActivePopup();
816             else
817                 if ( !mbAutoPopup )
818                 {
819                     ImplCreatePopup( true );
820                     mbAutoPopup = true;
821                 }
822             bDone = true;
823         }
824         else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) )
825         {
826             if ( !mbAutoPopup )
827             {
828                 ImplCreatePopup( true );
829                 mbAutoPopup = true;
830             }
831             bDone = true;
832         }
833         else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) )
834         {
835             if( m_pActivePopup )
836             {
837                 // hide the menu and remove the focus...
838                 mbAutoPopup = false;
839                 KillActivePopup();
840             }
841 
842             ChangeHighlightItem( ITEMPOS_INVALID, false );
843 
844             if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() )
845             {
846                 // put focus into document
847                 GrabFocusToDocument();
848             }
849 
850             bDone = true;
851         }
852     }
853 
854     if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) )
855     {
856         sal_Unicode nCharCode = rKEvent.GetCharCode();
857         if ( nCharCode )
858         {
859             size_t nEntry, nDuplicates;
860             MenuItemData* pData = m_pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, m_nHighlightedItem );
861             if ( pData && (nEntry != ITEMPOS_INVALID) )
862             {
863                 mbAutoPopup = true;
864                 ChangeHighlightItem( nEntry, true );
865                 bDone = true;
866             }
867         }
868     }
869 
870     return bDone;
871 }
872 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)873 void MenuBarWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
874 {
875     if (!m_pMenu)
876         return;
877 
878     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
879 
880     Size aOutputSize = GetOutputSizePixel();
881 
882     // no VCL paint if native menus
883     if (m_pMenu->ImplGetSalMenu() && m_pMenu->ImplGetSalMenu()->VisibleMenuBar())
884         return;
885 
886     // Make sure that all actual rendering happens in one go to avoid flicker.
887     vcl::BufferDevice pBuffer(this, rRenderContext);
888 
889     if (rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire))
890     {
891         MenubarValue aMenubarValue;
892         aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight(this);
893 
894         if (!rStyleSettings.GetPersonaHeader().IsEmpty())
895             Erase(*pBuffer);
896         else
897         {
898             tools::Rectangle aCtrlRegion( Point(), aOutputSize );
899 
900             pBuffer->DrawNativeControl(ControlType::Menubar, ControlPart::Entire, aCtrlRegion,
901                                        ControlState::ENABLED, aMenubarValue, OUString());
902         }
903 
904         ImplAddNWFSeparator(*pBuffer, aOutputSize, aMenubarValue);
905     }
906 
907     // shrink the area of the buttons
908     aOutputSize.AdjustWidth( -(m_aCloseBtn->GetSizePixel().Width()) );
909 
910     pBuffer->SetFillColor(rStyleSettings.GetMenuColor());
911     m_pMenu->ImplPaint(*pBuffer, aOutputSize, 0);
912 
913     if (m_nHighlightedItem != ITEMPOS_INVALID && m_pMenu && !m_pMenu->GetItemList()->GetDataFromPos(m_nHighlightedItem)->bHiddenOnGUI)
914         HighlightItem(*pBuffer, m_nHighlightedItem);
915     else if (m_nRolloveredItem != ITEMPOS_INVALID)
916         HighlightItem(*pBuffer, m_nRolloveredItem);
917 
918     // in high contrast mode draw a separating line on the lower edge
919     if (!rRenderContext.IsNativeControlSupported( ControlType::Menubar, ControlPart::Entire) &&
920         rStyleSettings.GetHighContrastMode())
921     {
922         pBuffer->Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::MAPMODE);
923         pBuffer->SetLineColor(COL_WHITE);
924         pBuffer->SetMapMode(MapMode(MapUnit::MapPixel));
925         Size aSize = GetSizePixel();
926         pBuffer->DrawLine(Point(0, aSize.Height() - 1),
927                           Point(aSize.Width() - 1, aSize.Height() - 1));
928         pBuffer->Pop();
929     }
930 }
931 
Resize()932 void MenuBarWindow::Resize()
933 {
934     Size aOutSz = GetOutputSizePixel();
935     tools::Long n      = aOutSz.Height()-4;
936     tools::Long nX     = aOutSz.Width()-3;
937     tools::Long nY     = 2;
938 
939     if ( m_aCloseBtn->IsVisible() )
940     {
941         m_aCloseBtn->Hide();
942         m_aCloseBtn->SetImages(n);
943         Size aTbxSize( m_aCloseBtn->CalcWindowSizePixel() );
944         nX -= aTbxSize.Width();
945         tools::Long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2;
946         m_aCloseBtn->setPosSizePixel(nX, nTbxY, aTbxSize.Width(), aTbxSize.Height());
947         nX -= 3;
948         m_aCloseBtn->Show();
949     }
950     if ( m_aFloatBtn->IsVisible() )
951     {
952         nX -= n;
953         m_aFloatBtn->setPosSizePixel( nX, nY, n, n );
954     }
955     if ( m_aHideBtn->IsVisible() )
956     {
957         nX -= n;
958         m_aHideBtn->setPosSizePixel( nX, nY, n, n );
959     }
960 
961     m_aFloatBtn->SetSymbol( SymbolType::FLOAT );
962     m_aHideBtn->SetSymbol( SymbolType::HIDE );
963 
964     Invalidate();
965 }
966 
ImplFindEntry(const Point & rMousePos) const967 sal_uInt16 MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const
968 {
969     if( m_pMenu )
970     {
971         tools::Long nX = 0;
972         size_t nCount = m_pMenu->pItemList->size();
973         for ( size_t n = 0; n < nCount; n++ )
974         {
975             MenuItemData* pData = m_pMenu->pItemList->GetDataFromPos( n );
976             if ( m_pMenu->ImplIsVisible( n ) )
977             {
978                 nX += pData->aSz.Width();
979                 if ( nX > rMousePos.X() )
980                     return static_cast<sal_uInt16>(n);
981             }
982         }
983     }
984     return ITEMPOS_INVALID;
985 }
986 
RequestHelp(const HelpEvent & rHEvt)987 void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt )
988 {
989     sal_uInt16 nId = m_nHighlightedItem;
990     if ( rHEvt.GetMode() & HelpEventMode::CONTEXT )
991         ChangeHighlightItem( ITEMPOS_INVALID, true );
992 
993     tools::Rectangle aHighlightRect( ImplGetItemRect( m_nHighlightedItem ) );
994     if( !ImplHandleHelpEvent( this, m_pMenu, nId, rHEvt, aHighlightRect ) )
995         Window::RequestHelp( rHEvt );
996 }
997 
StateChanged(StateChangedType nType)998 void MenuBarWindow::StateChanged( StateChangedType nType )
999 {
1000     Window::StateChanged( nType );
1001 
1002     if (nType == StateChangedType::ControlForeground ||
1003         nType == StateChangedType::ControlBackground)
1004     {
1005         ApplySettings(*GetOutDev());
1006         Invalidate();
1007     }
1008     else if (nType == StateChangedType::Enable)
1009     {
1010         Invalidate();
1011     }
1012     else if(m_pMenu)
1013     {
1014         m_pMenu->ImplKillLayoutData();
1015     }
1016 }
1017 
LayoutChanged()1018 void MenuBarWindow::LayoutChanged()
1019 {
1020     if (!m_pMenu)
1021         return;
1022 
1023     ApplySettings(*GetOutDev());
1024 
1025     // if the font was changed.
1026     tools::Long nHeight = m_pMenu->ImplCalcSize(this).Height();
1027 
1028     // depending on the native implementation or the displayable flag
1029     // the menubar windows is suppressed (ie, height=0)
1030     if (!m_pMenu->IsDisplayable() ||
1031         (m_pMenu->ImplGetSalMenu() && m_pMenu->ImplGetSalMenu()->VisibleMenuBar()))
1032     {
1033         nHeight = 0;
1034     }
1035     setPosSizePixel(0, 0, 0, nHeight, PosSizeFlags::Height);
1036     GetParent()->Resize();
1037     Invalidate();
1038     Resize();
1039 
1040     m_pMenu->ImplKillLayoutData();
1041 }
1042 
ApplySettings(vcl::RenderContext & rRenderContext)1043 void MenuBarWindow::ApplySettings(vcl::RenderContext& rRenderContext)
1044 {
1045     Window::ApplySettings(rRenderContext);
1046     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1047 
1048     SetPointFont(rRenderContext, rStyleSettings.GetMenuFont());
1049 
1050     const BitmapEx& rPersonaBitmap = Application::GetSettings().GetStyleSettings().GetPersonaHeader();
1051     SalMenu *pNativeMenu = m_pMenu ? m_pMenu->ImplGetSalMenu() : nullptr;
1052     if (pNativeMenu)
1053         pNativeMenu->ApplyPersona();
1054     if (!rPersonaBitmap.IsEmpty())
1055     {
1056         Wallpaper aWallpaper(rPersonaBitmap);
1057         aWallpaper.SetStyle(WallpaperStyle::TopRight);
1058         aWallpaper.SetColor(Application::GetSettings().GetStyleSettings().GetWorkspaceColor());
1059 
1060         rRenderContext.SetBackground(aWallpaper);
1061         SetPaintTransparent(false);
1062         SetParentClipMode();
1063     }
1064     else if (rRenderContext.IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire))
1065     {
1066         rRenderContext.SetBackground(); // background will be drawn by NWF
1067     }
1068     else
1069     {
1070         Wallpaper aWallpaper;
1071         aWallpaper.SetStyle(WallpaperStyle::ApplicationGradient);
1072         rRenderContext.SetBackground(aWallpaper);
1073         SetPaintTransparent(false);
1074         SetParentClipMode();
1075     }
1076 
1077     rRenderContext.SetTextColor(rStyleSettings.GetMenuBarTextColor());
1078     rRenderContext.SetTextFillColor();
1079     rRenderContext.SetLineColor();
1080 }
1081 
ImplInitStyleSettings()1082 void MenuBarWindow::ImplInitStyleSettings()
1083 {
1084     if (!(IsNativeControlSupported(ControlType::Menubar, ControlPart::MenuItem) &&
1085         IsNativeControlSupported(ControlType::Menubar, ControlPart::Entire)))
1086         return;
1087 
1088     AllSettings aSettings(GetSettings());
1089     ImplGetFrame()->UpdateSettings(aSettings); // to update persona
1090     StyleSettings aStyle(aSettings.GetStyleSettings());
1091     Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor;
1092     if (aHighlightTextColor != COL_TRANSPARENT)
1093     {
1094         aStyle.SetMenuHighlightTextColor(aHighlightTextColor);
1095     }
1096     aSettings.SetStyleSettings(aStyle);
1097     GetOutDev()->SetSettings(aSettings);
1098 }
1099 
DataChanged(const DataChangedEvent & rDCEvt)1100 void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt )
1101 {
1102     Window::DataChanged( rDCEvt );
1103 
1104     if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1105          (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
1106          ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1107           (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1108     {
1109         ApplySettings(*GetOutDev());
1110         ImplInitStyleSettings();
1111         LayoutChanged();
1112     }
1113 }
1114 
LoseFocus()1115 void MenuBarWindow::LoseFocus()
1116 {
1117     if ( !HasChildPathFocus( true ) )
1118         ChangeHighlightItem( ITEMPOS_INVALID, false, false );
1119 }
1120 
GetFocus()1121 void MenuBarWindow::GetFocus()
1122 {
1123     SalMenu *pNativeMenu = m_pMenu ? m_pMenu->ImplGetSalMenu() : nullptr;
1124     if (pNativeMenu && pNativeMenu->TakeFocus())
1125         return;
1126 
1127     if ( m_nHighlightedItem == ITEMPOS_INVALID )
1128     {
1129         mbAutoPopup = false;    // do not open menu when activated by focus handling like taskpane cycling
1130         ChangeHighlightItem( 0, false );
1131     }
1132 }
1133 
CreateAccessible()1134 css::uno::Reference<css::accessibility::XAccessible> MenuBarWindow::CreateAccessible()
1135 {
1136     css::uno::Reference<css::accessibility::XAccessible> xAcc;
1137 
1138     if (m_pMenu)
1139         xAcc = m_pMenu->GetAccessible();
1140 
1141     return xAcc;
1142 }
1143 
AddMenuBarButton(const Image & i_rImage,const Link<MenuBarButtonCallbackArg &,bool> & i_rLink,const OUString & i_rToolTip)1144 sal_uInt16 MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link<MenuBarButtonCallbackArg&,bool>& i_rLink, const OUString& i_rToolTip )
1145 {
1146     // find first free button id
1147     sal_uInt16 nId = IID_DOCUMENTCLOSE;
1148     std::map< sal_uInt16, AddButtonEntry >::const_iterator it;
1149     do
1150     {
1151         nId++;
1152         it = m_aAddButtons.find( nId );
1153     } while( it != m_aAddButtons.end() && nId < 128 );
1154     SAL_WARN_IF( nId >= 128, "vcl", "too many addbuttons in menubar" );
1155     AddButtonEntry& rNewEntry = m_aAddButtons[nId];
1156     rNewEntry.m_aSelectLink = i_rLink;
1157     m_aCloseBtn->InsertItem(ToolBoxItemId(nId), i_rImage, ToolBoxItemBits::NONE, 0);
1158     m_aCloseBtn->calcMinSize();
1159     ShowButtons(m_aCloseBtn->IsItemVisible(ToolBoxItemId(IID_DOCUMENTCLOSE)), m_aFloatBtn->IsVisible(), m_aHideBtn->IsVisible());
1160     LayoutChanged();
1161 
1162     if( m_pMenu->mpSalMenu )
1163         m_pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) );
1164 
1165     return nId;
1166 }
1167 
SetMenuBarButtonHighlightHdl(sal_uInt16 nId,const Link<MenuBarButtonCallbackArg &,bool> & rLink)1168 void MenuBarWindow::SetMenuBarButtonHighlightHdl( sal_uInt16 nId, const Link<MenuBarButtonCallbackArg&,bool>& rLink )
1169 {
1170     std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( nId );
1171     if( it != m_aAddButtons.end() )
1172         it->second.m_aHighlightLink = rLink;
1173 }
1174 
GetMenuBarButtonRectPixel(sal_uInt16 nId)1175 tools::Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( sal_uInt16 nId )
1176 {
1177     tools::Rectangle aRect;
1178     if( m_aAddButtons.find( nId ) != m_aAddButtons.end() )
1179     {
1180         if( m_pMenu->mpSalMenu )
1181         {
1182             aRect = m_pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame );
1183             if( aRect == tools::Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) )
1184             {
1185                 // system menu button is somewhere but location cannot be determined
1186                 return tools::Rectangle();
1187             }
1188         }
1189 
1190         if( aRect.IsEmpty() )
1191         {
1192             aRect = m_aCloseBtn->GetItemRect(ToolBoxItemId(nId));
1193             Point aOffset = m_aCloseBtn->OutputToScreenPixel(Point());
1194             aRect.Move( aOffset.X(), aOffset.Y() );
1195         }
1196     }
1197     return aRect;
1198 }
1199 
RemoveMenuBarButton(sal_uInt16 nId)1200 void MenuBarWindow::RemoveMenuBarButton( sal_uInt16 nId )
1201 {
1202     ToolBox::ImplToolItems::size_type nPos = m_aCloseBtn->GetItemPos(ToolBoxItemId(nId));
1203     m_aCloseBtn->RemoveItem(nPos);
1204     m_aAddButtons.erase( nId );
1205     m_aCloseBtn->calcMinSize();
1206     LayoutChanged();
1207 
1208     if( m_pMenu->mpSalMenu )
1209         m_pMenu->mpSalMenu->RemoveMenuBarButton( nId );
1210 }
1211 
HandleMenuButtonEvent(sal_uInt16 i_nButtonId)1212 bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId )
1213 {
1214     std::map< sal_uInt16, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId );
1215     if( it != m_aAddButtons.end() )
1216     {
1217         MenuBarButtonCallbackArg aArg;
1218         aArg.nId = it->first;
1219         aArg.bHighlight = true;
1220         return it->second.m_aSelectLink.Call( aArg );
1221     }
1222     return false;
1223 }
1224 
CanGetFocus() const1225 bool MenuBarWindow::CanGetFocus() const
1226 {
1227     /* #i83908# do not use the menubar if it is native or invisible
1228        this relies on MenuBar::ImplCreate setting the height of the menubar
1229        to 0 in this case
1230     */
1231     SalMenu *pNativeMenu = m_pMenu ? m_pMenu->ImplGetSalMenu() : nullptr;
1232     if (pNativeMenu && pNativeMenu->VisibleMenuBar())
1233         return pNativeMenu->CanGetFocus();
1234     return GetSizePixel().Height() > 0;
1235 }
1236 
1237 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1238