1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:57:35 +00:00

LibGUI: Rewrite layout system in terms of min and max sizes

This patch removes size policies and preferred sizes, and replaces them
with min-size and max-size for each widget.

Box layout now works in 3 passes:

    1) Set all items (widgets/spacers) to their min-size
    2) Distribute remaining space evenly, respecting max-size
    3) Place widgets one after the other, adding spacing in between

I've also added convenience helpers for setting a fixed size (which is
the same as setting min-size and max-size to the same value.)

This significantly reduces the verbosity of widget layout and makes GML
a bit more pleasant to write, too. :^)
This commit is contained in:
Andreas Kling 2020-12-30 01:23:32 +01:00
parent b2bba5ce5c
commit 7dc5a3ead8
83 changed files with 444 additions and 957 deletions

View file

@ -57,19 +57,16 @@ AboutDialog::AboutDialog(const StringView& name, const Gfx::Bitmap* icon, Window
banner_image.load_from_file("/res/graphics/brand-banner.png");
auto& content_container = widget.add<Widget>();
content_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
content_container.set_layout<HorizontalBoxLayout>();
auto& left_container = content_container.add<Widget>();
left_container.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
left_container.set_preferred_size(60, 0);
left_container.set_fixed_width(60);
left_container.set_layout<VerticalBoxLayout>();
left_container.layout()->set_margins({ 0, 12, 0, 0 });
if (icon) {
auto& icon_wrapper = left_container.add<Widget>();
icon_wrapper.set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
icon_wrapper.set_preferred_size(32, 48);
icon_wrapper.set_fixed_size(32, 48);
icon_wrapper.set_layout<VerticalBoxLayout>();
auto& icon_image = icon_wrapper.add<ImageWidget>();
@ -83,8 +80,7 @@ AboutDialog::AboutDialog(const StringView& name, const Gfx::Bitmap* icon, Window
auto make_label = [&](const StringView& text, bool bold = false) {
auto& label = right_container.add<Label>(text);
label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
label.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
label.set_preferred_size(0, 14);
label.set_fixed_height(14);
if (bold)
label.set_font(Gfx::Font::default_bold_font());
};
@ -98,13 +94,11 @@ AboutDialog::AboutDialog(const StringView& name, const Gfx::Bitmap* icon, Window
right_container.layout()->add_spacer();
auto& button_container = right_container.add<Widget>();
button_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container.set_preferred_size(0, 23);
button_container.set_fixed_height(23);
button_container.set_layout<HorizontalBoxLayout>();
button_container.layout()->add_spacer();
auto& ok_button = button_container.add<Button>("OK");
ok_button.set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
ok_button.set_preferred_size(80, 23);
ok_button.set_fixed_size(80, 23);
ok_button.on_click = [this](auto) {
done(Dialog::ExecOK);
};

View file

@ -350,7 +350,7 @@ void AbstractTableView::layout_headers()
int y = frame_thickness();
int width = AK::max(content_width(), rect().width() - frame_thickness() * 2 - row_header_width - vertical_scrollbar_width);
column_header().set_relative_rect(x, y, width, column_header().preferred_size().height());
column_header().set_relative_rect(x, y, width, column_header().min_size().height());
}
if (row_header().is_visible()) {
@ -361,7 +361,7 @@ void AbstractTableView::layout_headers()
int y = frame_thickness() + column_header_height - vertical_scrollbar().value();
int height = AK::max(content_height(), rect().height() - frame_thickness() * 2 - column_header_height - horizontal_scrollbar_height);
row_header().set_relative_rect(x, y, row_header().preferred_size().width(), height);
row_header().set_relative_rect(x, y, row_header().min_size().width(), height);
}
if (row_header().is_visible() && column_header().is_visible()) {

View file

@ -43,169 +43,124 @@ BoxLayout::BoxLayout(Orientation orientation)
void BoxLayout::run(Widget& widget)
{
bool should_log = false;
#ifdef GBOXLAYOUT_DEBUG
should_log = true;
#endif
if (should_log)
dbgprintf("BoxLayout: running layout on %s{%p}, entry count: %zu\n", widget.class_name(), &widget, m_entries.size());
if (m_entries.is_empty())
return;
Gfx::IntSize available_size = widget.size();
int number_of_entries_with_fixed_size = 0;
struct Item {
Widget* widget { nullptr };
int min_size { -1 };
int max_size { -1 };
int size { 0 };
bool final { false };
};
int number_of_visible_entries = 0;
if (should_log)
dbgprintf("BoxLayout: Starting with available size: %s\n", available_size.to_string().characters());
Vector<Item, 32> items;
for (size_t i = 0; i < m_entries.size(); ++i) {
auto& entry = m_entries[i];
if (entry.type == Entry::Type::Spacer) {
++number_of_visible_entries;
items.append(Item { nullptr, -1, -1 });
continue;
}
if (!entry.widget)
continue;
if (!entry.widget->is_visible())
continue;
++number_of_visible_entries;
if (entry.widget && entry.widget->size_policy(orientation()) == SizePolicy::Fixed) {
if (should_log) {
dbgprintf("BoxLayout: Subtracting for fixed %s{%p}, size: %s\n", entry.widget->class_name(), entry.widget.ptr(), entry.widget->preferred_size().to_string().characters());
dbgprintf("BoxLayout: Available size before: %s\n", available_size.to_string().characters());
auto min_size = entry.widget->min_size();
auto max_size = entry.widget->max_size();
items.append(Item { entry.widget.ptr(), min_size.primary_size_for_orientation(orientation()), max_size.primary_size_for_orientation(orientation()) });
}
if (items.is_empty())
return;
int available_size = widget.size().primary_size_for_orientation(orientation()) - spacing() * (items.size() - 1);
int unfinished_items = items.size();
if (orientation() == Gfx::Orientation::Horizontal)
available_size -= margins().left() + margins().right();
else
available_size -= margins().top() + margins().bottom();
// Pass 1: Set all items to their minimum size.
for (auto& item : items) {
item.size = 0;
if (item.min_size >= 0)
item.size = item.min_size;
available_size -= item.size;
if (item.min_size >= 0 && item.max_size >= 0 && item.min_size == item.max_size) {
// Fixed-size items finish immediately in the first pass.
item.final = true;
--unfinished_items;
}
}
// Pass 2: Distribute remaining available size evenly, respecting each item's maximum size.
while (unfinished_items && available_size > 0) {
int slice = available_size / unfinished_items;
available_size = 0;
for (auto& item : items) {
if (item.final)
continue;
int item_size_with_full_slice = item.size + slice;
item.size = item_size_with_full_slice;
if (item.max_size >= 0)
item.size = min(item.max_size, item_size_with_full_slice);
// If the slice was more than we needed, return remained to available_size.
int remainder_to_give_back = item_size_with_full_slice - item.size;
available_size += remainder_to_give_back;
if (item.max_size >= 0 && item.size == item.max_size) {
// We've hit the item's max size. Don't give it any more space.
item.final = true;
--unfinished_items;
}
available_size -= entry.widget->preferred_size();
if (should_log)
dbgprintf("BoxLayout: Available size after: %s\n", available_size.to_string().characters());
++number_of_entries_with_fixed_size;
}
available_size -= { spacing(), spacing() };
}
available_size += { spacing(), spacing() };
available_size -= { margins().left() + margins().right(), margins().top() + margins().bottom() };
if (should_log)
dbgprintf("BoxLayout: Number of visible: %d/%zu\n", number_of_visible_entries, m_entries.size());
int number_of_entries_with_automatic_size = number_of_visible_entries - number_of_entries_with_fixed_size;
if (should_log)
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;
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());
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);
remaining_size = available_size.height();
}
}
if (should_log)
dbgprintf("BoxLayout: automatic_size=%s\n", automatic_size.to_string().characters());
// Pass 3: Place the widgets.
int current_x = margins().left();
int current_y = margins().top();
for (size_t i = 0; i < m_entries.size(); ++i) {
auto& entry = m_entries[i];
if (entry.type == Entry::Type::Spacer) {
current_x += automatic_size.width();
current_y += automatic_size.height();
continue;
}
for (auto& item : items) {
Gfx::IntRect rect { current_x, current_y, 0, 0 };
if (!entry.widget)
continue;
if (!entry.widget->is_visible())
continue;
Gfx::IntRect rect(current_x, current_y, 0, 0);
if (entry.layout) {
// FIXME: Implement recursive layout.
ASSERT_NOT_REACHED();
}
ASSERT(entry.widget);
rect.set_primary_size_for_orientation(orientation(), item.size);
if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fixed) {
rect.set_width(widget.width());
rect.set_height(entry.widget->preferred_size().height());
} else {
if (orientation() == Orientation::Horizontal)
rect.set_height(widget.height());
if (item.widget) {
int secondary = widget.size().secondary_size_for_orientation(orientation());
if (orientation() == Gfx::Orientation::Horizontal)
secondary -= margins().top() + margins().bottom();
else
rect.set_height(remaining_size / number_of_entries_with_automatic_size_remaining);
}
secondary -= margins().left() + margins().right();
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);
int min_secondary = item.widget->min_size().secondary_size_for_orientation(orientation());
int max_secondary = item.widget->max_size().secondary_size_for_orientation(orientation());
if (min_secondary >= 0)
secondary = max(secondary, min_secondary);
if (max_secondary >= 0)
secondary = min(secondary, max_secondary);
rect.set_secondary_size_for_orientation(orientation(), secondary);
if (orientation() == Gfx::Orientation::Horizontal)
rect.center_vertically_within(widget.rect());
else
rect.set_width(widget.width());
rect.center_horizontally_within(widget.rect());
item.widget->set_relative_rect(rect);
}
if (orientation() == Orientation::Horizontal) {
if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fill)
rect.set_height(widget.height() - margins().top() - margins().bottom());
} else {
if (entry.widget->size_policy(Orientation::Horizontal) == SizePolicy::Fill)
rect.set_width(widget.width() - margins().left() - margins().right());
}
// 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 (entry.widget->size_policy(Orientation::Horizontal) == SizePolicy::Fill) {
remaining_size -= rect.width();
--number_of_entries_with_automatic_size_remaining;
}
if (orientation() == Gfx::Orientation::Horizontal)
current_x += rect.width() + spacing();
} else {
if (entry.widget->size_policy(Orientation::Vertical) == SizePolicy::Fill) {
remaining_size -= rect.height();
--number_of_entries_with_automatic_size_remaining;
}
else
current_y += rect.height() + spacing();
}
}
}
}

