1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
37 bool SalData::IsKnownMenuHandle( HMENU hMenu
)
39 if( mhMenuSet
.find( hMenu
) == mhMenuSet
.end() )
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;
54 pSalMenu
->mhMenu
= ::CreateMenu();
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
)
73 pSalMenuItem
->mInfo
.fMask
= MIIM_TYPE
;
74 pSalMenuItem
->mInfo
.fType
= MFT_SEPARATOR
;
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 );
116 WinSalMenu::WinSalMenu()
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
139 // Nevertheless, the native menus are always created
140 // and the application will properly react to all native
146 void WinSalMenu::SetFrame( const SalFrame
*pFrame
)
149 mhWnd
= static_cast<const WinSalFrame
*>(pFrame
)->mhWnd
;
154 void WinSalMenu::InsertItem( SalMenuItem
* pSalMenuItem
, unsigned nPos
)
158 WinSalMenuItem
* pWItem
= static_cast<WinSalMenuItem
*>(pSalMenuItem
);
159 if( nPos
== MENU_APPEND
)
161 nPos
= ::GetMenuItemCount( mhMenu
);
162 if( nPos
== static_cast<unsigned>( -1 ) )
166 if(!::InsertMenuItemW( mhMenu
, nPos
, TRUE
, &pWItem
->mInfo
))
167 myerr
= GetLastError();
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();
189 pSalMenuItem
= reinterpret_cast<WinSalMenuItem
*>(mi
.dwItemData
);
191 if( !::RemoveMenu( mhMenu
, nPos
, MF_BYPOSITION
) )
192 myerr
= GetLastError();
196 pSalMenuItem
->mpSalMenu
= nullptr;
197 ImplDrawMenuBar( this );
202 static void ImplRemoveItemById( WinSalMenu
*pSalMenu
, unsigned nItemId
)
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();
215 pSalMenuItem
= reinterpret_cast<WinSalMenuItem
*>(mi
.dwItemData
);
217 if( !::RemoveMenu( pSalMenu
->mhMenu
, nItemId
, MF_BYCOMMAND
) )
218 myerr
= GetLastError();
222 pSalMenuItem
->mpSalMenu
= nullptr;
223 ImplDrawMenuBar( pSalMenu
);
227 void WinSalMenu::SetSubMenu( SalMenuItem
* pSalMenuItem
, SalMenu
* pSubMenu
, unsigned nPos
)
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
;
241 pWMenuItem
->mInfo
.hSubMenu
= nullptr;
244 pWMenuItem
->mInfo
.hSubMenu
= pWSubMenu
->mhMenu
;
245 pWSubMenu
->mpParentMenu
= this;
248 if(!::SetMenuItemInfoW( mhMenu
, nPos
, TRUE
, &pWMenuItem
->mInfo
) )
249 myerr
= GetLastError();
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
)
271 WinSalMenuItem
* pWItem
= static_cast<WinSalMenuItem
*>(pSalMenuItem
);
273 pWItem
->maBitmap
= rImage
.GetBitmapEx().GetBitmap();
275 pWItem
->maBitmap
= Bitmap();
279 void WinSalMenu::SetItemText( unsigned nPos
, SalMenuItem
* pSalMenuItem
, const OUString
& rText
)
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();
302 ImplDrawMenuBar( this );
306 void WinSalMenu::SetAccelerator( unsigned nPos
, SalMenuItem
* pSalMenuItem
, const vcl::KeyCode
&, const OUString
& rKeyName
)
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();
327 ImplDrawMenuBar( this );
331 void WinSalMenu::GetSystemMenuData( SystemMenuData
* pData
)
334 pData
->hMenu
= mhMenu
;
341 WinSalMenuItem::WinSalMenuItem()
343 memset( &mInfo
, 0, sizeof( MENUITEMINFOW
) );
349 WinSalMenuItem::~WinSalMenuItem()
352 ImplRemoveItemById( mpSalMenu
, mnId
);
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */