[SOLVED] QPalette::Link for Constraint Formulas in Property Editor (NOTE: restart required)

A forum for research and development of the user interface of FreeCAD
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
LeeF
Posts: 4
Joined: Mon Mar 11, 2019 4:22 pm

[SOLVED] QPalette::Link for Constraint Formulas in Property Editor (NOTE: restart required)

Post by LeeF »

Hello ,

Sorry if this has been mentioned I did spend some time seeing if someone else had asked this.
For newer darker style sheets that are increasingly popular, displaying constraints as qt links renders them difficult to read (on windows anyway).

Image

commenting these offenders in PropertyItem.cpp rendered the text clearer for example:

Code: Select all

        
       	else if( role == Qt::TextColorRole) {
            //if(hasExpression())
             //   return QVariant::fromValue(QApplication::palette().color(QPalette::Link));
            return QVariant();
the result is as follows:

Image

I'm under the impression that QPalette::Link is being used to signal the value is a formula? Just the brackets denoting the formula would suffice to mitigate this issue in stylesheets without some added complexity getting these to respect a stylesheet.

Thanks!
Last edited by Kunda1 on Sun Oct 02, 2022 1:43 pm, edited 2 times in total.
Reason: Added note to title thread
vocx
Veteran
Posts: 5197
Joined: Thu Oct 18, 2018 9:18 pm

Re: QPalette::Link for Constraint Formulas in Property Editor

Post by vocx »

LeeF wrote: Fri Oct 02, 2020 12:06 am ...
I'm under the impression that QPalette::Link is being used to signal the value is a formula?
...
Maybe there is a way to use a different palette for this? FreeCAD is able to load weblinks so this palette is probably used there as intended. Here it seems it was chosen just as a way to highlight the items. So if you give it a custom palette, maybe the stylesheets author can assign a suitable color for it. Do you know Qt? Maybe you can investigate this further.
Always add the important information to your posts if you need help. Also see Tutorials and Video tutorials.
To support the documentation effort, and code development, your donation is appreciated: liberapay.com/FreeCAD.
LeeF
Posts: 4
Joined: Mon Mar 11, 2019 4:22 pm

Re: QPalette::Link for Constraint Formulas in Property Editor

Post by LeeF »

Yes I imagine its possible, I know nil about Qt but it doesn't seem like a difficult task. Happy to give it a try.

I do question however the rationale since the expression in parentheses clearly denotes to the user the value is coming from a formula. I would posit removing it altogether.
LeeF
Posts: 4
Joined: Mon Mar 11, 2019 4:22 pm

Re: QPalette::Link for Constraint Formulas in Property Editor

Post by LeeF »

So you cannot set a QPalette:Link colour directly from a Qt stylesheet unfortunately. But clever folk have provided for link colors correctly in the code already using css:

Code: Select all

          QString linkcolor = QApplication::palette().color(QPalette::Link).name();
            text = QString::fromLatin1(
                    "<html><head><style type=\"text/css\">"
                    "p, li { white-space: pre-wrap; }"
                    "</style></head><body>"
                    "<p>"
                    "<a href=\"%1#%2.%3\"><span style=\" text-decoration: underline; color:%4;\">%5</span></a>"
                    "</p></body></html>"
                    )
                .arg(QLatin1String(sobj.getDocumentName().c_str()),
                     QLatin1String(sobj.getObjectName().c_str()),
                     QString::fromUtf8(sobj.getSubName().c_str()),
                     linkcolor,
                     DlgPropertyLink::formatObject(
                         owner->getDocument(), sobj.getObject(), sobj.getSubName().c_str()));
Would be nice but somewhat hacky if there was a a way to use a custom widget in the stylesheet to set the link color as the %4 string in this css
wmayer
Founder
Posts: 20243
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: QPalette::Link for Constraint Formulas in Property Editor

Post by wmayer »

Here it's suggested to hard-code the link color of the application's palette. But it isn't very elegant to have to define a color that is outside of the style sheet file.

Luckily Qt's style sheets offer a way to respect a property set to a widget. So, the qss file can contain this:

Code: Select all

QLabel[haslink="true"] {
    color: green;
}
When creating a QLabel in C++ or Python code that sets the user-defined property "haslink" to "true" and the style sheet is applied then the text is shown in green.

Code: Select all

from PySide import QtGui

m = QtGui.QLabel()
m.setProperty("haslink", "true")
m.setText("Hello")
m.setStyleSheet("QLabel[haslink='true']{color: green}")
m.show()
But the second problem is that the item of the property editor is not a widget. Thus, there is no way to directly set a color depending on a property.

So, a (bit hackish) workaround is to implement a sub-class of QLabel and re-implement its paintEvent() function. The default implementation creates an instance of QStyleOptionFrame locally which will contain the currently used text color. Now the trick to be able to access the color is that we make QStyleOptionFrame a member of the sub-class and as soon as the widget gets a paint event we get the current text color.

Code: Select all

class MyLabel(QtGui.QLabel):
  def __init__(self):
    super(MyLabel, self).__init__()
    self.opt = QtGui.QStyleOptionFrame()
  def paintEvent(self, ev):
    p = QtGui.QPainter(self)
    self.initStyleOption(self.opt)
    self.style().drawControl(QtGui.QStyle.CE_ShapedFrame, self.opt, p, self)


m=MyLabel()
m.setProperty("haslink", "true")
m.setText("Hello")
m.setStyleSheet("QLabel[haslink='true']{color: green}")
m.opt.palette.color(QtGui.QPalette.Text)
m.show()
m.opt.palette.color(QtGui.QPalette.Text)
Once we have this color we set the link color of the application's palette.
wmayer
Founder
Posts: 20243
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: QPalette::Link for Constraint Formulas in Property Editor

Post by wmayer »

This idea can be further simplified. All what needs to be done is to extend the function Application::setStyleSheet:

Code: Select all


void Application::setStyleSheet(const QString& qssFile, bool tiledBackground)
{
    Gui::MainWindow* mw = getMainWindow();
    QMdiArea* mdi = mw->findChild<QMdiArea*>();
    mdi->setProperty("showImage", tiledBackground);

    static bool init = true;
    if (init) {
        init = false;
        mw->setProperty("fc_originalLinkCoor", qApp->palette().color(QPalette::Link));
    }
    else {
        QPalette newPal(qApp->palette());
        newPal.setColor(QPalette::Link, mw->property("fc_originalLinkCoor").value<QColor>());
        qApp->setPalette(newPal);
    }


    QString current = mw->property("fc_currentStyleSheet").toString();
    mw->setProperty("fc_currentStyleSheet", qssFile);

    if (!qssFile.isEmpty() && current != qssFile) {
        // Search for stylesheet in user-defined search paths.
        // For qss they are set-up in runApplication() with the prefix "qss"
        QString prefix(QLatin1String("qss:"));

        QFile f;
        if (QFile::exists(qssFile)) {
            f.setFileName(qssFile);
        }
        else if (QFile::exists(prefix + qssFile)) {
            f.setFileName(prefix + qssFile);
        }

        if (!f.fileName().isEmpty() && f.open(QFile::ReadOnly | QFile::Text)) {
            mdi->setBackground(QBrush(Qt::NoBrush));
            QTextStream str(&f);
            qApp->setStyleSheet(str.readAll());

            ActionStyleEvent e(ActionStyleEvent::Clear);
            qApp->sendEvent(mw, &e);

            {
                QLabel l1, l2;
                l2.setProperty("haslink", QByteArray("true"));

                l1.show();
                l2.show();
                QColor text = l1.palette().color(QPalette::Text);
                QColor link = l2.palette().color(QPalette::Text);

                if (text != link) {
                    QPalette newPal(qApp->palette());
                    newPal.setColor(QPalette::Link, link);
                    qApp->setPalette(newPal);
                }
            }
        }
    }

    if (qssFile.isEmpty()) {
        if (tiledBackground) {
            qApp->setStyleSheet(QString());
            ActionStyleEvent e(ActionStyleEvent::Restore);
            qApp->sendEvent(getMainWindow(), &e);
            mdi->setBackground(QPixmap(QLatin1String("images:background.png")));
        }
        else {
            qApp->setStyleSheet(QString());
            ActionStyleEvent e(ActionStyleEvent::Restore);
            qApp->sendEvent(getMainWindow(), &e);
            mdi->setBackground(QBrush(QColor(160,160,160)));
        }
#if QT_VERSION == 0x050600 && defined(Q_OS_WIN32)
        // Under Windows the tree indicator branch gets corrupted after a while.
        // For more details see also https://bugreports.qt.io/browse/QTBUG-52230
        // and https://codereview.qt-project.org/#/c/154357/2//ALL,unified
        // A workaround for Qt 5.6.0 is to set a minimal style sheet.
        QString qss = QString::fromLatin1(
               "QTreeView::branch:closed:has-children  {\n"
               "    image: url(:/icons/style/windows_branch_closed.png);\n"
               "}\n"
               "\n"
               "QTreeView::branch:open:has-children  {\n"
               "    image: url(:/icons/style/windows_branch_open.png);\n"
               "}\n");
        qApp->setStyleSheet(qss);
#endif
    }

    // At startup time unpolish() mustn't be executed because otherwise the QSint widget
    // appear incorrect due to an outdated cache.
    // See https://doc.qt.io/qt-5/qstyle.html#unpolish-1
    // See https://forum.freecadweb.org/viewtopic.php?f=17&t=50783
    if (d->startingUp == false) {
        if (mdi->style())
            mdi->style()->unpolish(qApp);
    }
}
If a stylesheet defines

Code: Select all


QLabel[haslink="true"] {
    color: #00ff00;
}
the specified color is used to show links. If the the stylesheet doesn't define it then the default color is used.
User avatar
Kunda1
Veteran
Posts: 13434
Joined: Thu Jan 05, 2017 9:03 pm

Re: [SOLVED] QPalette::Link for Constraint Formulas in Property Editor

Post by Kunda1 »

Marked thread as [Solved]
Alone you go faster. Together we go farther
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
User avatar
MisterMaker
Posts: 740
Joined: Mon Sep 21, 2020 7:41 am

Re: [SOLVED] QPalette::Link for Constraint Formulas in Property Editor

Post by MisterMaker »

Hey, I needed this.
But this does not work properly not in 0.20.1 and in 0.21.
When I change stylesheet it set the color correctly, but as soon as I exit the settings it pops back too blue.
See: https://files.gitter.im/587a69a0d73408c ... 4IfIdI.gif
User avatar
MisterMaker
Posts: 740
Joined: Mon Sep 21, 2020 7:41 am

Re: [SOLVED] QPalette::Link for Constraint Formulas in Property Editor

Post by MisterMaker »

MisterMaker wrote: Tue Sep 20, 2022 1:18 pm Hey, I needed this.
But this does not work properly not in 0.20.1 and in 0.21.
When I change stylesheet it set the color correctly, but as soon as I exit the settings it pops back too blue.
See: https://files.gitter.im/587a69a0d73408c ... 4IfIdI.gif
Wanted to make a issue about this but after starting Freecad up and checking it, it worked.
It seems that it needs a Freecad restart to make this stick.
Btw not a single other Dark theme has this:

Code: Select all

QLabel[haslink="true"] {
  color: orange;
}
Post Reply