commit cff8002912e2fbd52d9904edabc930a9aa077fe5
parent 7a6fd17c3d31fd728820bd3aa259894d7efbedb3
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Thu, 9 Feb 2023 22:33:28 +0100
Ability to create multiple independent menus
- Menu is no longer static
- Extract display logic to separate cpp file
Diffstat:
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;
-}