From a4c7e833915215b4e2020e8a3a8f1192ac8eff17 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Sun, 16 Jun 2013 19:54:22 +0300 Subject: [PATCH] Move context menu related code into ContextMenu.cpp --- Library/ContextMenu.cpp | 646 ++++++++++++++++++++++++++++++++ Library/ContextMenu.h | 50 +++ Library/DialogManage.cpp | 2 +- Library/Library.vcxproj | 4 + Library/Library.vcxproj.filters | 6 + Library/Rainmeter.cpp | 607 ------------------------------ Library/Rainmeter.h | 17 +- 7 files changed, 712 insertions(+), 620 deletions(-) create mode 100644 Library/ContextMenu.cpp create mode 100644 Library/ContextMenu.h diff --git a/Library/ContextMenu.cpp b/Library/ContextMenu.cpp new file mode 100644 index 00000000..0884baec --- /dev/null +++ b/Library/ContextMenu.cpp @@ -0,0 +1,646 @@ +/* + Copyright (C) 2013 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "StdAfx.h" +#include "../Common/MenuTemplate.h" +#include "ContextMenu.h" +#include "Rainmeter.h" +#include "Litestep.h" +#include "MeterWindow.h" +#include "System.h" +#include "TrayWindow.h" +#include "resource.h" + +ContextMenu::ContextMenu() : + m_MenuActive(false) +{ +} + +/* +** Opens the context menu in given coordinates. +*/ +void ContextMenu::ShowMenu(POINT pos, MeterWindow* meterWindow) +{ + static const MenuTemplate s_Menu[] = + { + MENU_ITEM(IDM_MANAGE, ID_STR_MANAGE), + MENU_ITEM(IDM_ABOUT, ID_STR_ABOUT), + MENU_ITEM(IDM_SHOW_HELP, ID_STR_HELP), + MENU_SEPARATOR(), + MENU_SUBMENU(ID_STR_SKINS, + MENU_ITEM_GRAYED(0, ID_STR_NOSKINS), + MENU_SEPARATOR(), + MENU_ITEM(IDM_OPENSKINSFOLDER, ID_STR_OPENFOLDER), + MENU_ITEM(IDM_DISABLEDRAG, ID_STR_DISABLEDRAGGING)), + MENU_SUBMENU(ID_STR_THEMES, + MENU_ITEM_GRAYED(0, ID_STR_NOTHEMES)), + MENU_SEPARATOR(), + MENU_ITEM(IDM_EDITCONFIG, ID_STR_EDITSETTINGS), + MENU_ITEM(IDM_REFRESH, ID_STR_REFRESHALL), + MENU_SEPARATOR(), + MENU_SUBMENU(ID_STR_LOGGING, + MENU_ITEM(IDM_SHOWLOGFILE, ID_STR_SHOWLOGFILE), + MENU_SEPARATOR(), + MENU_ITEM(IDM_STARTLOG, ID_STR_STARTLOGGING), + MENU_ITEM(IDM_STOPLOG, ID_STR_STOPLOGGING), + MENU_SEPARATOR(), + MENU_ITEM(IDM_DELETELOGFILE, ID_STR_DELETELOGFILE), + MENU_ITEM(IDM_DEBUGLOG, ID_STR_DEBUGMODE)), + MENU_SEPARATOR(), + MENU_ITEM(IDM_QUIT, ID_STR_EXIT) + }; + + if (m_MenuActive || (meterWindow && meterWindow->IsClosing())) + { + return; + } + + Rainmeter& rainmeter = GetRainmeter(); + + m_MenuActive = true; + + // Show context menu, if no actions were executed + HMENU menu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); + if (menu) + { + SetMenuDefaultItem(menu, IDM_MANAGE, MF_BYCOMMAND); + + if (_waccess(GetLogger().GetLogFilePath().c_str(), 0) == -1) + { + EnableMenuItem(menu, IDM_SHOWLOGFILE, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(menu, IDM_DELETELOGFILE, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(menu, IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED); + } + else + { + EnableMenuItem( + menu, + (GetLogger().IsLogToFile()) ? IDM_STARTLOG : IDM_STOPLOG, + MF_BYCOMMAND | MF_GRAYED); + } + + if (rainmeter.m_Debug) + { + CheckMenuItem(menu, IDM_DEBUGLOG, MF_BYCOMMAND | MF_CHECKED); + } + + HMENU allSkinsMenu = GetSubMenu(menu, 4); + if (allSkinsMenu) + { + if (!rainmeter.m_SkinRegistry.IsEmpty()) + { + DeleteMenu(allSkinsMenu, 0, MF_BYPOSITION); // "No skins available" menuitem + CreateAllSkinsMenu(allSkinsMenu); + } + + if (rainmeter.m_DisableDragging) + { + CheckMenuItem(allSkinsMenu, IDM_DISABLEDRAG, MF_BYCOMMAND | MF_CHECKED); + } + } + + HMENU layoutMenu = GetSubMenu(menu, 5); + if (layoutMenu) + { + if (!rainmeter.m_Layouts.empty()) + { + DeleteMenu(layoutMenu, 0, MF_BYPOSITION); // "No layouts available" menuitem + CreateLayoutMenu(layoutMenu); + } + } + + if (meterWindow) + { + HMENU rainmeterMenu = menu; + menu = CreateSkinMenu(meterWindow, 0, allSkinsMenu); + + InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_POPUP, (UINT_PTR)rainmeterMenu, L"Rainmeter"); + InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_SEPARATOR, 0, nullptr); + } + else + { + InsertMenu(menu, 12, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); + + // Create a menu for all active skins + int index = 0; + std::map::const_iterator iter = rainmeter.m_MeterWindows.begin(); + for (; iter != rainmeter.m_MeterWindows.end(); ++iter) + { + MeterWindow* mw = ((*iter).second); + HMENU skinMenu = CreateSkinMenu(mw, index, allSkinsMenu); + InsertMenu(menu, 12, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinMenu, mw->GetFolderPath().c_str()); + ++index; + } + + // Add update notification item + if (rainmeter.m_NewVersion) + { + InsertMenu(menu, 0, MF_BYPOSITION, IDM_NEW_VERSION, GetString(ID_STR_UPDATEAVAILABLE)); + HiliteMenuItem(rainmeter.GetTrayWindow()->GetWindow(), menu, 0, MF_BYPOSITION | MF_HILITE); + InsertMenu(menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); + } + } + + HWND hWnd = WindowFromPoint(pos); + if (hWnd != nullptr) + { + MeterWindow* mw = rainmeter.GetMeterWindow(hWnd); + if (mw) + { + // Cancel the mouse event beforehand + mw->SetMouseLeaveEvent(true); + } + } + + // Set the window to foreground + hWnd = meterWindow ? meterWindow->GetWindow() : rainmeter.m_TrayWindow->GetWindow(); + HWND hWndForeground = GetForegroundWindow(); + if (hWndForeground != hWnd) + { + DWORD foregroundThreadID = GetWindowThreadProcessId(hWndForeground, nullptr); + DWORD currentThreadID = GetCurrentThreadId(); + AttachThreadInput(currentThreadID, foregroundThreadID, TRUE); + SetForegroundWindow(hWnd); + AttachThreadInput(currentThreadID, foregroundThreadID, FALSE); + } + + // Show context menu + TrackPopupMenu( + menu, + TPM_RIGHTBUTTON | TPM_LEFTALIGN | (*GetString(ID_STR_ISRTL) == L'1' ? TPM_LAYOUTRTL : 0), + pos.x, + pos.y, + 0, + hWnd, + nullptr); + + if (meterWindow) + { + DestroyMenu(menu); + } + } + + DestroyMenu(menu); + + m_MenuActive = false; +} + +HMENU ContextMenu::CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu) +{ + static const MenuTemplate s_Menu[] = + { + MENU_ITEM(IDM_SKIN_OPENSKINSFOLDER, 0), + MENU_SEPARATOR(), + MENU_SUBMENU(ID_STR_VARIANTS, + MENU_SEPARATOR()), + MENU_SEPARATOR(), + MENU_SUBMENU(ID_STR_SETTINGS, + MENU_SUBMENU(ID_STR_POSITION, + MENU_SUBMENU(ID_STR_DISPLAYMONITOR, + MENU_ITEM(IDM_SKIN_MONITOR_PRIMARY, ID_STR_USEDEFAULTMONITOR), + MENU_ITEM(ID_MONITOR_FIRST, ID_STR_VIRTUALSCREEN), + MENU_SEPARATOR(), + MENU_SEPARATOR(), + MENU_ITEM(IDM_SKIN_MONITOR_AUTOSELECT, ID_STR_AUTOSELECTMONITOR)), + MENU_SEPARATOR(), + MENU_ITEM(IDM_SKIN_VERYTOPMOST, ID_STR_STAYTOPMOST), + MENU_ITEM(IDM_SKIN_TOPMOST, ID_STR_TOPMOST), + MENU_ITEM(IDM_SKIN_NORMAL, ID_STR_NORMAL), + MENU_ITEM(IDM_SKIN_BOTTOM, ID_STR_BOTTOM), + MENU_ITEM(IDM_SKIN_ONDESKTOP, ID_STR_ONDESKTOP), + MENU_SEPARATOR(), + MENU_ITEM(IDM_SKIN_FROMRIGHT, ID_STR_FROMRIGHT), + MENU_ITEM(IDM_SKIN_FROMBOTTOM, ID_STR_FROMBOTTOM), + MENU_ITEM(IDM_SKIN_XPERCENTAGE, ID_STR_XASPERCENTAGE), + MENU_ITEM(IDM_SKIN_YPERCENTAGE, ID_STR_YASPERCENTAGE)), + MENU_SUBMENU(ID_STR_TRANSPARENCY, + MENU_ITEM(IDM_SKIN_TRANSPARENCY_0, ID_STR_0PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_10, ID_STR_10PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_20, ID_STR_20PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_30, ID_STR_30PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_40, ID_STR_40PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_50, ID_STR_50PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_60, ID_STR_60PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_70, ID_STR_70PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_80, ID_STR_80PERCENT), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_90, ID_STR_90PERCENT), + MENU_SEPARATOR(), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEIN, ID_STR_FADEIN), + MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEOUT, ID_STR_FADEOUT)), + MENU_SEPARATOR(), + MENU_ITEM(IDM_SKIN_HIDEONMOUSE, ID_STR_HIDEONMOUSEOVER), + MENU_ITEM(IDM_SKIN_DRAGGABLE, ID_STR_DRAGGABLE), + MENU_ITEM(IDM_SKIN_REMEMBERPOSITION, ID_STR_SAVEPOSITION), + MENU_ITEM(IDM_SKIN_SNAPTOEDGES, ID_STR_SNAPTOEDGES), + MENU_ITEM(IDM_SKIN_CLICKTHROUGH, ID_STR_CLICKTHROUGH), + MENU_ITEM(IDM_SKIN_KEEPONSCREEN, ID_STR_KEEPONSCREEN)), + MENU_SEPARATOR(), + MENU_ITEM(IDM_SKIN_MANAGESKIN, ID_STR_MANAGESKIN), + MENU_ITEM(IDM_SKIN_EDITSKIN, ID_STR_EDITSKIN), + MENU_ITEM(IDM_SKIN_REFRESH, ID_STR_REFRESHSKIN), + MENU_SEPARATOR(), + MENU_ITEM(IDM_CLOSESKIN, ID_STR_UNLOADSKIN) + }; + + HMENU skinMenu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); + if (skinMenu) + { + // Tick the position + HMENU settingsMenu = GetSubMenu(skinMenu, 4); + if (settingsMenu) + { + HMENU posMenu = GetSubMenu(settingsMenu, 0); + if (posMenu) + { + UINT checkPos = IDM_SKIN_NORMAL - (UINT)meterWindow->GetWindowZPosition(); + CheckMenuRadioItem(posMenu, checkPos, checkPos, checkPos, MF_BYCOMMAND); + + if (meterWindow->GetXFromRight()) CheckMenuItem(posMenu, IDM_SKIN_FROMRIGHT, MF_BYCOMMAND | MF_CHECKED); + if (meterWindow->GetYFromBottom()) CheckMenuItem(posMenu, IDM_SKIN_FROMBOTTOM, MF_BYCOMMAND | MF_CHECKED); + if (meterWindow->GetXPercentage()) CheckMenuItem(posMenu, IDM_SKIN_XPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); + if (meterWindow->GetYPercentage()) CheckMenuItem(posMenu, IDM_SKIN_YPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); + + HMENU monitorMenu = GetSubMenu(posMenu, 0); + if (monitorMenu) + { + CreateMonitorMenu(monitorMenu, meterWindow); + } + } + + // Tick the transparency + HMENU alphaMenu = GetSubMenu(settingsMenu, 1); + if (alphaMenu) + { + UINT checkPos = (UINT)(10 - meterWindow->GetAlphaValue() / 25.5); + checkPos = min(9, checkPos); + checkPos = max(0, checkPos); + CheckMenuRadioItem(alphaMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); + + switch (meterWindow->GetWindowHide()) + { + case HIDEMODE_FADEIN: + CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_CHECKED); + EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); + break; + + case HIDEMODE_FADEOUT: + CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_CHECKED); + EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); + break; + + case HIDEMODE_HIDE: + EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); + break; + } + } + + // Tick the settings + switch (meterWindow->GetWindowHide()) + { + case HIDEMODE_HIDE: + CheckMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_CHECKED); + break; + + case HIDEMODE_FADEIN: + case HIDEMODE_FADEOUT: + EnableMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_GRAYED); + break; + } + + if (meterWindow->GetSnapEdges()) + { + CheckMenuItem(settingsMenu, IDM_SKIN_SNAPTOEDGES, MF_BYCOMMAND | MF_CHECKED); + } + + if (meterWindow->GetSavePosition()) + { + CheckMenuItem(settingsMenu, IDM_SKIN_REMEMBERPOSITION, MF_BYCOMMAND | MF_CHECKED); + } + + if (GetRainmeter().m_DisableDragging) + { + EnableMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_GRAYED); + } + else if (meterWindow->GetWindowDraggable()) + { + CheckMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_CHECKED); + } + + if (meterWindow->GetClickThrough()) + { + CheckMenuItem(settingsMenu, IDM_SKIN_CLICKTHROUGH, MF_BYCOMMAND | MF_CHECKED); + } + + if (meterWindow->GetKeepOnScreen()) + { + CheckMenuItem(settingsMenu, IDM_SKIN_KEEPONSCREEN, MF_BYCOMMAND | MF_CHECKED); + } + } + + // Add the name of the Skin to the menu + const std::wstring& skinName = meterWindow->GetFolderPath(); + ModifyMenu(skinMenu, IDM_SKIN_OPENSKINSFOLDER, MF_BYCOMMAND, IDM_SKIN_OPENSKINSFOLDER, skinName.c_str()); + SetMenuDefaultItem(skinMenu, IDM_SKIN_OPENSKINSFOLDER, FALSE); + + // Remove dummy menuitem from the variants menu + HMENU variantsMenu = GetSubMenu(skinMenu, 2); + if (variantsMenu) + { + DeleteMenu(variantsMenu, 0, MF_BYPOSITION); + } + + // Give the menuitem the unique id that depends on the skin + ChangeSkinIndex(skinMenu, index); + + // Add the variants menu + if (variantsMenu) + { + const SkinRegistry::Folder& skinFolder = *GetRainmeter().m_SkinRegistry.FindFolder(skinName); + for (int i = 0, isize = (int)skinFolder.files.size(); i < isize; ++i) + { + InsertMenu(variantsMenu, i, MF_BYPOSITION, skinFolder.baseID + i, skinFolder.files[i].c_str()); + } + + if (skinFolder.active) + { + UINT checkPos = skinFolder.active - 1; + CheckMenuRadioItem(variantsMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); + } + } + + // Add skin root menu + int itemCount = GetMenuItemCount(menu); + if (itemCount > 0) + { + std::wstring root = meterWindow->GetFolderPath(); + std::wstring::size_type pos = root.find_first_of(L'\\'); + if (pos != std::wstring::npos) + { + root.erase(pos); + } + + for (int i = 0; i < itemCount; ++i) + { + UINT state = GetMenuState(menu, i, MF_BYPOSITION); + if (state == 0xFFFFFFFF || (state & MF_POPUP) == 0) break; + + WCHAR buffer[MAX_PATH]; + if (GetMenuString(menu, i, buffer, MAX_PATH, MF_BYPOSITION)) + { + if (_wcsicmp(root.c_str(), buffer) == 0) + { + HMENU skinRootMenu = GetSubMenu(menu, i); + if (skinRootMenu) + { + InsertMenu(skinMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinRootMenu, root.c_str()); + } + break; + } + } + } + } + + // Add custom actions to the context menu + std::wstring contextTitle = meterWindow->GetParser().ReadString(L"Rainmeter", L"ContextTitle", L""); + if (!contextTitle.empty()) + { + auto isTitleSeparator = [](const std::wstring& title) + { + return title.find_first_not_of(L'-') == std::wstring::npos; + }; + + std::wstring contextAction = meterWindow->GetParser().ReadString(L"Rainmeter", L"ContextAction", L""); + if (!contextAction.empty() || isTitleSeparator(contextTitle)) + { + std::vector cTitles; + WCHAR buffer[128]; + int i = 1; + + while (!contextTitle.empty() && + (!contextAction.empty() || isTitleSeparator(contextTitle)) && + (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i - 1) <= IDM_SKIN_CUSTOMCONTEXTMENU_LAST) // Set maximum context items in resource.h + { + // Trim long titles + if (contextTitle.size() > 30) + { + contextTitle.replace(27, contextTitle.size() - 27, L"..."); + } + + cTitles.push_back(contextTitle); + + _snwprintf_s(buffer, _TRUNCATE, L"ContextTitle%i", ++i); + contextTitle = meterWindow->GetParser().ReadString(L"Rainmeter", buffer, L""); + _snwprintf_s(buffer, _TRUNCATE, L"ContextAction%i", i); + contextAction = meterWindow->GetParser().ReadString(L"Rainmeter", buffer, L""); + } + + // Build a sub-menu if more than three items + size_t titleSize = cTitles.size(); + if (titleSize <= 3) + { + size_t position = 0; + for (size_t i = 0; i < titleSize; ++i) + { + if (isTitleSeparator(cTitles[i])) + { + // Separators not allowed in main top-level menu + --position; + } + else + { + InsertMenu(skinMenu, position + 1, MF_BYPOSITION | MF_STRING, (index << 16) | (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i), cTitles[i].c_str()); + } + + ++position; + } + + if (position != 0) + { + InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, L"Custom skin actions"); + InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); + } + } + else + { + HMENU customMenu = CreatePopupMenu(); + InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)customMenu, L"Custom skin actions"); + + for (size_t i = 0; i < titleSize; ++i) + { + if (isTitleSeparator(cTitles[i])) + { + AppendMenu(customMenu, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); + } + else + { + AppendMenu(customMenu, MF_BYPOSITION | MF_STRING, (index << 16) | (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i), cTitles[i].c_str()); + } + } + + InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); + } + } + } + } + + return skinMenu; +} + +int ContextMenu::CreateAllSkinsMenuRecursive(HMENU skinMenu, int index) +{ + SkinRegistry& skinRegistry = GetRainmeter().m_SkinRegistry; + const int initialLevel = skinRegistry.GetFolder(index).level; + int menuIndex = 0; + + const size_t max = skinRegistry.GetFolderCount(); + while (index < max) + { + const SkinRegistry::Folder& skinFolder = skinRegistry.GetFolder(index); + if (skinFolder.level != initialLevel) + { + return index - 1; + } + + HMENU subMenu = CreatePopupMenu(); + + // Add current folder + InsertMenu(skinMenu, menuIndex, MF_POPUP | MF_BYPOSITION, (UINT_PTR)subMenu, skinFolder.name.c_str()); + + // Add subfolders + const bool hasSubfolder = (index + 1) < max && skinRegistry.GetFolder(index + 1).level == initialLevel + 1; + if (hasSubfolder) + { + index = CreateAllSkinsMenuRecursive(subMenu, index + 1); + } + + // Add files + { + int fileIndex = 0; + int fileCount = (int)skinFolder.files.size(); + for ( ; fileIndex < fileCount; ++fileIndex) + { + InsertMenu(subMenu, fileIndex, MF_STRING | MF_BYPOSITION, skinFolder.baseID + fileIndex, skinFolder.files[fileIndex].c_str()); + } + + if (skinFolder.active) + { + UINT checkPos = skinFolder.active - 1; + CheckMenuRadioItem(subMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); + } + + if (hasSubfolder && fileIndex != 0) + { + InsertMenu(subMenu, fileIndex, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr); + } + } + + ++menuIndex; + ++index; + } + + return index; +} + +void ContextMenu::CreateLayoutMenu(HMENU layoutMenu) +{ + const auto& layouts = GetRainmeter().m_Layouts; + for (size_t i = 0, isize = layouts.size(); i < isize; ++i) + { + InsertMenu(layoutMenu, i, MF_BYPOSITION, ID_THEME_FIRST + i, layouts[i].c_str()); + } +} + +void ContextMenu::CreateMonitorMenu(HMENU monitorMenu, MeterWindow* meterWindow) +{ + bool screenDefined = meterWindow->GetXScreenDefined(); + int screenIndex = meterWindow->GetXScreen(); + + // for the "Specified monitor" (@n) + const size_t numOfMonitors = System::GetMonitorCount(); // intentional + const std::vector& monitors = System::GetMultiMonitorInfo().monitors; + + int i = 1; + for (auto iter = monitors.cbegin(); iter != monitors.cend(); ++iter, ++i) + { + WCHAR buffer[64]; + size_t len = _snwprintf_s(buffer, _TRUNCATE, L"@%i: ", i); + + std::wstring item(buffer, len); + + if ((*iter).monitorName.size() > 32) + { + item.append((*iter).monitorName, 0, 32); + item += L"..."; + } + else + { + item += (*iter).monitorName; + } + + InsertMenu(monitorMenu, + i + 2, + MF_BYPOSITION | ((screenDefined && screenIndex == i) ? MF_CHECKED : MF_UNCHECKED) | ((!(*iter).active) ? MF_GRAYED : MF_ENABLED), + ID_MONITOR_FIRST + i, + item.c_str()); + } + + if (!screenDefined) + { + CheckMenuItem(monitorMenu, IDM_SKIN_MONITOR_PRIMARY, MF_BYCOMMAND | MF_CHECKED); + } + + if (screenDefined && screenIndex == 0) + { + CheckMenuItem(monitorMenu, ID_MONITOR_FIRST, MF_BYCOMMAND | MF_CHECKED); + } + + if (meterWindow->GetAutoSelectScreen()) + { + CheckMenuItem(monitorMenu, IDM_SKIN_MONITOR_AUTOSELECT, MF_BYCOMMAND | MF_CHECKED); + } +} + +void ContextMenu::ChangeSkinIndex(HMENU menu, int index) +{ + if (index > 0) + { + int count = GetMenuItemCount(menu); + + for (int i = 0; i < count; ++i) + { + HMENU subMenu = GetSubMenu(menu, i); + if (subMenu) + { + ChangeSkinIndex(subMenu, index); + } + else + { + MENUITEMINFO mii = {sizeof(MENUITEMINFO)}; + mii.fMask = MIIM_FTYPE | MIIM_ID; + GetMenuItemInfo(menu, i, TRUE, &mii); + if ((mii.fType & MFT_SEPARATOR) == 0) + { + mii.wID |= (index << 16); + mii.fMask = MIIM_ID; + SetMenuItemInfo(menu, i, TRUE, &mii); + } + } + } + } +} diff --git a/Library/ContextMenu.h b/Library/ContextMenu.h new file mode 100644 index 00000000..497941e2 --- /dev/null +++ b/Library/ContextMenu.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2013 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_LIBRARY_CONTEXTMENU_H +#define RM_LIBRARY_CONTEXTMENU_H + +#include + +class MeterWindow; + +// Handles the creation and display of Rainmeter and skin context menus. +class ContextMenu +{ +public: + ContextMenu(); + + bool IsMenuActive() { return m_MenuActive; } + + void ShowMenu(POINT pos, MeterWindow* meterWindow); + + static void CreateMonitorMenu(HMENU monitorMenu, MeterWindow* meterWindow); + +private: + static HMENU CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu); + static void ChangeSkinIndex(HMENU subMenu, int index); + + static void CreateAllSkinsMenu(HMENU skinMenu) { CreateAllSkinsMenuRecursive(skinMenu, 0); } + static int CreateAllSkinsMenuRecursive(HMENU skinMenu, int index); + + static void CreateLayoutMenu(HMENU layoutMenu); + + bool m_MenuActive; +}; + +#endif diff --git a/Library/DialogManage.cpp b/Library/DialogManage.cpp index fcfb3c99..442c218d 100644 --- a/Library/DialogManage.cpp +++ b/Library/DialogManage.cpp @@ -1185,7 +1185,7 @@ INT_PTR DialogManage::TabSkins::OnCommand(WPARAM wParam, LPARAM lParam) HMENU menu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); if (menu) { - GetRainmeter().CreateMonitorMenu(menu, m_SkinWindow); + ContextMenu::CreateMonitorMenu(menu, m_SkinWindow); RECT r; GetWindowRect((HWND)lParam, &r); diff --git a/Library/Library.vcxproj b/Library/Library.vcxproj index 02836968..68643ca3 100644 --- a/Library/Library.vcxproj +++ b/Library/Library.vcxproj @@ -90,6 +90,9 @@ $(ExcludeTests) + + Use + Use @@ -315,6 +318,7 @@ + diff --git a/Library/Library.vcxproj.filters b/Library/Library.vcxproj.filters index bf430c30..200a69ab 100644 --- a/Library/Library.vcxproj.filters +++ b/Library/Library.vcxproj.filters @@ -387,6 +387,9 @@ Source Files + + Source Files + @@ -662,6 +665,9 @@ Header Files + + Header Files + diff --git a/Library/Rainmeter.cpp b/Library/Rainmeter.cpp index 8fb4ab7e..244d1061 100644 --- a/Library/Rainmeter.cpp +++ b/Library/Rainmeter.cpp @@ -17,7 +17,6 @@ */ #include "StdAfx.h" -#include "../Common/MenuTemplate.h" #include "../Common/PathUtil.h" #include "Rainmeter.h" #include "TrayWindow.h" @@ -28,7 +27,6 @@ #include "MeasureNet.h" #include "MeasureCPU.h" #include "MeterString.h" -#include "resource.h" #include "UpdateCheck.h" #include "../Version.h" @@ -115,7 +113,6 @@ Rainmeter::Rainmeter() : m_DesktopWorkAreaChanged(false), m_DesktopWorkAreaType(false), m_NormalStayDesktop(true), - m_MenuActive(false), m_DisableRDP(false), m_DisableDragging(false), m_CurrentParser(), @@ -1708,610 +1705,6 @@ int Rainmeter::ShowMessage(HWND parent, const WCHAR* text, UINT type) return MessageBox(parent, text, APPNAME, type); }; -/* -** Opens the context menu in given coordinates. -** -*/ -void Rainmeter::ShowContextMenu(POINT pos, MeterWindow* meterWindow) -{ - static const MenuTemplate s_Menu[] = - { - MENU_ITEM(IDM_MANAGE, ID_STR_MANAGE), - MENU_ITEM(IDM_ABOUT, ID_STR_ABOUT), - MENU_ITEM(IDM_SHOW_HELP, ID_STR_HELP), - MENU_SEPARATOR(), - MENU_SUBMENU(ID_STR_SKINS, - MENU_ITEM_GRAYED(0, ID_STR_NOSKINS), - MENU_SEPARATOR(), - MENU_ITEM(IDM_OPENSKINSFOLDER, ID_STR_OPENFOLDER), - MENU_ITEM(IDM_DISABLEDRAG, ID_STR_DISABLEDRAGGING)), - MENU_SUBMENU(ID_STR_THEMES, - MENU_ITEM_GRAYED(0, ID_STR_NOTHEMES)), - MENU_SEPARATOR(), - MENU_ITEM(IDM_EDITCONFIG, ID_STR_EDITSETTINGS), - MENU_ITEM(IDM_REFRESH, ID_STR_REFRESHALL), - MENU_SEPARATOR(), - MENU_SUBMENU(ID_STR_LOGGING, - MENU_ITEM(IDM_SHOWLOGFILE, ID_STR_SHOWLOGFILE), - MENU_SEPARATOR(), - MENU_ITEM(IDM_STARTLOG, ID_STR_STARTLOGGING), - MENU_ITEM(IDM_STOPLOG, ID_STR_STOPLOGGING), - MENU_SEPARATOR(), - MENU_ITEM(IDM_DELETELOGFILE, ID_STR_DELETELOGFILE), - MENU_ITEM(IDM_DEBUGLOG, ID_STR_DEBUGMODE)), - MENU_SEPARATOR(), - MENU_ITEM(IDM_QUIT, ID_STR_EXIT) - }; - - if (!m_MenuActive && (!meterWindow || !meterWindow->IsClosing())) - { - m_MenuActive = true; - - // Show context menu, if no actions were executed - HMENU menu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); - if (menu) - { - SetMenuDefaultItem(menu, IDM_MANAGE, MF_BYCOMMAND); - - if (_waccess(GetLogger().GetLogFilePath().c_str(), 0) == -1) - { - EnableMenuItem(menu, IDM_SHOWLOGFILE, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(menu, IDM_DELETELOGFILE, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(menu, IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED); - } - else - { - EnableMenuItem( - menu, - (GetLogger().IsLogToFile()) ? IDM_STARTLOG : IDM_STOPLOG, - MF_BYCOMMAND | MF_GRAYED); - } - - if (m_Debug) - { - CheckMenuItem(menu, IDM_DEBUGLOG, MF_BYCOMMAND | MF_CHECKED); - } - - HMENU allSkinsMenu = GetSubMenu(menu, 4); - if (allSkinsMenu) - { - if (!m_SkinRegistry.IsEmpty()) - { - DeleteMenu(allSkinsMenu, 0, MF_BYPOSITION); // "No skins available" menuitem - CreateAllSkinsMenu(allSkinsMenu); - } - - if (m_DisableDragging) - { - CheckMenuItem(allSkinsMenu, IDM_DISABLEDRAG, MF_BYCOMMAND | MF_CHECKED); - } - } - - HMENU layoutMenu = GetSubMenu(menu, 5); - if (layoutMenu) - { - if (!m_Layouts.empty()) - { - DeleteMenu(layoutMenu, 0, MF_BYPOSITION); // "No layouts available" menuitem - CreateLayoutMenu(layoutMenu); - } - } - - if (meterWindow) - { - HMENU rainmeterMenu = menu; - menu = CreateSkinMenu(meterWindow, 0, allSkinsMenu); - - InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_POPUP, (UINT_PTR)rainmeterMenu, L"Rainmeter"); - InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_SEPARATOR, 0, nullptr); - } - else - { - InsertMenu(menu, 12, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); - - // Create a menu for all active skins - int index = 0; - std::map::const_iterator iter = m_MeterWindows.begin(); - for (; iter != m_MeterWindows.end(); ++iter) - { - MeterWindow* mw = ((*iter).second); - HMENU skinMenu = CreateSkinMenu(mw, index, allSkinsMenu); - InsertMenu(menu, 12, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinMenu, mw->GetFolderPath().c_str()); - ++index; - } - - // Add update notification item - if (m_NewVersion) - { - InsertMenu(menu, 0, MF_BYPOSITION, IDM_NEW_VERSION, GetString(ID_STR_UPDATEAVAILABLE)); - HiliteMenuItem(GetTrayWindow()->GetWindow(), menu, 0, MF_BYPOSITION | MF_HILITE); - InsertMenu(menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); - } - } - - HWND hWnd = WindowFromPoint(pos); - if (hWnd != nullptr) - { - MeterWindow* mw = GetMeterWindow(hWnd); - if (mw) - { - // Cancel the mouse event beforehand - mw->SetMouseLeaveEvent(true); - } - } - - // Set the window to foreground - hWnd = meterWindow ? meterWindow->GetWindow() : m_TrayWindow->GetWindow(); - HWND hWndForeground = GetForegroundWindow(); - if (hWndForeground != hWnd) - { - DWORD foregroundThreadID = GetWindowThreadProcessId(hWndForeground, nullptr); - DWORD currentThreadID = GetCurrentThreadId(); - AttachThreadInput(currentThreadID, foregroundThreadID, TRUE); - SetForegroundWindow(hWnd); - AttachThreadInput(currentThreadID, foregroundThreadID, FALSE); - } - - // Show context menu - TrackPopupMenu( - menu, - TPM_RIGHTBUTTON | TPM_LEFTALIGN | (*GetString(ID_STR_ISRTL) == L'1' ? TPM_LAYOUTRTL : 0), - pos.x, - pos.y, - 0, - hWnd, - nullptr); - - DestroyMenu(menu); - } - - m_MenuActive = false; - } -} - -int Rainmeter::CreateAllSkinsMenuRecursive(HMENU skinMenu, int index) -{ - const int initialLevel = m_SkinRegistry.GetFolder(index).level; - int menuIndex = 0; - - const size_t max = m_SkinRegistry.GetFolderCount(); - while (index < max) - { - const SkinRegistry::Folder& skinFolder = m_SkinRegistry.GetFolder(index); - if (skinFolder.level != initialLevel) - { - return index - 1; - } - - HMENU subMenu = CreatePopupMenu(); - - // Add current folder - InsertMenu(skinMenu, menuIndex, MF_POPUP | MF_BYPOSITION, (UINT_PTR)subMenu, skinFolder.name.c_str()); - - // Add subfolders - const bool hasSubfolder = (index + 1) < max && m_SkinRegistry.GetFolder(index + 1).level == initialLevel + 1; - if (hasSubfolder) - { - index = CreateAllSkinsMenuRecursive(subMenu, index + 1); - } - - // Add files - { - int fileIndex = 0; - int fileCount = (int)skinFolder.files.size(); - for ( ; fileIndex < fileCount; ++fileIndex) - { - InsertMenu(subMenu, fileIndex, MF_STRING | MF_BYPOSITION, skinFolder.baseID + fileIndex, skinFolder.files[fileIndex].c_str()); - } - - if (skinFolder.active) - { - UINT checkPos = skinFolder.active - 1; - CheckMenuRadioItem(subMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); - } - - if (hasSubfolder && fileIndex != 0) - { - InsertMenu(subMenu, fileIndex, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr); - } - } - - ++menuIndex; - ++index; - } - - return index; -} - -HMENU Rainmeter::CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu) -{ - static const MenuTemplate s_Menu[] = - { - MENU_ITEM(IDM_SKIN_OPENSKINSFOLDER, 0), - MENU_SEPARATOR(), - MENU_SUBMENU(ID_STR_VARIANTS, - MENU_SEPARATOR()), - MENU_SEPARATOR(), - MENU_SUBMENU(ID_STR_SETTINGS, - MENU_SUBMENU(ID_STR_POSITION, - MENU_SUBMENU(ID_STR_DISPLAYMONITOR, - MENU_ITEM(IDM_SKIN_MONITOR_PRIMARY, ID_STR_USEDEFAULTMONITOR), - MENU_ITEM(ID_MONITOR_FIRST, ID_STR_VIRTUALSCREEN), - MENU_SEPARATOR(), - MENU_SEPARATOR(), - MENU_ITEM(IDM_SKIN_MONITOR_AUTOSELECT, ID_STR_AUTOSELECTMONITOR)), - MENU_SEPARATOR(), - MENU_ITEM(IDM_SKIN_VERYTOPMOST, ID_STR_STAYTOPMOST), - MENU_ITEM(IDM_SKIN_TOPMOST, ID_STR_TOPMOST), - MENU_ITEM(IDM_SKIN_NORMAL, ID_STR_NORMAL), - MENU_ITEM(IDM_SKIN_BOTTOM, ID_STR_BOTTOM), - MENU_ITEM(IDM_SKIN_ONDESKTOP, ID_STR_ONDESKTOP), - MENU_SEPARATOR(), - MENU_ITEM(IDM_SKIN_FROMRIGHT, ID_STR_FROMRIGHT), - MENU_ITEM(IDM_SKIN_FROMBOTTOM, ID_STR_FROMBOTTOM), - MENU_ITEM(IDM_SKIN_XPERCENTAGE, ID_STR_XASPERCENTAGE), - MENU_ITEM(IDM_SKIN_YPERCENTAGE, ID_STR_YASPERCENTAGE)), - MENU_SUBMENU(ID_STR_TRANSPARENCY, - MENU_ITEM(IDM_SKIN_TRANSPARENCY_0, ID_STR_0PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_10, ID_STR_10PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_20, ID_STR_20PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_30, ID_STR_30PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_40, ID_STR_40PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_50, ID_STR_50PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_60, ID_STR_60PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_70, ID_STR_70PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_80, ID_STR_80PERCENT), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_90, ID_STR_90PERCENT), - MENU_SEPARATOR(), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEIN, ID_STR_FADEIN), - MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEOUT, ID_STR_FADEOUT)), - MENU_SEPARATOR(), - MENU_ITEM(IDM_SKIN_HIDEONMOUSE, ID_STR_HIDEONMOUSEOVER), - MENU_ITEM(IDM_SKIN_DRAGGABLE, ID_STR_DRAGGABLE), - MENU_ITEM(IDM_SKIN_REMEMBERPOSITION, ID_STR_SAVEPOSITION), - MENU_ITEM(IDM_SKIN_SNAPTOEDGES, ID_STR_SNAPTOEDGES), - MENU_ITEM(IDM_SKIN_CLICKTHROUGH, ID_STR_CLICKTHROUGH), - MENU_ITEM(IDM_SKIN_KEEPONSCREEN, ID_STR_KEEPONSCREEN)), - MENU_SEPARATOR(), - MENU_ITEM(IDM_SKIN_MANAGESKIN, ID_STR_MANAGESKIN), - MENU_ITEM(IDM_SKIN_EDITSKIN, ID_STR_EDITSKIN), - MENU_ITEM(IDM_SKIN_REFRESH, ID_STR_REFRESHSKIN), - MENU_SEPARATOR(), - MENU_ITEM(IDM_CLOSESKIN, ID_STR_UNLOADSKIN) - }; - - HMENU skinMenu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); - if (skinMenu) - { - // Tick the position - HMENU settingsMenu = GetSubMenu(skinMenu, 4); - if (settingsMenu) - { - HMENU posMenu = GetSubMenu(settingsMenu, 0); - if (posMenu) - { - UINT checkPos = IDM_SKIN_NORMAL - (UINT)meterWindow->GetWindowZPosition(); - CheckMenuRadioItem(posMenu, checkPos, checkPos, checkPos, MF_BYCOMMAND); - - if (meterWindow->GetXFromRight()) CheckMenuItem(posMenu, IDM_SKIN_FROMRIGHT, MF_BYCOMMAND | MF_CHECKED); - if (meterWindow->GetYFromBottom()) CheckMenuItem(posMenu, IDM_SKIN_FROMBOTTOM, MF_BYCOMMAND | MF_CHECKED); - if (meterWindow->GetXPercentage()) CheckMenuItem(posMenu, IDM_SKIN_XPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); - if (meterWindow->GetYPercentage()) CheckMenuItem(posMenu, IDM_SKIN_YPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); - - HMENU monitorMenu = GetSubMenu(posMenu, 0); - if (monitorMenu) - { - CreateMonitorMenu(monitorMenu, meterWindow); - } - } - - // Tick the transparency - HMENU alphaMenu = GetSubMenu(settingsMenu, 1); - if (alphaMenu) - { - UINT checkPos = (UINT)(10 - meterWindow->GetAlphaValue() / 25.5); - checkPos = min(9, checkPos); - checkPos = max(0, checkPos); - CheckMenuRadioItem(alphaMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); - - switch (meterWindow->GetWindowHide()) - { - case HIDEMODE_FADEIN: - CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_CHECKED); - EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); - break; - - case HIDEMODE_FADEOUT: - CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_CHECKED); - EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); - break; - - case HIDEMODE_HIDE: - EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); - break; - } - } - - // Tick the settings - switch (meterWindow->GetWindowHide()) - { - case HIDEMODE_HIDE: - CheckMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_CHECKED); - break; - - case HIDEMODE_FADEIN: - case HIDEMODE_FADEOUT: - EnableMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_GRAYED); - break; - } - - if (meterWindow->GetSnapEdges()) - { - CheckMenuItem(settingsMenu, IDM_SKIN_SNAPTOEDGES, MF_BYCOMMAND | MF_CHECKED); - } - - if (meterWindow->GetSavePosition()) - { - CheckMenuItem(settingsMenu, IDM_SKIN_REMEMBERPOSITION, MF_BYCOMMAND | MF_CHECKED); - } - - if (m_DisableDragging) - { - EnableMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_GRAYED); - } - else if (meterWindow->GetWindowDraggable()) - { - CheckMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_CHECKED); - } - - if (meterWindow->GetClickThrough()) - { - CheckMenuItem(settingsMenu, IDM_SKIN_CLICKTHROUGH, MF_BYCOMMAND | MF_CHECKED); - } - - if (meterWindow->GetKeepOnScreen()) - { - CheckMenuItem(settingsMenu, IDM_SKIN_KEEPONSCREEN, MF_BYCOMMAND | MF_CHECKED); - } - } - - // Add the name of the Skin to the menu - const std::wstring& skinName = meterWindow->GetFolderPath(); - ModifyMenu(skinMenu, IDM_SKIN_OPENSKINSFOLDER, MF_BYCOMMAND, IDM_SKIN_OPENSKINSFOLDER, skinName.c_str()); - SetMenuDefaultItem(skinMenu, IDM_SKIN_OPENSKINSFOLDER, FALSE); - - // Remove dummy menuitem from the variants menu - HMENU variantsMenu = GetSubMenu(skinMenu, 2); - if (variantsMenu) - { - DeleteMenu(variantsMenu, 0, MF_BYPOSITION); - } - - // Give the menuitem the unique id that depends on the skin - ChangeSkinIndex(skinMenu, index); - - // Add the variants menu - if (variantsMenu) - { - const SkinRegistry::Folder& skinFolder = *m_SkinRegistry.FindFolder(skinName); - for (int i = 0, isize = (int)skinFolder.files.size(); i < isize; ++i) - { - InsertMenu(variantsMenu, i, MF_BYPOSITION, skinFolder.baseID + i, skinFolder.files[i].c_str()); - } - - if (skinFolder.active) - { - UINT checkPos = skinFolder.active - 1; - CheckMenuRadioItem(variantsMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); - } - } - - // Add skin root menu - int itemCount = GetMenuItemCount(menu); - if (itemCount > 0) - { - std::wstring root = meterWindow->GetFolderPath(); - std::wstring::size_type pos = root.find_first_of(L'\\'); - if (pos != std::wstring::npos) - { - root.erase(pos); - } - - for (int i = 0; i < itemCount; ++i) - { - UINT state = GetMenuState(menu, i, MF_BYPOSITION); - if (state == 0xFFFFFFFF || (state & MF_POPUP) == 0) break; - - WCHAR buffer[MAX_PATH]; - if (GetMenuString(menu, i, buffer, MAX_PATH, MF_BYPOSITION)) - { - if (_wcsicmp(root.c_str(), buffer) == 0) - { - HMENU skinRootMenu = GetSubMenu(menu, i); - if (skinRootMenu) - { - InsertMenu(skinMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinRootMenu, root.c_str()); - } - break; - } - } - } - } - - // Add custom actions to the context menu - std::wstring contextTitle = meterWindow->GetParser().ReadString(L"Rainmeter", L"ContextTitle", L""); - if (!contextTitle.empty()) - { - auto isTitleSeparator = [](const std::wstring& title) - { - return title.find_first_not_of(L'-') == std::wstring::npos; - }; - - std::wstring contextAction = meterWindow->GetParser().ReadString(L"Rainmeter", L"ContextAction", L""); - if (!contextAction.empty() || isTitleSeparator(contextTitle)) - { - std::vector cTitles; - WCHAR buffer[128]; - int i = 1; - - while (!contextTitle.empty() && - (!contextAction.empty() || isTitleSeparator(contextTitle)) && - (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i - 1) <= IDM_SKIN_CUSTOMCONTEXTMENU_LAST) // Set maximum context items in resource.h - { - // Trim long titles - if (contextTitle.size() > 30) - { - contextTitle.replace(27, contextTitle.size() - 27, L"..."); - } - - cTitles.push_back(contextTitle); - - _snwprintf_s(buffer, _TRUNCATE, L"ContextTitle%i", ++i); - contextTitle = meterWindow->GetParser().ReadString(L"Rainmeter", buffer, L""); - _snwprintf_s(buffer, _TRUNCATE, L"ContextAction%i", i); - contextAction = meterWindow->GetParser().ReadString(L"Rainmeter", buffer, L""); - } - - // Build a sub-menu if more than three items - size_t titleSize = cTitles.size(); - if (titleSize <= 3) - { - size_t position = 0; - for (size_t i = 0; i < titleSize; ++i) - { - if (isTitleSeparator(cTitles[i])) - { - // Separators not allowed in main top-level menu - --position; - } - else - { - InsertMenu(skinMenu, position + 1, MF_BYPOSITION | MF_STRING, (index << 16) | (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i), cTitles[i].c_str()); - } - - ++position; - } - - if (position != 0) - { - InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, L"Custom skin actions"); - InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); - } - } - else - { - HMENU customMenu = CreatePopupMenu(); - InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)customMenu, L"Custom skin actions"); - - for (size_t i = 0; i < titleSize; ++i) - { - if (isTitleSeparator(cTitles[i])) - { - AppendMenu(customMenu, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); - } - else - { - AppendMenu(customMenu, MF_BYPOSITION | MF_STRING, (index << 16) | (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i), cTitles[i].c_str()); - } - } - - InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); - } - } - } - } - - return skinMenu; -} - -void Rainmeter::CreateLayoutMenu(HMENU layoutMenu) -{ - for (size_t i = 0, isize = m_Layouts.size(); i < isize; ++i) - { - InsertMenu(layoutMenu, i, MF_BYPOSITION, ID_THEME_FIRST + i, m_Layouts[i].c_str()); - } -} - -void Rainmeter::CreateMonitorMenu(HMENU monitorMenu, MeterWindow* meterWindow) -{ - bool screenDefined = meterWindow->GetXScreenDefined(); - int screenIndex = meterWindow->GetXScreen(); - - // for the "Specified monitor" (@n) - const size_t numOfMonitors = System::GetMonitorCount(); // intentional - const std::vector& monitors = System::GetMultiMonitorInfo().monitors; - - int i = 1; - for (auto iter = monitors.cbegin(); iter != monitors.cend(); ++iter, ++i) - { - WCHAR buffer[64]; - size_t len = _snwprintf_s(buffer, _TRUNCATE, L"@%i: ", i); - - std::wstring item(buffer, len); - - if ((*iter).monitorName.size() > 32) - { - item.append((*iter).monitorName, 0, 32); - item += L"..."; - } - else - { - item += (*iter).monitorName; - } - - InsertMenu(monitorMenu, - i + 2, - MF_BYPOSITION | ((screenDefined && screenIndex == i) ? MF_CHECKED : MF_UNCHECKED) | ((!(*iter).active) ? MF_GRAYED : MF_ENABLED), - ID_MONITOR_FIRST + i, - item.c_str()); - } - - if (!screenDefined) - { - CheckMenuItem(monitorMenu, IDM_SKIN_MONITOR_PRIMARY, MF_BYCOMMAND | MF_CHECKED); - } - - if (screenDefined && screenIndex == 0) - { - CheckMenuItem(monitorMenu, ID_MONITOR_FIRST, MF_BYCOMMAND | MF_CHECKED); - } - - if (meterWindow->GetAutoSelectScreen()) - { - CheckMenuItem(monitorMenu, IDM_SKIN_MONITOR_AUTOSELECT, MF_BYCOMMAND | MF_CHECKED); - } -} - -void Rainmeter::ChangeSkinIndex(HMENU menu, int index) -{ - if (index > 0) - { - int count = GetMenuItemCount(menu); - - for (int i = 0; i < count; ++i) - { - HMENU subMenu = GetSubMenu(menu, i); - if (subMenu) - { - ChangeSkinIndex(subMenu, index); - } - else - { - MENUITEMINFO mii = {sizeof(MENUITEMINFO)}; - mii.fMask = MIIM_FTYPE | MIIM_ID; - GetMenuItemInfo(menu, i, TRUE, &mii); - if ((mii.fType & MFT_SEPARATOR) == 0) - { - mii.wID |= (index << 16); - mii.fMask = MIIM_ID; - SetMenuItemInfo(menu, i, TRUE, &mii); - } - } - } - } -} - void Rainmeter::ShowLogFile() { std::wstring logFile = L'"' + GetLogger().GetLogFilePath(); diff --git a/Library/Rainmeter.h b/Library/Rainmeter.h index c2ad7fa2..c1eb66c6 100644 --- a/Library/Rainmeter.h +++ b/Library/Rainmeter.h @@ -25,6 +25,7 @@ #include #include #include "CommandHandler.h" +#include "ContextMenu.h" #include "Logger.h" #include "MeterWindow.h" #include "SkinRegistry.h" @@ -162,8 +163,8 @@ public: int ShowMessage(HWND parent, const WCHAR* text, UINT type); - bool IsMenuActive() { return m_MenuActive; } - void ShowContextMenu(POINT pos, MeterWindow* meterWindow); + bool IsMenuActive() { return m_ContextMenu.IsMenuActive(); } + void ShowContextMenu(POINT pos, MeterWindow* mw) { return m_ContextMenu.ShowMenu(pos, mw); } const std::wstring& GetTrayExecuteR() { return m_TrayExecuteR; } const std::wstring& GetTrayExecuteM() { return m_TrayExecuteM; } @@ -180,6 +181,7 @@ public: void PreserveSetting(const std::wstring& from, LPCTSTR key, bool replace = true); friend class CommandHandler; + friend class ContextMenu; friend class DialogManage; private: @@ -199,14 +201,7 @@ private: void SetLoadOrder(int folderIndex, int order); int GetLoadOrder(const std::wstring& folderPath); void UpdateDesktopWorkArea(bool reset); - HMENU CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu); - void ChangeSkinIndex(HMENU subMenu, int index); - - void CreateAllSkinsMenu(HMENU skinMenu) { CreateAllSkinsMenuRecursive(skinMenu, 0); } - int CreateAllSkinsMenuRecursive(HMENU skinMenu, int index); - void CreateLayoutMenu(HMENU layoutMenu); - void CreateMonitorMenu(HMENU monitorMenu, MeterWindow* meterWindow); void CreateOptionsFile(); void CreateDataFile(); void CreateComponentFolders(bool defaultIniLocation); @@ -249,8 +244,6 @@ private: bool m_NormalStayDesktop; - bool m_MenuActive; - bool m_DisableRDP; bool m_DisableDragging; @@ -258,7 +251,7 @@ private: std::wstring m_SkinEditor; CommandHandler m_CommandHandler; - + ContextMenu m_ContextMenu; SkinRegistry m_SkinRegistry; ConfigParser* m_CurrentParser;