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 .
23 #include <vcl/menu.hxx>
24 #include <vcl/sysdata.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>
35 // uncomment the following line to have ownerdrawn menus, ie, with bitmaps
36 // however, this is incompatible with OLE inplace editing
37 // so it is not activated by default
42 // =======================================================================
44 sal_Bool
SalData::IsKnownMenuHandle( HMENU hMenu
)
46 if( mhMenuSet
.find( hMenu
) == mhMenuSet
.end() )
52 // =======================================================================
54 // WinSalInst factory methods
56 SalMenu
* WinSalInstance::CreateMenu( sal_Bool bMenuBar
, Menu
* )
58 WinSalMenu
*pSalMenu
= new WinSalMenu();
60 pSalMenu
->mbMenuBar
= bMenuBar
;
61 pSalMenu
->mhWnd
= NULL
;
63 pSalMenu
->mhMenu
= ::CreateMenu();
65 pSalMenu
->mhMenu
= ::CreatePopupMenu();
67 if( pSalMenu
->mhMenu
)
68 GetSalData()->mhMenuSet
.insert( pSalMenu
->mhMenu
);
73 void WinSalInstance::DestroyMenu( SalMenu
* pSalMenu
)
79 SalMenuItem
* WinSalInstance::CreateMenuItem( const SalItemParams
* pItemData
)
84 WinSalMenuItem
*pSalMenuItem
= new WinSalMenuItem();
85 memset( &pSalMenuItem
->mInfo
, 0, sizeof( MENUITEMINFOW
) );
86 pSalMenuItem
->mInfo
.cbSize
= sizeof( MENUITEMINFOW
);
88 if( pItemData
->eType
== MENUITEM_SEPARATOR
)
91 pSalMenuItem
->mInfo
.fMask
= MIIM_TYPE
;
92 pSalMenuItem
->mInfo
.fType
= MFT_SEPARATOR
;
97 pSalMenuItem
->mText
= pItemData
->aText
;
98 pSalMenuItem
->mpMenu
= pItemData
->pMenu
;
99 pSalMenuItem
->maBitmap
= !!pItemData
->aImage
? pItemData
->aImage
.GetBitmapEx().GetBitmap() : Bitmap();
100 pSalMenuItem
->mnId
= pItemData
->nId
;
102 // 'translate' mnemonics
103 pSalMenuItem
->mText
.SearchAndReplace( '~', '&' );
105 pSalMenuItem
->mInfo
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_ID
| MIIM_DATA
;
106 pSalMenuItem
->mInfo
.fType
= MFT_STRING
;
108 if( pItemData
->pMenu
&& !pItemData
->pMenu
->IsMenuBar() )
109 pSalMenuItem
->mInfo
.fType
|= MFT_OWNERDRAW
;
110 pSalMenuItem
->mInfo
.fState
= MFS_ENABLED
;
112 pSalMenuItem
->mInfo
.dwTypeData
= (LPWSTR
) pSalMenuItem
->mText
.GetBuffer();
113 pSalMenuItem
->mInfo
.cch
= pSalMenuItem
->mText
.Len();
115 pSalMenuItem
->mInfo
.wID
= pItemData
->nId
;
116 pSalMenuItem
->mInfo
.dwItemData
= (ULONG_PTR
) pSalMenuItem
; // user data
122 void WinSalInstance::DestroyMenuItem( SalMenuItem
* pSalMenuItem
)
128 // =======================================================================
130 static void ImplDrawMenuBar( SalMenu
*pMenu
)
132 if( pMenu
->VisibleMenuBar() )
134 // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
136 WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
137 if( pMenuBar && pMenuBar->mhWnd )
138 ::DrawMenuBar( pMenuBar->mhWnd );
143 // =======================================================================
150 WinSalMenu::WinSalMenu()
158 WinSalMenu::~WinSalMenu()
160 // only required if not associated to a window...
161 GetSalData()->mhMenuSet
.erase( mhMenu
);
162 ::DestroyMenu( mhMenu
);
165 sal_Bool
WinSalMenu::VisibleMenuBar()
167 // The Win32 implementation never shows a native
168 // menubar. Thus, native menus are only visible
169 // when the menu is merged with an OLE container.
170 // The reason are missing tooltips, ownerdraw
171 // issues and accessibility which are better supported
173 // Nevertheless, the native menus are always created
174 // and the application will properly react to all native
180 void WinSalMenu::SetFrame( const SalFrame
*pFrame
)
183 mhWnd
= static_cast<const WinSalFrame
*>(pFrame
)->mhWnd
;
188 void WinSalMenu::InsertItem( SalMenuItem
* pSalMenuItem
, unsigned nPos
)
192 WinSalMenuItem
* pWItem
= static_cast<WinSalMenuItem
*>(pSalMenuItem
);
193 if( nPos
== MENU_APPEND
)
195 nPos
= ::GetMenuItemCount( mhMenu
);
196 if( nPos
== static_cast<unsigned>( -1 ) )
200 if(!::InsertMenuItemW( mhMenu
, nPos
, TRUE
, &pWItem
->mInfo
))
201 myerr
= GetLastError();
204 pWItem
->mpSalMenu
= this;
205 ImplDrawMenuBar( this );
210 void WinSalMenu::RemoveItem( unsigned nPos
)
212 int num
= ::GetMenuItemCount( mhMenu
);
213 if( num
!= -1 && nPos
< (unsigned)num
)
215 WinSalMenuItem
*pSalMenuItem
= NULL
;
218 memset( &mi
, 0, sizeof(mi
) );
219 mi
.cbSize
= sizeof( mi
);
220 mi
.fMask
= MIIM_DATA
;
221 if( !GetMenuItemInfoW( mhMenu
, nPos
, TRUE
, &mi
) )
222 myerr
= GetLastError();
224 pSalMenuItem
= (WinSalMenuItem
*) mi
.dwItemData
;
226 if( !::RemoveMenu( mhMenu
, nPos
, MF_BYPOSITION
) )
227 myerr
= GetLastError();
231 pSalMenuItem
->mpSalMenu
= NULL
;
232 ImplDrawMenuBar( this );
237 void ImplRemoveItemById( WinSalMenu
*pSalMenu
, unsigned nItemId
)
242 WinSalMenuItem
*pSalMenuItem
= NULL
;
245 memset( &mi
, 0, sizeof(mi
) );
246 mi
.cbSize
= sizeof( mi
);
247 mi
.fMask
= MIIM_DATA
;
248 if( !GetMenuItemInfoW( pSalMenu
->mhMenu
, nItemId
, FALSE
, &mi
) )
249 myerr
= GetLastError();
251 pSalMenuItem
= (WinSalMenuItem
*) mi
.dwItemData
;
253 if( !::RemoveMenu( pSalMenu
->mhMenu
, nItemId
, MF_BYCOMMAND
) )
254 myerr
= GetLastError();
258 pSalMenuItem
->mpSalMenu
= NULL
;
259 ImplDrawMenuBar( pSalMenu
);
263 void WinSalMenu::SetSubMenu( SalMenuItem
* pSalMenuItem
, SalMenu
* pSubMenu
, unsigned nPos
)
267 WinSalMenuItem
* pWMenuItem
= static_cast<WinSalMenuItem
*>(pSalMenuItem
);
268 WinSalMenu
* pWSubMenu
= static_cast<WinSalMenu
*>(pSubMenu
);
269 if( pWMenuItem
->mInfo
.hSubMenu
)
271 GetSalData()->mhMenuSet
.erase( pWMenuItem
->mInfo
.hSubMenu
);
272 ::DestroyMenu( pWMenuItem
->mInfo
.hSubMenu
);
275 pWMenuItem
->mInfo
.fMask
|= MIIM_SUBMENU
;
277 pWMenuItem
->mInfo
.hSubMenu
= NULL
;
280 pWMenuItem
->mInfo
.hSubMenu
= pWSubMenu
->mhMenu
;
281 pWSubMenu
->mpParentMenu
= this;
284 if(!::SetMenuItemInfoW( mhMenu
, nPos
, TRUE
, &pWMenuItem
->mInfo
) )
285 myerr
= GetLastError();
287 ImplDrawMenuBar( this );
291 void WinSalMenu::CheckItem( unsigned nPos
, sal_Bool bCheck
)
293 if( static_cast<unsigned>( -1 ) != ::CheckMenuItem( mhMenu
, nPos
, MF_BYPOSITION
|(bCheck
? MF_CHECKED
: MF_UNCHECKED
) ) )
294 ImplDrawMenuBar( this );
297 void WinSalMenu::EnableItem( unsigned nPos
, sal_Bool bEnable
)
299 if( -1 != ::EnableMenuItem( mhMenu
, nPos
, MF_BYPOSITION
|(bEnable
? MF_ENABLED
: (MF_DISABLED
|MF_GRAYED
) ) ) )
300 ImplDrawMenuBar( this );
303 void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem
* pSalMenuItem
, const Image
& rImage
)
307 WinSalMenuItem
* pWItem
= static_cast<WinSalMenuItem
*>(pSalMenuItem
);
309 pWItem
->maBitmap
= rImage
.GetBitmapEx().GetBitmap();
311 pWItem
->maBitmap
= Bitmap();
315 void WinSalMenu::SetItemText( unsigned nPos
, SalMenuItem
* pSalMenuItem
, const rtl::OUString
& rText
)
319 WinSalMenuItem
* pWItem
= static_cast<WinSalMenuItem
*>(pSalMenuItem
);
320 pWItem
->mText
= rText
;
321 // 'translate' mnemonics
322 pWItem
->mText
.SearchAndReplace( '~', '&' );
323 pWItem
->mInfo
.fMask
= MIIM_TYPE
| MIIM_DATA
;
324 pWItem
->mInfo
.fType
= MFT_STRING
;
326 if( pWItem
->mpMenu
&& !((Menu
*) pWItem
->mpMenu
)->IsMenuBar() )
327 pWItem
->mInfo
.fType
|= MFT_OWNERDRAW
;
330 // combine text and accelerator text
331 XubString
aStr( pWItem
->mText
);
332 if( pWItem
->mAccelText
.Len() )
334 aStr
.AppendAscii("\t");
335 aStr
.Append( pWItem
->mAccelText
);
337 pWItem
->mInfo
.dwTypeData
= (LPWSTR
) aStr
.GetBuffer();
338 pWItem
->mInfo
.cch
= aStr
.Len();
340 if(!::SetMenuItemInfoW( mhMenu
, nPos
, TRUE
, &pWItem
->mInfo
))
341 myerr
= GetLastError();
343 ImplDrawMenuBar( this );
347 void WinSalMenu::SetAccelerator( unsigned nPos
, SalMenuItem
* pSalMenuItem
, const KeyCode
&, const rtl::OUString
& rKeyName
)
351 WinSalMenuItem
* pWItem
= static_cast<WinSalMenuItem
*>(pSalMenuItem
);
352 pWItem
->mAccelText
= rKeyName
;
353 pWItem
->mInfo
.fMask
= MIIM_TYPE
| MIIM_DATA
;
354 pWItem
->mInfo
.fType
= MFT_STRING
;
356 if( pWItem
->mpMenu
&& !((Menu
*)pWItem
->mpMenu
)->IsMenuBar() )
357 pWItem
->mInfo
.fType
|= MFT_OWNERDRAW
;
359 // combine text and accelerator text
360 XubString
aStr( pWItem
->mText
);
361 if( pWItem
->mAccelText
.Len() )
363 aStr
.AppendAscii("\t");
364 aStr
.Append( pWItem
->mAccelText
);
366 pWItem
->mInfo
.dwTypeData
= (LPWSTR
) aStr
.GetBuffer();
367 pWItem
->mInfo
.cch
= aStr
.Len();
369 if(!::SetMenuItemInfoW( mhMenu
, nPos
, TRUE
, &pWItem
->mInfo
))
370 myerr
= GetLastError();
372 ImplDrawMenuBar( this );
376 void WinSalMenu::GetSystemMenuData( SystemMenuData
* pData
)
379 pData
->hMenu
= mhMenu
;
382 // =======================================================================
389 WinSalMenuItem::WinSalMenuItem()
391 memset( &mInfo
, 0, sizeof( MENUITEMINFOW
) );
397 WinSalMenuItem::~WinSalMenuItem()
400 ImplRemoveItemById( mpSalMenu
, mnId
);
403 // -------------------------------------------------------------------
405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */