Changing the colors and/or font of a Gtk.Entry

Hi –

I’m new to gtk3 and CSS and I’m not sure I’m approaching this problem in the right way. None of the things I’ve tried have worked, so I hope someone can point me in the right direction.

My program uses a bunch of Gtk.Entry’s to set parameters. Some of the parameters can either take a user supplied value or be set automatically by the program. I used to use a separate checkbox by the side of an Entry, and the automatic value would be used if the box was checked. It would be neater, though, to get rid of the checkbox and simply say that an empty Entry indicates that the automatic value should be used. To make it clear that that’s what’s happening, though, I’d like to write “automatic” in the Entry if the user hasn’t entered a value. I can catch keypress events in the Entry so it displays “automatic” when it’s empty and deletes it when the user starts typing. The problem is that “automatic” should be written in a different color, or in italics, or something, to indicate that it’s not a value entered by the user.

I can get the current foreground and background colors from the StyleContext, but how do I set new colors? Entry.override_color() is deprecated.

Can I use CSS? How would I indicate that special colors or fonts should be applied only to Entrys that are in the “automatic” state?

Should I be using pango to change the font? That seems like overkill and not easy.

Thanks for any suggestions.

– Steve

1 Like

You can add a CSS class to all those automatic entries and style them with CSS. You can add a CSS class name to a specific widget with
widget.get_style_context().add_class("automatic")

You can then target all those entries with CSS using

entry.automatic {
  color: red;
  text-decoration: underline;
  font-style: italic;
}
2 Likes

Thank you! That’s exactly what I was missing.

– Steve

As far as I know, there is no direct way to change colors based on text input. A hack you can do is, have two CSS, one for default value and one for custom value. When you detect that contents of the entry is changed (“changed” signal of Gtk.Entry), you can change the name of entry to point the valid CSS.

This is not “a hack”: it’s the recommended way to style entry widgets depending on their contents.

2 Likes

What is the recommended way to pick a color that doesn’t conflict with the theme? I wouldn’t want to set the text color to the background color, or make it look like the widget is inactive.

– Steve

There is no recommended way, because themes are entirely free to do whatever they want—including using a rainbow gradient, or a repeating image of Nyancat for selections, which means the concept of “picking a color” flawed to begin with.

You should pick the color that best suits the default GTK theme (Adwaita); if you want, you can support multiple themes, by watching the GtkSettings:gtk-theme-name property, and then choosing among a fixed set of colors.

Ok, thanks. I understand that changing style elements violates the spirit of CSS. Is there a better way to indicate that a widget is in a special state, or does that also violate the spirit of CSS?

Is it possible to find out if an entry is using italics? Turning that on and off might be more robust than changing the colors.

– Steve

That’s not really what I said. You should definitely change style elements via CSS; since the contents of a GtkEntry are not styled with CSS, this is kind of hard to do.

You add and remove style classes that you define in ancillary CSS, and that you ship with your application. Again, CSS classes do not apply to the contents of a text entry because the styling is performed by Pango, and Pango doesn’t know anything about GTK’s CSS.

I assume you mean whether it’s possible to know if the font used by the entry has been styled to use an italic font; you can use gtk_style_context_get() with the “font” property, and get the PangoFontDescription set by the theme. Whether that’s enough to discover if the font is italic or not, I leave it to you.

Personally, I think you’re overcomplicating the approach. Instead of using a GtkEntry and poking at its contents, you could use a GtkStack with a label that says “automatic”, and an entry in another page; then, if the user clicks on the label, you switch the stack page and show the entry.

I’m sorry if I don’t know the right questions to ask. That’s why I tried to explain the problem I’m really having as well as the problem I think I’m having.

I hadn’t thought about using GtkStack. I think the problem with that approach is switching back to automatic mode when the GtkEntry is emptied. I’d still need to do all the work that I’m doing now in the GtkEntry. Also, switching from the GtkLabel to the GtkEntry without losing a keystroke would mean forwarding an event generated on the GtkLabel (via a GtkEventBox?) to the GtkEntry. Is that possible?

I could just use the placeholder_text in the GtkEntry, but that doesn’t appear when the widget has focus, so it doesn’t tell the user that an empty GtkEntry is in automatic mode. Unless the GtkStack can be automatically switched between the GtkLabel and the GtkEntry, it’s functionally the same as the GtkEntry with a placeholder_text. Or am I misunderstanding your suggestion?

Thanks.

– Steve

What you want : An entry with a default text and something else if user wishes to change it.
What you can do : Make an entry, pre-fill it with the default text (using Gtk.Entry.set_text or equivalent in your language), keep a placeholder text that tells users what the default value will be used if they leave it empty.

Simple as that, don’t over-complicate it with CSS and theme. May be you can add an icon beside or label below the entry, informing users about default and over-written text. Or a tooltip can do the same. :smiley:

The placeholder text doesn’t solve the problem, because it doesn’t appear when the GtkEntry has focus. I want something that indicates that an empty widget is still in a valid state, even if the user starts typing and deletes everything.

– Steve

I’m not talking about placeholder text, I’m talking about pre-filling the entry with some text before showing it to the user. You can use a label or icon to indicate that default value will be used in case of empty entry.

The entry is initially filled with the last value that the user used for that input. Yes, a tooltip could explain that the entry could be left empty, but I like the idea of giving immediate feedback. I like the solution I have now, which displays “” in italics. It doesn’t take up any extra screen real estate, and the coding isn’t very complicated, and it ought to be clear even to a user who doesn’t read manuals (or tooltips).

Thank you for your advice, though.

– Steve

2 Likes