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