diff --git a/src/output.cc b/src/output.cc new file mode 100644 index 0000000..0723667 --- /dev/null +++ b/src/output.cc @@ -0,0 +1,17 @@ +#include "output.h" + +#include "constants.h" + +output::output(): + contents{DISPLAY_BUFFER_SIZE, 0} { + for (int i = 0; i < DISPLAY_BUFFER_SIZE; ++i) + contents.push_back(0); +} + +void output::clear() { + contents.clear(); + contents.reserve(DISPLAY_BUFFER_SIZE); + + for (int i = 0; i < DISPLAY_BUFFER_SIZE; ++i) + contents.push_back(0); +} diff --git a/src/output.h b/src/output.h new file mode 100644 index 0000000..217aa75 --- /dev/null +++ b/src/output.h @@ -0,0 +1,35 @@ +#ifndef __DISPLAY_H__ +#define __DISPLAY_H__ + +#include +#include +#include "position.h" +#include "cursor.h" + +class output { +protected: + // use an array of ints to keep track of what's on the screen + // This will have a bit of buffer for the last line + // just in case it overflows + std::vector contents; +public: + output(); + + virtual ~output() = default; + + // Only call this to refresh the entire output + virtual void render() = 0; + + // Clears the contents buffer + virtual void clear(); + + virtual void print_char(const position &pos, const char ch, + const int attrs = + A_NORMAL | COLOR_PAIR(COLOR_WHITE)) = 0; + virtual void print_str(const position &pos, const std::string &str, + const int attrs = + A_NORMAL | COLOR_PAIR(COLOR_WHITE)) = 0; + // default arguments are to be set in the base class's declaration +}; + +#endif diff --git a/src/output/console_output.cc b/src/output/console_output.cc new file mode 100644 index 0000000..beff4c2 --- /dev/null +++ b/src/output/console_output.cc @@ -0,0 +1,100 @@ +#include "console_output.h" + +#include +#include +#include + +#include "../constants.h" + +console_output::console_output(std::ostream &cout): out{cout} {} + +/* Attributes + black 30 40 + red 31 41 + green 32 42 + yellow 33 43 + blue 34 44 + magenta 35 45 + cyan 36 46 + white 37 47 + reset 0 (everything back to normal) + bold/bright 1 (often a brighter shade of the same colour) + underline 4 + inverse 7 (swap foreground and background colours) + bold/bright off 21 + underline off 24 + inverse off 27 + + Format: + \033[X;Ym + X Y are numbers from above +*/ + +std::string console_output::get_code(const int attrs) { + if (attrs < 255) + return "\033[0m"; + + std::string result = "\033[0m\033["; + + if (attrs & A_BOLD) + result += "1;"; + + if (attrs & A_UNDERLINE) + result += "4;"; + + if (attrs & A_STANDOUT) + result += "7;"; + + if ((attrs & COLOR_PAIR(COLOR_WHITE)) == COLOR_PAIR(COLOR_WHITE)) + result += "37;"; + else if ((attrs & COLOR_PAIR(COLOR_CYAN)) == COLOR_PAIR(COLOR_CYAN)) + result += "36;"; + else if ((attrs & COLOR_PAIR(COLOR_MAGENTA)) == COLOR_PAIR(COLOR_MAGENTA)) + result += "35;"; + else if ((attrs & COLOR_PAIR(COLOR_BLUE)) == COLOR_PAIR(COLOR_BLUE)) + result += "34;"; + else if ((attrs & COLOR_PAIR(COLOR_YELLOW)) == COLOR_PAIR(COLOR_YELLOW)) + result += "33;"; + else if ((attrs & COLOR_PAIR(COLOR_RED)) == COLOR_PAIR(COLOR_RED)) + result += "31;"; + else if ((attrs & COLOR_PAIR(COLOR_GREEN)) == COLOR_PAIR(COLOR_GREEN)) + result += "32;"; + else if ((attrs & COLOR_PAIR(COLOR_BLACK_ON_WHITE)) == COLOR_BLACK_ON_WHITE) + result += "30;47;"; + + result[result.length() - 1] = 'm'; + return result; +} + +void console_output::render() { + out << "\x1B[2J\x1B[H"; + + for (std::size_t idx = 0; idx < contents.size(); ++idx) { + if (idx % DISPLAY_WIDTH == 0 && idx) + out << std::endl; + + out << get_code(contents[idx]) + << (char)(contents[idx] ? contents[idx] : ' '); + } + + out << std::endl; +} + +void console_output::print_char(const position &pos, const char ch, + const int attrs) { + if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) + return; + + contents[pos.y * DISPLAY_WIDTH + pos.x] = attrs | ch; +} + +void console_output::print_str(const position &pos, const std::string &str, + const int attrs) { + if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) + return; + + int head = pos.y * DISPLAY_WIDTH + pos.x; + + for (std::size_t i = 0; i < str.length(); ++i) + contents[i + head] = attrs | str[i]; +} diff --git a/src/output/console_output.h b/src/output/console_output.h new file mode 100644 index 0000000..c8dbfd1 --- /dev/null +++ b/src/output/console_output.h @@ -0,0 +1,21 @@ +#ifndef __CONSOLE_OUTPUT_H__ +#define __CONSOLE_OUTPUT_H__ + +#include +#include "../output.h" + +class console_output final : public output { +private: + std::ostream &out; + std::string get_code(const int attrs); +public: + console_output(std::ostream &cout); + + void render() override; + void print_char(const position &pos, + const char ch, const int attrs) override; + void print_str(const position &pos, + const std::string &str, const int attrs) override; +}; + +#endif diff --git a/src/output/curses_output.cc b/src/output/curses_output.cc new file mode 100644 index 0000000..bee3adf --- /dev/null +++ b/src/output/curses_output.cc @@ -0,0 +1,38 @@ +#include "curses_output.h" + +#include "../constants.h" + +curses_output::curses_output(cursor *new_curse): + curse{new_curse} {} + +void curses_output::render() { + curse->show(); +} + +void curses_output::clear() { + curse->clear(); +} + +void curses_output::print_char(const position &pos, const char ch, + const int attrs) { + if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) + return; + + curse->print_char(pos, ch, attrs); +} + +void curses_output::print_str(const position &pos, const std::string &str, + const int attrs) { + if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) + return; + + position tmp = pos; + + for (std::size_t i = 0; i < str.length(); ++i) { + curse->print_char(tmp, str[i], attrs); + tmp += {1, 0}; + + if (tmp.x >= DISPLAY_WIDTH) + tmp = {0, tmp.y + 1}; + } +} diff --git a/src/output/curses_output.h b/src/output/curses_output.h new file mode 100644 index 0000000..7d841b9 --- /dev/null +++ b/src/output/curses_output.h @@ -0,0 +1,23 @@ +#ifndef __CURSES_OUTPUT_H__ +#define __CURSES_OUTPUT_H__ + +#include +#include +#include "../cursor.h" +#include "../output.h" + +class curses_output final : public output { +private: + cursor *curse; +public: + curses_output(cursor *new_curse); + + void render() override; + void clear() override; + void print_char(const position &pos, + const char ch, const int attrs) override; + void print_str(const position &pos, + const std::string &str, const int attrs) override; +}; + +#endif diff --git a/src/output/file_output.cc b/src/output/file_output.cc new file mode 100644 index 0000000..5408220 --- /dev/null +++ b/src/output/file_output.cc @@ -0,0 +1,38 @@ +#include "file_output.h" + +#include + +#include "../constants.h" + +file_output::file_output(std::ofstream &&ofs): + out{std::move(ofs)} {} + +void file_output::render() { + for (std::size_t idx = 0; idx < contents.size(); ++idx) { + if (idx % DISPLAY_WIDTH == 0 && idx) + out << std::endl; + + out << (char)(contents[idx] ? contents[idx] : ' '); + } + + out << std::endl; +} + +void file_output::print_char(const position &pos, const char ch, + const int attrs) { + if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) + return; + + contents[pos.y * DISPLAY_WIDTH + pos.x] = ch; +} + +void file_output::print_str(const position &pos, const std::string &str, + const int attrs) { + if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) + return; + + int head = pos.y * DISPLAY_WIDTH + pos.x; + + for (std::size_t i = 0; i < str.length(); ++i) + contents[i + head] = str[i]; +} diff --git a/src/output/file_output.h b/src/output/file_output.h new file mode 100644 index 0000000..5e0f80d --- /dev/null +++ b/src/output/file_output.h @@ -0,0 +1,20 @@ +#ifndef __FILE_OUTPUT_H__ +#define __FILE_OUTPUT_H__ + +#include +#include "../output.h" + +class file_output final : public output { +private: + std::ofstream out; +public: + file_output(std::ofstream &&ofs); + + void render() override; + void print_char(const position &pos, + const char ch, const int attrs) override; + void print_str(const position &pos, + const std::string &str, const int attrs) override; +}; + +#endif