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