Skip to content

Commit

Permalink
Add event handler to refresh menus on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Jan 4, 2017
1 parent 8e5747b commit d37f00d
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 55 deletions.
33 changes: 31 additions & 2 deletions plugins/uimanager/menu/MenuBar.cpp
Expand Up @@ -2,6 +2,8 @@

#include <wx/menu.h>

#include "MenuFolder.h"

namespace ui
{

Expand All @@ -13,14 +15,16 @@ wxMenuBar* MenuBar::getWidget()
{
if (_menuBar == nullptr)
{
constructWidget();
construct();
}

return _menuBar;
}

void MenuBar::constructWidget()
void MenuBar::construct()
{
_needsRefresh = false;

if (_menuBar != nullptr)
{
MenuElement::constructChildren();
Expand All @@ -29,6 +33,18 @@ void MenuBar::constructWidget()

_menuBar = new wxMenuBar;

// Set up the listener ensuring that the opened menu is up to date
_menuBar->Bind(wxEVT_MENU_OPEN, [&](wxMenuEvent& ev)
{
MenuElementPtr menu = findMenu(ev.GetMenu());

if (menu && menu->needsRefresh() && std::dynamic_pointer_cast<MenuFolder>(menu))
{
// Rebuild this entire menu
std::static_pointer_cast<MenuFolder>(menu)->refresh();
}
});

MenuElement::constructChildren();
}

Expand All @@ -43,4 +59,17 @@ void MenuBar::deconstruct()
}
}

MenuElementPtr MenuBar::findMenu(wxMenu* menu)
{
for (const MenuElementPtr& candidate : _children)
{
if (candidate->getWidget() == menu)
{
return candidate;
}
}

return MenuElementPtr();
}

}
6 changes: 4 additions & 2 deletions plugins/uimanager/menu/MenuBar.h
Expand Up @@ -17,10 +17,12 @@ class MenuBar :

virtual wxMenuBar* getWidget() override;

protected:
virtual void construct() override;
virtual void deconstruct() override;

protected:
virtual void constructWidget() override;
private:
MenuElementPtr findMenu(wxMenu* menu);
};

}
Expand Down
31 changes: 27 additions & 4 deletions plugins/uimanager/menu/MenuElement.cpp
Expand Up @@ -30,7 +30,8 @@ MenuElement::MenuElement(const MenuElementPtr& parent) :
_widget(nullptr),
_type(menuNothing),
_constructed(false),
_isVisible(true)
_isVisible(true),
_needsRefresh(false)
{}

MenuElement::~MenuElement()
Expand Down Expand Up @@ -206,6 +207,7 @@ int MenuElement::getMenuPosition(const MenuElementPtr& child)
return -1; // not found or wrong type
}

#if 0
wxObject* MenuElement::getWidget()
{
// Check for toggle, allocate the Gtk::Widget*
Expand All @@ -216,6 +218,7 @@ wxObject* MenuElement::getWidget()

return _widget;
}
#endif

MenuElementPtr MenuElement::find(const std::string& menuPath)
{
Expand Down Expand Up @@ -252,9 +255,9 @@ MenuElementPtr MenuElement::find(const std::string& menuPath)
return MenuElementPtr();
}

#if 0
void MenuElement::construct()
{
#if 0
if (_type == menuBar)
{
wxMenuBar* menuBar = new wxMenuBar;
Expand Down Expand Up @@ -371,8 +374,8 @@ void MenuElement::construct()
}

_constructed = true;
#endif
}
#endif

void MenuElement::connectEvent()
{
Expand Down Expand Up @@ -405,6 +408,16 @@ void MenuElement::disconnectEvent()
}
}

bool MenuElement::needsRefresh()
{
return _needsRefresh;
}

void MenuElement::setNeedsRefresh(bool needsRefresh)
{
_needsRefresh = needsRefresh;
}

void MenuElement::setWidget(wxObject* object)
{
// Disconnect the old widget before setting a new one
Expand Down Expand Up @@ -476,11 +489,21 @@ MenuElementPtr MenuElement::CreateFromNode(const xml::Node& node)
return item;
}

void MenuElement::setNeedsRefreshRecursively(bool needsRefresh)
{
setNeedsRefresh(needsRefresh);

for (const MenuElementPtr& child : _children)
{
child->setNeedsRefreshRecursively(needsRefresh);
}
}

void MenuElement::constructChildren()
{
for (const MenuElementPtr& child : _children)
{
child->constructWidget();
child->construct();
}
}

Expand Down
30 changes: 16 additions & 14 deletions plugins/uimanager/menu/MenuElement.h
Expand Up @@ -52,6 +52,10 @@ class MenuElement :

bool _isVisible;

// Checked if anything in this item or below has changed
// and needs reconstruction the next time the menu is opened
bool _needsRefresh;

static int _nextMenuItemId;

public:
Expand Down Expand Up @@ -116,17 +120,14 @@ class MenuElement :
void connectEvent();
void disconnectEvent();

bool needsRefresh();
void setNeedsRefresh(bool needsRefresh);

// Use this to get the corresponding wx menu widget out of this item.
virtual wxObject* getWidget() = 0;

void setWidget(wxObject* object);

// Destroys the wxWidget instantiation of this element and all children
// (which also nullifies the widget pointers). Next time
// the getWidget() method is called the widgets will be reconstructed.
// Subclasses should override this
virtual void deconstruct() = 0;

// Tries to (recursively) locate the MenuElement by looking up the path
MenuElementPtr find(const std::string& menuPath);

Expand All @@ -137,22 +138,23 @@ class MenuElement :
static MenuElementPtr CreateFromNode(const xml::Node& node);

