stamen

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

commitcff8002912e2fbd52d9904edabc930a9aa077fe5
parent7a6fd17c3d31fd728820bd3aa259894d7efbedb3
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateThu, 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|+-
MMakefile|+-
Minclude/menu.h|+++++++++++++++++++++++++++-----------------
Asrc/display.cpp|++++++++++++++++++++++++++++++++
Msrc/main.cpp|+++++-------
Msrc/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;
}