commit 260569531d18b4c35adeaa7b53c866ebea1e2d28
parent 0ab8d3b1b0cae32d598a861f4fa04f95b348d54c
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Tue, 7 Nov 2023 01:37:21 +0000
Refactoring
* Better initializastion of function lookup
* Consturctor now reads configuration directly
* More consistent menu display
* Remove menu.cpp
* Renaming
* Start menu with operator()
Diffstat:
6 files changed, 66 insertions(+), 59 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
Menu
- VERSION 0.0.1
+ VERSION 0.0.2
DESCRIPTION "Experimentation with dinamic menus"
LANGUAGES CXX
)
diff --git a/include/menu.h b/include/menu.h
@@ -9,7 +9,6 @@
#include <vector>
using json = nlohmann::json;
-using std::string, std::vector;
class EMenu_callback : std::exception {
virtual const char *what() const noexcept override {
@@ -25,49 +24,60 @@ class EMenu_call : std::exception {
class Menu {
public:
- typedef int (*Menu_f)(void);
-
- Menu() : function_lookup() {}
- Menu(const string &s) : Menu() {
- std::fstream f(s);
- Read(f);
+ typedef int (*callback_f)(void);
+
+ Menu(const std::string &s) {
+ for (const auto &menu : json::parse(std::fstream(s))) {
+ const json &items = menu["items"];
+ const function_t *mf =
+ new function_t(*this, menu["name"], {items.begin(), items.end()});
+ lookup.insert({menu["code"], callback_t(mf)});
+ }
}
- void Start() const { get_callback("main")(); }
+ void operator()() const { get_callback("main")(); }
- void Read(std::istream &is);
- Menu &Register(const string &s, Menu_f f) {
- function_lookup.insert({s, f});
- return *this;
+ struct record_t {
+ const std::string code;
+ const callback_f callback;
+ };
+
+ void insert(const record_t &record) {
+ lookup.insert({record.code, record.callback});
+ }
+ void insert(const std::vector<record_t> &records) {
+ for (const auto &record : records) { insert(record); }
}
private:
- struct Menu_item {
- const string prompt;
- const string callback;
+ struct item_t {
+ const std::string prompt;
+ const std::string callback;
- Menu_item(const string &p, const string &c) : prompt(p), callback(c) {}
- Menu_item(const json &j) : Menu_item(j["prompt"], j["callback"]) {}
+ item_t(const std::string &p, const std::string &c)
+ : prompt(p), callback(c) {}
+ item_t(const json &j) : item_t(j["prompt"], j["callback"]) {}
};
- struct Menu_function {
- Menu_function(const Menu &m, const string &n, const vector<Menu_item> &i)
+ struct function_t {
+ function_t(const Menu &m, const std::string &n,
+ const std::vector<item_t> &i)
: menu(m), name(n), items(i) {}
int display() const;
private:
const Menu &menu;
- const string name;
- const vector<Menu_item> items;
+ const std::string name;
+ const std::vector<item_t> items;
};
- struct Menu_callback {
- const Menu_f func = nullptr;
- const Menu_function *menu_func = nullptr;
+ struct callback_t {
+ const function_t *menu_func = nullptr;
+ const callback_f func = nullptr;
- Menu_callback(const Menu_f f) : func(f) {}
- Menu_callback(const Menu_function *f) : menu_func(f) {}
+ callback_t(const callback_f f) : func(f) {}
+ callback_t(const function_t *f) : menu_func(f) {}
int operator()() const {
if (!func && !menu_func) throw EMenu_callback();
@@ -75,13 +85,13 @@ private:
}
};
- 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;
+ const callback_t &get_callback(const std::string &s) const {
+ const auto it = lookup.find(s);
+ if (it == lookup.end()) throw EMenu_call();
+ return it->second;
}
- std::unordered_map<string, Menu_callback> function_lookup;
+ std::unordered_map<std::string, callback_t> lookup;
};
#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -1,5 +1,4 @@
add_library(menu
- menu.cpp
display.cpp
)
@@ -7,10 +6,7 @@ target_include_directories(menu
PUBLIC ../include
)
-
-add_executable(demo
- main.cpp
-)
+add_executable(demo main.cpp)
target_link_libraries(demo
PRIVATE menu
diff --git a/src/display.cpp b/src/display.cpp
@@ -1,24 +1,30 @@
#include "menu.h"
+#include <cmath>
+#include <format>
#include <iostream>
-int Menu::Menu_function::display() const {
+int Menu::function_t::display() const {
int choice;
- while (true) {
- std::cout << name << std::endl;
- for (auto i = 0ul; i < items.size(); i++)
- std::cout << i << ". " << items[i].prompt << std::endl;
+ const int n = items.size(), digits = std::log10(n) + 1;
+ while (true) {
+ std::cout << std::format("{}:\n", name);
+ for (auto i = 0ul; i < n; i++) {
+ std::cout << std::format(" {:{}}. {}\n", i, digits, items[i].prompt);
+ }
while (true) {
std::cout << "Choose an option: ";
- if (std::cin >> choice && choice >= -1 && choice < (int)items.size()) {
+ if (std::cin >> choice && choice >= -1 && choice < n) {
if (choice == -1) {
- std::cout << "Back" << items[choice].prompt << "\n";
+ std::cout << "choice: back\n";
return 1;
}
- std::cout << "Chosen: " << items[choice].prompt << "\n\n";
+
+ std::cout << std::format("Choice: {}\n\n", items[choice].prompt);
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";
@@ -27,7 +33,7 @@ int Menu::Menu_function::display() const {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
- std::cout << "Invalid option, please choose again!" << std::endl;
+ std::cout << "Invalid option, please choose again!\n";
}
std::cout << std::endl;
}
diff --git a/src/main.cpp b/src/main.cpp
@@ -3,11 +3,13 @@
int algorithms(void) {
std::cout << "algorithms" << std::endl;
+ std::cout << "nothing to do here" << std::endl;
return 1;
}
int settings(void) {
std::cout << "settings" << std::endl;
+ std::cout << "nothing to do here" << std::endl;
return 1;
}
@@ -18,9 +20,11 @@ int finish(void) {
int main(void) {
Menu menu("menu.json");
- menu.Register("algorithms", algorithms)
- .Register("settings", settings)
- .Register("finish", finish);
- menu.Start();
+ menu.insert({
+ {"algorithms", algorithms},
+ { "settings", settings},
+ { "finish", finish}
+ });
+ menu();
return 0;
}
diff --git a/src/menu.cpp b/src/menu.cpp
@@ -1,11 +1,2 @@
#include "menu.h"
-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(*this, menu["name"], {items.begin(), items.end()});
- function_lookup.insert({menu["code"], Menu_callback(mf)});
- }
-}