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