Skip to content

Instantly share code, notes, and snippets.

@medovina
Created February 12, 2025 12:53
Show Gist options
  • Save medovina/0ad9da73d3c0972f058cc1b726a18eed to your computer and use it in GitHub Desktop.
Save medovina/0ad9da73d3c0972f058cc1b726a18eed to your computer and use it in GitHub Desktop.
demo GTK 4 program with a GtkColumnView
// This demo GTK 4 program creates a GtkColumnView that shows a list of movies, each with
// a year and title. You can click column headers to sort by year or title. The
// sorting is implemented using GtkCustomSorter objects.
//
// To keep things simple, I haven't bothered to deref or free any allocated objects.
//
// To build, run
// $ gcc -Wall `pkg-config --cflags gtk4` -o column_view column_view.c `pkg-config --libs gtk4`
#include <gtk/gtk.h>
// Use GObject black magic to define a GObject subclass called DemoMovie.
// A DemoMovie contains a year (an int) plus a title (a string).
#define DEMO_TYPE_MOVIE (demo_movie_get_type ())
G_DECLARE_FINAL_TYPE (DemoMovie, demo_movie, DEMO, MOVIE, GObject)
struct _DemoMovie {
GObject parent_instance;
int year;
const char *title;
};
struct _DemoMovieClass {
GObjectClass parent_class;
};
G_DEFINE_TYPE (DemoMovie, demo_movie, G_TYPE_OBJECT)
void demo_movie_init(DemoMovie *movie) {
}
void demo_movie_class_init(DemoMovieClass *class) {
}
// end black magic
DemoMovie *demo_movie_new(int year, const char *title) {
DemoMovie *movie = g_object_new(DEMO_TYPE_MOVIE, NULL);
movie->year = year;
movie->title = title;
return movie;
}
void setup_label(GtkSignalListItemFactory *factory, GtkListItem *listitem) {
GtkLabel *label = (GtkLabel *) gtk_label_new("");
gtk_list_item_set_child(listitem, GTK_WIDGET(label));
}
void bind_year(GtkSignalListItemFactory *factory, GtkListItem *listitem) {
GtkLabel *label = GTK_LABEL(gtk_list_item_get_child(listitem));
DemoMovie *movie = DEMO_MOVIE(gtk_list_item_get_item(listitem));
char buffer[16];
g_snprintf(buffer, 16, "%d", movie->year);
gtk_label_set_text(label, buffer);
}
void bind_title(GtkSignalListItemFactory *factory, GtkListItem *listitem) {
GtkLabel *label = GTK_LABEL(gtk_list_item_get_child(listitem));
gtk_widget_set_halign(GTK_WIDGET(label), GTK_ALIGN_START);
DemoMovie *movie = DEMO_MOVIE(gtk_list_item_get_item(listitem));
gtk_label_set_text(label, movie->title);
}
gint sort_by_year(gconstpointer a, gconstpointer b, gpointer user_data) {
DemoMovie *movie_a = (DemoMovie *) a;
DemoMovie *movie_b = (DemoMovie *) b;
return movie_a->year - movie_b->year;
}
gint sort_by_title(gconstpointer a, gconstpointer b, gpointer user_data) {
DemoMovie *movie_a = (DemoMovie *) a;
DemoMovie *movie_b = (DemoMovie *) b;
return g_strcmp0(movie_a->title, movie_b->title);
}
void activate (GtkApplication* app, gpointer user_data) {
GtkApplicationWindow *window = (GtkApplicationWindow *) gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "column demo");
GListStore *store = g_list_store_new(DEMO_TYPE_MOVIE);
g_list_store_append(store, demo_movie_new(1981, "Raiders of the Lost Ark"));
g_list_store_append(store, demo_movie_new(1994, "The Shawshank Redemption"));
g_list_store_append(store, demo_movie_new(1995, "Clueless"));
g_list_store_append(store, demo_movie_new(2001, "Memento"));
GtkColumnView *view = (GtkColumnView *) gtk_column_view_new(NULL);
// add column "year" with sorter
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "setup", G_CALLBACK(setup_label), NULL);
g_signal_connect(factory, "bind", G_CALLBACK(bind_year), NULL);
GtkColumnViewColumn *column = gtk_column_view_column_new ("year", factory);
GtkCustomSorter *sorter = gtk_custom_sorter_new(sort_by_year, NULL, NULL);
gtk_column_view_column_set_sorter(column, GTK_SORTER(sorter));
gtk_column_view_append_column(view, column);
// add column "title" with sorter
factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "setup", G_CALLBACK(setup_label), NULL);
g_signal_connect(factory, "bind", G_CALLBACK(bind_title), NULL);
column = gtk_column_view_column_new ("title", factory);
sorter = gtk_custom_sorter_new(sort_by_title, NULL, NULL);
gtk_column_view_column_set_sorter(column, GTK_SORTER(sorter));
gtk_column_view_append_column(view, column);
// enable sorting using a GtkSortListModel
GtkSorter *view_sorter = gtk_column_view_get_sorter(view);
GtkSortListModel *model = gtk_sort_list_model_new(G_LIST_MODEL(store), view_sorter);
GtkSingleSelection *selection = gtk_single_selection_new(G_LIST_MODEL(model));
gtk_column_view_set_model(view, GTK_SELECTION_MODEL(selection));
gtk_window_set_child(GTK_WINDOW(window), GTK_WIDGET(view));
gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
gtk_window_present(GTK_WINDOW(window));
}
int main (int argc, char **argv) {
GtkApplication *app = gtk_application_new("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment