1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Added sub-menu support to ComboBoxes

This commit is contained in:
hogliux 2016-11-21 16:36:32 +00:00
parent 6641b9d844
commit 00c0671c6b
4 changed files with 134 additions and 136 deletions

View file

@ -22,27 +22,10 @@
==============================================================================
*/
ComboBox::ItemInfo::ItemInfo (const String& nm, int iid, bool enabled, bool heading)
: name (nm), itemId (iid), isEnabled (enabled), isHeading (heading)
{
}
bool ComboBox::ItemInfo::isSeparator() const noexcept
{
return name.isEmpty();
}
bool ComboBox::ItemInfo::isRealItem() const noexcept
{
return ! (isHeading || name.isEmpty());
}
//==============================================================================
ComboBox::ComboBox (const String& name)
: Component (name),
lastCurrentId (0),
isButtonDown (false),
separatorPending (false),
menuActive (false),
scrollWheelEnabled (false),
mouseWheelAccumulator (0),
@ -109,25 +92,19 @@ void ComboBox::addItem (const String& newItemText, const int newItemId)
if (newItemText.isNotEmpty() && newItemId != 0)
{
if (separatorPending)
{
separatorPending = false;
items.add (new ItemInfo (String(), 0, false, false));
}
items.add (new ItemInfo (newItemText, newItemId, true, false));
currentMenu.addItem (newItemId, newItemText, true, false);
}
}
void ComboBox::addItemList (const StringArray& itemsToAdd, const int firstItemIdOffset)
{
for (int i = 0; i < itemsToAdd.size(); ++i)
addItem (itemsToAdd[i], i + firstItemIdOffset);
currentMenu.addItem (i + firstItemIdOffset, itemsToAdd[i]);
}
void ComboBox::addSeparator()
{
separatorPending = (items.size() > 0);
currentMenu.addSeparator();
}
void ComboBox::addSectionHeading (const String& headingName)
@ -137,67 +114,69 @@ void ComboBox::addSectionHeading (const String& headingName)
if (headingName.isNotEmpty())
{
if (separatorPending)
{
separatorPending = false;
items.add (new ItemInfo (String(), 0, false, false));
}
items.add (new ItemInfo (headingName, 0, true, true));
currentMenu.addSectionHeader (headingName);
}
}
void ComboBox::setItemEnabled (const int itemId, const bool shouldBeEnabled)
{
if (ItemInfo* const item = getItemForId (itemId))
if (PopupMenu::Item* item = getItemForId (itemId))
item->isEnabled = shouldBeEnabled;
}
bool ComboBox::isItemEnabled (int itemId) const noexcept
{
const ItemInfo* const item = getItemForId (itemId);
const PopupMenu::Item* item = getItemForId (itemId);
return item != nullptr && item->isEnabled;
}
void ComboBox::changeItemText (const int itemId, const String& newText)
{
if (ItemInfo* const item = getItemForId (itemId))
item->name = newText;
if (PopupMenu::Item* item = getItemForId (itemId))
item->text = newText;
else
jassertfalse;
}
void ComboBox::clear (const NotificationType notification)
{
items.clear();
separatorPending = false;
currentMenu.clear();
if (! label->isEditable())
setSelectedItemIndex (-1, notification);
}
//==============================================================================
ComboBox::ItemInfo* ComboBox::getItemForId (const int itemId) const noexcept
PopupMenu::Item* ComboBox::getItemForId (const int itemId) const noexcept
{
if (itemId != 0)
{
for (int i = items.size(); --i >= 0;)
if (items.getUnchecked(i)->itemId == itemId)
return items.getUnchecked(i);
PopupMenu::MenuItemIterator iterator (currentMenu, true);
while (iterator.next())
{
PopupMenu::Item &item = iterator.getItem();
if (item.itemID == itemId)
return &item;
}
}
return nullptr;
}
ComboBox::ItemInfo* ComboBox::getItemForIndex (const int index) const noexcept
PopupMenu::Item* ComboBox::getItemForIndex (const int index) const noexcept
{
for (int n = 0, i = 0; i < items.size(); ++i)
{
ItemInfo* const item = items.getUnchecked(i);
int n = 0;
PopupMenu::MenuItemIterator iterator (currentMenu, true);
if (item->isRealItem())
while (iterator.next())
{
PopupMenu::Item &item = iterator.getItem();
if (item.itemID != 0)
if (n++ == index)
return item;
return &item;
}
return nullptr;
@ -206,42 +185,51 @@ ComboBox::ItemInfo* ComboBox::getItemForIndex (const int index) const noexcept
int ComboBox::getNumItems() const noexcept
{
int n = 0;
PopupMenu::MenuItemIterator iterator (currentMenu, true);
for (int i = items.size(); --i >= 0;)
if (items.getUnchecked(i)->isRealItem())
++n;
while (iterator.next())
{
PopupMenu::Item &item = iterator.getItem();
if (item.itemID != 0)
n++;
}
return n;
}
String ComboBox::getItemText (const int index) const
{
if (const ItemInfo* const item = getItemForIndex (index))
return item->name;
if (const PopupMenu::Item* const item = getItemForIndex (index))
return item->text;
return String();
}
int ComboBox::getItemId (const int index) const noexcept
{
if (const ItemInfo* const item = getItemForIndex (index))
return item->itemId;
if (const PopupMenu::Item* const item = getItemForIndex (index))
return item->itemID;
return 0;
}
int ComboBox::indexOfItemId (const int itemId) const noexcept
{
for (int n = 0, i = 0; i < items.size(); ++i)
if (itemId != 0)
{
const ItemInfo* const item = items.getUnchecked(i);
int n = 0;
PopupMenu::MenuItemIterator iterator (currentMenu, true);
if (item->isRealItem())
while (iterator.next())
{
if (item->itemId == itemId)
PopupMenu::Item &item = iterator.getItem();
if (item.itemID == itemId)
return n;
++n;
else if (item.itemID != 0)
n++;
}
}
@ -266,15 +254,15 @@ void ComboBox::setSelectedItemIndex (const int index, const NotificationType not
int ComboBox::getSelectedId() const noexcept
{
const ItemInfo* const item = getItemForId (currentId.getValue());
const PopupMenu::Item* const item = getItemForId (currentId.getValue());
return (item != nullptr && getText() == item->name) ? item->itemId : 0;
return (item != nullptr && getText() == item->text) ? item->itemID : 0;
}
void ComboBox::setSelectedId (const int newItemId, const NotificationType notification)
{
const ItemInfo* const item = getItemForId (newItemId);
const String newItemText (item != nullptr ? item->name : String());
const PopupMenu::Item* const item = getItemForId (newItemId);
const String newItemText (item != nullptr ? item->text : String());
if (lastCurrentId != newItemId || label->getText() != newItemText)
{
@ -290,7 +278,7 @@ void ComboBox::setSelectedId (const int newItemId, const NotificationType notifi
bool ComboBox::selectIfEnabled (const int index)
{
if (const ItemInfo* const item = getItemForIndex (index))
if (const PopupMenu::Item* const item = getItemForIndex (index))
{
if (item->isEnabled)
{
@ -325,14 +313,16 @@ String ComboBox::getText() const
void ComboBox::setText (const String& newText, const NotificationType notification)
{
for (int i = items.size(); --i >= 0;)
{
const ItemInfo* const item = items.getUnchecked(i);
PopupMenu::MenuItemIterator iterator (currentMenu, true);
if (item->isRealItem()
&& item->name == newText)
while (iterator.next())
{
PopupMenu::Item &item = iterator.getItem();
if (item.itemID != 0
&& item.text == newText)
{
setSelectedId (item->itemId, notification);
setSelectedId (item.itemID, notification);
return;
}
}
@ -540,11 +530,19 @@ static void comboBoxPopupMenuFinishedCallback (int result, ComboBox* combo)
void ComboBox::showPopup()
{
PopupMenu menu;
menu.setLookAndFeel (&getLookAndFeel());
addItemsToMenu (menu);
PopupMenu::MenuItemIterator iterator (currentMenu, true);
const int selectedId = getSelectedId();
menu.showMenuAsync (PopupMenu::Options().withTargetComponent (this)
while (iterator.next())
{
PopupMenu::Item &item = iterator.getItem();
if (item.itemID != 0)
item.isTicked = (item.itemID == selectedId);
}
currentMenu.setLookAndFeel(&getLookAndFeel());
currentMenu.showMenuAsync (PopupMenu::Options().withTargetComponent (this)
.withItemThatMustBeVisible (getSelectedId())
.withMinimumWidth (getWidth())
.withMaximumNumColumns (1)
@ -552,28 +550,6 @@ void ComboBox::showPopup()
ModalCallbackFunction::forComponent (comboBoxPopupMenuFinishedCallback, this));
}
void ComboBox::addItemsToMenu (PopupMenu& menu) const
{
const int selectedId = getSelectedId();
for (int i = 0; i < items.size(); ++i)
{
const ItemInfo* const item = items.getUnchecked(i);
jassert (item != nullptr);
if (item->isSeparator())
menu.addSeparator();
else if (item->isHeading)
menu.addSectionHeader (item->name);
else
menu.addItem (item->itemId, item->name,
item->isEnabled, item->itemId == selectedId);
}
if (items.size() == 0)
menu.addItem (1, noChoicesMessage, false);
}
//==============================================================================
void ComboBox::mouseDown (const MouseEvent& e)
{