iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IGraphicsPopupMenu.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
13#include <cmath>
14#include <cstring>
15#include <cstdio>
16#include <cassert>
17#include <memory>
18
19#include "wdlstring.h"
20#include "ptrlist.h"
21
29BEGIN_IPLUG_NAMESPACE
30BEGIN_IGRAPHICS_NAMESPACE
31
40{
41public:
43#pragma mark - IPopupMenu::Item
44 class Item
45 {
46 public:
47 enum Flags
48 {
49 kNoFlags = 0,
50 kDisabled = 1 << 0, // item is gray and not selectable
51 kTitle = 1 << 1, // item indicates a title and is not selectable
52 kChecked = 1 << 2, // item has a checkmark
53 kSeparator = 1 << 3 // item is a separator
54 };
55
56 Item(const char* str, int flags = kNoFlags, int tag = -1)
57 : mFlags(flags)
58 , mTag(tag)
59 {
60 SetText(str);
61 }
62
63 Item (const char* str, IPopupMenu* pSubMenu)
64 : mSubmenu(pSubMenu)
65 , mFlags(kNoFlags)
66 {
67 SetText(str);
68 }
69
70 Item(const Item&) = delete;
71 void operator=(const Item&) = delete;
72
73 ~Item()
74 {
75 }
76
77 void SetText(const char* str) { mText.Set(str); }
78 const char* GetText() const { return mText.Get(); }; // TODO: Text -> Str!
79
80 bool GetEnabled() const { return !(mFlags & kDisabled); }
81 bool GetChecked() const { return (mFlags & kChecked) != 0; }
82 bool GetIsTitle() const { return (mFlags & kTitle) != 0; }
83 bool GetIsSeparator() const { return (mFlags & kSeparator) != 0; }
84 int GetTag() const { return mTag; }
85 IPopupMenu* GetSubmenu() const { return mSubmenu.get(); }
86 bool GetIsChoosable() const
87 {
88 if(GetIsTitle()) return false;
89 if(GetIsSeparator()) return false;
90 if(GetSubmenu() != nullptr) return false;
91 if(!GetEnabled()) return false;
92
93 return true;
94 }
95
96 void SetEnabled(bool state) { SetFlag(kDisabled, !state); }
97 void SetChecked(bool state) { SetFlag(kChecked, state); }
98 void SetTitle(bool state) {SetFlag(kTitle, state); }
99 void SetSubmenu(IPopupMenu* pSubmenu) { mSubmenu.reset(pSubmenu); }
100
101 protected:
102 void SetFlag(Flags flag, bool state)
103 {
104 if (state)
105 mFlags |= flag;
106 else
107 mFlags &= ~flag;
108 }
109
110 WDL_String mText;
111 std::unique_ptr<IPopupMenu> mSubmenu;
112 int mFlags;
113 int mTag = -1;
114 };
115
116 #pragma mark -
117
118 IPopupMenu(const char* rootTitle = "", int prefix = 0, bool multicheck = false, const std::initializer_list<const char*>& items = {})
119 : mPrefix(prefix)
120 , mCanMultiCheck(multicheck)
121 , mRootTitle(rootTitle)
122 {
123 for (auto& item : items)
124 AddItem(item);
125 }
126
127 IPopupMenu(const char* rootTitle, const std::initializer_list<const char*>& items, IPopupFunction func = nullptr)
128 : mPrefix(0)
129 , mCanMultiCheck(false)
130 , mRootTitle(rootTitle)
131 {
132 for (auto& item : items)
133 AddItem(item);
134
135 SetFunction(func);
136 }
137
138 IPopupMenu(const IPopupMenu&) = delete;
139 void operator=(const IPopupMenu&) = delete;
140
142 {
143 mMenuItems.Empty(true);
144 }
145
146 static int Sortfunc(const Item **a, const Item **b)
147 {
148 return stricmp((*a)->GetText(),(*b)->GetText());
149 }
150
151 Item* AddItem(Item* pItem, int index = -1)
152 {
153 if (index == -1)
154 mMenuItems.Add(pItem); // add it to the end
155 else if (index == -2)
156 mMenuItems.InsertSorted(pItem, Sortfunc);
157 else
158 mMenuItems.Insert(index, pItem);
159
160 return pItem;
161 }
162
163 Item* AddItem(const char* str, int index = -1, int itemFlags = Item::kNoFlags) { return AddItem(new Item(str, itemFlags), index); }
164
165 Item* AddItem(const char* str, int index, IPopupMenu* pSubmenu)
166 {
167 assert(pSubmenu->GetFunction() == nullptr); // submenus should not have existing functions
168
169 if(GetFunction())
170 pSubmenu->SetFunction(GetFunction());
171
172 return AddItem(new Item(str, pSubmenu), index);
173 }
174
175 Item* AddItem(const char* str, IPopupMenu* pSubmenu, int index = -1)
176 {
177 assert(pSubmenu->GetFunction() == nullptr); // submenus should not have existing functions
178
179 if(GetFunction())
180 pSubmenu->SetFunction(GetFunction());
181
182 return AddItem(new Item(str, pSubmenu), index);
183 }
184
185 Item* AddSeparator(int index = -1)
186 {
187 Item* pItem = new Item ("", Item::kSeparator);
188 return AddItem(pItem, index);
189 }
190
191 void RemoveEmptySubmenus()
192 {
193 int n = mMenuItems.GetSize();
194
195 WDL_PtrList<IPopupMenu::Item> toDelete;
196
197 for (int i = 0; i < n; i++)
198 {
199 IPopupMenu::Item* pItem = GetItem(i);
200
201 IPopupMenu* pSubmenu = pItem->GetSubmenu();
202
203 if(pSubmenu && pSubmenu->NItems() == 0)
204 {
205 toDelete.Add(pItem);
206 }
207 }
208
209 for (int i = 0; i < toDelete.GetSize(); i++)
210 {
211 mMenuItems.DeletePtr(toDelete.Get(i));
212 }
213 }
214
215 void SetChosenItemIdx(int index) { mChosenItemIdx = index; };
216 int GetChosenItemIdx() const { return mChosenItemIdx; }
217 int NItems() const { return mMenuItems.GetSize(); }
218 int NItemsPerColumn() const { return mNItemsPerColumn; }
219 void SetNItemsPerColumn(int nItemsPerColumn) { mNItemsPerColumn = nItemsPerColumn; }
220 int GetPrefix() const { return mPrefix; }
221 bool GetCanMultiCheck() const { return mCanMultiCheck; }
222
223 bool HasSubMenus()
224 {
225 int n = mMenuItems.GetSize();
226
227 for (int i = 0; i < n; i++)
228 {
229 IPopupMenu::Item* pItem = GetItem(i);
230 IPopupMenu* pSubmenu = pItem->GetSubmenu();
231
232 if (pSubmenu)
233 {
234 return true;
235 }
236 }
237
238 return false;
239 }
240
241 Item* GetItem(int index)
242 {
243 int nItems = NItems();
244
245 if (index >= 0 && index < nItems)
246 {
247 return mMenuItems.Get(index);
248 }
249 else
250 {
251 return nullptr;
252 }
253 }
254
255 int GetIndexOfItem(Item* pItem) const
256 {
257 return mMenuItems.Find(pItem);
258 }
259
260 Item* GetChosenItem()
261 {
262 return GetItem(mChosenItemIdx);
263 }
264
265 const char* GetItemText(int index)
266 {
267 Item* pItem = GetItem(index);
268 if(pItem)
269 return pItem->GetText();
270 else
271 return "";
272 }
273
274 void SetPrefix(int count)
275 {
276 if (count >= 0 && count < 4)
277 {
278 mPrefix = count;
279 }
280 }
281
282 void SetMultiCheck(bool multicheck) { mCanMultiCheck = multicheck; }
283
284 void Clear(bool resetEverything = true)
285 {
286 if (resetEverything)
287 {
288 SetChosenItemIdx(-1);
289 SetPrefix(0);
290 mCanMultiCheck = false;
291 }
292
293 mMenuItems.Empty(true);
294 }
295
296 bool CheckItem(int index, bool state)
297 {
298 Item* pItem = mMenuItems.Get(index);
299
300 if (pItem)
301 {
302 pItem->SetChecked(state);
303 return true;
304 }
305 return false;
306 }
307
308 void CheckItemAlone(int index)
309 {
310 for (int i = 0; i < mMenuItems.GetSize(); i++)
311 {
312 mMenuItems.Get(i)->SetChecked(i == index);
313 }
314 }
315
316 void CheckItemWithText(const char* str, bool state = true)
317 {
318 for (int i = 0; i < mMenuItems.GetSize(); i++)
319 {
320 if (strcmp(mMenuItems.Get(i)->GetText(), str) == 0)
321 {
322 mMenuItems.Get(i)->SetChecked(state);
323 break;
324 }
325 }
326 }
327
328 void CheckItemAlone(Item* pItemToCheck)
329 {
330 int n = mMenuItems.GetSize();
331
332 for (int i = 0; i < n; i++)
333 {
334 IPopupMenu::Item* pItem = GetItem(i);
335 pItem->SetChecked(false);
336 IPopupMenu* pSubmenu = pItem->GetSubmenu();
337
338 if (pSubmenu)
339 {
340 pSubmenu->CheckItemAlone(pItemToCheck);
341 }
342 else if (pItem == pItemToCheck)
343 {
344 pItem->SetChecked(true);
345 }
346 }
347 }
348
349 bool IsItemChecked(int index)
350 {
351 Item* pItem = mMenuItems.Get(index);
352
353 if (pItem)
354 return pItem->GetChecked();
355
356 return false;
357 }
358
359 void SetFunction(IPopupFunction func)
360 {
361 mPopupFunc = func;
362 }
363
364 IPopupFunction GetFunction()
365 {
366 return mPopupFunc;
367 }
368
369 void ExecFunction()
370 {
371 mPopupFunc(this);
372 }
373
374 const char* GetRootTitle() const
375 {
376 return mRootTitle.Get();
377 }
378
379 void SetRootTitle(const char* rootTitle)
380 {
381 return mRootTitle.Set(rootTitle);
382 }
383
384private:
385 int mNItemsPerColumn = 0; // Windows can divide popup menu into columns
386 int mPrefix; // 0 = no prefix, 1 = numbers no leading zeros, 2 = 1 lz, 3 = 2lz
387 int mChosenItemIdx = -1;
388 bool mCanMultiCheck; // multicheck = 0 doesn't actually prohibit multichecking, you should do that in your code, by calling CheckItemAlone instead of CheckItem
389 WDL_PtrList<Item> mMenuItems;
390 IPopupFunction mPopupFunc = nullptr;
391 WDL_String mRootTitle;
392};
393
394END_IGRAPHICS_NAMESPACE
395END_IPLUG_NAMESPACE
396
A class to specify an item of a pop up menu.
A class for setting the contents of a pop up menu.