#include <iostream>
#include <stack>
class MenuItem
{
public:
constexpr MenuItem(auto name, std::add_pointer_t<void()> handler) :
_name(name),
_handler(handler),
_isLeaf(true)
{
}
constexpr MenuItem(auto name, auto... childs) :
_name(name),
_handler(nullptr),
_childsCount(sizeof...(childs)),
_isLeaf(false)
{
int i = 0;
for (auto child : { childs... })
{
_childs[i++] = child;
}
}
constexpr std::string_view GetName() const
{
return _name;
}
constexpr bool IsLeaf() const
{
return _isLeaf;
}
constexpr std::add_pointer_t<void()> GetHandler() const
{
return _handler;
}
constexpr const MenuItem* GetChild(int number) const
{
return _childs[number];
}
constexpr int GetChildsCount() const
{
return _childsCount;
}
private:
std::string_view _name;
std::add_pointer_t<void()> _handler;
const MenuItem* _childs[10] = {nullptr};
const int _childsCount = 0;
bool _isLeaf;
};
class Menu : public MenuItem
{
public:
constexpr Menu(auto... childs) : MenuItem("", childs...)
{
}
void Choose(int choise)
{
if (_breadCrumbs.size() > 0 && choise == _breadCrumbs.top()->GetChildsCount())
{
_breadCrumbs.pop();
return;
}
if ((!_breadCrumbs.empty() ? _breadCrumbs.top() : this)->GetChild(choise)->IsLeaf())
{
if (!_breadCrumbs.empty())
_breadCrumbs.top()->GetChild(choise)->GetHandler()();
else
this->GetChild(choise)->GetHandler()();
}
else
{
_breadCrumbs.push((!_breadCrumbs.empty() ? _breadCrumbs.top() : this)->GetChild(choise));
}
}
std::ostream& PrintMenu(std::ostream& stream)
{
for (int i = 0; i < (!_breadCrumbs.empty() ? _breadCrumbs.top() : this)->GetChildsCount(); ++i)
{
stream << i + 1 << ". " << (!_breadCrumbs.empty() ? _breadCrumbs.top() : this)->GetChild(i)->GetName() << std::endl;
}
if(!_breadCrumbs.empty())
stream << _breadCrumbs.top()->GetChildsCount() + 1 << ". Back" << std::endl;
return stream;
}
private:
std::stack<const MenuItem*> _breadCrumbs;
};
void L11Handler()
{
std::cout << "I'm L11 handler" << std::endl;
}
void L12Handler()
{
std::cout << "I'm L12 handler" << std::endl;
}
void L2Handler()
{
std::cout << "I'm L2 handler" << std::endl;
}
constexpr MenuItem l11("Menu11", L11Handler);
constexpr MenuItem l12("Menu12", L12Handler);
constexpr MenuItem m1("Menu1", &l11, &l12);
constexpr MenuItem m2("Menu2", L2Handler);
Menu Root(&m1, &m2);
int main()
{
int choise = 0;
while (true)
{
Root.PrintMenu(std::cout);
std::cout << "Input choise->";
std::cin >> choise;
--choise;
Root.Choose(choise);
}
}