menu.cpp (3877B)
1 /* ReaPack: Package manager for REAPER 2 * Copyright (C) 2015-2025 Christian Fillion 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "menu.hpp" 19 20 #include "win32.hpp" 21 22 #ifndef MIIM_FTYPE // for SWELL 23 # define MIIM_FTYPE MIIM_TYPE 24 #endif 25 26 #ifndef _WIN32 27 # include <swell/swell.h> 28 #endif 29 30 #include <reaper_plugin_functions.h> 31 32 Menu::Menu(HMENU handle) 33 : m_handle(handle), m_ownership(!handle) 34 { 35 if(m_ownership) 36 m_handle = CreatePopupMenu(); 37 38 m_size = GetMenuItemCount(m_handle); 39 } 40 41 Menu::~Menu() 42 { 43 if(m_ownership) 44 DestroyMenu(m_handle); 45 } 46 47 UINT Menu::addAction(const std::string &label, const int commandId) 48 { 49 MENUITEMINFO mii{}; 50 mii.cbSize = sizeof(mii); 51 52 mii.fMask |= MIIM_TYPE; 53 mii.fType = MFT_STRING; 54 const auto &&wideLabel = Win32::widen(label); 55 mii.dwTypeData = const_cast<Win32::char_type *>(wideLabel.c_str()); 56 57 mii.fMask |= MIIM_ID; 58 mii.wID = commandId; 59 60 const UINT index = m_size; 61 append(mii); 62 return index; 63 } 64 65 UINT Menu::addAction(const std::string &label, const char *namedCommand) 66 { 67 return addAction(label, NamedCommandLookup(namedCommand)); 68 } 69 70 void Menu::addSeparator() 71 { 72 MENUITEMINFO mii{}; 73 mii.cbSize = sizeof(mii); 74 75 mii.fMask = MIIM_TYPE; 76 mii.fType = MFT_SEPARATOR; 77 78 append(mii); 79 } 80 81 Menu Menu::addMenu(const std::string &label) 82 { 83 MENUITEMINFO mii{}; 84 mii.cbSize = sizeof(mii); 85 86 mii.fMask |= MIIM_TYPE; 87 mii.fType = MFT_STRING; 88 const auto &&wideLabel = Win32::widen(label); 89 mii.dwTypeData = const_cast<Win32::char_type *>(wideLabel.c_str()); 90 91 mii.fMask |= MIIM_SUBMENU; 92 mii.hSubMenu = CreatePopupMenu(); 93 94 append(mii); 95 96 return Menu(mii.hSubMenu); 97 } 98 99 void Menu::append(MENUITEMINFO &mii) 100 { 101 InsertMenuItem(m_handle, m_size++, true, &mii); 102 } 103 104 int Menu::show(const int x, const int y, HWND parent) const 105 { 106 const int command = TrackPopupMenu(m_handle, 107 TPM_TOPALIGN | TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, 108 x, y, 0, parent, nullptr); 109 110 // both send the notification and return the command id 111 SendMessage(parent, WM_COMMAND, command, 0); 112 113 return command; 114 } 115 116 int Menu::show(HWND control, HWND parent) const 117 { 118 RECT rect; 119 GetWindowRect(control, &rect); 120 121 return show(rect.left, rect.bottom - 1, parent); 122 } 123 124 void Menu::disable(const UINT index) 125 { 126 setEnabled(false, index); 127 } 128 129 void Menu::enable(const UINT index) 130 { 131 setEnabled(true, index); 132 } 133 134 void Menu::setEnabled(const bool enabled, const UINT index) 135 { 136 MENUITEMINFO mii{}; 137 mii.cbSize = sizeof(mii); 138 mii.fMask |= MIIM_STATE; 139 140 if(!GetMenuItemInfo(m_handle, index, true, &mii)) 141 return; 142 143 mii.fState |= enabled ? MFS_ENABLED : MFS_DISABLED; 144 145 SetMenuItemInfo(m_handle, index, true, &mii); 146 } 147 148 void Menu::check(const UINT index) 149 { 150 MENUITEMINFO mii{}; 151 mii.cbSize = sizeof(mii); 152 mii.fMask |= MIIM_STATE; 153 154 if(!GetMenuItemInfo(m_handle, index, true, &mii)) 155 return; 156 157 mii.fState |= MFS_CHECKED; 158 159 SetMenuItemInfo(m_handle, index, true, &mii); 160 } 161 162 void Menu::checkRadio(const UINT index) 163 { 164 MENUITEMINFO mii{}; 165 mii.cbSize = sizeof(mii); 166 mii.fMask |= MIIM_FTYPE; 167 mii.fMask |= MIIM_STATE; 168 169 if(!GetMenuItemInfo(m_handle, index, true, &mii)) 170 return; 171 172 mii.fType |= MFT_RADIOCHECK; 173 mii.fState |= MFS_CHECKED; 174 175 SetMenuItemInfo(m_handle, index, true, &mii); 176 }