summaryrefslogtreecommitdiff
path: root/chisel/box.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chisel/box.cpp')
-rw-r--r--chisel/box.cpp285
1 files changed, 285 insertions, 0 deletions
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 <algorithm>
+#include <iostream>
+
+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();
+ }
+}