summaryrefslogtreecommitdiff
path: root/Libraries/LibGUI/GBoxLayout.cpp
blob: 669a21b641cc599331e219dc13f5f3bcb122512d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GWidget.h>
#include <stdio.h>

//#define GBOXLAYOUT_DEBUG

GBoxLayout::GBoxLayout(Orientation orientation)
    : m_orientation(orientation)
{
}

GBoxLayout::~GBoxLayout()
{
}

void GBoxLayout::run(GWidget& widget)
{
    bool should_log = false;
#ifdef GBOXLAYOUT_DEBUG
    should_log = true;
#endif
    if (should_log)
        dbgprintf("GBoxLayout: running layout on %s{%p}, entry count: %d\n", widget.class_name(), &widget, m_entries.size());

    if (m_entries.is_empty())
        return;

    Size available_size = widget.size();
    int number_of_entries_with_fixed_size = 0;

    int number_of_visible_entries = 0;

    if (should_log)
        dbgprintf("GBoxLayout:  Starting with available size: %s\n", available_size.to_string().characters());

    for (auto& entry : m_entries) {
        if (entry.type == Entry::Type::Spacer) {
            ++number_of_visible_entries;
        }
        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("GBoxLayout:   Subtracting for fixed %s{%p}, size: %s\n", entry.widget->class_name(), entry.widget.ptr(), entry.widget->preferred_size().to_string().characters());
                dbgprintf("GBoxLayout:     Available size before: %s\n", available_size.to_string().characters());
            }
            available_size -= entry.widget->preferred_size();
            if (should_log)
                dbgprintf("GBoxLayout:     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("GBoxLayout:  Number of visible: %d/%d\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("GBoxLayout:   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);

    Size 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());
        } else {
            automatic_size.set_width(widget.width());
            automatic_size.set_height(available_size.height() / number_of_entries_with_automatic_size);
        }
    }

    if (should_log)
        dbgprintf("GBoxLayout:   automatic_size=%s\n", automatic_size.to_string().characters());

    int current_x = margins().left();
    int current_y = margins().top();

    for (auto& entry : m_entries) {
        if (entry.type == Entry::Type::Spacer) {
            current_x += automatic_size.width();
            current_y += automatic_size.height();
        }

        if (!entry.widget)
            continue;
        if (!entry.widget->is_visible())
            continue;
        Rect rect(current_x, current_y, 0, 0);
        if (entry.layout) {
            // FIXME: Implement recursive layout.
            ASSERT_NOT_REACHED();
        }
        ASSERT(entry.widget);
        rect.set_size(automatic_size);

        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)
            rect.set_width(entry.widget->preferred_size().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());
        }

        if (should_log)
            dbgprintf("GBoxLayout: 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)
            current_x += rect.width() + spacing();
        else
            current_y += rect.height() + spacing();
    }
}