From 532df0ac7ffaaee037dbb22985e29aeca605d088 Mon Sep 17 00:00:00 2001 From: "Alejandro W. Sior" Date: Thu, 2 Feb 2023 11:05:01 +0100 Subject: chisel: initial commit --- .build | 18 +++ .gitignore | 3 + chisel/.build | 12 ++ chisel/attribute.hpp | 17 +++ chisel/box.cpp | 285 ++++++++++++++++++++++++++++++++++++++++++++++++ chisel/box.hpp | 75 +++++++++++++ chisel/button.cpp | 42 +++++++ chisel/button.hpp | 19 ++++ chisel/kiosk.cpp | 30 +++++ chisel/kiosk.hpp | 13 +++ chisel/sdl_window.cpp | 141 ++++++++++++++++++++++++ chisel/sdl_window.hpp | 32 ++++++ chisel/vertical_box.cpp | 27 +++++ chisel/vertical_box.hpp | 15 +++ chisel/window.hpp | 17 +++ main.cpp | 112 +++++++++++++++++++ socket/readme | 6 + socket/socket.hpp | 68 ++++++++++++ 18 files changed, 932 insertions(+) create mode 100644 .build create mode 100644 .gitignore create mode 100644 chisel/.build create mode 100644 chisel/attribute.hpp create mode 100644 chisel/box.cpp create mode 100644 chisel/box.hpp create mode 100644 chisel/button.cpp create mode 100644 chisel/button.hpp create mode 100644 chisel/kiosk.cpp create mode 100644 chisel/kiosk.hpp create mode 100644 chisel/sdl_window.cpp create mode 100644 chisel/sdl_window.hpp create mode 100644 chisel/vertical_box.cpp create mode 100644 chisel/vertical_box.hpp create mode 100644 chisel/window.hpp create mode 100644 main.cpp create mode 100644 socket/readme create mode 100644 socket/socket.hpp diff --git a/.build b/.build new file mode 100644 index 0000000..4c3789e --- /dev/null +++ b/.build @@ -0,0 +1,18 @@ +this.include_dirs = [Path('.').resolve()] +this.objects = [] +this.deps = [] + +this('chisel') + +this.objects += this.cpp.cc( + 'main.cpp', + + include_dirs = this.include_dirs, + dependencies = this.deps +) + +chisel = this.cpp.exe('chtest', + this.objects, + + dependencies = this.deps +) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f7172c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/bld/ +.ninja_* +build.ninja diff --git a/chisel/.build b/chisel/.build new file mode 100644 index 0000000..4480210 --- /dev/null +++ b/chisel/.build @@ -0,0 +1,12 @@ +this.deps += CDependency(['sdl2']) + +this.objects += this.cpp.cc( + 'box.cpp', + 'button.cpp', + 'kiosk.cpp', + 'sdl_window.cpp', + 'vertical_box.cpp', + + include_dirs = this.include_dirs, + dependencies = this.deps +) diff --git a/chisel/attribute.hpp b/chisel/attribute.hpp new file mode 100644 index 0000000..2f94b9f --- /dev/null +++ b/chisel/attribute.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace chisel { + enum AttributeType { + PX, + PR, + AUTO + }; + + struct Attribute { + enum AttributeType type; + union { + int px; + float pr; + }; + }; +} diff --git a/chisel/box.cpp b/chisel/box.cpp new file mode 100644 index 0000000..3215c24 --- /dev/null +++ b/chisel/box.cpp @@ -0,0 +1,285 @@ +#include "box.hpp" +#include "window.hpp" + +#include +#include + +namespace chisel { + Box::Box() {} + Box::~Box() { + for (auto &child : children) + delete child; + } + + void Box::damage() { + if (window->damaged_set.count(this) > 0) + return; + + window->damaged_set.insert(this); + window->damaged_deque.push_back(this); + + for (auto& child : children) + child->damage(); + } + + void Box::draw() { + fill_rect(0, 0, width, height, width % 256, height % 256, (width + height) % 256); + } + + void Box::fill_rect(int x0, int y0, int w, int h, int r, int g, int b) { + if (!parent) + return; + + if (x0 < 0) + x0 = 0; + if (y0 < 0) + y0 = 0; + if (x0 + w >= width) + w = width - x0; + if (y0 + h >= height) + h = height - x0; + + parent->fill_rect(x + x0, y + y0, w, h, r, g, b); + } + + void Box::add_child(Box *child) { + child->window = window; + child->parent = this; + children.push_back(child); + } + + void Box::event_on_mouse_button_up(int x, int y, int button) { + mouse_button_up(x, y, button); + + for (auto& child : children) + if (x >= child->x && x < child->x + child->width && y >= child->y && y < child->y + child->height) + child->event_on_mouse_button_up(x - child->x, y - child->y, button); + } + + void Box::event_on_mouse_button_down(int x, int y, int button) { + mouse_button_down(x, y, button); + + for (auto& child : children) + if (x >= child->x && x < child->x + child->width && y >= child->y && y < child->y + child->height) + child->event_on_mouse_button_down(x - child->x, y - child->y, button); + } + + void Box::event_on_mouse_motion(int x, int y) { + mouse_motion(x, y); + + for (auto& child : children) + if (x >= child->x && x < child->x + child->width && y >= child->y && y < child->y + child->height) { + child->event_on_mouse_motion(x - child->x, y - child->y); + + if (!child->hovered) + child->event_on_mouse_enter(x - child->x, y - child->y); + } else if (child->hovered) + child->event_on_mouse_exit(x - child->x, y - child->y); + } + + void Box::event_on_mouse_enter(int x, int y) { + hovered = true; + mouse_enter(x, y); + } + + void Box::event_on_mouse_exit(int x, int y) { + hovered = false; + mouse_exit(x, y); + + for (auto &child : children) + if (child->hovered) + child->event_on_mouse_exit(x - child->x, y - child->y); + } + + void Box::event_on_resize() { + arrange_pass0(); + //arrange_pass1(); + //arrange_pass2(); + // Broadcast resize event on socket + //resize(); + + // Make sure everything respects padding + /*int padding_width = width - padding_left - padding_right; + int padding_height = height - padding_top - padding_bottom; + + for (auto &child : children) { + int cx = child->x; + int cy = child->y; + int cw = child->width; + int ch = child->height; + + if (cx < padding_left) + cx = padding_left; + if (cy < padding_top) + cy = padding_top; + if (cx - padding_left + cw >= padding_width) + cw = padding_width + padding_left - cx; + if (cy - padding_top + ch >= padding_height) + ch = padding_height + padding_top - cy; + + if (child->x != cx || child->y != cy || child->width != cw || child->height != ch) { + damage(); + + child->x = cx; + child->y = cy; + child->width = cw; + child->height = ch; + child->event_on_resize(); + } + }*/ + } + + void Box::arrange_pass0() { + virtual_width = 0; + virtual_height = 0; + + int parent_padding_width = width; + int parent_padding_height = height; + int parent_padding_left = 0; + int parent_padding_top = 0; + if (parent) { + parent_padding_width = std::max(0, parent->virtual_width - parent->padding_left - parent->padding_right); + parent_padding_height = std::max(0, parent->virtual_height - parent->padding_top - parent->padding_bottom); + parent_padding_left = parent->padding_left; + parent_padding_top = parent->padding_top; + } + + if (width_attr.type == PX) + virtual_width = width_attr.px; + if (height_attr.type == PX) + virtual_height = height_attr.px; + + if (parent && width_attr.type == PR) + virtual_width = (int)((float)parent_padding_width * width_attr.pr); + if (parent && height_attr.type == PR) + virtual_height = (int)((float)parent_padding_height * height_attr.pr); + + // FIXME: can do weird stuff with multiplication for small values + for (auto &child : children) + child->arrange_pass0(); + + arrange_pass1(); + + int min_x = -1, min_y = -1; + int max_x = -1, max_y = -1; + for (auto &child : children) { + if (min_x == -1) { + min_x = child->x; + min_y = child->y; + } + + min_x = std::min(min_x, child->x); + min_y = std::min(min_y, child->y); + max_x = std::max(max_x, child->x + child->virtual_width); + max_y = std::max(max_y, child->y + child->virtual_height); + } + + if (virtual_width == 0) + virtual_width = max_x - min_x + padding_left + padding_right; + if (virtual_height == 0) + virtual_height = max_y - min_y + padding_top + padding_bottom; + + bool parent_known_width = true; + bool parent_known_height = true; + if (parent) { + parent_known_width = parent->virtual_width != 0; + parent_known_height = parent->virtual_height != 0; + } + + int cx = x; + int cy = y; + int cw = virtual_width; + int ch = virtual_height; + + if (cx < parent_padding_left) + cx = parent_padding_left; + if (cy < parent_padding_top) + cy = parent_padding_top; + if (parent_known_width && cx - parent_padding_top + cw >= parent_padding_width) + cw = parent_padding_width + parent_padding_top - cx; + if (parent_known_height && cy - parent_padding_top + ch >= parent_padding_height) + ch = parent_padding_height + parent_padding_top - cy; + + virtual_width = cw; + virtual_height = ch; + + for (auto &child : children) + child->arrange_pass0(); + + arrange_pass1(); + } + + void Box::arrange_pass1() { + //std::cout << "noice" << std::endl; + resize(); + } + + void Box::arrange_pass2() { + int parent_padding_width = virtual_width; + int parent_padding_height = virtual_height; + int parent_padding_left = 0; + int parent_padding_top = 0; + if (parent) { + parent_padding_width = std::max(0, parent->virtual_width - parent->padding_left - parent->padding_right); + parent_padding_height = std::max(0, parent->virtual_height - parent->padding_top - parent->padding_bottom); + parent_padding_left = parent->padding_left; + parent_padding_top = parent->padding_top; + } + + // FIXME + int min_x = -1, min_y = -1; + int max_x = -1, max_y = -1; + for (auto &child : children) { + if (min_x == -1) { + min_x = child->x; + min_y = child->y; + } + + min_x = std::min(min_x, child->x); + min_y = std::min(min_y, child->y); + max_x = std::max(max_x, child->x + child->virtual_width); + max_y = std::max(max_y, child->y + child->virtual_height); + } + + if (virtual_width == 0) + virtual_width = max_x - min_x + padding_left + padding_right; + if (virtual_height == 0) + virtual_height = max_y - min_y + padding_top + padding_bottom; + + int cx = x; + int cy = y; + int cw = virtual_width; + int ch = virtual_height; + + if (cx < parent_padding_left) + cx = parent_padding_left; + if (cy < parent_padding_top) + cy = parent_padding_top; + if (cx - parent_padding_top + cw >= parent_padding_width) + cw = parent_padding_width + parent_padding_top - cx; + if (cy - parent_padding_top + ch >= parent_padding_height) + ch = parent_padding_height + parent_padding_top - cy; + + std::cout << "parent be like: " << parent_padding_width << "x" << parent_padding_height << std::endl; + if (children.empty()) { + std::cout << "hi, i am innermost component, my dims are: " << virtual_width << "x" << virtual_height << std::endl; + } + + if (virtual_width != cw || virtual_height != ch) { + virtual_width = cw; + virtual_height = ch; + width = cw; + height = ch; + + // Should i do this? perhaps in layouting or something + + arrange_pass1(); + + // ? + damage(); + } + + for (auto &child : children) + child->arrange_pass2(); + } +} diff --git a/chisel/box.hpp b/chisel/box.hpp new file mode 100644 index 0000000..b9787b8 --- /dev/null +++ b/chisel/box.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include "attribute.hpp" + +#include +#include + +namespace chisel { + class Window; + + class Box { + public: + Box(); + virtual ~Box(); + + std::string id; + + socket::Socket mouse_button_down; + socket::Socket mouse_button_up; + socket::Socket mouse_motion; + socket::Socket mouse_enter; + socket::Socket mouse_exit; + socket::Socket resize; + + Window *window; + Box *parent = nullptr; + std::vector children; + + /* Real position and dimension after layout-ing */ + int x = 0; + int y = 0; + int width = 0; + int height = 0; + + /* Virtual dimensions used for bounding box calculation */ + int virtual_width = 0; + int virtual_height = 0; + + /* Width and height attributes as configured by user */ + Attribute width_attr = { AUTO }; + Attribute height_attr = { AUTO }; + + /* Padding in px (for now) */ + int padding_left = 0; + int padding_right = 0; + int padding_top = 0; + int padding_bottom = 0; + + bool hovered = false; + + void damage(); + virtual void draw(); + + virtual void fill_rect(int x0, int y0, int w, int h, int r, int g, int b); + + void add_child(Box *child); + + void event_on_mouse_button_up(int x, int y, int button); + void event_on_mouse_button_down(int x, int y, int button); + void event_on_mouse_motion(int x, int y); + void event_on_mouse_enter(int x, int y); + void event_on_mouse_exit(int x, int y); + void event_on_resize(); + + // Self determination of current and children dims + void arrange_pass0(); + + // Layoutting of current + void arrange_pass1(); + + // Constraining the children + void arrange_pass2(); + }; +} diff --git a/chisel/button.cpp b/chisel/button.cpp new file mode 100644 index 0000000..fa90713 --- /dev/null +++ b/chisel/button.cpp @@ -0,0 +1,42 @@ +#include "button.hpp" + +namespace chisel { + Button::Button() { + mouse_enter.connect(this, &Button::hover); + mouse_exit.connect(this, &Button::hover); + mouse_button_down.connect(this, &Button::press); + mouse_button_up.connect(this, &Button::depress); + pressed = false; + r = 255; + g = 255; + b = 255; + } + Button::~Button() {} + + void Button::hover(int x, int y) { + if (!hovered) + pressed = false; + damage(); + } + + void Button::press(int x, int y, int b) { + pressed = true; + damage(); + } + + void Button::depress(int x, int y, int b) { + pressed = false; + damage(); + } + + void Button::draw() { + if (pressed) + r = g = b = 0; + else if (hovered) + r = g = b = 255/2; + else + r = g = b = 255; + + fill_rect(0, 0, width, height, r, g, b); + } +} diff --git a/chisel/button.hpp b/chisel/button.hpp new file mode 100644 index 0000000..477d013 --- /dev/null +++ b/chisel/button.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "box.hpp" + +namespace chisel { + class Button : public Box { + public: + Button(); + virtual ~Button(); + + int r, g, b; + bool pressed; + + void hover(int x, int y); + void press(int x, int y, int b); + void depress(int x, int y, int b); + void draw() override; + }; +} diff --git a/chisel/kiosk.cpp b/chisel/kiosk.cpp new file mode 100644 index 0000000..0323822 --- /dev/null +++ b/chisel/kiosk.cpp @@ -0,0 +1,30 @@ +#include "kiosk.hpp" +#include + +namespace chisel { + Kiosk::Kiosk() { + resize.connect(this, &Kiosk::layout); + } + + Kiosk::~Kiosk() {} + + void Kiosk::layout() { + for (auto &child : children) { + int cx = padding_left; + int cy = padding_top; + int cw = child->virtual_width; + int ch = child->virtual_height; + + if (child->x != cx || child->y != cy || child->width != cw || child->height != ch) { + child->x = cx; + child->y = cy; + child->width = cw; + child->height = ch; + + // FIXME: is this needed ? + child->arrange_pass0(); + damage(); + } + } + } +} diff --git a/chisel/kiosk.hpp b/chisel/kiosk.hpp new file mode 100644 index 0000000..6d6f944 --- /dev/null +++ b/chisel/kiosk.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "box.hpp" + +namespace chisel { + class Kiosk : public Box { + public: + Kiosk(); + virtual ~Kiosk(); + + void layout(); + }; +} diff --git a/chisel/sdl_window.cpp b/chisel/sdl_window.cpp new file mode 100644 index 0000000..a969767 --- /dev/null +++ b/chisel/sdl_window.cpp @@ -0,0 +1,141 @@ +#include "sdl_window.hpp" + +#include +#include +#include + +namespace chisel { + int SDLWindow::count = 0; + + SDLWindow::SDLWindow(std::string title) { + title_ = title; + window = this; + width_attr.type = PX; + height_attr.type = PX; + padding_left = 0; + padding_right = 0; + padding_top = 0; + padding_bottom = 0; + + if (SDLWindow::count++ == 0) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + std::cerr << "could not initiate SDL" << std::endl; + } + + sdl_window = SDL_CreateWindow(title_.c_str(), + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + 640, 480, + SDL_WINDOW_RESIZABLE + ); + + if (!sdl_window) + std::cerr << "could not initiate SDL" << std::endl; + + sdl_renderer = SDL_CreateRenderer( + sdl_window, + -1, + SDL_RENDERER_SOFTWARE + ); + + SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255); + SDL_RenderClear(sdl_renderer); + SDL_RenderPresent(sdl_renderer); + } + + SDLWindow::~SDLWindow() { + SDL_DestroyWindow(sdl_window); + + if (--SDLWindow::count == 0) + SDL_Quit(); + } + + void SDLWindow::on_sdl_event(SDL_Event *event) { + // If the event does not relate to window, exit + if (SDL_GetWindowFromID(event->window.windowID) != sdl_window) + return; + + // If quitting event, stop running + if (event->type == SDL_QUIT) + running = false; + + // If resize event, handle it + if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED) { + // Update the width and height + SDL_GetWindowSize(sdl_window, &width, &height); + width_attr.px = width; + height_attr.px = height; + + // FIXME: temporary way to check if resize handling works + std::stringstream s; + s << width << "x" << height; + title(s.str()); + + damage(); + event_on_resize(); + } + + // If mouse button up event + if (event->type == SDL_MOUSEBUTTONUP) + event_on_mouse_button_up(event->button.x, event->button.y, event->button.button); + + // If mouse button down event + if (event->type == SDL_MOUSEBUTTONDOWN) + event_on_mouse_button_down(event->button.x, event->button.y, event->button.button); + + // If mouse motion + if (event->type == SDL_MOUSEMOTION) + event_on_mouse_motion(event->motion.x, event->motion.y); + } + + void SDLWindow::run() { + running = true; + + SDL_GetWindowSize(sdl_window, &width, &height); + event_on_resize(); + + while (running) { + if (damaged_set.empty()) { + SDL_Event event; + SDL_WaitEvent(&event); + on_sdl_event(&event); + } + + // Redraw damaged stuff + for (auto &damage : damaged_deque) + damage->draw(); + + // Present the buffer + if (damaged_set.size() > 0) + SDL_RenderPresent(sdl_renderer); + + // Empty the damaged boxes list + damaged_set.clear(); + damaged_deque.clear(); + } + } + + void SDLWindow::title(std::string title) { + title_ = title; + SDL_SetWindowTitle(sdl_window, title_.c_str()); + } + + std::string& SDLWindow::title() { + return title_; + } + + void SDLWindow::draw() { + SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 0xFF); + SDL_RenderClear(sdl_renderer); + } + + void SDLWindow::fill_rect(int x0, int y0, int w, int h, int r, int g, int b) { + SDL_Rect rect; + rect.x = x0; + rect.y = y0; + rect.w = w; + rect.h = h; + SDL_SetRenderDrawColor(sdl_renderer, r, g, b, 0xFF); + SDL_RenderFillRect(sdl_renderer, &rect); + } +} diff --git a/chisel/sdl_window.hpp b/chisel/sdl_window.hpp new file mode 100644 index 0000000..d809f54 --- /dev/null +++ b/chisel/sdl_window.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "window.hpp" +#include + +namespace chisel { + class SDLWindow : public Window { + SDL_Window *sdl_window; + SDL_Renderer *sdl_renderer; + + static int count; + + bool running; + + void on_sdl_event(SDL_Event* event); + public: + SDLWindow(std::string title); + virtual ~SDLWindow(); + + void run(); + + // Implements Window + void title(std::string title) override; + std::string& title() override; + + // Implements Box + void draw() override; + void fill_rect(int x0, int y0, int w, int h, int r, int g, int b) override; + }; +} diff --git a/chisel/vertical_box.cpp b/chisel/vertical_box.cpp new file mode 100644 index 0000000..0dd474a --- /dev/null +++ b/chisel/vertical_box.cpp @@ -0,0 +1,27 @@ +#include "vertical_box.hpp" + + +namespace chisel { + VerticalBox::VerticalBox() { + resize.connect(this, &VerticalBox::layout); + } + + VerticalBox::~VerticalBox() {} + + void VerticalBox::layout() { + int pos = padding_top; + + for (auto &child : children) { + int cx = padding_left; + int cy = pos; + + child->x = cx; + child->y = cy; + child->width = child->virtual_width; + child->height = child->virtual_height; + damage(); + + pos += child->virtual_height + margin; + } + } +} diff --git a/chisel/vertical_box.hpp b/chisel/vertical_box.hpp new file mode 100644 index 0000000..8f20da3 --- /dev/null +++ b/chisel/vertical_box.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "box.hpp" + +namespace chisel { + class VerticalBox : public Box { + public: + VerticalBox(); + virtual ~VerticalBox(); + + int margin; + + void layout(); + }; +} diff --git a/chisel/window.hpp b/chisel/window.hpp new file mode 100644 index 0000000..058f8a4 --- /dev/null +++ b/chisel/window.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include "kiosk.hpp" + +namespace chisel { + struct Window : public Kiosk { + std::set damaged_set; + std::deque damaged_deque; + std::string title_; + + virtual void title(std::string name) = 0; + virtual std::string& title() = 0; + }; +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..c1c14ca --- /dev/null +++ b/main.cpp @@ -0,0 +1,112 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include + +void mouse_button_up(int x, int y, int button) { + std::cout << "mouse button up " << x << " " << y << " " << button << std::endl; +} + +void mouse_button_down(int x, int y, int button) { + std::cout << "mouse button down " << x << " " << y << " " << button << std::endl; +} + +void mouse_enter(int x, int y) { + std::cout << "mouse entered from " << x << " " << y << std::endl; +} + +void mouse_exit(int x, int y) { + std::cout << "mouse exitted on " << x << " " << y << std::endl; +} + +int main() { + std::cout << "chisel toolkit" << std::endl; + chisel::SDLWindow window("hai"); + chisel::Kiosk *a = new chisel::Kiosk(); + a->padding_top = 10; + a->padding_bottom = 10; + a->padding_left = 10; + a->padding_right = 10; + a->width_attr = { + .type = chisel::PR, + .pr = 1.0 + }; + a->height_attr = { + .type = chisel::PR, + .pr = 1.0 + }; + a->mouse_button_up.connect(mouse_button_up); + a->mouse_button_down.connect(mouse_button_down); + a->mouse_enter.connect(mouse_enter); + a->mouse_exit.connect(mouse_exit); + window.add_child(a); + chisel::VerticalBox *b = new chisel::VerticalBox(); + b->id = "B"; + b->margin = 8; + b->padding_top = 15; + b->padding_bottom = 15; + b->padding_left = 15; + b->padding_right = 15; + b->width_attr = { + .type = chisel::PR, + .pr = 1.0 + }; + b->height_attr = { + .type = chisel::PR, + .pr = 1.0 + }; + b->mouse_button_up.connect(mouse_button_up); + b->mouse_button_down.connect(mouse_button_down); + b->mouse_enter.connect(mouse_enter); + b->mouse_exit.connect(mouse_exit); + a->add_child(b); + + for (int i = 0; i < 5; i++) { + chisel::Button *c = new chisel::Button(); + c->width_attr = { + .type = chisel::PR, + .pr = 1.0 + }; + c->height_attr = { + .type = chisel::PR, + .pr = 0.08 + }; + c->mouse_button_up.connect(mouse_button_up); + c->mouse_button_down.connect(mouse_button_down); + c->mouse_enter.connect(mouse_enter); + c->mouse_exit.connect(mouse_exit); + b->add_child(c); + } + +/* + chisel::Button *c = new chisel::Button(); + c->x = 0; + c->y = 0; + c->width_attr = { + .type = chisel::PX, + .px = 30 + }; + c->height_attr = { + .type = chisel::PX, + .px = 25 + }; + c->parent = b; + c->window = &window; + c->mouse_button_up.connect(mouse_button_up); + c->mouse_button_down.connect(mouse_button_down); + c->mouse_enter.connect(mouse_enter); + c->mouse_exit.connect(mouse_exit); + b->add_child(c);*/ + + window.run(); + + chisel::AttributeType attr = chisel::AttributeType::AUTO; + + return 0; +} diff --git a/socket/readme b/socket/readme new file mode 100644 index 0000000..0046460 --- /dev/null +++ b/socket/readme @@ -0,0 +1,6 @@ +The [[socket]] module introduces a structure +called a socket, whose purpose is to be able +to dispatch a function call to an arbitrary +number of handlers. Those handlers can be +connected and disconnected from the socket +dynamically. diff --git a/socket/socket.hpp b/socket/socket.hpp new file mode 100644 index 0000000..dd9b2a3 --- /dev/null +++ b/socket/socket.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +namespace socket { + /* Allows casting R(Args...) */ + template + class Socket; + + /* A class that represents a socket that can + be used to dispatch a function call to different + handlers. Handlers can be connected and disconnected + from the socket at runtime. */ + template + class Socket { + /* The type of handler function or methods */ + using HandlerType = std::function; + + + /* The next handler descriptor to be assigned + the descriptor can be used to disconnect + a descriptor */ + int descriptor; + + /* Map between descriptors and handlers */ + std::map handlers; + public: + /* Connect a handler to the socket + handler: the handler to connect to + Returns the handler descriptor */ + int connect(HandlerType handler) { + // Get the handler descriptor of next handler + int hd = descriptor++; + + // Store the handler + handlers[hd] = handler; + + return hd; + } + + /* Connect a handler to the socket + and bind the call to an object, this + can be useful if the handler is a method */ + template + int connect(T *object, R (V::*handler)(Args...)) { + auto f = [=](Args... args) { + return std::invoke(handler, object, args...); + }; + + return connect(f); + } + + /* Disconnect a handler from the socket + hd: the handle descriptor of the handler + to disconnect */ + void disconnect(int hd) { + // Remove the handler from the map + handlers.erase(hd); + } + + /* Dispatch a call to all handlers */ + void operator()(Args... args) { + for (auto &handler : handlers) + handler.second(args...); + } + }; +} -- cgit v1.2.3