/
PopupMenu.cpp
152 lines (125 loc) · 3.35 KB
/
PopupMenu.cpp
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