further improve boxlayout

This commit is contained in:
hippoz 2022-07-11 02:57:49 +03:00
parent 4f35de353e
commit 2fa09abbf2
Signed by: hippoz
GPG key ID: 7C52899193467641
4 changed files with 55 additions and 69 deletions

View file

@ -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;
}
}
}
}

View file

@ -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; }

View file

@ -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<Slot> 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 });
}
}

View file

@ -22,14 +22,13 @@ int main() {
auto main_widget = window.set_main_widget<Raven::Widget>();
auto main_layout = main_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Vertical);
main_layout->slot_pixel(32); // top bar
main_layout->slot_pixel(30); // top bar
auto top_bar = main_widget->add<Raven::Widget>();
top_bar->set_style(&Raven::accent_widget_style);
top_bar->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
auto scroll_container = main_widget->add<Raven::ScrollContainer>();
auto container_widget = scroll_container->make_target();
auto container_widget = main_widget->add<Raven::Widget>();
container_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Vertical);
container_widget->resize(400, 400);
@ -43,7 +42,9 @@ int main() {
};
auto remove_button = top_bar->add<Raven::Button>("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<Raven::Button>("dummy");
dummy_button->rect().set_max_width(60);