I've started porting some of my gtkmm2 applications to gtkmm3 and I am not clear on the correct mechanism for changing properties such as color on a widget from within the application in response to a change of state. Here is a short example that illustrates what I am trying to achieve which is to invert the colors of the button image and the text depending on some defined state:
I create a window (Gwin) and hard-code a short CSS string that is enough to define the beginning state of the widgets at startup:
int main(int argc, char *argv[])
{
try
{
Gtk::Main *kit(new Gtk::Main(argc, argv));
GWin *dl(new GWin(sdi, argc, argv));
auto screen = dl->get_screen();
Glib::RefPtr<Gtk::CssProvider> css(Gtk::CssProvider::create());
Glib::RefPtr<Gtk::StyleContext> style(dl->get_style_context());
Glib::ustring theme(
"@define-color bg rgb(57.64%, 48.62%, 36.47%);"
"@define-color BtnBg rgb(23.13%, 19.60%, 16.07%);"
".background { background-color: @bg; }"
"button"
"{"
" background-image:image(@BtnBg);"
" border-color: @bg;"
" color: rgb(80.%, 80.%, 80.%);"
" padding-left: 4px;"
" padding-right: 4px;"
"}"
"button:hover"
"{"
" background-image:image(rgb(77%, 81%, 84%));"
" color: rgb(0.%, 0.%, 0.%);"
"}"
"#LSK0 { background-image: image(@bg); border-color:@bg }"
"#RSK0 { background-image: image(@bg); border-color:@bg }"
);
css->load_from_data(theme);
style->add_provider_for_screen(screen, css, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
dl->Run();
delete kit;
}
catch(const std::string &e)
{
std::cout << "ERROR: GWin now exits:\n" << e << std::endl;
}
return(0);
}
Now inside the GWin class, the relevant piece of code is the following signal handler that operates on the mRunButton Gtk::Button which has been initialized with mRunButton.set_name("RunButton"):
void GCDU::onBtnLight(bool on)
{
// The GTK3 code
Glib::RefPtr<Gtk::CssProvider> css(Gtk::CssProvider::create());
Glib::RefPtr<Gtk::StyleContext> style(mRunButton.get_style_context());
Glib::ustring theme(on ?
"#RunButton { background-image: image(rgb(80%, 80%, 80%); color: rgb(0.%, 0.%, 0.%); }"
:
"#RunButton { background-image: image(rgb(23.13%, 19.60%, 16.07%)); color: rgb(80.%, 80.%, 80.%); }"
);
css->load_from_data(theme);
style->add_provider(css, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
// The old GTK2 code
//Gdk::Color c(mButtonBG);
//Gdk::Color f;
//if(on)
//{
// c.set("white");
// f.set("black");
//}
//else
//{
// f.set("white");
//}
//mRunButton.modify_bg(Gtk::STATE_NORMAL, c);
//mRunButton.get_child()->modify_fg(Gtk::STATE_NORMAL, f);
}
I have searched around but most questions and their answers appear to be limited to setting the style properties once for a theme at run start or using the now deprecated override_ methods.
Thanks for looking at the question.
Well, after some more research from questions such as this and thisI found what I think is the correct way of doing what I need.
Basically define the properties for the states that the widget style will hold when adding the CSS provider to the window:
Updated from main() above in question:
Glib::ustring theme(
"@define-color bg rgb(57.64%, 48.62%, 36.47%);"
"@define-color BtnBg rgb(23.13%, 19.60%, 16.07%);"
".background { background-color: @bg; }"
"button"
"{"
" background-image:image(@BtnBg);"
" border-color: @bg;"
" color: rgb(80.%, 80.%, 80.%);"
" padding-left: 4px;"
" padding-right: 4px;"
"}"
"button:hover"
"{"
//" background-image:image(rgb(77%, 81%, 84%));"
" background-image:image(#FF4300);"
" color: rgb(100.%, 100.%, 100.%);"
"}"
"#LSK0 { background-image: image(@bg); border-color: @bg }"
"#RSK0 { background-image: image(@bg); border-color: @bg }"
".RunButton { background-image: image(rgb(80%, 80%, 80%)); color: rgb(0.%, 0.%, 0.%); }"
);
Also note that the properties for the "RunButton" style are now listed as a class (.RunButton) and NOT as an ID (#RunButton).
This added the style as a class inside the context of the window widgets but does not apply it to anything yet. Then programmatically during the execution of the code and in response to the state change event, the widget style is updated by adding and removing the style property classes:
void GWin::onBtnLight(bool on)
{
if(on)
{
mRunButton.get_style_context()->add_class("RunButton");
}
else
{
mRunButton.get_style_context()->remove_class("RunButton");
}
}
Now the button and label colors on the widget toggle between the RunButton style class and the default style class.