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