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 "gtkcolumnviewcolumnprivate.h"
23#include "gtkcolumnviewsorterprivate.h"
24
25#include "gtkcolumnviewprivate.h"
26#include "gtkcolumnviewtitleprivate.h"
27#include "gtkintl.h"
28#include "gtklistbaseprivate.h"
29#include "gtklistitemwidgetprivate.h"
30#include "gtkmain.h"
31#include "gtkprivate.h"
32#include "gtkrbtreeprivate.h"
33#include "gtksizegroup.h"
34#include "gtkwidgetprivate.h"
35#include "gtksorter.h"
36
37/**
38 * GtkColumnViewColumn:
39 *
40 * `GtkColumnViewColumn` represents the columns being added to `GtkColumnView`.
41 *
42 * The main ingredient for a `GtkColumnViewColumn` is the `GtkListItemFactory`
43 * that tells the columnview how to create cells for this column from items in
44 * the model.
45 *
46 * Columns have a title, and can optionally have a header menu set
47 * with [method@Gtk.ColumnViewColumn.set_header_menu].
48 *
49 * A sorter can be associated with a column using
50 * [method@Gtk.ColumnViewColumn.set_sorter], to let users influence sorting
51 * by clicking on the column header.
52 */
53
54struct _GtkColumnViewColumn
55{
56 GObject parent_instance;
57
58 GtkListItemFactory *factory;
59 char *title;
60 GtkSorter *sorter;
61
62 /* data for the view */
63 GtkColumnView *view;
64 GtkWidget *header;
65
66 int minimum_size_request;
67 int natural_size_request;
68 int allocation_offset;
69 int allocation_size;
70 int header_position;
71
72 int fixed_width;
73
74 guint visible : 1;
75 guint resizable : 1;
76 guint expand : 1;
77
78 GMenuModel *menu;
79
80 /* This list isn't sorted - this is just caching for performance */
81 GtkColumnViewCell *first_cell; /* no reference, just caching */
82};
83
84struct _GtkColumnViewColumnClass
85{
86 GObjectClass parent_class;
87};
88
89enum
90{
91 PROP_0,
92 PROP_COLUMN_VIEW,
93 PROP_FACTORY,
94 PROP_TITLE,
95 PROP_SORTER,
96 PROP_VISIBLE,
97 PROP_HEADER_MENU,
98 PROP_RESIZABLE,
99 PROP_EXPAND,
100 PROP_FIXED_WIDTH,
101
102 N_PROPS
103};
104
105G_DEFINE_TYPE (GtkColumnViewColumn, gtk_column_view_column, G_TYPE_OBJECT)
106
107static GParamSpec *properties[N_PROPS] = { NULL, };
108
109static void
110gtk_column_view_column_dispose (GObject *object)
111{
112 GtkColumnViewColumn *self = GTK_COLUMN_VIEW_COLUMN (object);
113
114 g_assert (self->view == NULL); /* would hold a ref otherwise */
115 g_assert (self->first_cell == NULL); /* no view = no children */
116
117 g_clear_object (&self->factory);
118 g_clear_object (&self->sorter);
119 g_clear_pointer (&self->title, g_free);
120 g_clear_object (&self->menu);
121
122 G_OBJECT_CLASS (gtk_column_view_column_parent_class)->dispose (object);
123}
124
125static void
126gtk_column_view_column_get_property (GObject *object,
127 guint property_id,
128 GValue *value,
129 GParamSpec *pspec)
130{
131 GtkColumnViewColumn *self = GTK_COLUMN_VIEW_COLUMN (object);
132
133 switch (property_id)
134 {
135 case PROP_COLUMN_VIEW:
136 g_value_set_object (value, v_object: self->view);
137 break;
138
139 case PROP_FACTORY:
140 g_value_set_object (value, v_object: self->factory);
141 break;
142
143 case PROP_TITLE:
144 g_value_set_string (value, v_string: self->title);
145 break;
146
147 case PROP_SORTER:
148 g_value_set_object (value, v_object: self->sorter);
149 break;
150
151 case PROP_VISIBLE:
152 g_value_set_boolean (value, v_boolean: self->visible);
153 break;
154
155 case PROP_HEADER_MENU:
156 g_value_set_object (value, v_object: self->menu);
157 break;
158
159 case PROP_RESIZABLE:
160 g_value_set_boolean (value, v_boolean: self->resizable);
161 break;
162
163 case PROP_EXPAND:
164 g_value_set_boolean (value, v_boolean: self->expand);
165 break;
166
167 case PROP_FIXED_WIDTH:
168 g_value_set_int (value, v_int: self->fixed_width);
169 break;
170
171 default:
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
173 break;
174 }
175}
176
177static void
178gtk_column_view_column_set_property (GObject *object,
179 guint property_id,
180 const GValue *value,
181 GParamSpec *pspec)
182{
183 GtkColumnViewColumn *self = GTK_COLUMN_VIEW_COLUMN (object);
184
185 switch (property_id)
186 {
187 case PROP_FACTORY:
188 gtk_column_view_column_set_factory (self, factory: g_value_get_object (value));
189 break;
190
191 case PROP_TITLE:
192 gtk_column_view_column_set_title (self, title: g_value_get_string (value));
193 break;
194
195 case PROP_SORTER:
196 gtk_column_view_column_set_sorter (self, sorter: g_value_get_object (value));
197 break;
198
199 case PROP_VISIBLE:
200 gtk_column_view_column_set_visible (self, visible: g_value_get_boolean (value));
201 break;
202
203 case PROP_HEADER_MENU:
204 gtk_column_view_column_set_header_menu (self, menu: g_value_get_object (value));
205 break;
206
207 case PROP_RESIZABLE:
208 gtk_column_view_column_set_resizable (self, resizable: g_value_get_boolean (value));
209 break;
210
211 case PROP_EXPAND:
212 gtk_column_view_column_set_expand (self, expand: g_value_get_boolean (value));
213 break;
214
215 case PROP_FIXED_WIDTH:
216 gtk_column_view_column_set_fixed_width (self, fixed_width: g_value_get_int (value));
217 break;
218
219 default:
220 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
221 break;
222 }
223}
224
225static void
226gtk_column_view_column_class_init (GtkColumnViewColumnClass *klass)
227{
228 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
229
230 gobject_class->dispose = gtk_column_view_column_dispose;
231 gobject_class->get_property = gtk_column_view_column_get_property;
232 gobject_class->set_property = gtk_column_view_column_set_property;
233
234 /**
235 * GtkColumnViewColumn:column-view: (attributes org.gtk.Property.get=gtk_column_view_column_get_column_view)
236 *
237 * The `GtkColumnView` this column is a part of.
238 */
239 properties[PROP_COLUMN_VIEW] =
240 g_param_spec_object (name: "column-view",
241 P_("Column view"),
242 P_("Column view this column is a part of"),
243 GTK_TYPE_COLUMN_VIEW,
244 flags: G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
245
246 /**
247 * GtkColumnViewColumn:factory: (attributes org.gtk.Property.get=gtk_column_view_column_get_factory org.gtk.Property.set=gtk_column_view_column_set_factory)
248 *
249 * Factory for populating list items.
250 */
251 properties[PROP_FACTORY] =
252 g_param_spec_object (name: "factory",
253 P_("Factory"),
254 P_("Factory for populating list items"),
255 GTK_TYPE_LIST_ITEM_FACTORY,
256 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
257
258 /**
259 * GtkColumnViewColumn:title: (attributes org.gtk.Property.get=gtk_column_view_column_get_title org.gtk.Property.set=gtk_column_view_column_set_title)
260 *
261 * Title displayed in the header.
262 */
263 properties[PROP_TITLE] =
264 g_param_spec_string (name: "title",
265 P_("Title"),
266 P_("Title displayed in the header"),
267 NULL,
268 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
269
270 /**
271 * GtkColumnViewColumn:sorter: (attributes org.gtk.Property.get=gtk_column_view_column_get_sorter org.gtk.Property.set=gtk_column_view_column_set_sorter)
272 *
273 * Sorter for sorting items according to this column.
274 */
275 properties[PROP_SORTER] =
276 g_param_spec_object (name: "sorter",
277 P_("Sorter"),
278 P_("Sorter for sorting items according to this column"),
279 GTK_TYPE_SORTER,
280 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
281
282 /**
283 * GtkColumnViewColumn:visible: (attributes org.gtk.Property.get=gtk_column_view_column_get_visible org.gtk.Property.set=gtk_column_view_column_set_visible)
284 *
285 * Whether this column is visible.
286 */
287 properties[PROP_VISIBLE] =
288 g_param_spec_boolean (name: "visible",
289 P_("Visible"),
290 P_("Whether this column is visible"),
291 TRUE,
292 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
293
294 /**
295 * GtkColumnViewColumn:header-menu: (attributes org.gtk.Property.get=gtk_column_view_column_get_header_menu org.gtk.Property.set=gtk_column_view_column_set_header_menu)
296 *
297 * Menu model used to create the context menu for the column header.
298 */
299 properties[PROP_HEADER_MENU] =
300 g_param_spec_object (name: "header-menu",
301 P_("Header menu"),
302 P_("Menu to use on the title of this column"),
303 G_TYPE_MENU_MODEL,
304 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
305
306 /**
307 * GtkColumnViewColumn:resizable: (attributes org.gtk.Property.get=gtk_column_view_column_get_resizable org.gtk.Property.set=gtk_column_view_column_set_resizable)
308 *
309 * Whether this column is resizable.
310 */
311 properties[PROP_RESIZABLE] =
312 g_param_spec_boolean (name: "resizable",
313 P_("Resizable"),
314 P_("Whether this column is resizable"),
315 FALSE,
316 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
317
318 /**
319 * GtkColumnViewColumn:expand: (attributes org.gtk.Property.get=gtk_column_view_column_get_expand org.gtk.Property.set=gtk_column_view_column_set_expand)
320 *
321 * Column gets share of extra width allocated to the view.
322 */
323 properties[PROP_EXPAND] =
324 g_param_spec_boolean (name: "expand",
325 P_("Expand"),
326 P_("column gets share of extra width"),
327 FALSE,
328 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
329
330 /**
331 * GtkColumnViewColumn:fixed-width: (attributes org.gtk.Property.get=gtk_column_view_column_get_fixed_width org.gtk.Property.set=gtk_column_view_column_set_fixed_width)
332 *
333 * If not -1, this is the width that the column is allocated,
334 * regardless of the size of its content.
335 */
336 properties[PROP_FIXED_WIDTH] =
337 g_param_spec_int (name: "fixed-width",
338 P_("Fixed width"),
339 P_("Fixed width of this column"),
340 minimum: -1, G_MAXINT, default_value: -1,
341 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
342
343 g_object_class_install_properties (oclass: gobject_class, n_pspecs: N_PROPS, pspecs: properties);
344}
345
346static void
347gtk_column_view_column_init (GtkColumnViewColumn *self)
348{
349 self->minimum_size_request = -1;
350 self->natural_size_request = -1;
351 self->visible = TRUE;
352 self->resizable = FALSE;
353 self->expand = FALSE;
354 self->fixed_width = -1;
355}
356
357/**
358 * gtk_column_view_column_new:
359 * @title: (nullable): Title to use for this column
360 * @factory: (transfer full) (nullable): The factory to populate items with
361 *
362 * Creates a new `GtkColumnViewColumn` that uses the given @factory for
363 * mapping items to widgets.
364 *
365 * You most likely want to call [method@Gtk.ColumnView.append_column] next.
366 *
367 * The function takes ownership of the argument, so you can write code like:
368 *
369 * ```c
370 * column = gtk_column_view_column_new (_("Name"),
371 * gtk_builder_list_item_factory_new_from_resource ("/name.ui"));
372 * ```
373 *
374 * Returns: a new `GtkColumnViewColumn` using the given @factory
375 */
376GtkColumnViewColumn *
377gtk_column_view_column_new (const char *title,
378 GtkListItemFactory *factory)
379{
380 GtkColumnViewColumn *result;
381
382 g_return_val_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory), NULL);
383
384 result = g_object_new (GTK_TYPE_COLUMN_VIEW_COLUMN,
385 first_property_name: "factory", factory,
386 "title", title,
387 NULL);
388
389 g_clear_object (&factory);
390
391 return result;
392}
393
394GtkColumnViewCell *
395gtk_column_view_column_get_first_cell (GtkColumnViewColumn *self)
396{
397 return self->first_cell;
398}
399
400void
401gtk_column_view_column_add_cell (GtkColumnViewColumn *self,
402 GtkColumnViewCell *cell)
403{
404 self->first_cell = cell;
405
406 gtk_widget_set_visible (GTK_WIDGET (cell), visible: self->visible);
407 gtk_column_view_column_queue_resize (self);
408}
409
410void
411gtk_column_view_column_remove_cell (GtkColumnViewColumn *self,
412 GtkColumnViewCell *cell)
413{
414 if (cell == self->first_cell)
415 self->first_cell = gtk_column_view_cell_get_next (self: cell);
416
417 gtk_column_view_column_queue_resize (self);
418 gtk_widget_queue_resize (GTK_WIDGET (cell));
419}
420
421void
422gtk_column_view_column_queue_resize (GtkColumnViewColumn *self)
423{
424 GtkColumnViewCell *cell;
425
426 if (self->minimum_size_request < 0)
427 return;
428
429 self->minimum_size_request = -1;
430 self->natural_size_request = -1;
431
432 if (self->header)
433 gtk_widget_queue_resize (widget: self->header);
434
435 for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (self: cell))
436 {
437 gtk_widget_queue_resize (GTK_WIDGET (cell));
438 }
439}
440
441void
442gtk_column_view_column_measure (GtkColumnViewColumn *self,
443 int *minimum,
444 int *natural)
445{
446 if (self->fixed_width > -1)
447 {
448 self->minimum_size_request = self->fixed_width;
449 self->natural_size_request = self->fixed_width;
450 }
451
452 if (self->minimum_size_request < 0)
453 {
454 GtkColumnViewCell *cell;
455 int min, nat, cell_min, cell_nat;
456
457 if (self->header)
458 {
459 gtk_widget_measure (widget: self->header, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1, minimum: &min, natural: &nat, NULL, NULL);
460 }
461 else
462 {
463 min = 0;
464 nat = 0;
465 }
466
467 for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (self: cell))
468 {
469 gtk_widget_measure (GTK_WIDGET (cell),
470 orientation: GTK_ORIENTATION_HORIZONTAL,
471 for_size: -1,
472 minimum: &cell_min, natural: &cell_nat,
473 NULL, NULL);
474
475 min = MAX (min, cell_min);
476 nat = MAX (nat, cell_nat);
477 }
478
479 self->minimum_size_request = min;
480 self->natural_size_request = nat;
481 }
482
483 *minimum = self->minimum_size_request;
484 *natural = self->natural_size_request;
485}
486
487void
488gtk_column_view_column_allocate (GtkColumnViewColumn *self,
489 int offset,
490 int size)
491{
492 self->allocation_offset = offset;
493 self->allocation_size = size;
494 self->header_position = offset;
495}
496
497void
498gtk_column_view_column_get_allocation (GtkColumnViewColumn *self,
499 int *offset,
500 int *size)
501{
502 if (offset)
503 *offset = self->allocation_offset;
504 if (size)
505 *size = self->allocation_size;
506}
507
508static void
509gtk_column_view_column_create_cells (GtkColumnViewColumn *self)
510{
511 GtkListView *list;
512 GtkWidget *row;
513
514 if (self->first_cell)
515 return;
516
517 list = gtk_column_view_get_list_view (GTK_COLUMN_VIEW (self->view));
518 for (row = gtk_widget_get_first_child (GTK_WIDGET (list));
519 row != NULL;
520 row = gtk_widget_get_next_sibling (widget: row))
521 {
522 GtkListItemWidget *list_item;
523 GtkWidget *cell;
524
525 if (!gtk_widget_get_root (widget: row))
526 continue;
527
528 list_item = GTK_LIST_ITEM_WIDGET (row);
529 cell = gtk_column_view_cell_new (column: self);
530 gtk_list_item_widget_add_child (self: list_item, child: cell);
531 gtk_list_item_widget_update (GTK_LIST_ITEM_WIDGET (cell),
532 position: gtk_list_item_widget_get_position (self: list_item),
533 item: gtk_list_item_widget_get_item (self: list_item),
534 selected: gtk_list_item_widget_get_selected (self: list_item));
535 }
536}
537
538static void
539gtk_column_view_column_remove_cells (GtkColumnViewColumn *self)
540{
541 while (self->first_cell)
542 gtk_column_view_cell_remove (self: self->first_cell);
543}
544
545static void
546gtk_column_view_column_create_header (GtkColumnViewColumn *self)
547{
548 if (self->header != NULL)
549 return;
550
551 self->header = gtk_column_view_title_new (column: self);
552 gtk_widget_set_visible (widget: self->header, visible: self->visible);
553 gtk_list_item_widget_add_child (self: gtk_column_view_get_header_widget (self: self->view),
554 child: self->header);
555 gtk_column_view_column_queue_resize (self);
556}
557
558static void
559gtk_column_view_column_remove_header (GtkColumnViewColumn *self)
560{
561 if (self->header == NULL)
562 return;
563
564 gtk_list_item_widget_remove_child (self: gtk_column_view_get_header_widget (self: self->view),
565 child: self->header);
566 self->header = NULL;
567 gtk_column_view_column_queue_resize (self);
568}
569
570static void
571gtk_column_view_column_ensure_cells (GtkColumnViewColumn *self)
572{
573 if (self->view && gtk_widget_get_root (GTK_WIDGET (self->view)))
574 gtk_column_view_column_create_cells (self);
575 else
576 gtk_column_view_column_remove_cells (self);
577
578 if (self->view)
579 gtk_column_view_column_create_header (self);
580 else
581 gtk_column_view_column_remove_header (self);
582}
583
584/**
585 * gtk_column_view_column_get_column_view: (attributes org.gtk.Method.get_property=column-view)
586 * @self: a `GtkColumnViewColumn`
587 *
588 * Gets the column view that's currently displaying this column.
589 *
590 * If @self has not been added to a column view yet, %NULL is returned.
591 *
592 * Returns: (nullable) (transfer none): The column view displaying @self.
593 */
594GtkColumnView *
595gtk_column_view_column_get_column_view (GtkColumnViewColumn *self)
596{
597 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), NULL);
598
599 return self->view;
600}
601
602void
603gtk_column_view_column_set_column_view (GtkColumnViewColumn *self,
604 GtkColumnView *view)
605{
606 if (self->view == view)
607 return;
608
609 gtk_column_view_column_remove_cells (self);
610 gtk_column_view_column_remove_header (self);
611
612 self->view = view;
613
614 gtk_column_view_column_ensure_cells (self);
615
616 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_COLUMN_VIEW]);
617}
618
619void
620gtk_column_view_column_set_position (GtkColumnViewColumn *self,
621 guint position)
622{
623 GtkColumnViewCell *cell;
624
625 gtk_list_item_widget_reorder_child (self: gtk_column_view_get_header_widget (self: self->view),
626 child: self->header,
627 position);
628
629 for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (self: cell))
630 {
631 GtkListItemWidget *list_item;
632
633 list_item = GTK_LIST_ITEM_WIDGET (gtk_widget_get_parent (GTK_WIDGET (cell)));
634 gtk_list_item_widget_reorder_child (self: list_item, GTK_WIDGET (cell), position);
635 }
636}
637
638/**
639 * gtk_column_view_column_get_factory: (attributes org.gtk.Method.get_property=factory)
640 * @self: a `GtkColumnViewColumn`
641 *
642 * Gets the factory that's currently used to populate list items for
643 * this column.
644 *
645 * Returns: (nullable) (transfer none): The factory in use
646 **/
647GtkListItemFactory *
648gtk_column_view_column_get_factory (GtkColumnViewColumn *self)
649{
650 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), NULL);
651
652 return self->factory;
653}
654
655/**
656 * gtk_column_view_column_set_factory: (attributes org.gtk.Method.set_property=factory)
657 * @self: a `GtkColumnViewColumn`
658 * @factory: (nullable) (transfer none): the factory to use
659 *
660 * Sets the `GtkListItemFactory` to use for populating list items for this
661 * column.
662 */
663void
664gtk_column_view_column_set_factory (GtkColumnViewColumn *self,
665 GtkListItemFactory *factory)
666{
667 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
668 g_return_if_fail (factory == NULL || GTK_LIST_ITEM_FACTORY (factory));
669
670 if (!g_set_object (&self->factory, factory))
671 return;
672
673 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_FACTORY]);
674}
675
676/**
677 * gtk_column_view_column_set_title: (attributes org.gtk.Method.set_property=title)
678 * @self: a `GtkColumnViewColumn`
679 * @title: (nullable): Title to use for this column
680 *
681 * Sets the title of this column.
682 *
683 * The title is displayed in the header of a `GtkColumnView`
684 * for this column and is therefore user-facing text that should
685 * be translated.
686 */
687void
688gtk_column_view_column_set_title (GtkColumnViewColumn *self,
689 const char *title)
690{
691 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
692
693 if (g_strcmp0 (str1: self->title, str2: title) == 0)
694 return;
695
696 g_free (mem: self->title);
697 self->title = g_strdup (str: title);
698
699 if (self->header)
700 gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
701
702 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_TITLE]);
703}
704
705/**
706 * gtk_column_view_column_get_title: (attributes org.gtk.Method.get_property=title)
707 * @self: a `GtkColumnViewColumn`
708 *
709 * Returns the title set with gtk_column_view_column_set_title().
710 *
711 * Returns: (nullable): The column's title
712 */
713const char *
714gtk_column_view_column_get_title (GtkColumnViewColumn *self)
715{
716 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), FALSE);
717
718 return self->title;
719}
720
721#if 0
722static void
723gtk_column_view_column_add_to_sorter (GtkColumnViewColumn *self)
724{
725 if (self->view == NULL)
726 return;
727
728 gtk_column_view_sorter_add_column (GTK_COLUMN_VIEW_SORTER (gtk_column_view_get_sorter (self->view)), self);
729}
730#endif
731
732static void
733gtk_column_view_column_remove_from_sorter (GtkColumnViewColumn *self)
734{
735 if (self->view == NULL)
736 return;
737
738 gtk_column_view_sorter_remove_column (self: GTK_COLUMN_VIEW_SORTER (ptr: gtk_column_view_get_sorter (self: self->view)), column: self);
739}
740
741/**
742 * gtk_column_view_column_set_sorter: (attributes org.gtk.Method.set_property=sorter)
743 * @self: a `GtkColumnViewColumn`
744 * @sorter: (nullable): the `GtkSorter` to associate with @column
745 *
746 * Associates a sorter with the column.
747 *
748 * If @sorter is %NULL, the column will not let users change
749 * the sorting by clicking on its header.
750 *
751 * This sorter can be made active by clicking on the column
752 * header, or by calling [method@Gtk.ColumnView.sort_by_column].
753 *
754 * See [method@Gtk.ColumnView.get_sorter] for the necessary steps
755 * for setting up customizable sorting for [class@Gtk.ColumnView].
756 */
757void
758gtk_column_view_column_set_sorter (GtkColumnViewColumn *self,
759 GtkSorter *sorter)
760{
761 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
762 g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter));
763
764 if (!g_set_object (&self->sorter, sorter))
765 return;
766
767 gtk_column_view_column_remove_from_sorter (self);
768
769 if (self->header)
770 gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
771
772 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_SORTER]);
773}
774
775/**
776 * gtk_column_view_column_get_sorter: (attributes org.gtk.Method.get_property=sorter)
777 * @self: a `GtkColumnViewColumn`
778 *
779 * Returns the sorter that is associated with the column.
780 *
781 * Returns: (nullable) (transfer none): the `GtkSorter` of @self
782 */
783GtkSorter *
784gtk_column_view_column_get_sorter (GtkColumnViewColumn *self)
785{
786 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), NULL);
787
788 return self->sorter;
789}
790
791void
792gtk_column_view_column_notify_sort (GtkColumnViewColumn *self)
793{
794 if (self->header)
795 gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
796}
797
798/**
799 * gtk_column_view_column_set_visible: (attributes org.gtk.Method.set_property=visible)
800 * @self: a `GtkColumnViewColumn`
801 * @visible: whether this column should be visible
802 *
803 * Sets whether this column should be visible in views.
804 */
805void
806gtk_column_view_column_set_visible (GtkColumnViewColumn *self,
807 gboolean visible)
808{
809 GtkColumnViewCell *cell;
810
811 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
812
813 if (self->visible == visible)
814 return;
815
816 self->visible = visible;
817
818 self->minimum_size_request = -1;
819 self->natural_size_request = -1;
820
821 if (self->header)
822 gtk_widget_set_visible (GTK_WIDGET (self->header), visible);
823
824 for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (self: cell))
825 {
826 gtk_widget_set_visible (GTK_WIDGET (cell), visible);
827 }
828
829 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_VISIBLE]);
830}
831
832/**
833 * gtk_column_view_column_get_visible: (attributes org.gtk.Method.get_property=visible)
834 * @self: a `GtkColumnViewColumn`
835 *
836 * Returns whether this column is visible.
837 *
838 * Returns: %TRUE if this column is visible
839 */
840gboolean
841gtk_column_view_column_get_visible (GtkColumnViewColumn *self)
842{
843 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), TRUE);
844
845 return self->visible;
846}
847
848/**
849 * gtk_column_view_column_set_header_menu: (attributes org.gtk.Method.set_property=header-menu)
850 * @self: a `GtkColumnViewColumn`
851 * @menu: (nullable): a `GMenuModel`
852 *
853 * Sets the menu model that is used to create the context menu
854 * for the column header.
855 */
856void
857gtk_column_view_column_set_header_menu (GtkColumnViewColumn *self,
858 GMenuModel *menu)
859{
860 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
861 g_return_if_fail (menu == NULL || G_IS_MENU_MODEL (menu));
862
863 if (!g_set_object (&self->menu, menu))
864 return;
865
866 if (self->header)
867 gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
868
869 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_HEADER_MENU]);
870}
871
872/**
873 * gtk_column_view_column_get_header_menu: (attributes org.gtk.Method.get_property=header-menu)
874 * @self: a `GtkColumnViewColumn`
875 *
876 * Gets the menu model that is used to create the context menu
877 * for the column header.
878 *
879 * Returns: (transfer none) (nullable): the `GMenuModel`
880 */
881GMenuModel *
882gtk_column_view_column_get_header_menu (GtkColumnViewColumn *self)
883{
884 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), NULL);
885
886 return self->menu;
887}
888
889/**
890 * gtk_column_view_column_set_expand: (attributes org.gtk.Method.set_property=expand)
891 * @self: a `GtkColumnViewColumn`
892 * @expand: %TRUE if this column should expand to fill available sace
893 *
894 * Sets the column to take available extra space.
895 *
896 * The extra space is shared equally amongst all columns that
897 * have the expand set to %TRUE.
898 */
899void
900gtk_column_view_column_set_expand (GtkColumnViewColumn *self,
901 gboolean expand)
902{
903 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
904
905 if (self->expand == expand)
906 return;
907
908 self->expand = expand;
909
910 if (self->visible && self->view)
911 gtk_widget_queue_resize (GTK_WIDGET (self->view));
912
913 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_EXPAND]);
914}
915
916/**
917 * gtk_column_view_column_get_expand: (attributes org.gtk.Method.get_property=expand)
918 * @self: a `GtkColumnViewColumn`
919 *
920 * Returns whether this column should expand.
921 *
922 * Returns: %TRUE if this column expands
923 */
924gboolean
925gtk_column_view_column_get_expand (GtkColumnViewColumn *self)
926{
927 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), TRUE);
928
929 return self->expand;
930}
931
932/**
933 * gtk_column_view_column_set_resizable: (attributes org.gtk.Method.set_property=resizable)
934 * @self: a `GtkColumnViewColumn`
935 * @resizable: whether this column should be resizable
936 *
937 * Sets whether this column should be resizable by dragging.
938 */
939void
940gtk_column_view_column_set_resizable (GtkColumnViewColumn *self,
941 gboolean resizable)
942{
943 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
944
945 if (self->resizable == resizable)
946 return;
947
948 self->resizable = resizable;
949
950 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_RESIZABLE]);
951}
952
953/**
954 * gtk_column_view_column_get_resizable: (attributes org.gtk.Method.get_property=resizable)
955 * @self: a `GtkColumnViewColumn`
956 *
957 * Returns whether this column is resizable.
958 *
959 * Returns: %TRUE if this column is resizable
960 */
961gboolean
962gtk_column_view_column_get_resizable (GtkColumnViewColumn *self)
963{
964 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), TRUE);
965
966 return self->resizable;
967}
968
969/**
970 * gtk_column_view_column_set_fixed_width: (attributes org.gtk.Method.set_property=fixed-width)
971 * @self: a `GtkColumnViewColumn`
972 * @fixed_width: the new fixed width, or -1
973 *
974 * If @fixed_width is not -1, sets the fixed width of @column;
975 * otherwise unsets it.
976 *
977 * Setting a fixed width overrides the automatically calculated
978 * width. Interactive resizing also sets the “fixed-width” property.
979 */
980void
981gtk_column_view_column_set_fixed_width (GtkColumnViewColumn *self,
982 int fixed_width)
983{
984 g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
985 g_return_if_fail (fixed_width >= -1);
986
987 if (self->fixed_width == fixed_width)
988 return;
989
990 self->fixed_width = fixed_width;
991
992 gtk_column_view_column_queue_resize (self);
993
994 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_FIXED_WIDTH]);
995}
996
997/**
998 * gtk_column_view_column_get_fixed_width: (attributes org.gtk.Method.get_property=fixed-width)
999 * @self: a `GtkColumnViewColumn`
1000 *
1001 * Gets the fixed width of the column.
1002 *
1003 * Returns: the fixed with of the column
1004 */
1005int
1006gtk_column_view_column_get_fixed_width (GtkColumnViewColumn *self)
1007{
1008 g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), -1);
1009
1010 return self->fixed_width;
1011}
1012
1013GtkWidget *
1014gtk_column_view_column_get_header (GtkColumnViewColumn *self)
1015{
1016 return self->header;
1017}
1018
1019void
1020gtk_column_view_column_set_header_position (GtkColumnViewColumn *self,
1021 int offset)
1022{
1023 self->header_position = offset;
1024}
1025
1026void
1027gtk_column_view_column_get_header_allocation (GtkColumnViewColumn *self,
1028 int *offset,
1029 int *size)
1030{
1031 if (offset)
1032 *offset = self->header_position;
1033
1034 if (size)
1035 *size = self->allocation_size;
1036}
1037

source code of gtk/gtk/gtkcolumnviewcolumn.c