Applying css style to Gtk::ToolButton is not working with a selector in gtkmm - c++

I am trying to set an application wide css style in gtkmm-3.0 .This is how i initialize and load the style:
#include "MainWindow.h"
#include <string>
#include <iostream>
const std::string style = R"(
toolbutton {
border-color : #000000;
border-width : 1px;
border-radius: 0px;
}
)";
void loadStyle()
{
try
{
auto css = Gtk::CssProvider::create();
css->load_from_data(style);
Gtk::StyleContext::add_provider_for_screen(
Gdk::Screen::get_default(), css,
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
}
catch(const Gtk::CssProviderError error)
{
std::cerr << "Failed to load style:" <<error.code() << std::endl;
}
}
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv,"com.test");
loadStyle();
MainWindow window(800, 600);
window.show_all();
return app->run(window);
}
MainWindow is just a Gtk::Window that has a Gtk::Toolbar with a few Gtk::ToolButton.
But for some reason the style isn't getting applied to my ToolButton's at all. If i change my stylesheet selector to "select all elements" it get's applied to my toolbuttons:
* {
border-color : #000000;
border-width : 1px;
border-radius: 0px;
}
So i am assuming my code is correct and the selector in my stylesheet is wrong.
However the documentation says GtkToolButton has a single CSS node with name toolbutton.
I am currently not setting any names or classes myself using set_name or add_class.
What am i doing wrong?

