From c4878487ba88cbd3273f6d83e9eeddba697f0958 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Sat, 2 Oct 2021 22:15:47 -0500 Subject: [PATCH 1/8] [Gui] Add StatefulLabel --- src/Gui/Widgets.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++ src/Gui/Widgets.h | 59 +++++++++++++++++++++++++ src/Gui/resource.cpp | 1 + 3 files changed, 161 insertions(+) diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index a310905d3a..fcf1a63790 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -874,6 +874,107 @@ void UrlLabel::setUrl(const QString& u) // -------------------------------------------------------------------- +StatefulLabel::StatefulLabel(QWidget* parent) + : QLabel(parent) +{ +} + +StatefulLabel::~StatefulLabel() +{ +} + +QString StatefulLabel::state() const +{ + return _state; +} + +void StatefulLabel::setDefaultStyle(const QString& defaultStyle) +{ + _defaultStyle = defaultStyle; +} + +void StatefulLabel::registerState(const QString& state, const QString& styleCSS, + const std::string& preferenceLocation, + const std::string& preferenceName) +{ + _availableStates[state] = { QColor(), QColor(), styleCSS, preferenceLocation, preferenceName }; +} + +void StatefulLabel::registerState(const QString& state, const QColor& color, + const std::string& preferenceLocation, + const std::string& preferenceName) +{ + _availableStates[state] = {color, QColor(), QString(), preferenceLocation, preferenceName}; +} + +void StatefulLabel::registerState(const QString& state, const QColor& foreground, const QColor& background, + const std::string& preferenceLocation, + const std::string& preferenceName) +{ + _availableStates[state] = { foreground, background, QString(), preferenceLocation, preferenceName }; +} + +void StatefulLabel::setState(const QString& state) +{ + _state = state; + if (auto entry = _availableStates.find(state); entry != _availableStates.end()) { + // Order of precedence: first, check if the user has set this in their preferences: + if (!entry->second.preferenceLocation.empty() && !entry->second.preferenceString.empty()) { + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(entry->second.preferenceLocation.c_str()); + + // First, try to see if it's just stored a color (as an unsigned int): + auto availableColorPrefs = hGrp->GetUnsignedMap(); + for (const auto &unsignedEntry : availableColorPrefs) { + if (unsignedEntry.first == entry->second.preferenceString) { + // Convert the stored Uint into usable color data: + unsigned int col = unsignedEntry.second; + QColor qcolor((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff); + this->setStyleSheet(QString::fromUtf8("Gui--StatefulLabel{ color : rgba(%1,%2,%3,%4) ;}").arg(qcolor.red()).arg(qcolor.green()).arg(qcolor.blue()).arg(qcolor.alpha())); + return; + } + } + + // If not, try to see if there's an entire style string set as ASCII: + auto availableStringPrefs = hGrp->GetASCIIMap(); + for (const auto& stringEntry : availableStringPrefs) { + if (stringEntry.first == entry->second.preferenceString) { + this->setStyleSheet(QString::fromStdString(stringEntry.second)); + return; + } + } + } + + // If there is no preferences entry for this label, allow the stylesheet to set it, and only set to the default + // formatting if there is no stylesheet entry + if (styleSheet().isEmpty()) { + if (!entry->second.defaultCSS.isEmpty()) { + this->setStyleSheet(entry->second.defaultCSS); + return; + } + else { + auto fg = entry->second.foregroundColor; + auto bg = entry->second.backgroundColor; + QString colorEntries; + if (fg.isValid()) + colorEntries.append(QString::fromUtf8("color : rgba(%1,%2,%3,%4);").arg(fg.red()).arg(fg.green()).arg(fg.blue()).arg(fg.alpha())); + if (bg.isValid()) + colorEntries.append(QString::fromUtf8("background-color : rgba(%1,%2,%3,%4);").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(bg.alpha())); + std::string tempForTesting = QString::fromUtf8("Gui--StatefulLabel{ %1 }").arg(colorEntries).toStdString(); + this->setStyleSheet(QString::fromUtf8("Gui--StatefulLabel{ %1 }").arg(colorEntries)); + return; + } + } + // else the stylesheet has already set our appearance, no need to do anything + } + else { + if (styleSheet().isEmpty()) { + this->setStyleSheet(_defaultStyle); + } + } +} + +// -------------------------------------------------------------------- + /* TRANSLATOR Gui::LabelButton */ /** diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index 86baff6a51..2b7384a7e6 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -273,6 +273,65 @@ private: QString _url; }; + +/** + * A text label whose appearance can change based on a specified state. + * + * The state is an arbitrary string exposed as a Qt Property (and thus available for selection via + * a stylesheet). This is intended for things like messages to the user, where a message that is an + * "error" might be colored differently than one that is a "warning" or a "message". + * + * In order of style precedence for a given state: User preference > Stylesheet > Default + * + * @author Chris Hennes + */ +class GuiExport StatefulLabel : public QLabel +{ + Q_OBJECT + Q_PROPERTY( QString state READ state WRITE setState) + +public: + StatefulLabel(QWidget* parent = nullptr); + virtual ~StatefulLabel(); + + QString state() const; + + /** If an unrecognized state is set, use this style */ + void setDefaultStyle(const QString &defaultStyle); + + /** Register a state and its corresponding style (optionally attached to a user preference) */ + void registerState(const QString &state, const QString &styleCSS, + const std::string& preferenceLocation = std::string(), + const std::string& preferenceName = std::string()); + + /** For convenience, allow simple color-only states via QColor (optionally attached to a user preference) */ + void registerState(const QString& state, const QColor& color, + const std::string& preferenceLocation = std::string(), + const std::string& preferenceName = std::string()); + + /** For convenience, allow simple color-only states via QColor (optionally attached to a user preference) */ + void registerState(const QString& state, const QColor& foreground, const QColor &background, + const std::string& preferenceLocation = std::string(), + const std::string& preferenceName = std::string()); + +public Q_SLOTS: + void setState(const QString &state); + +private: + QString _state; + + struct StateData { + QColor foregroundColor; + QColor backgroundColor; + QString defaultCSS; + std::string preferenceLocation; + std::string preferenceString; + }; + + std::map _availableStates; + QString _defaultStyle; +}; + // ---------------------------------------------------------------------- /** diff --git a/src/Gui/resource.cpp b/src/Gui/resource.cpp index 099539a5a1..10391bffbb 100644 --- a/src/Gui/resource.cpp +++ b/src/Gui/resource.cpp @@ -111,6 +111,7 @@ WidgetFactorySupplier::WidgetFactorySupplier() new WidgetProducer; new WidgetProducer; new WidgetProducer; + new WidgetProducer; new WidgetProducer; new WidgetProducer; new WidgetProducer; From ec249a8e4dfab5237555756b134598f580071a7c Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Sat, 2 Oct 2021 22:16:43 -0500 Subject: [PATCH 2/8] [Sketcher] Migrate constraint and solver status to StatefulLabel --- src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp | 26 ++++++++-- src/Mod/Sketcher/Gui/TaskSketcherMessages.h | 4 +- src/Mod/Sketcher/Gui/TaskSketcherMessages.ui | 9 +++- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 49 +++++++++++-------- src/Mod/Sketcher/Gui/ViewProviderSketch.h | 4 +- 5 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp index 14a3b4cb21..ac9e777c56 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp @@ -59,8 +59,8 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) : this->groupLayout()->addWidget(proxy); - connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this, bp::_1)); - connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this, bp::_1)); + connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this, bp::_1, bp::_2)); + connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this, bp::_1, bp::_2)); ui->labelConstrainStatus->setOpenExternalLinks(false); @@ -72,6 +72,20 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) : else sketchView->getSketchObject()->noRecomputes=true; + // Set up the possible state values for the solver status label + const std::string paramGroup ("User parameter:BaseApp/Preferences/Mod/Sketcher"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("empty_sketch"), QColor("black"), paramGroup, "emptySketchMessageColor"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("under_constrained"), QColor("black"), paramGroup, "underconstrainedMessageColor"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("malformed_constraints"), QColor("red"), paramGroup, "malformedConstraintMessageColor"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("conflicting_constraints"), QColor("orangered"), paramGroup, "conflictingConstraintMessageColor"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("redundant_constraints"), QColor("red"), paramGroup, "redundantConstraintMessageColor"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("partially_redundant_constraints"), QColor("royalblue"), paramGroup, "partiallyRedundantConstraintMessageColor"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("fully_constrained"), QColor("green"), paramGroup, "fullyConstrainedMessageColor"); + + ui->labelSolverStatus->registerState(QString::fromUtf8("good"), QColor("green"), QColor(255, 255, 255, 50), paramGroup, "solverGoodMessageColor"); + ui->labelSolverStatus->registerState(QString::fromUtf8("bad"), QColor("red"), QColor(255, 255, 255, 50), paramGroup, "solverBadMessageColor"); + ui->labelSolverStatus->registerState(QString::fromUtf8("neutral"), QColor("black"), paramGroup, "solverNeutralMessageColor"); + /*QObject::connect( ui->labelConstrainStatus, SIGNAL(linkActivated(const QString &)), this , SLOT (on_labelConstrainStatus_linkActivated(const QString &)) @@ -92,13 +106,15 @@ TaskSketcherMessages::~TaskSketcherMessages() connectionSolved.disconnect(); } -void TaskSketcherMessages::slotSetUp(QString msg) +void TaskSketcherMessages::slotSetUp(const QString &state, const QString &msg) { + ui->labelConstrainStatus->setState(state); ui->labelConstrainStatus->setText(msg); } -void TaskSketcherMessages::slotSolved(QString msg) +void TaskSketcherMessages::slotSolved(const QString& state, const QString& msg) { + ui->labelSolverStatus->setState(state); ui->labelSolverStatus->setText(msg); } @@ -115,7 +131,7 @@ void TaskSketcherMessages::on_labelConstrainStatus_linkActivated(const QString & else if( str == QString::fromLatin1("#malformed")) Gui::Application::Instance->commandManager().runCommandByName("Sketcher_SelectMalformedConstraints"); - else + else if( str == QString::fromLatin1("#partiallyredundant")) Gui::Application::Instance->commandManager().runCommandByName("Sketcher_SelectPartiallyRedundantConstraints"); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h index 30aae3fbb0..3c2669f81a 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h @@ -47,8 +47,8 @@ public: TaskSketcherMessages(ViewProviderSketch *sketchView); ~TaskSketcherMessages(); - void slotSetUp(QString msg); - void slotSolved(QString msg); + void slotSetUp(const QString &state, const QString &msg); + void slotSolved(const QString& state, const QString &msg); private Q_SLOTS: void on_labelConstrainStatus_linkActivated(const QString &); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui b/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui index 720b2c0391..cdfd694b57 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui @@ -15,7 +15,7 @@ - + Undefined degrees of freedom @@ -25,7 +25,7 @@ - + Not solved yet @@ -94,6 +94,11 @@ QCheckBox
Gui/PrefWidgets.h
+ + Gui::StatefulLabel + QLabel +
Gui/Widgets.h
+
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 3459526a49..951fe66507 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -402,6 +402,9 @@ ViewProviderSketch::ViewProviderSketch() //rubberband selection rubberband = new Gui::Rubberband(); + // Status message states: + + subscribeToParameters(); } @@ -1309,9 +1312,9 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor if (getSketchObject()->moveTemporaryPoint(GeoId, PosId, vec, false) == 0) { setPositionText(Base::Vector2d(x,y)); draw(true,false); - signalSolved(QString::fromLatin1("Solved in %1 sec").arg(getSolvedSketch().getSolveTime())); + signalSolved(QString::fromUtf8("neutral"), QString::fromLatin1("Solved in %1 sec").arg(getSolvedSketch().getSolveTime())); } else { - signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(getSolvedSketch().getSolveTime())); + signalSolved(QString::fromUtf8("bad"), QString::fromLatin1("Unsolved (%1 sec)").arg(getSolvedSketch().getSolveTime())); //Base::Console().Log("Error solving:%d\n",ret); } } @@ -1350,9 +1353,9 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor if (getSketchObject()->moveTemporaryPoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { setPositionText(Base::Vector2d(x,y)); draw(true,false); - signalSolved(QString::fromLatin1("Solved in %1 sec").arg(getSolvedSketch().getSolveTime())); + signalSolved(QString::fromUtf8("neutral"), QString::fromLatin1("Solved in %1 sec").arg(getSolvedSketch().getSolveTime())); } else { - signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(getSolvedSketch().getSolveTime())); + signalSolved(QString::fromUtf8("bad"), QString::fromLatin1("Unsolved (%1 sec)").arg(getSolvedSketch().getSolveTime())); } } return true; @@ -6591,35 +6594,39 @@ void ViewProviderSketch::UpdateSolverInformation() bool hasMalformed = getSketchObject()->getLastHasMalformedConstraints(); if (getSketchObject()->Geometry.getSize() == 0) { - signalSetUp(tr("Empty sketch")); - signalSolved(QString()); + signalSetUp(QString::fromUtf8("empty_sketch"), tr("Empty sketch")); + signalSolved(QString::fromUtf8("neutral"), QString()); } else if (dofs < 0) { // over-constrained sketch std::string msg; SketchObject::appendConflictMsg(getSketchObject()->getLastConflicting(), msg); - signalSetUp(QString::fromLatin1("%1 %2
%3

