diff options
Diffstat (limited to 'chisel/box.cpp')
| -rw-r--r-- | chisel/box.cpp | 285 |
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(); + } +} |
