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