when we create Gtktoolbutton it's actually using Gtkbutton.
so in your css if you add
toolbutton button {
it will work.
gtkcss can be kinda confusing to learn as you wont find proper documentation(well I was not able to find a very detailed doc and all).. it's better to use GtkInspector to debug gtk css..

Related

Change color of a Gtk::Entry stored in a specific variable

I am looking for a way to change the color of a Gtk::Entry that is stored in a specific variable. I am using the CSS way to specify the color of an Entry and I have found this code which changes the color of all entries in the application but this is not exactly what I am looking for:
styleContext = get_style_context();
provider = Gtk::CssProvider::create();
styleContext->add_provider_for_screen(Gdk::Screen::get_default(), provider,
GTK_STYLE_PROVIDER_PRIORITY_USER);
provider->load_from_data(".entry { background: red; }");
You can get the style context for that particular Gtk::Entry, it can look someting like:
auto style_context = entryWidget.get_style_context();
try {
auto red_background = Gtk::CssProvider::create();
red_background->load_from_data(" entry { background: red; } ");
style_context->add_provider(red_background, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
} catch (Gtk::CssProviderError& err) {
std::cerr << err.what() << "\n";
}
Sometimes it is tricky to have the style apply to the widget. If this is the case, try changing the selector from tag entry to *.
The API docs suggests it is possible use an id selector in the css and apply the css-provider to the parent Window. I have not been able to make this work.

C++ / QML interactive combo box implementation

I have two combo boxes, the data for the second one being determined by that of the first one. The number of strings in the second combo box varies from 2 to 4. If I:
select a new string in the first combo box and
the last choice is selected
in the second combo box with a longer list than the previous list of
that box,
the currentString in the second combo box remains and overrides the correct text
For instance, if I select Scubapro in the first combo box (4 options in 2nd box) and Smart in the second combo box (the 4th option), then select any other choice in the first combo box again (< 4 options in 2nd box), the entry in the second combo box remains "Smart", which is inappropriate. The correct list is, however, loaded into the 2nd combo box. Inspection of the underlying stringlist also suggests that it contains the correct data. The problem appears to be the visual updating of the second combo box. The heart of the algorithm comes from Stackoverflow and is the generator called each time text in combo box 1 changes.
What can one do to rectify this?
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QQuickView>
#include <QQuickItem>
#include <QStringListModel>
#include <QQmlContext>
#include <QDebug>
QStringList dat1, dat2, dat3;
QStringList vendorList;
class Generator : public QObject
Q_OBJECT
QStringListModel * m_model;
public:
Generator(QStringListModel * model) : m_model(model) {}
Q_INVOKABLE void generate(const QVariant & val) {
m_model->removeRows(0,m_model->rowCount()); // This has no effect
if (QString::compare(val.toString(), QString::fromStdString("Mares"), Qt::CaseInsensitive) == 0) {
m_model->setStringList(dat1);
}
else {
if (QString::compare(val.toString(), QString::fromStdString("ScubaPro"), Qt::CaseInsensitive) == 0) {
m_model->setStringList(dat2);
}
else
m_model->setStringList(dat3);
}
};
int main(int argc, char *argv[])
{
QStringListModel model1, model2;
generator(&model2);
dat1 << "Puck" << "Nemo" << "Matrix";
dat2 << "Aladin" << "Meridian" << "Galilio" << "Smart";
dat3 << "D4" << "D6";
vendorList << "Mares" << "Scubapro" << "Suunto" << "Shearwater";
model1.setStringList(vendorList);
QGuiApplication app(argc, argv);
QQuickView view;
QQmlContext *ctxt = view.rootContext();
ctxt->setContextProperty("model1", &model1);
ctxt->setContextProperty("model2", &model2);
ctxt->setContextProperty("generator", &generator);
view.setSource(QUrl("qrc:main.qml"));
view.show();
return app.exec();
}
#include "main.moc"
Here is the QML:
import QtQuick 2.0
import QtQuick.Controls 1.0
Rectangle {
width: 400; height: 300
Text { text: "Vendor"; }
Text {
x: 200
text: "Product"; }
ComboBox {
id: box2
objectName: "productBox"
x:200; y:25; width: 180
model: model2
textRole: "display"
}
ComboBox {
y:25; width: 180
id: box1
model: model1
textRole: "display"
onCurrentTextChanged: {
generator.generate(currentText)
}
}
}
Any comments are highly appreciated.
The ComboBox item does not react to changes performed under the hood to the model.
There are a couple of solutions to work around it.
A possible one is to reassign the model to itself at the end of the signal handler, by using the statement:
model = model;
As from the documentation:
Changing the model after initialization will reset currentIndex to 0.
Otherwise, you can explicitly set currentIndex to your preferred value or, even better, to -1.
In fact, from the documentation we have that:
Setting currentIndex to -1 will reset the selection and clear the text label.

Why does the Qt Stylesheet "Foo:hover * {" always apply?

I have a list of items which I want to shade the currently selected one. The problem is that the Foo widget has children and when the following rule always applies instead of just on hover:
Foo:hover {
background-color:#00FFFF;
}
Foo:hover * {
background-color:#00FFFF;
}
How do I fix this?
Your syntax is wrong. It should be like this:
Foo *::hover{ background-color: #00FFFF; }
Or if you only want to apply this to direct children:
Foo > *::hover{ background-color: #00FFFF; }

How to determine the rendered height of the lines of a Qt document

Windows 7 SP1
MSVS 2010
Qt 4.8.4
I am trying to determine what the rendered heights of each line (text block to be exact) of a Qt document are. The document has rich text, so each text block may have fragments. Assume no word wrapping so each text block is a line. To simplify things, here is what I want to do:
#include <QTGui>
int CalculateLineHeight(QTextBlock text_block);
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow* window = new QMainWindow;
QTextEdit* editor = new QTextEdit(window);
QTextDocument* text_document = new QTextDocument(window);
editor->setDocument(text_document);
QFile file("test.html");
if (file.open(QFile::ReadOnly | QFile::Text))
editor->setHtml(file.readAll());
QTextBlock text_block = text_document->begin();
while (text_block.isValid() )
{
qDebug() << text_block.text() << CalculateLineHeight(text_block);
text_block = text_block.next();
}
window->setCentralWidget(editor);
window->show();
return app.exec();
}
int CalculateLineHeight(QTextBlock text_block)
{
QList<QTextLayout::FormatRange> text_block_format_ranges;
// Gather the format ranges for each fragment of the text block.
for (QTextBlock::Iterator fragment_it = text_block.begin(); !(fragment_it.atEnd()); ++fragment_it)
{
QTextFragment fragment = fragment_it.fragment();
QTextCharFormat fragment_format = fragment.charFormat();
QTextLayout::FormatRange text_block_format_range;
text_block_format_range.format = fragment_format;
text_block_format_range.start = fragment.position();
text_block_format_range.length = fragment.length();
text_block_format_ranges << text_block_format_range;
}
// Create text layout
QTextLayout text_layout(text_block.text());
text_layout.setAdditionalFormats( text_block_format_ranges );
text_layout.beginLayout();
QTextLine line = text_layout.createLine();
text_layout.endLayout();
return text_layout.boundingRect().height();
}
This is test.html:
<!DOCTYPE html>
<html>
<head>
<style>
.consolas{
font-family: "Consolas";
font-size:14pt;
background-color: cyan;
}
.arial{
font-family: "Arial";
font-size:14pt;
background-color: cyan;
}
</style>
</head>
<body>
<p><span class="consolas">E</span></p>
<p><span class="arial">E</span></p>
<p><span class="consolas">E</span><span class="arial">E</span></p>
</body>
</html>
The window displays (with my annotations indicating the LineHeights):
But I get the following console output:
"E" 22
"E" 13
"EE" 13
So, it apparently calculates it properly on the first line, but subsequent lines it does not calculate it properly (2nd line s/b 23, 3rd s/b 24). I suspect my problem lies in how I am handling the text layouts.
This did the trick:
int CalculateLineHeight(QTextBlock text_block)
{
QList<QTextLayout::FormatRange> text_block_format_ranges;
// Gather the format ranges for each fragment of the text block.
for (QTextBlock::Iterator fragment_it = text_block.begin(); !(fragment_it.atEnd()); ++fragment_it)
{
QTextFragment fragment = fragment_it.fragment();
QTextCharFormat fragment_format = fragment.charFormat();
QTextLayout::FormatRange text_block_format_range;
text_block_format_range.format = fragment_format;
// fragment.position = position within the document whereas
// .start = position within the text block. Therefore, need
// to subtract out the text block's starting position within the document.
text_block_format_range.start = fragment.position()
- text_block.position();
text_block_format_range.length = fragment.length();
text_block_format_ranges << text_block_format_range;
}
// Create text layout
QTextLayout text_layout(text_block.text());
text_layout.setAdditionalFormats( text_block_format_ranges );
text_layout.beginLayout();
QTextLine line = text_layout.createLine();
text_layout.endLayout();
line.setLeadingIncluded(true); // Need to include the leading
return line.height();

How to set the QToolButton's icons using style sheet?

I would like to set a QToolButton's icons using style sheets, like this :
#include <QToolButton>
#include <QApplication>
QString FormStyleSheetString( const QString & name )
{
const QString thisItemStyle( "QToolButton:enabled { image: url(" + name + "_normal.png); } "
"QToolButton:pressed { image: url(" + name + "_pressed.png); } "
"QToolButton:disabled { image: url(" + name + "_disabled.png); } "
);
return thisItemStyle;
}
int main(int argc, char * argv[])
{
QApplication qapp(argc,argv);
QToolButton button;
button.setStyleSheet( FormStyleSheetString( "button" ) );
button.setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
button.setIconSize(QSize(200,200));
button.setText("some thing..." );
button.show();
return qapp.exec();
}
I compiled it like this :
g++ -O3 -std=c++0x -Wall -Wextra -pedantic test.cpp -lQtCore -lQtGui -I/usr/include/Qt/ -I/usr/include/QtCore/ -I/usr/include/QtGui/
Unfortunately, the above doesn't work (the icon is not shown).
If I use setIcon, then the icon is shown properly.
So, what am I doing wrong? How to set the button's icon using style sheet?
The images I used are :
PS Take a note that I asked similar question here, but the answer doesn't work once the text is set (the icon is all squished, and the text is not below the icon).
EDIT 1:
I also tried this function (as Kamil Klimek suggested) :
QString FormStyleSheetString( const QString & name )
{
const QString thisItemStyle( "QToolButton { qproperty-icon: url(" + name + "_normal.png); }; "
"QToolButton:pressed { qproperty-icon: url(" + name + "_pressed.png); }; "
"QToolButton:hover { qproperty-icon: url(" + name + "_disabled.png); }; "
);
return thisItemStyle;
}
but it also didn't work. Pressing the button, or hovering, doesn't change the icon.
Later that day I managed to somehow solve the problem, but forgot to post the solution :
QString FormStyleSheetString( const QString & name )
{
const QString thisItemStyle(
"QToolButton {\n"
" border: none;\n"
" background: url(" + name + "_normal.png) top center no-repeat;\n"
" padding-top: 200px;\n"
" width: 200px;\n"
" font: bold 14px;\n"
" color: red;\n"
"}\n"
"QToolButton:hover {\n"
" background: url("+name+"_hover.png) top center no-repeat;\n"
" color: blue;\n"
"}\n"
"QToolButton:pressed {\n"
" background: url("+name+"_pressed.png) top center no-repeat;\n"
" color: gray;\n}" );
return thisItemStyle;
}
It wasn't enough just to set the background. It also needed the size fixed.