1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#include "PopupMenu.h"
#include "SeparatorItem.h"
namespace wxutil
{
// Default constructor
PopupMenu::PopupMenu() :
wxMenu()
{
Bind(wxEVT_MENU, &PopupMenu::_onItemClick, this);
}
PopupMenu::~PopupMenu()
{}
// Add a named menu item
void PopupMenu::addItem(wxMenuItem* widget,
const Callback& callback,
const SensitivityTest& sensTest,
const VisibilityTest& visTest)
{
// Construct a wrapper and pass to specialised method
addItem(std::make_shared<wxutil::MenuItem>(widget, callback, sensTest, visTest));
}
void PopupMenu::addItem(const ui::IMenuItemPtr& item)
{
_menuItems.push_back(item);
// Add the widget to the menu
Append(item->getMenuItem());
}
void PopupMenu::addSeparator()
{
addItem(std::make_shared<SeparatorItem>(
new wxMenuItem(this, wxID_ANY, wxEmptyString, wxEmptyString, wxITEM_SEPARATOR))
);
}
void PopupMenu::attachItem(const ui::IMenuItemPtr& item, int position)
{
if (item->getMenuItem()->GetMenu() == nullptr)
{
Insert(position, item->getMenuItem());
}
}
void PopupMenu::detachItem(const ui::IMenuItemPtr& item)
{
if (item->getMenuItem()->GetMenu() != nullptr)
{
Remove(item->getMenuItem());
}
}
bool PopupMenu::itemIsVisible(int index, int menuPosition)
{
const auto& item = _menuItems[index];
// Call the user visibility check
bool visible = item->isVisible();
if (!visible)
{
// Item is hidden
return false;
}
// Special treatment for separators
if (item->getMenuItem()->IsSeparator())
{
// Trim separators from the beginning or the end of the menu
if (menuPosition == 0 || index + 1 >= _menuItems.size())
{
return false;
}
// Skip all consecutive seprators except for the last
if (index + 1 < _menuItems.size() && _menuItems[index + 1]->getMenuItem()->IsSeparator())
{
return false;
}
}
return true;
}
void PopupMenu::show(wxWindow* parent)
{
// Iterate through the list of MenuItems, showing/hiding and enabling/disabling each widget
// based on its test functions
int position = 0;
for (auto i = 0; i < _menuItems.size(); ++i)
{
const auto& item = _menuItems[i];
if (!itemIsVisible(i, position))
{
// Visibility check failed, detach and skip sensitivity check
// Don't increase the position counter
detachItem(item);
continue;
}
// Make sure visible items are attached, increase position
attachItem(item, position++);
// Perform the sensitivity check on visible items
item->getMenuItem()->Enable(item->isSensitive());
}
// Detach any separator that might end up at the bottom of the menu
if (GetMenuItemCount() > 0)
{
auto lastItem = FindItemByPosition(GetMenuItemCount() - 1);
if (lastItem && lastItem->IsSeparator())
{
Remove(lastItem);
}
}
parent->PopupMenu(this);
}
void PopupMenu::_onItemClick(wxCommandEvent& ev)
{
int commandId = ev.GetId();
// Find the menu item with that ID
for (auto item : _menuItems)
{
if (item->getMenuItem()->GetId() == commandId)
{
item->execute();
break;
}
}
}
void PopupMenu::foreachMenuItem(const std::function<void(const ui::IMenuItemPtr&)>& functor)
{
for (const auto& item : _menuItems)
{
functor(item);
}
}
} // namespace
|