View file

@ -74,12 +74,10 @@ void BreadcrumbBar::append_segment(const String& text, const Gfx::Bitmap* icon,
on_segment_click(index);
};
button.set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
auto button_text_width = button.font().width(text);
auto icon_width = icon ? icon->width() : 0;
auto icon_padding = icon ? 4 : 0;
button.set_preferred_size(button_text_width + icon_width + icon_padding + 16, 16 + 8);
button.set_fixed_size(button_text_width + icon_width + icon_padding + 16, 16 + 8);
Segment segment { icon, text, data, button.make_weak_ptr<GUI::Button>() };

View file

@ -66,8 +66,7 @@ Calendar::Calendar(Core::DateTime date_time)
m_day_name_container = add<GUI::Widget>();
m_day_name_container->set_layout<GUI::HorizontalBoxLayout>();
m_day_name_container->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
m_day_name_container->set_preferred_size(0, 16);
m_day_name_container->set_fixed_height(16);
m_day_name_container->layout()->set_spacing(0);
m_day_name_container->set_fill_with_background_color(true);
m_day_name_container->set_background_role(Gfx::ColorRole::HoverHighlight);

View file

@ -180,7 +180,6 @@ void ColorPicker::build_ui()
auto& tab_widget = root_container.add<GUI::TabWidget>();
auto& tab_palette = tab_widget.add_tab<Widget>("Palette");
tab_palette.set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
tab_palette.set_layout<VerticalBoxLayout>();
tab_palette.layout()->set_margins({ 4, 4, 4, 4 });
tab_palette.layout()->set_spacing(4);
@ -188,7 +187,6 @@ void ColorPicker::build_ui()
build_ui_palette(tab_palette);
auto& tab_custom_color = tab_widget.add_tab<Widget>("Custom Color");
tab_custom_color.set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
tab_custom_color.set_layout<VerticalBoxLayout>();
tab_custom_color.layout()->set_margins({ 4, 4, 4, 4 });
tab_custom_color.layout()->set_spacing(4);
@ -196,23 +194,20 @@ void ColorPicker::build_ui()
build_ui_custom(tab_custom_color);
auto& button_container = root_container.add<Widget>();
button_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container.set_preferred_size(0, 22);
button_container.set_fixed_height(22);
button_container.set_layout<HorizontalBoxLayout>();
button_container.layout()->set_spacing(4);
button_container.layout()->add_spacer();
auto& ok_button = button_container.add<Button>();
ok_button.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
ok_button.set_preferred_size(80, 0);
ok_button.set_fixed_width(80);
ok_button.set_text("OK");
ok_button.on_click = [this](auto) {
done(ExecOK);
};
auto& cancel_button = button_container.add<Button>();
cancel_button.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
cancel_button.set_preferred_size(80, 0);
cancel_button.set_fixed_width(80);
cancel_button.set_text("Cancel");
cancel_button.on_click = [this](auto) {
done(ExecCancel);
@ -231,7 +226,6 @@ void ColorPicker::build_ui_palette(Widget& root_container)
for (int r = 0; r < 4; r++) {
auto& colors_row = root_container.add<Widget>();
colors_row.set_layout<HorizontalBoxLayout>();
colors_row.set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
for (int i = 0; i < 8; i++) {
create_color_button(colors_row, colors[r][i]);
@ -254,8 +248,7 @@ void ColorPicker::build_ui_custom(Widget& root_container)
// Left Side
m_custom_color = horizontal_container.add<CustomColorWidget>(m_color);
m_custom_color->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
m_custom_color->set_preferred_size(299, 260);
m_custom_color->set_fixed_size(299, 260);
m_custom_color->on_pick = [this](Color color) {
if (m_color == color)
return;
@ -266,17 +259,15 @@ void ColorPicker::build_ui_custom(Widget& root_container)
// Right Side
auto& vertical_container = horizontal_container.add<Widget>();
vertical_container.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
vertical_container.set_layout<VerticalBoxLayout>();
vertical_container.layout()->set_margins({ 8, 0, 0, 0 });
vertical_container.set_preferred_size(128, 0);
vertical_container.set_fixed_width(128);
auto& preview_container = vertical_container.add<Frame>();
preview_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
preview_container.set_layout<VerticalBoxLayout>();
preview_container.layout()->set_margins({ 2, 2, 2, 2 });
preview_container.layout()->set_spacing(0);
preview_container.set_preferred_size(0, 128);
preview_container.set_fixed_height(128);
// Current color
preview_container.add<ColorPreview>(m_color);
@ -289,17 +280,14 @@ void ColorPicker::build_ui_custom(Widget& root_container)
// HTML
auto& html_container = vertical_container.add<GUI::Widget>();
html_container.set_layout<GUI::HorizontalBoxLayout>();
html_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
html_container.set_preferred_size(0, 22);
html_container.set_fixed_height(22);
auto& html_label = html_container.add<GUI::Label>();
html_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
html_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill);
html_label.set_preferred_size({ 48, 0 });
html_label.set_fixed_width(48);
html_label.set_text("HTML:");
m_html_text = html_container.add<GUI::TextBox>();
m_html_text->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fill);
m_html_text->set_text(m_color_has_alpha_channel ? m_color.to_string() : m_color.to_string_without_alpha());
m_html_text->on_change = [this]() {
auto color_name = m_html_text->text();
@ -321,17 +309,14 @@ void ColorPicker::build_ui_custom(Widget& root_container)
auto make_spinbox = [&](RGBComponent component, int initial_value) {
auto& rgb_container = vertical_container.add<GUI::Widget>();
rgb_container.set_layout<GUI::HorizontalBoxLayout>();
rgb_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
rgb_container.set_preferred_size(0, 22);
rgb_container.set_fixed_height(22);
auto& rgb_label = rgb_container.add<GUI::Label>();
rgb_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
rgb_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill);
rgb_label.set_preferred_size({ 48, 0 });
rgb_label.set_fixed_width(48);
auto& spinbox = rgb_container.add<SpinBox>();
spinbox.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
spinbox.set_preferred_size(0, 20);
spinbox.set_fixed_height(20);
spinbox.set_min(0);
spinbox.set_max(255);
spinbox.set_value(initial_value);
@ -395,7 +380,6 @@ void ColorPicker::create_color_button(Widget& container, unsigned rgb)
Color color = Color::from_rgb(rgb);
auto& widget = container.add<ColorButton>(*this, color);
widget.set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
widget.on_click = [this](Color color) {
for (auto& value : m_color_widgets) {
value->set_selected(false);
@ -465,18 +449,16 @@ CustomColorWidget::CustomColorWidget(Color color)
set_layout<HorizontalBoxLayout>();
m_color_field = add<ColorField>(color);
m_color_field->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
auto size = 256 + (m_color_field->frame_thickness() * 2);
m_color_field->set_preferred_size(size, size);
m_color_field->set_fixed_size(size, size);
m_color_field->on_pick = [this](Color color) {
if (on_pick)
on_pick(color);
};
m_color_slider = add<ColorSlider>(color.to_hsv().hue);
m_color_slider->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
auto slider_width = 24 + (m_color_slider->frame_thickness() * 2);
m_color_slider->set_preferred_size(slider_width, size);
m_color_slider->set_fixed_size(slider_width, size);
m_color_slider->on_pick = [this](double value) {
m_color_field->set_hue_from_pick(value);
};

View file

@ -106,17 +106,14 @@ FilePicker::FilePicker(Window* parent_window, Mode mode, Options options, const
auto& upper_container = vertical_container.add<Widget>();
upper_container.set_layout<HorizontalBoxLayout>();
upper_container.layout()->set_spacing(2);
upper_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
upper_container.set_preferred_size(0, 26);
upper_container.set_fixed_height(26);
auto& toolbar = upper_container.add<ToolBar>();
toolbar.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
toolbar.set_preferred_size(165, 0);
toolbar.set_fixed_width(165);
toolbar.set_has_frame(false);
m_location_textbox = upper_container.add<TextBox>();
m_location_textbox->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
m_location_textbox->set_preferred_size(0, 22);
m_location_textbox->set_fixed_height(22);
m_location_textbox->set_text(path);
m_view = vertical_container.add<MultiView>();
@ -176,17 +173,14 @@ FilePicker::FilePicker(Window* parent_window, Mode mode, Options options, const
auto& lower_container = vertical_container.add<Widget>();
lower_container.set_layout<VerticalBoxLayout>();
lower_container.layout()->set_spacing(4);
lower_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
lower_container.set_preferred_size(0, 48);
lower_container.set_fixed_height(48);
auto& filename_container = lower_container.add<Widget>();
filename_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
filename_container.set_preferred_size(0, 22);
filename_container.set_fixed_height(22);
filename_container.set_layout<HorizontalBoxLayout>();
auto& filename_label = filename_container.add<Label>("File name:");
filename_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
filename_label.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
filename_label.set_preferred_size(60, 0);
filename_label.set_fixed_width(60);
m_filename_textbox = filename_container.add<TextBox>();
m_filename_textbox->set_focus(true);
if (m_mode == Mode::Save) {
@ -214,23 +208,20 @@ FilePicker::FilePicker(Window* parent_window, Mode mode, Options options, const
};
auto& button_container = lower_container.add<Widget>();
button_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container.set_preferred_size(0, 22);
button_container.set_fixed_height(22);
button_container.set_layout<HorizontalBoxLayout>();
button_container.layout()->set_spacing(4);
button_container.layout()->add_spacer();
auto& cancel_button = button_container.add<Button>();
cancel_button.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
cancel_button.set_preferred_size(80, 0);
cancel_button.set_fixed_width(80);
cancel_button.set_text("Cancel");
cancel_button.on_click = [this](auto) {
done(ExecCancel);
};
auto& ok_button = button_container.add<Button>();
ok_button.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
ok_button.set_preferred_size(80, 0);
ok_button.set_fixed_width(80);
ok_button.set_text(ok_button_name(m_mode));
ok_button.on_click = [this](auto) {
on_file_return();
@ -253,24 +244,21 @@ FilePicker::FilePicker(Window* parent_window, Mode mode, Options options, const
if (!((unsigned)options & (unsigned)Options::DisablePreview)) {
m_preview_container = horizontal_container.add<Frame>();
m_preview_container->set_visible(false);
m_preview_container->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
m_preview_container->set_preferred_size(180, 0);
m_preview_container->set_fixed_width(180);
m_preview_container->set_layout<VerticalBoxLayout>();
m_preview_container->layout()->set_margins({ 8, 8, 8, 8 });
m_preview_image = m_preview_container->add<ImageWidget>();
m_preview_image->set_should_stretch(true);
m_preview_image->set_auto_resize(false);
m_preview_image->set_preferred_size(160, 160);
m_preview_image->set_fixed_size(160, 160);
m_preview_name_label = m_preview_container->add<Label>();
m_preview_name_label->set_font(Gfx::Font::default_bold_font());
m_preview_name_label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
m_preview_name_label->set_preferred_size(0, m_preview_name_label->font().glyph_height());
m_preview_name_label->set_fixed_height(m_preview_name_label->font().glyph_height());
m_preview_geometry_label = m_preview_container->add<Label>();
m_preview_geometry_label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
m_preview_geometry_label->set_preferred_size(0, m_preview_name_label->font().glyph_height());
m_preview_geometry_label->set_fixed_height(m_preview_name_label->font().glyph_height());
}
}

View file

@ -45,11 +45,9 @@ HeaderView::HeaderView(AbstractTableView& table_view, Gfx::Orientation orientati
set_font(Gfx::Font::default_bold_font());
if (m_orientation == Gfx::Orientation::Horizontal) {
set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
set_preferred_size(0, 16);
set_fixed_height(16);
} else {
set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
set_preferred_size(40, 0);
set_fixed_width(40);
}
}

View file

@ -39,7 +39,6 @@ ImageWidget::ImageWidget(const StringView&)
set_frame_thickness(0);
set_frame_shadow(Gfx::FrameShadow::Plain);
set_frame_shape(Gfx::FrameShape::NoFrame);
set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed);
set_auto_resize(true);
}
@ -54,7 +53,7 @@ void ImageWidget::set_bitmap(const Gfx::Bitmap* bitmap)
m_bitmap = bitmap;
if (m_bitmap && m_auto_resize)
set_preferred_size(m_bitmap->width(), m_bitmap->height());
set_fixed_size(m_bitmap->size());
update();
}
@ -64,7 +63,7 @@ void ImageWidget::set_auto_resize(bool value)
m_auto_resize = value;
if (m_bitmap)
set_preferred_size(m_bitmap->width(), m_bitmap->height());
set_fixed_size(m_bitmap->size());
}
void ImageWidget::animate()

View file

@ -74,20 +74,16 @@ void InputBox::build()
widget.layout()->set_spacing(6);
auto& label_editor_container = widget.add<Widget>();
label_editor_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
label_editor_container.set_layout<HorizontalBoxLayout>();
auto& label = label_editor_container.add<Label>(m_prompt);
label.set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
label.set_preferred_size(text_width, 16);
label.set_fixed_size(text_width, 16);
m_text_editor = label_editor_container.add<TextBox>();
m_text_editor->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
m_text_editor->set_preferred_size(0, 19);
m_text_editor->set_fixed_height(19);
auto& button_container_outer = widget.add<Widget>();
button_container_outer.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container_outer.set_preferred_size(0, 20);
button_container_outer.set_fixed_height(20);
button_container_outer.set_layout<VerticalBoxLayout>();
auto& button_container_inner = button_container_outer.add<Widget>();
@ -97,8 +93,7 @@ void InputBox::build()
button_container_inner.layout()->add_spacer();
m_ok_button = button_container_inner.add<Button>();
m_ok_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
m_ok_button->set_preferred_size(0, 20);
m_ok_button->set_fixed_height(20);
m_ok_button->set_text("OK");
m_ok_button->on_click = [this](auto) {
dbgprintf("GUI::InputBox: OK button clicked\n");
@ -107,8 +102,7 @@ void InputBox::build()
};
m_cancel_button = button_container_inner.add<Button>();
m_cancel_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
m_cancel_button->set_preferred_size(0, 20);
m_cancel_button->set_fixed_height(20);
m_cancel_button->set_text("Cancel");
m_cancel_button->on_click = [this](auto) {
dbgprintf("GUI::InputBox: Cancel button clicked\n");

View file

@ -119,8 +119,7 @@ void Label::paint_event(PaintEvent& event)
void Label::size_to_fit()
{
set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
set_preferred_size(font().width(m_text), 0);
set_fixed_width(font().width(m_text));
}
}

View file

@ -123,21 +123,18 @@ void MessageBox::build()
}
auto& label = message_container.add<Label>(m_text);
label.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
label.set_preferred_size(text_width, 16);
label.set_fixed_height(16);
if (m_type != Type::None)
label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
auto& button_container = widget.add<Widget>();
button_container.set_layout<HorizontalBoxLayout>();
button_container.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container.set_preferred_size(0, 24);
button_container.set_fixed_height(24);
button_container.layout()->set_spacing(8);
auto add_button = [&](String label, Dialog::ExecResult result) {
auto& button = button_container.add<Button>();
button.set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
button.set_preferred_size(96, 0);
button.set_fixed_width(96);
button.set_text(label);
button.on_click = [this, label, result](auto) {
done(result);

View file

@ -64,15 +64,13 @@ ProcessChooser::ProcessChooser(const StringView& window_title, const StringView&
m_table_view->on_activation = [this](const ModelIndex& index) { set_pid_from_index_and_close(index); };
auto& button_container = widget.add<GUI::Widget>();
button_container.set_preferred_size(0, 30);
button_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
button_container.set_fixed_height(30);
button_container.set_layout<GUI::HorizontalBoxLayout>();
button_container.layout()->set_margins({ 0, 0, 4, 0 });
button_container.layout()->add_spacer();
auto& select_button = button_container.add<GUI::Button>(m_button_label);
select_button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed);
select_button.set_preferred_size(80, 24);
select_button.set_fixed_size(80, 24);
select_button.on_click = [this](auto) {
if (m_table_view->selection().is_empty()) {
GUI::MessageBox::show(this, "No process selected!", m_window_title, GUI::MessageBox::Type::Error);
@ -82,8 +80,7 @@ ProcessChooser::ProcessChooser(const StringView& window_title, const StringView&
set_pid_from_index_and_close(index);
};
auto& cancel_button = button_container.add<GUI::Button>("Cancel");
cancel_button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed);
cancel_button.set_preferred_size(80, 24);
cancel_button.set_fixed_size(80, 24);
cancel_button.on_click = [this](auto) {
done(ExecCancel);
};

View file

@ -79,8 +79,7 @@ ResizeCorner::ResizeCorner()
{
set_override_cursor(Gfx::StandardCursor::ResizeDiagonalTLBR);
set_background_role(ColorRole::Button);
set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
set_preferred_size(16, 18);
set_fixed_size(16, 18);
}
ResizeCorner::~ResizeCorner()

View file

@ -100,9 +100,9 @@ ScrollBar::ScrollBar(Orientation orientation)
s_right_arrow_bitmap = &Gfx::CharacterBitmap::create_from_ascii(s_right_arrow_bitmap_data, 9, 9).leak_ref();
if (m_orientation == Orientation::Vertical) {
set_preferred_size(16, 0);
set_fixed_height(16);
} else {
set_preferred_size(0, 16);
set_fixed_width(16);
}
m_automatic_scrolling_timer->set_interval(100);

View file

@ -71,20 +71,20 @@ void ScrollableWidget::mousewheel_event(MouseEvent& event)
void ScrollableWidget::custom_layout()
{
auto inner_rect = frame_inner_rect_for_size(size());
int height_wanted_by_horizontal_scrollbar = m_horizontal_scrollbar->is_visible() ? m_horizontal_scrollbar->preferred_size().height() : 0;
int width_wanted_by_vertical_scrollbar = m_vertical_scrollbar->is_visible() ? m_vertical_scrollbar->preferred_size().width() : 0;
int height_wanted_by_horizontal_scrollbar = m_horizontal_scrollbar->is_visible() ? m_horizontal_scrollbar->min_height() : 0;
int width_wanted_by_vertical_scrollbar = m_vertical_scrollbar->is_visible() ? m_vertical_scrollbar->min_width() : 0;
m_vertical_scrollbar->set_relative_rect(
inner_rect.right() + 1 - m_vertical_scrollbar->preferred_size().width(),
inner_rect.right() + 1 - m_vertical_scrollbar->min_width(),
inner_rect.top(),
m_vertical_scrollbar->preferred_size().width(),
m_vertical_scrollbar->min_width(),
inner_rect.height() - height_wanted_by_horizontal_scrollbar);
m_horizontal_scrollbar->set_relative_rect(
inner_rect.left(),
inner_rect.bottom() + 1 - m_horizontal_scrollbar->preferred_size().height(),
inner_rect.bottom() + 1 - m_horizontal_scrollbar->min_height(),
inner_rect.width() - width_wanted_by_vertical_scrollbar,
m_horizontal_scrollbar->preferred_size().height());
m_horizontal_scrollbar->min_height());
m_corner_widget->set_visible(m_vertical_scrollbar->is_visible() && m_horizontal_scrollbar->is_visible());
if (m_corner_widget->is_visible()) {

View file

@ -183,11 +183,14 @@ void Splitter::mousemove_event(MouseEvent& event)
new_second_resizee_size.set_primary_size_for_orientation(m_orientation, new_second_resizee_size.primary_size_for_orientation(m_orientation) + correction);
new_first_resizee_size.set_primary_size_for_orientation(m_orientation, new_first_resizee_size.primary_size_for_orientation(m_orientation) - correction);
}
m_first_resizee->set_preferred_size(new_first_resizee_size);
m_second_resizee->set_preferred_size(new_second_resizee_size);
m_first_resizee->set_size_policy(m_orientation, SizePolicy::Fixed);
m_second_resizee->set_size_policy(m_orientation, SizePolicy::Fill);
if (m_orientation == Orientation::Horizontal) {
m_first_resizee->set_fixed_width(new_first_resizee_size.width());
m_second_resizee->set_fixed_width(-1);
} else {
m_first_resizee->set_fixed_height(new_first_resizee_size.height());
m_second_resizee->set_fixed_height(-1);
}
invalidate_layout();
}

View file

@ -37,8 +37,7 @@ namespace GUI {
StatusBar::StatusBar(int label_count)
{
set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
set_preferred_size(0, 18);
set_fixed_height(18);
set_layout<HorizontalBoxLayout>();
layout()->set_margins({ 0, 0, 0, 0 });
layout()->set_spacing(2);

View file

@ -40,11 +40,9 @@ ToolBar::ToolBar(Orientation orientation, int button_size)
: m_button_size(button_size)
{
if (orientation == Orientation::Horizontal) {
set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
set_preferred_size(0, button_size + 8);
set_fixed_height(button_size + 8);
} else {
set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
set_preferred_size(button_size + 8, 0);
set_fixed_width(button_size + 8);
}
set_layout<BoxLayout>(orientation);
layout()->set_spacing(0);
@ -74,7 +72,6 @@ private:
else
set_text(action.text());
set_button_style(Gfx::ButtonStyle::CoolBar);
set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
}
String tooltip(const Action& action) const
{
@ -96,7 +93,7 @@ void ToolBar::add_action(Action& action)
item->action = action;
auto& button = add<ToolBarButton>(action);
button.set_preferred_size(m_button_size + 8, m_button_size + 8);
button.set_fixed_size(m_button_size + 8, m_button_size + 8);
m_items.append(move(item));
}
@ -106,8 +103,7 @@ class SeparatorWidget final : public Widget {
public:
SeparatorWidget()
{
set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
set_preferred_size(8, 18);
set_fixed_size(8, 18);
}
virtual ~SeparatorWidget() override { }

View file

@ -72,18 +72,15 @@ void ToolBarContainer::recompute_preferred_size()
if (!toolbar.is_visible())
continue;
++visible_toolbar_count;
if (m_orientation == Gfx::Orientation::Horizontal)
preferred_size += toolbar.preferred_size().height();
else
preferred_size += toolbar.preferred_size().width();
preferred_size += toolbar.min_size().secondary_size_for_orientation(m_orientation);
}
preferred_size += (visible_toolbar_count - 1) * 2;
if (m_orientation == Gfx::Orientation::Horizontal)
set_preferred_size(0, preferred_size);
set_fixed_height(preferred_size);
else
set_preferred_size(preferred_size, 0);
set_fixed_width(preferred_size);
}
ToolBarContainer::ToolBarContainer(Gfx::Orientation orientation)
@ -95,11 +92,6 @@ ToolBarContainer::ToolBarContainer(Gfx::Orientation orientation)
set_frame_shape(Gfx::FrameShape::Box);
set_frame_shadow(Gfx::FrameShadow::Sunken);
if (m_orientation == Gfx::Orientation::Horizontal)
set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
else
set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
auto& layout = set_layout<VerticalBoxLayout>();
layout.set_spacing(2);
layout.set_margins({ 2, 2, 2, 2 });

View file

@ -132,11 +132,6 @@ Widget::Widget()
REGISTER_BOOL_PROPERTY("focused", is_focused, set_focus);
REGISTER_BOOL_PROPERTY("enabled", is_enabled, set_enabled);
REGISTER_STRING_PROPERTY("tooltip", tooltip, set_tooltip);
REGISTER_SIZE_PROPERTY("preferred_size", preferred_size, set_preferred_size);
REGISTER_INT_PROPERTY("preferred_width", preferred_width, set_preferred_width);
REGISTER_INT_PROPERTY("preferred_height", preferred_height, set_preferred_height);
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);
@ -686,31 +681,6 @@ void Widget::set_max_size(const Gfx::IntSize& size)
invalidate_layout();
}
void Widget::set_preferred_size(const Gfx::IntSize& size)
{
if (m_preferred_size == size)
return;
m_preferred_size = size;
invalidate_layout();
}
void Widget::set_size_policy(Orientation orientation, SizePolicy policy)
{
if (orientation == Orientation::Horizontal)
set_size_policy(policy, m_vertical_size_policy);
else
set_size_policy(m_horizontal_size_policy, policy);
}
void Widget::set_size_policy(SizePolicy horizontal_policy, SizePolicy vertical_policy)
{
if (m_horizontal_size_policy == horizontal_policy && m_vertical_size_policy == vertical_policy)
return;
m_horizontal_size_policy = horizontal_policy;
m_vertical_size_policy = vertical_policy;
invalidate_layout();
}
void Widget::invalidate_layout()
{
if (window())

View file

@ -112,14 +112,6 @@ public:
return layout;
}
SizePolicy horizontal_size_policy() const { return m_horizontal_size_policy; }
SizePolicy vertical_size_policy() const { return m_vertical_size_policy; }
SizePolicy size_policy(Orientation orientation) { return orientation == Orientation::Horizontal ? m_horizontal_size_policy : m_vertical_size_policy; }
void set_size_policy(SizePolicy horizontal_policy, SizePolicy vertical_policy);
void set_size_policy(Orientation, SizePolicy);
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 }); }
@ -158,15 +150,6 @@ public:
set_max_height(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 }); }
int preferred_width() const { return preferred_size().width(); }
int preferred_height() const { return preferred_size().height(); }
void set_preferred_width(int w) { set_preferred_size(w, preferred_height()); }
void set_preferred_height(int h) { set_preferred_size(preferred_width(), h); }
bool has_tooltip() const { return !m_tooltip.is_empty(); }
String tooltip() const { return m_tooltip; }
void set_tooltip(const StringView&);
@ -405,9 +388,6 @@ private:
NonnullRefPtr<Gfx::Font> m_font;
String m_tooltip;
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;

View file

@ -542,10 +542,10 @@ void Window::set_main_widget(Widget* widget)
if (m_main_widget) {
add_child(*widget);
auto new_window_rect = rect();
if (m_main_widget->horizontal_size_policy() == SizePolicy::Fixed)
new_window_rect.set_width(m_main_widget->preferred_size().width());
if (m_main_widget->vertical_size_policy() == SizePolicy::Fixed)
new_window_rect.set_height(m_main_widget->preferred_size().height());
if (m_main_widget->min_width() >= 0)
new_window_rect.set_width(max(new_window_rect.width(), m_main_widget->min_width()));
if (m_main_widget->min_height() >= 0)
new_window_rect.set_height(max(new_window_rect.height(), m_main_widget->min_height()));
set_rect(new_window_rect);
m_main_widget->set_relative_rect({ {}, new_window_rect.size() });
m_main_widget->set_window(this);