implement table styling for gtk3

Sun, 31 Aug 2025 09:44:53 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 31 Aug 2025 09:44:53 +0200
changeset 745
a4ee36ff7147
parent 744
0528926422da
child 746
7899792496cb

implement table styling for gtk3

application/main.c file | annotate | diff | comparison | revisions
ui/gtk/list.c file | annotate | diff | comparison | revisions
ui/gtk/list.h file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
--- a/application/main.c	Sun Aug 31 07:50:23 2025 +0200
+++ b/application/main.c	Sun Aug 31 09:44:53 2025 +0200
@@ -465,9 +465,16 @@
 UiBool table_getstyle(UiList *list, void *elm, int row, int col, void *userdata, UiTextStyle *style) {
     if(row < 2 && col != -1) {
         style->text_style = UI_TEXT_STYLE_BOLD;
+        if(col == 2) {
+            style->text_style = UI_TEXT_STYLE_ITALIC;
+        }
+        if(row == 1) {
+            style->text_style |= UI_TEXT_STYLE_UNDERLINE;
+        }
         style->fg.blue = col == 1 ? 255 : 0;
         style->fg.green = col == 2 ? 255 : 0;
         style->fg.red = col == 5 ? 255 : 0;
+        style->fg_set = TRUE;
         return TRUE;
     }
     return FALSE;
--- a/ui/gtk/list.c	Sun Aug 31 07:50:23 2025 +0200
+++ b/ui/gtk/list.c	Sun Aug 31 09:44:53 2025 +0200
@@ -772,14 +772,40 @@
 
 static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIter *iter, UiList *list, void *elm, int row) {
     UiModel *model = listview->model;
+    ui_getstylefunc getstyle = listview->getstyle;
+    
+    // get the row style
+    UiBool style_set = FALSE;
+    UiTextStyle style = { 0, 0 };
+    if(getstyle) {
+        style_set = getstyle(list, elm, row, -1, listview->getstyledata, &style);
+    }
+    
     // set column values
     int c = 0;
     for(int i=0;i<model->columns;i++,c++) {
         UiBool freevalue = FALSE;
         void *data = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
+        
+        UiModelType type = model->types[i];
+        
+        if(getstyle) {
+            // in case the column is icon+text, only get a style for the text column
+            int style_col = c;
+            if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
+                style_col++;
+            }
+            
+            // Get the individual column style 
+            // The column style overrides the row style, however if no column style
+            // is provided, we stick with the row style
+            if(getstyle(list, elm, row, style_col, listview->getstyledata, &style)) {
+                style_set = TRUE;
+            }
+        }
 
         GValue value = G_VALUE_INIT;
-        switch(model->types[i]) {
+        switch(type) {
             case UI_STRING_FREE: {
                 freevalue = TRUE;
             } 
@@ -852,13 +878,64 @@
         }
 
         gtk_list_store_set_value(store, iter, c, &value);
+        
+        if(style_set) {
+            int soff = listview->style_offset + i*6;
+            
+            GValue style_set_value = G_VALUE_INIT;
+            g_value_init(&style_set_value, G_TYPE_BOOLEAN);
+            g_value_set_boolean(&style_set_value, TRUE);
+            gtk_list_store_set_value(store, iter, soff, &style_set_value);
+            
+            GValue style_weight_value = G_VALUE_INIT;
+            g_value_init(&style_weight_value, G_TYPE_INT);
+            if(style.text_style & UI_TEXT_STYLE_BOLD) {
+                g_value_set_int(&style_weight_value, 600);
+            } else {
+                g_value_set_int(&style_weight_value, 400);
+            }
+            gtk_list_store_set_value(store, iter, soff + 1, &style_weight_value);
+            
+            GValue style_underline_value = G_VALUE_INIT;
+            g_value_init(&style_underline_value, G_TYPE_INT);
+            if(style.text_style & UI_TEXT_STYLE_UNDERLINE) {
+                g_value_set_int(&style_underline_value, PANGO_UNDERLINE_SINGLE);
+            } else {
+                g_value_set_int(&style_underline_value, PANGO_UNDERLINE_NONE);
+            }
+            gtk_list_store_set_value(store, iter, soff + 2, &style_underline_value);
+            
+            GValue style_italic_value = G_VALUE_INIT;
+            g_value_init(&style_italic_value, G_TYPE_INT);
+            if(style.text_style & UI_TEXT_STYLE_ITALIC) {
+                g_value_set_int(&style_italic_value, PANGO_STYLE_ITALIC);
+            } else {
+                g_value_set_int(&style_italic_value, PANGO_STYLE_NORMAL);
+            }
+            gtk_list_store_set_value(store, iter, soff + 3, &style_italic_value);
+            
+            GValue style_fgset_value = G_VALUE_INIT;
+            g_value_init(&style_fgset_value, G_TYPE_BOOLEAN);
+            g_value_set_boolean(&style_fgset_value, style.fg_set);
+            gtk_list_store_set_value(store, iter, soff + 4, &style_fgset_value);
+            
+            if(style.fg_set) {
+                char buf[8];
+                snprintf(buf, 8, "#%02X%02X%02X", (int)style.fg.red, (int)style.fg.green, (int)style.fg.blue);
+                
+                GValue style_fg_value = G_VALUE_INIT;
+                g_value_init(&style_fg_value, G_TYPE_STRING);
+                g_value_set_string(&style_fg_value, buf);
+                gtk_list_store_set_value(store, iter, soff + 5, &style_fg_value);
+            }
+        }
     }
 }
 
 static GtkListStore* create_list_store(UiListView *listview, UiList *list) {
     UiModel *model = listview->model;
     int columns = model->columns;
-    GType types[2*columns];
+    GType *types = calloc(columns*8, sizeof(GType));
     int c = 0;
     for(int i=0;i<columns;i++,c++) {
         switch(model->types[i]) {
@@ -873,8 +950,18 @@
             }
         }
     }
+    int s = 0;
+    for(int i=0;i<columns;i++) {
+        types[listview->style_offset+s] = G_TYPE_BOOLEAN; s++; // *-set
+        types[listview->style_offset+s] = G_TYPE_INT; s++;     // weight
+        types[listview->style_offset+s] = G_TYPE_INT; s++;     // underline
+        types[listview->style_offset+s] = G_TYPE_INT; s++;     // style
+        types[listview->style_offset+s] = G_TYPE_BOOLEAN; s++; // foreground-set
+        types[listview->style_offset+s] = G_TYPE_STRING; s++;  // foreground
+    }
     
-    GtkListStore *store = gtk_list_store_newv(c, types);
+    GtkListStore *store = gtk_list_store_newv(c+s, types);
+    free(types);
     
     if(list) {
         void *elm = list->first(list);
@@ -920,6 +1007,7 @@
     UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
     
     UiListView *listview = create_listview(obj, args);
+    listview->style_offset = 1;
     if(!args->getvalue && !args->getvalue2) {
         listview->getvalue = str_getvalue;
     }
@@ -1020,10 +1108,22 @@
     UiModel *model = args->model;
     int columns = model ? model->columns : 0;
     
+    // find the last data column index
     int addi = 0;
-    for(int i=0;i<columns;i++) {
+    int style_offset = 0;
+    int i = 0;
+    for(;i<columns;i++) {
+        if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
+            addi++;
+        }
+    }
+    style_offset = i+addi;
+    
+    // create columns and init cell renderers
+    addi = 0;
+    for(i=0;i<columns;i++) {
         GtkTreeViewColumn *column = NULL;
-        if(model->types[i] == UI_ICON_TEXT) {
+        if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
             column = gtk_tree_view_column_new();
             gtk_tree_view_column_set_title(column, model->titles[i]);
             
@@ -1037,6 +1137,19 @@
             gtk_tree_view_column_add_attribute(column, iconrenderer, "pixbuf", addi + i);
             gtk_tree_view_column_add_attribute(column, textrenderer, "text", addi + i+1);
             
+            if(args->getstyle) {
+                int soff = style_offset + i*6;
+                gtk_tree_view_column_add_attribute(column, textrenderer, "weight-set", soff);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "underline-set", soff);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "style-set", soff);
+                
+                gtk_tree_view_column_add_attribute(column, textrenderer, "weight", soff + 1);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "underline", soff + 2);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "style", soff + 3);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "foreground-set", soff + 4);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "foreground", soff + 5);
+            }
+            
             addi++;
         } else if (model->types[i] == UI_ICON) {
             GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new();
@@ -1047,13 +1160,26 @@
                 i + addi,
                 NULL);
         } else {
-            GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+            GtkCellRenderer *textrenderer = gtk_cell_renderer_text_new();
             column = gtk_tree_view_column_new_with_attributes(
                 model->titles[i],
-                renderer,
+                textrenderer,
                 "text",
                 i + addi,
                 NULL);
+            
+            if(args->getstyle) {
+                int soff = style_offset + i*6;
+                gtk_tree_view_column_add_attribute(column, textrenderer, "weight-set", soff);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "underline-set", soff);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "style-set", soff);
+                
+                gtk_tree_view_column_add_attribute(column, textrenderer, "weight", soff + 1);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "underline", soff + 2);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "style", soff + 3);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "foreground-set", soff + 4);
+                gtk_tree_view_column_add_attribute(column, textrenderer, "foreground", soff + 5);
+            }
         }
         
         int colsz = model->columnsize[i];
@@ -1083,6 +1209,7 @@
     // data changes
     UiListView *tableview = create_listview(obj, args);
     tableview->widget = view;
+    tableview->style_offset = style_offset;
     g_signal_connect(
                 view,
                 "destroy",
@@ -1218,6 +1345,7 @@
     
     UiListView *listview = create_listview(obj, args);
     listview->widget = combobox;
+    listview->style_offset = 1;
     listview->model = ui_model(obj->ctx, UI_STRING, "", -1);
     g_signal_connect(
                 combobox,
--- a/ui/gtk/list.h	Sun Aug 31 07:50:23 2025 +0200
+++ b/ui/gtk/list.h	Sun Aug 31 09:44:53 2025 +0200
@@ -60,6 +60,8 @@
     UiColData         *columns;
     PangoAttrList     *default_attributes; // TODO: remove
     PangoAttrList     *current_row_attributes;
+#else
+    int               style_offset;
 #endif
     ui_callback       onactivate;
     void              *onactivatedata;
--- a/ui/ui/toolkit.h	Sun Aug 31 07:50:23 2025 +0200
+++ b/ui/ui/toolkit.h	Sun Aug 31 09:44:53 2025 +0200
@@ -520,6 +520,7 @@
 struct UiTextStyle {
     uint32_t text_style;
     UiColor  fg;
+    UiBool   fg_set;
 };
 
 

mercurial