29namespace PopupMenuSettings
31 const int scrollZone = 24;
32 const int dismissCommandId = 0x6287345f;
34 static bool menuWasHiddenBecauseOfAppChange =
false;
56 && item.
subMenu->items.size() > 0;
102 : item (i), parentWindow (parent), options (
o), customComp (i.
customComponent)
107 if (customComp !=
nullptr)
109 setItem (*customComp, &item);
115 updateShortcutKeyDescription();
127 if (customComp !=
nullptr)
128 setItem (*customComp,
nullptr);
135 if (customComp !=
nullptr)
147 if (customComp ==
nullptr)
158 const auto border =
getLookAndFeel().getPopupMenuBorderSizeWithOptions (options);
171 if (customComp !=
nullptr)
176 handler->grabFocus();
182 static bool isAccessibilityHandlerRequired (
const PopupMenu::Item& item)
184 return item.
isSectionHeader || hasActiveSubMenu (item) || canBeTriggered (item);
187 PopupMenu::Item item;
191 class ItemAccessibilityHandler
final :
public AccessibilityHandler
203 String getTitle()
const override
205 return itemComponent.item.text;
208 AccessibleState getCurrentState()
const override
213 if (hasActiveSubMenu (itemComponent.item))
219 if (itemComponent.item.isTicked)
222 return state.
isFocused() ? state.withSelected() : state;
226 static AccessibilityActions getAccessibilityActions (ItemAccessibilityHandler& handler,
229 auto onFocus = [&item]
231 item.parentWindow.disableTimerUntilMouseMoves();
232 item.parentWindow.ensureItemComponentIsVisible (item, -1);
233 item.parentWindow.setCurrentlyHighlightedChild (&item);
236 auto onToggle = [&handler, &item, onFocus]
238 if (handler.getCurrentState().isSelected())
239 item.parentWindow.setCurrentlyHighlightedChild (
nullptr);
247 if (canBeTriggered (item.item))
251 item.parentWindow.setCurrentlyHighlightedChild (&item);
252 item.parentWindow.triggerCurrentlyHighlightedItem();
256 if (hasActiveSubMenu (item.item))
260 item.parentWindow.showSubMenuFor (&item);
262 if (
auto* subMenu = item.parentWindow.activeSubMenu.get())
263 subMenu->setCurrentlyHighlightedChild (subMenu->items.getFirst());
273 ItemComponent& itemComponent;
283 MenuWindow& parentWindow;
284 const PopupMenu::Options& options;
287 bool isHighlighted =
false;
289 void updateShortcutKeyDescription()
291 if (item.commandManager !=
nullptr
293 && item.shortcutKeyDescription.isEmpty())
297 for (
auto&
keypress : item.commandManager->getKeyMappings()
298 ->getKeyPressesAssignedToCommand (item.itemID))
300 auto key =
keypress.getTextDescriptionWithIcons();
305 if (key.length() == 1 && key[0] < 128)
315 String getTextForMeasurement()
const
317 return item.shortcutKeyDescription.isNotEmpty() ? item.text +
" " + item.shortcutKeyDescription
335 parent (parentWindow),
336 options (
opts.withParentComponent (findNonNullLookAndFeel (
menu, parentWindow).getParentComponentForMenuOptions (
opts))),
337 managerOfChosenCommand (manager),
338 componentAttachedTo (options.getTargetComponent()),
341 lastFocusedTime (windowCreationTime),
342 timeEnteredCurrentChildComp (windowCreationTime),
354 if (
auto*
pc = options.getParentComponent())
356 pc->addChildComponent (
this);
362 const auto*
compToCheck = parent !=
nullptr ? parent
363 : options.getTargetComponent();
373 |
lf.getMenuWindowFlags());
378 if (options.getParentComponent() ==
nullptr && parentWindow ==
nullptr &&
lf.shouldPopupMenuScaleWithTargetComponent (options))
379 if (
auto* targetComponent = options.getTargetComponent())
387 for (
int i = 0; i <
menu.items.size(); ++i)
389 auto& item =
menu.items.getReference (i);
393 auto* child = items.add (
new ItemComponent (item, options, *
this));
394 child->setExplicitFocusOrder (1 + i);
397 setCurrentlyHighlightedChild (child);
401 auto targetArea = options.getTargetScreenArea() / scaleFactor;
406 if (
auto visibleID = options.getItemThatMustBeVisible())
408 for (
auto* item : items)
414 if (
auto*
pc = options.getParentComponent())
415 return pc->getLocalPoint (
nullptr, targetArea.getTopLeft());
417 return targetArea.getTopLeft();
428 resizeToBestWindowPos();
430 getActiveWindows().add (
this);
431 lf.preparePopupMenuWindow (*
this);
438 getActiveWindows().removeFirstMatchingValue (
this);
440 activeSubMenu.reset();
457 const auto border =
theme.getPopupMenuBorderSizeWithOptions (options);
463 const Rectangle<int> separator (currentX + width,
466 getHeight() - border * 2);
467 theme.drawPopupMenuColumnSeparatorWithOptions (g, separator, options);
468 currentX += width + separatorWidth;
476 if (options.getParentComponent())
482 if (isTopScrollZoneActive())
484 lf.drawPopupMenuUpDownArrowWithOptions (g,
486 PopupMenuSettings::scrollZone,
491 if (isBottomScrollZoneActive())
494 lf.drawPopupMenuUpDownArrowWithOptions (g,
496 PopupMenuSettings::scrollZone,
511 activeSubMenu.reset();
512 currentChild =
nullptr;
521 auto resultID = options.hasWatchedComponentBeenDeleted() ? 0 : getResultItemID (item);
527 exitingModalState =
true;
535 && item->
action !=
nullptr)
540 static int getResultItemID (
const PopupMenu::Item* item)
545 if (
auto*
cc = item->customCallback.get())
546 if (!
cc->menuItemTriggered())
552 void dismissMenu (
const PopupMenu::Item* item)
554 if (parent !=
nullptr)
556 parent->dismissMenu (item);
568 hide (
nullptr,
true);
582 if (currentChild !=
nullptr)
583 if (
auto*
childHandler = currentChild->getAccessibilityHandler())
598 selectNextItem (MenuSelectionDirection::forwards);
602 selectNextItem (MenuSelectionDirection::backwards);
606 if (parent !=
nullptr)
611 hide (
nullptr,
true);
613 if (parentWindow !=
nullptr)
616 disableTimerUntilMouseMoves();
618 else if (componentAttachedTo !=
nullptr)
620 componentAttachedTo->keyPressed (key);
625 disableTimerUntilMouseMoves();
627 if (showSubMenuFor (currentChild))
629 if (isSubMenuVisible())
630 activeSubMenu->selectNextItem (MenuSelectionDirection::current);
632 else if (componentAttachedTo !=
nullptr)
634 componentAttachedTo->keyPressed (key);
639 triggerCurrentlyHighlightedItem();
643 dismissMenu (
nullptr);
657 for (
auto*
ms : mouseSourceStates)
665 if (! isOverAnyMenu())
667 if (componentAttachedTo !=
nullptr)
675 auto mousePos = componentAttachedTo->getMouseXYRelative();
677 if (componentAttachedTo->reallyContains (
mousePos,
true))
684 dismissMenu (
nullptr);
692 if (
commandId == PopupMenuSettings::dismissCommandId)
693 dismissMenu (
nullptr);
704 alterChildYPos (
roundToInt (-10.0f *
wheel.deltaY * PopupMenuSettings::scrollZone));
709 getMouseState (e.
source).handleMouseEvent (e);
712 bool windowIsStillValid()
717 if (componentAttachedTo != options.getTargetComponent())
719 dismissMenu (
nullptr);
727 if (exitingModalState)
739 MouseSourceState& getMouseState (MouseInputSource source)
743 for (
auto*
ms : mouseSourceStates)
746 else if (
ms->source.getType() != source.getType())
ms->stopTimer();
751 mouseState =
new MouseSourceState (*
this, source);
759 bool isOverAnyMenu()
const
761 return parent !=
nullptr ? parent->isOverAnyMenu()
765 bool isOverChildren()
const
768 && (isAnyMouseOver() || (activeSubMenu !=
nullptr && activeSubMenu->isOverChildren()));
771 bool isAnyMouseOver()
const
773 for (
auto*
ms : mouseSourceStates)
780 bool treeContains (
const MenuWindow*
const window)
const noexcept
784 while (
mw->parent !=
nullptr)
787 while (
mw !=
nullptr)
792 mw =
mw->activeSubMenu.get();
798 bool doesAnyJuceCompHaveFocus()
800 if (! detail::WindowingHelpers::isForegroundOrEmbeddedProcess (componentAttachedTo))
810 hasAnyJuceCompHadFocus =
true;
815 return ! hasAnyJuceCompHadFocus;
822 targetPoint =
relativeTo->localPointToGlobal (targetPoint);
827 if (
auto*
pc = options.getParentComponent())
829 return pc->getLocalArea (
nullptr,
830 pc->getScreenBounds()
831 .reduced (
getLookAndFeel().getPopupMenuBorderSizeWithOptions (options))
838 void calculateWindowPos (Rectangle<int> target,
const bool alignToRectangle)
840 auto parentArea = getParentArea (target.getCentre()) / scaleFactor;
842 if (
auto*
pc = options.getParentComponent())
858 if (options.getPreferredPopupDirection() == Options::PopupDirection::upwards)
860 : target.getBottom();
869 if (parent !=
nullptr)
871 if (parent->parent !=
nullptr)
874 > parent->parent->
getX() + parent->parent->
getWidth() / 2);
903 if (
getLookAndFeel().getPopupMenuBorderSizeWithOptions (options) == 0)
906 const auto border =
getLookAndFeel().getPopupMenuBorderSizeWithOptions (options);
908 : target.getY() - border;
917 hideOnExit = parent !=
nullptr
921 void layoutMenuItems (
const int maxMenuW,
const int maxMenuH,
int& width,
int& height)
924 if (
auto* last = items.getLast())
925 last->item.shouldBreakAfter =
false;
927 const auto isBreak = [] (
const ItemComponent* item) {
return item->item.shouldBreakAfter; };
937 needsToScroll = contentHeight > height;
939 width = updateYPositions();
944 numColumns = options.getMinimumNumColumns();
947 auto maximumNumColumns = options.getMaximumNumColumns() > 0 ? options.getMaximumNumColumns() : 7;
955 numColumns =
jmax (1, numColumns - 1);
968 const auto itemsPerColumn = (items.size() + numColumns - 1) / numColumns;
977 items[
breakIndex]->item.shouldBreakAfter =
true;
980 if (! items.isEmpty())
981 (*
std::prev (items.end()))->item.shouldBreakAfter =
false;
984 int correctColumnWidths (
const int maxMenuW)
987 const auto minWidth =
jmin (
maxMenuW, options.getMinimumWidth());
993 for (
auto& column : columnWidths)
994 column =
totalW / numColumns;
1000 void workOutManualSize (
const int maxMenuW)
1003 columnWidths.
clear();
1005 for (
auto it = items.begin(),
end = items.end();
it !=
end;)
1007 const auto isBreak = [] (
const ItemComponent* item) {
return item->item.shouldBreakAfter; };
1011 const auto getMaxWidth = [] (
int acc,
const ItemComponent* item) {
return jmax (
acc, item->getWidth()); };
1016 const auto sumHeight = [] (
int acc,
const ItemComponent* item) {
return acc + item->getHeight(); };
1019 contentHeight =
jmax (contentHeight,
colH);
1024 contentHeight +=
getLookAndFeel().getPopupMenuBorderSizeWithOptions (options) * 2;
1029 int workOutBestSize (
const int maxMenuW)
1034 for (
int col = 0;
col < numColumns; ++
col)
1036 int colW = options.getStandardItemHeight(),
colH = 0;
1039 (items.size() + numColumns - 1) / numColumns);
1044 colH += items.getUnchecked (
childNum + i)->getHeight();
1051 contentHeight =
jmax (contentHeight,
colH);
1056 return correctColumnWidths (
maxMenuW);
1059 void ensureItemComponentIsVisible (
const ItemComponent&
itemComp,
int wantedY)
1061 if (windowPos.
getHeight() > PopupMenuSettings::scrollZone * 4)
1069 jmax (PopupMenuSettings::scrollZone,
1070 windowPos.
getHeight() - (PopupMenuSettings::scrollZone +
itemComp.getHeight())),
1073 auto parentArea = getParentArea (windowPos.
getPosition(), options.getParentComponent()) / scaleFactor;
1074 auto deltaY =
wantedY - currentY;
1081 windowPos.
getY() + deltaY);
1085 childYOffset -= deltaY;
1093 void resizeToBestWindowPos()
1097 if (childYOffset < 0)
1099 r = r.
withTop (r.getY() - childYOffset);
1101 else if (childYOffset > 0)
1113 void alterChildYPos (
int delta)
1117 childYOffset += delta;
1122 return jmax (childYOffset, 0);
1126 const auto limit = contentHeight
1132 return childYOffset;
1142 resizeToBestWindowPos();
1146 int updateYPositions()
1150 - (childYOffset + (
getY() - windowPos.
getY()));
1156 for (
const auto& item : items)
1160 item->setBounds (x, y,
columnWidth, item->getHeight());
1161 y += item->getHeight();
1163 if (item->item.shouldBreakAfter)
1175 void setCurrentlyHighlightedChild (ItemComponent* child)
1177 if (currentChild !=
nullptr)
1178 currentChild->setHighlighted (
false);
1180 currentChild = child;
1182 if (currentChild !=
nullptr)
1184 currentChild->setHighlighted (
true);
1192 bool isSubMenuVisible()
const noexcept {
return activeSubMenu !=
nullptr && activeSubMenu->isVisible(); }
1194 bool showSubMenuFor (ItemComponent*
childComp)
1196 activeSubMenu.reset();
1201 activeSubMenu.reset (
new HelperClasses::MenuWindow (*(
childComp->item.subMenu),
this,
1202 options.forSubmenu()
1203 .withTargetScreenArea (
childComp->getScreenBounds())
1204 .withMinimumWidth (0),
1205 false, dismissOnMouseUp, managerOfChosenCommand, scaleFactor));
1207 activeSubMenu->setVisible (
true);
1208 activeSubMenu->enterModalState (
false);
1209 activeSubMenu->toFront (
false);
1213 void triggerCurrentlyHighlightedItem()
1215 if (currentChild !=
nullptr && canBeTriggered (currentChild->item))
1217 dismissMenu (¤tChild->item);
1221 enum class MenuSelectionDirection
1228 void selectNextItem (MenuSelectionDirection direction)
1230 disableTimerUntilMouseMoves();
1234 auto index = items.indexOf (currentChild);
1239 return direction == MenuSelectionDirection::backwards ? items.size() - 1
1243 auto preIncrement = (direction != MenuSelectionDirection::current && currentChild !=
nullptr);
1245 for (
int i = items.size(); --i >= 0;)
1248 start += (direction == MenuSelectionDirection::backwards ? -1 : 1);
1250 if (
auto*
mic = items.getUnchecked ((start + items.size()) % items.size()))
1252 if (canBeTriggered (
mic->item) || hasActiveSubMenu (
mic->item))
1254 setCurrentlyHighlightedChild (
mic);
1264 void disableTimerUntilMouseMoves()
1266 disableMouseMoves =
true;
1268 if (parent !=
nullptr)
1269 parent->disableTimerUntilMouseMoves();
1272 bool canScroll()
const noexcept {
return childYOffset != 0 || needsToScroll; }
1273 bool isTopScrollZoneActive()
const noexcept {
return canScroll() && childYOffset > 0; }
1274 bool isBottomScrollZoneActive()
const noexcept {
return canScroll() && childYOffset < contentHeight - windowPos.
getHeight(); }
1279 return std::make_unique<AccessibilityHandler> (*
this,
1280 AccessibilityRole::popupMenu,
1283 if (currentChild !=
nullptr)
1285 if (
auto* handler = currentChild->getAccessibilityHandler())
1286 handler->grabFocus();
1290 selectNextItem (MenuSelectionDirection::forwards);
1297 return parentWindow !=
nullptr ? &(parentWindow->
getLookAndFeel())
1298 :
menu.lookAndFeel.get();
1303 if (
auto* result = findLookAndFeel (
menu, parentWindow))
1311 const Options options;
1316 bool hasBeenOver =
false, needsToScroll =
false;
1317 bool dismissOnMouseUp, hideOnExit =
false, disableMouseMoves =
false, hasAnyJuceCompHadFocus =
false;
1318 int numColumns = 0, contentHeight = 0, childYOffset = 0;
1322 uint32 windowCreationTime, lastFocusedTime, timeEnteredCurrentChildComp;
1325 bool exitingModalState =
false;
1342 if (! window.windowIsStillValid())
1358 if (window.windowIsStillValid())
1359 handleMousePosition (source.getScreenPosition().roundToInt());
1372 double scrollAcceleration = 0;
1373 uint32 lastScrollTime, lastMouseMoveTime = 0;
1374 bool isDown =
false;
1381 if (
timeNow > window.timeEnteredCurrentChildComp + 100
1383 && window.currentChild !=
nullptr
1384 && ! (window.disableMouseMoves || window.isSubMenuVisible()))
1386 window.showSubMenuFor (window.currentChild);
1392 const bool isOverAny = window.isOverAnyMenu();
1394 if (window.hideOnExit && window.hasBeenOver && !
isOverAny)
1395 window.hide (
nullptr,
true);
1403 isDown = window.hasBeenOver
1411 if (
timeNow > window.lastFocusedTime + 10)
1413 PopupMenuSettings::menuWasHiddenBecauseOfAppChange =
true;
1414 window.dismissMenu (
nullptr);
1421 window.triggerCurrentlyHighlightedItem();
1422 else if ((window.hasBeenOver || ! window.dismissOnMouseUp) && !
isOverAny)
1423 window.dismissMenu (
nullptr);
1429 window.lastFocusedTime =
timeNow;
1437 const auto isMouseOver = window.reallyContains (
localMousePos,
true);
1440 window.hasBeenOver =
true;
1446 if (window.disableMouseMoves && isMouseOver)
1447 window.disableMouseMoves =
false;
1450 if (window.disableMouseMoves || (window.activeSubMenu !=
nullptr && window.activeSubMenu->isOverChildren()))
1465 auto* itemUnderMouse =
dynamic_cast<ItemComponent*
> (c);
1467 if (itemUnderMouse ==
nullptr && c !=
nullptr)
1468 itemUnderMouse = c->findParentComponentOfClass<ItemComponent>();
1470 if (itemUnderMouse != window.currentChild
1471 && (isMouseOver || (window.activeSubMenu ==
nullptr) || ! window.activeSubMenu->isVisible()))
1473 if (isMouseOver && (c !=
nullptr) && (window.activeSubMenu !=
nullptr))
1474 window.activeSubMenu->hide (
nullptr,
true);
1478 if (! window.hasBeenOver)
1481 itemUnderMouse =
nullptr;
1484 window.setCurrentlyHighlightedChild (itemUnderMouse);
1490 bool isMovingTowardsSubmenu (Point<int>
newGlobalPos)
const
1492 if (window.activeSubMenu ==
nullptr)
1524 if (window.canScroll()
1528 if (window.isTopScrollZoneActive() &&
localMousePos.y < PopupMenuSettings::scrollZone)
1531 if (window.isBottomScrollZoneActive() &&
localMousePos.y > window.getHeight() - PopupMenuSettings::scrollZone)
1535 scrollAcceleration = 1.0;
1541 if (
timeNow > lastScrollTime + 20)
1543 scrollAcceleration =
jmin (4.0, scrollAcceleration * 1.04);
1546 for (
int i = 0; i < window.items.size() &&
amount == 0; ++i)
1547 amount = ((
int) scrollAcceleration) * window.items.getUnchecked (i)->getHeight();
1549 window.alterChildYPos (
amount * direction);
1560 auto localPos = (window.activeSubMenu ==
nullptr) ? window.getLocalPoint (
nullptr,
screenPos)
1561 : window.activeSubMenu->getLocalPoint (
nullptr,
screenPos);
1578 width (w), height (h)
1595 const int width, height;
1604 : items (
other.items),
1605 lookAndFeel (
other.lookAndFeel)
1613 items =
other.items;
1614 lookAndFeel =
other.lookAndFeel;
1621 : items (std::move (
other.items)),
1622 lookAndFeel (std::move (
other.lookAndFeel))
1628 items = std::move (
other.items);
1629 lookAndFeel =
other.lookAndFeel;
1648 : text (
other.text),
1649 itemID (
other.itemID),
1650 action (
other.action),
1653 customComponent (
other.customComponent),
1654 customCallback (
other.customCallback),
1655 commandManager (
other.commandManager),
1656 shortcutKeyDescription (
other.shortcutKeyDescription),
1657 colour (
other.colour),
1658 isEnabled (
other.isEnabled),
1659 isTicked (
other.isTicked),
1660 isSeparator (
other.isSeparator),
1661 isSectionHeader (
other.isSectionHeader),
1662 shouldBreakAfter (
other.shouldBreakAfter)
1668 itemID =
other.itemID;
1669 action =
other.action;
1672 customComponent =
other.customComponent;
1673 customCallback =
other.customCallback;
1674 commandManager =
other.commandManager;
1675 shortcutKeyDescription =
other.shortcutKeyDescription;
1676 colour =
other.colour;
1677 isEnabled =
other.isEnabled;
1678 isTicked =
other.isTicked;
1679 isSeparator =
other.isSeparator;
1680 isSectionHeader =
other.isSectionHeader;
1681 shouldBreakAfter =
other.shouldBreakAfter;
1717 customComponent = comp;
1730 return std::move (*
this);
1736 return std::move (*
this);
1742 return std::move (*
this);
1748 return std::move (*
this);
1754 return std::move (*
this);
1759 customComponent = comp;
1760 return std::move (*
this);
1766 return std::move (*
this);
1775 ||
newItem.subMenu !=
nullptr);
1788 i.
action = std::move (action);
1843 jassert (commandManager !=
nullptr && commandID != 0);
1902 jassert (! (HelperClasses::ItemComponent::isAccessibilityHandlerRequired (i) &&
itemTitle.isEmpty()));
1914 auto comp = std::make_unique<HelperClasses::NormalComponentWrapper> (customComponent,
idealWidth,
idealHeight,
1955 Item i (std::move (title));
1973template <
typename Member,
typename Item>
1976 options.*
member = std::forward<Item> (item);
1982 auto o = with (with (*
this, &Options::targetComponent, comp), &Options::topLevelTarget, comp);
1984 if (comp !=
nullptr)
1992 return withTargetComponent (&comp);
1997 return with (*
this, &Options::targetArea, area);
2007 return with (with (*
this, &Options::isWatchingForDeletion,
true),
2008 &Options::componentToWatchForDeletion,
2014 return with (*
this, &Options::minWidth, w);
2019 return with (*
this, &Options::minColumns,
cols);
2024 return with (*
this, &Options::maxColumns,
cols);
2029 return with (*
this, &Options::standardHeight, height);
2039 return with (*
this, &Options::parentComponent, parent);
2044 return with (*
this, &Options::preferredPopupDirection, direction);
2054 return with (*
this, &Options::targetComponent,
nullptr);
2064 if (
auto* handle = target->getWindowHandle())
2065 return std::make_unique<ScopedThreadDPIAwarenessSetter> (handle);
2072 :
new HelperClasses::MenuWindow (*
this,
nullptr, options,
2075 managerOfChosenCommand);
2086 if (managerOfChosenCommand !=
nullptr && result != 0)
2089 info.
invocationMethod = ApplicationCommandTarget::InvocationInfo::fromMenu;
2091 managerOfChosenCommand->
invoke (info,
true);
2097 if (PopupMenuSettings::menuWasHiddenBecauseOfAppChange)
2100 if (
auto* focusComponent = Component::getCurrentlyFocusedComponent())
2102 const auto focusedIsNotMinimised = [focusComponent]
2104 if (
auto* peer = focusComponent->getPeer())
2105 return ! peer->isMinimised();
2110 if (focusedIsNotMinimised)
2112 if (
auto* topLevel = focusComponent->getTopLevelComponent())
2113 topLevel->toFront (
true);
2115 if (focusComponent->isShowing() && ! focusComponent->hasKeyboardFocus (
true))
2116 focusComponent->grabKeyboardFocus();
2127int PopupMenu::showWithOptionalCallback (
const Options& options,
2134 if (
auto* window = createWindow (options, &(callback->managerOfChosenCommand)))
2136 callback->component.reset (window);
2138 PopupMenuSettings::menuWasHiddenBecauseOfAppChange =
false;
2140 window->setVisible (
true);
2142 ModalComponentManager::getInstance()->attachCallback (window, callback.release());
2144 window->toFront (
false);
2147 #if JUCE_MODAL_LOOPS_PERMITTED
2149 return window->runModalLoop();
2159#if JUCE_MODAL_LOOPS_PERMITTED
2160int PopupMenu::showMenu (
const Options& options)
2162 return showWithOptionalCallback (options,
nullptr,
true);
2168 showWithOptionalCallback (options,
nullptr,
false);
2173 #if ! JUCE_MODAL_LOOPS_PERMITTED
2177 showWithOptionalCallback (options,
userCallback,
false);
2186#if JUCE_MODAL_LOOPS_PERMITTED
2192 .withMinimumWidth (minimumWidth)
2201 ModalComponentManager::Callback* callback)
2205 .withMinimumWidth (minimumWidth)
2214 ModalComponentManager::Callback* callback)
2224 return showWithOptionalCallback (options, callback,
true);
2230 auto& windows = HelperClasses::MenuWindow::getActiveWindows();
2235 if (
auto*
pmw = windows[i])
2237 pmw->setLookAndFeel (
nullptr);
2238 pmw->dismissMenu (
nullptr);
2250 for (
auto&
mi : items)
2251 if (!
mi.isSeparator)
2259 for (
auto&
mi : items)
2260 if ((
mi.itemID == commandID &&
mi.commandManager !=
nullptr)
2261 || (
mi.subMenu !=
nullptr &&
mi.subMenu->containsCommandItem (commandID)))
2269 for (
auto&
mi : items)
2271 if (
mi.subMenu !=
nullptr)
2273 if (
mi.subMenu->containsAnyActiveItems())
2276 else if (
mi.isEnabled)
2290void PopupMenu::setItem (CustomComponent& c,
const Item*
itemToUse)
2316 pmw->dismissMenu (&
mic->item);
2333PopupMenu::CustomCallback::CustomCallback() {}
2334PopupMenu::CustomCallback::~CustomCallback() {}
2347 if (index.size() == 0 || menus.getLast()->items.size() == 0)
2350 currentItem =
const_cast<PopupMenu::Item*
> (&(menus.getLast()->items.getReference (index.getLast())));
2352 if (searchRecursively && currentItem->subMenu !=
nullptr)
2355 menus.add (currentItem->subMenu.get());
2359 index.setUnchecked (index.size() - 1, index.getLast() + 1);
2362 while (index.size() > 0 && index.getLast() >= (
int) menus.getLast()->items.size())
2367 if (index.size() > 0)
2368 index.setUnchecked (index.size() - 1, index.getLast() + 1);
2376 jassert (currentItem !=
nullptr);
2377 return *(currentItem);
2393void PopupMenu::LookAndFeelMethods::drawPopupMenuUpDownArrow (
Graphics&,
int,
int,
bool) {}
2397int PopupMenu::LookAndFeelMethods::getPopupMenuBorderSize() {
return 0; }
A simple wrapper for building a collection of supported accessibility actions and corresponding callb...
virtual AccessibleState getCurrentState() const
Returns the current state of the UI element.
AccessibleState withExpandable() const noexcept
Sets the expandable flag and returns the new state.
AccessibleState withCheckable() const noexcept
Sets the checkable flag and returns the new state.
AccessibleState withAccessibleOffscreen() const noexcept
Sets the accessible offscreen flag and returns the new state.
AccessibleState withSelectable() const noexcept
Sets the selectable flag and returns the new state.
AccessibleState withExpanded() const noexcept
Sets the expanded flag and returns the new state.
AccessibleState withChecked() const noexcept
Sets the checked flag and returns the new state.
bool isFocused() const noexcept
Returns true if the UI element is focused.
AccessibleState withCollapsed() const noexcept
Sets the collapsed flag and returns the new state.
One of these objects holds a list of all the commands your app can perform, and despatches these comm...
ApplicationCommandTarget * getTargetForCommand(CommandID commandID, ApplicationCommandInfo &upToDateInfo)
Tries to find the best target to use to perform a given command.
const ApplicationCommandInfo * getCommandForID(CommandID commandID) const noexcept
Returns the details about a given command ID.
bool invoke(const ApplicationCommandTarget::InvocationInfo &invocationInfo, bool asynchronously)
Sends a command to the default target.
Holds a resizable array of primitive or copy-by-value objects.
bool isEmpty() const noexcept
Returns true if the array is empty, false otherwise.
int size() const noexcept
Returns the current number of elements in the array.
ElementType * begin() noexcept
Returns a pointer to the first element in the array.
ElementType * end() noexcept
Returns a pointer to the element which follows the last element in the array.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
void set(int indexToChange, ParameterType newValue)
Replaces an element with a new value.
void clear()
Removes all elements from the array.
ElementType getLast() const noexcept
Returns the last element in the array, or a default value if the array is empty.
Specifies a set of gaps to be left around the sides of a rectangle.
Represents a colour, also including a transparency value.
static ModifierKeys getCurrentModifiersRealtime() noexcept
On desktop platforms this method will check all the mouse and key states and return a ModifierKeys ob...
static int getNumPeers() noexcept
Returns the number of currently-active peers.
@ windowIsTemporary
Indicates that the window is a temporary popup, like a menu, tooltip, etc.
@ windowIgnoresKeyPresses
Tells the window not to catch any keypresses.
static ComponentPeer * getPeer(int index) noexcept
Returns one of the currently-active peers.
Holds a pointer to some type of Component, which automatically becomes null if the component is delet...
The base class for all JUCE user-interface objects.
void setLookAndFeel(LookAndFeel *newLookAndFeel)
Sets the look and feel to use for this component.
bool isAccessible() const noexcept
Returns true if this component and its children are visible to accessibility clients.
static Component *JUCE_CALLTYPE getCurrentlyModalComponent(int index=0) noexcept
Returns one of the components that are currently modal.
void setAccessible(bool shouldBeAccessible)
Sets whether this component and its children are visible to accessibility clients.
bool isVisible() const noexcept
Tests whether the component is visible or not.
void exitModalState(int returnValue=0)
Ends a component's modal state.
bool reallyContains(Point< int > localPoint, bool returnTrueIfWithinAChild)
Returns true if a given point lies in this component, taking any overlapping siblings into account.
bool isOpaque() const noexcept
Returns true if no parts of this component are transparent.
void setFocusContainerType(FocusContainerType containerType) noexcept
Sets whether this component is a container for components that can have their focus traversed,...
int getHeight() const noexcept
Returns the component's height in pixels.
int getX() const noexcept
Returns the x coordinate of the component's left edge.
Point< int > getLocalPoint(const Component *sourceComponent, Point< int > pointRelativeToSourceComponent) const
Converts a point to be relative to this component's coordinate space.
static Component *JUCE_CALLTYPE getCurrentlyFocusedComponent() noexcept
Returns the component that currently has the keyboard focus.
bool isShowing() const
Tests whether this component and all its parents are visible.
static float JUCE_CALLTYPE getApproximateScaleFactorForComponent(const Component *targetComponent)
Returns the approximate scale factor for a given component by traversing its parent hierarchy and app...
void addAndMakeVisible(Component *child, int zOrder=-1)
Adds a child component to this one, and also makes the child visible if it isn't already.
void setAlwaysOnTop(bool shouldStayOnTop)
Sets whether the component should always be kept at the front of its siblings.
void addMouseListener(MouseListener *newListener, bool wantsEventsForAllNestedChildComponents)
Registers a listener to be told when mouse events occur in this component.
AccessibilityHandler * getAccessibilityHandler()
Returns the accessibility handler for this component, or nullptr if this component is not accessible.
void setOpaque(bool shouldBeOpaque)
Indicates whether any parts of the component might be transparent.
void postCommandMessage(int commandId)
Dispatches a numbered message to this component.
void repaint()
Marks the whole component as needing to be redrawn.
Component() noexcept
Creates a component.
@ focusContainer
The component will act as a top-level component within which focus is passed around.
Rectangle< int > getScreenBounds() const
Returns the bounds of this component, relative to the screen's top-left.
int getY() const noexcept
Returns the y coordinate of the top of this component.
virtual void setName(const String &newName)
Sets the name of this component.
void removeChildComponent(Component *childToRemove)
Removes one of this component's child-components.
Component * getChildComponent(int index) const noexcept
Returns one of this component's child components, by it index.
virtual void addToDesktop(int windowStyleFlags, void *nativeWindowToAttachTo=nullptr)
Makes this component appear as a window on the desktop.
void setBounds(int x, int y, int width, int height)
Changes the component's position and size.
void setSize(int newWidth, int newHeight)
Changes the size of the component.
void setWantsKeyboardFocus(bool wantsFocus) noexcept
Sets a flag to indicate whether this component wants keyboard focus or not.
void setMouseClickGrabsKeyboardFocus(bool shouldGrabFocus)
Chooses whether a click on this component automatically grabs the focus.
int getWidth() const noexcept
Returns the component's width in pixels.
LookAndFeel & getLookAndFeel() const noexcept
Finds the appropriate look-and-feel to use for this component.
Rectangle< int > getLocalBounds() const noexcept
Returns the component's bounds, relative to its own origin.
void setTopLeftPosition(int x, int y)
Moves the component to a new position.
virtual void setVisible(bool shouldBeVisible)
Makes the component visible or invisible.
String getName() const noexcept
Returns the name of this component.
virtual void handleCommandMessage(int commandId)
Called to handle a command that was sent by postCommandMessage().
float getGlobalScaleFactor() const noexcept
Returns the current global scale factor, as set by setGlobalScaleFactor().
const Displays & getDisplays() const noexcept
Returns the Displays object representing the connected displays.
void addGlobalMouseListener(MouseListener *listener)
Registers a MouseListener that will receive all mouse events that occur on any component.
static Point< int > getMousePosition()
Returns the mouse position.
static Desktop &JUCE_CALLTYPE getInstance()
There's only one desktop object, and this method will return it.
void removeGlobalMouseListener(MouseListener *listener)
Unregisters a MouseListener that was added with addGlobalMouseListener().
static bool canUseSemiTransparentWindows() noexcept
True if the OS supports semitransparent windows.
Rectangle< int > userArea
The total area of this display in logical pixels which isn't covered by OS-dependent objects like the...
const Display * getDisplayForPoint(Point< int > point, bool isPhysical=false) const noexcept
Returns the Display object representing the display containing a given Point (either in logical or ph...
A drawable object which is a bitmap image.
The base class for objects which can draw themselves, e.g.
A graphics context, used for drawing a component or image.
void fillAll() const
Fills the context's entire clip region with the current colour or brush.
void setOrigin(Point< int > newOrigin)
Moves the position of the context's origin.
Holds a fixed-size bitmap.
Represents a key press, including any modifier keys that are needed.
static const int upKey
key-code for the cursor-up key
bool isKeyCode(int keyCodeToCompare) const noexcept
Checks whether the KeyPress's key is the same as the one provided, without checking the modifiers.
static const int rightKey
key-code for the cursor-right key
static const int downKey
key-code for the cursor-down key
static const int spaceKey
key-code for the space bar
static const int escapeKey
key-code for the escape key
static const int returnKey
key-code for the return key
static const int leftKey
key-code for the cursor-left key
LookAndFeel objects define the appearance of all the JUCE widgets, and subclasses can be used to appl...
static bool callAsync(std::function< void()> functionToCall)
Asynchronously invokes a function or C++11 lambda on the message thread.
static ModalComponentManager::Callback * create(CallbackFn &&fn)
This is a utility function to create a ModalComponentManager::Callback that will call a callable obje...
Receives callbacks when a modal component is dismissed.
static ModifierKeys currentModifiers
This object represents the last-known state of the keyboard and mouse buttons.
bool isAnyMouseButtonDown() const noexcept
Tests for any of the mouse-button flags.
Contains position and status information about a mouse event.
MouseInputSource source
The source device that generated this event.
Point< int > getScreenPosition() const
Returns the mouse position of this event, in global screen coordinates.
An array designed for holding objects.
A pair of (x, y) coordinates.
ValueType getDistanceFrom(Point other) const noexcept
Returns the straight-line distance between this point and another one.
constexpr Point< int > roundToInt() const noexcept
Casts this point to a Point<int> object using roundToInt() to convert the values.
Manages a rectangle and allows geometric operations to be performed on it.
bool intersects(Rectangle other) const noexcept
Returns true if any part of another rectangle overlaps this one.
Rectangle withPosition(ValueType newX, ValueType newY) const noexcept
Returns a rectangle with the same size as this one, but a new position.
ValueType getX() const noexcept
Returns the x coordinate of the rectangle's left-hand-side.
Point< ValueType > getPosition() const noexcept
Returns the rectangle's top-left position as a Point.
Rectangle getIntersection(Rectangle other) const noexcept
Returns the region that is the overlap between this and another rectangle.
void setSize(ValueType newWidth, ValueType newHeight) noexcept
Changes the rectangle's size, leaving the position of its top-left corner unchanged.
ValueType getWidth() const noexcept
Returns the width of the rectangle.
void setPosition(Point< ValueType > newPos) noexcept
Changes the position of the rectangle's top-left corner (leaving its size unchanged).
ValueType getY() const noexcept
Returns the y coordinate of the rectangle's top edge.
bool isEmpty() const noexcept
Returns true if the rectangle's width or height are zero or less.
Rectangle withTop(ValueType newTop) const noexcept
Returns a new rectangle with a different y position, but the same bottom edge as this one.
ValueType getHeight() const noexcept
Returns the height of the rectangle.
Rectangle expanded(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is larger than this one by a given amount.
void setBounds(ValueType newX, ValueType newY, ValueType newWidth, ValueType newHeight) noexcept
Changes all the rectangle's coordinates.
A smart-pointer class which points to a reference-counted object.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
static uint32 getApproximateMillisecondCounter() noexcept
Less-accurate but faster version of getMillisecondCounter().
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).
Makes repeated callbacks to a virtual method at a specified time interval.
void startTimerHz(int timerFrequencyHz) noexcept
Starts the timer with an interval specified in Hertz.
This class acts as a pointer which will automatically become null if the object to which it points is...
Type * createCopyIfNotNull(const Type *objectToCopy)
If a pointer is non-null, this returns a new copy of the object that it points to,...
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Returns a default-constructed sentinel value.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
@ rowSelectionChanged
Indicates that the selection of rows in a list or table has changed.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
@ showMenu
Represents the user showing a contextual menu for a UI element.
@ focus
Indicates that the UI element has received focus.
@ toggle
Represents a "toggle" action.
@ press
Represents a "press" action.
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
int CommandID
A type used to hold the unique ID for an application command.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
AccessibilityRole
The list of available roles for an AccessibilityHandler object.
Contains status information about a mouse wheel event.
Holds information describing an application command.
int flags
A bitwise-OR of the values specified in the CommandFlags enum.
@ isTicked
Indicates that the command should have a tick next to it on a menu.
@ isDisabled
Indicates that the command can't currently be performed.
String shortName
A short name to describe the command.
Contains contextual details about the invocation of a command.
InvocationMethod invocationMethod
The type of event that triggered this command.
virtual int getPopupMenuColumnSeparatorWidthWithOptions(const Options &)=0
Return the amount of space that should be left between popup menu columns.
virtual void getIdealPopupMenuItemSizeWithOptions(const String &text, bool isSeparator, int standardMenuItemHeight, int &idealWidth, int &idealHeight, const Options &)=0
Finds the best size for an item in a popup menu.
virtual void drawPopupMenuItemWithOptions(Graphics &, const Rectangle< int > &area, bool isHighlighted, const Item &item, const Options &)=0
Draws one of the items in a popup menu.
virtual void getIdealPopupMenuItemSize(const String &text, bool isSeparator, int standardMenuItemHeight, int &idealWidth, int &idealHeight)
Finds the best size for an item in a popup menu.
virtual void drawPopupMenuBackground(Graphics &, int width, int height)
Fills the background of a popup menu component.
virtual void drawPopupMenuItem(Graphics &, const Rectangle< int > &area, bool isSeparator, bool isActive, bool isHighlighted, bool isTicked, bool hasSubMenu, const String &text, const String &shortcutKeyText, const Drawable *icon, const Colour *textColour)
Draws one of the items in a popup menu.