stamen

Static Menu Generator
git clone git://git.dimitrijedobrota.com/stamen.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit cff8002912e2fbd52d9904edabc930a9aa077fe5
parent 7a6fd17c3d31fd728820bd3aa259894d7efbedb3
author Dimitrije Dobrota <mail@dimitrijedobrota.com>
date Thu, 9 Feb 2023 21:33:28 +0100

Ability to create multiple independent menus - Menu is no longer static - Extract display logic to separate cpp file

Diffstat:
M .ccls | + -
M Makefile | + -
M include/menu.h | +++++++++++++++++++++++++++ -----------------
A src/display.cpp | ++++++++++++++++++++++++++++++++
M src/main.cpp | +++++ -------
M src/menu.cpp | + ----------------------------------

6 files changed, 67 insertions(+), 60 deletions(-)


diff --git a/ .ccls b/ .ccls

@@ -1,4 +1,4 @@ clang++ -style=file
%c++ -std=c++17
-std=c++17
-Iinclude

diff --git a/ Makefile b/ Makefile

@@ -5,7 +5,7 @@ SRC = src INC = include BUILD = build
CFLAGS = -I$(INC)
CFLAGS = -I$(INC) --std=c++17
LDFLAGS = SRCS := $(wildcard $(SRC)/*.cpp)

diff --git a/ include/menu.h b/ include/menu.h

@@ -3,10 +3,13 @@ #include "json.hpp" #include <exception>
#include <fstream>
#include <string> #include <unordered_map> #include <vector>
using json = nlohmann::json;
using std::string, std::vector;
class EMenu_callback : std::exception { virtual const char *what() const noexcept override {

@@ -23,33 +26,40 @@ class EMenu_call : std::exception { class Menu { public: typedef int (*Menu_f)(void);
static void Register(const std::string &s, Menu_f f) {
Menu() : function_lookup() {}
Menu(const string &s) : Menu() {
std::fstream f(s);
Read(f);
}
void Start() const { get_callback("main")(); }
void Read(std::istream &is);
Menu &Register(const string &s, Menu_f f) {
function_lookup.insert({s, f});
return *this;
}
static void Start() { get_callback("main")(); }
static void Read(std::istream &is);
private:
Menu() = delete;
struct Menu_item {
const std::string prompt;
const std::string callback;
const string prompt;
const string callback;
Menu_item(const std::string &p, const std::string &c)
: prompt(p), callback(c) {}
Menu_item(const string &p, const string &c) : prompt(p), callback(c) {}
Menu_item(const json &j) : Menu_item(j["prompt"], j["callback"]) {} }; struct Menu_function {
Menu_function(const std::string &n, const std::vector<Menu_item> &i)
: name(n), items(i) {}
Menu_function(const Menu &m, const string &n, const vector<Menu_item> &i)
: menu(m), name(n), items(i) {}
int call() const;
int display() const;
private:
const std::string name;
const std::vector<Menu_item> items;
const Menu &menu;
const string name;
const vector<Menu_item> items;
}; struct Menu_callback {

@@ -61,17 +71,17 @@ private: int operator()() const { if (!func && !menu_func) throw EMenu_callback();
return func ? func() : menu_func->call();
return func ? func() : menu_func->display();
} };
static const Menu_callback &get_callback(const std::string &s) {
const Menu_callback &get_callback(const string &s) const {
auto it = function_lookup.find(s); if (it == function_lookup.end()) throw EMenu_call(); return (*it).second; }
static std::unordered_map<std::string, Menu_callback> function_lookup;
std::unordered_map<string, Menu_callback> function_lookup;
}; #endif

diff --git a/ src/display.cpp b/ src/display.cpp

@@ -0,0 +1,32 @@
#include "menu.h"
#include <iostream>
int Menu::Menu_function::display() const {
unsigned long choice;
while (true) {
std::cout << name << std::endl;
for (auto i = 0ul; i < items.size(); i++)
std::cout << i << ". " << items[i].prompt << std::endl;
while (true) {
std::cout << "Choose an option: ";
if (std::cin >> choice && choice < items.size()) {
std::cout << "Chosen: " << items[choice].prompt << "\n\n";
int res = menu.get_callback(items[choice].callback)();
if (--res) return res;
break;
} else if (std::cin.eof()) {
std::cerr << "encountered end of input!\n";
return std::numeric_limits<int>::max();
} else {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "Invalid option, please choose again!" << std::endl;
}
std::cout << std::endl;
}
return 1;
}

diff --git a/ src/main.cpp b/ src/main.cpp

@@ -1,5 +1,4 @@ #include "menu.h"
#include <fstream>
#include <iostream> int algorithms(void) {

@@ -18,11 +17,10 @@ int finish(void) { } int main(void) {
std::fstream f("menu.json");
Menu::Register("algorithms", algorithms);
Menu::Read(f);
Menu::Register("settings", settings);
Menu::Register("finish", finish);
Menu::Start();
Menu menu("menu.json");
menu.Register("algorithms", algorithms)
.Register("settings", settings)
.Register("finish", finish);
menu.Start();
return 0; }

diff --git a/ src/menu.cpp b/ src/menu.cpp

@@ -1,44 +1,11 @@ #include "menu.h"
#include <iostream>
std::unordered_map<std::string, Menu::Menu_callback> Menu::function_lookup;
void Menu::Read(std::istream &is) { json file = json::parse(is); for (auto &menu : file) { const json &items = menu["items"]; const Menu_function *mf =
new Menu_function(menu["name"], {items.begin(), items.end()});
new Menu_function(*this, menu["name"], {items.begin(), items.end()});
function_lookup.insert({menu["code"], Menu_callback(mf)}); } }
int Menu::Menu_function::call() const {
unsigned long choice;
while (true) {
std::cout << name << std::endl;
for (auto i = 0ul; i < items.size(); i++)
std::cout << i << ". " << items[i].prompt << std::endl;
while (true) {
std::cout << "Choose an option: ";
if (std::cin >> choice && choice < items.size()) {
std::cout << "Chosen: " << items[choice].prompt << "\n\n";
int res = get_callback(items[choice].callback)();
if (--res) return res;
break;
} else if (std::cin.eof()) {
std::cerr << "encountered end of input!\n";
return std::numeric_limits<int>::max();
} else {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "Invalid option, please choose again!" << std::endl;
}
std::cout << std::endl;
}
return 1;
}