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 "gtkcolumnviewcellprivate.h" |
23 | |
24 | #include "gtkcolumnviewcolumnprivate.h" |
25 | #include "gtkintl.h" |
26 | #include "gtklistitemwidgetprivate.h" |
27 | #include "gtkwidgetprivate.h" |
28 | #include "gtkcssnodeprivate.h" |
29 | #include "gtkcssnumbervalueprivate.h" |
30 | |
31 | |
32 | struct _GtkColumnViewCell |
33 | { |
34 | GtkListItemWidget parent_instance; |
35 | |
36 | GtkColumnViewColumn *column; |
37 | |
38 | /* This list isn't sorted - next/prev refer to list elements, not rows in the list */ |
39 | GtkColumnViewCell *next_cell; |
40 | GtkColumnViewCell *prev_cell; |
41 | }; |
42 | |
43 | struct _GtkColumnViewCellClass |
44 | { |
45 | GtkListItemWidgetClass parent_class; |
46 | }; |
47 | |
48 | G_DEFINE_TYPE (GtkColumnViewCell, gtk_column_view_cell, GTK_TYPE_LIST_ITEM_WIDGET) |
49 | |
50 | static int |
51 | get_number (GtkCssValue *value) |
52 | { |
53 | double d = _gtk_css_number_value_get (number: value, one_hundred_percent: 100); |
54 | |
55 | if (d < 1) |
56 | return ceil (x: d); |
57 | else |
58 | return floor (x: d); |
59 | } |
60 | |
61 | static int |
62 | unadjust_width (GtkWidget *widget, |
63 | int width) |
64 | { |
65 | GtkCssStyle *style; |
66 | int widget_margins; |
67 | int ; |
68 | |
69 | style = gtk_css_node_get_style (cssnode: gtk_widget_get_css_node (widget)); |
70 | css_extra = get_number (value: style->size->margin_left) + |
71 | get_number (value: style->size->margin_right) + |
72 | get_number (value: style->border->border_left_width) + |
73 | get_number (value: style->border->border_right_width) + |
74 | get_number (value: style->size->padding_left) + |
75 | get_number (value: style->size->padding_right); |
76 | widget_margins = widget->priv->margin.left + widget->priv->margin.right; |
77 | |
78 | return MAX (0, width - widget_margins - css_extra); |
79 | } |
80 | |
81 | static void |
82 | gtk_column_view_cell_measure (GtkWidget *widget, |
83 | GtkOrientation orientation, |
84 | int for_size, |
85 | int *minimum, |
86 | int *natural, |
87 | int *minimum_baseline, |
88 | int *natural_baseline) |
89 | { |
90 | GtkColumnViewCell *cell = GTK_COLUMN_VIEW_CELL (widget); |
91 | GtkWidget *child = gtk_widget_get_first_child (widget); |
92 | int fixed_width = gtk_column_view_column_get_fixed_width (self: cell->column); |
93 | int unadj_width; |
94 | |
95 | unadj_width = unadjust_width (widget, width: fixed_width); |
96 | |
97 | if (orientation == GTK_ORIENTATION_VERTICAL) |
98 | { |
99 | if (fixed_width > -1) |
100 | { |
101 | if (for_size == -1) |
102 | for_size = unadj_width; |
103 | else |
104 | for_size = MIN (for_size, unadj_width); |
105 | } |
106 | } |
107 | |
108 | if (child) |
109 | gtk_widget_measure (widget: child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); |
110 | |
111 | if (orientation == GTK_ORIENTATION_HORIZONTAL) |
112 | { |
113 | if (fixed_width > -1) |
114 | { |
115 | *minimum = 0; |
116 | *natural = unadj_width; |
117 | } |
118 | } |
119 | } |
120 | |
121 | static void |
122 | gtk_column_view_cell_size_allocate (GtkWidget *widget, |
123 | int width, |
124 | int height, |
125 | int baseline) |
126 | { |
127 | GtkWidget *child = gtk_widget_get_first_child (widget); |
128 | |
129 | if (child) |
130 | { |
131 | int min; |
132 | |
133 | gtk_widget_measure (widget: child, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: height, minimum: &min, NULL, NULL, NULL); |
134 | |
135 | gtk_widget_allocate (widget: child, MAX (min, width), height, baseline, NULL); |
136 | } |
137 | } |
138 | |
139 | static void |
140 | gtk_column_view_cell_root (GtkWidget *widget) |
141 | { |
142 | GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (widget); |
143 | |
144 | GTK_WIDGET_CLASS (gtk_column_view_cell_parent_class)->root (widget); |
145 | |
146 | self->next_cell = gtk_column_view_column_get_first_cell (self: self->column); |
147 | if (self->next_cell) |
148 | self->next_cell->prev_cell = self; |
149 | |
150 | gtk_column_view_column_add_cell (self: self->column, cell: self); |
151 | } |
152 | |
153 | static void |
154 | gtk_column_view_cell_unroot (GtkWidget *widget) |
155 | { |
156 | GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (widget); |
157 | |
158 | gtk_column_view_column_remove_cell (self: self->column, cell: self); |
159 | |
160 | if (self->prev_cell) |
161 | self->prev_cell->next_cell = self->next_cell; |
162 | if (self->next_cell) |
163 | self->next_cell->prev_cell = self->prev_cell; |
164 | |
165 | self->prev_cell = NULL; |
166 | self->next_cell = NULL; |
167 | |
168 | GTK_WIDGET_CLASS (gtk_column_view_cell_parent_class)->unroot (widget); |
169 | } |
170 | |
171 | static void |
172 | gtk_column_view_cell_dispose (GObject *object) |
173 | { |
174 | GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (object); |
175 | |
176 | g_clear_object (&self->column); |
177 | |
178 | G_OBJECT_CLASS (gtk_column_view_cell_parent_class)->dispose (object); |
179 | } |
180 | |
181 | static GtkSizeRequestMode |
182 | gtk_column_view_cell_get_request_mode (GtkWidget *widget) |
183 | { |
184 | GtkWidget *child = gtk_widget_get_first_child (widget); |
185 | |
186 | if (child) |
187 | return gtk_widget_get_request_mode (widget: child); |
188 | else |
189 | return GTK_SIZE_REQUEST_CONSTANT_SIZE; |
190 | } |
191 | |
192 | static void |
193 | gtk_column_view_cell_class_init (GtkColumnViewCellClass *klass) |
194 | { |
195 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
196 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
197 | |
198 | widget_class->root = gtk_column_view_cell_root; |
199 | widget_class->unroot = gtk_column_view_cell_unroot; |
200 | widget_class->measure = gtk_column_view_cell_measure; |
201 | widget_class->size_allocate = gtk_column_view_cell_size_allocate; |
202 | widget_class->get_request_mode = gtk_column_view_cell_get_request_mode; |
203 | |
204 | gobject_class->dispose = gtk_column_view_cell_dispose; |
205 | |
206 | gtk_widget_class_set_css_name (widget_class, I_("cell" )); |
207 | gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_GRID_CELL); |
208 | } |
209 | |
210 | static void |
211 | gtk_column_view_cell_resize_func (GtkWidget *widget) |
212 | { |
213 | GtkColumnViewCell *self = GTK_COLUMN_VIEW_CELL (widget); |
214 | |
215 | if (self->column) |
216 | gtk_column_view_column_queue_resize (self: self->column); |
217 | } |
218 | |
219 | static void |
220 | gtk_column_view_cell_init (GtkColumnViewCell *self) |
221 | { |
222 | GtkWidget *widget = GTK_WIDGET (self); |
223 | |
224 | gtk_widget_set_focusable (widget, FALSE); |
225 | gtk_widget_set_overflow (widget, overflow: GTK_OVERFLOW_HIDDEN); |
226 | /* FIXME: Figure out if setting the manager class to INVALID should work */ |
227 | gtk_widget_set_layout_manager (widget, NULL); |
228 | widget->priv->resize_func = gtk_column_view_cell_resize_func; |
229 | } |
230 | |
231 | GtkWidget * |
232 | gtk_column_view_cell_new (GtkColumnViewColumn *column) |
233 | { |
234 | GtkColumnViewCell *cell; |
235 | |
236 | cell = g_object_new (GTK_TYPE_COLUMN_VIEW_CELL, |
237 | first_property_name: "factory" , gtk_column_view_column_get_factory (self: column), |
238 | "visible" , gtk_column_view_column_get_visible (self: column), |
239 | NULL); |
240 | |
241 | cell->column = g_object_ref (column); |
242 | |
243 | return GTK_WIDGET (cell); |
244 | } |
245 | |
246 | void |
247 | gtk_column_view_cell_remove (GtkColumnViewCell *self) |
248 | { |
249 | GtkWidget *widget = GTK_WIDGET (self); |
250 | |
251 | gtk_list_item_widget_remove_child (GTK_LIST_ITEM_WIDGET (gtk_widget_get_parent (widget)), child: widget); |
252 | } |
253 | |
254 | GtkColumnViewCell * |
255 | gtk_column_view_cell_get_next (GtkColumnViewCell *self) |
256 | { |
257 | return self->next_cell; |
258 | } |
259 | |
260 | GtkColumnViewCell * |
261 | gtk_column_view_cell_get_prev (GtkColumnViewCell *self) |
262 | { |
263 | return self->prev_cell; |
264 | } |
265 | |
266 | GtkColumnViewColumn * |
267 | gtk_column_view_cell_get_column (GtkColumnViewCell *self) |
268 | { |
269 | return self->column; |
270 | } |
271 | |