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