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