diff --git a/meson.build b/meson.build index 36e45e4..df5ab20 100644 --- a/meson.build +++ b/meson.build @@ -16,6 +16,7 @@ executable( './src/DocumentLayout.cpp', './src/HorizontalBoxLayout.cpp', './src/VerticalBoxLayout.cpp', + './src/BoxLayout.cpp', './src/Label.cpp', './src/main.cpp', dependencies : [cairomm_dep, xlib_dep, pangocairo_dep] diff --git a/src/Box.hpp b/src/Box.hpp index 056faba..d141b46 100644 --- a/src/Box.hpp +++ b/src/Box.hpp @@ -4,6 +4,11 @@ namespace Raven { +enum class Direction { + Horizontal, + Vertical +}; + class Box { private: double m_x {0}; diff --git a/src/BoxLayout.cpp b/src/BoxLayout.cpp new file mode 100644 index 0000000..3b3b31e --- /dev/null +++ b/src/BoxLayout.cpp @@ -0,0 +1,90 @@ +#include "BoxLayout.hpp" +#include "Box.hpp" +#include "Widget.hpp" +#include + + +namespace Raven { + +void BoxLayout::run() { + if (!m_target) { + return; + } + + Box free_space = m_target->rect().max_geometry(); + Box total_space = m_target->rect().max_geometry(); + Point current_position { 0.0, 0.0 }; + + int unslotted_widgets = 0; + for (unsigned int i = 0; i < m_target->children().size(); i++) { + if (i >= m_slots.size()) { + unslotted_widgets++; + } + } + double space_per_unslotted_widget = m_direction == Direction::Horizontal ? total_space.width() / unslotted_widgets : total_space.height() / unslotted_widgets; + + for (unsigned int i = 0; i < m_target->children().size(); i++) { + auto child = m_target->children()[i]; + Slot slot; + if (i >= m_slots.size()) { + slot = Slot { + 0.0, + space_per_unslotted_widget, + SlotType::Pixel + }; + } else { + slot = m_slots[i]; + } + + // resolve slot size + if (slot.type == SlotType::Percent) { + if (m_direction == Direction::Horizontal) { + slot.pixel = (free_space.width() / 100.0) * slot.percent; + } else { + slot.pixel = (free_space.height() / 100.0) * slot.percent; + } + } + + // justify child geometry, stop looping if free space has been exhausted + child->rect().set_x(current_position.x()); + child->rect().set_y(current_position.y()); + if (m_direction == Direction::Horizontal) { + child->rect().set_width(slot.pixel); + child->rect().set_height(free_space.height()); + current_position.add(slot.pixel, 0); + free_space.set_width(free_space.width() - slot.pixel); + + if (free_space.width() <= 0) { + break; + } + } else { + child->rect().set_width(free_space.width()); + child->rect().set_height(slot.pixel); + current_position.add(0, slot.pixel); + free_space.set_height(free_space.height() - slot.pixel); + + if (free_space.height() <= 0) { + break; + } + } + } +}; + +void BoxLayout::slot_percent(double 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, + }); +} + +} + diff --git a/src/BoxLayout.hpp b/src/BoxLayout.hpp new file mode 100644 index 0000000..296d6d9 --- /dev/null +++ b/src/BoxLayout.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "src/Layout.hpp" +#include "src/Widget.hpp" +#include "src/Box.hpp" +#include +#include + +namespace Raven { + +class BoxLayout : public Layout { +public: +enum class SlotType { + No, + Percent, + Pixel +}; +struct Slot { + double percent, pixel; + SlotType type; +}; +public: + BoxLayout(Direction direction) + : Layout() + , m_direction(direction) {} + ~BoxLayout() {} + + void run(); + void slot_percent(double percent); + void slot_pixel(double pixel); +private: + std::vector m_slots; + Direction m_direction { Direction::Horizontal }; +}; + +} + diff --git a/src/main.cpp b/src/main.cpp index 7da42ce..c5aeade 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,8 @@ #include "RGB.hpp" #include "DocumentLayout.hpp" #include "Events.hpp" +#include "src/BoxLayout.hpp" +#include "src/Box.hpp" #include "src/HorizontalBoxLayout.hpp" #include "src/ScrollContainer.hpp" #include "src/Styles.hpp" @@ -21,18 +23,17 @@ int main() { window.spawn_window(); auto main_widget = window.set_main_widget(); - main_widget->set_layout(6.0); + main_widget->set_layout(Raven::Direction::Horizontal); - auto scroll = main_widget->add(); - scroll->set_style(&Raven::accent_widget_style); - scroll->resize(200, 200); - auto target = scroll->make_target(); - target->set_layout(8.0); - target->rect().set_max_width(200); + auto inner = main_widget->add(); + inner->resize(400, 200); + inner->set_style(&Raven::accent_widget_style); + auto inner_layout = inner->set_layout(Raven::Direction::Horizontal); + inner_layout->slot_pixel(20); + inner_layout->slot_percent(50); - for (int i = 0; i < 300; i++) { - auto button = target->add(std::to_string(i)); - button->set_style(&Raven::accent_button_style); + for (int i = 0; i < 4; i++) { + auto button = inner->add("h"); } window.run(true);