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