From 00c3422c1f9e474d042ec34ea300ca6a3a7503a7 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Thu, 29 Jan 2026 15:04:40 +0100 Subject: [PATCH] Sketcher: Tooltip when hovering expression driven constraint (#25954) --- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 63 ++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index ee532450ca..ff821cdec2 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -34,11 +34,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -2414,6 +2416,48 @@ bool ViewProviderSketch::detectAndShowPreselection(SoPickedPoint* Point) { assert(isInEditMode()); + // Event filter to intercept the delayed tooltip event from Qt + class ToolTipFilter : public QObject { + public: + bool eventFilter(QObject *obj, QEvent *event) override { + if (event->type() == QEvent::ToolTip) { + // When Qt's idle timer fires, this event is sent. + // We intercept it to show the tooltip. + QHelpEvent *helpEvent = static_cast(event); + QWidget *widget = qobject_cast(obj); + if (widget && !widget->toolTip().isEmpty()) { + QToolTip::showText(helpEvent->globalPos(), widget->toolTip(), widget); + return true; // Mark as handled so default processing doesn't hide it + } + } + return QObject::eventFilter(obj, event); + } + }; + static ToolTipFilter filter; + + auto updateToolTip = [this](const QString& text = QString()) { + auto* view = qobject_cast(this->getActiveView()); + QWidget* widget = view ? view->getViewer()->getGLWidget() : nullptr; + + if (!widget) return; + + if (text.isEmpty()) { + // Hide tooltip and cleanup + QToolTip::hideText(); + widget->removeEventFilter(&filter); + widget->setToolTip(QString()); + } else { + // 1. Set the tooltip text on the widget. + // This arm's Qt's internal timer to fire QEvent::ToolTip after the standard delay. + widget->setToolTip(text); + + // 2. Install the filter to catch that event. + // We remove it first to ensure we don't install it multiple times. + widget->removeEventFilter(&filter); + widget->installEventFilter(&filter); + } + }; + if (Point) { EditModeCoinManager::PreselectionResult result = editCoinManager->detectPreselection(Point); @@ -2429,6 +2473,7 @@ bool ViewProviderSketch::detectAndShowPreselection(SoPickedPoint* Point) preselection.blockedPreselection = !accepted; if (accepted) { setPreselectPoint(result.PointIndex); + updateToolTip(); // Clear tooltip on point selection return true; } @@ -2450,6 +2495,7 @@ bool ViewProviderSketch::detectAndShowPreselection(SoPickedPoint* Point) if (accepted) { resetPreselectPoint(); preselection.PreselectCurve = result.GeoIndex; + updateToolTip(); // Clear tooltip on curve selection return true; } @@ -2483,6 +2529,7 @@ bool ViewProviderSketch::detectAndShowPreselection(SoPickedPoint* Point) resetPreselectPoint(); preselection.PreselectCross = static_cast(static_cast(result.Cross)); + updateToolTip(); // Clear tooltip on axis selection return true; } @@ -2503,12 +2550,24 @@ bool ViewProviderSketch::detectAndShowPreselection(SoPickedPoint* Point) != 0; preselection.blockedPreselection = !accepted; - // TODO: Should we clear preselections that went through, if one fails? } if (accepted) { resetPreselectPoint(); preselection.PreselectConstraintSet = result.ConstrIndices; + // Build tooltip text for expressions + QString tooltipText; + for (int id : result.ConstrIndices) { + if (constraintHasExpression(id)) { + std::string expr = getSketchObject()->getConstraintExpression(id); + if (!expr.empty()) { + tooltipText = QString::fromUtf8("\U0001D453\U0001D465 = ") + QString::fromStdString(expr); + break; + } + } + } + updateToolTip(tooltipText); + return true;// Preselection changed } } @@ -2522,6 +2581,7 @@ bool ViewProviderSketch::detectAndShowPreselection(SoPickedPoint* Point) // we have just left a preselection resetPreselectPoint(); preselection.blockedPreselection = false; + updateToolTip(); // Clear tooltip when leaving preselection return true; } @@ -2533,6 +2593,7 @@ bool ViewProviderSketch::detectAndShowPreselection(SoPickedPoint* Point) || preselection.blockedPreselection) { resetPreselectPoint(); preselection.blockedPreselection = false; + updateToolTip(); // Clear tooltip when no point picked return true; }