") + signalSetUp(QString::fromUtf8("conflicting_constraints"), + QString::fromLatin1("%1 %2
%3
") .arg(tr("Over-constrained sketch")) .arg(tr("(click to select)")) .arg(QString::fromStdString(msg))); - signalSolved(QString()); + signalSolved(QString::fromUtf8("neutral"), QString()); } else if (hasMalformed) { // malformed constraints - signalSetUp(QString::fromLatin1("%1 %2
%3

") + signalSetUp(QString::fromUtf8("malformed_constraints"), + QString::fromLatin1("%1 %2
%3
") .arg(tr("Sketch contains malformed constraints")) .arg(tr("(click to select)")) .arg(appendMalformedMsg(getSketchObject()->getLastMalformedConstraints()))); - signalSolved(QString()); + signalSolved(QString::fromUtf8("neutral"), QString()); } else if (hasConflicts) { // conflicting constraints - signalSetUp(QString::fromLatin1("%1 %2
%3

") + signalSetUp(QString::fromUtf8("conflicting_constraints"), + QString::fromLatin1("%1 %2
%3
") .arg(tr("Sketch contains conflicting constraints")) .arg(tr("(click to select)")) .arg(appendConflictMsg(getSketchObject()->getLastConflicting()))); - signalSolved(QString()); + signalSolved(QString::fromUtf8("neutral"), QString()); } else { if (hasRedundancies) { // redundant constraints - signalSetUp(QString::fromLatin1("%1 %2
%3

") + signalSetUp(QString::fromUtf8("redundant_constraints"), + QString::fromLatin1("%1 %2
%3
") .arg(tr("Sketch contains redundant constraints")) .arg(tr("(click to select)")) .arg(appendRedundantMsg(getSketchObject()->getLastRedundant()))); @@ -6628,7 +6635,7 @@ void ViewProviderSketch::UpdateSolverInformation() QString partiallyRedundantString; if(hasPartiallyRedundant) { - partiallyRedundantString = QString::fromLatin1("
%1 %2
%3

") + partiallyRedundantString = QString::fromLatin1("
%1 %2
%3

