Skip to content

Instantly share code, notes, and snippets.

@angstyloop
Last active May 14, 2023 04:44
Show Gist options
  • Save angstyloop/6f809d96b66afc4feddf55ce19b7975c to your computer and use it in GitHub Desktop.
Save angstyloop/6f809d96b66afc4feddf55ce19b7975c to your computer and use it in GitHub Desktop.
Example of how to show metadata with VIPS in a GTK4 GtkColumnView widget.
/*
ABOUT
Example of how to show metadata with VIPS in a GTK4 GtkColumnView widget.
Also supports css.
COMPILE
gcc `pkg-config --cflags gtk4 vips` -o metadata-columnview metadata-columnview.c `pkg-config --libs gtk4 vips`
RUN
./metadata-columnview
*/
#include <gtk/gtk.h>
#include <vips/vips.h>
static VipsImage *image = NULL;
/* We could play the same game with the setup function, to produce a custom
* widget type for the items in each column, but for now we'll just use a
* GtkLabel for all items in the view.
*/
static void
factory_setup( GtkListItemFactory *factory, GtkListItem *list_item )
{
GtkWidget *label = gtk_label_new( "" );
gtk_widget_set_halign( label, GTK_ALIGN_START );
gtk_list_item_set_child( list_item, label );
}
/* The bind function for the field name factory, corresponding to the first
* column. In this case, the field name is the metadata field name.
*/
static void
field_name_factory_bind( GtkListItemFactory *factory, GtkListItem *list_item )
{
GtkWidget *label;
GtkStringObject *string_object;
const char *field_name;
label = gtk_list_item_get_child( list_item );
string_object = GTK_STRING_OBJECT( gtk_list_item_get_item( list_item ) );
field_name = gtk_string_object_get_string( string_object );
gtk_label_set_label( GTK_LABEL( label ), field_name );
}
/* The bind function for the other factories, corresponding to columns after
* the field name column.
*/
static void
value_factory_bind( GtkListItemFactory *factory, GtkListItem *list_item, gpointer user_data )
{
GtkWidget *label;
GtkStringObject *string_object;
const char *field_name, *column_name = (const char *) user_data;
char str[256];
// It is crucial to zero the GValue whose address we pass to
// vips_image_get. Otherwise, we will get runtime errors.
GValue value = { 0 };
VipsBuf buf = VIPS_BUF_STATIC( str );
label = gtk_list_item_get_child( list_item );
string_object = GTK_STRING_OBJECT( gtk_list_item_get_item( list_item ) );
field_name = gtk_string_object_get_string( string_object );
/* Get the value of the given metadata field from the (global) test
* image.
*/
vips_image_get( image, field_name, &value );
vips_buf_appendgv( &buf, &value );
gtk_label_set_label( GTK_LABEL( label ), vips_buf_all( &buf ) );
}
/* Callback that starts the application.
*/
static void
activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window, *view;
GtkColumnViewColumn* column;
GdkDisplay *display;
char *column_names[] = { "Field", "Value" };
const int column_names_length = 2;
/* Create the (global) test image.
*/
image = vips_image_new_temp_file("a.jpg");
/* Create the application window.
*/
window = gtk_application_window_new( app );
gtk_window_set_title( GTK_WINDOW( window ), "Metadata" );
gtk_window_set_default_size( GTK_WINDOW( window ), 200, 200 );
display = gtk_widget_get_display( GTK_WIDGET( window ) );
const char *css_path = "metadata-columnview.css";
GtkCssProvider *provider = gtk_css_provider_new();
gtk_css_provider_load_from_path( provider, css_path );
gtk_style_context_add_provider_for_display( display,
GTK_STYLE_PROVIDER( provider ),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION );
/* Define the list items of the first column. For this example, these
* are exactly the names of the fields on the (global) test image.
*/
char** field_names = vips_image_get_fields( image );
/* Define the list model our selection model will use.
*/
GtkStringList *list_model = gtk_string_list_new( (const char* const*) field_names );
/* Create simple selection model, which does not have any selection
* logic. Curiously, you can still see the mouseover highlight effect
* and onclick highlight effect even for GtkNoSelection, perhaps for
* accessibility reasons.
*/
GtkNoSelection *selection_model = gtk_no_selection_new( G_LIST_MODEL( list_model ) );
/* Initialize the array of GtkListItemFactory - one for each column.
*/
GtkListItemFactory *factories[column_names_length];
for ( int i = 0; i < column_names_length; i++ )
factories[i] = gtk_signal_list_item_factory_new();
/* Connect handlers to the field name factory.
*/
g_signal_connect( factories[0], "setup", G_CALLBACK( factory_setup ), NULL );
g_signal_connect( factories[0], "bind", G_CALLBACK( field_name_factory_bind ), column_names[0] );
/* Connect handlers to the other factories.
*/
for ( int i = 1; i < column_names_length; i++ ) {
g_signal_connect( factories[i], "setup", G_CALLBACK( factory_setup ), NULL );
g_signal_connect( factories[i], "bind", G_CALLBACK( value_factory_bind ), column_names[i] );
}
/* Create the column view.
*/
view = gtk_column_view_new( GTK_SELECTION_MODEL( selection_model ) );
//gtk_column_view_set_show_column_separators( GTK_COLUMN_VIEW( view ), TRUE );
//gtk_column_view_set_show_row_separators( GTK_COLUMN_VIEW( view ), TRUE );
gtk_window_set_child( GTK_WINDOW( window ), view );
/* Create the columns.
*/
for ( int i = 0; i < column_names_length; i++ ) {
column = gtk_column_view_column_new( column_names[i], factories[i] );
//gtk_column_view_column_set_resizable( column, TRUE );
gtk_column_view_column_set_expand( column, TRUE );
gtk_column_view_append_column( GTK_COLUMN_VIEW( view ), column );
}
/* Show everything.
*/
gtk_widget_show (window);
}
/* The main just function sets up a signal handler for "activate".
*/
int
main (int argc, char **argv) {
GtkApplication *app;
int status;
VIPS_INIT( argv[0] );
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment