So I looked for a way to implement it in GTK4, then I read in here that it’s a complex functionality.
But in response to the last post in that thread, I really need to ask how I can assign and remove CSS based on some logic? There’s no option in Gtk.ColumnViewRow to add CSS, and the Gtk.ColumnView class doesn’t have background-color listed as a CSS option.
How do I make the rows with individual colours if there’s no option to do so?
Each visible cell in an Gtk.ColumnView is representated by an widget generated by an factory [1]. So, you can use the normal widget methods to add or remove CSS classes from it in code [2]. Then, you can style a cell in your application CSS stylesheet.
So, if you were, for example, using the Gtk.SignalListItemFactory to populate your grid, you would add the css classes on the bind signal activation, and remove them on the unbind signal.
I tried that too, in fact I even tried using Gtk.Box as the child widget of Gtk.ColumnViewCell:child property, and set up the AddCssClass("background-color: #FF5733"), just to test it out and make sure it works, and nope, nothing.
Looking back at the code, it seems you’ve misinterpreted what the add_css_class method [1] does.
This method is used to add a CSS class to the widget, which then can be referenced in your CSS stylesheet.
As an example:
If I were to set custom-background as a css class, I could then set the style for it using this CSS snippet:
.custom-background {
background-color: red;
}
So, you need to set a name in the method and then set the styling in your CSS stylesheet.
If you use libadwaita, adding your own stylesheet is as simple as adding a style.css to your application resources [2]. In the base GTK, I think you need to add the CSS file yourself using a Gtk.CssProvider[3].
If you want to dynamically change row colors at runtime, I think you can generate a CSS at runtime and use that. But if that is something you’re planning, I would check how applications like GNOME Text Editor accomplish this.
I tried with CssProvider.LoadFromString(), since I want to do it all at runtime without having to write an entirely new file.
private static void OnBindEventTypeText(Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args)
{
if (args.Object is not Gtk.ListItem listItem)
{
return;
}
if (listItem.Child is not Gtk.Box box) return;
if (listItem.Item is not TrackViewer userData) return;
if (box.GetFirstChild() is not Gtk.Label label) return;
if (userData._eventType is null) return;
var cssProvider = Gtk.CssProvider.New();
cssProvider.LoadFromString(
".custom-background {" +
"background-image: none;" +
"background-color: red;" +
"}"
);
box.AddCssClass("custom-background");
label.SetText(userData._eventType);
}
This doesn’t work at all. How do I use LoadFromString correctly?
I even tried using Gtk.DrawingArea as an alternative, but it doesn’t render at all in Gtk.ColumnView. Is there something blocking DrawingArea from being used in Gtk.ColumnView?
Also, it should be noted that CSS in GTK should be applied globally. So the whole CSS provider code should be in your application class, not your widget.
The only issues now is that the background color doesn’t cover the entire cell, and when the row is selected, the color still covers the highlighted selection.
private static void OnBindEventTypeText(Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args)
{
if (args.Object is not Gtk.ListItem listItem)
{
return;
}
if (listItem.Child is not Gtk.Box box) return;
if (listItem.Item is not TrackViewer userData) return;
if (box.GetFirstChild() is not Gtk.Label label) return;
if (userData._eventType is null) return;
var hexCode = $"{userData._commandColor.R:X2}{userData._commandColor.G:X2}{userData._commandColor.B:X2}".ToLower();
var eventClass = $"{userData._eventType}".ToLower().Replace(' ', '-');
var cssProvider = Gtk.CssProvider.New();
cssProvider.LoadFromString(
$".{eventClass}" + " {" +
"background-image: none;" +
$"background-color: #{hexCode};" +
"}"
);
box.AddCssClass($"{eventClass}");
Gtk.StyleContext.AddProviderForDisplay(box.GetDisplay(), cssProvider, 0);
label.SetText(userData._eventType);
}
Is there any way to fill the entire cell with the background color and disable the background color when the row is selected?
Edit: Another issue! Why does the colors get broken when there’s a lot of ColumnView entries? It’s supposed to only apply the color per-event type, but I see it applying to the wrong events (eg. Note is colored red instead of green) when scrolling all the way down when there’s a lot of entries. Here’s what I mean:
This will impact every “row” in your project, so if needed, you might want to use a class or an id on your listview/columnview, and use the child combinator to access the row child. For example :
Unfortunately, there is no way to add a class directly to a row as far as I know.
As CodedOre said, you need to put your css provider etc outside you binding function. At the time of binding, you should only add/bind your css class to the widget.