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