Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / win / window / salmenu.cxx
blob190f507304743ffa70d634d60948a9e9174fc315
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>
26 #include <win/wincomp.hxx>
27 #include <win/saldata.hxx>
28 #include <win/salinst.h>
29 #include <win/salframe.h>
30 #include <win/salmenu.h>
32 #include <salgdi.hxx>
34 static DWORD myerr=0;
36 bool SalData::IsKnownMenuHandle( HMENU hMenu )
38 if( mhMenuSet.find( hMenu ) == mhMenuSet.end() )
39 return FALSE;
40 else
41 return TRUE;
44 // WinSalInst factory methods
46 std::unique_ptr<SalMenu> WinSalInstance::CreateMenu( bool bMenuBar, Menu* )
48 WinSalMenu *pSalMenu = new WinSalMenu();
50 pSalMenu->mbMenuBar = bMenuBar;
51 pSalMenu->mhWnd = nullptr;
52 if( bMenuBar )
53 pSalMenu->mhMenu = ::CreateMenu();
54 else
55 pSalMenu->mhMenu = ::CreatePopupMenu();
57 if( pSalMenu->mhMenu )
58 GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu );
60 return std::unique_ptr<SalMenu>(pSalMenu);
63 std::unique_ptr<SalMenuItem> WinSalInstance::CreateMenuItem( const SalItemParams & rItemData )
65 WinSalMenuItem *pSalMenuItem = new WinSalMenuItem();
66 memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) );
67 pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW );
69 if( rItemData.eType == MenuItemType::SEPARATOR )
71 // separator
72 pSalMenuItem->mInfo.fMask = MIIM_TYPE;
73 pSalMenuItem->mInfo.fType = MFT_SEPARATOR;
75 else
77 // item
78 pSalMenuItem->mText = rItemData.aText;
79 pSalMenuItem->mpMenu = rItemData.pMenu;
80 pSalMenuItem->maBitmap= !!rItemData.aImage ? rItemData.aImage.GetBitmapEx().GetBitmap() : Bitmap();
81 pSalMenuItem->mnId = rItemData.nId;
83 // 'translate' mnemonics
84 pSalMenuItem->mText = pSalMenuItem->mText.replaceAll( "~", "&" );
86 pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
87 pSalMenuItem->mInfo.fType = MFT_STRING;
88 pSalMenuItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(pSalMenuItem->mText.getStr()));
89 pSalMenuItem->mInfo.cch = pSalMenuItem->mText.getLength();
91 pSalMenuItem->mInfo.wID = rItemData.nId;
92 pSalMenuItem->mInfo.dwItemData = reinterpret_cast<ULONG_PTR>(pSalMenuItem); // user data
95 return std::unique_ptr<SalMenuItem>(pSalMenuItem);
98 static void ImplDrawMenuBar( SalMenu *pMenu )
100 if( pMenu->VisibleMenuBar() )
102 // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
104 WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
105 if( pMenuBar && pMenuBar->mhWnd )
106 ::DrawMenuBar( pMenuBar->mhWnd );
112 * WinSalMenu
115 WinSalMenu::WinSalMenu()
117 mhMenu = nullptr;
118 mbMenuBar = FALSE;
119 mhWnd = nullptr;
120 mpParentMenu = nullptr;
123 WinSalMenu::~WinSalMenu()
125 // only required if not associated to a window...
126 GetSalData()->mhMenuSet.erase( mhMenu );
127 ::DestroyMenu( mhMenu );
130 bool WinSalMenu::VisibleMenuBar()
132 // The Win32 implementation never shows a native
133 // menubar. Thus, native menus are only visible
134 // when the menu is merged with an OLE container.
135 // The reason are missing tooltips, ownerdraw
136 // issues and accessibility which are better supported
137 // by VCL menus.
138 // Nevertheless, the native menus are always created
139 // and the application will properly react to all native
140 // menu messages.
142 return FALSE;
145 void WinSalMenu::SetFrame( const SalFrame *pFrame )
147 if( pFrame )
148 mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd;
149 else
150 mhWnd = nullptr;
153 void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
155 if( pSalMenuItem )
157 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
158 if( nPos == MENU_APPEND )
160 nPos = ::GetMenuItemCount( mhMenu );
161 if( nPos == static_cast<unsigned>( -1 ) )
162 return;
165 if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
166 myerr = GetLastError();
167 else
169 pWItem->mpSalMenu = this;
170 ImplDrawMenuBar( this );
175 void WinSalMenu::RemoveItem( unsigned nPos )
177 int num = ::GetMenuItemCount( mhMenu );
178 if( num != -1 && nPos < static_cast<unsigned>(num) )
180 WinSalMenuItem *pSalMenuItem = nullptr;
182 MENUITEMINFOW mi = {};
183 mi.cbSize = sizeof( mi );
184 mi.fMask = MIIM_DATA;
185 if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) )
186 myerr = GetLastError();
187 else
188 pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
190 if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) )
191 myerr = GetLastError();
192 else
194 if( pSalMenuItem )
195 pSalMenuItem->mpSalMenu = nullptr;
196 ImplDrawMenuBar( this );
201 static void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId )
203 if( !pSalMenu )
204 return;
206 WinSalMenuItem *pSalMenuItem = nullptr;
208 MENUITEMINFOW mi = {};
209 mi.cbSize = sizeof( mi );
210 mi.fMask = MIIM_DATA;
211 if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) )
212 myerr = GetLastError();
213 else
214 pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
216 if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) )
217 myerr = GetLastError();
218 else
220 if( pSalMenuItem )
221 pSalMenuItem->mpSalMenu = nullptr;
222 ImplDrawMenuBar( pSalMenu );
226 void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
228 if( pSalMenuItem )
230 WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
231 WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu);
232 if( pWMenuItem->mInfo.hSubMenu )
234 GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu );
235 ::DestroyMenu( pWMenuItem->mInfo.hSubMenu );
238 pWMenuItem->mInfo.fMask |= MIIM_SUBMENU;
239 if( !pSubMenu )
240 pWMenuItem->mInfo.hSubMenu = nullptr;
241 else
243 pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu;
244 pWSubMenu->mpParentMenu = this;
247 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) )
248 myerr = GetLastError();
249 else
250 ImplDrawMenuBar( this );
254 void WinSalMenu::CheckItem( unsigned nPos, bool bCheck )
256 if( static_cast<unsigned>( -1 ) != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) )
257 ImplDrawMenuBar( this );
260 void WinSalMenu::EnableItem( unsigned nPos, bool bEnable )
262 if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) )
263 ImplDrawMenuBar( this );
266 void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage )
268 if( pSalMenuItem )
270 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
271 if( !!rImage )
272 pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap();
273 else
274 pWItem->maBitmap = Bitmap();
278 void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText )
280 if( pSalMenuItem )
282 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
283 pWItem->mText = rText;
284 // 'translate' mnemonics
285 pWItem->mText = pWItem->mText.replaceAll( "~", "&" );
286 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
287 pWItem->mInfo.fType = MFT_STRING;
289 // combine text and accelerator text
290 OUString aStr( pWItem->mText );
291 if( pWItem->mAccelText.getLength() )
293 aStr += "\t" + pWItem->mAccelText;
295 pWItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(aStr.getStr()));
296 pWItem->mInfo.cch = aStr.getLength();
298 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
299 myerr = GetLastError();
300 else
301 ImplDrawMenuBar( this );
305 void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode&, const OUString& rKeyName )
307 if( pSalMenuItem )
309 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
310 pWItem->mAccelText = rKeyName;
311 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
312 pWItem->mInfo.fType = MFT_STRING;
314 // combine text and accelerator text
315 OUString aStr( pWItem->mText );
316 if( pWItem->mAccelText.getLength() )
318 aStr += "\t" + pWItem->mAccelText;
320 pWItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(aStr.getStr()));
321 pWItem->mInfo.cch = aStr.getLength();
323 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
324 myerr = GetLastError();
325 else
326 ImplDrawMenuBar( this );
330 void WinSalMenu::GetSystemMenuData( SystemMenuData* pData )
332 if( pData )
333 pData->hMenu = mhMenu;
337 * SalMenuItem
340 WinSalMenuItem::WinSalMenuItem()
342 memset( &mInfo, 0, sizeof( MENUITEMINFOW ) );
343 mpMenu = nullptr;
344 mnId = 0xFFFF;
345 mpSalMenu = nullptr;
348 WinSalMenuItem::~WinSalMenuItem()
350 if( mpSalMenu )
351 ImplRemoveItemById( mpSalMenu, mnId );
354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */