diff options
Diffstat (limited to 'libraries/pake/source')
-rw-r--r-- | libraries/pake/source/dirtiable-image.cpp | 80 | ||||
-rw-r--r-- | libraries/pake/source/widgets/fixed-text.cpp | 41 | ||||
-rw-r--r-- | libraries/pake/source/window.cpp | 78 |
3 files changed, 199 insertions, 0 deletions
diff --git a/libraries/pake/source/dirtiable-image.cpp b/libraries/pake/source/dirtiable-image.cpp new file mode 100644 index 0000000..9e5c979 --- /dev/null +++ b/libraries/pake/source/dirtiable-image.cpp @@ -0,0 +1,80 @@ +#include <pake/dirtiable-image.hpp> + +namespace pake { + + struct dirty_region_builder { + + std::vector<region> regions_not_on_bottom; + std::list<region> regions_on_bottom; + + void add_row(const std::vector<region> &row) { + + std::list<region> new_regions_on_bottom; + + for (auto i = row.begin(); i < row.end(); ++i) { + bool expanded = false; + for (auto j = regions_on_bottom.begin(); j != regions_on_bottom.end(); ++j) + if (i->start_x == j->start_x && i->width == j->width) { + j->height += i->height; + new_regions_on_bottom.push_back(*j); + regions_on_bottom.erase(j); + expanded = true; + break; + } + if (!expanded) + new_regions_on_bottom.push_back(*i); + } + + for (auto i = regions_on_bottom.begin(); i != regions_on_bottom.end(); ++i) + regions_not_on_bottom.push_back(*i); + + regions_on_bottom = std::move(new_regions_on_bottom); + + } + + }; + + std::vector<region> dirtiable_image::get_dirty_regions() { + + dirty_region_builder builder; + + std::vector<region> row; + + for (int y = 0; y < dirty.height; ++y) { + + int r = 0; + for (int x = 0; x < dirty.width; ++x) + if (!dirty.at(x, y)) { + if (r != x) + row.push_back({ + .start_x = r, .start_y = y, + .width = x - r, .height = 1 + }); + r = x + 1; + } + if (r != dirty.width) + row.push_back({ + .start_x = r, .start_y = y, + .width = dirty.width - r, .height = 1 + }); + + builder.add_row(row); + row.clear(); + + } + + builder.add_row(row); + return builder.regions_not_on_bottom; + + } + + void dirtiable_image::clear_dirty() { + dirty.fill(false); + } + + dirtiable_image::dirtiable_image(int width, int height) + : image(width, height), dirty(width, height) { + dirty.fill(false); + } + +} diff --git a/libraries/pake/source/widgets/fixed-text.cpp b/libraries/pake/source/widgets/fixed-text.cpp new file mode 100644 index 0000000..9ae55dc --- /dev/null +++ b/libraries/pake/source/widgets/fixed-text.cpp @@ -0,0 +1,41 @@ +#include <pake/widgets/fixed-text.hpp> + +static void draw_if_true( + daguerre::hilbert_color &out, const bool &in, + const daguerre::hilbert_color ¶m) { + if (in) out = param; +} + +namespace pake::widgets { + + fixed_text::fixed_text( + std::string &&text, + const daguerre::fixed_font<bool> *font, + daguerre::hilbert_color bg, + daguerre::hilbert_color fg) + : font(font), bg(bg), fg(fg), text(std::move(text)) {} + + void fixed_text::render( + dirtiable_image &onto, int x_off, int y_off, bool force) { + + if (force) { + onto.image.fill( bg, x_off, y_off, width, height); + onto.dirty.fill(true, x_off, y_off, width, height); + //TODO: have options for alignment + //TODO: check overflow + onto.image.render_text( + *font, fg, x_off, y_off, + text.data(), draw_if_true); + onto.dirty.fill( + true, x_off, y_off, + font->glyph_width * text.size(), + font->glyph_height); + } + + } + + void fixed_text::notify_size(int width, int height) { + this->width = width; this->height = height; + } + +} diff --git a/libraries/pake/source/window.cpp b/libraries/pake/source/window.cpp new file mode 100644 index 0000000..c1c773f --- /dev/null +++ b/libraries/pake/source/window.cpp @@ -0,0 +1,78 @@ +#include <pake/window.hpp> +#include <cassert> + +//TODO: handle errors on socket connection, read, and write + +namespace pake { + + window::window(int width, int height, const std::string &title) + : width(width), height(height), contents(width, height), root() { + + euler::syscall::connect_to_socket("hilbert.compositor", socket); + + assert(width >= 0 && height >= 0); + + struct [[gnu::packed]] { uint8_t type; uint32_t width; uint32_t height; } + dimensions_pkt = {.type = 0x02, .width = (uint32_t)width, .height = (uint32_t)height }; + euler::syscall::write_to_stream(socket, sizeof(dimensions_pkt), &dimensions_pkt); + + assert(title.size() <= UINT32_MAX); + + struct [[gnu::packed]] { uint8_t type; uint32_t length; } + title_pkt = {.type = 0x03, .length = (uint32_t)title.size() }; + euler::syscall::write_to_stream(socket, sizeof(title_pkt), &title_pkt); + euler::syscall::write_to_stream(socket, title.size(), title.data()); + + } + + window::~window() { + euler::syscall::close_stream(socket); + } + + void window::show() { + uint8_t packet = 0; + euler::syscall::write_to_stream(socket, 1, &packet); + } + + void window::hide() { + uint8_t packet = 1; + euler::syscall::write_to_stream(socket, 1, &packet); + } + + void window::set_root(std::unique_ptr<widget> &&w) { + root = std::move(w); + root->notify_size(width, height); + root->render(contents, 0, 0, true); + } + + void window::render_and_send_to_compositor() { + + root->render(contents, 0, 0, false); + auto dirties = contents.get_dirty_regions(); + + for (auto it = dirties.cbegin(); it != dirties.cend(); ++it) { + + struct [[gnu::packed]] { + uint8_t type; + uint32_t start_x; uint32_t start_y; + uint32_t width; uint32_t height; + } update_pkt = { + .type = 0x04, + .start_x = (uint32_t)it->start_x, .start_y = (uint32_t)it->start_y, + . width = (uint32_t)it-> width, . height = (uint32_t)it-> height + }; + + euler::syscall::write_to_stream(socket, sizeof(update_pkt), &update_pkt); + + for (int y = it->start_y; y < it->start_y + it->height; ++y) + euler::syscall::write_to_stream(socket, + it->width * sizeof(daguerre::hilbert_color), + &contents.image.at(it->start_x, y)); + + } + + contents.clear_dirty(); + + } + +} |