From 3661ffe7fbf3a13a0c14fcffcf4245e232059a26 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 5 Jan 2021 15:03:47 +0100 Subject: [PATCH] Sketcher: Constraint icons and fonts in 3D View =============================================== Based on PRs #4146 #4155. PR #4155 proposes a scaling factor to be used to scale up constraint icons and the subindex font of icons. The scaling factor is a parameter. PR #4146 proposes to derive the constraint icon size from the system font size via function of the dpi. The constraint icon subindex is a factor of the constraint size. Observations: - PR #4146 identifies the need for a scaling factor too, but this is a hardcoded 1.25 factor. - PR #4146 appears to mix font points and font pixels when deriving the sizes. - PR #4155 deals exclusively with icon size and subindex font, not with constraint label Useful concepts: - Font point is a physical distance. There are 72 points in one inch. - Monitors have pixels with varying pixel densities. The number of pixels in one point varies with pixel density. Hence the need for a correction based on the dpi of the monitor. API constraints: - While QT's configuration can be obtained in points or pixels, coin3D sets the font size in points. Solution: - Continue relying on the local font setting from preferences for coin3d font, albeit by converting from pixels to points. - Introduce a sketcher wide 3D view scaling factor, as per #4155. This factor is however used for geometry, not for fonts. - Geometry is scaled to compensate for the scaling factor and the monitor pixel density (the scaling factor is the product of both scaling factors). - Derive the 3D view icon size to be 80% (hardcoded) of the 3D view font size. Having constraint icons proportional to contraint label font size gives consistency to the interface, as constraint icons also have subindices. I do not think it is worth to provide this 80% as a configurable parameter - The constraint icon subindex, being a special case of font relative to the accompanying icon, is set to be the 80% of the icon size (hardcoded). I think it is not worth to provide this as a configurable parameter. Bonus: - ViewProviderSketch implements an observer of parameter group and tracks view scaling factor parameter and marker size. - On change of parameter the inventor nodes are updated and the 3D view redrawn. - Size information is moved to edit structure for consistency with Marker size. --- src/Mod/Sketcher/Gui/SoDatumLabel.cpp | 2 +- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 195 +++++++++++++++----- src/Mod/Sketcher/Gui/ViewProviderSketch.h | 17 +- 3 files changed, 159 insertions(+), 55 deletions(-) diff --git a/src/Mod/Sketcher/Gui/SoDatumLabel.cpp b/src/Mod/Sketcher/Gui/SoDatumLabel.cpp index 9d416f336a..d31ae8fe49 100644 --- a/src/Mod/Sketcher/Gui/SoDatumLabel.cpp +++ b/src/Mod/Sketcher/Gui/SoDatumLabel.cpp @@ -503,7 +503,7 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) const SbColor& t = textColor.getValue(); // Set GL Properties - glLineWidth(2.f); + glLineWidth(this->lineWidth.getValue()); glColor3f(t[0], t[1], t[2]); if (this->datumtype.getValue() == DISTANCE || diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 326d57d33f..797472aec4 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -188,6 +188,8 @@ struct EditData { PreselectCurve(-1), PreselectCross(-1), MarkerSize(7), + coinFontSize(11), // default of 11 points (not pixels) + constraintIconSize(15), // 11 points @ 96 ppi where 72 points = 1 inch blockedPreselection(false), FullyConstrained(false), //ActSketch(0), // if you are wondering, it went to SketchObject, accessible via getSolvedSketch() and via SketchObject interface as appropriate @@ -208,7 +210,13 @@ struct EditData { textPos(0), constrGroup(0), infoGroup(0), - pickStyleAxes(0) + pickStyleAxes(0), + PointsDrawStyle(0), + CurvesDrawStyle(0), + RootCrossDrawStyle(0), + EditCurvesDrawStyle(0), + ConstraintDrawStyle(0), + InformationDrawStyle(0) {} // pointer to the active handler for new sketch objects @@ -228,6 +236,9 @@ struct EditData { int PreselectCurve; int PreselectCross; int MarkerSize; + int coinFontSize; + int constraintIconSize; + double pixelScalingFactor; std::set PreselectConstraintSet; bool blockedPreselection; bool FullyConstrained; @@ -273,6 +284,13 @@ struct EditData { SmSwitchboard *constrGroup; SoGroup *infoGroup; SoPickStyle *pickStyleAxes; + + SoDrawStyle * PointsDrawStyle; + SoDrawStyle * CurvesDrawStyle; + SoDrawStyle * RootCrossDrawStyle; + SoDrawStyle * EditCurvesDrawStyle; + SoDrawStyle * ConstraintDrawStyle; + SoDrawStyle * InformationDrawStyle; }; @@ -373,7 +391,8 @@ ViewProviderSketch::ViewProviderSketch() //rubberband selection rubberband = new Gui::Rubberband(); - InitItemsSizes(); + + subscribeToParameters(); } ViewProviderSketch::~ViewProviderSketch() @@ -3191,11 +3210,14 @@ QString ViewProviderSketch::getPresentationString(const Constraint *constraint) } } } + if (constraint->Type == Sketcher::Diameter){ userStr.insert(0, QChar(8960)); // Diameter sign - }else if (constraint->Type == Sketcher::Radius){ + } + else if (constraint->Type == Sketcher::Radius){ userStr.insert(0, QChar(82)); // Capital letter R } + return userStr; } @@ -3652,10 +3674,10 @@ QImage ViewProviderSketch::renderConstrIcon(const QString &type, // Constants to help create constraint icons QString joinStr = QString::fromLatin1(", "); - QImage icon = Gui::BitmapFactory().pixmapFromSvg(type.toLatin1().data(),QSizeF(constraintIconSize,constraintIconSize)).toImage(); + QImage icon = Gui::BitmapFactory().pixmapFromSvg(type.toLatin1().data(),QSizeF(edit->constraintIconSize,edit->constraintIconSize)).toImage(); QFont font = QApplication::font(); - font.setPixelSize(static_cast(0.8 * constraintIconSize)); + font.setPixelSize(static_cast(0.8 * edit->constraintIconSize)); font.setBold(true); QFontMetrics qfm = QFontMetrics(font); @@ -3754,23 +3776,97 @@ float ViewProviderSketch::getScaleFactor() } } -void ViewProviderSketch::InitItemsSizes() +void ViewProviderSketch::OnChange(Base::Subject &rCaller, const char * sReason) +{ + (void) rCaller; + //ParameterGrp& rclGrp = ((ParameterGrp&)rCaller); + if (strcmp(sReason, "ViewScalingFactor") == 0 || + strcmp(sReason, "MarkerSize") == 0 || + strcmp(sReason, "EditSketcherFontSize") == 0 ) { + if(edit) { // only if in edit mode, if not it gets updated when entering edit mode + initItemsSizes(); + updateInventorNodeSizes(); + rebuildConstraintsVisual(); + draw(); + } + } +} + +void ViewProviderSketch::subscribeToParameters() +{ + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + hGrp->Attach(this); +} + +void ViewProviderSketch::updateInventorNodeSizes() +{ + assert(edit); + edit->PointsDrawStyle->pointSize = std::lround(8 * edit->pixelScalingFactor); + edit->PointSet->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_FILLED", edit->MarkerSize); + edit->CurvesDrawStyle->lineWidth = std::lround(3 * edit->pixelScalingFactor); + edit->RootCrossDrawStyle->lineWidth = std::lround(2 * edit->pixelScalingFactor); + edit->EditCurvesDrawStyle->lineWidth = std::lround(3 * edit->pixelScalingFactor); + edit->ConstraintDrawStyle->lineWidth = std::lround(1 * edit->pixelScalingFactor); + edit->InformationDrawStyle->lineWidth = std::lround(1 * edit->pixelScalingFactor); +} + +void ViewProviderSketch::initItemsSizes() { //Add scaling to Constraint icons - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); - double viewScalingFactor = hGrp->GetFloat("ViewScalingFactor", 1.25); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + double viewScalingFactor = hGrp->GetFloat("ViewScalingFactor", 1.0); viewScalingFactor = Base::clamp(viewScalingFactor, 0.5, 5.0); + int markersize = hGrp->GetInt("MarkerSize", 7); - int defaultFontSize = QApplication::fontMetrics().height(); - int ldpi = QApplication::desktop()->logicalDpiX(); - float virtualdpi = 96.; - float QtPixelRatio = virtualdpi/ldpi; - float coinFontPixelRatio = QtPixelRatio; // this is not absolute exactly, but the ratio is correct + int defaultFontSizePixels = QApplication::fontMetrics().height(); // returns height in pixels, not points + int sketcherfontSize = hGrp->GetInt("EditSketcherFontSize", defaultFontSizePixels); - hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - coinFontSize = hGrp->GetInt("EditSketcherFontSize", defaultFontSize * QtPixelRatio * coinFontPixelRatio * viewScalingFactor); - constraintIconSize = coinFontSize / coinFontPixelRatio; - return; + auto pixelsToPoints = [](int pixels, int dpi) { + return pixels*72/dpi; // definition of point, 72 points = 1 inch + }; + + // coin takes the font size in points, not pixels + // the coin FontSize in points from the system font, taking into account the application scaling factor is: + // -> pixelsToPoints(defaultFontSizePixels * viewScalingFactor, dpi) + + int dpi = QApplication::desktop()->logicalDpiX(); + + if(edit) { + // simple scaling factor for hardcoded pixel values in the Sketcher + edit->pixelScalingFactor = viewScalingFactor * dpi / 96; // 96 ppi is the standard pixel density for which pixel quantities were calculated + + edit->coinFontSize = pixelsToPoints(sketcherfontSize, dpi); + edit->constraintIconSize = std::lround(0.8 * sketcherfontSize); + + // The global default is used. + // + // Rationale: + // -> Other WBs use the default value as is + // -> If a user has a HDPI, he will eventually change the value for the other WBs + // -> If we correct the value here in addition, we would get two times a resize + + edit->MarkerSize = markersize; + + // This commented code would find a the closest supported marker value to a provided value. + // It may be useful if a different global marker size implementation is provided. + // + // Here marker size is used as a ratio to the default of 7 px (as a second scaling factor) + // the default marker size is 30% of the view3dFontPixels + // NOTE: Not all marker sizes are supported, grab the closest supported one. + /* + std::vector supportedsizes {5, 7, 9, 11, 13, 15}; + int calculatedmarker = std::lround(0.3*view3dFontPixels*markersize/7.0); + + auto pos = std::upper_bound(supportedsizes.begin(), supportedsizes.end(), calculatedmarker); + + if(pos == supportedsizes.end()) + edit->MarkerSize = *std::prev(supportedsizes.end()); + else if(pos == supportedsizes.begin()) + edit->MarkerSize = *supportedsizes.begin(); + else + edit->MarkerSize = (*pos - calculatedmarker > calculatedmarker - *std::prev(pos))?*std::prev(pos):*pos; + */ + } } void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer /*=true*/) @@ -4251,7 +4347,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoFont *font = new SoFont; font->name.setValue("Helvetica"); - font->size.setValue(coinFontSize); + font->size.setValue(edit->coinFontSize); SoText2 *degreetext = new SoText2; degreetext->string = SbString(spline->getDegree()); @@ -4530,7 +4626,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoFont *font = new SoFont; font->name.setValue("Helvetica"); - font->size.setValue(coinFontSize); + font->size.setValue(edit->coinFontSize); SoText2 *degreetext = new SoText2; degreetext->string = SbString("(") + SbString(*itm) + SbString(")"); @@ -4597,7 +4693,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoFont* font = new SoFont; font->name.setValue("Helvetica"); - font->size.setValue(coinFontSize); + font->size.setValue(edit->coinFontSize); translate->translation.setValue(poleposition.x, poleposition.y, zInfo); @@ -5815,7 +5911,8 @@ void ViewProviderSketch::rebuildConstraintsVisual(void) ConstrDimColor :NonDrivingConstrDimColor) :DeactivatedConstrDimColor; - text->size.setValue(coinFontSize); + text->size.setValue(edit->coinFontSize); + text->lineWidth = std::lround(2 * edit->pixelScalingFactor); text->useAntialiasing = false; SoAnnotation *anno = new SoAnnotation(); anno->renderCaching = SoSeparator::OFF; @@ -5918,6 +6015,7 @@ void ViewProviderSketch::rebuildConstraintsVisual(void) arrows->norm.setValue(norm); arrows->string = ""; arrows->textColor = ConstrDimColor; + arrows->lineWidth = std::lround(2 * edit->pixelScalingFactor); // #define CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL 0 sep->addChild(arrows); @@ -6105,8 +6203,8 @@ bool ViewProviderSketch::setEdit(int ModNum) assert(!edit); edit = new EditData(); - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - edit->MarkerSize = hGrp->GetInt("MarkerSize", 7); + // Init icon, font and marker sizes + initItemsSizes(); ParameterGrp::handle hSketch = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); edit->handleEscapeButton = !hSketch->GetBool("LeaveSketchWithEscape", true); @@ -6161,6 +6259,7 @@ bool ViewProviderSketch::setEdit(int ModNum) float transparency; + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); // set the point color unsigned long color = (unsigned long)(VertexColor.getPackedValue()); color = hGrp->GetUnsigned("EditedVertexColor", color); @@ -6424,10 +6523,10 @@ void ViewProviderSketch::createEditInventorNodes(void) edit->PointsCoordinate->setName("PointsCoordinate"); pointsRoot->addChild(edit->PointsCoordinate); - SoDrawStyle *drawStyle = new SoDrawStyle; - drawStyle->setName("PointsDrawStyle"); - drawStyle->pointSize = 8; - pointsRoot->addChild(drawStyle); + edit->PointsDrawStyle = new SoDrawStyle; + edit->PointsDrawStyle->setName("PointsDrawStyle"); + edit->PointsDrawStyle->pointSize = std::lround(8 * edit->pixelScalingFactor); + pointsRoot->addChild(edit->PointsDrawStyle); edit->PointSet = new SoMarkerSet; edit->PointSet->setName("PointSet"); @@ -6450,10 +6549,10 @@ void ViewProviderSketch::createEditInventorNodes(void) edit->CurvesCoordinate->setName("CurvesCoordinate"); curvesRoot->addChild(edit->CurvesCoordinate); - drawStyle = new SoDrawStyle; - drawStyle->setName("CurvesDrawStyle"); - drawStyle->lineWidth = 3; - curvesRoot->addChild(drawStyle); + edit->CurvesDrawStyle = new SoDrawStyle; + edit->CurvesDrawStyle->setName("CurvesDrawStyle"); + edit->CurvesDrawStyle->lineWidth = std::lround(3 * edit->pixelScalingFactor); + curvesRoot->addChild(edit->CurvesDrawStyle); edit->CurveSet = new SoLineSet; edit->CurveSet->setName("CurvesLineSet"); @@ -6470,10 +6569,10 @@ void ViewProviderSketch::createEditInventorNodes(void) MtlBind->value = SoMaterialBinding::PER_FACE; crossRoot->addChild(MtlBind); - drawStyle = new SoDrawStyle; - drawStyle->setName("RootCrossDrawStyle"); - drawStyle->lineWidth = 2; - crossRoot->addChild(drawStyle); + edit->RootCrossDrawStyle = new SoDrawStyle; + edit->RootCrossDrawStyle->setName("RootCrossDrawStyle"); + edit->RootCrossDrawStyle->lineWidth = std::lround(2 * edit->pixelScalingFactor); + crossRoot->addChild(edit->RootCrossDrawStyle); edit->RootCrossMaterials = new SoMaterial; edit->RootCrossMaterials->setName("RootCrossMaterials"); @@ -6500,10 +6599,10 @@ void ViewProviderSketch::createEditInventorNodes(void) edit->EditCurvesCoordinate->setName("EditCurvesCoordinate"); editCurvesRoot->addChild(edit->EditCurvesCoordinate); - drawStyle = new SoDrawStyle; - drawStyle->setName("EditCurvesDrawStyle"); - drawStyle->lineWidth = 3; - editCurvesRoot->addChild(drawStyle); + edit->EditCurvesDrawStyle = new SoDrawStyle; + edit->EditCurvesDrawStyle->setName("EditCurvesDrawStyle"); + edit->EditCurvesDrawStyle->lineWidth = std::lround(3 * edit->pixelScalingFactor); + editCurvesRoot->addChild(edit->EditCurvesDrawStyle); edit->EditCurveSet = new SoLineSet; edit->EditCurveSet->setName("EditCurveLineSet"); @@ -6529,7 +6628,7 @@ void ViewProviderSketch::createEditInventorNodes(void) Coordsep->addChild(CoordTextMaterials); SoFont *font = new SoFont(); - font->size.setValue(coinFontSize); + font->size.setValue(edit->coinFontSize); Coordsep->addChild(font); @@ -6549,10 +6648,10 @@ void ViewProviderSketch::createEditInventorNodes(void) edit->EditRoot->addChild(MtlBind); // use small line width for the Constraints - drawStyle = new SoDrawStyle; - drawStyle->setName("ConstraintDrawStyle"); - drawStyle->lineWidth = 1; - edit->EditRoot->addChild(drawStyle); + edit->ConstraintDrawStyle = new SoDrawStyle; + edit->ConstraintDrawStyle->setName("ConstraintDrawStyle"); + edit->ConstraintDrawStyle->lineWidth = std::lround(1 * edit->pixelScalingFactor); + edit->EditRoot->addChild(edit->ConstraintDrawStyle); // add the group where all the constraints has its SoSeparator edit->constrGroup = new SmSwitchboard(); @@ -6566,10 +6665,10 @@ void ViewProviderSketch::createEditInventorNodes(void) edit->EditRoot->addChild(MtlBind); // use small line width for the information visual - drawStyle = new SoDrawStyle; - drawStyle->setName("InformationDrawStyle"); - drawStyle->lineWidth = 1; - edit->EditRoot->addChild(drawStyle); + edit->InformationDrawStyle = new SoDrawStyle; + edit->InformationDrawStyle->setName("InformationDrawStyle"); + edit->InformationDrawStyle->lineWidth = std::lround(1 * edit->pixelScalingFactor); + edit->EditRoot->addChild(edit->InformationDrawStyle); // add the group where all the information entity has its SoSeparator edit->infoGroup = new SoGroup(); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 2650b06ffc..fae7607729 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -87,6 +87,7 @@ class DrawSketchHandler; class SketcherGuiExport ViewProviderSketch : public PartGui::ViewProvider2DObjectGrid , public PartGui::ViewProviderAttachExtension , public Gui::SelectionObserver + , public ParameterGrp::ObserverType { Q_DECLARE_TR_FUNCTIONS(SketcherGui::ViewProviderSketch) /// generates a warning message about constraint conflicts and appends it to the given message @@ -113,9 +114,6 @@ public: App::PropertyBool RestoreCamera; App::PropertyString EditingWorkbench; - /// set icon & font sizes - void InitItemsSizes(); - /// Draw all constraint icons /*! Except maybe the radius and lock ones? */ void drawConstraintIcons(); @@ -274,6 +272,9 @@ public: /// signals if the elements list has changed boost::signals2::signal signalElementsChanged; + /** Observer for parameter group. */ + void OnChange(Base::Subject &rCaller, const char * sReason) override; + protected: Base::Placement getEditingPlacement() const; @@ -306,6 +307,13 @@ protected: boost::signals2::connection connectUndoDocument; boost::signals2::connection connectRedoDocument; + /// set icon & font sizes + void initItemsSizes(); + /// subscribe to parameter groups as an observer + void subscribeToParameters(); + /// updates the sizes of the edit mode inventor node + void updateInventorNodeSizes(); + void forceUpdateData(); /// Auxiliary function to generate messages about conflicting, redundant and malformed constraints @@ -471,9 +479,6 @@ protected: bool isShownVirtualSpace; // indicates whether the present virtual space view is the Real Space or the Virtual Space (virtual space 1 or 2) ShortcutListener* listener; - - int coinFontSize; - int constraintIconSize; }; } // namespace PartGui