1 | /* |
2 | * Copyright © 2019 Benjamin Otte |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Authors: Benjamin Otte <otte@gnome.org> |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include "gtkcolumnviewlayoutprivate.h" |
23 | |
24 | #include "gtkcolumnviewcellprivate.h" |
25 | #include "gtkcolumnviewcolumnprivate.h" |
26 | #include "gtkcolumnviewprivate.h" |
27 | #include "gtkcolumnviewtitleprivate.h" |
28 | #include "gtkwidgetprivate.h" |
29 | |
30 | struct _GtkColumnViewLayout |
31 | { |
32 | GtkLayoutManager parent_instance; |
33 | |
34 | GtkColumnView *view; /* no reference */ |
35 | }; |
36 | |
37 | G_DEFINE_TYPE (GtkColumnViewLayout, gtk_column_view_layout, GTK_TYPE_LAYOUT_MANAGER) |
38 | |
39 | static void |
40 | gtk_column_view_layout_measure_along (GtkColumnViewLayout *self, |
41 | GtkWidget *widget, |
42 | int for_size, |
43 | int *minimum, |
44 | int *natural, |
45 | int *minimum_baseline, |
46 | int *natural_baseline) |
47 | { |
48 | GtkOrientation orientation = GTK_ORIENTATION_VERTICAL; |
49 | GtkWidget *child; |
50 | guint i, n; |
51 | GtkRequestedSize *sizes = NULL; |
52 | |
53 | if (for_size > -1) |
54 | { |
55 | n = g_list_model_get_n_items (list: gtk_column_view_get_columns (self: self->view)); |
56 | sizes = g_newa (GtkRequestedSize, n); |
57 | gtk_column_view_distribute_width (self: self->view, width: for_size, sizes); |
58 | } |
59 | |
60 | for (child = _gtk_widget_get_first_child (widget), i = 0; |
61 | child != NULL; |
62 | child = _gtk_widget_get_next_sibling (widget: child), i++) |
63 | { |
64 | int child_min = 0; |
65 | int child_nat = 0; |
66 | int child_min_baseline = -1; |
67 | int child_nat_baseline = -1; |
68 | |
69 | if (!gtk_widget_should_layout (widget: child)) |
70 | continue; |
71 | |
72 | gtk_widget_measure (widget: child, orientation, |
73 | for_size: for_size > -1 ? sizes[i].minimum_size : -1, |
74 | minimum: &child_min, natural: &child_nat, |
75 | minimum_baseline: &child_min_baseline, natural_baseline: &child_nat_baseline); |
76 | |
77 | *minimum = MAX (*minimum, child_min); |
78 | *natural = MAX (*natural, child_nat); |
79 | |
80 | if (child_min_baseline > -1) |
81 | *minimum_baseline = MAX (*minimum_baseline, child_min_baseline); |
82 | if (child_nat_baseline > -1) |
83 | *natural_baseline = MAX (*natural_baseline, child_nat_baseline); |
84 | } |
85 | } |
86 | |
87 | static void |
88 | gtk_column_view_layout_measure (GtkLayoutManager *layout, |
89 | GtkWidget *widget, |
90 | GtkOrientation orientation, |
91 | int for_size, |
92 | int *minimum, |
93 | int *natural, |
94 | int *minimum_baseline, |
95 | int *natural_baseline) |
96 | { |
97 | GtkColumnViewLayout *self = GTK_COLUMN_VIEW_LAYOUT (ptr: layout); |
98 | |
99 | if (orientation == GTK_ORIENTATION_HORIZONTAL) |
100 | { |
101 | gtk_column_view_measure_across (GTK_COLUMN_VIEW (self->view), |
102 | minimum, |
103 | natural); |
104 | } |
105 | else |
106 | { |
107 | gtk_column_view_layout_measure_along (self, |
108 | widget, |
109 | for_size, |
110 | minimum, |
111 | natural, |
112 | minimum_baseline, |
113 | natural_baseline); |
114 | } |
115 | } |
116 | |
117 | static void |
118 | gtk_column_view_layout_allocate (GtkLayoutManager *layout_manager, |
119 | GtkWidget *widget, |
120 | int width, |
121 | int height, |
122 | int baseline) |
123 | { |
124 | GtkWidget *child; |
125 | |
126 | for (child = _gtk_widget_get_first_child (widget); |
127 | child != NULL; |
128 | child = _gtk_widget_get_next_sibling (widget: child)) |
129 | { |
130 | GtkColumnViewColumn *column; |
131 | int col_x, col_width, min; |
132 | |
133 | if (!gtk_widget_should_layout (widget: child)) |
134 | continue; |
135 | |
136 | if (GTK_IS_COLUMN_VIEW_CELL (child)) |
137 | { |
138 | column = gtk_column_view_cell_get_column (GTK_COLUMN_VIEW_CELL (child)); |
139 | gtk_column_view_column_get_allocation (self: column, offset: &col_x, size: &col_width); |
140 | } |
141 | else |
142 | { |
143 | column = gtk_column_view_title_get_column (GTK_COLUMN_VIEW_TITLE (child)); |
144 | gtk_column_view_column_get_header_allocation (self: column, offset: &col_x, size: &col_width); |
145 | } |
146 | |
147 | gtk_widget_measure (widget: child, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1, minimum: &min, NULL, NULL, NULL); |
148 | |
149 | gtk_widget_size_allocate (widget: child, allocation: &(GtkAllocation) { col_x, 0, MAX (min, col_width), height }, baseline); |
150 | } |
151 | } |
152 | |
153 | static void |
154 | gtk_column_view_layout_class_init (GtkColumnViewLayoutClass *klass) |
155 | { |
156 | GtkLayoutManagerClass *layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (ptr: klass); |
157 | |
158 | layout_manager_class->measure = gtk_column_view_layout_measure; |
159 | layout_manager_class->allocate = gtk_column_view_layout_allocate; |
160 | } |
161 | |
162 | static void |
163 | gtk_column_view_layout_init (GtkColumnViewLayout *self) |
164 | { |
165 | } |
166 | |
167 | GtkLayoutManager * |
168 | gtk_column_view_layout_new (GtkColumnView *view) |
169 | { |
170 | GtkColumnViewLayout *result; |
171 | |
172 | result = g_object_new (GTK_TYPE_COLUMN_VIEW_LAYOUT, NULL); |
173 | |
174 | result->view = view; |
175 | |
176 | return GTK_LAYOUT_MANAGER (ptr: result); |
177 | } |
178 | |