summaryrefslogtreecommitdiff
path: root/libraries/pake/source
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/pake/source')
-rw-r--r--libraries/pake/source/dirtiable-image.cpp80
-rw-r--r--libraries/pake/source/widgets/fixed-text.cpp41
-rw-r--r--libraries/pake/source/window.cpp78
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 &param) {
+ 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();
+
+ }
+
+}