From 24bdf39e6c21ab846f6c86803761d78a094e05c0 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Thu, 26 May 2022 20:31:26 +0300 Subject: Added files from project 1 (mirror) --- .../src/Generic/ConsoleInterface/Command.cpp | 24 +++ .../src/Generic/ConsoleInterface/Command.h | 27 +++ .../src/Generic/ConsoleInterface/Menu.cpp | 135 +++++++++++++ .../Project 1/src/Generic/ConsoleInterface/Menu.h | 46 +++++ .../src/Generic/ConsoleInterface/Toolbox.cpp | 223 +++++++++++++++++++++ .../src/Generic/ConsoleInterface/Toolbox.hpp | 115 +++++++++++ 6 files changed, 570 insertions(+) create mode 100644 Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp create mode 100644 Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h create mode 100644 Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp create mode 100644 Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h create mode 100644 Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp create mode 100644 Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp (limited to 'Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface') diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp new file mode 100644 index 0000000..c14bcc8 --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.cpp @@ -0,0 +1,24 @@ +#include "Command.h" +#include + +Command::Command() : Command("", nullptr) {} + +/*! \param nameInMenu C-style string, class stores at most 255 characters (last character is always terminating zero) + * \param exec Function pointer that will be executed when run() is called. Can be nullptr. + */ +Command::Command(const char* nameInMenu, void (*exec)()) { + strncpy(this->nameInMenu, nameInMenu, 255); + this->nameInMenu[255] = '\0'; + this->exec = exec; +} + +/*! Executes the stored function pointer, when it's not nullptr. Otherwise does nothing. + */ +void Command::run() const { + if (exec != nullptr) + exec(); +} + +const char* Command::get_nameInMenu() const { + return nameInMenu; +} diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h new file mode 100644 index 0000000..f1eb55b --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Command.h @@ -0,0 +1,27 @@ +#ifndef HEADER_CONSOLEINTERFACE_COMMAND +#define HEADER_CONSOLEINTERFACE_COMMAND + +/*! \file Command.h + * \brief Stores the declaration of class Command + */ + +/*! \brief Stores a 256 character name and a function pointer to be executed when calling run() + * + * Menu uses this class for a more generic implementation of it's navigate function. + */ +class Command { + char nameInMenu[256]; + void (*exec)(); + +public: + //! Leaves name empty and exec function pointer to nullptr + Command(); + //! Copies contents of nameInMenu and stores exec + Command(const char* nameInMenu, void (*exec)()); + //! Executes the stored function pointer + void run() const; + + const char* get_nameInMenu() const; +}; + +#endif diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp new file mode 100644 index 0000000..3ab857e --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.cpp @@ -0,0 +1,135 @@ +#include "Menu.h" +#include "Toolbox.hpp" +#include + +Menu::Menu() : Menu("Menu", false, false) {} + +/*! \param title C-style string, class stores at most 255 characters (last character is always terminating zero) + * \param backExistsApp Flag whether or not to list the 0-th option as "Exit", rather than "Go Back" + * \param isSubMenu Flag whether or not to show the title as a subTitle or not + */ +Menu::Menu(const char* title, bool backExistsApp, bool isSubMenu) : menuOptions() { + this->backExistsApp = backExistsApp; + this->isSubMenu = isSubMenu; + strncpy(this->title, title, 255); + this->title[255] = '\0'; +} + +/*! \param title C-style string, class stores at most 255 characters (last character is always terminating zero) + * \param backExistsApp Flag whether or not to list the 0-th option as "Exit", rather than "Go Back" + * \param isSubMenu Flag whether or not to show the title as a subTitle or not + * \param commands Pointer to an array of Command instances + * \param commandCount Number of elements that "commands" points to + */ +Menu::Menu(const char* title, bool backExistsApp, bool isSubMenu, const Command* commands, unsigned commandCount) { + this->backExistsApp = backExistsApp; + this->isSubMenu = isSubMenu; + menuOptions = List(commands, commandCount); + strncpy(this->title, title, 255); + this->title[255] = '\0'; +} + +void Menu::addCommand(const Command& command) { + menuOptions.add(command); +} + +enum MessageType { + NoPrint, + Success, + Warning, + Error, +}; +const char* msg; +MessageType msgType; + +/*! \param message C-style string, saves to pointer for later reuse when showing the message. + * + * Stores the message pointer in a global variable (in the cpp file) and + * sets it's type as an Error in another global variable (in the cpp file). + * + * The next time the whole Menu is shown, the message will appear below the title. + */ +void Menu::registerError(const char* message) const { + msg = message; + msgType = Error; +} + +/*! \param message C-style string, saves to pointer for later reuse when showing the message. + * + * Stores the message pointer in a global variable (in the cpp file) and + * sets it's type as a Warning in another global variable (in the cpp file). + * + * The next time the whole Menu is shown, the message will appear below the title. + */ +void Menu::registerWarning(const char* message) const { + msg = message; + msgType = Warning; +} + +/*! \param message C-style string, saves to pointer for later reuse when showing the message. + * + * Stores the message pointer in a global variable (in the cpp file) and + * sets it's type as Success in another global variable (in the cpp file). + * + * The next time the whole Menu is shown, the message will appear below the title. + */ +void Menu::registerSuccess(const char* message) const { + msg = message; + msgType = Success; +} + +/*! + * Prints the title, then an Error/Warning/Sucess message (if set), + * prints all command names as an ordered list (starting from 1), + * waits for user input to select one of those commands (by list number) + * and finally executes the appropriate command's run() function. + * + * After the run() function exists, everything is reprinted. + * The 0 list index is always "Go Back"/"Exit" and it always stops the reprinting loop. + * + * If there are no commands, prints "Menu is empty!". + * If user input doesn't correspond to any command, registers an error message and reprints. + */ +void Menu::navigate() const { + if (menuOptions.get_count() == 0) { + printLine("Menu is empty!"); + return; + } + + unsigned buffer = 1; // We immedeately read the value of buffer, so this is fine + + while (buffer != 0) { + clear(); + if (isSubMenu) + subTitleBox(title); + else + titleBox(title); + + switch(msgType) { + case Error: errorBox(msg); msgType = NoPrint; break; + case Warning: warningBox(msg); msgType = NoPrint; break; + case Success: successBox(msg); msgType = NoPrint; break; + case NoPrint: printLine(""); break; + } + printLine(""); + + resetOrderedList(0); + if (backExistsApp) + printOrderedListElem("Exit"); + else + printOrderedListElem("Go Back"); + + for (unsigned i = 0; i < menuOptions.get_count(); i++) + printOrderedListElem(menuOptions[i].get_nameInMenu()); + + _printInputBoxLabel("Execute No [0-"); + print(menuOptions.get_count()); + print("]: "); + read(buffer); + + if (buffer > menuOptions.get_count()) + registerError("Invalid menu option!"); + else if (buffer > 0) + menuOptions[buffer - 1].run(); + } +} diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h new file mode 100644 index 0000000..e0ea685 --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Menu.h @@ -0,0 +1,46 @@ +#ifndef HEADER_CONSOLEINTERFACE_MENU +#define HEADER_CONSOLEINTERFACE_MENU + +/*! \file Menu.h + * \brief Stores the declaration of class Menu + */ + +#include "Command.h" +#include "../List/List.hpp" + +/*! \brief Handles navigation between multiple commands + * + * Shows the title, then below it an Error/Warning/Success message if set, + * lists all command options as an enumerated list, takes command index + * and calls the chosen command's run() function. + */ +class Menu { + char title[256]; + List menuOptions; + + bool backExistsApp; + bool isSubMenu; + +public: + //! Sets name as "Menu", leaves all flags to false and creates an empty Command list + Menu(); + //! Copies title, saves flags and creates and empty Command list + Menu(const char* title, bool backExistsApp, bool isSubMenu); + //! Copies title, saves flags and copies commands + Menu(const char* title, bool backExistsApp, bool isSubMenu, const Command* commands, unsigned commandCount); + + //! Adds a command to the internal Command list + void addCommand(const Command& command); + + //! Tell Menu to show an error message next time it prints + void registerError(const char* message) const; + //! Tell Menu to show a warning message next time it prints + void registerWarning(const char* message) const; + //! Tell Menu to show a success message next time it prints + void registerSuccess(const char* message) const; + + //! Lists commands and after user input executes an appropriate command run() function + void navigate() const; +}; + +#endif diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp new file mode 100644 index 0000000..ca83b3b --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.cpp @@ -0,0 +1,223 @@ +#include "Toolbox.hpp" + +/*! + * Erases display and moves cursor to top left corner via ANSI escape sequences: \c ESC[2J \c ESC[1;1H + * + * \warning Not all terminals support any or all ANSI escape sequences + * + * \note Source: https://stackoverflow.com/a/52895729/12036073 + */ +void clear() { + std::cout << u8"\033[2J\033[1;1H"; +} + +/*! + * Sub boxes are like normal boxes, but indented with 4 spaces. + */ +void _printSubBoxSpacing() { + std::cout << " "; +} + +/* Title boxes */ + +/*! \param title C-style string, there are no size checks so it could wrap + * + * Prints the title, surrounded by "===". + */ +void titleBox(const char* title) { + std::cout << std::endl << "=== " << title << " ===" << std::endl; +} + +/*! \param title C-style string, there are no size checks so it could wrap + * + * Prints the title, surrounded by "---". + */ +void subTitleBox(const char* title) { + std::cout << std::endl << "--- " << title << " ---" << std::endl; +} + +/* Status boxes */ + +/*! \param message C-style string, there are no size checks so it could wrap + * + * Success boxes start with "" and print the message. + * + * \remark Success/Warning/Error boxes start with "" where C is an appropriate character. + */ +void successBox(const char* message) { + std::cout << " " << message << std::endl; +} + +/*! + * \copydetails successBox() + * \sa _printSubBoxSpacing() + */ +void successSubBox(const char* message) { + _printSubBoxSpacing(); + successBox(message); +} + +/*! \param message C-style string, there are no size checks so it could wrap + * + * Warning boxes start with "" and print the message. + * + * \remark Success/Warning/Error boxes start with "" where C is an appropriate character. + */ +void warningBox(const char* message) { + std::cout << " " << message << std::endl; +} + +/*! + * \copydetails warningBox() + * \sa _printSubBoxSpacing() + */ +void warningSubBox(const char* message) { + _printSubBoxSpacing(); + warningBox(message); +} + +/*! \param message C-style string, there are no size checks so it could wrap + * + * Error boxes start with "" and print the message. + * + * \remark Success/Warning/Error boxes start with "" where C is an appropriate character. + */ +void errorBox(const char* message) { + std::cout << " " << message << std::endl; +} + +/*! + * \copydetails errorBox() + * \sa _printSubBoxSpacing() + */ +void errorSubBox(const char* message) { + _printSubBoxSpacing(); + errorBox(message); +} + +/* Input line boxes */ + +/*! \param label C-style string, there are no size checks so it could wrap + * + * Prints "(+)" and then the given label. + * It doesn't create spacing after label, so it should exist in the label itself. + * + * \remark Semi-internal means the function is defined in the header out of necessity (for templated functions) + */ +void _printInputBoxLabel(const char* label) { + std::cout << "(+) " << label; +} + +void __inputLineBoxGetInput(char* output, unsigned maxWidth, bool ignore) { + if (ignore) + std::cin.ignore(); + std::cin.getline(output, maxWidth); +} + +/*! \param label C-style string, there are no size check so it could wrap + * \param output Pointer to a char array + * \param maxWidth Maximum count of characters to read from user input. output MUST be able to hold that many characters! + * \param ignore Whether or not to ignore the first new-line delimiter. + * true by default, should be set to false only when an inputLineBox/SubBox has been issued directly prior or when it's the very first issued box command. + * + * Prints "(+)" before the label. + */ +void inputLineBox(const char* label, char* output, unsigned maxWidth, bool ignore) { + _printInputBoxLabel(label); + __inputLineBoxGetInput(output, maxWidth, ignore); +} + +/*! + * \copydetails inputLineBox() + * \sa _printSubBoxSpacing() + */ +void inputLineSubBox(const char* label, char* output, unsigned maxWidth, bool ignore) { + _printSubBoxSpacing(); + _printInputBoxLabel(label); + __inputLineBoxGetInput(output, maxWidth, ignore); +} + +/*! \param ignore Whether or not to ignore the first new-line delimiter. + * true by default, should be set to false only when an inputLineBox/SubBox has been issued directly prior or when it's the very first issued box command. + * + * Prints a "Press enter to continue" message and waits for the user + */ +void pressEnterToContinue(bool ignore) { + char tmp; + inputLineBox("[Press enter to continue]", &tmp, 1, ignore); +} + +/* Ordered list */ + +int orderedListIndex = 1; + +/*! + * Prints the latests ordered list index, surrounded by square brackets, and increments the ordered list index. + * + * \remark There are no size checks, so list index could overflow. + * + * \remark Semi-internal means the function is defined in the header out of necessity (for templated functions) + */ + +void _printOrderedListBeginning() { + std::cout << "[" << orderedListIndex++ << "] "; +} + +/*! \param starter Sets the starting number by which ordered list will enumerate + * + * \remark Although starter can be a negative number, ordered list will always increment up the number. + */ +void resetOrderedList(int starter) { + orderedListIndex = starter; +} + +/* Table */ + +void __printTableHeaderNumber(unsigned number) { + std::cout << ":" << ((number < 100) ? " " : "") << number << ((number < 10) ? " " : ""); +} + +void __printTableColumnHeader(unsigned start, unsigned count) { + std::cout << ": "; + for (unsigned i = 0; i < count; i++) + __printTableHeaderNumber(start++); + std::cout << ":" << std::endl; + + for (unsigned i = 0; i <= count; i++) + std::cout << "===="; + std::cout << "=" << std::endl; +} + +void __printTableLine(unsigned columns) { + std::cout << ":==="; + for (unsigned i = 0; i < columns; i++) + std::cout << "+---"; + std::cout << ":" << std::endl; +} + +/*! \param startNumber The number by which column and row enumeration begins + * \param columns How many columns the table should have + * \param items C-style string, each cell is a single character from the string + * + * Prints a string as a grid/table of characters from top to bottom, left to right. + * The first character is on the top left, the last one is on the bottom right. + * + * Table is printed until a terminating zero is encountered. + * The rows are "calculated" from the columns count and the items length. + */ +void table(unsigned startNumber, unsigned columns, const char* items) { + __printTableColumnHeader(startNumber, columns); + + __printTableHeaderNumber(startNumber); + for (unsigned i = 0, colInd = 0, rowInd = 0; items[i] != '\0'; i++, (++colInd) %= columns) { + if (colInd == 0 && i != 0) { + std::cout << ":" << std::endl; + __printTableLine(columns); + __printTableHeaderNumber((++rowInd) + startNumber); + } + + std::cout << ((colInd == 0) ? "║ " : "| ") << items[rowInd * columns + colInd] << " "; + } + std::cout << ":" << std::endl; +} + diff --git a/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp new file mode 100644 index 0000000..91306cb --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 1/src/Generic/ConsoleInterface/Toolbox.hpp @@ -0,0 +1,115 @@ +#ifndef HEADER_CONSOLEINTERFACE_TOOLBOX +#define HEADER_CONSOLEINTERFACE_TOOLBOX + +#include + +/*! \file Toolbox.hpp + * \brief Stores a wide range of functions for simpler/more automated printing. + * + * Adds a lot of functions for printing. + * + * \remark iostream is included by necessity (templated functions), you should only use the provided functions, if you can. + */ + +#define MAX_LINE_WIDTH 1024 + +//! Clears the console screen +void clear(); +//! Prints a title box +void titleBox(const char* title); +//! Prints a title sub box +void subTitleBox(const char* title); + +//! Prints a success box +void successBox(const char* message); +//! Prints a success box as a sub box +void successSubBox(const char* message); +//! Prints a warning box +void warningBox(const char* message); +//! Prints a warning box as a sub box +void warningSubBox(const char* message); +//! Prints an error box +void errorBox(const char* message); +//! Prints an error box as a sub box +void errorSubBox(const char* message); + +//! Prints label, gets a whole line of input and stores it to output +void inputLineBox(const char* label, char* output, unsigned maxWidth, bool ignore = true); +//! Prints label as a sub box, gets a whole line of input and stores it to output +void inputLineSubBox(const char* label, char* output, unsigned maxWidth, bool ignore = true); +//! Waits for user to press enter +void pressEnterToContinue(bool ignore = true); + +//! Resets the ordered list starting number +void resetOrderedList(int starter = 1); + +//! Prints a string as a table +void table(unsigned startNumber, unsigned columns, const char* items); + +//! Semi-internal function that prints the spacing for sub boxes +void _printSubBoxSpacing(); +//! Semi-internal function that prints the label of an input box +void _printInputBoxLabel(const char* label); +//! Semi-internal function that prints the latest ordered list index +void _printOrderedListBeginning(); + +//! Reads user input and stores it +template +void read(T* storage) { + std::cin >> storage; +} + +//! Reads user input and stores it +template +void read(T& storage) { + std::cin >> storage; +} + +//! Prints given item +template +void print(const T* item) { + std::cout << item; +} + +//! Prints given item +template +void print(const T& item) { + std::cout << item; +} + +//! Prints given item and an endline character +template +void printLine(const T* item) { + std::cout << item << std::endl; +} + +//! Prints given item and an endline character +template +void printLine(const T& item) { + std::cout << item << std::endl; +} + +//! Prints the element as the latest list item +template +void printOrderedListElem(const T& elem) { + _printOrderedListBeginning(); + printLine(elem); +} + +//! Prints a label and then reads user input and stores it +template +void inputBox(const char* label, T* output) { + _printInputBoxLabel(label); + std::cin >> *output; +} + +//! Prints a label with sub box spacing and then reads user input and stores it +//! \sa _printSubBoxSpacing() +template +void inputSubBox(const char* label, T* output) { + _printSubBoxSpacing(); + _printInputBoxLabel(label); + std::cin >> *output; +} + +#endif -- cgit v1.3.1-23-gd82d