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
32struct _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
43struct _GtkColumnViewCellClass
44{
45 GtkListItemWidgetClass parent_class;
46};
47
48G_DEFINE_TYPE (GtkColumnViewCell, gtk_column_view_cell, GTK_TYPE_LIST_ITEM_WIDGET)
49
50static int
51get_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
61static int
62unadjust_width (GtkWidget *widget,
63 int width)
64{
65 GtkCssStyle *style;
66 int widget_margins;
67 int css_extra;
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
81static void
82gtk_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
121static void
122gtk_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
139static void
140gtk_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
153static void
154gtk_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
171static void
172gtk_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
181static GtkSizeRequestMode
182gtk_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
192static void
193gtk_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
210static void
211gtk_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
219static void
220gtk_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
231GtkWidget *
232gtk_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
246void
247gtk_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
254GtkColumnViewCell *
255gtk_column_view_cell_get_next (GtkColumnViewCell *self)
256{
257 return self->next_cell;
258}
259
260GtkColumnViewCell *
261gtk_column_view_cell_get_prev (GtkColumnViewCell *self)
262{
263 return self->prev_cell;
264}
265
266GtkColumnViewColumn *
267gtk_column_view_cell_get_column (GtkColumnViewCell *self)
268{
269 return self->column;
270}
271

source code of gtk/gtk/gtkcolumnviewcell.c