xref: /aoo41x/main/vcl/win/source/window/salmenu.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <tools/svwin.h>
32 
33 #include <vcl/menu.hxx>
34 #include <vcl/sysdata.hxx>
35 
36 #include <win/wincomp.hxx>
37 #include <win/saldata.hxx>
38 #include <win/salinst.h>
39 #include <win/salframe.h>
40 #include <win/salmenu.h>
41 
42 #include <impbmp.hxx>
43 #include <salgdi.hxx>
44 
45 // uncomment the following line to have ownerdrawn menues, ie, with bitmaps
46 // however, this is incompatible with OLE inplace editing
47 // so it is not activated by default
48 //#define OWNERDRAW
49 
50 static DWORD myerr=0;
51 
52 // =======================================================================
53 
54 sal_Bool SalData::IsKnownMenuHandle( HMENU hMenu )
55 {
56     if( mhMenuSet.find( hMenu ) == mhMenuSet.end() )
57         return FALSE;
58     else
59         return TRUE;
60 }
61 
62 // =======================================================================
63 
64 // WinSalInst factory methods
65 
66 SalMenu* WinSalInstance::CreateMenu( sal_Bool bMenuBar, Menu* )
67 {
68     WinSalMenu *pSalMenu = new WinSalMenu();
69 
70     pSalMenu->mbMenuBar = bMenuBar;
71     pSalMenu->mhWnd     = NULL;
72     if( bMenuBar )
73         pSalMenu->mhMenu = ::CreateMenu();
74     else
75         pSalMenu->mhMenu = ::CreatePopupMenu();
76 
77     if( pSalMenu->mhMenu )
78         GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu );
79 
80     return pSalMenu;
81 }
82 
83 void WinSalInstance::DestroyMenu( SalMenu* pSalMenu )
84 {
85     delete pSalMenu;
86 }
87 
88 
89 SalMenuItem* WinSalInstance::CreateMenuItem( const SalItemParams* pItemData )
90 {
91     if( !pItemData )
92         return NULL;
93 
94     WinSalMenuItem *pSalMenuItem = new WinSalMenuItem();
95     memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) );
96     pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW );
97 
98     if( pItemData->eType == MENUITEM_SEPARATOR )
99     {
100         // separator
101         pSalMenuItem->mInfo.fMask = MIIM_TYPE;
102         pSalMenuItem->mInfo.fType = MFT_SEPARATOR;
103     }
104     else
105     {
106         // item
107         pSalMenuItem->mText   = pItemData->aText;
108         pSalMenuItem->mpMenu  = pItemData->pMenu;
109         pSalMenuItem->maBitmap= !!pItemData->aImage ? pItemData->aImage.GetBitmapEx().GetBitmap() : Bitmap();
110         pSalMenuItem->mnId    = pItemData->nId;
111 
112         // 'translate' mnemonics
113         pSalMenuItem->mText.SearchAndReplace( '~', '&' );
114 
115         pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
116         pSalMenuItem->mInfo.fType = MFT_STRING;
117 #ifdef OWNERDRAW
118         if( pItemData->pMenu && !pItemData->pMenu->IsMenuBar() )
119             pSalMenuItem->mInfo.fType |= MFT_OWNERDRAW;
120         pSalMenuItem->mInfo.fState = MFS_ENABLED;
121 #endif
122         pSalMenuItem->mInfo.dwTypeData = (LPWSTR) pSalMenuItem->mText.GetBuffer();
123         pSalMenuItem->mInfo.cch = pSalMenuItem->mText.Len();
124 
125         pSalMenuItem->mInfo.wID = pItemData->nId;
126         pSalMenuItem->mInfo.dwItemData = (ULONG_PTR) pSalMenuItem; // user data
127     }
128 
129     return pSalMenuItem;
130 }
131 
132 void WinSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
133 {
134     delete pSalMenuItem;
135 }
136 
137 
138 // =======================================================================
139 
140 static void ImplDrawMenuBar( SalMenu *pMenu )
141 {
142     if( pMenu->VisibleMenuBar() )
143     {
144         // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
145         /*
146         WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
147         if( pMenuBar && pMenuBar->mhWnd )
148             ::DrawMenuBar( pMenuBar->mhWnd );
149             */
150     }
151 }
152 
153 // =======================================================================
154 
155 
156 /*
157  * WinSalMenu
158  */
159 
160 WinSalMenu::WinSalMenu()
161 {
162     mhMenu       = NULL;
163     mbMenuBar    = FALSE;
164     mhWnd        = NULL;
165     mpParentMenu = NULL;
166 }
167 
168 WinSalMenu::~WinSalMenu()
169 {
170     // only required if not associated to a window...
171     GetSalData()->mhMenuSet.erase( mhMenu );
172     ::DestroyMenu( mhMenu );
173 }
174 
175 sal_Bool WinSalMenu::VisibleMenuBar()
176 {
177     // The Win32 implementation never shows a native
178     // menubar. Thus, native menues are only visible
179     // when the menu is merged with an OLE container.
180     // The reason are missing tooltips, ownerdraw
181     // issues and accessibility which are better supported
182     // by VCL menues.
183     // Nevertheless, the native menues are always created
184     // and the application will properly react to all native
185     // menu messages.
186 
187     return FALSE;
188 }
189 
190 void WinSalMenu::SetFrame( const SalFrame *pFrame )
191 {
192     if( pFrame )
193         mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd;
194     else
195         mhWnd = NULL;
196 }
197 
198 void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
199 {
200     if( pSalMenuItem )
201     {
202 	WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
203         if( nPos == MENU_APPEND )
204         {
205             nPos = ::GetMenuItemCount( mhMenu );
206             if( nPos == -1 )
207                 return;
208         }
209 
210         if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
211             myerr = GetLastError();
212         else
213         {
214             pWItem->mpSalMenu = this;
215             ImplDrawMenuBar( this );
216         }
217     }
218 }
219 
220 void WinSalMenu::RemoveItem( unsigned nPos )
221 {
222     int num = ::GetMenuItemCount( mhMenu );
223     if( num != -1 && nPos < (unsigned)num )
224     {
225         WinSalMenuItem *pSalMenuItem = NULL;
226 
227         MENUITEMINFOW mi;
228         memset( &mi, 0, sizeof(mi) );
229         mi.cbSize = sizeof( mi );
230         mi.fMask = MIIM_DATA;
231         if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) )
232             myerr = GetLastError();
233         else
234             pSalMenuItem = (WinSalMenuItem *) mi.dwItemData;
235 
236         if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) )
237             myerr = GetLastError();
238         else
239         {
240             if( pSalMenuItem )
241                 pSalMenuItem->mpSalMenu = NULL;
242             ImplDrawMenuBar( this );
243         }
244     }
245 }
246 
247 void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId )
248 {
249     if( !pSalMenu )
250         return;
251 
252     WinSalMenuItem *pSalMenuItem = NULL;
253 
254     MENUITEMINFOW mi;
255     memset( &mi, 0, sizeof(mi) );
256     mi.cbSize = sizeof( mi );
257     mi.fMask = MIIM_DATA;
258     if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) )
259         myerr = GetLastError();
260     else
261         pSalMenuItem = (WinSalMenuItem *) mi.dwItemData;
262 
263     if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) )
264         myerr = GetLastError();
265     else
266     {
267         if( pSalMenuItem )
268             pSalMenuItem->mpSalMenu = NULL;
269         ImplDrawMenuBar( pSalMenu );
270     }
271 }
272 
273 void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
274 {
275     if( pSalMenuItem )
276     {
277 	    WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
278 	    WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu);
279         if( pWMenuItem->mInfo.hSubMenu )
280         {
281             GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu );
282             ::DestroyMenu( pWMenuItem->mInfo.hSubMenu );
283         }
284 
285         pWMenuItem->mInfo.fMask |= MIIM_SUBMENU;
286         if( !pSubMenu )
287             pWMenuItem->mInfo.hSubMenu = NULL;
288         else
289         {
290             pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu;
291             pWSubMenu->mpParentMenu = this;
292         }
293 
294         if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) )
295             myerr = GetLastError();
296         else
297             ImplDrawMenuBar( this );
298     }
299 }
300 
301 void WinSalMenu::CheckItem( unsigned nPos, sal_Bool bCheck )
302 {
303     if( -1 != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) )
304         ImplDrawMenuBar( this );
305 }
306 
307 void WinSalMenu::EnableItem( unsigned nPos, sal_Bool bEnable )
308 {
309     if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) )
310         ImplDrawMenuBar( this );
311 }
312 
313 void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage )
314 {
315     if( pSalMenuItem )
316     {
317 	WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
318         if( !!rImage )
319             pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap();
320         else
321             pWItem->maBitmap = Bitmap();
322     }
323 }
324 
325 void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText )
326 {
327     if( pSalMenuItem )
328     {
329 	WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
330         pWItem->mText = rText;
331         // 'translate' mnemonics
332         pWItem->mText.SearchAndReplace( '~', '&' );
333         pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
334         pWItem->mInfo.fType = MFT_STRING;
335 #ifdef OWNERDRAW
336         if( pWItem->mpMenu && !((Menu*) pWItem->mpMenu)->IsMenuBar() )
337             pWItem->mInfo.fType |= MFT_OWNERDRAW;
338 #endif
339 
340         // combine text and accelerator text
341         XubString aStr( pWItem->mText );
342         if( pWItem->mAccelText.Len() )
343         {
344             aStr.AppendAscii("\t");
345             aStr.Append( pWItem->mAccelText );
346         }
347         pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer();
348         pWItem->mInfo.cch = aStr.Len();
349 
350         if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
351             myerr = GetLastError();
352         else
353             ImplDrawMenuBar( this );
354     }
355 }
356 
357 void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode&, const XubString& rKeyName )
358 {
359     if( pSalMenuItem )
360     {
361 	WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
362         pWItem->mAccelText = rKeyName;
363         pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
364         pWItem->mInfo.fType = MFT_STRING;
365 #ifdef OWNERDRAW
366         if( pWItem->mpMenu && !((Menu*)pWItem->mpMenu)->IsMenuBar() )
367             pWItem->mInfo.fType |= MFT_OWNERDRAW;
368 #endif
369         // combine text and accelerator text
370         XubString aStr( pWItem->mText );
371         if( pWItem->mAccelText.Len() )
372         {
373             aStr.AppendAscii("\t");
374             aStr.Append( pWItem->mAccelText );
375         }
376         pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer();
377         pWItem->mInfo.cch = aStr.Len();
378 
379         if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
380             myerr = GetLastError();
381         else
382             ImplDrawMenuBar( this );
383     }
384 }
385 
386 void WinSalMenu::GetSystemMenuData( SystemMenuData* pData )
387 {
388     if( pData )
389         pData->hMenu = mhMenu;
390 }
391 
392 // =======================================================================
393 
394 /*
395  * SalMenuItem
396  */
397 
398 
399 WinSalMenuItem::WinSalMenuItem()
400 {
401     memset( &mInfo, 0, sizeof( MENUITEMINFOW ) );
402     mpMenu = NULL;
403     mnId  = 0xFFFF;
404     mpSalMenu = NULL;
405 }
406 
407 WinSalMenuItem::~WinSalMenuItem()
408 {
409     if( mpSalMenu )
410         ImplRemoveItemById( mpSalMenu, mnId );
411 }
412 
413 // -------------------------------------------------------------------
414 
415