Initial release
This commit is contained in:
@@ -0,0 +1,918 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "coptionmenu.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cstring.h"
|
||||
#include "../events.h"
|
||||
|
||||
#include "../platform/iplatformoptionmenu.h"
|
||||
#include "../platform/iplatformframe.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct CMenuItem::Impl
|
||||
{
|
||||
UTF8String title;
|
||||
UTF8String keyCode;
|
||||
SharedPointer<COptionMenu> submenu;
|
||||
SharedPointer<CBitmap> icon;
|
||||
int32_t flags {0};
|
||||
int32_t keyModifiers {0};
|
||||
VirtualKey virtualKey {VirtualKey::None};
|
||||
int32_t tag {-1};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CMenuItem
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CMenuItem
|
||||
Defines an item of a VSTGUI::COptionMenu
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem ()
|
||||
{
|
||||
impl = std::make_unique<Impl> ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::~CMenuItem () noexcept = default;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem constructor.
|
||||
* @param inTitle title of item
|
||||
* @param inFlags CMenuItem::Flags of item
|
||||
* @param inKeycode keycode of item
|
||||
* @param inKeyModifiers keymodifiers of item
|
||||
* @param inIcon icon of item
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const UTF8String& inTitle, const UTF8String& inKeycode, int32_t inKeyModifiers, CBitmap* inIcon, int32_t inFlags)
|
||||
: CMenuItem ()
|
||||
{
|
||||
impl->flags = inFlags;
|
||||
setTitle (inTitle);
|
||||
setKey (inKeycode, inKeyModifiers);
|
||||
setIcon (inIcon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem constructor.
|
||||
* @param inTitle title of item
|
||||
* @param inSubmenu submenu of item
|
||||
* @param inIcon icon of item
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const UTF8String& inTitle, COptionMenu* inSubmenu, CBitmap* inIcon)
|
||||
: CMenuItem ()
|
||||
{
|
||||
setTitle (inTitle);
|
||||
setSubmenu (inSubmenu);
|
||||
setIcon (inIcon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem constructor.
|
||||
* @param inTitle title of item
|
||||
* @param inTag tag of item
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const UTF8String& inTitle, int32_t inTag)
|
||||
: CMenuItem ()
|
||||
{
|
||||
setTitle (inTitle);
|
||||
setTag (inTag);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem copy constructor.
|
||||
* @param item item to copy
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const CMenuItem& item)
|
||||
: CMenuItem ()
|
||||
{
|
||||
impl->flags = item.impl->flags;
|
||||
setTitle (item.getTitle ());
|
||||
setIcon (item.getIcon ());
|
||||
if (item.getVirtualKey () != VirtualKey::None)
|
||||
setVirtualKey (item.getVirtualKey (), item.getKeyModifiers ());
|
||||
else
|
||||
setKey (item.getKeycode (), item.getKeyModifiers ());
|
||||
setTag (item.getTag ());
|
||||
setSubmenu (item.getSubmenu ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setTitle (const UTF8String& inTitle)
|
||||
{
|
||||
impl->title = inTitle;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setKey (const UTF8String& inKeycode, int32_t inKeyModifiers)
|
||||
{
|
||||
impl->keyCode = inKeycode;
|
||||
impl->keyModifiers = inKeyModifiers;
|
||||
impl->virtualKey = VirtualKey::None;
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setVirtualKey (int32_t inVirtualKeyCode, int32_t inKeyModifiers)
|
||||
{
|
||||
setKey (nullptr, inKeyModifiers);
|
||||
impl->virtualKey = fromVstVirtualKey (inVirtualKeyCode);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CMenuItem::getVirtualKeyCode () const
|
||||
{
|
||||
return toVstVirtualKey (impl->virtualKey);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setVirtualKey (VirtualKey inVirtualKey, int32_t inKeyModifiers)
|
||||
{
|
||||
setKey (nullptr, inKeyModifiers);
|
||||
impl->virtualKey = inVirtualKey;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setSubmenu (COptionMenu* inSubmenu)
|
||||
{
|
||||
impl->submenu = inSubmenu;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setIcon (CBitmap* inIcon)
|
||||
{
|
||||
impl->icon = inIcon;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setTag (int32_t t)
|
||||
{
|
||||
impl->tag = t;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setEnabled (bool state)
|
||||
{
|
||||
setBit (impl->flags, kDisabled, !state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setChecked (bool state)
|
||||
{
|
||||
setBit (impl->flags, kChecked, state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setIsTitle (bool state)
|
||||
{
|
||||
setBit (impl->flags, kTitle, state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setIsSeparator (bool state)
|
||||
{
|
||||
setBit (impl->flags, kSeparator, state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isEnabled () const
|
||||
{
|
||||
return !hasBit (impl->flags, kDisabled);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isChecked () const
|
||||
{
|
||||
return hasBit (impl->flags, kChecked);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isTitle () const
|
||||
{
|
||||
return hasBit (impl->flags, kTitle);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isSeparator () const
|
||||
{
|
||||
return hasBit (impl->flags, kSeparator);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const UTF8String& CMenuItem::getTitle () const
|
||||
{
|
||||
return impl->title;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CMenuItem::getKeyModifiers () const
|
||||
{
|
||||
return impl->keyModifiers;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const UTF8String& CMenuItem::getKeycode () const
|
||||
{
|
||||
return impl->keyCode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
VirtualKey CMenuItem::getVirtualKey () const
|
||||
{
|
||||
return impl->virtualKey;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu* CMenuItem::getSubmenu () const
|
||||
{
|
||||
return impl->submenu;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CBitmap* CMenuItem::getIcon () const
|
||||
{
|
||||
return impl->icon;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CMenuItem::getTag () const
|
||||
{
|
||||
return impl->tag;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CCommandMenuItem
|
||||
|
||||
The CCommandMenuItem supports setting a category, name and a target. The target will get a @link CBaseObject::notify notify()@endlink call before the item is
|
||||
displayed and after it was selected. @see CCommandMenuItem::kMsgMenuItemValidate and @see CCommandMenuItem::kMsgMenuItemSelected
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CCommandMenuItem::CCommandMenuItem (Desc&& args)
|
||||
: CMenuItem (args.title, args.keycode, args.keyModifiers, args.icon, args.flags)
|
||||
, commandCategory (std::move (args.commandCategory))
|
||||
, commandName (std::move (args.commandName))
|
||||
, itemTarget (std::move (args.target))
|
||||
{
|
||||
setTag (args.tag);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCommandMenuItem::CCommandMenuItem (const Desc& args)
|
||||
: CMenuItem (args.title, args.keycode, args.keyModifiers, args.icon, args.flags)
|
||||
, commandCategory (args.commandCategory)
|
||||
, commandName (args.commandName)
|
||||
, itemTarget (args.target)
|
||||
{
|
||||
setTag (args.tag);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCommandMenuItem::CCommandMenuItem (const CCommandMenuItem& item)
|
||||
: CMenuItem (item)
|
||||
, validateFunc (item.validateFunc)
|
||||
, selectedFunc (item.selectedFunc)
|
||||
, commandCategory (item.commandCategory)
|
||||
, commandName (item.commandName)
|
||||
{
|
||||
setItemTarget (item.itemTarget);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setItemTarget (ICommandMenuItemTarget* target)
|
||||
{
|
||||
itemTarget = target;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setCommandCategory (const UTF8String& category)
|
||||
{
|
||||
commandCategory = category;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CCommandMenuItem::isCommandCategory (const UTF8String& category) const
|
||||
{
|
||||
return commandCategory == category;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setCommandName (const UTF8String& name)
|
||||
{
|
||||
commandName = name;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CCommandMenuItem::isCommandName (const UTF8String& name) const
|
||||
{
|
||||
return commandName == name;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setActions (SelectedCallbackFunction&& selected, ValidateCallbackFunction&& validate)
|
||||
{
|
||||
selectedFunc = std::move (selected);
|
||||
validateFunc = std::move (validate);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::execute ()
|
||||
{
|
||||
if (selectedFunc)
|
||||
selectedFunc (this);
|
||||
|
||||
if (itemTarget)
|
||||
itemTarget->onCommandMenuItemSelected (this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::validate ()
|
||||
{
|
||||
if (validateFunc)
|
||||
validateFunc (this);
|
||||
|
||||
if (itemTarget)
|
||||
itemTarget->validateCommandMenuItem (this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// COptionMenu
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class COptionMenu
|
||||
Define a rectangle view where a text-value can be displayed with a given font and color.
|
||||
The text-value is centered in the given rect.
|
||||
A bitmap can be used as background, a second bitmap can be used when the option menu is popuped.
|
||||
There are 2 styles with or without a shadowed text. When a mouse click occurs, a popup menu is displayed.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* COptionMenu constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background the background bitmap
|
||||
* @param bgWhenClick the background bitmap if the option menu is displayed
|
||||
* @param style the style of the display (see CParamDisplay for styles)
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::COptionMenu (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, CBitmap* bgWhenClick, const int32_t style)
|
||||
: CParamDisplay (size, background, style)
|
||||
, bgWhenClick (bgWhenClick)
|
||||
{
|
||||
this->listener = listener;
|
||||
this->tag = tag;
|
||||
|
||||
lastButton = kRButton;
|
||||
|
||||
menuItems = new CMenuItemList;
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::COptionMenu ()
|
||||
: CParamDisplay (CRect (0, 0, 0, 0))
|
||||
{
|
||||
menuItems = new CMenuItemList;
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::COptionMenu (const COptionMenu& v)
|
||||
: CParamDisplay (v)
|
||||
, menuItems (new CMenuItemList (*v.menuItems))
|
||||
, nbItemsPerColumn (v.nbItemsPerColumn)
|
||||
, bgWhenClick (v.bgWhenClick)
|
||||
{
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::~COptionMenu () noexcept
|
||||
{
|
||||
removeAllEntry ();
|
||||
|
||||
delete menuItems;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::registerOptionMenuListener (IOptionMenuListener* listener)
|
||||
{
|
||||
if (!listeners)
|
||||
listeners = std::unique_ptr<MenuListenerList> (new MenuListenerList ());
|
||||
listeners->add (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::unregisterOptionMenuListener (IOptionMenuListener* listener)
|
||||
{
|
||||
if (listeners)
|
||||
listeners->remove (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyUp && event.modifiers.empty () && event.character == 0)
|
||||
{
|
||||
if (event.virt == VirtualKey::Return)
|
||||
{
|
||||
auto self = shared (this);
|
||||
getFrame ()->doAfterEventProcessing ([self] () {
|
||||
self->doPopup ();
|
||||
});
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
if (!(style & (kMultipleCheckStyle & ~kCheckStyle)))
|
||||
{
|
||||
if (event.virt == VirtualKey::Up)
|
||||
{
|
||||
int32_t value = (int32_t)getValue ()-1;
|
||||
if (value >= 0)
|
||||
{
|
||||
CMenuItem* entry = getEntry (value);
|
||||
while (entry && (entry->isSeparator () || entry->isTitle () || !entry->isEnabled () || entry->getSubmenu ()))
|
||||
entry = getEntry (--value);
|
||||
if (entry)
|
||||
{
|
||||
beginEdit ();
|
||||
setValue ((float)value);
|
||||
lastResult = (int32_t)getValue ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
if (event.virt == VirtualKey::Down)
|
||||
{
|
||||
int32_t value = (int32_t)getValue ()+1;
|
||||
if (value < getNbEntries ())
|
||||
{
|
||||
CMenuItem* entry = getEntry (value);
|
||||
while (entry && (entry->isSeparator () || entry->isTitle () || !entry->isEnabled () || entry->getSubmenu ()))
|
||||
entry = getEntry (++value);
|
||||
if (entry)
|
||||
{
|
||||
beginEdit ();
|
||||
setValue ((float)value);
|
||||
lastResult = (int32_t)getValue ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
CParamDisplay::onKeyboardEvent (event);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::beforePopup ()
|
||||
{
|
||||
if (listeners)
|
||||
listeners->forEach ([this] (IOptionMenuListener* l) { l->onOptionMenuPrePopup (this); });
|
||||
for (auto& menuItem : *menuItems)
|
||||
{
|
||||
if (auto* commandItem = menuItem.cast<CCommandMenuItem> ())
|
||||
commandItem->validate ();
|
||||
if (menuItem->getSubmenu ())
|
||||
menuItem->getSubmenu ()->beforePopup ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::afterPopup ()
|
||||
{
|
||||
for (auto& menuItem : *menuItems)
|
||||
{
|
||||
if (menuItem->getSubmenu ())
|
||||
menuItem->getSubmenu ()->afterPopup ();
|
||||
}
|
||||
if (listeners)
|
||||
listeners->forEach ([this] (IOptionMenuListener* l) { l->onOptionMenuPostPopup (this); });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::doPopup ()
|
||||
{
|
||||
if (bgWhenClick)
|
||||
invalid ();
|
||||
auto result = popup ();
|
||||
if (bgWhenClick)
|
||||
invalid ();
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::popup (const PopupCallback& callback)
|
||||
{
|
||||
if (!getFrame ())
|
||||
return false;
|
||||
|
||||
beforePopup ();
|
||||
|
||||
lastResult = -1;
|
||||
lastMenu = nullptr;
|
||||
|
||||
if (!menuItems->empty ())
|
||||
{
|
||||
getFrame ()->onStartLocalEventLoop ();
|
||||
if (auto platformMenu = getFrame ()->getPlatformFrame ()->createPlatformOptionMenu ())
|
||||
{
|
||||
inPopup = true;
|
||||
auto self = shared (this);
|
||||
platformMenu->popup (this, [self, callback] (COptionMenu* menu, PlatformOptionMenuResult result) {
|
||||
if (result.menu != nullptr)
|
||||
{
|
||||
bool preventSettingValue = false;
|
||||
if (self->listeners)
|
||||
{
|
||||
self->listeners->forEach (
|
||||
[self, &result] (IOptionMenuListener* l) {
|
||||
return l->onOptionMenuSetPopupResult (self, result.menu,
|
||||
result.index);
|
||||
},
|
||||
[&preventSettingValue] (bool result) {
|
||||
if (result)
|
||||
preventSettingValue = true;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
if (!preventSettingValue)
|
||||
{
|
||||
self->beginEdit ();
|
||||
self->lastMenu = result.menu;
|
||||
self->lastResult = result.index;
|
||||
self->lastMenu->setValue (static_cast<float> (self->lastResult));
|
||||
self->valueChanged ();
|
||||
self->invalid ();
|
||||
if (auto commandItem = dynamic_cast<CCommandMenuItem*> (
|
||||
self->lastMenu->getEntry (self->lastResult)))
|
||||
commandItem->execute ();
|
||||
self->endEdit ();
|
||||
}
|
||||
}
|
||||
self->afterPopup ();
|
||||
if (callback)
|
||||
callback (self);
|
||||
self->inPopup = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::popup (CFrame* frame, const CPoint& frameLocation, const PopupCallback& callback)
|
||||
{
|
||||
if (frame == nullptr || menuItems->empty ())
|
||||
return false;
|
||||
if (isAttached ())
|
||||
return false;
|
||||
CView* oldFocusView = frame->getFocusView ();
|
||||
CRect size (frameLocation, CPoint (0, 0));
|
||||
setViewSize (size);
|
||||
frame->addView (this);
|
||||
|
||||
auto prevFocusView = shared (oldFocusView);
|
||||
popup ([prevFocusView, callback] (COptionMenu* menu) {
|
||||
if (auto frame = menu->getFrame ())
|
||||
{
|
||||
frame->removeView (menu, false);
|
||||
frame->setFocusView (prevFocusView);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the selected menu item is a command menu and the command menu has removed this
|
||||
// option menu from the view hierarchy then we have to make sure the reference count is
|
||||
// corrected
|
||||
menu->remember ();
|
||||
}
|
||||
if (callback)
|
||||
callback (menu);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::cleanupSeparators (bool deep)
|
||||
{
|
||||
if (getItems ()->empty ())
|
||||
return;
|
||||
|
||||
std::list<int32_t>indicesToRemove;
|
||||
bool lastEntryWasSeparator = true;
|
||||
for (auto i = 0; i < getNbEntries () - 1; ++i)
|
||||
{
|
||||
auto entry = getEntry (i);
|
||||
vstgui_assert (entry);
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
if (entry->isSeparator ())
|
||||
{
|
||||
if (lastEntryWasSeparator)
|
||||
{
|
||||
indicesToRemove.push_front (i);
|
||||
}
|
||||
lastEntryWasSeparator = true;
|
||||
}
|
||||
else
|
||||
lastEntryWasSeparator = false;
|
||||
if (deep)
|
||||
{
|
||||
if (auto subMenu = entry->getSubmenu ())
|
||||
{
|
||||
subMenu->cleanupSeparators (deep);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto lastIndex = getNbEntries () - 1;
|
||||
if (getEntry (lastIndex)->isSeparator ())
|
||||
{
|
||||
indicesToRemove.push_front (lastIndex);
|
||||
}
|
||||
|
||||
for (auto index : indicesToRemove)
|
||||
{
|
||||
removeEntry (index);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::setPrefixNumbers (int32_t preCount)
|
||||
{
|
||||
if (preCount >= 0 && preCount <= 4)
|
||||
prefixNumbers = preCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param item menu item to add. Takes ownership of item.
|
||||
* @param index position of insertation. -1 appends the item
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addEntry (CMenuItem* item, int32_t index)
|
||||
{
|
||||
if (index < 0 || index > getNbEntries ())
|
||||
menuItems->emplace_back (owned (item));
|
||||
else
|
||||
{
|
||||
menuItems->insert (menuItems->begin () + index, owned (item));
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addEntry (COptionMenu* submenu, const UTF8String& title)
|
||||
{
|
||||
auto* item = new CMenuItem (title, submenu);
|
||||
return addEntry (item);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addEntry (const UTF8String& title, int32_t index, int32_t itemFlags)
|
||||
{
|
||||
if (title == "-")
|
||||
return addSeparator (index);
|
||||
auto* item = new CMenuItem (title, nullptr, 0, nullptr, itemFlags);
|
||||
return addEntry (item, index);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addSeparator (int32_t index)
|
||||
{
|
||||
auto* item = new CMenuItem ("", nullptr, 0, nullptr, CMenuItem::kSeparator);
|
||||
return addEntry (item, index);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::getCurrent () const
|
||||
{
|
||||
return getEntry (currentIndex);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::getEntry (int32_t index) const
|
||||
{
|
||||
if (index < 0 || menuItems->empty () || index >= getNbEntries ())
|
||||
return nullptr;
|
||||
|
||||
return (*menuItems)[static_cast<size_t> (index)];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int32_t COptionMenu::getNbEntries () const
|
||||
{
|
||||
return static_cast<int32_t> (menuItems->size ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu* COptionMenu::getSubMenu (int32_t idx) const
|
||||
{
|
||||
CMenuItem* item = getEntry (idx);
|
||||
if (item)
|
||||
return item->getSubmenu ();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t COptionMenu::getCurrentIndex (bool countSeparator) const
|
||||
{
|
||||
if (countSeparator)
|
||||
return currentIndex;
|
||||
int32_t i = 0;
|
||||
int32_t numSeparators = 0;
|
||||
for (auto& item : *menuItems)
|
||||
{
|
||||
if (item->isSeparator ())
|
||||
numSeparators++;
|
||||
if (i == currentIndex)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return currentIndex - numSeparators;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::setCurrent (int32_t index, bool countSeparator)
|
||||
{
|
||||
CMenuItem* item = nullptr;
|
||||
if (countSeparator)
|
||||
{
|
||||
item = getEntry (index);
|
||||
if (!item || item->isSeparator ())
|
||||
return false;
|
||||
currentIndex = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t i = 0;
|
||||
for (auto& menuItem : *menuItems)
|
||||
{
|
||||
if (i > index)
|
||||
break;
|
||||
if (menuItem->isSeparator ())
|
||||
index++;
|
||||
i++;
|
||||
}
|
||||
currentIndex = index;
|
||||
item = getEntry (currentIndex);
|
||||
}
|
||||
if (item && style & (kMultipleCheckStyle & ~kCheckStyle))
|
||||
item->setChecked (!item->isChecked ());
|
||||
|
||||
// to force the redraw
|
||||
setDirty ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::removeEntry (int32_t index)
|
||||
{
|
||||
if (index < 0 || menuItems->empty () || index >= getNbEntries ())
|
||||
return false;
|
||||
menuItems->erase (menuItems->begin () + index);
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::removeAllEntry ()
|
||||
{
|
||||
menuItems->clear ();
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::checkEntry (int32_t index, bool state)
|
||||
{
|
||||
CMenuItem* item = getEntry (index);
|
||||
if (item)
|
||||
{
|
||||
item->setChecked (state);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::checkEntryAlone (int32_t index)
|
||||
{
|
||||
int32_t pos = 0;
|
||||
for (auto& item : *menuItems)
|
||||
{
|
||||
item->setChecked (pos == index);
|
||||
pos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::isCheckEntry (int32_t index) const
|
||||
{
|
||||
CMenuItem* item = getEntry (index);
|
||||
if (item && item->isChecked ())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::draw (CDrawContext *pContext)
|
||||
{
|
||||
CMenuItem* item = getEntry (currentIndex);
|
||||
drawBack (pContext, inPopup ? bgWhenClick : nullptr);
|
||||
if (item)
|
||||
drawPlatformText (pContext, item->getTitle ());
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult COptionMenu::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
lastButton = buttons;
|
||||
if (lastButton & (kLButton|kRButton|kApple))
|
||||
{
|
||||
auto self = shared (this);
|
||||
getFrame ()->doAfterEventProcessing ([self] () {
|
||||
self->doPopup ();
|
||||
});
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu *COptionMenu::getLastItemMenu (int32_t &idxInMenu) const
|
||||
{
|
||||
idxInMenu = lastMenu ? (int32_t)lastMenu->getValue (): -1;
|
||||
return lastMenu;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::setValue (float val)
|
||||
{
|
||||
auto newIndex = static_cast<int32_t> (std::round (val));
|
||||
if (newIndex < 0 || newIndex >= getNbEntries ())
|
||||
return;
|
||||
|
||||
currentIndex = newIndex;
|
||||
if (style & (kMultipleCheckStyle & ~kCheckStyle))
|
||||
{
|
||||
CMenuItem* item = getCurrent ();
|
||||
if (item)
|
||||
item->setChecked (!item->isChecked ());
|
||||
}
|
||||
CParamDisplay::setValue (static_cast<float> (newIndex));
|
||||
|
||||
// to force the redraw
|
||||
setDirty ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
float COptionMenu::getMax () const
|
||||
{
|
||||
if (menuItems->empty ())
|
||||
return 0.f;
|
||||
return static_cast<float> (menuItems->size () - 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::takeFocus ()
|
||||
{
|
||||
CParamDisplay::takeFocus ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::looseFocus ()
|
||||
{
|
||||
CView* receiver = getParentView () ? getParentView () : getFrame ();
|
||||
while (receiver)
|
||||
{
|
||||
if (receiver->notify (this, kMsgLooseFocus) == kMessageNotified)
|
||||
break;
|
||||
receiver = receiver->getParentView ();
|
||||
}
|
||||
CParamDisplay::looseFocus ();
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
Reference in New Issue
Block a user