diff options
Added files from project 2 (mirror)
6 files changed, 304 insertions, 0 deletions
diff --git a/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Command.cpp b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Command.cpp new file mode 100644 index 0000000..d05dc8d --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Command.cpp @@ -0,0 +1,24 @@ +#include "Command.h" +#include <cstring> + +Command::Command() : Command("", nullptr) {} + +/*! \param name 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* name, void (*exec)(const char* params)) { + strncpy(this->name, name, 255); + this->name[255] = '\0'; + this->exec = exec; +} + +/*! Executes the stored function pointer, when it's not nullptr. Otherwise does nothing. + */ +void Command::run(const char* params) const { + if (exec != nullptr) + exec(params); +} + +const char* Command::get_name() const { + return name; +} diff --git a/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Command.h b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Command.h new file mode 100644 index 0000000..393d705 --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 2/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 name[256]; + void (*exec)(const char* params); + +public: + //! Leaves name empty and exec function pointer to nullptr + Command(); + //! Copies contents of nameInMenu and stores exec + Command(const char* name, void (*exec)(const char* params)); + //! Executes the stored function pointer + void run(const char* params) const; + + const char* get_name() const; +}; + +#endif diff --git a/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Menu.cpp b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Menu.cpp new file mode 100644 index 0000000..9c2fca5 --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Menu.cpp @@ -0,0 +1,72 @@ +#include "Menu.h" +#include "Toolbox.hpp" +#include <cstring> + +Menu::Menu() : menuOptions() {} + +unsigned indexOfCommandEnd(char* str) { + unsigned ind = 0; + std::cout << str[ind] << std::endl; + + return ind; +} + +void Menu::addCommand(const Command& command) { + menuOptions.add(command); +} + +/*! + * 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; + } + + char buffer[MAX_LINE_WIDTH]; + + unsigned startIndex, commandEnd, paramsStart, index; + bool hasThrown = false; + while (!hasThrown) { + startIndex = 0; + inputLineBox(buffer, MAX_LINE_WIDTH, false); + + while (buffer[startIndex] == ' ') startIndex++; + + commandEnd = startIndex; + while (buffer[commandEnd] != ' ' && buffer[commandEnd] != '\n' && buffer[commandEnd] != '\0') + commandEnd++; + + index = menuOptions.get_count(); + for (unsigned i = 0; i < menuOptions.get_count() && index == menuOptions.get_count(); i++) { + if (strncmp(buffer + startIndex, menuOptions[i].get_name(), commandEnd - startIndex) == 0) + index = i; + } + + paramsStart = startIndex + commandEnd; + while (buffer[paramsStart] == ' ') paramsStart++; + + if (index == menuOptions.get_count()) { + printLine("Invalid menu option!"); + continue; + } + + try { + menuOptions[index].run(buffer + paramsStart); + } + catch (std::logic_error err) { + hasThrown = true; + printLine(err.what()); + } + } +} diff --git a/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Menu.h b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Menu.h new file mode 100644 index 0000000..faadba9 --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Menu.h @@ -0,0 +1,33 @@ +#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 { + List<Command> menuOptions; + +public: + //! Sets name as "Menu", leaves all flags to false and creates an empty Command list + Menu(); + //! Copies commands + Menu(const Command* commands, unsigned commandCount); + + //! Adds a command to the internal Command list + void addCommand(const Command& command); + + //! 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 2/src/Generic/ConsoleInterface/Toolbox.cpp b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Toolbox.cpp new file mode 100644 index 0000000..ca739f0 --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Toolbox.cpp @@ -0,0 +1,88 @@ +#include "Toolbox.hpp" + +/* Input line boxes */ + +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(char* output, unsigned maxWidth, bool ignore) { + print("> "); + __inputLineBoxGetInput(output, maxWidth, ignore); +} + +/* Table */ + +void __printTableHeaderNumber(unsigned number) { + std::cout << ":" << ((number < 100) ? " " : "") << number << ((number < 10) ? " " : ""); +} + +void __printTableColumnHeader(unsigned count, unsigned start = 1) { + 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; +} + +void __printPadded(const String& str, unsigned width) { + while (width - str.get_length() > 0) { + width--; + print(" "); + } + print(str.get_cstr()); +} + +/*! \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 printTable(const List<String>& items, unsigned columns) { + unsigned *colWidths = new unsigned[columns]; + for (unsigned i = 0; i < columns; i++) + colWidths[i] = 0; + + for (unsigned i = 0; i < items.get_count(); i++) { + if (colWidths[i % columns] < items[i].get_length()) + colWidths[i % columns] = items[i].get_length(); + } + + // __printTableColumnHeader(columns); + + for (unsigned i = 0; i < items.get_count(); i++) { + __printPadded(items[i], colWidths[i % columns]); + if (i % columns == columns - 1) + printLine(""); + else + print("|"); + } + + delete[] colWidths; +} + diff --git a/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Toolbox.hpp b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Toolbox.hpp new file mode 100644 index 0000000..4b59626 --- /dev/null +++ b/Year 1/Object-oriented Programming/Project 2/src/Generic/ConsoleInterface/Toolbox.hpp @@ -0,0 +1,60 @@ +#ifndef HEADER_CONSOLEINTERFACE_TOOLBOX +#define HEADER_CONSOLEINTERFACE_TOOLBOX + +#include <iostream> +#include "../List/List.hpp" +#include "../String/String.h" + +/*! \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 + +//! Prints label, gets a whole line of input and stores it to output +void inputLineBox(char* output, unsigned maxWidth, bool ignore = true); + +//! Prints a string list as a table +void printTable(const List<String>& items, unsigned columns); + +//! Reads user input and stores it +template <typename T> +void read(T* storage) { + std::cin >> storage; +} + +//! Reads user input and stores it +template <typename T> +void read(T& storage) { + std::cin >> storage; +} + +//! Prints given item +template <typename T> +void print(const T* item) { + std::cout << item; +} + +//! Prints given item +template <typename T> +void print(const T& item) { + std::cout << item; +} + +//! Prints given item and an endline character +template <typename T> +void printLine(const T* item) { + std::cout << item << std::endl; +} + +//! Prints given item and an endline character +template <typename T> +void printLine(const T& item) { + std::cout << item << std::endl; +} + +#endif |
