Store the names of commands in the menu rather than references to the commands themselves, to avoid crashes with dynamically created and removed commands. This makes most menu operations a bit slower, but it appears to be sufficiently fast.
Originally committed to SVN as r6259.
This commit is contained in:
parent
1801583ed7
commit
a0fcd535c1
1 changed files with 22 additions and 20 deletions
|
@ -58,7 +58,7 @@ using std::tr1::bind;
|
||||||
class MruMenu : public wxMenu {
|
class MruMenu : public wxMenu {
|
||||||
std::string type;
|
std::string type;
|
||||||
std::vector<wxMenuItem *> items;
|
std::vector<wxMenuItem *> items;
|
||||||
std::vector<cmd::Command*> *cmds;
|
std::vector<std::string> *cmds;
|
||||||
|
|
||||||
void Resize(size_t new_size) {
|
void Resize(size_t new_size) {
|
||||||
for (size_t i = GetMenuItemCount(); i > new_size; --i) {
|
for (size_t i = GetMenuItemCount(); i > new_size; --i) {
|
||||||
|
@ -68,14 +68,14 @@ class MruMenu : public wxMenu {
|
||||||
for (size_t i = GetMenuItemCount(); i < new_size; ++i) {
|
for (size_t i = GetMenuItemCount(); i < new_size; ++i) {
|
||||||
if (i >= items.size()) {
|
if (i >= items.size()) {
|
||||||
items.push_back(new wxMenuItem(this, MENU_ID_BASE + cmds->size(), "_"));
|
items.push_back(new wxMenuItem(this, MENU_ID_BASE + cmds->size(), "_"));
|
||||||
cmds->push_back(cmd::get(STD_STR(wxString::Format("recent/%s/%d", lagi_wxString(type).Lower(), (int)i))));
|
cmds->push_back(STD_STR(wxString::Format("recent/%s/%d", lagi_wxString(type).Lower(), (int)i)));
|
||||||
}
|
}
|
||||||
Append(items[i]);
|
Append(items[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MruMenu(std::string const& type, std::vector<cmd::Command*> *cmds)
|
MruMenu(std::string const& type, std::vector<std::string> *cmds)
|
||||||
: type(type)
|
: type(type)
|
||||||
, cmds(cmds)
|
, cmds(cmds)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +114,7 @@ public:
|
||||||
struct menu_item_cmp {
|
struct menu_item_cmp {
|
||||||
wxMenuItem *item;
|
wxMenuItem *item;
|
||||||
menu_item_cmp(wxMenuItem *item) : item(item) { }
|
menu_item_cmp(wxMenuItem *item) : item(item) { }
|
||||||
bool operator()(std::pair<cmd::Command*, wxMenuItem*> o) const {
|
bool operator()(std::pair<std::string, wxMenuItem*> const& o) const {
|
||||||
return o.second == item;
|
return o.second == item;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -128,11 +128,11 @@ struct menu_item_cmp {
|
||||||
/// handlers makes everything involves events unusably slow.
|
/// handlers makes everything involves events unusably slow.
|
||||||
class CommandManager {
|
class CommandManager {
|
||||||
/// Menu items which need to do something on menu open
|
/// Menu items which need to do something on menu open
|
||||||
std::deque<std::pair<cmd::Command*, wxMenuItem*> > dynamic_items;
|
std::deque<std::pair<std::string, wxMenuItem*> > dynamic_items;
|
||||||
/// Menu items which need to be updated only when hotkeys change
|
/// Menu items which need to be updated only when hotkeys change
|
||||||
std::deque<std::pair<cmd::Command*, wxMenuItem*> > static_items;
|
std::deque<std::pair<std::string, wxMenuItem*> > static_items;
|
||||||
/// window id -> command map
|
/// window id -> command map
|
||||||
std::vector<cmd::Command*> items;
|
std::vector<std::string> items;
|
||||||
/// MRU menus which need to be updated on menu open
|
/// MRU menus which need to be updated on menu open
|
||||||
std::deque<MruMenu*> mru;
|
std::deque<MruMenu*> mru;
|
||||||
|
|
||||||
|
@ -143,14 +143,15 @@ class CommandManager {
|
||||||
agi::signal::Connection hotkeys_changed;
|
agi::signal::Connection hotkeys_changed;
|
||||||
|
|
||||||
/// Update a single dynamic menu item
|
/// Update a single dynamic menu item
|
||||||
void UpdateItem(std::pair<cmd::Command*, wxMenuItem*> const& item) {
|
void UpdateItem(std::pair<std::string, wxMenuItem*> const& item) {
|
||||||
int flags = item.first->Type();
|
cmd::Command *c = cmd::get(item.first);
|
||||||
|
int flags = c->Type();
|
||||||
if (flags & cmd::COMMAND_DYNAMIC_NAME)
|
if (flags & cmd::COMMAND_DYNAMIC_NAME)
|
||||||
UpdateItemName(item);
|
UpdateItemName(item);
|
||||||
if (flags & cmd::COMMAND_VALIDATE)
|
if (flags & cmd::COMMAND_VALIDATE)
|
||||||
item.second->Enable(item.first->Validate(context));
|
item.second->Enable(c->Validate(context));
|
||||||
if (flags & cmd::COMMAND_RADIO || flags & cmd::COMMAND_TOGGLE) {
|
if (flags & cmd::COMMAND_RADIO || flags & cmd::COMMAND_TOGGLE) {
|
||||||
bool check = item.first->IsActive(context);
|
bool check = c->IsActive(context);
|
||||||
// Don't call Check(false) on radio items as this causes wxGtk to
|
// Don't call Check(false) on radio items as this causes wxGtk to
|
||||||
// send a menu clicked event, and it should be a no-op anyway
|
// send a menu clicked event, and it should be a no-op anyway
|
||||||
if (check || flags & cmd::COMMAND_TOGGLE)
|
if (check || flags & cmd::COMMAND_TOGGLE)
|
||||||
|
@ -158,13 +159,14 @@ class CommandManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateItemName(std::pair<cmd::Command*, wxMenuItem*> const& item) {
|
void UpdateItemName(std::pair<std::string, wxMenuItem*> const& item) {
|
||||||
|
cmd::Command *c = cmd::get(item.first);
|
||||||
wxString text;
|
wxString text;
|
||||||
if (item.first->Type() & cmd::COMMAND_DYNAMIC_NAME)
|
if (c->Type() & cmd::COMMAND_DYNAMIC_NAME)
|
||||||
text = item.first->StrMenu(context);
|
text = c->StrMenu(context);
|
||||||
else
|
else
|
||||||
text = item.second->GetItemLabel().BeforeFirst('\t');
|
text = item.second->GetItemLabel().BeforeFirst('\t');
|
||||||
item.second->SetItemLabel(text + "\t" + hotkey::get_hotkey_str_first("Default", item.first->name()));
|
item.second->SetItemLabel(text + "\t" + hotkey::get_hotkey_str_first("Default", c->name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -192,19 +194,19 @@ public:
|
||||||
item->SetBitmap(co->Icon(16));
|
item->SetBitmap(co->Icon(16));
|
||||||
#endif
|
#endif
|
||||||
parent->Append(item);
|
parent->Append(item);
|
||||||
items.push_back(co);
|
items.push_back(co->name());
|
||||||
|
|
||||||
if (flags != cmd::COMMAND_NORMAL)
|
if (flags != cmd::COMMAND_NORMAL)
|
||||||
dynamic_items.push_back(std::make_pair(co, item));
|
dynamic_items.push_back(std::make_pair(co->name(), item));
|
||||||
else
|
else
|
||||||
static_items.push_back(std::make_pair(co, item));
|
static_items.push_back(std::make_pair(co->name(), item));
|
||||||
|
|
||||||
return item->GetId();
|
return item->GetId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unregister a dynamic menu item
|
/// Unregister a dynamic menu item
|
||||||
void Remove(wxMenuItem *item) {
|
void Remove(wxMenuItem *item) {
|
||||||
std::deque<std::pair<cmd::Command*, wxMenuItem*> >::iterator it =
|
std::deque<std::pair<std::string, wxMenuItem*> >::iterator it =
|
||||||
find_if(dynamic_items.begin(), dynamic_items.end(), menu_item_cmp(item));
|
find_if(dynamic_items.begin(), dynamic_items.end(), menu_item_cmp(item));
|
||||||
if (it != dynamic_items.end())
|
if (it != dynamic_items.end())
|
||||||
dynamic_items.erase(it);
|
dynamic_items.erase(it);
|
||||||
|
@ -228,7 +230,7 @@ public:
|
||||||
// the window ID ranges really need to be unique
|
// the window ID ranges really need to be unique
|
||||||
size_t id = static_cast<size_t>(evt.GetId() - MENU_ID_BASE);
|
size_t id = static_cast<size_t>(evt.GetId() - MENU_ID_BASE);
|
||||||
if (id < items.size())
|
if (id < items.size())
|
||||||
(*items[id])(context);
|
cmd::call(items[id], context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the hotkeys for all menu items
|
/// Update the hotkeys for all menu items
|
||||||
|
|
Loading…
Reference in a new issue