diff --git a/Libraries/LibGUI/BoxLayout.cpp b/Libraries/LibGUI/BoxLayout.cpp index 10aa0f7932..c38ff6b5cb 100644 --- a/Libraries/LibGUI/BoxLayout.cpp +++ b/Libraries/LibGUI/BoxLayout.cpp @@ -61,8 +61,6 @@ void BoxLayout::run(Widget& widget) if (should_log) dbgprintf("BoxLayout: Starting with available size: %s\n", available_size.to_string().characters()); - Optional last_entry_with_automatic_size; - for (size_t i = 0; i < m_entries.size(); ++i) { auto& entry = m_entries[i]; if (entry.type == Entry::Type::Spacer) { @@ -83,8 +81,6 @@ void BoxLayout::run(Widget& widget) if (should_log) dbgprintf("BoxLayout: Available size after: %s\n", available_size.to_string().characters()); ++number_of_entries_with_fixed_size; - } else { - last_entry_with_automatic_size = i; } available_size -= { spacing(), spacing() }; } @@ -102,21 +98,21 @@ void BoxLayout::run(Widget& widget) dbgprintf("BoxLayout: available_size=%s, fixed=%d, fill=%d\n", available_size.to_string().characters(), number_of_entries_with_fixed_size, number_of_entries_with_automatic_size); Gfx::IntSize automatic_size; - Gfx::IntSize automatic_size_for_last_entry; + + int remaining_size = 0; + int number_of_entries_with_automatic_size_remaining = number_of_entries_with_automatic_size; if (number_of_entries_with_automatic_size) { if (m_orientation == Orientation::Horizontal) { automatic_size.set_width(available_size.width() / number_of_entries_with_automatic_size); automatic_size.set_height(widget.height()); - automatic_size_for_last_entry.set_width(available_size.width() - (number_of_entries_with_automatic_size - 1) * automatic_size.width()); - automatic_size_for_last_entry.set_height(widget.height()); + remaining_size = available_size.width(); } else { automatic_size.set_width(widget.width()); automatic_size.set_height(available_size.height() / number_of_entries_with_automatic_size); - automatic_size_for_last_entry.set_width(widget.width()); - automatic_size_for_last_entry.set_height(available_size.height() - (number_of_entries_with_automatic_size - 1) * automatic_size.height()); + remaining_size = available_size.height(); } } @@ -131,6 +127,7 @@ void BoxLayout::run(Widget& widget) if (entry.type == Entry::Type::Spacer) { current_x += automatic_size.width(); current_y += automatic_size.height(); + continue; } if (!entry.widget) @@ -144,36 +141,71 @@ void BoxLayout::run(Widget& widget) } ASSERT(entry.widget); - if (last_entry_with_automatic_size.has_value() && i == last_entry_with_automatic_size.value()) { - rect.set_size(automatic_size_for_last_entry); + if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fixed) { + rect.set_width(widget.width()); + rect.set_height(entry.widget->preferred_size().height()); } else { - rect.set_size(automatic_size); + if (orientation() == Orientation::Horizontal) + rect.set_height(widget.height()); + else + rect.set_height(remaining_size / number_of_entries_with_automatic_size_remaining); } - if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fixed) - rect.set_height(entry.widget->preferred_size().height()); - - if (entry.widget->size_policy(Orientation::Horizontal) == SizePolicy::Fixed) + if (entry.widget->size_policy(Orientation::Horizontal) == SizePolicy::Fixed) { rect.set_width(entry.widget->preferred_size().width()); + rect.set_height(widget.height()); + } else { + if (orientation() == Orientation::Horizontal) + rect.set_width(remaining_size / number_of_entries_with_automatic_size_remaining); + else + rect.set_width(widget.width()); + } if (orientation() == Orientation::Horizontal) { if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fill) rect.set_height(widget.height() - margins().top() - margins().bottom()); - rect.center_vertically_within(widget.rect()); } else { if (entry.widget->size_policy(Orientation::Horizontal) == SizePolicy::Fill) rect.set_width(widget.width() - margins().left() - margins().right()); - rect.center_horizontally_within(widget.rect()); } + // Apply min/max constraints to filled widgets. + if (entry.widget->size_policy(Orientation::Horizontal) == SizePolicy::Fill) { + if (entry.widget->min_size().width() >= 0) + rect.set_width(max(entry.widget->min_size().width(), rect.width())); + if (entry.widget->max_size().width() >= 0) + rect.set_width(min(entry.widget->max_size().width(), rect.width())); + } + if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fill) { + if (entry.widget->min_size().height() >= 0) + rect.set_height(max(entry.widget->min_size().height(), rect.height())); + if (entry.widget->max_size().height() >= 0) + rect.set_height(min(entry.widget->max_size().height(), rect.height())); + } + + if (orientation() == Orientation::Horizontal) + rect.center_vertically_within(widget.rect()); + else + rect.center_horizontally_within(widget.rect()); + if (should_log) dbgprintf("BoxLayout: apply, %s{%p} <- %s\n", entry.widget->class_name(), entry.widget.ptr(), rect.to_string().characters()); + entry.widget->set_relative_rect(rect); - if (orientation() == Orientation::Horizontal) + if (orientation() == Orientation::Horizontal) { + if (entry.widget->size_policy(Orientation::Horizontal) == SizePolicy::Fill) { + remaining_size -= rect.width(); + --number_of_entries_with_automatic_size_remaining; + } current_x += rect.width() + spacing(); - else + } else { + if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fill) { + remaining_size -= rect.height(); + --number_of_entries_with_automatic_size_remaining; + } current_y += rect.height() + spacing(); + } } } } diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index b0d93fd8df..5c8f72c9ff 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -138,6 +138,13 @@ Widget::Widget() REGISTER_SIZE_POLICY_PROPERTY("horizontal_size_policy", horizontal_size_policy, set_horizontal_size_policy); REGISTER_SIZE_POLICY_PROPERTY("vertical_size_policy", vertical_size_policy, set_vertical_size_policy); + REGISTER_SIZE_PROPERTY("min_size", min_size, set_min_size); + REGISTER_SIZE_PROPERTY("max_size", max_size, set_max_size); + REGISTER_INT_PROPERTY("min_width", min_width, set_min_width); + REGISTER_INT_PROPERTY("max_width", max_width, set_max_width); + REGISTER_INT_PROPERTY("min_height", min_height, set_min_height); + REGISTER_INT_PROPERTY("max_height", max_height, set_max_height); + register_property( "focus_policy", [this]() -> JsonValue { auto policy = focus_policy(); @@ -659,6 +666,22 @@ bool Widget::global_cursor_tracking() const return win->global_cursor_tracking_widget() == this; } +void Widget::set_min_size(const Gfx::IntSize& size) +{ + if (m_min_size == size) + return; + m_min_size = size; + invalidate_layout(); +} + +void Widget::set_max_size(const Gfx::IntSize& size) +{ + if (m_max_size == size) + return; + m_max_size = size; + invalidate_layout(); +} + void Widget::set_preferred_size(const Gfx::IntSize& size) { if (m_preferred_size == size) diff --git a/Libraries/LibGUI/Widget.h b/Libraries/LibGUI/Widget.h index 162c46039e..987f8d1d49 100644 --- a/Libraries/LibGUI/Widget.h +++ b/Libraries/LibGUI/Widget.h @@ -120,6 +120,24 @@ public: void set_horizontal_size_policy(SizePolicy policy) { set_size_policy(policy, vertical_size_policy()); } void set_vertical_size_policy(SizePolicy policy) { set_size_policy(horizontal_size_policy(), policy); } + Gfx::IntSize min_size() const { return m_min_size; } + void set_min_size(const Gfx::IntSize&); + void set_min_size(int width, int height) { set_min_size({ width, height }); } + + int min_width() const { return m_min_size.width(); } + int min_height() const { return m_min_size.height(); } + void set_min_width(int width) { set_min_size(width, min_height()); } + void set_min_height(int height) { set_min_size(min_width(), height); } + + Gfx::IntSize max_size() const { return m_max_size; } + void set_max_size(const Gfx::IntSize&); + void set_max_size(int width, int height) { set_max_size({ width, height }); } + + int max_width() const { return m_max_size.width(); } + int max_height() const { return m_max_size.height(); } + void set_max_width(int width) { set_max_size(width, max_height()); } + void set_max_height(int height) { set_max_size(max_width(), height); } + Gfx::IntSize preferred_size() const { return m_preferred_size; } void set_preferred_size(const Gfx::IntSize&); void set_preferred_size(int width, int height) { set_preferred_size({ width, height }); } @@ -365,6 +383,8 @@ private: SizePolicy m_horizontal_size_policy { SizePolicy::Fill }; SizePolicy m_vertical_size_policy { SizePolicy::Fill }; Gfx::IntSize m_preferred_size; + Gfx::IntSize m_min_size { -1, -1 }; + Gfx::IntSize m_max_size { -1, -1 }; Margins m_content_margins; bool m_fill_with_background_color { false };