") .arg(tr("Sketch contains partially redundant constraints")) .arg(tr("(click to select)")) .arg(appendPartiallyRedundantMsg(getSketchObject()->getLastPartiallyRedundant())); @@ -6641,25 +6648,27 @@ void ViewProviderSketch::UpdateSolverInformation() edit->FullyConstrained = true; if (!hasRedundancies) { - signalSetUp(QString::fromLatin1("%1 %2").arg(tr("Fully constrained sketch")).arg(partiallyRedundantString)); + signalSetUp(QString::fromUtf8("fully_constrained"), + partiallyRedundantString + tr("Fully constrained sketch")); } } else if (!hasRedundancies) { QString infoString; - if (dofs == 1) - signalSetUp(tr("Under-constrained sketch with 1 degree of freedom. %1") + signalSetUp(QString::fromUtf8("under_constrained"), + tr("Under-constrained sketch with 1 degree of freedom. %1") .arg(partiallyRedundantString)); else - signalSetUp(tr("Under-constrained sketch with %1 degrees of freedom. %2") + signalSetUp(QString::fromUtf8("under_constrained"), + tr("Under-constrained sketch with %1 degrees of freedom. %2") .arg(dofs) .arg(partiallyRedundantString)); } - signalSolved(QString::fromLatin1("%1").arg(tr("Solved in %1 sec").arg(getSketchObject()->getLastSolveTime()))); + signalSolved(QString::fromUtf8("good"), tr("Solved in %1 sec").arg(getSketchObject()->getLastSolveTime())); } else { - signalSolved(QString::fromLatin1("%1").arg(tr("Unsolved (%1 sec)").arg(getSketchObject()->getLastSolveTime()))); + signalSolved(QString::fromUtf8("bad"), tr("Unsolved (%1 sec)").arg(getSketchObject()->getLastSolveTime())); } } } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 598ff154c9..b086f1554d 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -273,9 +273,9 @@ public: /// signals if the constraints list has changed boost::signals2::signal signalConstraintsChanged; /// signals if the sketch has been set up - boost::signals2::signal signalSetUp; + boost::signals2::signal signalSetUp; /// signals if the sketch has been solved - boost::signals2::signal signalSolved; + boost::signals2::signal signalSolved; /// signals if the elements list has changed boost::signals2::signal signalElementsChanged; From 224ffe37e254259678461ac34919d99b6bc294a2 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Tue, 5 Oct 2021 23:20:29 -0500 Subject: [PATCH 3/8] [Gui] New widget supporting per-state styles The new StatefulLabel widget is designed to be customizable by optional preferences entries, Qt stylesheets, and default styles, set on a per-state basis, where "state" is a Qt property that can be changed dynamically at runtime. --- src/Gui/Widgets.cpp | 128 ++++++++++++++++++++++++++++++++------------ src/Gui/Widgets.h | 36 +++++++++---- 2 files changed, 119 insertions(+), 45 deletions(-) diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index fcf1a63790..632feb4866 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -814,6 +814,7 @@ void ColorButton::onRejected() UrlLabel::UrlLabel(QWidget * parent, Qt::WindowFlags f) : QLabel(parent, f) + , _launchExternal(true) { _url = QString::fromLatin1("http://localhost"); setToolTip(this->_url); @@ -827,6 +828,11 @@ UrlLabel::~UrlLabel() { } +void Gui::UrlLabel::setLaunchExternal(bool l) +{ + _launchExternal = l; +} + void UrlLabel::enterEvent ( QEvent * ) { setCursor(Qt::PointingHandCursor); @@ -839,26 +845,32 @@ void UrlLabel::leaveEvent ( QEvent * ) void UrlLabel::mouseReleaseEvent (QMouseEvent *) { - // The webbrowser Python module allows to start the system browser in an OS-independent way - Base::PyGILStateLocker lock; - PyObject* module = PyImport_ImportModule("webbrowser"); - if (module) { - // get the methods dictionary and search for the 'open' method - PyObject* dict = PyModule_GetDict(module); - PyObject* func = PyDict_GetItemString(dict, "open"); - if (func) { - PyObject* args = Py_BuildValue("(s)", (const char*)this->_url.toLatin1()); + if (_launchExternal) { + // The webbrowser Python module allows to start the system browser in an OS-independent way + Base::PyGILStateLocker lock; + PyObject* module = PyImport_ImportModule("webbrowser"); + if (module) { + // get the methods dictionary and search for the 'open' method + PyObject* dict = PyModule_GetDict(module); + PyObject* func = PyDict_GetItemString(dict, "open"); + if (func) { + PyObject* args = Py_BuildValue("(s)", (const char*)this->_url.toLatin1()); #if PY_VERSION_HEX < 0x03090000 - PyObject* result = PyEval_CallObject(func,args); + PyObject* result = PyEval_CallObject(func, args); #else - PyObject* result = PyObject_CallObject(func,args); + PyObject* result = PyObject_CallObject(func, args); #endif - // decrement the args and module reference - Py_XDECREF(result); - Py_DECREF(args); - Py_DECREF(module); + // decrement the args and module reference + Py_XDECREF(result); + Py_DECREF(args); + Py_DECREF(module); + } } } + else { + // Someone else will deal with it... + Q_EMIT linkClicked(_url); + } } QString UrlLabel::url() const @@ -866,6 +878,11 @@ QString UrlLabel::url() const return this->_url; } +bool Gui::UrlLabel::launchExternal() const +{ + return _launchExternal; +} + void UrlLabel::setUrl(const QString& u) { this->_url = u; @@ -877,15 +894,16 @@ void UrlLabel::setUrl(const QString& u) StatefulLabel::StatefulLabel(QWidget* parent) : QLabel(parent) { + // Always attach to the parameter group that stores the main FreeCAD stylesheet + _stylesheetGroup = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General"); + _stylesheetGroup->Attach(this); } StatefulLabel::~StatefulLabel() { -} - -QString StatefulLabel::state() const -{ - return _state; + if (_parameterGroup.isValid()) + _parameterGroup->Detach(this); + _stylesheetGroup->Detach(this); } void StatefulLabel::setDefaultStyle(const QString& defaultStyle) @@ -893,52 +911,88 @@ void StatefulLabel::setDefaultStyle(const QString& defaultStyle) _defaultStyle = defaultStyle; } +void StatefulLabel::setParameterGroup(const std::string& groupName) +{ + if (_parameterGroup.isValid()) + _parameterGroup->Detach(this); + + // Attach to the Parametergroup so we know when it changes + _parameterGroup = App::GetApplication().GetParameterGroupByPath(groupName.c_str()); + if (_parameterGroup.isValid()) + _parameterGroup->Attach(this); +} + void StatefulLabel::registerState(const QString& state, const QString& styleCSS, - const std::string& preferenceLocation, const std::string& preferenceName) { - _availableStates[state] = { QColor(), QColor(), styleCSS, preferenceLocation, preferenceName }; + _availableStates[state] = { QColor(), QColor(), styleCSS, preferenceName }; } void StatefulLabel::registerState(const QString& state, const QColor& color, - const std::string& preferenceLocation, const std::string& preferenceName) { - _availableStates[state] = {color, QColor(), QString(), preferenceLocation, preferenceName}; + _availableStates[state] = {color, QColor(), QString(), preferenceName}; } void StatefulLabel::registerState(const QString& state, const QColor& foreground, const QColor& background, const std::string& preferenceLocation, const std::string& preferenceName) { - _availableStates[state] = { foreground, background, QString(), preferenceLocation, preferenceName }; + _availableStates[state] = { foreground, background, QString(), preferenceName }; } -void StatefulLabel::setState(const QString& state) +/** Observes the parameter group and clears the cache if it changes */ +void StatefulLabel::OnChange(Base::Subject& rCaller, const char* rcReason) +{ + auto changedItem = std::string(rcReason); + if (changedItem == "StyleSheet") { + _styleCache.clear(); + } + else { + for (const auto& state : _availableStates) { + if (state.second.preferenceString == changedItem) { + _styleCache.erase(_styleCache.find(state.first)); + } + } + } +} + +void StatefulLabel::setState(QString state) { _state = state; + std::string stateIn = state.toStdString(); + + // Check the cache first: + if (auto style = _styleCache.find(_state); style != _styleCache.end()) { + auto test = style->second.toStdString(); + this->setStyleSheet(style->second); + return; + } + if (auto entry = _availableStates.find(state); entry != _availableStates.end()) { // Order of precedence: first, check if the user has set this in their preferences: - if (!entry->second.preferenceLocation.empty() && !entry->second.preferenceString.empty()) { - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(entry->second.preferenceLocation.c_str()); - + if (!entry->second.preferenceString.empty()) { // First, try to see if it's just stored a color (as an unsigned int): - auto availableColorPrefs = hGrp->GetUnsignedMap(); + auto availableColorPrefs = _parameterGroup->GetUnsignedMap(); + std::string lookingForGroup = entry->second.preferenceString; for (const auto &unsignedEntry : availableColorPrefs) { + std::string foundGroup = unsignedEntry.first; if (unsignedEntry.first == entry->second.preferenceString) { // Convert the stored Uint into usable color data: unsigned int col = unsignedEntry.second; QColor qcolor((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff); this->setStyleSheet(QString::fromUtf8("Gui--StatefulLabel{ color : rgba(%1,%2,%3,%4) ;}").arg(qcolor.red()).arg(qcolor.green()).arg(qcolor.blue()).arg(qcolor.alpha())); + _styleCache[state] = this->styleSheet(); return; } } // If not, try to see if there's an entire style string set as ASCII: - auto availableStringPrefs = hGrp->GetASCIIMap(); + auto availableStringPrefs = _parameterGroup->GetASCIIMap(); for (const auto& stringEntry : availableStringPrefs) { if (stringEntry.first == entry->second.preferenceString) { this->setStyleSheet(QString::fromStdString(stringEntry.second)); + _styleCache[state] = this->styleSheet(); return; } } @@ -946,9 +1000,10 @@ void StatefulLabel::setState(const QString& state) // If there is no preferences entry for this label, allow the stylesheet to set it, and only set to the default // formatting if there is no stylesheet entry - if (styleSheet().isEmpty()) { + if (qApp->styleSheet().isEmpty()) { if (!entry->second.defaultCSS.isEmpty()) { this->setStyleSheet(entry->second.defaultCSS); + _styleCache[state] = this->styleSheet(); return; } else { @@ -959,16 +1014,21 @@ void StatefulLabel::setState(const QString& state) colorEntries.append(QString::fromUtf8("color : rgba(%1,%2,%3,%4);").arg(fg.red()).arg(fg.green()).arg(fg.blue()).arg(fg.alpha())); if (bg.isValid()) colorEntries.append(QString::fromUtf8("background-color : rgba(%1,%2,%3,%4);").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(bg.alpha())); - std::string tempForTesting = QString::fromUtf8("Gui--StatefulLabel{ %1 }").arg(colorEntries).toStdString(); this->setStyleSheet(QString::fromUtf8("Gui--StatefulLabel{ %1 }").arg(colorEntries)); + _styleCache[state] = this->styleSheet(); return; } } - // else the stylesheet has already set our appearance, no need to do anything + // else the stylesheet sets our appearance: make sure it recalculates the appearance: + this->setStyleSheet(QString()); + this->setStyle(qApp->style()); + this->style()->unpolish(this); + this->style()->polish(this); } else { if (styleSheet().isEmpty()) { this->setStyleSheet(_defaultStyle); + _styleCache[state] = this->styleSheet(); } } } diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index 2b7384a7e6..a59ac1896c 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -36,6 +36,7 @@ #include #include #include "ExpressionBinding.h" +#include "Base/Parameter.h" namespace Gui { class PrefCheckBox; @@ -254,15 +255,21 @@ class GuiExport UrlLabel : public QLabel { Q_OBJECT Q_PROPERTY( QString url READ url WRITE setUrl) + Q_PROPERTY( bool launchExternal READ launchExternal WRITE setLaunchExternal) public: UrlLabel ( QWidget * parent = 0, Qt::WindowFlags f = Qt::WindowFlags() ); virtual ~UrlLabel(); QString url() const; + bool launchExternal() const; + +Q_SIGNALS: + void linkClicked(QString url); public Q_SLOTS: void setUrl( const QString &u ); + void setLaunchExternal(bool l); protected: void enterEvent ( QEvent * ); @@ -271,6 +278,7 @@ protected: private: QString _url; + bool _launchExternal; }; @@ -285,50 +293,56 @@ private: * * @author Chris Hennes */ -class GuiExport StatefulLabel : public QLabel +class GuiExport StatefulLabel : public QLabel, public Base::Observer { Q_OBJECT - Q_PROPERTY( QString state READ state WRITE setState) + Q_PROPERTY( QString state MEMBER _state WRITE setState ) public: StatefulLabel(QWidget* parent = nullptr); virtual ~StatefulLabel(); - QString state() const; - /** If an unrecognized state is set, use this style */ void setDefaultStyle(const QString &defaultStyle); + /** If any of the states have user preferences associated with them, this sets the parameter + group that stores those preferences. All states must be in the same parameter group, but + the group does not have to have entries for all of them. */ + void setParameterGroup(const std::string& groupName); + /** Register a state and its corresponding style (optionally attached to a user preference) */ void registerState(const QString &state, const QString &styleCSS, - const std::string& preferenceLocation = std::string(), const std::string& preferenceName = std::string()); /** For convenience, allow simple color-only states via QColor (optionally attached to a user preference) */ void registerState(const QString& state, const QColor& color, - const std::string& preferenceLocation = std::string(), const std::string& preferenceName = std::string()); /** For convenience, allow simple color-only states via QColor (optionally attached to a user preference) */ void registerState(const QString& state, const QColor& foreground, const QColor &background, - const std::string& preferenceLocation = std::string(), - const std::string& preferenceName = std::string()); + const std::string& foregroundPreference = std::string(), + const std::string& backgroundPreference = std::string()); + + /** Observes the parameter group and clears the cache if it changes */ + void OnChange(Base::Subject& rCaller, const char* rcReason); public Q_SLOTS: - void setState(const QString &state); + void setState(QString state); private: QString _state; + ParameterGrp::handle _parameterGroup; + ParameterGrp::handle _stylesheetGroup; struct StateData { QColor foregroundColor; QColor backgroundColor; QString defaultCSS; - std::string preferenceLocation; std::string preferenceString; }; - + std::map _availableStates; + std::map _styleCache; QString _defaultStyle; }; From f2a073ca5a36559ef41184ddf4da17d5a8334ac2 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Tue, 5 Oct 2021 23:24:09 -0500 Subject: [PATCH 4/8] [Sketcher] Make status message styleable Reduce the size and verbosity of the solver and constraint status messages, and make them styleable both via stylesheets and user preferences. --- src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp | 43 +++--- src/Mod/Sketcher/Gui/TaskSketcherMessages.h | 6 +- src/Mod/Sketcher/Gui/TaskSketcherMessages.ui | 62 +++++--- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 136 ++++++++---------- src/Mod/Sketcher/Gui/ViewProviderSketch.h | 4 +- 5 files changed, 121 insertions(+), 130 deletions(-) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp index ac9e777c56..85bf3d7e0f 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp @@ -59,8 +59,7 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) : this->groupLayout()->addWidget(proxy); - connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this, bp::_1, bp::_2)); - connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this, bp::_1, bp::_2)); + connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this, bp::_1, bp::_2, bp::_3, bp::_4)); ui->labelConstrainStatus->setOpenExternalLinks(false); @@ -72,19 +71,22 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) : else sketchView->getSketchObject()->noRecomputes=true; - // Set up the possible state values for the solver status label - const std::string paramGroup ("User parameter:BaseApp/Preferences/Mod/Sketcher"); - ui->labelConstrainStatus->registerState(QString::fromUtf8("empty_sketch"), QColor("black"), paramGroup, "emptySketchMessageColor"); - ui->labelConstrainStatus->registerState(QString::fromUtf8("under_constrained"), QColor("black"), paramGroup, "underconstrainedMessageColor"); - ui->labelConstrainStatus->registerState(QString::fromUtf8("malformed_constraints"), QColor("red"), paramGroup, "malformedConstraintMessageColor"); - ui->labelConstrainStatus->registerState(QString::fromUtf8("conflicting_constraints"), QColor("orangered"), paramGroup, "conflictingConstraintMessageColor"); - ui->labelConstrainStatus->registerState(QString::fromUtf8("redundant_constraints"), QColor("red"), paramGroup, "redundantConstraintMessageColor"); - ui->labelConstrainStatus->registerState(QString::fromUtf8("partially_redundant_constraints"), QColor("royalblue"), paramGroup, "partiallyRedundantConstraintMessageColor"); - ui->labelConstrainStatus->registerState(QString::fromUtf8("fully_constrained"), QColor("green"), paramGroup, "fullyConstrainedMessageColor"); + // Set up the possible state values for the status label + ui->labelConstrainStatus->setParameterGroup("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); + ui->labelConstrainStatus->registerState(QString::fromUtf8("empty_sketch"), QColor("black"), std::string("EmptySketchMessageColor")); + ui->labelConstrainStatus->registerState(QString::fromUtf8("under_constrained"), QColor("black"), std::string("UnderconstrainedMessageColor")); + ui->labelConstrainStatus->registerState(QString::fromUtf8("malformed_constraints"), QColor("red"), std::string("MalformedConstraintMessageColor")); + ui->labelConstrainStatus->registerState(QString::fromUtf8("conflicting_constraints"), QColor("orangered"), std::string("ConflictingConstraintMessageColor")); + ui->labelConstrainStatus->registerState(QString::fromUtf8("redundant_constraints"), QColor("red"), std::string("RedundantConstraintMessageColor")); + ui->labelConstrainStatus->registerState(QString::fromUtf8("partially_redundant_constraints"), QColor("royalblue"), std::string("PartiallyRedundantConstraintMessageColor")); + ui->labelConstrainStatus->registerState(QString::fromUtf8("solver_failed"), QColor("red"), std::string("SolverFailedMessageColor")); + ui->labelConstrainStatus->registerState(QString::fromUtf8("fully_constrained"), QColor("green"), std::string("FullyConstrainedMessageColor")); - ui->labelSolverStatus->registerState(QString::fromUtf8("good"), QColor("green"), QColor(255, 255, 255, 50), paramGroup, "solverGoodMessageColor"); - ui->labelSolverStatus->registerState(QString::fromUtf8("bad"), QColor("red"), QColor(255, 255, 255, 50), paramGroup, "solverBadMessageColor"); - ui->labelSolverStatus->registerState(QString::fromUtf8("neutral"), QColor("black"), paramGroup, "solverNeutralMessageColor"); + ui->labelConstrainStatusLink->setLaunchExternal(false); + + // Manually connect the link since it uses "clicked()", which labels don't have natively + connect(ui->labelConstrainStatusLink, &Gui::UrlLabel::linkClicked, + this, &TaskSketcherMessages::on_labelConstrainStatusLink_linkClicked); /*QObject::connect( ui->labelConstrainStatus, SIGNAL(linkActivated(const QString &)), @@ -103,22 +105,17 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) : TaskSketcherMessages::~TaskSketcherMessages() { connectionSetUp.disconnect(); - connectionSolved.disconnect(); } -void TaskSketcherMessages::slotSetUp(const QString &state, const QString &msg) +void TaskSketcherMessages::slotSetUp(const QString& state, const QString& msg, const QString& link, const QString& linkText) { ui->labelConstrainStatus->setState(state); ui->labelConstrainStatus->setText(msg); + ui->labelConstrainStatusLink->setUrl(link); + ui->labelConstrainStatusLink->setText(linkText); } -void TaskSketcherMessages::slotSolved(const QString& state, const QString& msg) -{ - ui->labelSolverStatus->setState(state); - ui->labelSolverStatus->setText(msg); -} - -void TaskSketcherMessages::on_labelConstrainStatus_linkActivated(const QString &str) +void TaskSketcherMessages::on_labelConstrainStatusLink_linkClicked(const QString &str) { if( str == QString::fromLatin1("#conflicting")) Gui::Application::Instance->commandManager().runCommandByName("Sketcher_SelectConflictingConstraints"); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h index 3c2669f81a..300059c905 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h @@ -47,11 +47,10 @@ public: TaskSketcherMessages(ViewProviderSketch *sketchView); ~TaskSketcherMessages(); - void slotSetUp(const QString &state, const QString &msg); - void slotSolved(const QString& state, const QString &msg); + void slotSetUp(const QString &state, const QString &msg, const QString& link, const QString& linkText); private Q_SLOTS: - void on_labelConstrainStatus_linkActivated(const QString &); + void on_labelConstrainStatusLink_linkClicked(const QString &); void on_autoUpdate_stateChanged(int state); void on_autoRemoveRedundants_stateChanged(int state); void on_manualUpdate_clicked(bool checked); @@ -59,7 +58,6 @@ private Q_SLOTS: protected: ViewProviderSketch *sketchView; Connection connectionSetUp; - Connection connectionSolved; private: QWidget* proxy; diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui b/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui index cdfd694b57..8c95744c99 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.ui @@ -15,24 +15,35 @@ - - - Undefined degrees of freedom - - - true - - - - - - - Not solved yet - - - true - - + + + + + DOF + + + + + + + Link + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -94,11 +105,16 @@ QCheckBox
Gui/PrefWidgets.h
- - Gui::StatefulLabel - QLabel -
Gui/Widgets.h
-
+ + Gui::StatefulLabel + QLabel +
Gui/Widgets.h
+
+ + Gui::UrlLabel + QLabel +
Gui/Widgets.h
+
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 951fe66507..a63a7bf104 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -1312,10 +1312,6 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor if (getSketchObject()->moveTemporaryPoint(GeoId, PosId, vec, false) == 0) { setPositionText(Base::Vector2d(x,y)); draw(true,false); - signalSolved(QString::fromUtf8("neutral"), QString::fromLatin1("Solved in %1 sec").arg(getSolvedSketch().getSolveTime())); - } else { - signalSolved(QString::fromUtf8("bad"), QString::fromLatin1("Unsolved (%1 sec)").arg(getSolvedSketch().getSolveTime())); - //Base::Console().Log("Error solving:%d\n",ret); } } } @@ -1353,9 +1349,6 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor if (getSketchObject()->moveTemporaryPoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { setPositionText(Base::Vector2d(x,y)); draw(true,false); - signalSolved(QString::fromUtf8("neutral"), QString::fromLatin1("Solved in %1 sec").arg(getSolvedSketch().getSolveTime())); - } else { - signalSolved(QString::fromUtf8("bad"), QString::fromLatin1("Unsolved (%1 sec)").arg(getSolvedSketch().getSolveTime())); } } return true; @@ -6584,6 +6577,29 @@ QString ViewProviderSketch::appendConstraintMsg(const QString & singularmsg, return msg; } +inline QString intListHelper(const std::vector &ints) +{ + QString results; + if (ints.size() < 8) { // The 8 is a bit heuristic... more than that and we shift formats + for (const auto i : ints) { + if (results.isEmpty()) + results.append(QString::fromUtf8("%1").arg(i)); + else + results.append(QString::fromUtf8(", %1").arg(i)); + } + } + else { + const int numToShow = 3; + int more = ints.size() - numToShow; + for (int i = 0; i < numToShow; ++i) { + results.append(QString::fromUtf8("%1, ").arg(ints[i])); + } + results.append(QCoreApplication::translate("ViewProviderSketch","and %1 more").arg(more)); + } + std::string testString = results.toStdString(); + return results; +} + void ViewProviderSketch::UpdateSolverInformation() { // Updates Solver Information with the Last solver execution at SketchObject level @@ -6594,82 +6610,48 @@ void ViewProviderSketch::UpdateSolverInformation() bool hasMalformed = getSketchObject()->getLastHasMalformedConstraints(); if (getSketchObject()->Geometry.getSize() == 0) { - signalSetUp(QString::fromUtf8("empty_sketch"), tr("Empty sketch")); - signalSolved(QString::fromUtf8("neutral"), QString()); + signalSetUp(QString::fromUtf8("empty_sketch"), tr("Empty sketch"), QString(), QString()); } - else if (dofs < 0) { // over-constrained sketch - std::string msg; - SketchObject::appendConflictMsg(getSketchObject()->getLastConflicting(), msg); - signalSetUp(QString::fromUtf8("conflicting_constraints"), - QString::fromLatin1("%1 %2
%3
") - .arg(tr("Over-constrained sketch")) - .arg(tr("(click to select)")) - .arg(QString::fromStdString(msg))); - signalSolved(QString::fromUtf8("neutral"), QString()); + else if (dofs < 0 || hasConflicts) { // over-constrained sketch + signalSetUp(QString::fromUtf8("conflicting_constraints"), + tr("Over-constrained: "), + QString::fromUtf8("#conflicting"), + QString::fromUtf8("(%1)").arg(intListHelper(getSketchObject()->getLastConflicting()))); } else if (hasMalformed) { // malformed constraints - signalSetUp(QString::fromUtf8("malformed_constraints"), - QString::fromLatin1("%1 %2
%3
") - .arg(tr("Sketch contains malformed constraints")) - .arg(tr("(click to select)")) - .arg(appendMalformedMsg(getSketchObject()->getLastMalformedConstraints()))); - signalSolved(QString::fromUtf8("neutral"), QString()); + signalSetUp(QString::fromUtf8("malformed_constraints"), + tr("Malformed constraints: "), + QString::fromUtf8("#malformed"), + QString::fromUtf8("(%1)").arg(intListHelper(getSketchObject()->getLastMalformedConstraints()))); } - else if (hasConflicts) { // conflicting constraints - signalSetUp(QString::fromUtf8("conflicting_constraints"), - QString::fromLatin1("%1 %2
%3
") - .arg(tr("Sketch contains conflicting constraints")) - .arg(tr("(click to select)")) - .arg(appendConflictMsg(getSketchObject()->getLastConflicting()))); - signalSolved(QString::fromUtf8("neutral"), QString()); + else if (hasRedundancies) { + signalSetUp(QString::fromUtf8("redundant_constraints"), + tr("Redundant constraints:"), + QString::fromUtf8("#redundant"), + QString::fromUtf8("(%1)").arg(intListHelper(getSketchObject()->getLastRedundant()))); + } + else if (hasPartiallyRedundant) { + signalSetUp(QString::fromUtf8("partially_redundant_constraints"), + tr("Partially redundant:"), + QString::fromUtf8("#partiallyredundant"), + QString::fromUtf8("(%1)").arg(intListHelper(getSketchObject()->getLastPartiallyRedundant()))); + } + else if (getSketchObject()->getLastSolverStatus() != 0) { + signalSetUp(QString::fromUtf8("solver_failed"), + tr("Solver failed to converge"), + QString::fromUtf8(""), + QString::fromUtf8("")); + } else if (dofs > 0) { + signalSetUp(QString::fromUtf8("under_constrained"), + tr("Under constrained:"), + QString::fromUtf8("#dofs"), + QString::fromUtf8("%1 %2").arg(dofs).arg(tr("DoF"))); } else { - if (hasRedundancies) { // redundant constraints - signalSetUp(QString::fromUtf8("redundant_constraints"), - QString::fromLatin1("%1 %2
%3
") - .arg(tr("Sketch contains redundant constraints")) - .arg(tr("(click to select)")) - .arg(appendRedundantMsg(getSketchObject()->getLastRedundant()))); - } - - QString partiallyRedundantString; - - if(hasPartiallyRedundant) { - partiallyRedundantString = QString::fromLatin1("
%1 %2
%3

") - .arg(tr("Sketch contains partially redundant constraints")) - .arg(tr("(click to select)")) - .arg(appendPartiallyRedundantMsg(getSketchObject()->getLastPartiallyRedundant())); - } - - if (getSketchObject()->getLastSolverStatus() == 0) { - if (dofs == 0) { - // color the sketch as fully constrained if it has geometry (other than the axes) - if(getSolvedSketch().getGeometrySize()>2) - edit->FullyConstrained = true; - - if (!hasRedundancies) { - signalSetUp(QString::fromUtf8("fully_constrained"), - partiallyRedundantString + tr("Fully constrained sketch")); - } - } - else if (!hasRedundancies) { - QString infoString; - if (dofs == 1) - signalSetUp(QString::fromUtf8("under_constrained"), - tr("Under-constrained sketch with 1 degree of freedom. %1") - .arg(partiallyRedundantString)); - else - signalSetUp(QString::fromUtf8("under_constrained"), - tr("Under-constrained sketch with %1 degrees of freedom. %2") - .arg(dofs) - .arg(partiallyRedundantString)); - } - - signalSolved(QString::fromUtf8("good"), tr("Solved in %1 sec").arg(getSketchObject()->getLastSolveTime())); - } - else { - signalSolved(QString::fromUtf8("bad"), tr("Unsolved (%1 sec)").arg(getSketchObject()->getLastSolveTime())); - } + signalSetUp(QString::fromUtf8("fully_constrained"), tr("Fully constrained"), QString(), QString()); + // color the sketch as fully constrained if it has geometry (other than the axes) + if(getSolvedSketch().getGeometrySize()>2) + edit->FullyConstrained = true; } } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index b086f1554d..fabb68c1ea 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -273,9 +273,7 @@ public: /// signals if the constraints list has changed boost::signals2::signal signalConstraintsChanged; /// signals if the sketch has been set up - boost::signals2::signal signalSetUp; - /// signals if the sketch has been solved - boost::signals2::signal signalSolved; + boost::signals2::signal signalSetUp; /// signals if the elements list has changed boost::signals2::signal signalElementsChanged; From 4154bdd1581e501739e1b1aac6fe85a804b7823a Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Tue, 5 Oct 2021 23:25:20 -0500 Subject: [PATCH 5/8] [Stylesheet] Add styling for Sketcher labels With Sketcher's constraint status label now exposed to stylesheet control on a per-state basis, add basic styling that is more visible in this dark stylesheet. --- src/Gui/Stylesheets/Behave-dark.qss | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Gui/Stylesheets/Behave-dark.qss b/src/Gui/Stylesheets/Behave-dark.qss index da1db23fc5..411734083e 100644 --- a/src/Gui/Stylesheets/Behave-dark.qss +++ b/src/Gui/Stylesheets/Behave-dark.qss @@ -2276,3 +2276,34 @@ QPushButton#NavigationIndicator::menu-indicator { image: none; width: 0px; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,50,50,255); +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,50,50,255); +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,0,100,255); +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(255,25,100,255); +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); + font-weight: bold; +} \ No newline at end of file From 6858d938cc6b0899fb3e55e55d29875a203fd4fe Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Wed, 6 Oct 2021 11:43:06 -0500 Subject: [PATCH 6/8] [Gui] Add ability for stylesheet to override prefs --- src/Gui/Widgets.cpp | 13 ++++++++++++- src/Gui/Widgets.h | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index 632feb4866..2db9575fd1 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -893,6 +893,7 @@ void UrlLabel::setUrl(const QString& u) StatefulLabel::StatefulLabel(QWidget* parent) : QLabel(parent) + , _overridePreference(false) { // Always attach to the parameter group that stores the main FreeCAD stylesheet _stylesheetGroup = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General"); @@ -957,10 +958,20 @@ void StatefulLabel::OnChange(Base::Subject& rCaller, const char* rc } } +void StatefulLabel::setOverridePreference(bool overridePreference) +{ + _overridePreference = overridePreference; +} + void StatefulLabel::setState(QString state) { _state = state; - std::string stateIn = state.toStdString(); + this->ensurePolished(); + + // If the stylesheet insists, ignore all other logic and let it do its thing. This + // property is *only* set by the stylesheet. + if (_overridePreference) + return; // Check the cache first: if (auto style = _styleCache.find(_state); style != _styleCache.end()) { diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index a59ac1896c..93e9d22bd1 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -290,12 +290,27 @@ private: * "error" might be colored differently than one that is a "warning" or a "message". * * In order of style precedence for a given state: User preference > Stylesheet > Default + * unless the stylesheet sets the overridePreference, in which case the stylesheet will + * take precedence. If a stylesheet sets styles for this widgets states, it should also + * set the "handledByStyle" property to ensure the style values are used, rather than the + * defaults. + * + * For example, the .qss might contain: + * Gui--StatefulLabel { + * qproperty-overridePreference: true; + * } + * Gui--StatefulLabel[state="special_state"] { + * color: red; + * } + * In this case, StatefulLabels with state "special_state" will be colored red, regardless of any + * entry in preferences. Use the "overridePreference" stylesheet option with care! * * @author Chris Hennes */ class GuiExport StatefulLabel : public QLabel, public Base::Observer { Q_OBJECT + Q_PROPERTY( bool overridePreference MEMBER _overridePreference WRITE setOverridePreference) Q_PROPERTY( QString state MEMBER _state WRITE setState ) public: @@ -328,9 +343,11 @@ public: public Q_SLOTS: void setState(QString state); + void setOverridePreference(bool overridePreference); private: QString _state; + bool _overridePreference; ParameterGrp::handle _parameterGroup; ParameterGrp::handle _stylesheetGroup; From 23622c8e08283e05d77c4c3f4563698c3bb5bf57 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Tue, 12 Oct 2021 11:23:13 -0500 Subject: [PATCH 7/8] [Gui] Refactor StatefulLabel coloring --- src/Gui/Widgets.cpp | 47 ++++++++++++++++++++------------------------- src/Gui/Widgets.h | 7 ++----- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index ca752a5194..cf59f11167 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -854,12 +854,11 @@ void Gui::UrlLabel::setLaunchExternal(bool l) void UrlLabel::mouseReleaseEvent(QMouseEvent*) { - if (_launchExternal) { + if (_launchExternal) QDesktopServices::openUrl(this->_url); - else { + else // Someone else will deal with it... Q_EMIT linkClicked(_url); - } } QString UrlLabel::url() const @@ -915,25 +914,34 @@ void StatefulLabel::setParameterGroup(const std::string& groupName) void StatefulLabel::registerState(const QString& state, const QString& styleCSS, const std::string& preferenceName) { - _availableStates[state] = { QColor(), QColor(), styleCSS, preferenceName }; + _availableStates[state] = { styleCSS, preferenceName }; } void StatefulLabel::registerState(const QString& state, const QColor& color, const std::string& preferenceName) { - _availableStates[state] = {color, QColor(), QString(), preferenceName}; + QString css; + if (color.isValid()) + css = QString::fromUtf8("Gui--StatefulLabel{ color : rgba(%1,%2,%3,%4) ;}").arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()); + _availableStates[state] = { css, preferenceName }; } -void StatefulLabel::registerState(const QString& state, const QColor& foreground, const QColor& background, - const std::string& preferenceLocation, +void StatefulLabel::registerState(const QString& state, const QColor& fg, const QColor& bg, const std::string& preferenceName) { - _availableStates[state] = { foreground, background, QString(), preferenceName }; + QString colorEntries; + if (fg.isValid()) + colorEntries.append(QString::fromUtf8("color : rgba(%1,%2,%3,%4);").arg(fg.red()).arg(fg.green()).arg(fg.blue()).arg(fg.alpha())); + if (bg.isValid()) + colorEntries.append(QString::fromUtf8("background-color : rgba(%1,%2,%3,%4);").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(bg.alpha())); + QString css = QString::fromUtf8("Gui--StatefulLabel{ %1 }").arg(colorEntries); + _availableStates[state] = { css, preferenceName }; } /** Observes the parameter group and clears the cache if it changes */ void StatefulLabel::OnChange(Base::Subject& rCaller, const char* rcReason) { + Q_UNUSED(rCaller); auto changedItem = std::string(rcReason); if (changedItem == "StyleSheet") { _styleCache.clear(); @@ -991,7 +999,8 @@ void StatefulLabel::setState(QString state) auto availableStringPrefs = _parameterGroup->GetASCIIMap(); for (const auto& stringEntry : availableStringPrefs) { if (stringEntry.first == entry->second.preferenceString) { - this->setStyleSheet(QString::fromStdString(stringEntry.second)); + QString css = QString::fromUtf8("Gui--StatefulLabel{ %1 }").arg(QString::fromStdString(stringEntry.second)); + this->setStyleSheet(css); _styleCache[state] = this->styleSheet(); return; } @@ -1001,23 +1010,9 @@ void StatefulLabel::setState(QString state) // If there is no preferences entry for this label, allow the stylesheet to set it, and only set to the default // formatting if there is no stylesheet entry if (qApp->styleSheet().isEmpty()) { - if (!entry->second.defaultCSS.isEmpty()) { - this->setStyleSheet(entry->second.defaultCSS); - _styleCache[state] = this->styleSheet(); - return; - } - else { - auto fg = entry->second.foregroundColor; - auto bg = entry->second.backgroundColor; - QString colorEntries; - if (fg.isValid()) - colorEntries.append(QString::fromUtf8("color : rgba(%1,%2,%3,%4);").arg(fg.red()).arg(fg.green()).arg(fg.blue()).arg(fg.alpha())); - if (bg.isValid()) - colorEntries.append(QString::fromUtf8("background-color : rgba(%1,%2,%3,%4);").arg(bg.red()).arg(bg.green()).arg(bg.blue()).arg(bg.alpha())); - this->setStyleSheet(QString::fromUtf8("Gui--StatefulLabel{ %1 }").arg(colorEntries)); - _styleCache[state] = this->styleSheet(); - return; - } + this->setStyleSheet(entry->second.defaultCSS); + _styleCache[state] = this->styleSheet(); + return; } // else the stylesheet sets our appearance: make sure it recalculates the appearance: this->setStyleSheet(QString()); diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index cc8760d81f..c4064eb50e 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -336,9 +336,8 @@ public: const std::string& preferenceName = std::string()); /** For convenience, allow simple color-only states via QColor (optionally attached to a user preference) */ - void registerState(const QString& state, const QColor& foreground, const QColor &background, - const std::string& foregroundPreference = std::string(), - const std::string& backgroundPreference = std::string()); + void registerState(const QString& state, const QColor& foregroundColor, const QColor& backgroundColor, + const std::string& preferenceName = std::string()); /** Observes the parameter group and clears the cache if it changes */ void OnChange(Base::Subject& rCaller, const char* rcReason); @@ -354,8 +353,6 @@ private: ParameterGrp::handle _stylesheetGroup; struct StateData { - QColor foregroundColor; - QColor backgroundColor; QString defaultCSS; std::string preferenceString; }; From dc3583e5dffb4139773bcf16e55e96392e4e7eb2 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Tue, 12 Oct 2021 11:23:53 -0500 Subject: [PATCH 8/8] [Stylesheets] Add StatefulLabel and UrlLabel styles --- src/Gui/Stylesheets/Behave-dark.qss | 22 +++++++++------- src/Gui/Stylesheets/Dark-blue.qss | 36 +++++++++++++++++++++++++++ src/Gui/Stylesheets/Dark-contrast.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/Dark-green.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/Dark-orange.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/Darker-blue.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/Darker-green.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/Darker-orange.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/Light-blue.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/Light-green.qss | 36 +++++++++++++++++++++++++++ src/Gui/Stylesheets/Light-orange.qss | 35 ++++++++++++++++++++++++++ src/Gui/Stylesheets/ProDark.qss | 31 +++++++++++++++++++++++ 12 files changed, 396 insertions(+), 9 deletions(-) diff --git a/src/Gui/Stylesheets/Behave-dark.qss b/src/Gui/Stylesheets/Behave-dark.qss index 411734083e..5c4e3e4da0 100644 --- a/src/Gui/Stylesheets/Behave-dark.qss +++ b/src/Gui/Stylesheets/Behave-dark.qss @@ -2282,28 +2282,32 @@ SKETCHER ==================================================================================================*/ Gui--StatefulLabel[state="empty_sketch"] { - color : rgba(255,255,255,127); + color : rgba(255,255,255,127); /* 50% opacity white */ } Gui--StatefulLabel[state="under_constrained"] { - color : rgba(255,255,255,255); + color : rgba(255,255,255,255); /* White */ } Gui--StatefulLabel[state="conflicting_constraints"] { - color : rgba(255,50,50,255); + color : rgba(255,0,0,255); /* Red */ } Gui--StatefulLabel[state="malformed_constraints"] { - color : rgba(255,50,50,255); + color : rgba(255,0,0,255); /* Red */ } Gui--StatefulLabel[state="redundant_constraints"] { - color : rgba(255,0,100,255); + color : rgba(255,69,0,255); /* Orange red */ } Gui--StatefulLabel[state="partially_redundant_constraints"] { - color : rgba(255,25,100,255); + color : rgba(65,105,225,255); /* Royal blue */ } Gui--StatefulLabel[state="solver_failed"] { - color : rgba(255,0,0,255); + color : rgba(255,0,0,255); /* Red */ font-weight: bold; } Gui--StatefulLabel[state="fully_constrained"] { - color : rgba(0,255,0,255); + color : rgba(0,255,0,255); /* Green */ font-weight: bold; -} \ No newline at end of file +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Dark-blue.qss b/src/Gui/Stylesheets/Dark-blue.qss index 32c2c0f3d1..22e24d6864 100644 --- a/src/Gui/Stylesheets/Dark-blue.qss +++ b/src/Gui/Stylesheets/Dark-blue.qss @@ -2243,3 +2243,39 @@ QPushButton#NavigationIndicator::menu-indicator { image: none; width: 0px; } + + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Dark-contrast.qss b/src/Gui/Stylesheets/Dark-contrast.qss index a60202a669..bbb69eca74 100644 --- a/src/Gui/Stylesheets/Dark-contrast.qss +++ b/src/Gui/Stylesheets/Dark-contrast.qss @@ -2269,3 +2269,38 @@ QToolBar QToolButton[popupMode="1"] { width: 100px; background: red; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Dark-green.qss b/src/Gui/Stylesheets/Dark-green.qss index 7b49d5bcd0..82e972b618 100644 --- a/src/Gui/Stylesheets/Dark-green.qss +++ b/src/Gui/Stylesheets/Dark-green.qss @@ -2242,3 +2242,38 @@ QPushButton#NavigationIndicator::menu-indicator { image: none; width: 0px; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Dark-orange.qss b/src/Gui/Stylesheets/Dark-orange.qss index 4305187e0f..99da5bfaa9 100644 --- a/src/Gui/Stylesheets/Dark-orange.qss +++ b/src/Gui/Stylesheets/Dark-orange.qss @@ -2243,3 +2243,38 @@ QPushButton#NavigationIndicator::menu-indicator { image: none; width: 0px; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Darker-blue.qss b/src/Gui/Stylesheets/Darker-blue.qss index 12cf7a1204..2f08c5139f 100644 --- a/src/Gui/Stylesheets/Darker-blue.qss +++ b/src/Gui/Stylesheets/Darker-blue.qss @@ -2269,3 +2269,38 @@ QToolBar QToolButton[popupMode="1"] { width: 100px; background: red; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Darker-green.qss b/src/Gui/Stylesheets/Darker-green.qss index 9a54cefc36..529fc276c7 100644 --- a/src/Gui/Stylesheets/Darker-green.qss +++ b/src/Gui/Stylesheets/Darker-green.qss @@ -2269,3 +2269,38 @@ QToolBar QToolButton[popupMode="1"] { width: 100px; background: red; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Darker-orange.qss b/src/Gui/Stylesheets/Darker-orange.qss index 1f94c59206..68e77082fa 100644 --- a/src/Gui/Stylesheets/Darker-orange.qss +++ b/src/Gui/Stylesheets/Darker-orange.qss @@ -2269,3 +2269,38 @@ QToolBar QToolButton[popupMode="1"] { width: 100px; background: red; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,91,255,255); /* Deep sky blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Light-blue.qss b/src/Gui/Stylesheets/Light-blue.qss index 0742fd3cf2..e009d5826c 100644 --- a/src/Gui/Stylesheets/Light-blue.qss +++ b/src/Gui/Stylesheets/Light-blue.qss @@ -2244,3 +2244,38 @@ QPushButton#NavigationIndicator::menu-indicator { image: none; width: 0px; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(0,0,0,127); /* 50% opacity black */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(0,0,0,255); /* Black */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,0,255,255); /* Blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Light-green.qss b/src/Gui/Stylesheets/Light-green.qss index 6bf2e1a460..e2e3c3b1cd 100644 --- a/src/Gui/Stylesheets/Light-green.qss +++ b/src/Gui/Stylesheets/Light-green.qss @@ -2244,3 +2244,39 @@ QPushButton#NavigationIndicator::menu-indicator { image: none; width: 0px; } + + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(0,0,0,127); /* 50% opacity black */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(0,0,0,255); /* Black */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,0,255,255); /* Blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/Light-orange.qss b/src/Gui/Stylesheets/Light-orange.qss index 3df634467c..00f410f979 100644 --- a/src/Gui/Stylesheets/Light-orange.qss +++ b/src/Gui/Stylesheets/Light-orange.qss @@ -2244,3 +2244,38 @@ QPushButton#NavigationIndicator::menu-indicator { image: none; width: 0px; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(0,0,0,127); /* 50% opacity black */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(0,0,0,255); /* Black */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +} +Gui--UrlLabel { + color : rgba(0,0,255,255); /* Blue */ + text-decoration : underline; +} diff --git a/src/Gui/Stylesheets/ProDark.qss b/src/Gui/Stylesheets/ProDark.qss index 1fe4f811fe..0024af9d0c 100644 --- a/src/Gui/Stylesheets/ProDark.qss +++ b/src/Gui/Stylesheets/ProDark.qss @@ -2494,3 +2494,34 @@ QToolBar QToolButton[popupMode="1"] { width: 100px; background: red; } + +/*================================================================================================== +SKETCHER +==================================================================================================*/ + +Gui--StatefulLabel[state="empty_sketch"] { + color : rgba(255,255,255,127); /* 50% opacity white */ +} +Gui--StatefulLabel[state="under_constrained"] { + color : rgba(255,255,255,255); /* White */ +} +Gui--StatefulLabel[state="conflicting_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="malformed_constraints"] { + color : rgba(255,0,0,255); /* Red */ +} +Gui--StatefulLabel[state="redundant_constraints"] { + color : rgba(255,69,0,255); /* Orange red */ +} +Gui--StatefulLabel[state="partially_redundant_constraints"] { + color : rgba(65,105,225,255); /* Royal blue */ +} +Gui--StatefulLabel[state="solver_failed"] { + color : rgba(255,0,0,255); /* Red */ + font-weight: bold; +} +Gui--StatefulLabel[state="fully_constrained"] { + color : rgba(0,255,0,255); /* Green */ + font-weight: bold; +}