Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / vcl / win / window / salmenu.cxx
blob1339f80afa3d3cd5e0952ef5f2beb8d268d18911
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 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 pSalMenu;
63 void WinSalInstance::DestroyMenu( SalMenu* pSalMenu )
65 delete pSalMenu;
68 SalMenuItem* WinSalInstance::CreateMenuItem( const SalItemParams* pItemData )
70 if( !pItemData )
71 return nullptr;
73 WinSalMenuItem *pSalMenuItem = new WinSalMenuItem();
74 memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) );
75 pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW );
77 if( pItemData->eType == MenuItemType::SEPARATOR )
79 // separator
80 pSalMenuItem->mInfo.fMask = MIIM_TYPE;
81 pSalMenuItem->mInfo.fType = MFT_SEPARATOR;
83 else
85 // item
86 pSalMenuItem->mText = pItemData->aText;
87 pSalMenuItem->mpMenu = pItemData->pMenu;
88 pSalMenuItem->maBitmap= !!pItemData->aImage ? pItemData->aImage.GetBitmapEx().GetBitmap() : Bitmap();
89 pSalMenuItem->mnId = pItemData->nId;
91 // 'translate' mnemonics
92 pSalMenuItem->mText = pSalMenuItem->mText.replaceAll( "~", "&" );
94 pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
95 pSalMenuItem->mInfo.fType = MFT_STRING;
96 pSalMenuItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(pSalMenuItem->mText.getStr()));
97 pSalMenuItem->mInfo.cch = pSalMenuItem->mText.getLength();
99 pSalMenuItem->mInfo.wID = pItemData->nId;
100 pSalMenuItem->mInfo.dwItemData = reinterpret_cast<ULONG_PTR>(pSalMenuItem); // user data
103 return pSalMenuItem;
106 void WinSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
108 delete pSalMenuItem;
111 static void ImplDrawMenuBar( SalMenu *pMenu )
113 if( pMenu->VisibleMenuBar() )
115 // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
117 WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
118 if( pMenuBar && pMenuBar->mhWnd )
119 ::DrawMenuBar( pMenuBar->mhWnd );
125 * WinSalMenu
128 WinSalMenu::WinSalMenu()
130 mhMenu = nullptr;
131 mbMenuBar = FALSE;
132 mhWnd = nullptr;
133 mpParentMenu = nullptr;
136 WinSalMenu::~WinSalMenu()
138 // only required if not associated to a window...
139 GetSalData()->mhMenuSet.erase( mhMenu );
140 ::DestroyMenu( mhMenu );
143 bool WinSalMenu::VisibleMenuBar()
145 // The Win32 implementation never shows a native
146 // menubar. Thus, native menus are only visible
147 // when the menu is merged with an OLE container.
148 // The reason are missing tooltips, ownerdraw
149 // issues and accessibility which are better supported
150 // by VCL menus.
151 // Nevertheless, the native menus are always created
152 // and the application will properly react to all native
153 // menu messages.
155 return FALSE;
158 void WinSalMenu::SetFrame( const SalFrame *pFrame )
160 if( pFrame )
161 mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd;
162 else
163 mhWnd = nullptr;
166 void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
168 if( pSalMenuItem )
170 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
171 if( nPos == MENU_APPEND )
173 nPos = ::GetMenuItemCount( mhMenu );
174 if( nPos == static_cast<unsigned>( -1 ) )
175 return;
178 if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
179 myerr = GetLastError();
180 else
182 pWItem->mpSalMenu = this;
183 ImplDrawMenuBar( this );
188 void WinSalMenu::RemoveItem( unsigned nPos )
190 int num = ::GetMenuItemCount( mhMenu );
191 if( num != -1 && nPos < static_cast<unsigned>(num) )
193 WinSalMenuItem *pSalMenuItem = nullptr;
195 MENUITEMINFOW mi;
196 memset( &mi, 0, sizeof(mi) );
197 mi.cbSize = sizeof( mi );
198 mi.fMask = MIIM_DATA;
199 if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) )
200 myerr = GetLastError();
201 else
202 pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
204 if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) )
205 myerr = GetLastError();
206 else
208 if( pSalMenuItem )
209 pSalMenuItem->mpSalMenu = nullptr;
210 ImplDrawMenuBar( this );
215 void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId )
217 if( !pSalMenu )
218 return;
220 WinSalMenuItem *pSalMenuItem = nullptr;
222 MENUITEMINFOW mi;
223 memset( &mi, 0, sizeof(mi) );
224 mi.cbSize = sizeof( mi );
225 mi.fMask = MIIM_DATA;
226 if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) )
227 myerr = GetLastError();
228 else
229 pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
231 if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) )
232 myerr = GetLastError();
233 else
235 if( pSalMenuItem )
236 pSalMenuItem->mpSalMenu = nullptr;
237 ImplDrawMenuBar( pSalMenu );
241 void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
243 if( pSalMenuItem )
245 WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
246 WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu);
247 if( pWMenuItem->mInfo.hSubMenu )
249 GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu );
250 ::DestroyMenu( pWMenuItem->mInfo.hSubMenu );
253 pWMenuItem->mInfo.fMask |= MIIM_SUBMENU;
254 if( !pSubMenu )
255 pWMenuItem->mInfo.hSubMenu = nullptr;
256 else
258 pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu;
259 pWSubMenu->mpParentMenu = this;
262 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) )
263 myerr = GetLastError();
264 else
265 ImplDrawMenuBar( this );
269 void WinSalMenu::CheckItem( unsigned nPos, bool bCheck )
271 if( static_cast<unsigned>( -1 ) != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) )
272 ImplDrawMenuBar( this );
275 void WinSalMenu::EnableItem( unsigned nPos, bool bEnable )
277 if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) )
278 ImplDrawMenuBar( this );
281 void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage )
283 if( pSalMenuItem )
285 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
286 if( !!rImage )
287 pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap();
288 else
289 pWItem->maBitmap = Bitmap();
293 void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText )
295 if( pSalMenuItem )
297 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
298 pWItem->mText = rText;
299 // 'translate' mnemonics
300 pWItem->mText = pWItem->mText.replaceAll( "~", "&" );
301 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
302 pWItem->mInfo.fType = MFT_STRING;
304 // combine text and accelerator text
305 OUString aStr( pWItem->mText );
306 if( pWItem->mAccelText.getLength() )
308 aStr += "\t" + pWItem->mAccelText;
310 pWItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(aStr.getStr()));
311 pWItem->mInfo.cch = aStr.getLength();
313 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
314 myerr = GetLastError();
315 else
316 ImplDrawMenuBar( this );
320 void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode&, const OUString& rKeyName )
322 if( pSalMenuItem )
324 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
325 pWItem->mAccelText = rKeyName;
326 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
327 pWItem->mInfo.fType = MFT_STRING;
329 // combine text and accelerator text
330 OUString aStr( pWItem->mText );
331 if( pWItem->mAccelText.getLength() )
333 aStr += "\t" + pWItem->mAccelText;
335 pWItem->mInfo.dwTypeData = o3tl::toW(const_cast<sal_Unicode *>(aStr.getStr()));
336 pWItem->mInfo.cch = aStr.getLength();
338 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
339 myerr = GetLastError();
340 else
341 ImplDrawMenuBar( this );
345 void WinSalMenu::GetSystemMenuData( SystemMenuData* pData )
347 if( pData )
348 pData->hMenu = mhMenu;
352 * SalMenuItem
355 WinSalMenuItem::WinSalMenuItem()
357 memset( &mInfo, 0, sizeof( MENUITEMINFOW ) );
358 mpMenu = nullptr;
359 mnId = 0xFFFF;
360 mpSalMenu = nullptr;
363 WinSalMenuItem::~WinSalMenuItem()
365 if( mpSalMenu )
366 ImplRemoveItemById( mpSalMenu, mnId );
369 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */