Let me preface this by saying I'm a GTK Noob and find myself parachuted into modifying someone else's code - that someone else having fled the country to greener pa$ture$.
So, we have a GTK grid of buttons which are just a coloured square, each of which can be modified on-the-fly to change colour.
At present, the program flow goes something like this;
Generate CSS containing a list of 25 button colour styles like this:
.btn_colour_id_XX{background: #336699}
.btn_colour_id_XX:active{ background: shade(#336699, 0.5) }
Then attach a style to each button based on which colour we want it to be:
GtkStyleContext *context = gtk_widget_get_style_context(button);
snprintf(value, 20, "btn_colour_id_%02d", colour_id); // Apply colour_id to button
gtk_style_context_add_class(context, value);
And display our window full of buttons.
When we get a call to modify a button colour, the code just switches the CSS style of that button to the requested one:
snprintf(desired_class, 10, "btn_colour_id_%02d", color_id); // Style we want for button
for (GList *l = classes; l != NULL; l = l->next)
{
char *classname = (char *)l->data;
if (strstr(classname, "btn_colour_id_") == NULL)
{
continue;
}
if (strlen(classname) != strlen(desired_class) || strstr(classname, desired_class) == NULL)
{
g_message("Swapping [%s] colour from %s > %s", name, classname, desired_class);
gtk_style_context_remove_class(context, (const gchar *)l->data);
gtk_style_context_add_class(context, desired_class);
}
}
However, what NEEDS to happen is to be able to set any button to any RGB colour on-the-fly, and I'm not convincted that creating 2^24 CSS styles is the optimum route for that ;)
My idea is that we instead give each button its own CSS id selector with its own RGB colour and simply modify the colour values in the CSS as required... however, I have googled myself half to death looking at GTK documentation and I can't see any obvious method by which I could modify the existing CSS and have that change reflected in the displayed buttons.
Can anyone point me in the right direction on this?
EDIT: So far I've found a couple of potential examples...
This one...
static GtkCssProvider* provider = NULL;
static void set_label_color(GtkWidget* label, const char* color)
{
const char* format = "label { color: %s; }";
size_t length = strlen(format) - 2 + 1;
char style[length];
sprintf(style, format, color);
if (provider == NULL) {
// only create and add the provider the first time
provider = gtk_css_provider_new();
gtk_style_context_add_provider(
gtk_widget_get_style_context(label),
GTK_STYLE_PROVIDER(provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref(provider);
}
gtk_css_provider_load_from_data(provider, style, -1, NULL);
}
And this one...
void set_background_color(GtkWidget *w, gchar *color)
{
GtkCssProvider *gcp;
GtkStyleContext *gsc;
gsc = gtk_widget_get_style_context(w);
const gchar *type = g_type_name (G_TYPE_FROM_INSTANCE (w));
gchar *str = g_strdup_printf ("%s {background-color: %s;}", type,
color);
gcp= gtk_css_provider_new();
gtk_css_provider_load_from_data(gcp, str, -1, 0);
g_free (str);
gtk_style_context_add_provider(gsc, GTK_STYLE_PROVIDER(gcp),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
// I don't know if there is a memory leak here though...
I also don't know for sure if there's a memory leak in either of these and whether providers are static or are destroyed / can be free()d after being added to a widget's context... the docs/examples seem vague on this, anyone got a decent tutorial on how to create/curate multiple proviers in an app?
The 1st example looks most promising to me, although it seems a bit rough to just re-write the provier over and over?
OK, I've figured it out myself - this may be totally the wrong way to do it but it works.
It involves keeping the CSS provider (rather than g_object_deref() after use) in a global context that contains info about all the buttons. Then simply over-writing the CSS provider each time, which TFM says is perfectly fine.
We have to keep the CSS provider and the ref to it as GTK seems to be missing a lot of functions to get this sort information back from an object once you've created it - you can add new, replace, and destroy/deref but you can't read the existing one back & modify it. I guess most UI's you write it once and that's it.
Context:
struct dev_button
{
GtkWidget *btn;
GtkCssProvider *bp;
};
Creating buttons:
dbp = &_context->buttons[i]; // Pointer to a dev_button struct
GtkStyleContext *context = gtk_widget_get_style_context(dbp->btn);
dbp->bp = gtk_css_provider_new();
// Create a CSS for this button
snprintf(css, LONG_STR, ".btnid_%02d{background: #%06X}", btnID, colour);
// Convert CSS to provider
gtk_css_provider_load_from_data(dbp->bp, tstr, -1, NULL);
// Add provider to button
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER(dbp->bp), GTK_STYLE_PROVIDER_PRIORITY_USER);
// Give the button the CSS style/class corresponding to the one we just created for it
snprintf(value, SHORT_STR, "btnid_%02d", buttonId); // Sets default colour from table
gtk_style_context_add_class(context, value);
Dynamically change the button's colour:
// Create new CSS
snprintf(temp_css, LONG_STR, ".btnid_%02d{background: #%06X}", btnID, new_colour);
// Re-load into provider
gtk_css_provider_load_from_data(dbp->bp, tstr, -1, NULL);
That's it, it works, and it doesn't leak memory.