nss: upgrade to release 3.73
[LibreOffice.git] / vcl / win / window / salmenu.cxx
blob6f8dc8bff283617eae942d72f0137aecc60f976b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svsys.h>
22 #include <vcl/menu.hxx>
23 #include <vcl/sysdata.hxx>
24 #include <o3tl/char16_t2wchar_t.hxx>
25 #include <o3tl/safeint.hxx>
27 #include <win/wincomp.hxx>
28 #include <win/saldata.hxx>
29 #include <win/salinst.h>
30 #include <win/salframe.h>
31 #include <win/salmenu.h>
33 #include <salgdi.hxx>
35 static DWORD myerr=0;
37 bool SalData::IsKnownMenuHandle( HMENU hMenu )
39 if( mhMenuSet.find( hMenu ) == mhMenuSet.end() )
40 return false;
41 else
42 return true;
45 // WinSalInst factory methods
47 std::unique_ptr<SalMenu> WinSalInstance::CreateMenu( bool bMenuBar, Menu* )
49 WinSalMenu *pSalMenu = new WinSalMenu();
51 pSalMenu->mbMenuBar = bMenuBar;
52 pSalMenu->mhWnd = nullptr;
53 if( bMenuBar )
54 pSalMenu->mhMenu = ::CreateMenu();
55 else
56 pSalMenu->mhMenu = ::CreatePopupMenu();
58 if( pSalMenu->mhMenu )
59 GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu );
61 return std::unique_ptr<SalMenu>(pSalMenu);
64 std::unique_ptr<SalMenuItem> WinSalInstance::CreateMenuItem( const SalItemParams & rItemData )
66 WinSalMenuItem *pSalMenuItem = new WinSalMenuItem();
67 memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) );
68 pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW );
70 if( rItemData.eType == MenuItemType::SEPARATOR )
72 // separator
73 pSalMenuItem->mInfo.fMask = MIIM_TYPE;
74 pSalMenuItem->mInfo.fType = MFT_SEPARATOR;
76 else
78 // item
79 pSalMenuItem->mText = rItemData.aText;
80 pSalMenuItem->mpMenu = rItemData.pMenu;
81 pSalMenuItem->maBitmap= !!rItemData.aImage ? rItemData.aImage.GetBitmapEx().GetBitmap() : Bitmap();
82 pSalMenuItem->mnId = rItemData.nId;
84 // 'translate' mnemonics
85 pSalMenuItem->mText = pSalMenuItem->mText.replaceAll( "~", "&" );
87 pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
88 pSalMenuItem->mInfo.fType = MFT_STRING;
89 pSalMenuItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(pSalMenuItem->mText.getStr()));
90 pSalMenuItem->mInfo.cch = pSalMenuItem->mText.getLength();
92 pSalMenuItem->mInfo.wID = rItemData.nId;
93 pSalMenuItem->mInfo.dwItemData = reinterpret_cast<ULONG_PTR>(pSalMenuItem); // user data
96 return std::unique_ptr<SalMenuItem>(pSalMenuItem);
99 static void ImplDrawMenuBar( SalMenu *pMenu )
101 if( pMenu->VisibleMenuBar() )
103 // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
105 WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
106 if( pMenuBar && pMenuBar->mhWnd )
107 ::DrawMenuBar( pMenuBar->mhWnd );
113 * WinSalMenu
116 WinSalMenu::WinSalMenu()
118 mhMenu = nullptr;
119 mbMenuBar = false;
120 mhWnd = nullptr;
121 mpParentMenu = nullptr;
124 WinSalMenu::~WinSalMenu()
126 // only required if not associated to a window...
127 GetSalData()->mhMenuSet.erase( mhMenu );
128 ::DestroyMenu( mhMenu );
131 bool WinSalMenu::VisibleMenuBar()
133 // The Win32 implementation never shows a native
134 // menubar. Thus, native menus are only visible
135 // when the menu is merged with an OLE container.
136 // The reason are missing tooltips, ownerdraw
137 // issues and accessibility which are better supported
138 // by VCL menus.
139 // Nevertheless, the native menus are always created
140 // and the application will properly react to all native
141 // menu messages.
143 return false;
146 void WinSalMenu::SetFrame( const SalFrame *pFrame )
148 if( pFrame )
149 mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd;
150 else
151 mhWnd = nullptr;
154 void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
156 if( pSalMenuItem )
158 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
159 if( nPos == MENU_APPEND )
161 nPos = ::GetMenuItemCount( mhMenu );
162 if( nPos == static_cast<unsigned>( -1 ) )
163 return;
166 if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
167 myerr = GetLastError();
168 else
170 pWItem->mpSalMenu = this;
171 ImplDrawMenuBar( this );
176 void WinSalMenu::RemoveItem( unsigned nPos )
178 int num = ::GetMenuItemCount( mhMenu );
179 if( num != -1 && nPos < o3tl::make_unsigned(num) )
181 WinSalMenuItem *pSalMenuItem = nullptr;
183 MENUITEMINFOW mi = {};
184 mi.cbSize = sizeof( mi );
185 mi.fMask = MIIM_DATA;
186 if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) )
187 myerr = GetLastError();
188 else
189 pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
191 if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) )
192 myerr = GetLastError();
193 else
195 if( pSalMenuItem )
196 pSalMenuItem->mpSalMenu = nullptr;
197 ImplDrawMenuBar( this );
202 static void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId )
204 if( !pSalMenu )
205 return;
207 WinSalMenuItem *pSalMenuItem = nullptr;
209 MENUITEMINFOW mi = {};
210 mi.cbSize = sizeof( mi );
211 mi.fMask = MIIM_DATA;
212 if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) )
213 myerr = GetLastError();
214 else
215 pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
217 if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) )
218 myerr = GetLastError();
219 else
221 if( pSalMenuItem )
222 pSalMenuItem->mpSalMenu = nullptr;
223 ImplDrawMenuBar( pSalMenu );
227 void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
229 if( pSalMenuItem )
231 WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
232 WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu);
233 if( pWMenuItem->mInfo.hSubMenu )
235 GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu );
236 ::DestroyMenu( pWMenuItem->mInfo.hSubMenu );
239 pWMenuItem->mInfo.fMask |= MIIM_SUBMENU;
240 if( !pSubMenu )
241 pWMenuItem->mInfo.hSubMenu = nullptr;
242 else
244 pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu;
245 pWSubMenu->mpParentMenu = this;
248 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) )
249 myerr = GetLastError();
250 else
251 ImplDrawMenuBar( this );
255 void WinSalMenu::CheckItem( unsigned nPos, bool bCheck )
257 if( static_cast<unsigned>( -1 ) != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) )
258 ImplDrawMenuBar( this );
261 void WinSalMenu::EnableItem( unsigned nPos, bool bEnable )
263 if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) )
264 ImplDrawMenuBar( this );
267 void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage )
269 if( pSalMenuItem )
271 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
272 if( !!rImage )
273 pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap();
274 else
275 pWItem->maBitmap = Bitmap();
279 void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText )
281 if( pSalMenuItem )
283 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
284 pWItem->mText = rText;
285 // 'translate' mnemonics
286 pWItem->mText = pWItem->mText.replaceAll( "~", "&" );
287 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
288 pWItem->mInfo.fType = MFT_STRING;
290 // combine text and accelerator text
291 OUString aStr( pWItem->mText );
292 if( pWItem->mAccelText.getLength() )
294 aStr += "\t" + pWItem->mAccelText;
296 pWItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(aStr.getStr()));
297 pWItem->mInfo.cch = aStr.getLength();
299 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
300 myerr = GetLastError();
301 else
302 ImplDrawMenuBar( this );
306 void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode&, const OUString& rKeyName )
308 if( pSalMenuItem )
310 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
311 pWItem->mAccelText = rKeyName;
312 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
313 pWItem->mInfo.fType = MFT_STRING;
315 // combine text and accelerator text
316 OUString aStr( pWItem->mText );
317 if( pWItem->mAccelText.getLength() )
319 aStr += "\t" + pWItem->mAccelText;
321 pWItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(aStr.getStr()));
322 pWItem->mInfo.cch = aStr.getLength();
324 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
325 myerr = GetLastError();
326 else
327 ImplDrawMenuBar( this );
331 void WinSalMenu::GetSystemMenuData( SystemMenuData* pData )
333 if( pData )
334 pData->hMenu = mhMenu;
338 * SalMenuItem
341 WinSalMenuItem::WinSalMenuItem()
343 memset( &mInfo, 0, sizeof( MENUITEMINFOW ) );
344 mpMenu = nullptr;
345 mnId = 0xFFFF;
346 mpSalMenu = nullptr;
349 WinSalMenuItem::~WinSalMenuItem()
351 if( mpSalMenu )
352 ImplRemoveItemById( mpSalMenu, mnId );
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */