/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include static DWORD myerr=0; bool SalData::IsKnownMenuHandle( HMENU hMenu ) { if( mhMenuSet.find( hMenu ) == mhMenuSet.end() ) return false; else return true; } // WinSalInst factory methods std::unique_ptr WinSalInstance::CreateMenu( bool bMenuBar, Menu* ) { WinSalMenu *pSalMenu = new WinSalMenu(); pSalMenu->mbMenuBar = bMenuBar; pSalMenu->mhWnd = nullptr; if( bMenuBar ) pSalMenu->mhMenu = ::CreateMenu(); else pSalMenu->mhMenu = ::CreatePopupMenu(); if( pSalMenu->mhMenu ) GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu ); return std::unique_ptr(pSalMenu); } std::unique_ptr WinSalInstance::CreateMenuItem( const SalItemParams & rItemData ) { WinSalMenuItem *pSalMenuItem = new WinSalMenuItem(); memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) ); pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW ); if( rItemData.eType == MenuItemType::SEPARATOR ) { // separator pSalMenuItem->mInfo.fMask = MIIM_TYPE; pSalMenuItem->mInfo.fType = MFT_SEPARATOR; } else { // item pSalMenuItem->mText = rItemData.aText; pSalMenuItem->mpMenu = rItemData.pMenu; pSalMenuItem->maBitmap= !!rItemData.aImage ? rItemData.aImage.GetBitmapEx().GetBitmap() : Bitmap(); pSalMenuItem->mnId = rItemData.nId; // 'translate' mnemonics pSalMenuItem->mText = pSalMenuItem->mText.replaceAll( "~", "&" ); pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA; pSalMenuItem->mInfo.fType = MFT_STRING; pSalMenuItem->mInfo.dwTypeData = o3tl::toW(const_cast(pSalMenuItem->mText.getStr())); pSalMenuItem->mInfo.cch = pSalMenuItem->mText.getLength(); pSalMenuItem->mInfo.wID = rItemData.nId; pSalMenuItem->mInfo.dwItemData = reinterpret_cast(pSalMenuItem); // user data } return std::unique_ptr(pSalMenuItem); } /* * WinSalMenu */ WinSalMenu::WinSalMenu() { mhMenu = nullptr; mbMenuBar = false; mhWnd = nullptr; mpParentMenu = nullptr; } WinSalMenu::~WinSalMenu() { // only required if not associated to a window... GetSalData()->mhMenuSet.erase( mhMenu ); ::DestroyMenu( mhMenu ); } bool WinSalMenu::VisibleMenuBar() { // The Win32 implementation never shows a native // menubar. Thus, native menus are only visible // when the menu is merged with an OLE container. // The reason are missing tooltips, ownerdraw // issues and accessibility which are better supported // by VCL menus. // Nevertheless, the native menus are always created // and the application will properly react to all native // menu messages. return false; } void WinSalMenu::SetFrame( const SalFrame *pFrame ) { if( pFrame ) mhWnd = static_cast(pFrame)->mhWnd; else mhWnd = nullptr; } void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ) { if( pSalMenuItem ) { WinSalMenuItem* pWItem = static_cast(pSalMenuItem); if( nPos == MENU_APPEND ) { nPos = ::GetMenuItemCount( mhMenu ); if( nPos == static_cast( -1 ) ) return; } if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo )) myerr = GetLastError(); else pWItem->mpSalMenu = this; } } void WinSalMenu::RemoveItem( unsigned nPos ) { int num = ::GetMenuItemCount( mhMenu ); if( num != -1 && nPos < o3tl::make_unsigned(num) ) { WinSalMenuItem *pSalMenuItem = nullptr; MENUITEMINFOW mi = {}; mi.cbSize = sizeof( mi ); mi.fMask = MIIM_DATA; if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) ) myerr = GetLastError(); else pSalMenuItem = reinterpret_cast(mi.dwItemData); if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) ) myerr = GetLastError(); else { if( pSalMenuItem ) pSalMenuItem->mpSalMenu = nullptr; } } } static void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId ) { if( !pSalMenu ) return; WinSalMenuItem *pSalMenuItem = nullptr; MENUITEMINFOW mi = {}; mi.cbSize = sizeof( mi ); mi.fMask = MIIM_DATA; if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) ) myerr = GetLastError(); else pSalMenuItem = reinterpret_cast(mi.dwItemData); if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) ) myerr = GetLastError(); else { if( pSalMenuItem ) pSalMenuItem->mpSalMenu = nullptr; } } void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ) { if( pSalMenuItem ) { WinSalMenuItem* pWMenuItem = static_cast(pSalMenuItem); WinSalMenu* pWSubMenu = static_cast(pSubMenu); if( pWMenuItem->mInfo.hSubMenu ) { GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu ); ::DestroyMenu( pWMenuItem->mInfo.hSubMenu ); } pWMenuItem->mInfo.fMask |= MIIM_SUBMENU; if( !pSubMenu ) pWMenuItem->mInfo.hSubMenu = nullptr; else { pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu; pWSubMenu->mpParentMenu = this; } if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) ) myerr = GetLastError(); } } void WinSalMenu::CheckItem( unsigned nPos, bool bCheck ) { ::CheckMenuItem(mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED)); } void WinSalMenu::EnableItem( unsigned nPos, bool bEnable ) { ::EnableMenuItem(mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED))); } void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage ) { if( pSalMenuItem ) { WinSalMenuItem* pWItem = static_cast(pSalMenuItem); if( !!rImage ) pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap(); else pWItem->maBitmap = Bitmap(); } } void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText ) { if( pSalMenuItem ) { WinSalMenuItem* pWItem = static_cast(pSalMenuItem); pWItem->mText = rText; // 'translate' mnemonics pWItem->mText = pWItem->mText.replaceAll( "~", "&" ); pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA; pWItem->mInfo.fType = MFT_STRING; // combine text and accelerator text OUString aStr( pWItem->mText ); if( pWItem->mAccelText.getLength() ) { aStr += "\t" + pWItem->mAccelText; } pWItem->mInfo.dwTypeData = o3tl::toW(const_cast(aStr.getStr())); pWItem->mInfo.cch = aStr.getLength(); if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo )) myerr = GetLastError(); } } void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode&, const OUString& rKeyName ) { if( pSalMenuItem ) { WinSalMenuItem* pWItem = static_cast(pSalMenuItem); pWItem->mAccelText = rKeyName; pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA; pWItem->mInfo.fType = MFT_STRING; // combine text and accelerator text OUString aStr( pWItem->mText ); if( pWItem->mAccelText.getLength() ) { aStr += "\t" + pWItem->mAccelText; } pWItem->mInfo.dwTypeData = o3tl::toW(const_cast(aStr.getStr())); pWItem->mInfo.cch = aStr.getLength(); if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo )) myerr = GetLastError(); } } void WinSalMenu::GetSystemMenuData( SystemMenuData* pData ) { if( pData ) pData->hMenu = mhMenu; } /* * SalMenuItem */ WinSalMenuItem::WinSalMenuItem() { memset( &mInfo, 0, sizeof( MENUITEMINFOW ) ); mpMenu = nullptr; mnId = 0xFFFF; mpSalMenu = nullptr; } WinSalMenuItem::~WinSalMenuItem() { if( mpSalMenu ) ImplRemoveItemById( mpSalMenu, mnId ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */