summaryrefslogtreecommitdiffstats
path: root/vcl/win/window/salmenu.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vcl/win/window/salmenu.cxx355
1 files changed, 355 insertions, 0 deletions
diff --git a/vcl/win/window/salmenu.cxx b/vcl/win/window/salmenu.cxx
new file mode 100644
index 000000000..6f8dc8bff
--- /dev/null
+++ b/vcl/win/window/salmenu.cxx
@@ -0,0 +1,355 @@
+/* -*- 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 <svsys.h>
+
+#include <vcl/menu.hxx>
+#include <vcl/sysdata.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <o3tl/safeint.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+#include <win/salframe.h>
+#include <win/salmenu.h>
+
+#include <salgdi.hxx>
+
+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<SalMenu> 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<SalMenu>(pSalMenu);
+}
+
+std::unique_ptr<SalMenuItem> 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<sal_Unicode *>(pSalMenuItem->mText.getStr()));
+ pSalMenuItem->mInfo.cch = pSalMenuItem->mText.getLength();
+
+ pSalMenuItem->mInfo.wID = rItemData.nId;
+ pSalMenuItem->mInfo.dwItemData = reinterpret_cast<ULONG_PTR>(pSalMenuItem); // user data
+ }
+
+ return std::unique_ptr<SalMenuItem>(pSalMenuItem);
+}
+
+static void ImplDrawMenuBar( SalMenu *pMenu )
+{
+ if( pMenu->VisibleMenuBar() )
+ {
+ // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
+ /*
+ WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
+ if( pMenuBar && pMenuBar->mhWnd )
+ ::DrawMenuBar( pMenuBar->mhWnd );
+ */
+ }
+}
+
+/*
+ * 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<const WinSalFrame*>(pFrame)->mhWnd;
+ else
+ mhWnd = nullptr;
+}
+
+void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ if( nPos == MENU_APPEND )
+ {
+ nPos = ::GetMenuItemCount( mhMenu );
+ if( nPos == static_cast<unsigned>( -1 ) )
+ return;
+ }
+
+ if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ {
+ pWItem->mpSalMenu = this;
+ ImplDrawMenuBar( 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<WinSalMenuItem *>(mi.dwItemData);
+
+ if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) )
+ myerr = GetLastError();
+ else
+ {
+ if( pSalMenuItem )
+ pSalMenuItem->mpSalMenu = nullptr;
+ ImplDrawMenuBar( this );
+ }
+ }
+}
+
+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<WinSalMenuItem *>(mi.dwItemData);
+
+ if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) )
+ myerr = GetLastError();
+ else
+ {
+ if( pSalMenuItem )
+ pSalMenuItem->mpSalMenu = nullptr;
+ ImplDrawMenuBar( pSalMenu );
+ }
+}
+
+void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(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();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::CheckItem( unsigned nPos, bool bCheck )
+{
+ if( static_cast<unsigned>( -1 ) != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) )
+ ImplDrawMenuBar( this );
+}
+
+void WinSalMenu::EnableItem( unsigned nPos, bool bEnable )
+{
+ if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) )
+ ImplDrawMenuBar( this );
+}
+
+void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(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<WinSalMenuItem*>(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<sal_Unicode *>(aStr.getStr()));
+ pWItem->mInfo.cch = aStr.getLength();
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode&, const OUString& rKeyName )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(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<sal_Unicode *>(aStr.getStr()));
+ pWItem->mInfo.cch = aStr.getLength();
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+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: */