summaryrefslogtreecommitdiff
path: root/LibGUI/GBoxLayout.cpp
blob: 9abea5ed622bea080dc05a4029feeb9e8af4ebf3 (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
133
134
135
136
137
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GWidget.h>
#include <stdio.h>

//#define GBOXLAYOUT_DEBUG

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

GBoxLayout::~GBoxLayout()
{
}

#if 0
Size GLayout::compute_preferred_size() const
{

}


static Size compute_preferred_size(GLayout::Entry& entry)
{
    if (entry.layout)
        return entry.layout->compute_preferred_size();
    else {
        return entry.widget->preferred_size();
    }
}
#endif

void GBoxLayout::run(GWidget& widget)
{
    bool should_log = false;
#ifdef GBOXLAYOUT_DEBUG
    should_log = true;
#endif
    if (should_log)
        printf("GBoxLayout: running layout on %s{%p}\n", widget.class_name(), &widget);
    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)
        printf("GBoxLayout:  Starting with available size: %s\n", available_size.to_string().characters());

    for (auto& entry : m_entries) {
        if (!entry.widget->is_visible())
            continue;
        ++number_of_visible_entries;
        if (entry.widget && entry.widget->size_policy(orientation()) == SizePolicy::Fixed) {
            if (should_log) {
                printf("GBoxLayout:   Subtracting for fixed %s{%p}, size: %s\n", entry.widget->class_name(), entry.widget.ptr(), entry.widget->preferred_size().to_string().characters());
                printf("GBoxLayout:     Available size before: %s\n", available_size.to_string().characters());
            }

            available_size -= entry.widget->preferred_size();
            if (should_log)
                printf("GBoxLayout:     Available size  after: %s\n", available_size.to_string().characters());
            ++number_of_entries_with_fixed_size;
        }
    }

    if (should_log)
        printf("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;

#ifdef GBOXLAYOUT_DEBUG
    if (should_log)
        printf("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);
#endif

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

#ifdef GBOXLAYOUT_DEBUG
    if (should_log)
        printf("GBoxLayout:   automatic_size=%s\n", automatic_size.to_string().characters());
#endif

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

    for (auto& entry : m_entries) {
        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.width() - margins().left() - margins().right(), automatic_size.height() - margins().top() - margins().bottom());

        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());
        }

#ifdef GBOXLAYOUT_DEBUG
        if (should_log)
            printf("GBoxLayout: apply, %s{%p} <- %s\n", entry.widget->class_name(), entry.widget.ptr(), rect.to_string().characters());
#endif
        entry.widget->set_relative_rect(rect);

        if (orientation() == Orientation::Horizontal)
            current_x += rect.width() + spacing();
        else
            current_y += rect.height() + spacing();
    }
}