diff --git a/src/Box.cpp b/src/Box.cpp index bc5a46f..ee6d1df 100644 --- a/src/Box.cpp +++ b/src/Box.cpp @@ -75,4 +75,24 @@ Box Box::min_geometry() { return Box{ m_x, m_y, min_width, min_height }; } +double Box::clamp_for_dimension(Direction direction, double value) { + if (direction == Direction::Vertical) { + if (m_max_height != -1 && value > m_max_height) { + return m_max_height; + } else if (m_min_height != -1 && value < m_min_height) { + return m_min_height; + } else { + return value; + } + } else { + if (m_max_width != -1 && value > m_max_width) { + return m_max_width; + } else if (m_min_width != -1 && value < m_min_width) { + return m_min_width; + } else { + return value; + } + } +} + } diff --git a/src/Box.hpp b/src/Box.hpp index 201350b..08d22ab 100644 --- a/src/Box.hpp +++ b/src/Box.hpp @@ -51,6 +51,10 @@ public: double min_height() const { return m_min_height; } double max_width() const { return m_max_width; } double max_height() const { return m_max_height; } + double dimension_at(Direction direction) { return direction == Direction::Horizontal ? width() : height(); } + double max_dimension_at(Direction direction) { return direction == Direction::Horizontal ? max_width() : max_height(); } + double min_dimension_at(Direction direction) { return direction == Direction::Horizontal ? min_width() : min_height(); } + double clamp_for_dimension(Direction direction, double value); void set_x(double x) { m_x = x; } void set_y(double y) { m_y = y; } diff --git a/src/BoxLayout.cpp b/src/BoxLayout.cpp index 66ce463..edca432 100644 --- a/src/BoxLayout.cpp +++ b/src/BoxLayout.cpp @@ -13,80 +13,48 @@ void BoxLayout::run() { return; } - double total_space = m_direction == Direction::Horizontal ? m_target->rect().width() : m_target->rect().height(); + double total_space = m_target->rect().dimension_at(m_direction); double free_space = total_space; Point current_position { 0.0, 0.0 }; int unslotted_widgets = 0; std::vector working_slots(m_slots); for (unsigned int i = 0; i < m_target->children().size(); i++) { + auto child = m_target->children()[i]; if (i >= working_slots.size()) { - auto child = m_target->children()[i]; - if (m_direction == Direction::Horizontal) { - if (child->rect().min_width() != -1 || child->rect().max_width() != -1) { - child->rect().update(); - working_slots.push_back(Slot { - 0, - child->rect().width(), - SlotType::Pixel - }); - } else { - unslotted_widgets++; - working_slots.push_back(Slot { - 0, - 0, - SlotType::Auto - }); - } + // widgets which are outside the pre-defined slot range + + if (child->rect().max_dimension_at(m_direction) != -1 || child->rect().min_dimension_at(m_direction) != -1) { + // if the widget has a minimum or maximum size, we'll make a slot for its preferred size + child->rect().update(); + working_slots.push_back(Slot { 0, child->rect().dimension_at(m_direction), SlotType::Pixel }); + free_space -= child->rect().dimension_at(m_direction); } else { - if (child->rect().min_height() != -1 || child->rect().max_height() != -1) { - child->rect().update(); - working_slots.push_back(Slot { - 0, - child->rect().height(), - SlotType::Pixel - }); - } else { - unslotted_widgets++; - working_slots.push_back(Slot { - 0, - 0, - SlotType::Auto - }); - } + // we can consider widgets with no size perference "unslotted". these widgets will be evenly spaced amongst themselves. + unslotted_widgets++; + working_slots.push_back(Slot{ 0, 0, SlotType::Auto }); + } + } else { + // widgets which have a pre-defined slot + + // if the slot is fixed, we can already clamp it and subtract from free_space + if (working_slots[i].type == SlotType::Pixel) { + working_slots[i].pixel = child->rect().clamp_for_dimension(m_direction, working_slots[i].pixel); + free_space -= working_slots[i].pixel; } } } + // compute all percentages for slots for (unsigned int i = 0; i < m_target->children().size(); i++) { Slot *slot = &working_slots[i]; auto child = m_target->children()[i]; - if (slot->type == SlotType::Auto) { - continue; - } - if (slot->type == SlotType::Percent) { slot->pixel = ((free_space / 100.0) * slot->percent); + slot->pixel = child->rect().clamp_for_dimension(m_direction, slot->pixel); + free_space -= slot->pixel; } - - if (m_direction == Direction::Horizontal) { - if (child->rect().max_width() != -1 && slot->pixel > child->rect().max_width()) { - slot->pixel = child->rect().max_width(); - } - if (child->rect().min_width() != -1 && slot->pixel < child->rect().min_width()) { - slot->pixel = child->rect().min_width(); - } - } else { - if (child->rect().max_height() != -1 && slot->pixel > child->rect().max_height()) { - slot->pixel = child->rect().max_height(); - } - if (child->rect().min_height() != -1 && slot->pixel < child->rect().min_height()) { - slot->pixel = child->rect().min_height(); - } - } - - free_space -= slot->pixel; } double space_per_unslotted_widget = free_space / unslotted_widgets; @@ -94,6 +62,7 @@ void BoxLayout::run() { for (unsigned int i = 0; i < m_target->children().size(); i++) { auto child = m_target->children()[i]; Slot slot = working_slots[i]; + if (slot.type == SlotType::Auto) { slot.pixel = space_per_unslotted_widget; } @@ -117,19 +86,11 @@ void BoxLayout::run() { }; void BoxLayout::slot_percent(double percent) { - m_slots.push_back(Slot { - percent, - 0, - SlotType::Percent, - }); + m_slots.push_back(Slot { percent, 0, SlotType::Percent }); } void BoxLayout::slot_pixel(double pixel) { - m_slots.push_back(Slot { - 0, - pixel, - SlotType::Pixel, - }); + m_slots.push_back(Slot { 0, pixel, SlotType::Pixel }); } } diff --git a/src/main.cpp b/src/main.cpp index 828f328..24e3861 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,14 +22,13 @@ int main() { auto main_widget = window.set_main_widget(); auto main_layout = main_widget->set_layout(Raven::Direction::Vertical); - main_layout->slot_pixel(32); // top bar + main_layout->slot_pixel(30); // top bar auto top_bar = main_widget->add(); top_bar->set_style(&Raven::accent_widget_style); top_bar->set_layout(Raven::Direction::Horizontal); - auto scroll_container = main_widget->add(); - auto container_widget = scroll_container->make_target(); + auto container_widget = main_widget->add(); container_widget->set_layout(Raven::Direction::Vertical); container_widget->resize(400, 400); @@ -43,7 +42,9 @@ int main() { }; auto remove_button = top_bar->add("remove"); remove_button->on_click = [container_widget]() { - container_widget->remove_child(container_widget->children()[0]); + if (container_widget->children().size() > 0) { + container_widget->remove_child(container_widget->children()[0]); + } }; auto dummy_button = top_bar->add("dummy"); dummy_button->rect().set_max_width(60);