protected:
void setNeedsRefreshRecursively(bool needsRefresh);

// Instantiates this all current child elements recursively as wxObjects
// to be overridden by subclasses
virtual void constructWidget() = 0;
virtual void construct() = 0;

// Destroys the wxWidget instantiation of this element and all children
// (which also nullifies the widget pointers). Next time
// the getWidget() method is called the widgets will be reconstructed.
// Subclasses should override this
virtual void deconstruct() = 0;

// This default implementaton here does as exepected: constructs all children
virtual void constructChildren();

// This default implementation passes the deconstruct() call to all children
virtual void deconstructChildren();

private:
/** greebo: This constructs the actual widgets. This is invoked as soon
* as the first getWidget of this object is requested.
* DEPRECATED
*/
void construct();
};

} // namespace ui
27 changes: 17 additions & 10 deletions plugins/uimanager/menu/MenuFolder.cpp
Expand Up @@ -19,13 +19,21 @@ wxMenu* MenuFolder::getWidget()
{
if (_menu == nullptr)
{
constructWidget();
construct();
}

return _menu;
}

void MenuFolder::constructWidget()
void MenuFolder::refresh()
{
deconstructChildren();
constructChildren();

setNeedsRefreshRecursively(false);
}

void MenuFolder::construct()
{
if (_menu != nullptr)
{
Expand Down Expand Up @@ -70,7 +78,7 @@ void MenuFolder::deconstruct()
{
if (_parentItem->GetMenu() != nullptr)
{
// This is a submenu, we can just rely on the parent item deleting the _menu object
// This is a submenu, remove the item we're attached to first
_parentItem->GetMenu()->Delete(_parentItem);
}
else
Expand All @@ -80,9 +88,6 @@ void MenuFolder::deconstruct()
}

_parentItem = nullptr;

// Parent item deleted the _menu already in its destructor
_menu = nullptr;
}

if (_menu != nullptr)
Expand All @@ -102,11 +107,13 @@ void MenuFolder::deconstruct()
}
}
}

// Regardless of whether we have a bar attached, we need to delete the menu
delete _menu;
_menu = nullptr;
}

// Regardless what happened before, we need to delete the menu ourselves
// (Any parent item didn't delete the _menu in its destructor
// as wxWidgets nullified the submenu member before deleting it)
delete _menu;
_menu = nullptr;
}

}
6 changes: 5 additions & 1 deletion plugins/uimanager/menu/MenuFolder.h
Expand Up @@ -21,8 +21,12 @@ class MenuFolder :

virtual wxMenu* getWidget() override;

// Empties this menu and rebuilds the wxWidget objects
// Clears the needsRefresh flag on this object and all children
void refresh();

protected:
virtual void constructWidget() override;
virtual void construct() override;
virtual void deconstruct() override;
};

Expand Down
4 changes: 2 additions & 2 deletions plugins/uimanager/menu/MenuItem.cpp
Expand Up @@ -17,13 +17,13 @@ wxMenuItem* MenuItem::getWidget()
{
if (_menuItem == nullptr)
{
constructWidget();
construct();
}

return _menuItem;
}

void MenuItem::constructWidget()
void MenuItem::construct()
{
if (_menuItem != nullptr)
{
Expand Down
5 changes: 2 additions & 3 deletions plugins/uimanager/menu/MenuItem.h
Expand Up @@ -18,10 +18,9 @@ class MenuItem :

virtual wxMenuItem* getWidget() override;

virtual void deconstruct() override;

protected:
virtual void constructWidget() override;
virtual void construct() override;
virtual void deconstruct() override;
};

}
24 changes: 14 additions & 10 deletions plugins/uimanager/menu/MenuManager.cpp
Expand Up @@ -67,12 +67,12 @@ void MenuManager::setVisibility(const std::string& path, bool visible)
{
element->setIsVisible(visible);

// The corresponding menu should be reconstructed
MenuElementPtr parentMenu = findParentMenu(element);
// The corresponding top level menu needs reconstruction
MenuElementPtr parentMenu = findTopLevelMenu(element);

if (parentMenu)
{
//parentMenu->deconstruct();
parentMenu->setNeedsRefresh(true);
}
}
}
Expand Down Expand Up @@ -418,18 +418,22 @@ void MenuManager::remove(const std::string& path)
#endif
}

MenuElementPtr MenuManager::findParentMenu(const MenuElementPtr& element)
MenuElementPtr MenuManager::findTopLevelMenu(const MenuElementPtr& element)
{
if (!element) return MenuElementPtr();
MenuElementPtr candidate = element;

MenuElementPtr parent = element->getParent();

while (parent)
while (candidate)
{
if (std::dynamic_pointer_cast<MenuFolder>(parent))
MenuElementPtr parent = candidate->getParent();

if (candidate &&
std::dynamic_pointer_cast<MenuFolder>(candidate) &&
std::dynamic_pointer_cast<MenuBar>(parent))
{
return parent;
return candidate;
}

candidate = parent;
}

return MenuElementPtr();
Expand Down
4 changes: 2 additions & 2 deletions plugins/uimanager/menu/MenuManager.h
Expand Up @@ -83,8 +83,8 @@ class MenuManager :
void clear();

private:
// Returns the parent menu (== MenuFolder) for the given element
MenuElementPtr findParentMenu(const MenuElementPtr& element);
// Returns the top level menu (== MenuFolder) this element is part of
MenuElementPtr findTopLevelMenu(const MenuElementPtr& element);
};

} // namespace ui

0 comments on commit d37f00d

Please sign in to comment.