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
G_DEFINE_TYPE(GtkColumnViewLayout,gtk_column_view_layout,GTK_TYPE_LAYOUT_MANAGER)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 (gtk_column_view_get_columns (self->view));
56 sizes = g_newa (GtkRequestedSize, n);
57 gtk_column_view_distribute_width (self->view, 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 (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 (child))
70 continue;
71
72 gtk_widget_measure (child, orientation,
73 for_size > -1 ? sizes[i].minimum_size : -1,
74 &child_min, &child_nat,
75 &child_min_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
gtk_column_view_layout_measure(GtkLayoutManager * layout,GtkWidget * widget,GtkOrientation orientation,int for_size,int * minimum,int * natural,int * minimum_baseline,int * natural_baseline)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 (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
gtk_column_view_layout_allocate(GtkLayoutManager * layout_manager,GtkWidget * widget,int width,int height,int baseline)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 (child))
129 {
130 GtkColumnViewColumn *column;
131 int col_x, col_width, min;
132
133 if (!gtk_widget_should_layout (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 (column, &col_x, &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 (column, &col_x, &col_width);
145 }
146
147 gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL);
148
149 gtk_widget_size_allocate (child, &(GtkAllocation) { col_x, 0, MAX (min, col_width), height }, baseline);
150 }
151 }
152
153 static void
gtk_column_view_layout_class_init(GtkColumnViewLayoutClass * klass)154 gtk_column_view_layout_class_init (GtkColumnViewLayoutClass *klass)
155 {
156 GtkLayoutManagerClass *layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (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
gtk_column_view_layout_init(GtkColumnViewLayout * self)163 gtk_column_view_layout_init (GtkColumnViewLayout *self)
164 {
165 }
166
167 GtkLayoutManager *
gtk_column_view_layout_new(GtkColumnView * view)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 (result);
177 }
178