From dc3c855ecf0522ba30fb8a8f8b1be0de761c093d Mon Sep 17 00:00:00 2001 From: bog Date: Thu, 5 Oct 2023 20:59:46 +0200 Subject: [PATCH] :sparkles: can now write on the View from UI class. --- meson.build | 5 ++ src/core/Color.cpp | 36 +++++++++++++++ src/core/Color.hpp | 38 +++++++++++++++ src/core/Coord.cpp | 32 +++++++++++++ src/core/Coord.hpp | 31 +++++++++++++ src/core/Event.hpp | 22 +++++++++ src/core/Pixel.hpp | 18 ++++++++ src/core/Plugin.hpp | 1 - src/core/Rect.cpp | 32 +++++++++++++ src/core/Rect.hpp | 31 +++++++++++++ src/core/Tiwiq.cpp | 2 +- src/core/UI.cpp | 44 ++++++++++++++++++ src/core/UI.hpp | 16 ++++++- src/main.cpp | 5 ++ src/term/Controller.cpp | 1 + src/term/Term.cpp | 5 ++ src/term/Term.hpp | 5 ++ src/term/View.cpp | 100 ++++++++++++++++++++++++++++++++++++++++ src/term/View.hpp | 42 +++++++++++++++++ 19 files changed, 463 insertions(+), 3 deletions(-) create mode 100644 src/core/Color.cpp create mode 100644 src/core/Color.hpp create mode 100644 src/core/Coord.cpp create mode 100644 src/core/Coord.hpp create mode 100644 src/core/Pixel.hpp create mode 100644 src/core/Rect.cpp create mode 100644 src/core/Rect.hpp create mode 100644 src/term/View.cpp create mode 100644 src/term/View.hpp diff --git a/meson.build b/meson.build index e8411b5..64a309d 100644 --- a/meson.build +++ b/meson.build @@ -22,11 +22,16 @@ twq_lib = static_library('tiwiq', 'src/core/Observable.cpp', 'src/core/Event.cpp', + 'src/core/Coord.cpp', + 'src/core/Rect.cpp', + 'src/core/Color.cpp', + 'src/cmd/QuitCmd.cpp', 'src/plugins/CorePlugin.cpp', 'src/term/Controller.cpp', + 'src/term/View.cpp', 'src/term/Term.cpp', ], dependencies: [ diff --git a/src/core/Color.cpp b/src/core/Color.cpp new file mode 100644 index 0000000..128d680 --- /dev/null +++ b/src/core/Color.cpp @@ -0,0 +1,36 @@ +#include "Color.hpp" + +namespace twq +{ + namespace core + { + /*static*/ Color Color::black() { return Color {0, 0, 0}; } + /*static*/ Color Color::white() { return Color {255, 255, 255}; } + /*static*/ Color Color::red() { return Color {255, 0, 0}; } + /*static*/ Color Color::green() { return Color {0, 255, 0}; } + /*static*/ Color Color::blue() { return Color {0, 0, 255}; } + + /*explicit*/ Color::Color() + : Color(0, 0, 0) + { + } + + /*explicit*/ Color::Color(int red, int green, int blue) + : m_red { red } + , m_green { green } + , m_blue { blue } + { + } + + /*virtual*/ Color::~Color() + { + } + + bool Color::equals(Color const& rhs) const + { + return m_red == rhs.m_red + && m_green == rhs.m_green + && m_blue == rhs.m_blue; + } + } +} diff --git a/src/core/Color.hpp b/src/core/Color.hpp new file mode 100644 index 0000000..cff0438 --- /dev/null +++ b/src/core/Color.hpp @@ -0,0 +1,38 @@ +#ifndef twq_core_COLOR_HPP +#define twq_core_COLOR_HPP + +#include "../commons.hpp" + +namespace twq +{ + namespace core + { + class Color + { + public: + static Color black(); + static Color white(); + static Color red(); + static Color green(); + static Color blue(); + + explicit Color(); + explicit Color(int red, int green, int blue); + virtual ~Color(); + + int r() const { return m_red; } + int g() const { return m_green; } + int b() const { return m_blue; } + + bool equals(Color const& rhs) const; + + private: + int m_red; + int m_green; + int m_blue; + + }; + } +} + +#endif diff --git a/src/core/Coord.cpp b/src/core/Coord.cpp new file mode 100644 index 0000000..1a497f7 --- /dev/null +++ b/src/core/Coord.cpp @@ -0,0 +1,32 @@ +#include "Coord.hpp" + +namespace twq +{ + namespace core + { + /*explicit*/ Coord::Coord() + : Coord(0, 0) + { + } + + /*explicit*/ Coord::Coord(int row, int col) + : m_row { row } + , m_col { col } + { + } + + /*virtual*/ Coord::~Coord() + { + } + + std::string Coord::string() const + { + return std::to_string(m_row) + "x" + std::to_string(m_col); + } + + bool Coord::equals(Coord const& rhs) const + { + return m_row == rhs.m_row && m_col == rhs.m_col; + } + } +} diff --git a/src/core/Coord.hpp b/src/core/Coord.hpp new file mode 100644 index 0000000..8eed3b5 --- /dev/null +++ b/src/core/Coord.hpp @@ -0,0 +1,31 @@ +#ifndef twq_core_COORD_HPP +#define twq_core_COORD_HPP + +#include "../commons.hpp" + +namespace twq +{ + namespace core + { + class Coord + { + public: + explicit Coord(); + explicit Coord(int row, int col); + virtual ~Coord(); + + int row() const { return m_row; } + int col() const { return m_col; } + + std::string string() const; + + bool equals(Coord const& rhs) const; + + private: + int m_row; + int m_col; + }; + } +} + +#endif diff --git a/src/core/Event.hpp b/src/core/Event.hpp index ad12bd0..606b221 100644 --- a/src/core/Event.hpp +++ b/src/core/Event.hpp @@ -3,14 +3,36 @@ #include "../commons.hpp" #include "KeyMod.hpp" +#include "Pixel.hpp" +#include "Coord.hpp" + +#define EVENT_TYPES(G) \ + G(EVENT_UNKNOWN), \ + G(EVENT_KEY), \ + G(EVENT_DRAW) namespace twq { namespace core { + TWQ_ENUM(EventType, EVENT_TYPES); + + struct DrawEvent { + Coord coord; + Pixel pixel; + }; + + struct ResizeEvent { + int w; + int h; + }; + struct Event { + EventType type = EVENT_UNKNOWN; std::optional key; + std::optional draw; + std::optional resize; }; } } diff --git a/src/core/Pixel.hpp b/src/core/Pixel.hpp new file mode 100644 index 0000000..25aac24 --- /dev/null +++ b/src/core/Pixel.hpp @@ -0,0 +1,18 @@ +#ifndef twq_core_PIXEL_HPP +#define twq_core_PIXEL_HPP + +#include "Color.hpp" + +namespace twq +{ + namespace core + { + struct Pixel { + Color background; + Color foreground; + wchar_t text; + }; + } +} + +#endif diff --git a/src/core/Plugin.hpp b/src/core/Plugin.hpp index 0ee8de1..6640f27 100644 --- a/src/core/Plugin.hpp +++ b/src/core/Plugin.hpp @@ -23,7 +23,6 @@ namespace twq private: std::string m_name; std::shared_ptr m_executor; - std::shared_ptr m_ui = std::make_shared(); }; diff --git a/src/core/Rect.cpp b/src/core/Rect.cpp new file mode 100644 index 0000000..f2c8092 --- /dev/null +++ b/src/core/Rect.cpp @@ -0,0 +1,32 @@ +#include "Rect.hpp" + +namespace twq +{ + namespace core + { + /*explicit*/ Rect::Rect() + : Rect(Coord {0, 0}, Coord {0, 0}) + { + } + + /*explicit*/ Rect::Rect(Coord const& pos, Coord const& size) + : m_pos { pos } + , m_size { size } + { + } + + /*virtual*/ Rect::~Rect() + { + } + + std::string Rect::string() const + { + return "(" + m_pos.string() + " " + m_size.string() + ")"; + } + + bool Rect::equals(Rect const& rhs) const + { + return m_pos.equals(rhs.m_pos) && m_size.equals(rhs.m_size); + } + } +} diff --git a/src/core/Rect.hpp b/src/core/Rect.hpp new file mode 100644 index 0000000..8d7eb52 --- /dev/null +++ b/src/core/Rect.hpp @@ -0,0 +1,31 @@ +#ifndef twq_core_RECT_HPP +#define twq_core_RECT_HPP + +#include "Coord.hpp" + +namespace twq +{ + namespace core + { + class Rect + { + public: + explicit Rect(); + explicit Rect(Coord const& pos, Coord const& size); + virtual ~Rect(); + + Coord pos() const { return m_pos; } + Coord size() const { return m_size; } + + std::string string() const; + + bool equals(Rect const& rhs) const; + + private: + Coord m_pos; + Coord m_size; + }; + } +} + +#endif diff --git a/src/core/Tiwiq.cpp b/src/core/Tiwiq.cpp index 611e789..69b5807 100644 --- a/src/core/Tiwiq.cpp +++ b/src/core/Tiwiq.cpp @@ -31,7 +31,7 @@ namespace twq void Tiwiq::update(Event& event) /*override*/ { - if (event.key) + if (event.type == EVENT_KEY) { if (!m_plugins.empty()) { diff --git a/src/core/UI.cpp b/src/core/UI.cpp index 702728e..ab73c49 100644 --- a/src/core/UI.cpp +++ b/src/core/UI.cpp @@ -11,5 +11,49 @@ namespace twq /*virtual*/ UI::~UI() { } + + void UI::write(Pixel const& pixel, Coord const& coord) + { + size_t index = coord.row() * m_screen_rect.size().col() + + coord.col(); + + TWQ_ASSERT(index < m_pixels.size(), "cannot write pixel at coord '" + + coord.string() + + "' (actual screen rect: '" + + m_screen_rect.string() + + "'"); + + m_pixels[index] = pixel; + + Event event; + event.type = EVENT_DRAW; + event.draw = DrawEvent { + coord, + pixel, + }; + + notify(event); + } + + void UI::resize(Rect const& rect) + { + size_t dim = rect.size().row() * rect.size().col(); + m_pixels.clear(); + + for (size_t i=0; i m_pixels; }; } } diff --git a/src/main.cpp b/src/main.cpp index e061cd7..f2f006c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,16 +7,21 @@ int main(int, char**) { auto tiwiq = std::make_shared(); auto term = std::make_shared(); + term->controller().lock()->add_observer(tiwiq); // Build and add plugins // --------------------- auto core_plugin = std::make_shared(); + core_plugin->ui().lock()->add_observer(term->view().lock()); + core_plugin->ui().lock()->resize(term->view().lock()->dim()); + tiwiq->add_plugin(core_plugin); // Start TiwiQ // ----------- tiwiq->start(); + bool a = true; while (tiwiq->is_running()) { diff --git a/src/term/Controller.cpp b/src/term/Controller.cpp index 3c88c9e..c728e26 100644 --- a/src/term/Controller.cpp +++ b/src/term/Controller.cpp @@ -18,6 +18,7 @@ namespace twq void Controller::update() { core::Event event; + event.type = core::EVENT_KEY; event.key = get(); notify(event); } diff --git a/src/term/Term.cpp b/src/term/Term.cpp index 39eba32..4a5c489 100644 --- a/src/term/Term.cpp +++ b/src/term/Term.cpp @@ -1,4 +1,5 @@ #include "Term.hpp" +#include namespace twq { @@ -12,6 +13,10 @@ namespace twq raw(); keypad(stdscr, TRUE); noecho(); + curs_set(0); + + TWQ_ASSERT(has_colors(), "your terminal does not support colors"); + start_color(); } /*virtual*/ Term::~Term() diff --git a/src/term/Term.hpp b/src/term/Term.hpp index 9021c41..44496dd 100644 --- a/src/term/Term.hpp +++ b/src/term/Term.hpp @@ -5,6 +5,7 @@ #include "../commons.hpp" #include "Controller.hpp" +#include "View.hpp" namespace twq { @@ -17,10 +18,14 @@ namespace twq virtual ~Term(); std::weak_ptr controller() { return m_controller; } + std::weak_ptr view() { return m_view; } private: std::shared_ptr m_controller = std::make_shared(); + + std::shared_ptr m_view = + std::make_shared(); }; } } diff --git a/src/term/View.cpp b/src/term/View.cpp new file mode 100644 index 0000000..c9d6a1d --- /dev/null +++ b/src/term/View.cpp @@ -0,0 +1,100 @@ +#include "View.hpp" +#include "../core/Event.hpp" + +namespace twq +{ + namespace term + { + /*explicit*/ View::View() + { + + } + + /*virtual*/ View::~View() + { + } + + core::Rect View::dim() const + { + int w, h; + getmaxyx(stdscr, h, w); + + return core::Rect { + core::Coord {0, 0}, + core::Coord {h, w} + }; + } + + void View::update(core::Event& event) /*override*/ + { + if (event.draw) + { + bkgdset(COLOR_PAIR(get_attr(Attribute { + core::Color::black(), + core::Color::white(), + }))); + + clear(); + + int i = event.draw->coord.row(); + int j = event.draw->coord.col(); + + int pair = get_attr(Attribute { + event.draw->pixel.background, + event.draw->pixel.foreground + }); + + attron(COLOR_PAIR(pair)); + mvprintw(j, i, "%lc", event.draw->pixel.text); + attroff(COLOR_PAIR(pair)); + + refresh(); + } + } + + int View::get_color(core::Color const& color) + { + for (auto p: m_colors) + { + if (p.second.equals(color)) + { + return p.first; + } + } + + int id = m_colors.size() + COLOR_WHITE + 1; + + auto format = [](int color_in){ + return static_cast((color_in / 255.0) * 1000.0); + }; + + init_color(id, + format(color.r()), + format(color.g()), + format(color.b())); + + + m_colors[id] = color; + + return id; + } + + int View::get_attr(Attribute const& attr) + { + for (auto p: m_attrs) + { + if (p.second.fg.equals(attr.fg) + && p.second.bg.equals(attr.bg)) + { + return p.first; + } + } + + int id = m_attrs.size() + 1; + init_pair(id, get_color(attr.fg), get_color(attr.bg)); + m_attrs[id] = attr; + + return id; + } + } +} diff --git a/src/term/View.hpp b/src/term/View.hpp new file mode 100644 index 0000000..8014d24 --- /dev/null +++ b/src/term/View.hpp @@ -0,0 +1,42 @@ +#ifndef twq_term_VIEW_HPP +#define twq_term_VIEW_HPP + +#include +#include "../commons.hpp" +#include "../core/Observer.hpp" +#include "../core/Observable.hpp" + +#include "../core/Rect.hpp" + +namespace twq +{ + namespace term + { + struct Attribute { + core::Color bg; + core::Color fg; + }; + + class View: public core::Observer, public core::Observable + { + public: + explicit View(); + virtual ~View(); + + core::Rect dim() const; + void update(core::Event& event) override; + + int get_color(core::Color const& color); + int get_attr(Attribute const& attr); + + private: + core::Rect m_prev_dim; + core::Rect m_dim; + + std::unordered_map m_colors; + std::unordered_map m_attrs; + }; + } +} + +#endif