From 7db539fb212f31792a4ac180a6ca30de9818c0de Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Sun, 22 Mar 2020 17:03:27 +0100 Subject: [PATCH 01/62] [Sketcher] Distinguish normal/reference/construction elements in task dialog --- src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 200 ++++++++++-------- src/Mod/Sketcher/Gui/TaskSketcherElements.h | 9 + 2 files changed, 122 insertions(+), 87 deletions(-) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index b8235c5ac2..89fdd40042 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -29,6 +29,8 @@ # include # include # include +# include +# include # include #endif @@ -663,34 +665,34 @@ void TaskSketcherElements::leaveEvent (QEvent * event) void TaskSketcherElements::slotElementsChanged(void) { - QIcon Sketcher_Element_Arc_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_Edge") ); - QIcon Sketcher_Element_Arc_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_EndPoint") ); - QIcon Sketcher_Element_Arc_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_MidPoint") ); - QIcon Sketcher_Element_Arc_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_StartingPoint") ); - QIcon Sketcher_Element_Circle_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Circle_Edge") ); - QIcon Sketcher_Element_Circle_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Circle_MidPoint") ); - QIcon Sketcher_Element_Line_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Line_Edge") ); - QIcon Sketcher_Element_Line_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Line_EndPoint") ); - QIcon Sketcher_Element_Line_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Line_StartingPoint") ); - QIcon Sketcher_Element_Point_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Point_StartingPoint") ); - QIcon Sketcher_Element_Ellipse_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Ellipse_Edge_2") ); - QIcon Sketcher_Element_Ellipse_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Ellipse_CentrePoint") ); - QIcon Sketcher_Element_ArcOfEllipse_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_Edge") ); - QIcon Sketcher_Element_ArcOfEllipse_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_Centre_Point") ); - QIcon Sketcher_Element_ArcOfEllipse_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_Start_Point") ); - QIcon Sketcher_Element_ArcOfEllipse_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_End_Point") ); - QIcon Sketcher_Element_ArcOfHyperbola_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_Edge") ); - QIcon Sketcher_Element_ArcOfHyperbola_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_Centre_Point") ); - QIcon Sketcher_Element_ArcOfHyperbola_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_Start_Point") ); - QIcon Sketcher_Element_ArcOfHyperbola_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_End_Point") ); - QIcon Sketcher_Element_ArcOfParabola_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_Edge") ); - QIcon Sketcher_Element_ArcOfParabola_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_Centre_Point") ); - QIcon Sketcher_Element_ArcOfParabola_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_Start_Point") ); - QIcon Sketcher_Element_ArcOfParabola_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_End_Point") ); - QIcon Sketcher_Element_BSpline_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_BSpline_Edge") ); - QIcon Sketcher_Element_BSpline_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_BSpline_StartPoint") ); - QIcon Sketcher_Element_BSpline_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_BSpline_EndPoint") ); - QIcon none( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_SelectionTypeInvalid") ); + multIcon Sketcher_Element_Arc_Edge = tamperIcons("Sketcher_Element_Arc_Edge"); + multIcon Sketcher_Element_Arc_EndPoint = tamperIcons("Sketcher_Element_Arc_EndPoint"); + multIcon Sketcher_Element_Arc_MidPoint = tamperIcons("Sketcher_Element_Arc_MidPoint"); + multIcon Sketcher_Element_Arc_StartingPoint = tamperIcons("Sketcher_Element_Arc_StartingPoint"); + multIcon Sketcher_Element_Circle_Edge = tamperIcons("Sketcher_Element_Circle_Edge"); + multIcon Sketcher_Element_Circle_MidPoint = tamperIcons("Sketcher_Element_Circle_MidPoint"); + multIcon Sketcher_Element_Line_Edge = tamperIcons("Sketcher_Element_Line_Edge"); + multIcon Sketcher_Element_Line_EndPoint = tamperIcons("Sketcher_Element_Line_EndPoint"); + multIcon Sketcher_Element_Line_StartingPoint = tamperIcons("Sketcher_Element_Line_StartingPoint"); + multIcon Sketcher_Element_Point_StartingPoint = tamperIcons("Sketcher_Element_Point_StartingPoint"); + multIcon Sketcher_Element_Ellipse_Edge = tamperIcons("Sketcher_Element_Ellipse_Edge_2"); + multIcon Sketcher_Element_Ellipse_MidPoint = tamperIcons("Sketcher_Element_Ellipse_CentrePoint"); + multIcon Sketcher_Element_ArcOfEllipse_Edge = tamperIcons("Sketcher_Element_Elliptical_Arc_Edge"); + multIcon Sketcher_Element_ArcOfEllipse_MidPoint = tamperIcons("Sketcher_Element_Elliptical_Arc_Centre_Point"); + multIcon Sketcher_Element_ArcOfEllipse_StartingPoint = tamperIcons("Sketcher_Element_Elliptical_Arc_Start_Point"); + multIcon Sketcher_Element_ArcOfEllipse_EndPoint = tamperIcons("Sketcher_Element_Elliptical_Arc_End_Point"); + multIcon Sketcher_Element_ArcOfHyperbola_Edge = tamperIcons("Sketcher_Element_Hyperbolic_Arc_Edge"); + multIcon Sketcher_Element_ArcOfHyperbola_MidPoint = tamperIcons("Sketcher_Element_Hyperbolic_Arc_Centre_Point"); + multIcon Sketcher_Element_ArcOfHyperbola_StartingPoint = tamperIcons("Sketcher_Element_Hyperbolic_Arc_Start_Point"); + multIcon Sketcher_Element_ArcOfHyperbola_EndPoint = tamperIcons("Sketcher_Element_Hyperbolic_Arc_End_Point"); + multIcon Sketcher_Element_ArcOfParabola_Edge = tamperIcons("Sketcher_Element_Parabolic_Arc_Edge"); + multIcon Sketcher_Element_ArcOfParabola_MidPoint = tamperIcons("Sketcher_Element_Parabolic_Arc_Centre_Point"); + multIcon Sketcher_Element_ArcOfParabola_StartingPoint = tamperIcons("Sketcher_Element_Parabolic_Arc_Start_Point"); + multIcon Sketcher_Element_ArcOfParabola_EndPoint = tamperIcons("Sketcher_Element_Parabolic_Arc_End_Point"); + multIcon Sketcher_Element_BSpline_Edge = tamperIcons("Sketcher_Element_BSpline_Edge"); + multIcon Sketcher_Element_BSpline_StartingPoint = tamperIcons("Sketcher_Element_BSpline_StartPoint"); + multIcon Sketcher_Element_BSpline_EndPoint = tamperIcons("Sketcher_Element_BSpline_EndPoint"); + multIcon none = tamperIcons("Sketcher_Element_SelectionTypeInvalid"); assert(sketchView); // Build up ListView with the elements @@ -707,34 +709,34 @@ void TaskSketcherElements::slotElementsChanged(void) bool construction = (*it)->Construction; ui->listWidgetElements->addItem(new ElementItem( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint : - (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge : - (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint : - none, + (type == Part::GeomPoint::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Point_StartingPoint.ref : Sketcher_Element_Point_StartingPoint.norm : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Line_Edge.ref : Sketcher_Element_Line_Edge.norm : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Line_StartingPoint.ref : Sketcher_Element_Line_StartingPoint.norm : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Line_EndPoint.ref : Sketcher_Element_Line_EndPoint.norm : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Arc_Edge.ref : Sketcher_Element_Arc_Edge.norm : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Arc_StartingPoint.ref : Sketcher_Element_Arc_StartingPoint.norm : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Arc_EndPoint.ref : Sketcher_Element_Arc_EndPoint.norm : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Arc_MidPoint.ref : Sketcher_Element_Arc_MidPoint.norm : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Circle_Edge.ref : Sketcher_Element_Circle_Edge.norm : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Circle_MidPoint.ref : Sketcher_Element_Circle_MidPoint.norm : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Ellipse_Edge.ref : Sketcher_Element_Ellipse_Edge.norm : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Ellipse_MidPoint.ref : Sketcher_Element_Ellipse_MidPoint.norm : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfEllipse_Edge.ref : Sketcher_Element_ArcOfEllipse_Edge.norm : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfEllipse_StartingPoint.ref : Sketcher_Element_ArcOfEllipse_StartingPoint.norm : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfEllipse_EndPoint.ref : Sketcher_Element_ArcOfEllipse_EndPoint.norm : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfEllipse_MidPoint.ref : Sketcher_Element_ArcOfEllipse_MidPoint.norm : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfHyperbola_Edge.ref : Sketcher_Element_ArcOfHyperbola_Edge.norm : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfHyperbola_StartingPoint.ref : Sketcher_Element_ArcOfHyperbola_StartingPoint.norm : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfHyperbola_EndPoint.ref : Sketcher_Element_ArcOfHyperbola_EndPoint.norm : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfHyperbola_MidPoint.ref : Sketcher_Element_ArcOfHyperbola_MidPoint.norm : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfParabola_Edge.ref : Sketcher_Element_ArcOfParabola_Edge.norm : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfParabola_StartingPoint.ref : Sketcher_Element_ArcOfParabola_StartingPoint.norm : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfParabola_EndPoint.ref : Sketcher_Element_ArcOfParabola_EndPoint.norm : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfParabola_MidPoint.ref : Sketcher_Element_ArcOfParabola_MidPoint.norm : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? construction ? Sketcher_Element_BSpline_Edge.ref : Sketcher_Element_BSpline_Edge.norm : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? construction ? Sketcher_Element_BSpline_StartingPoint.ref : Sketcher_Element_BSpline_StartingPoint.norm : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? construction ? Sketcher_Element_BSpline_EndPoint.ref : Sketcher_Element_BSpline_EndPoint.norm : + construction ? none.ref : none.norm, type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Point") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Point"))) : @@ -813,34 +815,34 @@ void TaskSketcherElements::slotElementsChanged(void) ui->listWidgetElements->addItem(new ElementItem( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint : - (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge : - (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint : - none, + (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint.ext : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge.ext : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint.ext : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint.ext : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge.ext : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint.ext : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint.ext : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint.ext : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge.ext : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint.ext : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge.ext : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint.ext : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge.ext : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint.ext : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint.ext : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint.ext : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge.ext : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint.ext : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint.ext : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint.ext : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge.ext : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint.ext : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint.ext : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint.ext : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge.ext : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint.ext : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint.ext : + none.ext, type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Point") + linkname): (QString::fromLatin1("%1-").arg(i-2)+tr("Point"))) : @@ -939,7 +941,8 @@ void TaskSketcherElements::on_listWidgetElements_filterShortcutPressed() } //update the icon - updateIcons(element); + //updateIcons(element); + slotElementsChanged(); updatePreselection(); } @@ -964,7 +967,8 @@ void TaskSketcherElements::on_listWidgetElements_currentFilterChanged ( int inde Gui::Selection().rmvPreselect(); - updateIcons(index); + //updateIcons(index); + slotElementsChanged(); updatePreselection(); @@ -1105,6 +1109,28 @@ void TaskSketcherElements::changeEvent(QEvent *e) } } - +multIcon TaskSketcherElements::tamperIcons(const char* name) +{ + QIcon normIcon = Gui::BitmapFactory().iconFromTheme(name); + QImage imgRef(normIcon.pixmap(normIcon.availableSizes()[0]).toImage()); + QImage imgCons(imgRef); + + for(int ix=0 ; ix= 0) { + if(hue > 330 || hue < 30) { + clr.setHsl((hue + 240) % 360, clr.saturation(), clr.lightness(), clr.alpha()); + imgRef.setPixelColor(ix, iy, clr); + } + clr.setHsl(300, clr.saturation(), clr.lightness(), clr.alpha()); + imgCons.setPixelColor(ix, iy, clr); + } + } + } + return {normIcon, QIcon(QPixmap::fromImage(imgRef)), QIcon(QPixmap::fromImage(imgCons))}; +} + #include "moc_TaskSketcherElements.cpp" diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.h b/src/Mod/Sketcher/Gui/TaskSketcherElements.h index 64c0619a5e..2b2f4dddd4 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace App { class Property; @@ -87,6 +88,12 @@ protected Q_SLOTS: }; +struct multIcon { + QIcon norm; + QIcon ref; + QIcon ext; +}; + class TaskSketcherElements : public Gui::TaskView::TaskBox, public Gui::SelectionObserver { Q_OBJECT @@ -132,6 +139,8 @@ private: bool isautoSwitchBoxChecked; bool inhibitSelectionUpdate; + + multIcon tamperIcons(const char*); }; } //namespace SketcherGui From 779631a67b620ffcfc0a5e47b05ec7b09f376a61 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 5 Apr 2020 11:41:02 +0200 Subject: [PATCH 02/62] Sketcher: Element Widget External/Construction icons fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ========================================================== Changes: - Move multIcon structure to be internal to TaskSketcherElements class - Change Caps to MultIcon for consistency - Move tamperIcon from TaskSketcherElements to MultIcon struct - Change tamperIcon method to be the constructor of MultIcon and change from struct to class - Update the tamperIcon algorithm, so that only the point that is not marked in green as selected is made pink. Bug fix: UpdateIcons and SlotElementsChanged are methods sharing code (they could benefit from a refactoring), but they are conceptually different and are called in very different circumnstances. UpdateIcons preserves selection. This means that one may select the stating point of line1, press z to switch to edges, select the edge of line 2 and do a point on object constraint all without touching the 3D view. SlotElementsChanged occurs when there are additions or removals in the number of geometry elements of the widget. Warning: This code requires QT 5.6 because of function pixelColour(int, int): https://doc.qt.io/qt-5/qimage.html#pixelColor-1 Travis without QT5 complains with: /home/travis/build/FreeCAD/FreeCAD/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp:1120:31: error: ‘class QImage’ has no member named ‘pixelColor’; did you mean ‘setColor’? --- src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 318 +++++++++--------- src/Mod/Sketcher/Gui/TaskSketcherElements.h | 18 +- 2 files changed, 173 insertions(+), 163 deletions(-) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index 89fdd40042..92cde9598c 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -665,34 +665,34 @@ void TaskSketcherElements::leaveEvent (QEvent * event) void TaskSketcherElements::slotElementsChanged(void) { - multIcon Sketcher_Element_Arc_Edge = tamperIcons("Sketcher_Element_Arc_Edge"); - multIcon Sketcher_Element_Arc_EndPoint = tamperIcons("Sketcher_Element_Arc_EndPoint"); - multIcon Sketcher_Element_Arc_MidPoint = tamperIcons("Sketcher_Element_Arc_MidPoint"); - multIcon Sketcher_Element_Arc_StartingPoint = tamperIcons("Sketcher_Element_Arc_StartingPoint"); - multIcon Sketcher_Element_Circle_Edge = tamperIcons("Sketcher_Element_Circle_Edge"); - multIcon Sketcher_Element_Circle_MidPoint = tamperIcons("Sketcher_Element_Circle_MidPoint"); - multIcon Sketcher_Element_Line_Edge = tamperIcons("Sketcher_Element_Line_Edge"); - multIcon Sketcher_Element_Line_EndPoint = tamperIcons("Sketcher_Element_Line_EndPoint"); - multIcon Sketcher_Element_Line_StartingPoint = tamperIcons("Sketcher_Element_Line_StartingPoint"); - multIcon Sketcher_Element_Point_StartingPoint = tamperIcons("Sketcher_Element_Point_StartingPoint"); - multIcon Sketcher_Element_Ellipse_Edge = tamperIcons("Sketcher_Element_Ellipse_Edge_2"); - multIcon Sketcher_Element_Ellipse_MidPoint = tamperIcons("Sketcher_Element_Ellipse_CentrePoint"); - multIcon Sketcher_Element_ArcOfEllipse_Edge = tamperIcons("Sketcher_Element_Elliptical_Arc_Edge"); - multIcon Sketcher_Element_ArcOfEllipse_MidPoint = tamperIcons("Sketcher_Element_Elliptical_Arc_Centre_Point"); - multIcon Sketcher_Element_ArcOfEllipse_StartingPoint = tamperIcons("Sketcher_Element_Elliptical_Arc_Start_Point"); - multIcon Sketcher_Element_ArcOfEllipse_EndPoint = tamperIcons("Sketcher_Element_Elliptical_Arc_End_Point"); - multIcon Sketcher_Element_ArcOfHyperbola_Edge = tamperIcons("Sketcher_Element_Hyperbolic_Arc_Edge"); - multIcon Sketcher_Element_ArcOfHyperbola_MidPoint = tamperIcons("Sketcher_Element_Hyperbolic_Arc_Centre_Point"); - multIcon Sketcher_Element_ArcOfHyperbola_StartingPoint = tamperIcons("Sketcher_Element_Hyperbolic_Arc_Start_Point"); - multIcon Sketcher_Element_ArcOfHyperbola_EndPoint = tamperIcons("Sketcher_Element_Hyperbolic_Arc_End_Point"); - multIcon Sketcher_Element_ArcOfParabola_Edge = tamperIcons("Sketcher_Element_Parabolic_Arc_Edge"); - multIcon Sketcher_Element_ArcOfParabola_MidPoint = tamperIcons("Sketcher_Element_Parabolic_Arc_Centre_Point"); - multIcon Sketcher_Element_ArcOfParabola_StartingPoint = tamperIcons("Sketcher_Element_Parabolic_Arc_Start_Point"); - multIcon Sketcher_Element_ArcOfParabola_EndPoint = tamperIcons("Sketcher_Element_Parabolic_Arc_End_Point"); - multIcon Sketcher_Element_BSpline_Edge = tamperIcons("Sketcher_Element_BSpline_Edge"); - multIcon Sketcher_Element_BSpline_StartingPoint = tamperIcons("Sketcher_Element_BSpline_StartPoint"); - multIcon Sketcher_Element_BSpline_EndPoint = tamperIcons("Sketcher_Element_BSpline_EndPoint"); - multIcon none = tamperIcons("Sketcher_Element_SelectionTypeInvalid"); + MultIcon Sketcher_Element_Arc_Edge("Sketcher_Element_Arc_Edge"); + MultIcon Sketcher_Element_Arc_EndPoint("Sketcher_Element_Arc_EndPoint"); + MultIcon Sketcher_Element_Arc_MidPoint("Sketcher_Element_Arc_MidPoint"); + MultIcon Sketcher_Element_Arc_StartingPoint("Sketcher_Element_Arc_StartingPoint"); + MultIcon Sketcher_Element_Circle_Edge("Sketcher_Element_Circle_Edge"); + MultIcon Sketcher_Element_Circle_MidPoint("Sketcher_Element_Circle_MidPoint"); + MultIcon Sketcher_Element_Line_Edge("Sketcher_Element_Line_Edge"); + MultIcon Sketcher_Element_Line_EndPoint("Sketcher_Element_Line_EndPoint"); + MultIcon Sketcher_Element_Line_StartingPoint("Sketcher_Element_Line_StartingPoint"); + MultIcon Sketcher_Element_Point_StartingPoint("Sketcher_Element_Point_StartingPoint"); + MultIcon Sketcher_Element_Ellipse_Edge("Sketcher_Element_Ellipse_Edge_2"); + MultIcon Sketcher_Element_Ellipse_MidPoint("Sketcher_Element_Ellipse_CentrePoint"); + MultIcon Sketcher_Element_ArcOfEllipse_Edge("Sketcher_Element_Elliptical_Arc_Edge"); + MultIcon Sketcher_Element_ArcOfEllipse_MidPoint("Sketcher_Element_Elliptical_Arc_Centre_Point"); + MultIcon Sketcher_Element_ArcOfEllipse_StartingPoint("Sketcher_Element_Elliptical_Arc_Start_Point"); + MultIcon Sketcher_Element_ArcOfEllipse_EndPoint("Sketcher_Element_Elliptical_Arc_End_Point"); + MultIcon Sketcher_Element_ArcOfHyperbola_Edge("Sketcher_Element_Hyperbolic_Arc_Edge"); + MultIcon Sketcher_Element_ArcOfHyperbola_MidPoint("Sketcher_Element_Hyperbolic_Arc_Centre_Point"); + MultIcon Sketcher_Element_ArcOfHyperbola_StartingPoint("Sketcher_Element_Hyperbolic_Arc_Start_Point"); + MultIcon Sketcher_Element_ArcOfHyperbola_EndPoint("Sketcher_Element_Hyperbolic_Arc_End_Point"); + MultIcon Sketcher_Element_ArcOfParabola_Edge("Sketcher_Element_Parabolic_Arc_Edge"); + MultIcon Sketcher_Element_ArcOfParabola_MidPoint("Sketcher_Element_Parabolic_Arc_Centre_Point"); + MultIcon Sketcher_Element_ArcOfParabola_StartingPoint("Sketcher_Element_Parabolic_Arc_Start_Point"); + MultIcon Sketcher_Element_ArcOfParabola_EndPoint("Sketcher_Element_Parabolic_Arc_End_Point"); + MultIcon Sketcher_Element_BSpline_Edge("Sketcher_Element_BSpline_Edge"); + MultIcon Sketcher_Element_BSpline_StartingPoint("Sketcher_Element_BSpline_StartPoint"); + MultIcon Sketcher_Element_BSpline_EndPoint("Sketcher_Element_BSpline_EndPoint"); + MultIcon none("Sketcher_Element_SelectionTypeInvalid"); assert(sketchView); // Build up ListView with the elements @@ -709,34 +709,34 @@ void TaskSketcherElements::slotElementsChanged(void) bool construction = (*it)->Construction; ui->listWidgetElements->addItem(new ElementItem( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Point_StartingPoint.ref : Sketcher_Element_Point_StartingPoint.norm : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Line_Edge.ref : Sketcher_Element_Line_Edge.norm : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Line_StartingPoint.ref : Sketcher_Element_Line_StartingPoint.norm : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Line_EndPoint.ref : Sketcher_Element_Line_EndPoint.norm : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Arc_Edge.ref : Sketcher_Element_Arc_Edge.norm : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Arc_StartingPoint.ref : Sketcher_Element_Arc_StartingPoint.norm : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Arc_EndPoint.ref : Sketcher_Element_Arc_EndPoint.norm : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Arc_MidPoint.ref : Sketcher_Element_Arc_MidPoint.norm : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Circle_Edge.ref : Sketcher_Element_Circle_Edge.norm : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Circle_MidPoint.ref : Sketcher_Element_Circle_MidPoint.norm : - (type == Part::GeomEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Ellipse_Edge.ref : Sketcher_Element_Ellipse_Edge.norm : - (type == Part::GeomEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Ellipse_MidPoint.ref : Sketcher_Element_Ellipse_MidPoint.norm : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfEllipse_Edge.ref : Sketcher_Element_ArcOfEllipse_Edge.norm : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfEllipse_StartingPoint.ref : Sketcher_Element_ArcOfEllipse_StartingPoint.norm : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfEllipse_EndPoint.ref : Sketcher_Element_ArcOfEllipse_EndPoint.norm : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfEllipse_MidPoint.ref : Sketcher_Element_ArcOfEllipse_MidPoint.norm : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfHyperbola_Edge.ref : Sketcher_Element_ArcOfHyperbola_Edge.norm : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfHyperbola_StartingPoint.ref : Sketcher_Element_ArcOfHyperbola_StartingPoint.norm : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfHyperbola_EndPoint.ref : Sketcher_Element_ArcOfHyperbola_EndPoint.norm : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfHyperbola_MidPoint.ref : Sketcher_Element_ArcOfHyperbola_MidPoint.norm : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfParabola_Edge.ref : Sketcher_Element_ArcOfParabola_Edge.norm : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfParabola_StartingPoint.ref : Sketcher_Element_ArcOfParabola_StartingPoint.norm : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfParabola_EndPoint.ref : Sketcher_Element_ArcOfParabola_EndPoint.norm : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfParabola_MidPoint.ref : Sketcher_Element_ArcOfParabola_MidPoint.norm : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? construction ? Sketcher_Element_BSpline_Edge.ref : Sketcher_Element_BSpline_Edge.norm : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? construction ? Sketcher_Element_BSpline_StartingPoint.ref : Sketcher_Element_BSpline_StartingPoint.norm : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? construction ? Sketcher_Element_BSpline_EndPoint.ref : Sketcher_Element_BSpline_EndPoint.norm : - construction ? none.ref : none.norm, + (type == Part::GeomPoint::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Point_StartingPoint.Construction : Sketcher_Element_Point_StartingPoint.Normal : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Line_Edge.Construction : Sketcher_Element_Line_Edge.Normal : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Line_StartingPoint.Construction : Sketcher_Element_Line_StartingPoint.Normal : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Line_EndPoint.Construction : Sketcher_Element_Line_EndPoint.Normal : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Arc_Edge.Construction : Sketcher_Element_Arc_Edge.Normal : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Arc_StartingPoint.Construction : Sketcher_Element_Arc_StartingPoint.Normal : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Arc_EndPoint.Construction : Sketcher_Element_Arc_EndPoint.Normal : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Arc_MidPoint.Construction : Sketcher_Element_Arc_MidPoint.Normal : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Circle_Edge.Construction : Sketcher_Element_Circle_Edge.Normal : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Circle_MidPoint.Construction : Sketcher_Element_Circle_MidPoint.Normal : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Ellipse_Edge.Construction : Sketcher_Element_Ellipse_Edge.Normal : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Ellipse_MidPoint.Construction : Sketcher_Element_Ellipse_MidPoint.Normal : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfEllipse_Edge.Construction : Sketcher_Element_ArcOfEllipse_Edge.Normal : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfEllipse_StartingPoint.Construction : Sketcher_Element_ArcOfEllipse_StartingPoint.Normal : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfEllipse_EndPoint.Construction : Sketcher_Element_ArcOfEllipse_EndPoint.Normal : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfEllipse_MidPoint.Construction : Sketcher_Element_ArcOfEllipse_MidPoint.Normal : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfHyperbola_Edge.Construction : Sketcher_Element_ArcOfHyperbola_Edge.Normal : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfHyperbola_StartingPoint.Construction : Sketcher_Element_ArcOfHyperbola_StartingPoint.Normal : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfHyperbola_EndPoint.Construction : Sketcher_Element_ArcOfHyperbola_EndPoint.Normal : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfHyperbola_MidPoint.Construction : Sketcher_Element_ArcOfHyperbola_MidPoint.Normal : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfParabola_Edge.Construction : Sketcher_Element_ArcOfParabola_Edge.Normal : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfParabola_StartingPoint.Construction : Sketcher_Element_ArcOfParabola_StartingPoint.Normal : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfParabola_EndPoint.Construction : Sketcher_Element_ArcOfParabola_EndPoint.Normal : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfParabola_MidPoint.Construction : Sketcher_Element_ArcOfParabola_MidPoint.Normal : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? construction ? Sketcher_Element_BSpline_Edge.Construction : Sketcher_Element_BSpline_Edge.Normal : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? construction ? Sketcher_Element_BSpline_StartingPoint.Construction : Sketcher_Element_BSpline_StartingPoint.Normal : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? construction ? Sketcher_Element_BSpline_EndPoint.Construction : Sketcher_Element_BSpline_EndPoint.Normal : + construction ? none.Construction : none.Normal, type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Point") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Point"))) : @@ -815,34 +815,34 @@ void TaskSketcherElements::slotElementsChanged(void) ui->listWidgetElements->addItem(new ElementItem( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint.ext : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge.ext : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint.ext : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint.ext : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge.ext : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint.ext : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint.ext : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint.ext : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge.ext : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint.ext : - (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge.ext : - (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint.ext : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge.ext : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint.ext : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint.ext : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint.ext : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge.ext : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint.ext : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint.ext : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint.ext : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge.ext : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint.ext : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint.ext : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint.ext : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge.ext : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint.ext : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint.ext : - none.ext, + (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint.External : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge.External : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint.External : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint.External : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge.External : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint.External : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint.External : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint.External : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge.External : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint.External : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge.External : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint.External : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge.External : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint.External : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint.External : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint.External : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge.External : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint.External : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint.External : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint.External : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge.External : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint.External : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint.External : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint.External : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge.External : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint.External : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint.External : + none.External, type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Point") + linkname): (QString::fromLatin1("%1-").arg(i-2)+tr("Point"))) : @@ -941,8 +941,7 @@ void TaskSketcherElements::on_listWidgetElements_filterShortcutPressed() } //update the icon - //updateIcons(element); - slotElementsChanged(); + updateIcons(element); updatePreselection(); } @@ -967,8 +966,7 @@ void TaskSketcherElements::on_listWidgetElements_currentFilterChanged ( int inde Gui::Selection().rmvPreselect(); - //updateIcons(index); - slotElementsChanged(); + updateIcons(index); updatePreselection(); @@ -1037,67 +1035,74 @@ void TaskSketcherElements::updateVisibility(int filterindex) void TaskSketcherElements::updateIcons(int element) { - QIcon Sketcher_Element_Arc_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_Edge") ); - QIcon Sketcher_Element_Arc_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_EndPoint") ); - QIcon Sketcher_Element_Arc_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_MidPoint") ); - QIcon Sketcher_Element_Arc_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Arc_StartingPoint") ); - QIcon Sketcher_Element_Circle_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Circle_Edge") ); - QIcon Sketcher_Element_Circle_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Circle_MidPoint") ); - QIcon Sketcher_Element_Line_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Line_Edge") ); - QIcon Sketcher_Element_Line_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Line_EndPoint") ); - QIcon Sketcher_Element_Line_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Line_StartingPoint") ); - QIcon Sketcher_Element_Point_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Point_StartingPoint") ); - QIcon Sketcher_Element_Ellipse_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Ellipse_Edge_2") ); - QIcon Sketcher_Element_Ellipse_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Ellipse_CentrePoint") ); - QIcon Sketcher_Element_ArcOfEllipse_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_Edge") ); - QIcon Sketcher_Element_ArcOfEllipse_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_Centre_Point") ); - QIcon Sketcher_Element_ArcOfEllipse_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_Start_Point") ); - QIcon Sketcher_Element_ArcOfEllipse_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Elliptical_Arc_End_Point") ); - QIcon Sketcher_Element_ArcOfHyperbola_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_Edge") ); - QIcon Sketcher_Element_ArcOfHyperbola_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_Centre_Point") ); - QIcon Sketcher_Element_ArcOfHyperbola_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_Start_Point") ); - QIcon Sketcher_Element_ArcOfHyperbola_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Hyperbolic_Arc_End_Point") ); - QIcon Sketcher_Element_ArcOfParabola_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_Edge") ); - QIcon Sketcher_Element_ArcOfParabola_MidPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_Centre_Point") ); - QIcon Sketcher_Element_ArcOfParabola_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_Start_Point") ); - QIcon Sketcher_Element_ArcOfParabola_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_Parabolic_Arc_End_Point") ); - QIcon Sketcher_Element_BSpline_Edge( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_BSpline_Edge") ); - QIcon Sketcher_Element_BSpline_StartingPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_BSpline_StartPoint") ); - QIcon Sketcher_Element_BSpline_EndPoint( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_BSpline_EndPoint") ); - QIcon none( Gui::BitmapFactory().iconFromTheme("Sketcher_Element_SelectionTypeInvalid") ); + MultIcon Sketcher_Element_Arc_Edge("Sketcher_Element_Arc_Edge"); + MultIcon Sketcher_Element_Arc_EndPoint("Sketcher_Element_Arc_EndPoint"); + MultIcon Sketcher_Element_Arc_MidPoint("Sketcher_Element_Arc_MidPoint"); + MultIcon Sketcher_Element_Arc_StartingPoint("Sketcher_Element_Arc_StartingPoint"); + MultIcon Sketcher_Element_Circle_Edge("Sketcher_Element_Circle_Edge"); + MultIcon Sketcher_Element_Circle_MidPoint("Sketcher_Element_Circle_MidPoint"); + MultIcon Sketcher_Element_Line_Edge("Sketcher_Element_Line_Edge"); + MultIcon Sketcher_Element_Line_EndPoint("Sketcher_Element_Line_EndPoint"); + MultIcon Sketcher_Element_Line_StartingPoint("Sketcher_Element_Line_StartingPoint"); + MultIcon Sketcher_Element_Point_StartingPoint("Sketcher_Element_Point_StartingPoint"); + MultIcon Sketcher_Element_Ellipse_Edge("Sketcher_Element_Ellipse_Edge_2"); + MultIcon Sketcher_Element_Ellipse_MidPoint("Sketcher_Element_Ellipse_CentrePoint"); + MultIcon Sketcher_Element_ArcOfEllipse_Edge("Sketcher_Element_Elliptical_Arc_Edge"); + MultIcon Sketcher_Element_ArcOfEllipse_MidPoint("Sketcher_Element_Elliptical_Arc_Centre_Point"); + MultIcon Sketcher_Element_ArcOfEllipse_StartingPoint("Sketcher_Element_Elliptical_Arc_Start_Point"); + MultIcon Sketcher_Element_ArcOfEllipse_EndPoint("Sketcher_Element_Elliptical_Arc_End_Point"); + MultIcon Sketcher_Element_ArcOfHyperbola_Edge("Sketcher_Element_Hyperbolic_Arc_Edge"); + MultIcon Sketcher_Element_ArcOfHyperbola_MidPoint("Sketcher_Element_Hyperbolic_Arc_Centre_Point"); + MultIcon Sketcher_Element_ArcOfHyperbola_StartingPoint("Sketcher_Element_Hyperbolic_Arc_Start_Point"); + MultIcon Sketcher_Element_ArcOfHyperbola_EndPoint("Sketcher_Element_Hyperbolic_Arc_End_Point"); + MultIcon Sketcher_Element_ArcOfParabola_Edge("Sketcher_Element_Parabolic_Arc_Edge"); + MultIcon Sketcher_Element_ArcOfParabola_MidPoint("Sketcher_Element_Parabolic_Arc_Centre_Point"); + MultIcon Sketcher_Element_ArcOfParabola_StartingPoint("Sketcher_Element_Parabolic_Arc_Start_Point"); + MultIcon Sketcher_Element_ArcOfParabola_EndPoint("Sketcher_Element_Parabolic_Arc_End_Point"); + MultIcon Sketcher_Element_BSpline_Edge("Sketcher_Element_BSpline_Edge"); + MultIcon Sketcher_Element_BSpline_StartingPoint("Sketcher_Element_BSpline_StartPoint"); + MultIcon Sketcher_Element_BSpline_EndPoint("Sketcher_Element_BSpline_EndPoint"); + MultIcon none("Sketcher_Element_SelectionTypeInvalid"); + for (int i=0;ilistWidgetElements->count(); i++) { Base::Type type = static_cast(ui->listWidgetElements->item(i))->GeometryType; + bool construction = static_cast(ui->listWidgetElements->item(i))->isConstruction; + bool external = static_cast(ui->listWidgetElements->item(i))->isExternal; + auto getElementIcon = [construction, external](MultIcon icon) { + return external ? icon.External : ( construction ? icon.Construction : icon.Normal ); + }; + ui->listWidgetElements->item(i)->setIcon( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint : - (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge : - (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint : - none); + (type == Part::GeomPoint::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_Point_StartingPoint) : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Line_Edge) : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_Line_StartingPoint) : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_Line_EndPoint) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Arc_Edge) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_Arc_StartingPoint) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_Arc_EndPoint) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_Arc_MidPoint) : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Circle_Edge) : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_Circle_MidPoint) : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Ellipse_Edge) : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_Ellipse_MidPoint) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_ArcOfEllipse_Edge) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_ArcOfEllipse_StartingPoint) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_ArcOfEllipse_EndPoint) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_ArcOfEllipse_MidPoint) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_Edge) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_StartingPoint) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_EndPoint) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_MidPoint) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_ArcOfParabola_Edge) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_ArcOfParabola_StartingPoint) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_ArcOfParabola_EndPoint) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_ArcOfParabola_MidPoint) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_BSpline_Edge) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_BSpline_StartingPoint) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_BSpline_EndPoint) : + getElementIcon(none)); } } @@ -1109,27 +1114,30 @@ void TaskSketcherElements::changeEvent(QEvent *e) } } -multIcon TaskSketcherElements::tamperIcons(const char* name) +TaskSketcherElements::MultIcon::MultIcon(const char* name) { - QIcon normIcon = Gui::BitmapFactory().iconFromTheme(name); - QImage imgRef(normIcon.pixmap(normIcon.availableSizes()[0]).toImage()); - QImage imgCons(imgRef); + Normal = Gui::BitmapFactory().iconFromTheme(name); + QImage imgConstr(Normal.pixmap(Normal.availableSizes()[0]).toImage()); + QImage imgExt(imgConstr); - for(int ix=0 ; ix= 0) { if(hue > 330 || hue < 30) { clr.setHsl((hue + 240) % 360, clr.saturation(), clr.lightness(), clr.alpha()); - imgRef.setPixelColor(ix, iy, clr); + imgConstr.setPixelColor(ix, iy, clr); + + clr.setHsl(300, clr.saturation(), clr.lightness(), clr.alpha()); + imgExt.setPixelColor(ix, iy, clr); } - clr.setHsl(300, clr.saturation(), clr.lightness(), clr.alpha()); - imgCons.setPixelColor(ix, iy, clr); } } } - return {normIcon, QIcon(QPixmap::fromImage(imgRef)), QIcon(QPixmap::fromImage(imgCons))}; + Construction = QIcon(QPixmap::fromImage(imgConstr)); + External = QIcon(QPixmap::fromImage(imgExt)); + } diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.h b/src/Mod/Sketcher/Gui/TaskSketcherElements.h index 2b2f4dddd4..800c5942f6 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.h @@ -88,16 +88,20 @@ protected Q_SLOTS: }; -struct multIcon { - QIcon norm; - QIcon ref; - QIcon ext; -}; - class TaskSketcherElements : public Gui::TaskView::TaskBox, public Gui::SelectionObserver { Q_OBJECT + class MultIcon { + + public: + MultIcon(const char*); + + QIcon Normal; + QIcon Construction; + QIcon External; + }; + public: TaskSketcherElements(ViewProviderSketch *sketchView); ~TaskSketcherElements(); @@ -139,8 +143,6 @@ private: bool isautoSwitchBoxChecked; bool inhibitSelectionUpdate; - - multIcon tamperIcons(const char*); }; } //namespace SketcherGui From 3bfe6e245936afc019319fe262551e6c9b14a969 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Sun, 5 Apr 2020 16:09:18 +0200 Subject: [PATCH 03/62] [Sketcher] Fix Qt4 compatibility in MultIcon + minor improvement --- src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 129 +++++++++--------- src/Mod/Sketcher/Gui/TaskSketcherElements.h | 2 + 2 files changed, 68 insertions(+), 63 deletions(-) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index 92cde9598c..2f8dffc42d 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -709,34 +709,34 @@ void TaskSketcherElements::slotElementsChanged(void) bool construction = (*it)->Construction; ui->listWidgetElements->addItem(new ElementItem( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Point_StartingPoint.Construction : Sketcher_Element_Point_StartingPoint.Normal : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Line_Edge.Construction : Sketcher_Element_Line_Edge.Normal : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Line_StartingPoint.Construction : Sketcher_Element_Line_StartingPoint.Normal : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Line_EndPoint.Construction : Sketcher_Element_Line_EndPoint.Normal : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Arc_Edge.Construction : Sketcher_Element_Arc_Edge.Normal : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? construction ? Sketcher_Element_Arc_StartingPoint.Construction : Sketcher_Element_Arc_StartingPoint.Normal : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? construction ? Sketcher_Element_Arc_EndPoint.Construction : Sketcher_Element_Arc_EndPoint.Normal : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Arc_MidPoint.Construction : Sketcher_Element_Arc_MidPoint.Normal : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Circle_Edge.Construction : Sketcher_Element_Circle_Edge.Normal : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Circle_MidPoint.Construction : Sketcher_Element_Circle_MidPoint.Normal : - (type == Part::GeomEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_Ellipse_Edge.Construction : Sketcher_Element_Ellipse_Edge.Normal : - (type == Part::GeomEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_Ellipse_MidPoint.Construction : Sketcher_Element_Ellipse_MidPoint.Normal : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfEllipse_Edge.Construction : Sketcher_Element_ArcOfEllipse_Edge.Normal : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfEllipse_StartingPoint.Construction : Sketcher_Element_ArcOfEllipse_StartingPoint.Normal : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfEllipse_EndPoint.Construction : Sketcher_Element_ArcOfEllipse_EndPoint.Normal : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfEllipse_MidPoint.Construction : Sketcher_Element_ArcOfEllipse_MidPoint.Normal : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfHyperbola_Edge.Construction : Sketcher_Element_ArcOfHyperbola_Edge.Normal : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfHyperbola_StartingPoint.Construction : Sketcher_Element_ArcOfHyperbola_StartingPoint.Normal : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfHyperbola_EndPoint.Construction : Sketcher_Element_ArcOfHyperbola_EndPoint.Normal : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfHyperbola_MidPoint.Construction : Sketcher_Element_ArcOfHyperbola_MidPoint.Normal : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? construction ? Sketcher_Element_ArcOfParabola_Edge.Construction : Sketcher_Element_ArcOfParabola_Edge.Normal : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? construction ? Sketcher_Element_ArcOfParabola_StartingPoint.Construction : Sketcher_Element_ArcOfParabola_StartingPoint.Normal : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? construction ? Sketcher_Element_ArcOfParabola_EndPoint.Construction : Sketcher_Element_ArcOfParabola_EndPoint.Normal : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? construction ? Sketcher_Element_ArcOfParabola_MidPoint.Construction : Sketcher_Element_ArcOfParabola_MidPoint.Normal : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? construction ? Sketcher_Element_BSpline_Edge.Construction : Sketcher_Element_BSpline_Edge.Normal : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? construction ? Sketcher_Element_BSpline_StartingPoint.Construction : Sketcher_Element_BSpline_StartingPoint.Normal : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? construction ? Sketcher_Element_BSpline_EndPoint.Construction : Sketcher_Element_BSpline_EndPoint.Normal : - construction ? none.Construction : none.Normal, + (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint.getIcon(construction, false) : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge.getIcon(construction, false) : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint.getIcon(construction, false) : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint.getIcon(construction, false) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge.getIcon(construction, false) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint.getIcon(construction, false) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint.getIcon(construction, false) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint.getIcon(construction, false) : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge.getIcon(construction, false) : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint.getIcon(construction, false) : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge.getIcon(construction, false) : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint.getIcon(construction, false) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge.getIcon(construction, false) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint.getIcon(construction, false) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint.getIcon(construction, false) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint.getIcon(construction, false) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge.getIcon(construction, false) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint.getIcon(construction, false) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint.getIcon(construction, false) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint.getIcon(construction, false) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge.getIcon(construction, false) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint.getIcon(construction, false) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint.getIcon(construction, false) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint.getIcon(construction, false) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge.getIcon(construction, false) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint.getIcon(construction, false) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint.getIcon(construction, false) : + none.getIcon(construction, false), type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Point") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Point"))) : @@ -1069,40 +1069,36 @@ void TaskSketcherElements::updateIcons(int element) Base::Type type = static_cast(ui->listWidgetElements->item(i))->GeometryType; bool construction = static_cast(ui->listWidgetElements->item(i))->isConstruction; bool external = static_cast(ui->listWidgetElements->item(i))->isExternal; - - auto getElementIcon = [construction, external](MultIcon icon) { - return external ? icon.External : ( construction ? icon.Construction : icon.Normal ); - }; ui->listWidgetElements->item(i)->setIcon( - (type == Part::GeomPoint::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_Point_StartingPoint) : - (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Line_Edge) : - (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_Line_StartingPoint) : - (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_Line_EndPoint) : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Arc_Edge) : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_Arc_StartingPoint) : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_Arc_EndPoint) : - (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_Arc_MidPoint) : - (type == Part::GeomCircle::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Circle_Edge) : - (type == Part::GeomCircle::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_Circle_MidPoint) : - (type == Part::GeomEllipse::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_Ellipse_Edge) : - (type == Part::GeomEllipse::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_Ellipse_MidPoint) : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_ArcOfEllipse_Edge) : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_ArcOfEllipse_StartingPoint) : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_ArcOfEllipse_EndPoint) : - (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_ArcOfEllipse_MidPoint) : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_Edge) : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_StartingPoint) : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_EndPoint) : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_ArcOfHyperbola_MidPoint) : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_ArcOfParabola_Edge) : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_ArcOfParabola_StartingPoint) : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_ArcOfParabola_EndPoint) : - (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? getElementIcon(Sketcher_Element_ArcOfParabola_MidPoint) : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? getElementIcon(Sketcher_Element_BSpline_Edge) : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? getElementIcon(Sketcher_Element_BSpline_StartingPoint) : - (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? getElementIcon(Sketcher_Element_BSpline_EndPoint) : - getElementIcon(none)); + (type == Part::GeomPoint::getClassTypeId() && element==1) ? Sketcher_Element_Point_StartingPoint.getIcon(construction, external) : + (type == Part::GeomLineSegment::getClassTypeId() && element==0) ? Sketcher_Element_Line_Edge.getIcon(construction, external) : + (type == Part::GeomLineSegment::getClassTypeId() && element==1) ? Sketcher_Element_Line_StartingPoint.getIcon(construction, external) : + (type == Part::GeomLineSegment::getClassTypeId() && element==2) ? Sketcher_Element_Line_EndPoint.getIcon(construction, external) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==0) ? Sketcher_Element_Arc_Edge.getIcon(construction, external) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==1) ? Sketcher_Element_Arc_StartingPoint.getIcon(construction, external) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==2) ? Sketcher_Element_Arc_EndPoint.getIcon(construction, external) : + (type == Part::GeomArcOfCircle::getClassTypeId() && element==3) ? Sketcher_Element_Arc_MidPoint.getIcon(construction, external) : + (type == Part::GeomCircle::getClassTypeId() && element==0) ? Sketcher_Element_Circle_Edge.getIcon(construction, external) : + (type == Part::GeomCircle::getClassTypeId() && element==3) ? Sketcher_Element_Circle_MidPoint.getIcon(construction, external) : + (type == Part::GeomEllipse::getClassTypeId() && element==0) ? Sketcher_Element_Ellipse_Edge.getIcon(construction, external) : + (type == Part::GeomEllipse::getClassTypeId() && element==3) ? Sketcher_Element_Ellipse_MidPoint.getIcon(construction, external) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfEllipse_Edge.getIcon(construction, external) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfEllipse_StartingPoint.getIcon(construction, external) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfEllipse_EndPoint.getIcon(construction, external) : + (type == Part::GeomArcOfEllipse::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfEllipse_MidPoint.getIcon(construction, external) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge.getIcon(construction, external) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint.getIcon(construction, external) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint.getIcon(construction, external) : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint.getIcon(construction, external) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge.getIcon(construction, external) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint.getIcon(construction, external) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint.getIcon(construction, external) : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint.getIcon(construction, external) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge.getIcon(construction, external) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint.getIcon(construction, external) : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint.getIcon(construction, external) : + none.getIcon(construction, external)); } } @@ -1122,15 +1118,15 @@ TaskSketcherElements::MultIcon::MultIcon(const char* name) for(int ix=0 ; ix= 0) { if(hue > 330 || hue < 30) { clr.setHsl((hue + 240) % 360, clr.saturation(), clr.lightness(), clr.alpha()); - imgConstr.setPixelColor(ix, iy, clr); + imgConstr.setPixel(ix, iy, clr.rgba()); clr.setHsl(300, clr.saturation(), clr.lightness(), clr.alpha()); - imgExt.setPixelColor(ix, iy, clr); + imgExt.setPixel(ix, iy, clr.rgba()); } } } @@ -1140,5 +1136,12 @@ TaskSketcherElements::MultIcon::MultIcon(const char* name) } +QIcon TaskSketcherElements::MultIcon::getIcon(bool construction, bool external) const +{ + if (construction && external) return QIcon(); + if (construction) return Construction; + if (external) return External; + return Normal; +} #include "moc_TaskSketcherElements.cpp" diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.h b/src/Mod/Sketcher/Gui/TaskSketcherElements.h index 800c5942f6..493e81ac8b 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.h @@ -100,6 +100,8 @@ class TaskSketcherElements : public Gui::TaskView::TaskBox, public Gui::Selectio QIcon Normal; QIcon Construction; QIcon External; + + QIcon getIcon(bool construction, bool external) const; }; public: From 8c33c43532c0db935696fac76c9c0d4dd3f1e830 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Tue, 7 Apr 2020 12:40:36 +0200 Subject: [PATCH 04/62] [Sketcher] Improve elements color tampering with edge coloring Use HSV colorspace for maximum Qt4 compatibility --- src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index 2f8dffc42d..1a43878cab 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -1112,6 +1112,7 @@ void TaskSketcherElements::changeEvent(QEvent *e) TaskSketcherElements::MultIcon::MultIcon(const char* name) { + int hue, sat, val, alp; Normal = Gui::BitmapFactory().iconFromTheme(name); QImage imgConstr(Normal.pixmap(Normal.availableSizes()[0]).toImage()); QImage imgExt(imgConstr); @@ -1119,13 +1120,19 @@ TaskSketcherElements::MultIcon::MultIcon(const char* name) for(int ix=0 ; ix= 0) { - if(hue > 330 || hue < 30) { - clr.setHsl((hue + 240) % 360, clr.saturation(), clr.lightness(), clr.alpha()); + clr.getHsv(&hue, &sat, &val, &alp); + if (alp > 127 && hue >= 0) { + if (sat > 127 && (hue > 330 || hue < 30)) { + clr.setHsv((hue + 240) % 360, sat, val, alp); imgConstr.setPixel(ix, iy, clr.rgba()); - - clr.setHsl(300, clr.saturation(), clr.lightness(), clr.alpha()); + clr.setHsv((hue + 300) % 360, sat, val, alp); + imgExt.setPixel(ix, iy, clr.rgba()); + } + else if (sat < 64 && val > 192) + { + clr.setHsv(240, (255-sat), val, alp); + imgConstr.setPixel(ix, iy, clr.rgba()); + clr.setHsv(300, (255-sat), val, alp); imgExt.setPixel(ix, iy, clr.rgba()); } } From 855dc4c989e85e04c4cf3de31254c98fb5e71316 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sat, 29 Feb 2020 18:19:56 -0600 Subject: [PATCH 05/62] Draft: docstrings for the submodules --- src/Mod/Draft/draftguitools/__init__.py | 6 ++++++ src/Mod/Draft/draftobjects/__init__.py | 8 ++++++++ src/Mod/Draft/drafttaskpanels/__init__.py | 7 +++++++ src/Mod/Draft/drafttests/__init__.py | 8 +++++++- src/Mod/Draft/draftutils/__init__.py | 6 ++++++ src/Mod/Draft/draftviewproviders/__init__.py | 7 +++++++ 6 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Mod/Draft/draftguitools/__init__.py b/src/Mod/Draft/draftguitools/__init__.py index e69de29bb2..5566380aa1 100644 --- a/src/Mod/Draft/draftguitools/__init__.py +++ b/src/Mod/Draft/draftguitools/__init__.py @@ -0,0 +1,6 @@ +"""Commands that require the graphical user interface to work. + +These GUI commands are called by buttons, menus, contextual menus, +toolbars, or other ways that require graphical widgets. +They are normally loaded in the workbench's `InitGui.py`. +""" diff --git a/src/Mod/Draft/draftobjects/__init__.py b/src/Mod/Draft/draftobjects/__init__.py index e69de29bb2..418915c82b 100644 --- a/src/Mod/Draft/draftobjects/__init__.py +++ b/src/Mod/Draft/draftobjects/__init__.py @@ -0,0 +1,8 @@ +"""Functions and classes that define custom scripted objects. + +These classes define a custom object which is based on one of the core +objects defined in C++. The custom object inherits some basic properties, +and new properties are added. + +Most Draft objects are based on Part::Part2DObject. +""" diff --git a/src/Mod/Draft/drafttaskpanels/__init__.py b/src/Mod/Draft/drafttaskpanels/__init__.py index e69de29bb2..ca18b3c193 100644 --- a/src/Mod/Draft/drafttaskpanels/__init__.py +++ b/src/Mod/Draft/drafttaskpanels/__init__.py @@ -0,0 +1,7 @@ +"""Classes that define the task panels of GUI commands. + +These classes load `.ui` files that will be used in the task panel +of the graphical commands. +The classes define the behavior and callbacks of the different widgets +included in the `.ui` file. +""" diff --git a/src/Mod/Draft/drafttests/__init__.py b/src/Mod/Draft/drafttests/__init__.py index 4287ca8617..058cb96aef 100644 --- a/src/Mod/Draft/drafttests/__init__.py +++ b/src/Mod/Draft/drafttests/__init__.py @@ -1 +1,7 @@ -# \ No newline at end of file +"""Classes and functions used to test the workbench. + +These classes are called by the unit test launcher +that is defined in `Init.py` and `InitGui.py`. + +The unit tests are based on the standard `unittest` module. +""" diff --git a/src/Mod/Draft/draftutils/__init__.py b/src/Mod/Draft/draftutils/__init__.py index e69de29bb2..b086fa4c12 100644 --- a/src/Mod/Draft/draftutils/__init__.py +++ b/src/Mod/Draft/draftutils/__init__.py @@ -0,0 +1,6 @@ +"""Utility functions that do not require the graphical user interface. + +These functions are used throughout the Draft Workbench. +They can be called from any module, whether it uses the graphical +user interface or not. +""" diff --git a/src/Mod/Draft/draftviewproviders/__init__.py b/src/Mod/Draft/draftviewproviders/__init__.py index e69de29bb2..f634964578 100644 --- a/src/Mod/Draft/draftviewproviders/__init__.py +++ b/src/Mod/Draft/draftviewproviders/__init__.py @@ -0,0 +1,7 @@ +"""Classes that define the viewproviders of custom scripted objects. + +These classes define viewproviders for the custom objects +defined in `draftobjects`. +The viewproviders can be used only when the graphical interface +is available; in console mode the viewproviders are not available. +""" From 7f99cead72c6ece22c1c9a6ebe5a7f6056d9b9e5 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 13 Feb 2020 02:18:10 -0600 Subject: [PATCH 06/62] Draft: DraftTools.py clean up header and imports Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Also use the class name `ToDo` in `CamelCase`, as it is indicated in Python guidelines for classes. --- src/Mod/Draft/DraftTools.py | 144 +++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 66 deletions(-) diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index ab7f5428bb..aa9b520afd 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -1,50 +1,69 @@ # -*- coding: utf8 -*- -#*************************************************************************** -#* Copyright (c) 2009, 2010 Yorik van Havre * -#* Copyright (c) 2009, 2010 Ken Cline * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** - -__title__="FreeCAD Draft Workbench GUI Tools" -__author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, Dmitry Chigrin" -__url__ = "https://www.freecadweb.org" +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provide GUI commands of the Draft Workbench. +This module loads all graphical commands of the Draft Workbench, +that is, those actions that can be called from menus and buttons. +This module must be imported only when the graphical user interface +is available, for example, during the workbench definition in `IntiGui.py`. +""" ## @package DraftTools # \ingroup DRAFT -# \brief GUI Commands of the Draft workbench +# \brief Provide GUI commands of the Draft workbench. # -# This module contains all the FreeCAD commands -# of the Draft module +# This module contains all the graphical commands of the Draft workbench, +# that is, those actions that can be called from menus and buttons. -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # Generic stuff -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- +import math +import sys +from PySide import QtCore, QtGui +from pivy import coin -import sys, FreeCAD, FreeCADGui, WorkingPlane, math, Draft, Draft_rc, DraftVecUtils +import FreeCAD +import FreeCADGui from FreeCAD import Vector -from PySide import QtCore,QtGui -import DraftGui -from draftutils.todo import todo + +import Draft +import Draft_rc +import DraftGui # Initializes the DraftToolBar class +import DraftVecUtils +import WorkingPlane +from draftutils.todo import ToDo from draftutils.translate import translate import draftguitools.gui_snapper as gui_snapper import draftguitools.gui_trackers as trackers -from pivy import coin + +# The module is used to prevent complaints from code checkers (flake8) +True if Draft_rc.__name__ else False +True if DraftGui.__name__ else False + +__title__ = "FreeCAD Draft Workbench GUI Tools" +__author__ = ("Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, " + "Dmitry Chigrin") +__url__ = "https://www.freecadweb.org" if not hasattr(FreeCADGui, "Snapper"): FreeCADGui.Snapper = gui_snapper.Snapper() @@ -52,20 +71,18 @@ if not hasattr(FreeCADGui, "Snapper"): if not hasattr(FreeCAD, "DraftWorkingPlane"): FreeCAD.DraftWorkingPlane = WorkingPlane.plane() -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # Commands that have been migrated to their own modules -#--------------------------------------------------------------------------- - +# --------------------------------------------------------------------------- import draftguitools.gui_edit import draftguitools.gui_selectplane # import DraftFillet import drafttaskpanels.task_shapestring as task_shapestring import drafttaskpanels.task_scale as task_scale -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # Preflight stuff -#--------------------------------------------------------------------------- - +# --------------------------------------------------------------------------- # update the translation engine FreeCADGui.updateLocale() @@ -86,10 +103,9 @@ MODCONSTRAIN = MODS[Draft.getParam("modconstrain",0)] MODSNAP = MODS[Draft.getParam("modsnap",1)] MODALT = MODS[Draft.getParam("modalt",2)] -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # General functions -#--------------------------------------------------------------------------- - +# --------------------------------------------------------------------------- def formatUnit(exp,unit="mm"): '''returns a formatting string to set a number to the correct unit''' return FreeCAD.Units.Quantity(exp,FreeCAD.Units.Length).UserString @@ -221,12 +237,9 @@ def setMod(args,mod,state): args["AltDown"] = state - - -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # Base Class -#--------------------------------------------------------------------------- - +# --------------------------------------------------------------------------- class DraftTool: """The base class of all Draft Tools""" @@ -296,7 +309,7 @@ class DraftTool: pass self.call = None if self.commitList: - todo.delayCommit(self.commitList) + ToDo.delayCommit(self.commitList) self.commitList = [] def commit(self,name,func): @@ -334,10 +347,9 @@ class DraftTool: return qr,sup,points,fil -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # Geometry constructors -#--------------------------------------------------------------------------- - +# --------------------------------------------------------------------------- def redraw3DView(): """redraw3DView(): forces a redraw of 3d view.""" try: @@ -463,7 +475,7 @@ class Line(Creator): # object already deleted, for some reason pass else: - todo.delay(self.doc.removeObject,old) + ToDo.delay(self.doc.removeObject, old) self.obj = None def undolast(self): @@ -575,7 +587,7 @@ class Wire(Line): pts = pts.replace("Vector","FreeCAD.Vector") rems = ["FreeCAD.ActiveDocument.removeObject(\""+o.Name+"\")" for o in FreeCADGui.Selection.getSelection()] FreeCADGui.addModule("Draft") - todo.delayCommit([(translate("draft","Convert to Wire"), + ToDo.delayCommit([(translate("draft", "Convert to Wire"), ['wire = Draft.makeWire(['+pts+'])']+rems+['Draft.autogroup(wire)', 'FreeCAD.ActiveDocument.recompute()'])]) return @@ -665,7 +677,7 @@ class BSpline(Line): if self.obj: # remove temporary object, if any old = self.obj.Name - todo.delay(self.doc.removeObject,old) + ToDo.delay(self.doc.removeObject, old) if (len(self.node) > 1): try: # building command string @@ -785,7 +797,7 @@ class BezCurve(Line): if self.obj: # remove temporary object, if any old = self.obj.Name - todo.delay(self.doc.removeObject,old) + ToDo.delay(self.doc.removeObject, old) if (len(self.node) > 1): try: # building command string @@ -944,7 +956,7 @@ class CubicBezCurve(Line): if self.obj: # remove temporary object, if any old = self.obj.Name - todo.delay(self.doc.removeObject,old) + ToDo.delay(self.doc.removeObject, old) if closed == False : cleannd=(len(self.node)-1) % self.degree if cleannd == 0 : self.node = self.node[0:-3] @@ -2248,7 +2260,7 @@ class ShapeString(Creator): pass self.task = task_shapestring.ShapeStringTaskPanel() self.task.sourceCmd = self - todo.delay(FreeCADGui.Control.showDialog,self.task) + ToDo.delay(FreeCADGui.Control.showDialog, self.task) else: self.dialog = None self.text = '' @@ -2408,7 +2420,7 @@ class Move(Modifier): ghost.finalize() if cont and self.ui: if self.ui.continueMode: - todo.delayAfter(self.Activated,[]) + ToDo.delayAfter(self.Activated, []) Modifier.finish(self) def action(self,arg): @@ -2750,7 +2762,7 @@ class Rotate(Modifier): ghost.finalize() if cont and self.ui: if self.ui.continueMode: - todo.delayAfter(self.Activated,[]) + ToDo.delayAfter(self.Activated, []) Modifier.finish(self) if self.doc: self.doc.recompute() @@ -4133,9 +4145,9 @@ class Scale(Modifier): self.view.removeEventCallback("SoEvent",self.call) self.task = task_scale.ScaleTaskPanel() self.task.sourceCmd = self - todo.delay(FreeCADGui.Control.showDialog,self.task) - todo.delay(self.task.xValue.selectAll,None) - todo.delay(self.task.xValue.setFocus,None) + ToDo.delay(FreeCADGui.Control.showDialog, self.task) + ToDo.delay(self.task.xValue.selectAll, None) + ToDo.delay(self.task.xValue.setFocus, None) for ghost in self.ghosts: ghost.on() elif len(self.node) == 2: @@ -4788,7 +4800,7 @@ class Point(Creator): ['point = Draft.makePoint('+str(self.stack[0][0])+','+str(self.stack[0][1])+','+str(self.stack[0][2])+')', 'Draft.autogroup(point)', 'FreeCAD.ActiveDocument.recompute()'])) - todo.delayCommit(commitlist) + ToDo.delayCommit(commitlist) FreeCADGui.Snapper.off() self.finish() @@ -4856,7 +4868,7 @@ class Draft_Clone(Modifier): def finish(self,close=False): Modifier.finish(self,close=False) if self.moveAfterCloning: - todo.delay(FreeCADGui.runCommand,"Draft_Move") + ToDo.delay(FreeCADGui.runCommand, "Draft_Move") class ToggleGrid(): From 2ef52b390988887d4478f80ec210c8f234dff49d Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 18 Feb 2020 18:09:24 -0600 Subject: [PATCH 07/62] Draft: Draft.py clean up header and imports --- src/Mod/Draft/Draft.py | 106 +++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index c125005009..7f07386ee4 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -1,73 +1,77 @@ # -*- coding: utf-8 -*- -#*************************************************************************** -#* Copyright (c) 2009, 2010 Yorik van Havre * -#* Copyright (c) 2009, 2010 Ken Cline * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** - -#from __future__ import division - -__title__="FreeCAD Draft Workbench" -__author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, Dmitry Chigrin, Daniel Falck" -__url__ = "https://www.freecadweb.org" +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provide the Draft Workbench public programming interface. +The Draft module offers tools to create and manipulate 2D objects. +The functions in this file must be usable without requiring the +graphical user interface. +These functions can be used as the backend for the graphical commands +defined in `DraftTools.py`. +""" ## \addtogroup DRAFT # \brief Create and manipulate basic 2D objects # -# This module offers a range of tools to create and manipulate basic 2D objects +# This module offers tools to create and manipulate basic 2D objects # -# The module allows to create 2D geometric objects such as line, rectangle, circle, -# etc, modify these objects by moving, scaling or rotating them, and offers a couple of -# other utilities to manipulate further these objects, such as decompose them (downgrade) -# into smaller elements. +# The module allows to create 2D geometric objects such as line, rectangle, +# circle, etc., modify these objects by moving, scaling or rotating them, +# and offers a couple of other utilities to manipulate further these objects, +# such as decompose them (downgrade) into smaller elements. # # The functionality of the module is divided into GUI tools, usable from the -# FreeCAD interface, and corresponding python functions, that can perform the same -# operation programmatically. +# visual interface, and corresponding python functions, that can perform +# the same operation programmatically. # # @{ -"""The Draft module offers a range of tools to create and manipulate basic 2D objects""" - -import FreeCAD, math, sys, os, DraftVecUtils, WorkingPlane -import DraftGeomUtils -import draftutils.translate -from FreeCAD import Vector +import math +import sys from PySide.QtCore import QT_TRANSLATE_NOOP +import FreeCAD +from FreeCAD import Vector + +import DraftVecUtils +import WorkingPlane +from draftutils.translate import translate if FreeCAD.GuiUp: - import FreeCADGui, Draft_rc - from PySide import QtCore + import FreeCADGui + import Draft_rc gui = True - #from DraftGui import translate + # To prevent complaints from code checkers (flake8) + True if Draft_rc.__name__ else False else: - # def QT_TRANSLATE_NOOP(ctxt,txt): - # return txt - #print("FreeCAD Gui not present. Draft module will have some features disabled.") gui = False -translate = draftutils.translate.translate +__title__ = "FreeCAD Draft Workbench" +__author__ = ("Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, " + "Dmitry Chigrin, Daniel Falck") +__url__ = "https://www.freecadweb.org" -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # Backwards compatibility -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- import DraftLayer _VisGroup = DraftLayer.Layer @@ -78,9 +82,9 @@ makeLayer = DraftLayer.makeLayer # Fillet = DraftFillet.Fillet # makeFillet = DraftFillet.makeFillet -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # General functions -#--------------------------------------------------------------------------- +# --------------------------------------------------------------------------- import draftutils.utils import draftutils.gui_utils From 1fcd4ac556ec11511dd9a7a655337c2ed9f1328a Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 19 Feb 2020 01:06:52 -0600 Subject: [PATCH 08/62] Draft: Draft.py improve imports of utility functions --- src/Mod/Draft/Draft.py | 124 ++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 7f07386ee4..1e67841e31 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -72,11 +72,9 @@ __url__ = "https://www.freecadweb.org" # --------------------------------------------------------------------------- # Backwards compatibility # --------------------------------------------------------------------------- - -import DraftLayer -_VisGroup = DraftLayer.Layer -_ViewProviderVisGroup = DraftLayer.ViewProviderLayer -makeLayer = DraftLayer.makeLayer +from DraftLayer import Layer as _VisGroup +from DraftLayer import ViewProviderLayer as _ViewProviderVisGroup +from DraftLayer import makeLayer # import DraftFillet # Fillet = DraftFillet.Fillet @@ -85,94 +83,91 @@ makeLayer = DraftLayer.makeLayer # --------------------------------------------------------------------------- # General functions # --------------------------------------------------------------------------- -import draftutils.utils -import draftutils.gui_utils +from draftutils.utils import ARROW_TYPES as arrowtypes -arrowtypes = draftutils.utils.ARROW_TYPES +from draftutils.utils import stringencodecoin +from draftutils.utils import string_encode_coin -stringencodecoin = draftutils.utils.string_encode_coin -string_encode_coin = draftutils.utils.string_encode_coin +from draftutils.utils import typecheck +from draftutils.utils import type_check -typecheck = draftutils.utils.type_check -type_check = draftutils.utils.type_check +from draftutils.utils import getParamType +from draftutils.utils import get_param_type -getParamType = draftutils.utils.get_param_type -get_param_type = draftutils.utils.get_param_type +from draftutils.utils import getParam +from draftutils.utils import get_param -getParam = draftutils.utils.get_param -get_param = draftutils.utils.get_param +from draftutils.utils import setParam +from draftutils.utils import set_param -setParam = draftutils.utils.set_param -set_param = draftutils.utils.set_param +from draftutils.utils import precision +from draftutils.utils import tolerance +from draftutils.utils import epsilon -precision = draftutils.utils.precision -tolerance = draftutils.utils.tolerance -epsilon = draftutils.utils.epsilon +from draftutils.utils import getRealName +from draftutils.utils import get_real_name -getRealName = draftutils.utils.get_real_name -get_real_name = draftutils.utils.get_real_name +from draftutils.utils import getType +from draftutils.utils import get_type -getType = draftutils.utils.get_type -get_type = draftutils.utils.get_type +from draftutils.utils import getObjectsOfType +from draftutils.utils import get_objects_of_type -getObjectsOfType = draftutils.utils.get_objects_of_type -get_objects_of_type = draftutils.utils.get_objects_of_type +from draftutils.utils import isClone +from draftutils.utils import is_clone -get3DView = draftutils.gui_utils.get_3d_view -get_3d_view = draftutils.gui_utils.get_3d_view +from draftutils.utils import getGroupNames +from draftutils.utils import get_group_names -isClone = draftutils.utils.is_clone -is_clone = draftutils.utils.is_clone +from draftutils.utils import ungroup -getGroupNames = draftutils.utils.get_group_names -get_group_names = draftutils.utils.get_group_names +from draftutils.utils import getGroupContents +from draftutils.utils import get_group_contents -ungroup = draftutils.utils.ungroup +from draftutils.utils import printShape +from draftutils.utils import print_shape -autogroup = draftutils.gui_utils.autogroup +from draftutils.utils import compareObjects +from draftutils.utils import compare_objects -dimSymbol = draftutils.gui_utils.dim_symbol -dim_symbol = draftutils.gui_utils.dim_symbol +from draftutils.utils import shapify -dimDash = draftutils.gui_utils.dim_dash -dim_dash = draftutils.gui_utils.dim_dash +from draftutils.utils import loadSvgPatterns +from draftutils.utils import load_svg_patterns -shapify = draftutils.utils.shapify +from draftutils.utils import svgpatterns +from draftutils.utils import svg_patterns -getGroupContents = draftutils.utils.get_group_contents -get_group_contents = draftutils.utils.get_group_contents +from draftutils.utils import getMovableChildren +from draftutils.utils import get_movable_children -removeHidden = draftutils.gui_utils.remove_hidden -remove_hidden = draftutils.gui_utils.remove_hidden +from draftutils.gui_utils import get3DView +from draftutils.gui_utils import get_3d_view -printShape = draftutils.utils.print_shape -print_shape = draftutils.utils.print_shape +from draftutils.gui_utils import autogroup -compareObjects = draftutils.utils.compare_objects -compare_objects = draftutils.utils.compare_objects +from draftutils.gui_utils import dimSymbol +from draftutils.gui_utils import dim_symbol -formatObject = draftutils.gui_utils.format_object -format_object = draftutils.gui_utils.format_object +from draftutils.gui_utils import dimDash +from draftutils.gui_utils import dim_dash -getSelection = draftutils.gui_utils.get_selection -get_selection = draftutils.gui_utils.get_selection +from draftutils.gui_utils import removeHidden +from draftutils.gui_utils import remove_hidden -getSelectionEx = draftutils.gui_utils.get_selection_ex -get_selection_ex = draftutils.gui_utils.get_selection_ex +from draftutils.gui_utils import formatObject +from draftutils.gui_utils import format_object -select = draftutils.gui_utils.select +from draftutils.gui_utils import getSelection +from draftutils.gui_utils import get_selection -loadSvgPatterns = draftutils.utils.load_svg_patterns -load_svg_patterns = draftutils.utils.load_svg_patterns +from draftutils.gui_utils import getSelectionEx +from draftutils.gui_utils import get_selection_ex -svgpatterns = draftutils.utils.svg_patterns -svg_patterns = draftutils.utils.svg_patterns +from draftutils.gui_utils import select -loadTexture = draftutils.gui_utils.load_texture -load_texture = draftutils.gui_utils.load_texture - -getMovableChildren = draftutils.utils.get_movable_children -get_movable_children = draftutils.utils.get_movable_children +from draftutils.gui_utils import loadTexture +from draftutils.gui_utils import load_texture def makeCircle(radius, placement=None, face=None, startangle=None, endangle=None, support=None): @@ -3879,6 +3874,7 @@ class _ViewProviderDimension(_ViewProviderDraft): return mode def is_linked_to_circle(self): + import DraftGeomUtils _obj = self.Object if _obj.LinkedGeometry and len(_obj.LinkedGeometry) == 1: lobj = _obj.LinkedGeometry[0][0] From eafba705a4963472a8beb25e2ae38815c6ebc816 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 26 Feb 2020 00:59:55 -0600 Subject: [PATCH 09/62] Draft: utils.py clean up header and imports Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Also use the new `messages` module to provide the functions to print text to the console. --- src/Mod/Draft/draftutils/utils.py | 66 ++++++++++--------------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/src/Mod/Draft/draftutils/utils.py b/src/Mod/Draft/draftutils/utils.py index 8b75b4f6c7..bb747008e4 100644 --- a/src/Mod/Draft/draftutils/utils.py +++ b/src/Mod/Draft/draftutils/utils.py @@ -1,13 +1,4 @@ # -*- coding: utf-8 -*- -"""This module provides utility functions for the Draft Workbench. - -This module should contain auxiliary functions which don't require -the graphical user interface (GUI). -""" -## @package utils -# \ingroup DRAFT -# \brief This module provides utility functions for the Draft Workbench - # *************************************************************************** # * (c) 2009, 2010 * # * Yorik van Havre , Ken Cline * @@ -32,52 +23,35 @@ the graphical user interface (GUI). # * USA * # * * # *************************************************************************** +"""Provides utility functions for the Draft Workbench. + +This module contains auxiliary functions which can be used +in other modules of the workbench, and which don't require +the graphical user interface (GUI). +""" +## @package utils +# \ingroup DRAFT +# \brief This module provides utility functions for the Draft Workbench import os -import FreeCAD from PySide import QtCore + +import FreeCAD import Draft_rc +from draftutils.messages import _msg +from draftutils.translate import _tr + App = FreeCAD # The module is used to prevent complaints from code checkers (flake8) True if Draft_rc else False - -if App.GuiUp: - # The right translate function needs to be imported here - # from DraftGui import translate - - # At the moment it is the same function as without GUI - def translate(context, text): - return text -else: - def translate(context, text): - return text - - -def _tr(text): - """Function to translate with the context set.""" - return translate("Draft", text) - - -def _msg(text, end="\n"): - App.Console.PrintMessage(text + end) - - -def _wrn(text, end="\n"): - App.Console.PrintWarning(text + end) - - -def _log(text, end="\n"): - App.Console.PrintLog(text + end) - - ARROW_TYPES = ["Dot", "Circle", "Arrow", "Tick", "Tick-2"] arrowtypes = ARROW_TYPES def string_encode_coin(ustr): - """Encode a unicode object to be used as a string in coin + """Encode a unicode object to be used as a string in coin. Parameters ---------- @@ -132,7 +106,7 @@ def type_check(args_and_types, name="?"): Defaults to `'?'`. The name of the check. Raises - ------- + ------ TypeError If the first element in the tuple is not an instance of the second element, it raises `Draft.name`. @@ -265,7 +239,7 @@ getParam = get_param def set_param(param, value): - """Set a Draft parameter with the given value + """Set a Draft parameter with the given value. The parameter database is located in the tree :: @@ -981,7 +955,7 @@ getMovableChildren = get_movable_children def utf8_decode(text): - """Decode the input string and return a unicode string. + r"""Decode the input string and return a unicode string. Python 2: :: @@ -1017,14 +991,14 @@ def utf8_decode(text): >>> "Aá".decode("utf-8") >>> b"Aá".decode("utf-8") - u'A\\xe1' + u'A\xe1' In Python 2 the unicode string is prefixed with `u`, and unicode characters are replaced by their two-digit hexadecimal representation, or four digit unicode escape. >>> "AáBẃCñ".decode("utf-8") - u'A\\xe1B\\u1e83C\\xf1' + u'A\xe1B\u1e83C\xf1' In Python 2 it will always return a `unicode` object. From 0714ab786f5c725bf32b2bd4e9aeff21879434db Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 26 Feb 2020 01:27:15 -0600 Subject: [PATCH 10/62] Draft: gui_utils.py clean up imports Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Also use the new `messages` module to provide the functions to print text to the console. --- src/Mod/Draft/draftutils/gui_utils.py | 39 +++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Mod/Draft/draftutils/gui_utils.py b/src/Mod/Draft/draftutils/gui_utils.py index d9056b8480..e3b76ece5d 100644 --- a/src/Mod/Draft/draftutils/gui_utils.py +++ b/src/Mod/Draft/draftutils/gui_utils.py @@ -1,12 +1,3 @@ -"""This module provides GUI utility functions for the Draft Workbench. - -This module should contain auxiliary functions which require -the graphical user interface (GUI). -""" -## @package gui_utils -# \ingroup DRAFT -# \brief This module provides utility functions for the Draft Workbench - # *************************************************************************** # * (c) 2009, 2010 * # * Yorik van Havre , Ken Cline * @@ -31,24 +22,32 @@ the graphical user interface (GUI). # * USA * # * * # *************************************************************************** +"""Provides GUI utility functions for the Draft Workbench. +This module contains auxiliary functions which can be used +in other modules of the workbench, and which require +the graphical user interface (GUI), as they access the view providers +of the objects or the 3D view. +""" +## @package gui_utils +# \ingroup DRAFT +# \brief This module provides GUI utility functions for the Draft Workbench + +import math +import os +import six import FreeCAD -from .utils import _msg -from .utils import _wrn -# from .utils import _log -from .utils import _tr -from .utils import getParam -from .utils import get_type -import os -import math -import six +from draftutils.messages import _msg, _wrn +from draftutils.utils import getParam +from draftutils.utils import get_type +from draftutils.translate import _tr, translate if FreeCAD.GuiUp: import FreeCADGui from pivy import coin from PySide import QtGui -# from PySide import QtSvg # for load_texture + # from PySide import QtSvg # for load_texture def get_3d_view(): @@ -80,7 +79,7 @@ get3DView = get_3d_view def autogroup(obj): - """Adds a given object to the defined Draft autogroup, if applicable. + """Add a given object to the defined Draft autogroup, if applicable. This function only works if the graphical interface is available. It checks that the `FreeCAD.draftToolBar` class is available, From 79233ee4d015a12cba231d5a127706b8d1ee8584 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 26 Feb 2020 11:16:53 -0600 Subject: [PATCH 11/62] Draft: todo.py clean up header, imports and messages Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Also use the new `messages` module to provide the functions to print text to the console. Use two `DEBUG` variables to print information about the `ToDo` class in order to see the scheduled commands when the graphical commands are executed. --- src/Mod/Draft/draftutils/todo.py | 82 +++++++++++++++++++------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/src/Mod/Draft/draftutils/todo.py b/src/Mod/Draft/draftutils/todo.py index b5afd97369..d2da1bf4dc 100644 --- a/src/Mod/Draft/draftutils/todo.py +++ b/src/Mod/Draft/draftutils/todo.py @@ -1,12 +1,3 @@ -"""This module provides the ToDo class for the Draft Workbench. - -This module provides the ToDo class to delay the commit of commands, -which depends on QtCore.QTimer. -""" -## @package todo -# \ingroup DRAFT -# \brief This module provides the ToDo class for the Draft Workbench. - # *************************************************************************** # * (c) 2009, Yorik van Havre * # * (c) 2019 Eliud Cabrera Castillo * @@ -30,20 +21,33 @@ which depends on QtCore.QTimer. # * USA * # * * # *************************************************************************** +"""Provides the ToDo class for the Draft Workbench. + +The ToDo class is used to delay the commit of commands for later execution. +This is necessary when a GUI command needs to manipulate the 3D view +in such a way that a callback would crash Coin. +The ToDo class essentially calls `QtCore.QTimer.singleShot` +to execute the instructions stored in internal lists. +""" +## @package todo +# \ingroup DRAFT +# \brief This module provides the ToDo class for the Draft Workbench. -import sys import six +import sys import traceback -import FreeCAD -import FreeCADGui from PySide import QtCore +import FreeCAD +import FreeCADGui +from draftutils.messages import _msg, _wrn, _log __title__ = "FreeCAD Draft Workbench, Todo class" __author__ = "Yorik van Havre " __url__ = ["http://www.freecadweb.org"] _DEBUG = 0 +_DEBUG_inner = 0 class ToDo: @@ -114,29 +118,31 @@ class ToDo: The lists are `itinerary`, `commitlist` and `afteritinerary`. """ if _DEBUG: - print("Debug: doing delayed tasks.\n" - "itinerary: {0}\n" - "commitlist: {1}\n" - "afteritinerary: {2}\n".format(todo.itinerary, - todo.commitlist, - todo.afteritinerary)) + _msg("Debug: doing delayed tasks.\n" + "itinerary: {0}\n" + "commitlist: {1}\n" + "afteritinerary: {2}\n".format(todo.itinerary, + todo.commitlist, + todo.afteritinerary)) try: for f, arg in todo.itinerary: try: - # print("debug: executing", f) + if _DEBUG_inner: + _msg("Debug: executing.\n" + "function: {}\n".format(f)) if arg or (arg is False): f(arg) else: f() except Exception: - FreeCAD.Console.PrintLog(traceback.format_exc()) + _log(traceback.format_exc()) wrn = ("ToDo.doTasks, Unexpected error:\n" "{0}\n" "in {1}({2})".format(sys.exc_info()[0], f, arg)) - FreeCAD.Console.PrintWarning(wrn) + _wrn(wrn) except ReferenceError: - print("Debug: ToDo.doTasks: " - "queue contains a deleted object, skipping") + _wrn("Debug: ToDo.doTasks: " + "queue contains a deleted object, skipping") todo.itinerary = [] if todo.commitlist: @@ -144,7 +150,9 @@ class ToDo: if six.PY2: if isinstance(name, six.text_type): name = name.encode("utf8") - # print("debug: committing " + str(name)) + if _DEBUG_inner: + _msg("Debug: committing.\n" + "name: {}\n".format(name)) try: name = str(name) FreeCAD.ActiveDocument.openTransaction(name) @@ -155,11 +163,11 @@ class ToDo: func() FreeCAD.ActiveDocument.commitTransaction() except Exception: - FreeCAD.Console.PrintLog(traceback.format_exc()) + _log(traceback.format_exc()) wrn = ("ToDo.doTasks, Unexpected error:\n" "{0}\n" - "in {1}".format(sys.exec_info()[0], func)) - FreeCAD.Console.PrintWarning(wrn) + "in {1}".format(sys.exc_info()[0], func)) + _wrn(wrn) # Restack Draft screen widgets after creation if hasattr(FreeCADGui, "Snapper"): FreeCADGui.Snapper.restack() @@ -167,17 +175,19 @@ class ToDo: for f, arg in todo.afteritinerary: try: - # print("debug: executing", f) + if _DEBUG_inner: + _msg("Debug: executing after.\n" + "function: {}\n".format(f)) if arg: f(arg) else: f() except Exception: - FreeCAD.Console.PrintLog(traceback.format_exc()) + _log(traceback.format_exc()) wrn = ("ToDo.doTasks, Unexpected error:\n" "{0}\n" "in {1}({2})".format(sys.exc_info()[0], f, arg)) - FreeCAD.Console.PrintWarning(wrn) + _wrn(wrn) todo.afteritinerary = [] @staticmethod @@ -207,7 +217,9 @@ class ToDo: :: f(arg) """ - # print("debug: delaying", f) + if _DEBUG: + _msg("Debug: delaying.\n" + "function: {}\n".format(f)) if todo.itinerary == []: QtCore.QTimer.singleShot(0, todo.doTasks) todo.itinerary.append((f, arg)) @@ -235,7 +247,9 @@ class ToDo: See the attributes of the `ToDo` class for more information. """ - # print("debug: delaying commit", cl) + if _DEBUG: + _msg("Debug: delaying commit.\n" + "commitlist: {}\n".format(cl)) QtCore.QTimer.singleShot(0, todo.doTasks) todo.commitlist = cl @@ -255,7 +269,9 @@ class ToDo: Finally, it will build the tuple `(f, arg)` and append it to the `afteritinerary` list. """ - # print("debug: delaying", f) + if _DEBUG: + _msg("Debug: delaying after.\n" + "function: {}\n".format(f)) if todo.afteritinerary == []: QtCore.QTimer.singleShot(0, todo.doTasks) todo.afteritinerary.append((f, arg)) From 09cc7e02648cca604bef6ffd1557cdf1d9e5ccf1 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 26 Feb 2020 13:44:11 -0600 Subject: [PATCH 12/62] Draft: gui_snapper.py clean up imports and spaces Small spacing fixes like imports in separate lines for more clarity. Also use the `OrderedDict` prefixed with the `collections` module. --- src/Mod/Draft/draftguitools/gui_snapper.py | 131 ++++++++++++--------- 1 file changed, 73 insertions(+), 58 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index 189207f30a..b9a739cfd5 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -18,26 +18,37 @@ # * USA * # * * # *************************************************************************** +"""Provide the Snapper class to control snapping in the Draft Workbench. + +This module provides tools to handle point snapping and +everything that goes with it (toolbar buttons, cursor icons, etc.). +It also creates the Draft grid, which is actually a tracker +defined by `gui_trackers.gridTracker`. +""" +## @package gui_snapper +# \ingroup DRAFT +# \brief Snapper class to control snapping in the Draft Workbench. +# +# This module provides tools to handle point snapping and +# everything that goes with it (toolbar buttons, cursor icons, etc.). + +import collections as coll +import itertools +import math +from pivy import coin +from PySide import QtCore, QtGui + +import FreeCAD +import FreeCADGui +import Draft +import DraftVecUtils +from FreeCAD import Vector +import draftguitools.gui_trackers as trackers __title__ = "FreeCAD Draft Snap tools" __author__ = "Yorik van Havre" __url__ = "https://www.freecadweb.org" -## @package DraftSnap -# \ingroup DRAFT -# \brief Snapping system used by Draft & Arch workbenches -# -# This module provides tools to handle point snapping and -# everything that goes with it (toolbar buttons, cursor icons, etc) - - -import FreeCAD, FreeCADGui, math, Draft, DraftVecUtils, itertools -import draftguitools.gui_trackers as trackers -from collections import OrderedDict -from FreeCAD import Vector -from pivy import coin -from PySide import QtCore, QtGui - class Snapper: """Classes to manage snapping in Draft and Arch. @@ -63,7 +74,7 @@ class Snapper: def __init__(self): self.activeview = None - self.lastObj = [None,None] + self.lastObj = [None, None] self.maxEdges = 0 self.radius = 0 self.constraintAxis = None @@ -71,9 +82,9 @@ class Snapper: self.affinity = None self.mask = None self.cursorMode = None - if Draft.getParam("maxSnap",0): - self.maxEdges = Draft.getParam("maxSnapEdges",0) - self.snapStyle = Draft.getParam("snapStyle",0) + if Draft.getParam("maxSnap", 0): + self.maxEdges = Draft.getParam("maxSnapEdges", 0) + self.snapStyle = Draft.getParam("snapStyle", 0) # we still have no 3D view when the draft module initializes self.tracker = None @@ -90,9 +101,12 @@ class Snapper: self.active = True self.forceGridOff = False self.lastExtensions = [] - # the trackers are stored in lists because there can be several views, each with its own set - self.trackers = [[],[],[],[],[],[],[],[],[],[]] # view, grid, snap, extline, radius, dim1, dim2, trackLine, extline2, crosstrackers - self.polarAngles = [90,45] + # the trackers are stored in lists because there can be several views, + # each with its own set + # view, grid, snap, extline, radius, dim1, dim2, trackLine, + # extline2, crosstrackers + self.trackers = [[], [], [], [], [], [], [], [], [], []] + self.polarAngles = [90, 45] self.selectMode = False self.holdTracker = None self.holdPoints = [] @@ -103,44 +117,45 @@ class Snapper: # the snapmarker has "dot","circle" and "square" available styles if self.snapStyle: - self.mk = OrderedDict([('passive', 'empty'), - ('extension', 'empty'), - ('parallel', 'empty'), - ('grid', 'quad'), - ('endpoint', 'quad'), - ('midpoint', 'quad'), - ('perpendicular','quad'), - ('angle', 'quad'), - ('center', 'quad'), - ('ortho', 'quad'), - ('intersection', 'quad'), - ('special', 'quad')]) + self.mk = coll.OrderedDict([('passive', 'empty'), + ('extension', 'empty'), + ('parallel', 'empty'), + ('grid', 'quad'), + ('endpoint', 'quad'), + ('midpoint', 'quad'), + ('perpendicular', 'quad'), + ('angle', 'quad'), + ('center', 'quad'), + ('ortho', 'quad'), + ('intersection', 'quad'), + ('special', 'quad')]) else: - self.mk = OrderedDict([('passive', 'circle'), - ('extension', 'circle'), - ('parallel', 'circle'), - ('grid', 'circle'), - ('endpoint', 'dot'), - ('midpoint', 'square'), - ('perpendicular','dot'), - ('angle', 'square'), - ('center', 'dot'), - ('ortho', 'dot'), - ('intersection', 'dot'), - ('special', 'dot')]) + self.mk = coll.OrderedDict([('passive', 'circle'), + ('extension', 'circle'), + ('parallel', 'circle'), + ('grid', 'circle'), + ('endpoint', 'dot'), + ('midpoint', 'square'), + ('perpendicular', 'dot'), + ('angle', 'square'), + ('center', 'dot'), + ('ortho', 'dot'), + ('intersection', 'dot'), + ('special', 'dot')]) - self.cursors = OrderedDict([('passive', ':/icons/Snap_Near.svg'), - ('extension', ':/icons/Snap_Extension.svg'), - ('parallel', ':/icons/Snap_Parallel.svg'), - ('grid', ':/icons/Snap_Grid.svg'), - ('endpoint', ':/icons/Snap_Endpoint.svg'), - ('midpoint', ':/icons/Snap_Midpoint.svg'), - ('perpendicular', ':/icons/Snap_Perpendicular.svg'), - ('angle', ':/icons/Snap_Angle.svg'), - ('center', ':/icons/Snap_Center.svg'), - ('ortho', ':/icons/Snap_Ortho.svg'), - ('intersection', ':/icons/Snap_Intersection.svg'), - ('special', ':/icons/Snap_Special.svg')]) + self.cursors = \ + coll.OrderedDict([('passive', ':/icons/Snap_Near.svg'), + ('extension', ':/icons/Snap_Extension.svg'), + ('parallel', ':/icons/Snap_Parallel.svg'), + ('grid', ':/icons/Snap_Grid.svg'), + ('endpoint', ':/icons/Snap_Endpoint.svg'), + ('midpoint', ':/icons/Snap_Midpoint.svg'), + ('perpendicular', ':/icons/Snap_Perpendicular.svg'), + ('angle', ':/icons/Snap_Angle.svg'), + ('center', ':/icons/Snap_Center.svg'), + ('ortho', ':/icons/Snap_Ortho.svg'), + ('intersection', ':/icons/Snap_Intersection.svg'), + ('special', ':/icons/Snap_Special.svg')]) def cstr(self, lastpoint, constrain, point): "constrains if needed" From b9968d2aa311c3af8fd34521ffa2ee6640747c52 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 26 Feb 2020 16:16:27 -0600 Subject: [PATCH 13/62] Draft: gui_trackers.py clean up imports and spaces Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Also use the `ToDo` class with this new name following Python guidelines. --- src/Mod/Draft/draftguitools/gui_trackers.py | 111 +++++++++++--------- 1 file changed, 62 insertions(+), 49 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py index 1e952cf58b..7e5f343b7a 100644 --- a/src/Mod/Draft/draftguitools/gui_trackers.py +++ b/src/Mod/Draft/draftguitools/gui_trackers.py @@ -1,44 +1,57 @@ -#*************************************************************************** -#* Copyright (c) 2011 Yorik van Havre * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** +# *************************************************************************** +# * Copyright (c) 2011 Yorik van Havre * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provide Coin based objects used for previews in the Draft Workbench. -__title__="FreeCAD Draft Trackers" +This module provides Coin (pivy) based objects +that are used by the Draft Workbench to draw temporary geometry, +that is, previews, of the real objects that will be created on the 3D view. +""" +## @package DraftTrackers +# \ingroup DRAFT +# \brief Provide Coin based objects used for previews in the Draft Workbench. +# +# This module provides Coin (pivy) based objects +# that are used by the Draft Workbench to draw temporary geometry, +# that is, previews, of the real objects that will be created on the 3D view. + +import math +from pivy import coin + +import FreeCAD +import FreeCADGui +import Draft +import DraftVecUtils +from FreeCAD import Vector +from draftutils.todo import ToDo + +__title__ = "FreeCAD Draft Trackers" __author__ = "Yorik van Havre" __url__ = "https://www.freecadweb.org" -## @package DraftTrackers -# \ingroup DRAFT -# \brief Custom Pivy-based objects used by the Draft workbench -# -# This module contains a collection of Coin3D (pivy)-based objects -# that are used by the Draft workbench to draw temporary geometry -# on the 3D view - -import FreeCAD,FreeCADGui,math,Draft, DraftVecUtils -from FreeCAD import Vector -from pivy import coin - class Tracker: - """A generic Draft Tracker, to be used by other specific trackers""" - def __init__(self,dotted=False,scolor=None,swidth=None,children=[],ontop=False,name=None): + """A generic Draft Tracker, to be used by other specific trackers.""" + + def __init__(self, dotted=False, scolor=None, swidth=None, + children=[], ontop=False, name=None): global Part, DraftGeomUtils import Part, DraftGeomUtils self.ontop = ontop @@ -50,37 +63,35 @@ class Tracker: if dotted: drawstyle.style = coin.SoDrawStyle.LINES drawstyle.lineWeight = 3 - drawstyle.linePattern = 0x0f0f #0xaa + drawstyle.linePattern = 0x0f0f # 0xaa node = coin.SoSeparator() for c in [drawstyle, color] + children: node.addChild(c) - self.switch = coin.SoSwitch() # this is the on/off switch + self.switch = coin.SoSwitch() # this is the on/off switch if name: self.switch.setName(name) self.switch.addChild(node) self.switch.whichChild = -1 self.Visible = False - from DraftGui import todo - todo.delay(self._insertSwitch, self.switch) + ToDo.delay(self._insertSwitch, self.switch) def finalize(self): - from DraftGui import todo - todo.delay(self._removeSwitch, self.switch) + ToDo.delay(self._removeSwitch, self.switch) self.switch = None def _insertSwitch(self, switch): '''insert self.switch into the scene graph. Must not be called from an event handler (or other scene graph traversal).''' - sg=Draft.get3DView().getSceneGraph() + sg = Draft.get3DView().getSceneGraph() if self.ontop: - sg.insertChild(switch,0) + sg.insertChild(switch, 0) else: sg.addChild(switch) def _removeSwitch(self, switch): '''remove self.switch from the scene graph. As with _insertSwitch, must not be called during scene graph traversal).''' - sg=Draft.get3DView().getSceneGraph() + sg = Draft.get3DView().getSceneGraph() if sg.findChild(switch) >= 0: sg.removeChild(switch) @@ -96,7 +107,7 @@ class Tracker: '''lowers the tracker to the bottom of the scenegraph, so it doesn't obscure the other objects''' if self.switch: - sg=Draft.get3DView().getSceneGraph() + sg = Draft.get3DView().getSceneGraph() sg.removeChild(self.switch) sg.addChild(self.switch) @@ -104,12 +115,14 @@ class Tracker: '''raises the tracker to the top of the scenegraph, so it obscures the other objects''' if self.switch: - sg=Draft.get3DView().getSceneGraph() + sg = Draft.get3DView().getSceneGraph() sg.removeChild(self.switch) - sg.insertChild(self.switch,0) - + sg.insertChild(self.switch, 0) + + class snapTracker(Tracker): - """A Snap Mark tracker, used by tools that support snapping""" + """Define Snap Mark tracker, used by tools that support snapping.""" + def __init__(self): color = coin.SoBaseColor() color.rgb = FreeCADGui.draftToolBar.getDefaultColor("snap") From 5125c584bd46d0073d10261c8a120849276c3859 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Fri, 28 Feb 2020 00:19:33 -0600 Subject: [PATCH 14/62] Draft: DraftVecUtils.py clean up imports and messages Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Also use the new `messages` module to provide the functions to print text to the console. Also use `Matrix` prefixed by the `FreeCAD` module. --- src/Mod/Draft/DraftVecUtils.py | 65 +++++++++++++++++----------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/Mod/Draft/DraftVecUtils.py b/src/Mod/Draft/DraftVecUtils.py index d829e36a2a..87fbfbf7d5 100644 --- a/src/Mod/Draft/DraftVecUtils.py +++ b/src/Mod/Draft/DraftVecUtils.py @@ -1,19 +1,3 @@ -## \defgroup DRAFTVECUTILS DraftVecUtils -# \ingroup UTILITIES -# \brief Vector math utilities used in Draft workbench -# -# Vector math utilities used primarily in the Draft workbench -# but which can also be used in other workbenches and in macros. -"""\defgroup DRAFTVECUTILS DraftVecUtils -\ingroup UTILITIES -\brief Vector math utilities used in Draft workbench - -Vector math utilities used primarily in the Draft workbench -but which can also be used in other workbenches and in macros. -""" -# Check code with -# flake8 --ignore=E226,E266,E401,W503 - # *************************************************************************** # * Copyright (c) 2009, 2010 Yorik van Havre * # * Copyright (c) 2009, 2010 Ken Cline * @@ -35,19 +19,32 @@ but which can also be used in other workbenches and in macros. # * USA * # * * # *************************************************************************** +"""Provide vector math utilities used in the Draft workbench. + +Vector math utilities used primarily in the Draft workbench +but which can also be used in other workbenches and in macros. +""" +## \defgroup DRAFTVECUTILS DraftVecUtils +# \ingroup UTILITIES +# \brief Vector math utilities used in Draft workbench +# +# Vector math utilities used primarily in the Draft workbench +# but which can also be used in other workbenches and in macros. + +# Check code with +# flake8 --ignore=E226,E266,E401,W503 + +import math +import sys + +import FreeCAD +from FreeCAD import Vector +import draftutils.messages as messages __title__ = "FreeCAD Draft Workbench - Vector library" __author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline" __url__ = "https://www.freecadweb.org" -## \addtogroup DRAFTVECUTILS -# @{ - -import sys -import math, FreeCAD -from FreeCAD import Vector, Matrix -from FreeCAD import Console as FCC - # Python 2 has two integer types, int and long. # In Python 3 there is no 'long' anymore, so make it 'int'. try: @@ -57,6 +54,9 @@ except NameError: params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") +## \addtogroup DRAFTVECUTILS +# @{ + def precision(): """Get the number of decimal numbers used for precision. @@ -97,16 +97,15 @@ def typecheck(args_and_types, name="?"): Defaults to `'?'`. The name of the check. Raises - ------- + ------ TypeError If the first element in the tuple is not an instance of the second element. """ for v, t in args_and_types: if not isinstance(v, t): - _msg = ("typecheck[" + str(name) + "]: " - + str(v) + " is not " + str(t) + "\n") - FCC.PrintWarning(_msg) + _msg = "typecheck[{0}]: {1} is not {2}".format(name, v, t) + messages._wrn(_msg) raise TypeError("fcvec." + str(name)) @@ -208,7 +207,7 @@ def equals(u, v): The second vector. Returns - ------ + ------- bool `True` if the vectors are within the precision, `False` otherwise. """ @@ -497,9 +496,9 @@ def rotate(u, angle, axis=Vector(0, 0, 1)): ys = y * s zs = z * s - m = Matrix(c + x*x*t, xyt - zs, xzt + ys, 0, - xyt + zs, c + y*y*t, yzt - xs, 0, - xzt - ys, yzt + xs, c + z*z*t, 0) + m = FreeCAD.Matrix(c + x*x*t, xyt - zs, xzt + ys, 0, + xyt + zs, c + y*y*t, yzt - xs, 0, + xzt - ys, yzt + xs, c + z*z*t, 0) return m.multiply(u) @@ -547,7 +546,7 @@ def getRotation(vector, reference=Vector(1, 0, 0)): def isNull(vector): - """Returns `False` if each of the components of the vector is zero. + """Return False if each of the components of the vector is zero. Due to rounding errors, an element is probably never going to be exactly zero. Therefore, it rounds the element by the number From 106cd631e02668a9d10652ae302b94cdd1a73e77 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Fri, 28 Feb 2020 23:44:18 -0600 Subject: [PATCH 15/62] Draft: WorkingPlane.py clean up imports and docstrings Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Cleaned up the class docstring, so it is in only one place below the class definition. Also small fixes in the docstrings of the class methods. The class is now in upper case `Plane` to conform with Python guidelines. An alias in lowercase `plane` is still provided for compatibility purposes; this will be deprecated in the future. --- src/Mod/Draft/WorkingPlane.py | 132 ++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index f0910f28e5..7efe0f4c81 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -1,20 +1,3 @@ -## @package WorkingPlane -# \ingroup DRAFT -# \brief This module handles the Working Plane and grid of the Draft module. -# -# This module provides the plane class which provides a virtual working plane -# in FreeCAD and a couple of utility functions. -"""@package WorkingPlane -\ingroup DRAFT -\brief This module handles the working plane and grid of the Draft Workbench. - -This module provides the plane class which provides a virtual working plane -in FreeCAD and a couple of utility functions. -The working plane is mostly intended to be used in the Draft Workbench -to draw 2D objects in various orientations, not only in the standard XY, -YZ, and XZ planes. -""" - # *************************************************************************** # * Copyright (c) 2009, 2010 Ken Cline * # * * @@ -35,64 +18,87 @@ YZ, and XZ planes. # * USA * # * * # *************************************************************************** +"""Provide the working plane code and utilities for the Draft Workbench. +This module provides the plane class which provides a virtual working plane +in FreeCAD and a couple of utility functions. +The working plane is mostly intended to be used in the Draft Workbench +to draw 2D objects in various orientations, not only in the standard XY, +YZ, and XZ planes. +""" +## @package WorkingPlane +# \ingroup DRAFT +# \brief This module handles the Working Plane and grid of the Draft module. +# +# This module provides the plane class which provides a virtual working plane +# in FreeCAD and a couple of utility functions. -import FreeCAD, math, DraftVecUtils +import math + +import FreeCAD +import DraftVecUtils from FreeCAD import Vector -from FreeCAD import Console as FCC __title__ = "FreeCAD Working Plane utility" __author__ = "Ken Cline" __url__ = "https://www.freecadweb.org" -class plane: +class Plane: """A WorkPlane object. + Parameters + ---------- + u: Base::Vector3, optional + An axis (vector) that helps define the working plane. + It defaults to `(1, 0, 0)`, or the +X axis. + + v: Base::Vector3, optional + An axis (vector) that helps define the working plane. + It defaults to `(0, 1, 0)`, or the +Y axis. + + w: Base::Vector3, optional + An axis that is supposed to be perpendicular to `u` and `v`; + it is redundant. + It defaults to `(0, 0, 1)`, or the +Z axis. + + pos: Base::Vector3, optional + A point through which the plane goes through. + It defaults to the origin `(0, 0, 0)`. + Attributes ---------- - doc : App::Document + doc: App::Document The active document. Reset view when `doc` changes. - weak : bool + + weak: bool It is `True` if the plane has been defined by `setup()` or has been reset. A weak plane can be changed (it is the "auto" mode), while a strong plane will keep its position until weakened (it is "locked") - u : Base::Vector3 + + u: Base::Vector3 An axis (vector) that helps define the working plane. - v : Base::Vector3 + + v: Base::Vector3 An axis (vector) that helps define the working plane. - axis : Base::Vector3 + + axis: Base::Vector3 A vector that is supposed to be perpendicular to `u` and `v`; it is helpful although redundant. - position : Base::Vector3 + + position: Base::Vector3 A point, which the plane goes through, that helps define the working plane. - stored : bool + + stored: bool A placeholder for a stored state. """ def __init__(self, u=Vector(1, 0, 0), v=Vector(0, 1, 0), w=Vector(0, 0, 1), pos=Vector(0, 0, 0)): - """Initialize the working plane. - Parameters - ---------- - u : Base::Vector3, optional - An axis (vector) that helps define the working plane. - It defaults to `(1, 0, 0)`, or the +X axis. - v : Base::Vector3, optional - An axis (vector) that helps define the working plane. - It defaults to `(0, 1, 0)`, or the +Y axis. - w : Base::Vector3, optional - An axis that is supposed to be perpendicular to `u` and `v`; - it is redundant. - It defaults to `(0, 0, 1)`, or the +Z axis. - pos : Base::Vector3, optional - A point through which the plane goes through. - It defaults to the origin `(0, 0, 0)`. - """ # keep track of active document. Reset view when doc changes. self.doc = None self.weak = True @@ -122,6 +128,7 @@ class plane: ---------- p : Base::Vector3 The external point to consider. + direction : Base::Vector3, optional The unit vector that indicates the direction of the distance. @@ -326,8 +333,8 @@ class plane: offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False - # FCC.PrintMessage("(position = " + str(self.position) + ")\n") - # FCC.PrintMessage(self.__repr__() + "\n") + # Console.PrintMessage("(position = " + str(self.position) + ")\n") + # Console.PrintMessage(self.__repr__() + "\n") def alignToPointAndAxis_SVG(self, point, axis, offset=0): """Align the working plane to a point and an axis (vector). @@ -436,14 +443,14 @@ class plane: # spat_vec = self.u.cross(self.v) # spat_res = spat_vec.dot(axis) - # FCC.PrintMessage(projcase + " spat Prod = " + str(spat_res) + "\n") + # Console.PrintMessage(projcase + " spat Prod = " + str(spat_res) + "\n") offsetVector = Vector(axis) offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False - # FCC.PrintMessage("(position = " + str(self.position) + ")\n") - # FCC.PrintMessage(self.__repr__() + "\n") + # Console.PrintMessage("(position = " + str(self.position) + ")\n") + # Console.PrintMessage(self.__repr__() + "\n") def alignToCurve(self, shape, offset=0): """Align plane to curve. NOT YET IMPLEMENTED. @@ -631,7 +638,7 @@ class plane: When the interface is not loaded it should fail and print a message, `FreeCAD.Console.PrintError()`. - See also + See Also -------- alignToFace, alignToCurve """ @@ -652,7 +659,7 @@ class plane: return False def setup(self, direction=None, point=None, upvec=None, force=False): - """Setup the working plane if it exists but is undefined. + """Set up the working plane if it exists but is undefined. If `direction` and `point` are present, it calls `alignToPointAndAxis(point, direction, 0, upvec)`. @@ -704,7 +711,7 @@ class plane: # perpendicular to the current view self.alignToPointAndAxis(Vector(0, 0, 0), vdir.negative(), 0, upvec) - except: + except Exception: pass if force: self.weak = False @@ -878,7 +885,7 @@ class plane: Base::Vector3 The relative coordinates of the point from the plane. - See also + See Also -------- getGlobalCoords, getLocalRot, getGlobalRot @@ -944,7 +951,7 @@ class plane: Base::Vector3 The coordinates of the point from the absolute origin. - See also + See Also -------- getLocalCoords, getLocalRot, getGlobalRot @@ -999,7 +1006,7 @@ class plane: The relative coordinates of the point from the plane, if the plane had its `position` at the global origin. - See also + See Also -------- getLocalCoords, getGlobalCoords, getGlobalRot """ @@ -1039,7 +1046,7 @@ class plane: Base::Vector3 The coordinates of the point from the absolute origin. - See also + See Also -------- getGlobalCoords, getLocalCoords, getLocalRot """ @@ -1144,7 +1151,7 @@ class plane: Angle between the `u` vector, and a projected vector on the global horizontal plane. - See also + See Also -------- DraftVecUtils.angle """ @@ -1156,6 +1163,9 @@ class plane: return DraftVecUtils.angle(self.u, proj, norm) +plane = Plane + + def getPlacementFromPoints(points): """Return a placement from a list of 3 or 4 points. @@ -1185,7 +1195,7 @@ def getPlacementFromPoints(points): defined by `points`, or `None` is it fails to use the points. - See also + See Also -------- getPlacement """ @@ -1198,7 +1208,7 @@ def getPlacementFromPoints(points): pl.axis = (points[3].sub(points[0]).normalize()) else: pl.axis = ((pl.u).cross(pl.v)).normalize() - except: + except Exception: return None p = pl.getPlacement() del pl @@ -1229,14 +1239,14 @@ def getPlacementFromFace(face, rotated=False): defined by `face`, or `None` if it fails to use `face`. - See also + See Also -------- alignToFace, getPlacement """ pl = plane() try: pl.alignToFace(face) - except: + except Exception: return None p = pl.getPlacement(rotated) del pl From 95b8b6ebc4f63115eac93596a353ff94c904e666 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sat, 29 Feb 2020 01:30:12 -0600 Subject: [PATCH 16/62] Draft: DraftGeomUtils clean up imports, and Python 2 compatibility Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Also fix copying of a list in order to keep compatibility with Python 2. --- src/Mod/Draft/DraftGeomUtils.py | 71 +++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index c98dc29506..7a9494a9ff 100644 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -1,29 +1,31 @@ -#*************************************************************************** -#* Copyright (c) 2009, 2010 Yorik van Havre * -#* Copyright (c) 2009, 2010 Ken Cline * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** - -__title__="FreeCAD Draft Workbench - Geometry library" -__author__ = "Yorik van Havre, Jacques-Antoine Gaudin, Ken Cline" -__url__ = ["https://www.freecadweb.org"] +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Define geometry functions for manipulating shapes in the Draft Workbench. +These functions are used by different object creation functions +of the Draft Workbench, both in `Draft.py` and `DraftTools.py`. +They operate on the internal shapes (`Part::TopoShape`) of different objects +and on their subelements, that is, vertices, edges, and faces. +""" ## \defgroup DRAFTGEOMUTILS DraftGeomUtils # \ingroup UTILITIES # \brief Shape manipulation utilities for the Draft workbench @@ -32,20 +34,26 @@ __url__ = ["https://www.freecadweb.org"] ## \addtogroup DRAFTGEOMUTILS # @{ +import cmath +import math -"this file contains generic geometry functions for manipulating Part shapes" - -import FreeCAD, Part, DraftVecUtils, math, cmath +import FreeCAD +import Part +import DraftVecUtils from FreeCAD import Vector -NORM = Vector(0,0,1) # provisory normal direction for all geometry ops. +__title__ = "FreeCAD Draft Workbench - Geometry library" +__author__ = "Yorik van Havre, Jacques-Antoine Gaudin, Ken Cline" +__url__ = ["https://www.freecadweb.org"] + +NORM = Vector(0, 0, 1) # provisory normal direction for all geometry ops. params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") # Generic functions ********************************************************* def precision(): - "precision(): returns the Draft precision setting" + """precision(): returns the Draft precision setting""" # Set precision level with a cap to avoid overspecification that: # 1 - whilst it is precise enough (e.g. that OCC would consider 2 points are coincident) # (not sure what it should be 10 or otherwise); @@ -1260,7 +1268,8 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a # Make a copy of alignList - to avoid changes in this function become starting input of next call of this function ? # https://www.dataquest.io/blog/tutorial-functions-modify-lists-dictionaries-python/ - alignListC = alignList.copy() + # alignListC = alignList.copy() # Only Python 3 + alignListC = list(alignList) # Python 2 and 3 # Check the direction / offset of starting edge From 173f50934921597b603243cbe7b89765a53b0287 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sat, 29 Feb 2020 12:55:09 -0600 Subject: [PATCH 17/62] Draft: DraftGeomUtils clean up docstrings and spaces --- src/Mod/Draft/DraftGeomUtils.py | 464 +++++++++++++++++--------------- 1 file changed, 249 insertions(+), 215 deletions(-) diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index 7a9494a9ff..cd6c9c1b68 100644 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -52,6 +52,7 @@ params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") # Generic functions ********************************************************* + def precision(): """precision(): returns the Draft precision setting""" # Set precision level with a cap to avoid overspecification that: @@ -63,10 +64,11 @@ def precision(): precisionMax = 10 precisionInt = params.GetInt("precision",6) precisionInt = (precisionInt if precisionInt <=10 else precisionMax) - return precisionInt #return params.GetInt("precision",6) + return precisionInt # return params.GetInt("precision",6) + def vec(edge): - "vec(edge) or vec(line): returns a vector from an edge or a Part.LineSegment" + """vec(edge) or vec(line): returns a vector from an edge or a Part.LineSegment""" # if edge is not straight, you'll get strange results! if isinstance(edge,Part.Shape): return edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point) @@ -75,14 +77,16 @@ def vec(edge): else: return None -def edg(p1,p2): - "edg(Vector,Vector): returns an edge from 2 vectors" + +def edg(p1, p2): + """edg(Vector,Vector): returns an edge from 2 vectors""" if isinstance(p1,FreeCAD.Vector) and isinstance(p2,FreeCAD.Vector): if DraftVecUtils.equals(p1,p2): return None else: return Part.LineSegment(p1,p2).toShape() + def getVerts(shape): - "getVerts(shape): returns a list containing vectors of each vertex of the shape" + """getVerts(shape): returns a list containing vectors of each vertex of the shape""" if not hasattr(shape,"Vertexes"): return [] p = [] @@ -90,13 +94,15 @@ def getVerts(shape): p.append(v.Point) return p + def v1(edge): - "v1(edge): returns the first point of an edge" + """v1(edge): returns the first point of an edge""" return edge.Vertexes[0].Point + def isNull(something): - '''isNull(object): returns true if the given shape is null or the given placement is null or - if the given vector is (0,0,0)''' + """isNull(object): returns true if the given shape is null or the given placement is null or + if the given vector is (0,0,0)""" if isinstance(something,Part.Shape): return something.isNull() elif isinstance(something,FreeCAD.Vector): @@ -110,8 +116,9 @@ def isNull(something): else: return False -def isPtOnEdge(pt,edge) : - '''isPtOnEdge(Vector,edge): Tests if a point is on an edge''' + +def isPtOnEdge(pt, edge): + """isPtOnEdge(Vector,edge): Tests if a point is on an edge""" v = Part.Vertex(pt) try: d = v.distToShape(edge) @@ -123,15 +130,17 @@ def isPtOnEdge(pt,edge) : return True return False + def hasCurves(shape): - "hasCurve(shape): checks if the given shape has curves" + """hasCurve(shape): checks if the given shape has curves""" for e in shape.Edges: if not isinstance(e.Curve,(Part.LineSegment,Part.Line)): return True return False -def isAligned(edge,axis="x"): - "isAligned(edge,axis): checks if the given edge or line is aligned to the given axis (x, y or z)" + +def isAligned(edge, axis="x"): + """isAligned(edge,axis): checks if the given edge or line is aligned to the given axis (x, y or z)""" if axis == "x": if isinstance(edge,Part.Edge): if len(edge.Vertexes) == 2: @@ -158,6 +167,7 @@ def isAligned(edge,axis="x"): return True return False + def getQuad(face): """getQuad(face): returns a list of 3 vectors (basepoint, Xdir, Ydir) if the face is a quad, or None if not.""" @@ -178,7 +188,8 @@ def getQuad(face): ov.normalize() return [face.Edges[0].Vertexes[0].Point,v1,ov] -def areColinear(e1,e2): + +def areColinear(e1, e2): """areColinear(e1,e2): returns True if both edges are colinear""" if not isinstance(e1.Curve,(Part.LineSegment,Part.Line)): return False @@ -197,8 +208,9 @@ def areColinear(e1,e2): return True return False + def hasOnlyWires(shape): - "hasOnlyWires(shape): returns True if all the edges are inside a wire" + """hasOnlyWires(shape): returns True if all the edges are inside a wire""" ne = 0 for w in shape.Wires: ne += len(w.Edges) @@ -206,8 +218,9 @@ def hasOnlyWires(shape): return True return False + def geomType(edge): - "returns the type of geom this edge is based on" + """returns the type of geom this edge is based on""" try: if isinstance(edge.Curve,(Part.LineSegment,Part.Line)): return "Line" @@ -224,8 +237,9 @@ def geomType(edge): except: return "Unknown" + def isValidPath(shape): - "isValidPath(shape): returns True if the shape can be used as an extrusion path" + """isValidPath(shape): returns True if the shape can be used as an extrusion path""" if shape.isNull(): return False if shape.Faces: @@ -239,10 +253,11 @@ def isValidPath(shape): return False return True -# edge functions ***************************************************************** +# edge functions ************************************************************* -def findEdge(anEdge,aList): - '''findEdge(anEdge,aList): returns True if anEdge is found in aList of edges''' + +def findEdge(anEdge, aList): + """findEdge(anEdge,aList): returns True if anEdge is found in aList of edges""" for e in range(len(aList)): if str(anEdge.Curve) == str(aList[e].Curve): if DraftVecUtils.equals(anEdge.Vertexes[0].Point,aList[e].Vertexes[0].Point): @@ -251,13 +266,16 @@ def findEdge(anEdge,aList): return None -def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=False,dts=True,findAll=False) : - '''findIntersection(edge1,edge2,infinite1=False,infinite2=False,dts=True): +def findIntersection(edge1, edge2, + infinite1=False, infinite2=False, + ex1=False, ex2=False, + dts=True, findAll=False): + """findIntersection(edge1,edge2,infinite1=False,infinite2=False,dts=True): returns a list containing the intersection point(s) of 2 edges. You can also feed 4 points instead of edge1 and edge2. If dts is used, - Shape.distToShape() is used, which can be buggy''' + Shape.distToShape() is used, which can be buggy""" - def getLineIntersections(pt1,pt2,pt3,pt4,infinite1,infinite2): + def getLineIntersections(pt1, pt2, pt3, pt4, infinite1, infinite2): if pt1: # first check if we don't already have coincident endpoints if (pt1 in [pt3,pt4]): @@ -424,9 +442,7 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F return int elif (geomType(edge1) == "Circle") and (geomType(edge2) == "Circle") : - # deals with 2 arcs or circles - cent1, cent2 = edge1.Curve.Center, edge2.Curve.Center rad1 , rad2 = edge1.Curve.Radius, edge2.Curve.Radius axis1, axis2 = edge1.Curve.Axis , edge2.Curve.Axis @@ -458,7 +474,7 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F else : int = [cent1.add(c2c)] else : - return [] # circles are on parallel planes + return [] # circles are on parallel planes else : # circles aren't on same plane axis1.normalize() ; axis2.normalize() @@ -489,15 +505,17 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F print("DraftGeomUtils: Unsupported curve type: (" + str(edge1.Curve) + ", " + str(edge2.Curve) + ")") return [] -def wiresIntersect(wire1,wire2): - "wiresIntersect(wire1,wire2): returns True if some of the edges of the wires are intersecting otherwise False" + +def wiresIntersect(wire1, wire2): + """wiresIntersect(wire1,wire2): returns True if some of the edges of the wires are intersecting otherwise False""" for e1 in wire1.Edges: for e2 in wire2.Edges: if findIntersection(e1,e2,dts=False): return True return False -def pocket2d(shape,offset): + +def pocket2d(shape, offset): """pocket2d(shape,offset): return a list of wires obtained from offsetting the wires from the given shape by the given offset, and intersection if needed.""" # find the outer wire @@ -563,6 +581,7 @@ def pocket2d(shape,offset): offsetWires = [o for o in offsetWires if o != None] return offsetWires + def orientEdge(edge, normal=None, make_arc=False): """Re-orients 'edge' such that it is in the x-y plane. If 'normal' is passed, this is used as the basis for the rotation, otherwise the Placement property of 'edge' @@ -593,8 +612,9 @@ def orientEdge(edge, normal=None, make_arc=False): edge.LastParameter,edge.Curve.Axis.z>0) return edge.Curve -def mirror (point, edge): - "finds mirror point relative to an edge" + +def mirror(point, edge): + """Find mirror point relative to an edge.""" normPoint = point.add(findDistance(point, edge, False)) if normPoint: normPoint_point = Vector.sub(point, normPoint) @@ -604,8 +624,9 @@ def mirror (point, edge): else: return None -def isClockwise(edge,ref=None): - """Returns True if a circle-based edge has a clockwise direction""" + +def isClockwise(edge, ref=None): + """Return True if a circle-based edge has a clockwise direction.""" if not geomType(edge) == "Circle": return True v1 = edge.Curve.tangent(edge.ParameterRange[0])[0] @@ -625,7 +646,8 @@ def isClockwise(edge,ref=None): return False return True -def isSameLine(e1,e2): + +def isSameLine(e1, e2): """isSameLine(e1,e2): return True if the 2 edges are lines and have the same points""" if not isinstance(e1.Curve,Part.LineSegment): @@ -640,6 +662,7 @@ def isSameLine(e1,e2): return True return False + def isWideAngle(edge): """returns True if the given edge is an arc with angle > 180 degrees""" if geomType(edge) != "Circle": @@ -650,12 +673,13 @@ def isWideAngle(edge): return True return False -def findClosest(basepoint,pointslist): - ''' + +def findClosest(basepoint, pointslist): + """ findClosest(vector,list) in a list of 3d points, finds the closest point to the base point. an index from the list is returned. - ''' + """ npoint = None if not pointslist: return None @@ -667,8 +691,9 @@ def findClosest(basepoint,pointslist): npoint = n return npoint + def concatenate(shape): - "concatenate(shape) -- turns several faces into one" + """concatenate(shape) -- turns several faces into one""" edges = getBoundary(shape) edges = Part.__sortEdges__(edges) try: @@ -681,8 +706,9 @@ def concatenate(shape): if not wire.isClosed(): return(wire) else: return(face) + def getBoundary(shape): - "getBoundary(shape) -- this function returns the boundary edges of a group of faces" + """getBoundary(shape) -- this function returns the boundary edges of a group of faces""" # make a lookup-table where we get the number of occurrences # to each edge in the fused face if isinstance(shape,list): @@ -699,8 +725,9 @@ def getBoundary(shape): if lut[e.hashCode()] == 1: bound.append(e) return bound + def isLine(bsp): - "returns True if the given BSpline curve is a straight line" + """Return True if the given BSpline curve is a straight line.""" step = bsp.LastParameter/10 b = bsp.tangent(0) for i in range(10): @@ -710,8 +737,7 @@ def isLine(bsp): def sortEdges(edges): - "Deprecated. Use Part.__sortEdges__ instead" - + """Deprecated. Use Part.__sortEdges__ instead.""" raise DeprecationWarning("Deprecated. Use Part.__sortEdges__ instead") # Build a dictionary of edges according to their end points. @@ -788,8 +814,7 @@ def sortEdges(edges): def sortEdgesOld(lEdges, aVertex=None): - "Deprecated. Use Part.__sortEdges__ instead" - + """Deprecated. Use Part.__sortEdges__ instead.""" raise DeprecationWarning("Deprecated. Use Part.__sortEdges__ instead") #There is no reason to limit this to lines only because every non-closed edge always @@ -800,8 +825,8 @@ def sortEdgesOld(lEdges, aVertex=None): # return lEdges def lookfor(aVertex, inEdges): - ''' Look for (aVertex, inEdges) returns count, the position of the instance - the position in the instance and the instance of the Edge''' + """Look for (aVertex, inEdges) returns count, the position of the instance + the position in the instance and the instance of the Edge""" count = 0 linstances = [] #lists the instances of aVertex for i in range(len(inEdges)) : @@ -880,7 +905,7 @@ def sortEdgesOld(lEdges, aVertex=None): def invert(shape): - '''invert(edge): returns an inverted copy of this edge or wire''' + """invert(edge): returns an inverted copy of this edge or wire""" if shape.ShapeType == "Wire": edges = [invert(edge) for edge in shape.OrderedEdges] edges.reverse() @@ -902,9 +927,10 @@ def invert(shape): print("DraftGeomUtils.invert: unable to handle",shape.ShapeType) return shape + def flattenWire(wire): - '''flattenWire(wire): forces a wire to get completely flat - along its normal.''' + """flattenWire(wire): forces a wire to get completely flat + along its normal.""" import WorkingPlane n = getNormal(wire) if not n: @@ -920,11 +946,13 @@ def flattenWire(wire): w = Part.makePolygon(verts) return w + def findWires(edgeslist): return [ Part.Wire(e) for e in Part.sortEdges(edgeslist)] + def findWiresOld2(edgeslist): - '''finds connected wires in the given list of edges''' + """Find connected wires in the given list of edges.""" def touches(e1,e2): if len(e1.Vertexes) < 2: @@ -981,9 +1009,10 @@ def findWiresOld2(edgeslist): nwires.append(wi) return nwires -def superWire(edgeslist,closed=False): - '''superWire(edges,[closed]): forces a wire between edges that don't necessarily - have coincident endpoints. If closed=True, wire will always be closed''' + +def superWire(edgeslist, closed=False): + """superWire(edges,[closed]): forces a wire between edges that don't necessarily + have coincident endpoints. If closed=True, wire will always be closed""" def median(v1,v2): vd = v2.sub(v1) vd.scale(.5,.5,.5) @@ -1035,8 +1064,9 @@ def superWire(edgeslist,closed=False): print(newedges) return Part.Wire(newedges) + def findMidpoint(edge): - "calculates the midpoint of an edge" + """Calculate the midpoint of an edge.""" first = edge.Vertexes[0].Point last = edge.Vertexes[-1].Point if geomType(edge) == "Circle": @@ -1066,15 +1096,15 @@ def findMidpoint(edge): return None -def findPerpendicular(point,edgeslist,force=None): - ''' +def findPerpendicular(point, edgeslist, force=None): + """ findPerpendicular(vector,wire,[force]): finds the shortest perpendicular distance between a point and an edgeslist. If force is specified, only the edge[force] will be considered, and it will be considered infinite. The function will return a list [vector_from_point_to_closest_edge,edge_index] or None if no perpendicular vector could be found. - ''' + """ if not isinstance(edgeslist,list): try: edgeslist = edgeslist.Edges @@ -1097,13 +1127,14 @@ def findPerpendicular(point,edgeslist,force=None): else: return None return None -def offset(edge,vector,trim=False): - ''' + +def offset(edge, vector, trim=False): + """ offset(edge,vector) returns a copy of the edge at a certain (vector) distance if the edge is an arc, the vector will be added at its first point and a complete circle will be returned - ''' + """ if (not isinstance(edge,Part.Shape)) or (not isinstance(vector,FreeCAD.Vector)): return None if geomType(edge) == "Line": @@ -1121,9 +1152,9 @@ def offset(edge,vector,trim=False): else: return None -def isReallyClosed(wire): - "checks if a wire is really closed" +def isReallyClosed(wire): + """Check if a wire is really closed.""" ## TODO yet to find out why not use wire.isClosed() direct, in isReallyClosed(wire) # Remark out below - Found not true if a vertex is used again in a wire in sketch ( e.g. wire with shape like 'd', 'b', 'g'... ) @@ -1147,8 +1178,9 @@ def isReallyClosed(wire): if DraftVecUtils.equals(v1,v2): return True return False + def getNormal(shape): - "finds the normal of a shape, if possible" + """Find the normal of a shape, if possible.""" n = Vector(0,0,1) if shape.isNull(): return n @@ -1177,8 +1209,9 @@ def getNormal(shape): return None return n -def getRotation(v1,v2=FreeCAD.Vector(0,0,1)): - '''Get the rotation Quaternion between 2 vectors''' + +def getRotation(v1, v2=FreeCAD.Vector(0, 0, 1)): + """Get the rotation Quaternion between 2 vectors.""" if (v1.dot(v2) > 0.999999) or (v1.dot(v2) < -0.999999): # vectors are opposite return None @@ -1188,10 +1221,11 @@ def getRotation(v1,v2=FreeCAD.Vector(0,0,1)): angle = math.degrees(DraftVecUtils.angle(v1,v2,axis)) return FreeCAD.Rotation(axis,angle) + def calculatePlacement(shape): - '''calculatePlacement(shape): if the given shape is planar, this function + """calculatePlacement(shape): if the given shape is planar, this function returns a placement located at the center of gravity of the shape, and oriented - towards the shape's normal. Otherwise, it returns a null placement.''' + towards the shape's normal. Otherwise, it returns a null placement.""" if not isPlanar(shape): return FreeCAD.Placement() pos = shape.BoundBox.Center @@ -1204,8 +1238,10 @@ def calculatePlacement(shape): return pla -def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, alignList=[], normal=None, basewireOffset=0): # offsetMode="BasewireMode" or None - ''' +def offsetWire(wire, dvec, bind=False, occ=False, + widthList=None, offsetMode=None, alignList=[], + normal=None, basewireOffset=0): # offsetMode="BasewireMode" or None + """ offsetWire(wire,vector,[bind]): offsets the given wire along the given vector. The vector will be applied at the first vertex of the wire. If bind is True (and the shape is open), the original wire and the offsetted one @@ -1226,16 +1262,16 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a 'dvec' vector to offset is now derived (and can be ignored) in this function if widthList and alignList are provided - 'dvec' to be obsolete in future ? 'basewireOffset' corresponds to 'offset' in ArchWall which offset the basewire before creating the wall outline - ''' + """ # Accept 'wire' as a list of edges (use the list directly), or previously as a wire or a face (Draft Wire with MakeFace True or False supported) if isinstance(wire,Part.Wire) or isinstance(wire,Part.Face): - edges = wire.Edges # Seems has repeatedly sortEdges, remark out here - edges = Part.__sortEdges__(wire.Edges) + edges = wire.Edges # Seems has repeatedly sortEdges, remark out here - edges = Part.__sortEdges__(wire.Edges) elif isinstance(wire, list): if isinstance(wire[0],Part.Edge): edges = wire.copy() - wire = Part.Wire( Part.__sortEdges__(edges) ) # How to avoid __sortEdges__ again? Make getNormal directly tackle edges ? + wire = Part.Wire( Part.__sortEdges__(edges) ) # How to avoid __sortEdges__ again? Make getNormal directly tackle edges ? else: print ("Either Part.Wire or Part.Edges should be provided, returning None ") return None @@ -1245,7 +1281,7 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a if normal: norm = normal else: - norm = getNormal(wire) #norm = Vector(0,0,1) + norm = getNormal(wire) # norm = Vector(0, 0, 1) closed = isReallyClosed(wire) nedges = [] @@ -1272,7 +1308,6 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a alignListC = list(alignList) # Python 2 and 3 # Check the direction / offset of starting edge - firstDir = None try: if alignListC[0] == 'Left': @@ -1288,7 +1323,6 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a pass # Should no longer happen for ArchWall - as aligns are 'filled in' by ArchWall # If not provided by alignListC checked above, check the direction of offset in dvec (not 'align') - if not firstDir: ## TODO Should check if dvec is provided or not ('legacy/backward-compatible' mode) if isinstance(e.Curve,Part.Circle): # need to test against Part.Circle, not Part.ArcOfCircle v0 = e.Vertexes[0].Point.sub(e.Curve.Center) @@ -1310,7 +1344,6 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a alignListC.append('Left') for i in range(len(edges)): - # make a copy so it do not reverse the self.baseWires edges pointed to by _Wall.getExtrusionData() ? curredge = edges[i].copy() @@ -1331,7 +1364,6 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a curOrientation = curredge.Vertexes[0].Orientation # TODO Could be edge.Orientation in fact # Consider individual edge width - if widthList: # ArchWall should now always provide widthList try: if widthList[i] > 0: @@ -1351,12 +1383,11 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a delta = DraftVecUtils.scaleTo(delta,dvec.Length) # Consider individual edge Align direction - ArchWall should now always provide alignList - if i == 0: if alignListC[0] == 'Center': delta = DraftVecUtils.scaleTo(delta, delta.Length/2) - #No need to do anything for 'Left' and 'Rigtht' as original dvec have set both the direction and amount of offset correct - #elif alignListC[i] == 'Left': #elif alignListC[i] == 'Right': + # No need to do anything for 'Left' and 'Right' as original dvec have set both the direction and amount of offset correct + # elif alignListC[i] == 'Left': #elif alignListC[i] == 'Right': if i != 0: try: if alignListC[i] == 'Left': @@ -1379,7 +1410,6 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a delta = DraftVecUtils.scaleTo(delta, delta.Length/2) # Consider whether generating the 'offset wire' or the 'base wire' - if offsetMode == None: # Consider if curOrientation and/or curDir match their firstOrientation/firstDir - to determine whether and how to offset the current edge if (curOrientation == firstOrientation) != (curDir == firstDir): # i.e. xor @@ -1394,7 +1424,7 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a delta = DraftVecUtils.scaleTo(delta, delta.Length+basewireOffset) nedge = offset(curredge,delta,trim=True) - if curOrientation == "Reversed": # TODO arc always in counter-clockwise directinon ... ( not necessarily 'reversed') + if curOrientation == "Reversed": # TODO arc always in counter-clockwise directinon ... ( not necessarily 'reversed') if not isinstance(curredge.Curve,Part.Circle): # need to test against Part.Circle, not Part.ArcOfCircle # if not arc/circle, assume straight line, reverse it nedge = Part.Edge(nedge.Vertexes[1],nedge.Vertexes[0]) @@ -1437,7 +1467,7 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a nedge = Part.ArcOfCircle(nedge.Vertexes[1].Point, midOfArc, nedge.Vertexes[0].Point).toShape() # TODO any better solution than to calculate midpoint of arc to reverse ? else: - print (" something wrong ") + print(" something wrong ") return if not nedge: return None @@ -1458,8 +1488,8 @@ def offsetWire(wire,dvec,bind=False,occ=False,widthList=None, offsetMode=None, a else: return nedges -def connect(edges,closed=False): - '''connects the edges in the given list by their intersections''' +def connect(edges, closed=False): + """Connect the edges in the given list by their intersections.""" nedges = [] v2 = None @@ -1524,12 +1554,12 @@ def connect(edges,closed=False): print(e.Curve, " ",e.Vertexes[0].Point, " ", e.Vertexes[-1].Point) return None -def findDistance(point,edge,strict=False): - ''' +def findDistance(point, edge, strict=False): + """ findDistance(vector,edge,[strict]) - Returns a vector from the point to its closest point on the edge. If strict is True, the vector will be returned only if its endpoint lies on the edge. Edge can also be a list of 2 points. - ''' + """ if isinstance(point, FreeCAD.Vector): if isinstance(edge,list): segment = edge[1].sub(edge[0]) @@ -1612,7 +1642,7 @@ def findDistance(point,edge,strict=False): def angleBisection(edge1, edge2): - "angleBisection(edge,edge) - Returns an edge that bisects the angle between the 2 edges." + """angleBisection(edge,edge) - Returns an edge that bisects the angle between the 2 edges.""" if (geomType(edge1) == "Line") and (geomType(edge2) == "Line"): p1 = edge1.Vertexes[0].Point p2 = edge1.Vertexes[-1].Point @@ -1635,8 +1665,8 @@ def angleBisection(edge1, edge2): else: return None -def findClosestCircle(point,circles): - "findClosestCircle(Vector, list of circles) -- returns the circle with closest center" +def findClosestCircle(point, circles): + """Return the circle with closest center.""" dist = 1000000 closest = None for c in circles: @@ -1645,8 +1675,9 @@ def findClosestCircle(point,circles): closest = c return closest -def isCoplanar(faces,tolerance=0): - "isCoplanar(faces,[tolerance]): checks if all faces in the given list are coplanar. Tolerance is the max deviation to be considered coplanar" + +def isCoplanar(faces, tolerance=0): + """isCoplanar(faces,[tolerance]): checks if all faces in the given list are coplanar. Tolerance is the max deviation to be considered coplanar""" if len(faces) < 2: return True base =faces[0].normalAt(0,0) @@ -1658,8 +1689,9 @@ def isCoplanar(faces,tolerance=0): return False return True + def isPlanar(shape): - "checks if the given shape is planar" + """Check if the given shape is planar.""" if len(shape.Vertexes) <= 3: return True n = getNormal(shape) @@ -1670,9 +1702,10 @@ def isPlanar(shape): return False return True + def findWiresOld(edges): - '''finds connected edges in the list, and returns a list of lists containing edges - that can be connected''' + """finds connected edges in the list, and returns a list of lists containing edges + that can be connected""" raise DeprecationWarning("This function shouldn't be called anymore - use findWires() instead") def verts(shape): return [shape.Vertexes[0].Point,shape.Vertexes[-1].Point] @@ -1702,11 +1735,12 @@ def findWiresOld(edges): edgeSet = result[1] return result[1] -def getTangent(edge,frompoint=None): - ''' + +def getTangent(edge, frompoint=None): + """ returns the tangent to an edge. If from point is given, it is used to calculate the tangent (only useful for an arc of course). - ''' + """ if geomType(edge) == "Line": return vec(edge) elif geomType(edge) == "BSplineCurve" or \ @@ -1723,9 +1757,10 @@ def getTangent(edge,frompoint=None): return v1.cross(edge.Curve.Axis) return None -def bind(w1,w2): - '''bind(wire1,wire2): binds 2 wires by their endpoints and - returns a face''' + +def bind(w1, w2): + """bind(wire1,wire2): binds 2 wires by their endpoints and + returns a face""" if (not w1) or (not w2): print("DraftGeomUtils: unable to bind wires") return None @@ -1748,16 +1783,16 @@ def bind(w1,w2): return None def cleanFaces(shape): - "removes inner edges from coplanar faces" + """Remove inner edges from coplanar faces.""" faceset = shape.Faces def find(hc): - "finds a face with the given hashcode" + """finds a face with the given hashcode""" for f in faceset: if f.hashCode() == hc: return f def findNeighbour(hface,hfacelist): - "finds the first neighbour of a face in a list, and returns its index" + """finds the first neighbour of a face in a list, and returns its index""" eset = [] for e in find(hface).Edges: eset.append(e.hashCode()) @@ -1848,8 +1883,8 @@ def cleanFaces(shape): def isCubic(shape): - '''isCubic(shape): verifies if a shape is cubic, that is, has - 8 vertices, 6 faces, and all angles are 90 degrees.''' + """isCubic(shape): verifies if a shape is cubic, that is, has + 8 vertices, 6 faces, and all angles are 90 degrees.""" # first we try fast methods if len(shape.Vertexes) != 8: return False @@ -1873,10 +1908,11 @@ def isCubic(shape): return False return True + def getCubicDimensions(shape): - '''getCubicDimensions(shape): returns a list containing the placement, + """getCubicDimensions(shape): returns a list containing the placement, the length, the width and the height of a cubic shape. If not cubic, nothing - is returned. The placement point is the lowest corner of the shape.''' + is returned. The placement point is the lowest corner of the shape.""" if not isCubic(shape): return None # determine lowest face, which will be our base z = [10,1000000000000] @@ -1914,9 +1950,10 @@ def getCubicDimensions(shape): mat.rotateZ(rotZ) return [FreeCAD.Placement(mat),round(vx.Length,precision()),round(vy.Length,precision()),round(vz.Length,precision())] + def removeInterVertices(wire): - '''removeInterVertices(wire) - remove unneeded vertices (those that - are in the middle of a straight line) from a wire, returns a new wire.''' + """removeInterVertices(wire) - remove unneeded vertices (those that + are in the middle of a straight line) from a wire, returns a new wire.""" edges = Part.__sortEdges__(wire.Edges) nverts = [] def getvec(v1,v2): @@ -1937,6 +1974,7 @@ def removeInterVertices(wire): else: return wire + def arcFromSpline(edge): """arcFromSpline(edge): turns the given edge into an arc, by taking its first point, midpoint and endpoint. Works best with bspline @@ -1970,33 +2008,33 @@ def arcFromSpline(edge): except: print("couldn't make a circle out of this edge") -# Fillet code graciously donated by Jacques-Antoine Gaudin -def fillet(lEdges,r,chamfer=False): - '''fillet(lEdges,r,chamfer=False): Take a list of two Edges & a float as argument, - Returns a list of sorted edges describing a round corner''' +def fillet(lEdges, r, chamfer=False): + """fillet(lEdges,r,chamfer=False): Take a list of two Edges & a float as argument, + Returns a list of sorted edges describing a round corner""" + # Fillet code graciously donated by Jacques-Antoine Gaudin - def getCurveType(edge,existingCurveType = None): - '''Builds or completes a dictionary containing edges with keys "Arc" and "Line"''' - if not existingCurveType : + def getCurveType(edge, existingCurveType=None): + """Builds or completes a dictionary containing edges with keys "Arc" and 'Line'""" + if not existingCurveType: existingCurveType = { 'Line' : [], 'Arc' : [] } - if issubclass(type(edge.Curve),Part.LineSegment) : + if issubclass(type(edge.Curve),Part.LineSegment): existingCurveType['Line'] += [edge] - elif issubclass(type(edge.Curve),Part.Line) : + elif issubclass(type(edge.Curve),Part.Line): existingCurveType['Line'] += [edge] - elif issubclass(type(edge.Curve),Part.Circle) : + elif issubclass(type(edge.Curve),Part.Circle): existingCurveType['Arc'] += [edge] - else : + else: raise ValueError("Edge's curve must be either Line or Arc") return existingCurveType rndEdges = lEdges[0:2] rndEdges = Part.__sortEdges__(rndEdges) - if len(rndEdges) < 2 : + if len(rndEdges) < 2: return rndEdges - if r <= 0 : + if r <= 0: print("DraftGeomUtils.fillet : Error : radius is negative.") return rndEdges @@ -2006,9 +2044,7 @@ def fillet(lEdges,r,chamfer=False): lVertexes = rndEdges[0].Vertexes + [rndEdges[1].Vertexes[-1]] if len(curveType['Line']) == 2: - # Deals with 2-line-edges lists -------------------------------------- - U1 = lVertexes[0].Point.sub(lVertexes[1].Point) ; U1.normalize() U2 = lVertexes[2].Point.sub(lVertexes[1].Point) ; U2.normalize() alpha = U1.getAngle(U2) @@ -2055,12 +2091,10 @@ def fillet(lEdges,r,chamfer=False): return rndEdges elif len(curveType['Arc']) == 1 : - - # Deals with lists containing an arc and a line ---------------------------------- - - if lEdges[0] in curveType['Arc'] : + # Deals with lists containing an arc and a line ---------------------- + if lEdges[0] in curveType['Arc']: lineEnd = lVertexes[2] ; arcEnd = lVertexes[0] ; arcFirst = True - else : + else: lineEnd = lVertexes[0] ; arcEnd = lVertexes[2] ; arcFirst = False arcCenter = curveType['Arc'][0].Curve.Center arcRadius = curveType['Arc'][0].Curve.Radius @@ -2071,23 +2105,23 @@ def fillet(lEdges,r,chamfer=False): toCenter = arcCenter.sub(lVertexes[1].Point) if arcFirst : # make sure the tangent points towards the arc T = arcAxis.cross(toCenter) - else : + else: T = toCenter.cross(arcAxis) projCenter = toCenter.dot(U1) - if round(abs(projCenter),precision()) > 0 : + if round(abs(projCenter),precision()) > 0: normToLine = U1.cross(T).cross(U1) - else : + else: normToLine = Vector(toCenter) normToLine.normalize() dCenterToLine = toCenter.dot(normToLine) - r - if round(projCenter,precision()) > 0 : + if round(projCenter,precision()) > 0: newRadius = arcRadius - r elif round(projCenter,precision()) < 0 or (round(projCenter,precision()) == 0 and U1.dot(T) > 0): newRadius = arcRadius + r - else : + else: print("DraftGeomUtils.fillet : Warning : edges are already tangent. Did nothing") return rndEdges @@ -2146,9 +2180,7 @@ def fillet(lEdges,r,chamfer=False): return rndEdges elif len(curveType['Arc']) == 2 : - - # Deals with lists of 2 arc-edges -------------------------------------------- - + # Deals with lists of 2 arc-edges ----------------------------------- arcCenter, arcRadius, arcAxis, arcLength, toCenter, T, newRadius = [], [], [], [], [], [], [] for i in range(2) : arcCenter += [curveType['Arc'][i].Curve.Center] @@ -2173,10 +2205,10 @@ def fillet(lEdges,r,chamfer=False): elif T[0].dot(T[1]) > 0 : newRadius += [arcRadius[0]+r] newRadius += [arcRadius[1]+r] - else : + else: print("DraftGeomUtils.fillet : Warning : edges are already tangent. Did nothing") return rndEdges - elif not sameDirection : + elif not sameDirection: if round(TcrossT.dot(arcAxis[0]),precision()) > 0 : newRadius += [arcRadius[0]+r] newRadius += [arcRadius[1]-r] @@ -2247,10 +2279,11 @@ def fillet(lEdges,r,chamfer=False): return rndEdges -def filletWire(aWire,r,chamfer=False): - ''' Fillets each angle of a wire with r as radius value + +def filletWire(aWire, r, chamfer=False): + """Fillets each angle of a wire with r as radius value if chamfer is true, a chamfer is made instead and r is the - size of the chamfer''' + size of the chamfer""" edges = aWire.Edges edges = Part.__sortEdges__(edges) @@ -2268,8 +2301,9 @@ def filletWire(aWire,r,chamfer=False): filEdges[0] = result[2] return Part.Wire(filEdges) + def getCircleFromSpline(edge): - "returns a circle-based edge from a bspline-based edge" + """Return a circle-based edge from a bspline-based edge.""" if geomType(edge) != "BSplineCurve": return None if len(edge.Vertexes) != 1: @@ -2297,7 +2331,8 @@ def getCircleFromSpline(edge): #print(circle.Curve) return circle -def curvetowire(obj,steps): + +def curvetowire(obj, steps): points = obj.copy().discretize(steps) p0 = points[0] edgelist = [] @@ -2307,8 +2342,9 @@ def curvetowire(obj,steps): p0 = p return edgelist -def cleanProjection(shape,tessellate=True,seglength=.05): - "returns a valid compound of edges, by recreating them" + +def cleanProjection(shape, tessellate=True, seglength=0.05): + """Return a valid compound of edges, by recreating them.""" # this is because the projection algorithm somehow creates wrong shapes. # they display fine, but on loading the file the shape is invalid # Now with tanderson's fix to ProjectionAlgos, that isn't the case, but this @@ -2351,7 +2387,8 @@ def cleanProjection(shape,tessellate=True,seglength=.05): print("Debug: error cleaning edge ",e) return Part.makeCompound(newedges) -def curvetosegment(curve,seglen): + +def curvetosegment(curve, seglen): points = curve.discretize(seglen) p0 = points[0] edgelist = [] @@ -2361,9 +2398,10 @@ def curvetosegment(curve,seglen): p0 = p return edgelist -def tessellateProjection(shape,seglen): - ''' Returns projection with BSplines and Ellipses broken into line segments. - Useful for exporting projected views to *dxf files.''' + +def tessellateProjection(shape, seglen): + """Returns projection with BSplines and Ellipses broken into line segments. + Useful for exporting projected views to *dxf files.""" oldedges = shape.Edges newedges = [] for e in oldedges: @@ -2383,8 +2421,7 @@ def tessellateProjection(shape,seglen): return Part.makeCompound(newedges) -def rebaseWire(wire,vidx): - +def rebaseWire(wire, vidx): """rebaseWire(wire,vidx): returns a new wire which is a copy of the current wire, but where the first vertex is the vertex indicated by the given index vidx, starting from 1. 0 will return an exact copy of the wire.""" @@ -2424,9 +2461,9 @@ def removeSplitter(shape): # circle functions ********************************************************* -def getBoundaryAngles(angle,alist): - '''returns the 2 closest angles from the list that - encompass the given angle''' +def getBoundaryAngles(angle, alist): + """returns the 2 closest angles from the list that + encompass the given angle""" negs = True while negs: negs = False @@ -2467,7 +2504,7 @@ def getBoundaryAngles(angle,alist): def circleFrom2tan1pt(tan1, tan2, point): - "circleFrom2tan1pt(edge, edge, Vector)" + """circleFrom2tan1pt(edge, edge, Vector)""" if (geomType(tan1) == "Line") and (geomType(tan2) == "Line") and isinstance(point, FreeCAD.Vector): return circlefrom2Lines1Point(tan1, tan2, point) elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Line") and isinstance(point, FreeCAD.Vector): @@ -2477,8 +2514,9 @@ def circleFrom2tan1pt(tan1, tan2, point): elif (geomType(tan2) == "Circle") and (geomType(tan1) == "Circle") and isinstance(point, FreeCAD.Vector): return circlefrom2Circles1Point(tan2, tan1, point) + def circleFrom2tan1rad(tan1, tan2, rad): - "circleFrom2tan1rad(edge, edge, float)" + """circleFrom2tan1rad(edge, edge, float)""" if (geomType(tan1) == "Line") and (geomType(tan2) == "Line"): return circleFrom2LinesRadius(tan1, tan2, rad) elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Line"): @@ -2488,18 +2526,21 @@ def circleFrom2tan1rad(tan1, tan2, rad): elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Circle"): return circleFrom2CirclesRadius(tan1, tan2, rad) + def circleFrom1tan2pt(tan1, p1, p2): if (geomType(tan1) == "Line") and isinstance(p1, FreeCAD.Vector) and isinstance(p2, FreeCAD.Vector): return circlefrom1Line2Points(tan1, p1, p2) if (geomType(tan1) == "Line") and isinstance(p1, FreeCAD.Vector) and isinstance(p2, FreeCAD.Vector): return circlefrom1Circle2Points(tan1, p1, p2) + def circleFrom1tan1pt1rad(tan1, p1, rad): if (geomType(tan1) == "Line") and isinstance(p1, FreeCAD.Vector): return circleFromPointLineRadius(p1, tan1, rad) if (geomType(tan1) == "Circle") and isinstance(p1, FreeCAD.Vector): return circleFromPointCircleRadius(p1, tan1, rad) + def circleFrom3tan(tan1, tan2, tan3): tan1IsLine = (geomType(tan1) == "Line") tan2IsLine = (geomType(tan2) == "Line") @@ -2524,15 +2565,17 @@ def circleFrom3tan(tan1, tan2, tan3): elif (tan1IsCircle and tan2IsCircle and tan3IsLine): return circleFrom2Circle1Lines(tan1, tan2, tan3) + def circlefrom2Lines1Point(edge1, edge2, point): - "circlefrom2Lines1Point(edge, edge, Vector)" + """circlefrom2Lines1Point(edge, edge, Vector)""" bis = angleBisection(edge1, edge2) if not bis: return None mirrPoint = mirror(point, bis) return circlefrom1Line2Points(edge1, point, mirrPoint) + def circlefrom1Line2Points(edge, p1, p2): - "circlefrom1Line2Points(edge, Vector, Vector)" + """circlefrom1Line2Points(edge, Vector, Vector)""" p1_p2 = edg(p1, p2) s = findIntersection(edge, p1_p2, True, True) if not s: return None @@ -2562,8 +2605,9 @@ def circlefrom1Line2Points(edge, p1, p2): if circles: return circles else: return None -def circleFrom2LinesRadius (edge1, edge2, radius): - "circleFrom2LinesRadius(edge,edge,radius)" + +def circleFrom2LinesRadius(edge1, edge2, radius): + """circleFrom2LinesRadius(edge,edge,radius)""" int = findIntersection(edge1, edge2, True, True) if not int: return None int = int[0] @@ -2584,8 +2628,9 @@ def circleFrom2LinesRadius (edge1, edge2, radius): circles.append(Part.Circle(cen, NORM, radius)) return circles -def circleFrom3LineTangents (edge1, edge2, edge3): - "circleFrom3LineTangents(edge,edge,edge)" + +def circleFrom3LineTangents(edge1, edge2, edge3): + """circleFrom3LineTangents(edge,edge,edge)""" def rot(ed): return Part.LineSegment(v1(ed),v1(ed).add(DraftVecUtils.rotate(vec(ed),math.pi/2))).toShape() bis12 = angleBisection(edge1,edge2) @@ -2630,8 +2675,8 @@ def circleFrom3LineTangents (edge1, edge2, edge3): else: return None -def circleFromPointLineRadius (point, edge, radius): - "circleFromPointLineRadius (point, edge, radius)" +def circleFromPointLineRadius(point, edge, radius): + """circleFromPointLineRadius (point, edge, radius)""" dist = findDistance(point, edge, False) center1 = None center2 = None @@ -2676,8 +2721,9 @@ def circleFromPointLineRadius (point, edge, radius): else: return None + def circleFrom2PointsRadius(p1, p2, radius): - "circleFrom2PointsRadiust(Vector, Vector, radius)" + """circleFrom2PointsRadiust(Vector, Vector, radius)""" if DraftVecUtils.equals(p1, p2): return None p1_p2 = Part.LineSegment(p1, p2).toShape() @@ -2699,9 +2745,8 @@ def circleFrom2PointsRadius(p1, p2, radius): else: return None -def arcFrom2Pts(firstPt,lastPt,center,axis=None): - - '''Builds an arc with center and 2 points, can be oriented with axis''' +def arcFrom2Pts(firstPt, lastPt, center, axis=None): + """Build an arc with center and 2 points, can be oriented with axis.""" radius1 = firstPt.sub(center).Length radius2 = lastPt.sub(center).Length @@ -2730,9 +2775,7 @@ def arcFrom2Pts(firstPt,lastPt,center,axis=None): def outerSoddyCircle(circle1, circle2, circle3): - ''' - Computes the outer soddy circle for three tightly packed circles. - ''' + """Compute the outer soddy circle for three tightly packed circles.""" if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle") \ and (geomType(circle3) == "Circle"): # Original Java code Copyright (rc) 2008 Werner Randelshofer @@ -2782,10 +2825,9 @@ def outerSoddyCircle(circle1, circle2, circle3): # FreeCAD.Console.PrintMessage("debug: outerSoddyCircle bad parameters!\n") return None + def innerSoddyCircle(circle1, circle2, circle3): - ''' - Computes the inner soddy circle for three tightly packed circles. - ''' + """Compute the inner soddy circle for three tightly packed circles.""" if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle") \ and (geomType(circle3) == "Circle"): # Original Java code Copyright (rc) 2008 Werner Randelshofer @@ -2834,12 +2876,13 @@ def innerSoddyCircle(circle1, circle2, circle3): # FreeCAD.Console.PrintMessage("debug: innerSoddyCircle bad parameters!\n") return None + def circleFrom3CircleTangents(circle1, circle2, circle3): - ''' + """ http://en.wikipedia.org/wiki/Problem_of_Apollonius#Inversive_methods http://mathworld.wolfram.com/ApolloniusCircle.html http://mathworld.wolfram.com/ApolloniusProblem.html - ''' + """ if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle") \ and (geomType(circle3) == "Circle"): @@ -2888,9 +2931,9 @@ def circleFrom3CircleTangents(circle1, circle2, circle3): return None -def linearFromPoints (p1, p2): - ''' - Calculate linear equation from points. +def linearFromPoints(p1, p2): + """Calculate linear equation from points. + Calculate the slope and offset parameters of the linear equation of a line defined by two points. Linear equation: @@ -2899,7 +2942,7 @@ def linearFromPoints (p1, p2): m ... Slope b ... Offset (point where the line intersects the y axis) dx/dy ... Delta x and y. Using both as a vector results in a non-offset direction vector. - ''' + """ if isinstance(p1, Vector) and isinstance(p2, Vector): line = {} line['dx'] = (p2.x - p1.x) @@ -2911,11 +2954,11 @@ def linearFromPoints (p1, p2): return None -def determinant (mat,n): - ''' +def determinant(mat, n): + """ determinant(matrix,int) - Determinat function. Returns the determinant of a n-matrix. It recursively expands the minors. - ''' + """ matTemp = [[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]] if (n > 1): if n == 2: @@ -2938,13 +2981,11 @@ def determinant (mat,n): def findHomotheticCenterOfCircles(circle1, circle2): - ''' - findHomotheticCenterOfCircles(circle1, circle2) - Calculates the homothetic center(s) of two circles. + """Calculate the homothetic center(s) of two circles. http://en.wikipedia.org/wiki/Homothetic_center http://mathworld.wolfram.com/HomotheticCenter.html - ''' + """ if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"): if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): @@ -2981,14 +3022,13 @@ def findHomotheticCenterOfCircles(circle1, circle2): return None else: - print("debug: findHomotheticCenterOfCircles bad parameters!\n") FreeCAD.Console.PrintMessage("debug: findHomotheticCenterOfCirclescleFrom3tan bad parameters!\n") return None def findRadicalAxis(circle1, circle2): - ''' - Calculates the radical axis of two circles. + """Calculate the radical axis of two circles. + On the radical axis (also called power line) of two circles any tangents drawn from a point on the axis to both circles have the same length. @@ -2996,8 +3036,7 @@ def findRadicalAxis(circle1, circle2): http://mathworld.wolfram.com/RadicalLine.html @sa findRadicalCenter - ''' - + """ if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"): if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None @@ -3032,14 +3071,12 @@ def findRadicalAxis(circle1, circle2): else: return None else: - print("debug: findRadicalAxis bad parameters!\n") FreeCAD.Console.PrintMessage("debug: findRadicalAxis bad parameters!\n") return None - def findRadicalCenter(circle1, circle2, circle3): - ''' + """ findRadicalCenter(circle1, circle2, circle3): Calculates the radical center (also called the power center) of three circles. It is the intersection point of the three radical axes of the pairs of circles. @@ -3048,8 +3085,7 @@ def findRadicalCenter(circle1, circle2, circle3): http://mathworld.wolfram.com/RadicalCenter.html @sa findRadicalAxis - ''' - + """ if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"): radicalAxis12 = findRadicalAxis(circle1, circle2) radicalAxis23 = findRadicalAxis(circle1, circle2) @@ -3066,22 +3102,21 @@ def findRadicalCenter(circle1, circle2, circle3): # No radical center could be calculated. return None else: - print("debug: findRadicalCenter bad parameters!\n") FreeCAD.Console.PrintMessage("debug: findRadicalCenter bad parameters!\n") return None + def pointInversion(circle, point): - ''' + """Circle inversion of a point. + pointInversion(Circle, Vector) - Circle inversion of a point. Will calculate the inversed point an return it. If the given point is equal to the center of the circle "None" will be returned. See also: http://en.wikipedia.org/wiki/Inversive_geometry - ''' - + """ if (geomType(circle) == "Circle") and isinstance(point, FreeCAD.Vector): cen = circle.Curve.Center rad = circle.Curve.Radius @@ -3102,19 +3137,20 @@ def pointInversion(circle, point): return invPoint else: - print("debug: pointInversion bad parameters!\n") FreeCAD.Console.PrintMessage("debug: pointInversion bad parameters!\n") return None + def polarInversion(circle, edge): - ''' + """Return the inversion pole of a line. + polarInversion(circle, edge): - Returns the inversion pole of a line. + edge ... The polar. i.e. The nearest point on the line is inversed. http://mathworld.wolfram.com/InversionPole.html - ''' + """ if (geomType(circle) == "Circle") and (geomType(edge) == "Line"): nearest = circle.Curve.Center.add(findDistance(circle.Curve.Center, edge, False)) @@ -3122,18 +3158,17 @@ def polarInversion(circle, edge): inversionPole = pointInversion(circle, nearest) if inversionPole: return inversionPole - else: - print("debug: circleInversionPole bad parameters!\n") FreeCAD.Console.PrintMessage("debug: circleInversionPole bad parameters!\n") return None + def circleInversion(circle, circle2): - ''' + """ pointInversion(Circle, Circle) Circle inversion of a circle. - ''' + """ if (geomType(circle) == "Circle") and (geomType(circle2) == "Circle"): cen1 = circle.Curve.Center rad1 = circle.Curve.Radius @@ -3149,7 +3184,6 @@ def circleInversion(circle, circle2): return Part.Circle(invCen2, norm, DraftVecUtils.dist(invCen2, invPointOnCircle2)) else: - print("debug: circleInversion bad parameters!\n") FreeCAD.Console.PrintMessage("debug: circleInversion bad parameters!\n") return None From 33d82d44dc8bba80bc38332d422d00a2d0b252ef Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sat, 29 Feb 2020 16:46:01 -0600 Subject: [PATCH 18/62] Draft: clean up gui_arrays and gui_base Small spacing fixes like imports in separate lines for more clarity, the module docstring, and the position of the license. Remove unused imports. And use proper `ToDo` class instead of importing `DraftGui`. --- src/Mod/Draft/draftguitools/gui_arrays.py | 19 +++++++++++-------- src/Mod/Draft/draftguitools/gui_base.py | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_arrays.py b/src/Mod/Draft/draftguitools/gui_arrays.py index 49a7f096f5..81bff17fbb 100644 --- a/src/Mod/Draft/draftguitools/gui_arrays.py +++ b/src/Mod/Draft/draftguitools/gui_arrays.py @@ -1,8 +1,3 @@ -"""Provide the Draft ArrayTools command to group the other array tools.""" -## @package gui_arrays -# \ingroup DRAFT -# \brief Provide the Draft ArrayTools command to group the other array tools. - # *************************************************************************** # * (c) 2020 Eliud Cabrera Castillo * # * * @@ -25,9 +20,14 @@ # * USA * # * * # *************************************************************************** +"""Provide the Draft ArrayTools command to group the other array tools.""" +## @package gui_arrays +# \ingroup DRAFT +# \brief Provide the Draft ArrayTools command to group the other array tools. +from PySide.QtCore import QT_TRANSLATE_NOOP + import FreeCAD as App import FreeCADGui as Gui -from PySide.QtCore import QT_TRANSLATE_NOOP class ArrayGroupCommand: @@ -49,8 +49,11 @@ class ArrayGroupCommand: 'ToolTip': QT_TRANSLATE_NOOP("Arch", _tooltip)} def IsActive(self): - """Be active only when a document is active.""" - return App.ActiveDocument is not None + """Return True when this command should be available.""" + if App.ActiveDocument: + return True + else: + return False Gui.addCommand('Draft_ArrayTools', ArrayGroupCommand()) diff --git a/src/Mod/Draft/draftguitools/gui_base.py b/src/Mod/Draft/draftguitools/gui_base.py index f307b67315..1a149cc8cc 100644 --- a/src/Mod/Draft/draftguitools/gui_base.py +++ b/src/Mod/Draft/draftguitools/gui_base.py @@ -1,9 +1,3 @@ -"""This module provides the Base object for all Draft Gui commands. -""" -## @package gui_base -# \ingroup DRAFT -# \brief This module provides the Base object for all Draft Gui commands. - # *************************************************************************** # * (c) 2009 Yorik van Havre * # * (c) 2010 Ken Cline * @@ -28,10 +22,14 @@ # * USA * # * * # *************************************************************************** +"""Provide the Base object for all Draft Gui commands.""" +## @package gui_base +# \ingroup DRAFT +# \brief This module provides the Base object for all Draft Gui commands. import FreeCAD as App import FreeCADGui as Gui -import DraftGui +import draftutils.todo as todo class GuiCommandBase: @@ -52,7 +50,7 @@ class GuiCommandBase: Each string in the list of strings represents a Python instruction which will be executed in a delayed fashion - by `DraftGui.todo.delayCommit()` + by `todo.ToDo.delayCommit()` :: list1 = ["a = FreeCAD.Vector()", "pl = FreeCAD.Placement()", @@ -69,6 +67,7 @@ class GuiCommandBase: >>> pl = FreeCAD.Placement() >>> Draft.autogroup(obj) """ + def __init__(self): self.call = None self.commit_list = [] @@ -78,7 +77,8 @@ class GuiCommandBase: self.planetrack = None def IsActive(self): - if Gui.ActiveDocument: + """Return True when this command should be available.""" + if App.ActiveDocument: return True else: return False @@ -102,7 +102,7 @@ class GuiCommandBase: pass self.call = None if self.commit_list: - DraftGui.todo.delayCommit(self.commit_list) + todo.ToDo.delayCommit(self.commit_list) self.commit_list = [] def commit(self, name, func): From d5e80819b19f054bd6f75ce40a696df07d79f460 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sat, 29 Feb 2020 19:06:53 -0600 Subject: [PATCH 19/62] Draft: gui_circulararray cleanup Small spacing fixes like imports in separate lines for more clarity, the module docstring, and the position of the license. Remove unnecessary check for the graphical interface as this command should be imported when the interface is already up and running. Use proper `ToDo` class instead of importing `DraftGui`. --- .../Draft/draftguitools/gui_circulararray.py | 56 ++++++------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_circulararray.py b/src/Mod/Draft/draftguitools/gui_circulararray.py index e75139f35e..955230df14 100644 --- a/src/Mod/Draft/draftguitools/gui_circulararray.py +++ b/src/Mod/Draft/draftguitools/gui_circulararray.py @@ -1,9 +1,3 @@ -"""This module provides the Draft CircularArray tool. -""" -## @package gui_circulararray -# \ingroup DRAFT -# \brief This module provides the Draft CircularArray tool. - # *************************************************************************** # * (c) 2019 Eliud Cabrera Castillo * # * * @@ -26,41 +20,28 @@ # * USA * # * * # *************************************************************************** +"""Provides the Draft CircularArray tool.""" +## @package gui_circulararray +# \ingroup DRAFT +# \brief This module provides the Draft CircularArray tool. + +from pivy import coin +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD as App import FreeCADGui as Gui import Draft -import DraftGui import Draft_rc -from . import gui_base +from draftguitools import gui_base from drafttaskpanels import task_circulararray +import draftutils.todo as todo - -if App.GuiUp: - from PySide.QtCore import QT_TRANSLATE_NOOP - # import DraftTools - from DraftGui import translate - # from DraftGui import displayExternal - from pivy import coin -else: - def QT_TRANSLATE_NOOP(context, text): - return text - - def translate(context, text): - return text - - -def _tr(text): - """Function to translate with the context set""" - return translate("Draft", text) - - -# So the resource file doesn't trigger errors from code checkers (flake8) +# The module is used to prevent complaints from code checkers (flake8) True if Draft_rc.__name__ else False class GuiCommandCircularArray(gui_base.GuiCommandBase): - """Gui command for the CircularArray tool""" + """Gui command for the CircularArray tool.""" def __init__(self): super().__init__() @@ -74,6 +55,7 @@ class GuiCommandCircularArray(gui_base.GuiCommandBase): self.point = App.Vector() def GetResources(self): + """Set icon, menu and tooltip.""" _msg = ("Creates copies of a selected object, " "and places the copies in a circular pattern.\n" "The properties of the array can be further modified after " @@ -85,7 +67,7 @@ class GuiCommandCircularArray(gui_base.GuiCommandBase): return d def Activated(self): - """This is called when the command is executed. + """Execute when the command is called. We add callbacks that connect the 3D view with the widgets of the task panel. @@ -103,10 +85,10 @@ class GuiCommandCircularArray(gui_base.GuiCommandBase): # of the interface, to be able to call a function from within it. self.ui.source_command = self # Gui.Control.showDialog(self.ui) - DraftGui.todo.delay(Gui.Control.showDialog, self.ui) + todo.ToDo.delay(Gui.Control.showDialog, self.ui) def move(self, event_cb): - """This is a callback for when the mouse pointer moves in the 3D view. + """Execute as a callback when the pointer moves in the 3D view. It should automatically update the coordinates in the widgets of the task panel. @@ -119,7 +101,7 @@ class GuiCommandCircularArray(gui_base.GuiCommandBase): self.ui.display_point(self.point) def click(self, event_cb=None): - """This is a callback for when the mouse pointer clicks on the 3D view. + """Execute as a callback when the pointer clicks on the 3D view. It should act as if the Enter key was pressed, or the OK button was pressed in the task panel. @@ -136,7 +118,7 @@ class GuiCommandCircularArray(gui_base.GuiCommandBase): self.ui.accept() def completed(self): - """This is called when the command is terminated. + """Execute when the command is terminated. We should remove the callbacks that were added to the 3D view and then close the task panel. @@ -146,10 +128,8 @@ class GuiCommandCircularArray(gui_base.GuiCommandBase): self.view.removeEventCallbackPivy(self.mouse_event, self.callback_click) if Gui.Control.activeDialog(): - Gui.Snapper.off() Gui.Control.closeDialog() super().finish() -if App.GuiUp: - Gui.addCommand('Draft_CircularArray', GuiCommandCircularArray()) +Gui.addCommand('Draft_CircularArray', GuiCommandCircularArray()) From bc84eda70f21efd02053ad445be0f3add0b32979 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sat, 29 Feb 2020 19:41:49 -0600 Subject: [PATCH 20/62] Draft: gui_edit cleanup Small spacing fixes like imports in separate lines for more clarity, the module docstring, the position of the license, and trailing spaces. Remove unnecessary check for the graphical interface as this command should be imported when the interface is already up and running. Properly import `gui_trackers` module and use tracker classes prefixed accordingly. --- src/Mod/Draft/draftguitools/gui_edit.py | 291 +++++++++++------------- 1 file changed, 138 insertions(+), 153 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_edit.py b/src/Mod/Draft/draftguitools/gui_edit.py index 09d5687e50..8220f3083b 100644 --- a/src/Mod/Draft/draftguitools/gui_edit.py +++ b/src/Mod/Draft/draftguitools/gui_edit.py @@ -1,94 +1,89 @@ +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * Copyright (c) 2019, 2020 Carlo Pavan * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** """Provide the Draft_Edit command used by the Draft workbench.""" ## @package gui_edit # \ingroup DRAFT # \brief Provide the Draft_Edit command used by the Draft workbench -#*************************************************************************** -#* Copyright (c) 2009, 2010 Yorik van Havre * -#* Copyright (c) 2009, 2010 Ken Cline * -#* Copyright (c) 2019, 2020 Carlo Pavan * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** - -__title__= "FreeCAD Draft Edit Tool" -__author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, \ - Dmitry Chigrin, Carlo Pavan" -__url__ = "https://www.freecadweb.org" +import math +from pivy import coin +from PySide import QtCore, QtGui import FreeCAD as App -import math +import FreeCADGui as Gui import Draft +import DraftTools +from draftutils.translate import translate +import draftguitools.gui_trackers as trackers -if App.GuiUp: - # Do not import GUI-related modules if GUI is not there - import FreeCADGui as Gui - import DraftTools - from draftguitools.gui_trackers import editTracker, wireTracker, arcTracker, bsplineTracker, bezcurveTracker - from pivy import coin - from PySide import QtCore, QtGui - from PySide.QtCore import QT_TRANSLATE_NOOP - from DraftTools import translate +__title__ = "FreeCAD Draft Edit Tool" +__author__ = ("Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, " + "Dmitry Chigrin, Carlo Pavan") +__url__ = "https://www.freecadweb.org" - COLORS = { - "default": Gui.draftToolBar.getDefaultColor("snap"), - "black": (0., 0., 0.), - "white": (1., 1., 1.), - "grey": (.5, .5, .5), - "red": (1., 0., 0.), - "green": (0., 1., 0.), - "blue": (0., 0., 1.), - "yellow": (1., 1., 0.), - "cyan": (0., 1., 1.), - "magenta":(1., 0., 1.) - } +COLORS = { + "default": Gui.draftToolBar.getDefaultColor("snap"), + "black": (0., 0., 0.), + "white": (1., 1., 1.), + "grey": (.5, .5, .5), + "red": (1., 0., 0.), + "green": (0., 1., 0.), + "blue": (0., 0., 1.), + "yellow": (1., 1., 0.), + "cyan": (0., 1., 1.), + "magenta": (1., 0., 1.) +} -class Edit(): - """ - The Draft_Edit FreeCAD command definition. +class Edit: + """The Draft_Edit FreeCAD command definition. + A tool to graphically edit FreeCAD objects. Current implementation use many parts of pivy graphics code by user "looo". - The tool collect editpoints from objects and display Trackers on them to allow - editing their Shape and their parameters. - + The tool collect editpoints from objects and display Trackers on them + to allow editing their Shape and their parameters. Callbacks - ---------- + --------- selection_callback registered when tool is launched, identify selected objects. - + editing_callbacks self._keyPressedCB -> self.keyPressed self._mouseMovedCB -> self._mouseMovedCB if self._mousePressedCB -> self.mousePressed when trackers are displayed for selected objects, - these callbacks capture user events and forward + these callbacks capture user events and forward them to related functions - Task panel (Draft Toolbar) ---------- self.ui = Gui.draftToolBar TODO: since we introduced context menu for interacting - with editTrackers, point 2 should become obsolete, + with editTrackers, point 2 should become obsolete, because not consistent with multi-object editing. + Draft_Edit uses taskpanel in 3 ways: 1 - when waiting for user to select an object @@ -112,62 +107,58 @@ class Edit(): self.ui.lineUi() self.ui.isRelative.show() - Tracker selection - ---------- + ----------------- If the tool recognize mouse click as an attempt to startEditing, using soRayPickAction, it identifies the selected editTracker and start editing it. Here is where "looo" code was very useful. Editing preview - ---------- - When object editing begins, self.ghost is initiated with the + --------------- + When object editing begins, self.ghost is initiated with the corresponding DraftTracker of the object type. The object Tracker is deleted when user clicks again and endEditing. - Context Menu - ---------- + ------------ Activated with Alt+LeftClick or pressing key "e" It's a custom context menu, that depends on clicked tracker or on clicked object. display_tracker_menu populates the menu with custom actions - + evaluate_menu_action evaluate user chosen action and launch corresponding function. - Preferences - ---------- - maxObjects : Int + ----------- + maxObjects: Int set by "DraftEditMaxObjects" in user preferences The max number of FreeCAD objects the tool is allowed to edit at the same time. - pick_radius : Int + pick_radius: Int set by "DraftEditPickRadius" in user preferences The pick radius during editing operation. Increase if you experience problems in clicking on a editTracker because of screen resolution. - Attributes ---------- - obj : Edited object + obj: Edited object I'm planning to discard this attribute. - In old implementation every function was supposed to + In old implementation every function was supposed to act on self.obj, self.editpoints, self.trackers, self.pl, self.invpl. Due to multiple object editing, i'm planning to keep just self.trackers. Any other object will be identified and processed starting from editTracker information. - - editing : Int - Index of the editTracker that has been clicked by the + + editing: Int + Index of the editTracker that has been clicked by the user. Tracker selection mechanism is based on it. if self.editing == None : the user didn't click any node, and next click will @@ -176,51 +167,48 @@ class Edit(): the user is editing corresponding node, so next click will be processed as an attempt to end editing operation - editpoints : List [FreeCAD::App.Vector] - List of editpoints collected from the edited object, + editpoints: List [FreeCAD::App.Vector] + List of editpoints collected from the edited object, on whick editTrackers will be placed. - trackers : Dictionary {object.Name : [editTrackers]} + trackers: Dictionary {object.Name : [editTrackers]} It records the list of DraftTrackers.editTracker. {object.Name as String : [editTrackers for the object]} - Each tracker is created with (position,obj.Name,idx), - so it's possible to recall it + Each tracker is created with (position,obj.Name,idx), + so it's possible to recall it self.trackers[str(node.objectName.getValue())][ep] - overNode : DraftTrackers.editTracker + overNode: DraftTrackers.editTracker It represent the editTracker under the cursor position. It is used to preview the tracker selection action. - ghost : DraftTrackers.* + ghost: DraftTrackers.* Handles the tracker to preview editing operations. it is initialized when user clicks on a editTracker by self.startEditing() function. - alt_edit_mode : Int + alt_edit_mode: Int Allows alternative editing modes for objects. ATM supported for: - - arcs: if 0 edit by 3 points, if 1 edit by center, + - arcs: if 0 edit by 3 points, if 1 edit by center, radius, angles - supportedObjs : List + supportedObjs: List List of supported Draft Objects. The tool use Draft.getType(obj) to compare object type to the list. - supportedPartObjs : List + supportedPartObjs: List List of supported Part Objects. - The tool use Draft.getType(obj) and obj.TypeId to compare + The tool use Draft.getType(obj) and obj.TypeId to compare object type to the list. - """ - + def __init__(self): - """ - Initialize Draft_Edit Command. - """ + """Initialize Draft_Edit Command.""" self.running = False - self.trackers = {'object':[]} - self.overNode = None # preselected node with mouseover + self.trackers = {'object': []} + self.overNode = None # preselected node with mouseover self.obj = None self.editing = None @@ -269,9 +257,9 @@ class Edit(): } - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # MAIN FUNCTIONS - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def Activated(self): """ @@ -361,9 +349,9 @@ class Edit(): from PySide import QtCore QtCore.QTimer.singleShot(0,Gui.ActiveDocument.resetEdit) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # SCENE EVENTS CALLBACKS - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def register_selection_callback(self): """ @@ -416,9 +404,9 @@ class Edit(): self._mousePressedCB = None #App.Console.PrintMessage("Draft edit mouse button callback unregistered \n") - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # SCENE EVENT HANDLERS - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def keyPressed(self, event_callback): """ @@ -456,7 +444,7 @@ class Edit(): self.endEditing(self.obj,self.editing) elif event.wasAltDown(): #left click with ctrl down self.display_tracker_menu(event) - + def mouseMoved(self, event_callback): "mouse moved event handler, update tracker position and update preview ghost" event = event_callback.getEvent() @@ -536,9 +524,9 @@ class Edit(): self.showTrackers() DraftTools.redraw3DView() - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # UTILS - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def getObjsFromSelection(self): "evaluate selection and returns a valid object to edit" @@ -650,9 +638,9 @@ class Edit(): return None - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT TRACKERS functions - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def setTrackers(self, obj, points=None): "set Edit Trackers for editpoints collected from self.obj" @@ -671,7 +659,7 @@ class Edit(): if obj.Name in self.trackers: self.removeTrackers(obj) for ep in range(len(points)): - self.trackers[obj.Name].append(editTracker(pos=points[ep],name=obj.Name,idx=ep)) + self.trackers[obj.Name].append(trackers.editTracker(pos=points[ep],name=obj.Name,idx=ep)) def resetTrackers(self, obj): "reset Edit Trackers and set them again" @@ -726,20 +714,20 @@ class Edit(): for t in self.trackers[obj.Name]: t.on() - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # PREVIEW - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def initGhost(self,obj): "initialize preview ghost" if Draft.getType(obj) == "Wire": - return wireTracker(obj.Shape) + return trackers.wireTracker(obj.Shape) elif Draft.getType(obj) == "BSpline": - return bsplineTracker() + return trackers.bsplineTracker() elif Draft.getType(obj) == "BezCurve": - return bezcurveTracker() + return trackers.bezcurveTracker() elif Draft.getType(obj) == "Circle": - return arcTracker() + return trackers.arcTracker() def updateGhost(self,obj,idx,pt): if Draft.getType(obj) in ["Wire"]: @@ -830,9 +818,9 @@ class Edit(): except: return - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : Add/Delete Vertexes - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def addPoint(self,event): "called by action, add point to obj and reset trackers" @@ -863,7 +851,7 @@ class Edit(): self.obj.recompute() self.removeTrackers(self.obj) self.setEditPoints(self.obj) - #self.setSelectState(self.obj, False) + # self.setSelectState(self.obj, False) return @@ -971,9 +959,9 @@ class Edit(): self.removeTrackers(self.obj) self.setEditPoints(self.obj) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : GENERAL - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def setEditPoints(self,obj): "append given object's editpoints to self.edipoints and set EditTrackers" @@ -1007,7 +995,7 @@ class Edit(): elif objectType == "Dimension": return self.getDimensionPts(obj) elif objectType == "Wall": - return self.getWallPts(obj) + return self.getWallPts(obj) elif objectType == "Window": return self.getWindowPts(obj) elif objectType == "Space": @@ -1073,9 +1061,9 @@ class Edit(): except AttributeError as err: pass - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : Line/Wire/Bspline/Bezcurve - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def getWirePts(self,obj): editpoints = [] @@ -1106,7 +1094,7 @@ class Edit(): return if Draft.getType(obj) in ["BezCurve"]: pts = self.recomputePointsBezier(obj,pts,nodeIndex,v,obj.Degree,moveTrackers=False) - + if obj.Closed: # check that the new point lies on the plane of the wire if hasattr(obj.Shape,"normalAt"): @@ -1202,7 +1190,7 @@ class Edit(): for index, pwm in enumerate(pointswithmarkers): p,marker = pwm #if self.pl: p = self.pl.multVec(p) - self.trackers[obj.Name].append(editTracker(p,obj.Name, + self.trackers[obj.Name].append(trackers.editTracker(p,obj.Name, index,obj.ViewObject.LineColor,marker=marker)) def smoothBezPoint(self, obj, point, style='Symmetric'): @@ -1294,9 +1282,9 @@ class Edit(): obj.Continuity = newcont self.resetTrackers(obj) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : Rectangle - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def getRectanglePts(self, obj): """ @@ -1329,9 +1317,9 @@ class Edit(): obj.Height = DraftVecUtils.project(delta,App.Vector(0,1,0)).Length self.updateRectangleTrackers(obj) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : Ellipse (# TODO: yet to be implemented) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def setEllipsePts(self): return @@ -1339,9 +1327,9 @@ class Edit(): def updateEllipse(self,v): return - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : Circle/Arc - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def getCirclePts(self, obj): """ @@ -1406,15 +1394,15 @@ class Edit(): self.setPlacement(obj) else: - if nodeIndex == 1:#first point + if nodeIndex == 1: # first point p1=v p2=self.getArcMid(obj,global_placement=True) p3=self.getArcEnd(obj,global_placement=True) - elif nodeIndex == 3:#midpoint + elif nodeIndex == 3: # midpoint p1=self.getArcStart(obj,global_placement=True) p2=v p3=self.getArcEnd(obj,global_placement=True) - elif nodeIndex == 2:#second point + elif nodeIndex == 2: # second point p1=self.getArcStart(obj,global_placement=True) p2=self.getArcMid(obj,global_placement=True) p3=v @@ -1477,9 +1465,9 @@ class Edit(): obj.recompute() self.updateCircleTrackers(obj) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : Polygon (maybe could also rotate the polygon) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def getPolygonPts(self, obj): editpoints = [] @@ -1504,9 +1492,9 @@ class Edit(): self.obj.recompute() self.trackers[self.obj.Name][1].set(self.obj.Shape.Vertexes[0].Point) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : Dimension (point on dimension line is not clickable) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- def getDimensionPts(self, obj): editpoints = [] @@ -1527,11 +1515,11 @@ class Edit(): elif self.editing == 3: self.obj.ViewObject.TextPosition = v - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- # EDIT OBJECT TOOLS : ARCH Wall, Windows, Structure, Panel, etc. - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------- - # SKETCH: just if it's composed by a single segment------------------------- + # SKETCH: just if it's composed by a single segment----------------------- def getSketchPts(self, obj): """ @@ -1565,7 +1553,7 @@ class Edit(): obj.recompute() - #WALL----------------------------------------------------------------------- + # WALL--------------------------------------------------------------------- def getWallPts(self, obj): """ @@ -1610,7 +1598,7 @@ class Edit(): obj.recompute() - #WINDOW--------------------------------------------------------------------- + # WINDOW------------------------------------------------------------------- def getWindowPts(self, obj): import DraftGeomUtils @@ -1641,7 +1629,7 @@ class Edit(): obj.recompute() self.obj.recompute() - #STRUCTURE------------------------------------------------------------------- + # STRUCTURE---------------------------------------------------------------- def getStructurePts(self, obj): if obj.Nodes: @@ -1665,7 +1653,7 @@ class Edit(): nodes[self.editing] = self.invpl.multVec(v) self.obj.Nodes = nodes - #SPACE---------------------------------------------------------------------- + # SPACE-------------------------------------------------------------------- def getSpacePts(self, obj): try: @@ -1679,7 +1667,7 @@ class Edit(): if self.editing == 0: self.obj.ViewObject.TextPosition = v - #PANELS--------------------------------------------------------------------- + # PANELS------------------------------------------------------------------- def getPanelCutPts(self, obj): editpoints = [] @@ -1707,7 +1695,7 @@ class Edit(): else: self.obj.Group[self.editing-1].Placement.Base = self.invpl.multVec(v) - # PART::LINE---------------------------------------------------------------- + # PART::LINE-------------------------------------------------------------- def getPartLinePts(self, obj): editpoints = [] @@ -1726,7 +1714,7 @@ class Edit(): self.obj.Y2 = pt.y self.obj.Z2 = pt.z - # PART::BOX----------------------------------------------------------------- + # PART::BOX--------------------------------------------------------------- def getPartBoxPts(self, obj): editpoints = [] @@ -1756,9 +1744,9 @@ class Edit(): self.trackers[self.obj.Name][2].set(self.pl.multVec(App.Vector(0,self.obj.Width,0))) self.trackers[self.obj.Name][3].set(self.pl.multVec(App.Vector(0,0,self.obj.Height))) - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------ # Context menu - #--------------------------------------------------------------------------- + # ------------------------------------------------------------------------ def display_tracker_menu(self, event): self.tracker_menu = QtGui.QMenu() @@ -1829,7 +1817,4 @@ class Edit(): del self.event - -if App.GuiUp: - # setup command - Gui.addCommand('Draft_Edit', Edit()) +Gui.addCommand('Draft_Edit', Edit()) From f329fbeb40f4cc753d71e5fdb3cfe9cd51bafcb2 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sun, 1 Mar 2020 01:31:28 -0600 Subject: [PATCH 21/62] Draft: gui_edit, many small spacing and docstring edits --- src/Mod/Draft/draftguitools/gui_edit.py | 375 ++++++++++++------------ 1 file changed, 189 insertions(+), 186 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_edit.py b/src/Mod/Draft/draftguitools/gui_edit.py index 8220f3083b..a8c3e3a574 100644 --- a/src/Mod/Draft/draftguitools/gui_edit.py +++ b/src/Mod/Draft/draftguitools/gui_edit.py @@ -269,7 +269,7 @@ class Edit: """ if self.running: self.finish() - DraftTools.Modifier.Activated(self,"Edit") + DraftTools.Modifier.Activated(self, "Edit") if not App.ActiveDocument: self.finish() @@ -281,26 +281,26 @@ class Edit: else: self.ui.selectUi() App.Console.PrintMessage(translate("draft", - "Select a Draft object to edit") - + "\n") + "Select a Draft object to edit") + + "\n") self.register_selection_callback() def proceed(self): - "this method defines editpoints and set the editTrackers" + """this method defines editpoints and set the editTrackers""" self.unregister_selection_callback() self.edited_objects = self.getObjsFromSelection() if not self.edited_objects: - return self.finish() + return self.finish() # Save selectstate and turn selectable false. # Object can remain selectable commenting following lines: - # self.saveSelectState(self.obj) + # self.saveSelectState(self.obj) # self.setSelectState(self.obj, False) # start object editing Gui.Selection.clearSelection() Gui.Snapper.setSelectMode(True) - + self.ui.editUi() for obj in self.edited_objects: @@ -313,10 +313,8 @@ class Edit: # self.alignWorkingPlane() - def finish(self,closed=False): - """ - terminates Edit Tool - """ + def finish(self, closed=False): + """Terminate Edit Tool.""" self.unregister_selection_callback() self.unregister_editing_callbacks() self.editing = None @@ -347,16 +345,14 @@ class Edit: self.running = False # delay resetting edit mode otherwise it doesn't happen from PySide import QtCore - QtCore.QTimer.singleShot(0,Gui.ActiveDocument.resetEdit) + QtCore.QTimer.singleShot(0, Gui.ActiveDocument.resetEdit) # ------------------------------------------------------------------------- # SCENE EVENTS CALLBACKS # ------------------------------------------------------------------------- def register_selection_callback(self): - """ - register callback for selection when command is launched - """ + """Register callback for selection when command is launched.""" self.unregister_selection_callback() self.selection_callback = self.view.addEventCallback("SoEvent",DraftTools.selectObject) @@ -365,7 +361,7 @@ class Edit: remove selection callback if it exists """ if self.selection_callback: - self.view.removeEventCallback("SoEvent",self.selection_callback) + self.view.removeEventCallback("SoEvent", self.selection_callback) self.selection_callback = None def register_editing_callbacks(self): @@ -409,23 +405,21 @@ class Edit: # ------------------------------------------------------------------------- def keyPressed(self, event_callback): - """ - keyboard event handler - """ - #TODO: Get the keys from preferences + """Execute as callback for keyboard event.""" + # TODO: Get the keys from preferences event = event_callback.getEvent() if event.getState() == coin.SoKeyboardEvent.DOWN: key = event.getKey() - #App.Console.PrintMessage("pressed key : "+str(key)+"\n") - if key == 65307: # ESC + # App.Console.PrintMessage("pressed key : "+str(key)+"\n") + if key == 65307: # ESC self.finish() - if key == 97: # "a" + if key == 97: # "a" self.finish() - if key == 111: # "o" + if key == 111: # "o" self.finish(closed=True) - if key == 101: # "e" + if key == 101: # "e" self.display_tracker_menu(event) - if key == 105: # "i" + if key == 105: # "i" if Draft.getType(self.obj) == "Circle": self.arcInvert(self.obj) @@ -441,14 +435,17 @@ class Edit: if self.editing is None: self.startEditing(event) else: - self.endEditing(self.obj,self.editing) - elif event.wasAltDown(): #left click with ctrl down + self.endEditing(self.obj, self.editing) + elif event.wasAltDown(): # left click with ctrl down self.display_tracker_menu(event) def mouseMoved(self, event_callback): - "mouse moved event handler, update tracker position and update preview ghost" + """Execute as callback for mouse movement. + + Update tracker position and update preview ghost. + """ event = event_callback.getEvent() - if self.editing != None: + if self.editing is not None: self.updateTrackerAndGhost(event) else: # look for a node in mouse position and highlight it @@ -466,7 +463,7 @@ class Edit: self.overNode = None def startEditing(self, event): - "start editing selected EditNode" + """Start editing selected EditNode.""" pos = event.getPosition() node = self.getEditNode(pos) ep = self.getEditNodeIndex(node) @@ -494,18 +491,19 @@ class Edit: self.hideTrackers() def updateTrackerAndGhost(self, event): - "updates tracker position when editing and update ghost" + """Update tracker position when editing and update ghost.""" pos = event.getPosition().getValue() orthoConstrain = False - if event.wasShiftDown() == 1: orthoConstrain = True + if event.wasShiftDown() == 1: + orthoConstrain = True snappedPos = Gui.Snapper.snap((pos[0],pos[1]),self.node[-1], constrain=orthoConstrain) self.trackers[self.obj.Name][self.editing].set(snappedPos) - self.ui.displayPoint(snappedPos,self.node[-1]) + self.ui.displayPoint(snappedPos, self.node[-1]) if self.ghost: - self.updateGhost(obj=self.obj,idx=self.editing,pt=snappedPos) + self.updateGhost(obj=self.obj, idx=self.editing, pt=snappedPos) - def endEditing(self, obj, nodeIndex, v = None): - "terminate editing and start object updating process" + def endEditing(self, obj, nodeIndex, v=None): + """Terminate editing and start object updating process.""" self.finalizeGhost() self.trackers[obj.Name][nodeIndex].on() Gui.Snapper.setSelectMode(True) @@ -529,7 +527,7 @@ class Edit: # ------------------------------------------------------------------------- def getObjsFromSelection(self): - "evaluate selection and returns a valid object to edit" + """Evaluate selection and return a valid object to edit.""" selection = Gui.Selection.getSelection() self.edited_objects = [] if len(selection) > self.maxObjects: @@ -552,8 +550,9 @@ class Edit: return self.edited_objects def get_selected_obj_at_position(self, pos): - """return object at given position - if object is one of the edited objects (self.edited_objects) + """Return object at given position. + + If object is one of the edited objects (self.edited_objects). """ selobjs = Gui.ActiveDocument.ActiveView.getObjectsInfo((pos[0],pos[1])) if not selobjs: @@ -566,19 +565,22 @@ class Edit: return obj def numericInput(self, v, numy=None, numz=None): - """this function gets called by the toolbar - or by the mouse click and activate the update function""" - if (numy is not None): - v = App.Vector(v,numy,numz) + """Execute callback by the toolbar to activate the update function. + + This function gets called by the toolbar + or by the mouse click and activate the update function. + """ + if numy: + v = App.Vector(v, numy, numz) self.endEditing(self.obj, self.editing, v) App.ActiveDocument.recompute() - def setSelectState(self, obj, selState = False): - if hasattr(obj.ViewObject,"Selectable"): + def setSelectState(self, obj, selState=False): + if hasattr(obj.ViewObject, "Selectable"): obj.ViewObject.Selectable = selState def saveSelectState(self, obj): - if hasattr(obj.ViewObject,"Selectable"): + if hasattr(obj.ViewObject, "Selectable"): self.selectstate = obj.ViewObject.Selectable def restoreSelectState(self,obj): @@ -586,8 +588,12 @@ class Edit: if hasattr(obj.ViewObject,"Selectable") and (self.selectstate is not None): obj.ViewObject.Selectable = self.selectstate - def setPlacement(self,obj): - "set self.pl and self.invpl to self.obj placement and inverse placement" + def setPlacement(self, obj): + """Set placement of object. + + Set self.pl and self.invpl to self.obj placement + and inverse placement. + """ if not obj: return if "Placement" in obj.PropertiesList: @@ -595,7 +601,7 @@ class Edit: self.invpl = self.pl.inverse() def alignWorkingPlane(self): - "align working plane to self.obj" + """Align working plane to self.obj.""" if "Shape" in self.obj.PropertiesList: if DraftTools.plane.weak: DraftTools.plane.alignToFace(self.obj.Shape) @@ -603,12 +609,12 @@ class Edit: self.planetrack.set(self.editpoints[0]) def getEditNode(self, pos): - "get edit node from given screen position" + """Get edit node from given screen position.""" node = self.sendRay(pos) return node def sendRay(self, mouse_pos): - "sends a ray through the scene and return the nearest entity" + """Send a ray through the scene and return the nearest entity.""" ray_pick = coin.SoRayPickAction(self.render_manager.getViewportRegion()) ray_pick.setPoint(coin.SbVec2s(*mouse_pos)) ray_pick.setRadius(self.pick_radius) @@ -618,7 +624,7 @@ class Edit: return self.searchEditNode(picked_point) def searchEditNode(self, picked_point): - "search edit node inside picked point list and retrurn node number" + """Search edit node inside picked point list and return node number.""" for point in picked_point: path = point.getPath() length = path.getLength() @@ -629,7 +635,7 @@ class Edit: return None def getEditNodeIndex(self, point): - "get edit node index from given screen position" + """Get edit node index from given screen position.""" if point: subElement = str(point.subElementName.getValue()) ep = int(subElement[8:]) @@ -637,19 +643,18 @@ class Edit: else: return None - # ------------------------------------------------------------------------- # EDIT TRACKERS functions # ------------------------------------------------------------------------- def setTrackers(self, obj, points=None): - "set Edit Trackers for editpoints collected from self.obj" + """Set Edit Trackers for editpoints collected from self.obj.""" if points is None or len(points) == 0: App.Console.PrintWarning(translate("draft", - "No edit point found for selected object") - + "\n") + "No edit point found for selected object") + + "\n") # do not finish if some trackers are still present - if self.trackers == {'object':[]}: + if self.trackers == {'object': []}: self.finish() return self.trackers[obj.Name] = [] @@ -662,12 +667,12 @@ class Edit: self.trackers[obj.Name].append(trackers.editTracker(pos=points[ep],name=obj.Name,idx=ep)) def resetTrackers(self, obj): - "reset Edit Trackers and set them again" + """Reset Edit Trackers and set them again.""" self.removeTrackers(obj) self.setTrackers(obj, self.getEditPoints(obj)) - def removeTrackers(self, obj = None): - "reset Edit Trackers and set them again" + def removeTrackers(self, obj=None): + """Remove Edit Trackers.""" if obj: if obj.Name in self.trackers: for t in self.trackers[obj.Name]: @@ -677,16 +682,16 @@ class Edit: for key in self.trackers.keys(): for t in self.trackers[key]: t.finalize() - self.trackers = {'object':[]} + self.trackers = {'object': []} def hideTrackers(self, obj=None): - """hide Edit Trackers + """Hide Edit Trackers. Attributes ---------- - obj : FreeCAD object - hides trackers only for given object, + obj: FreeCAD object + Hides trackers only for given object, if obj is None, hides all trackers """ if obj is None: @@ -698,12 +703,12 @@ class Edit: t.off() def showTrackers(self, obj=None): - """show Edit Trackers + """Show Edit Trackers. Attributes ---------- - obj : FreeCAD object - shows trackers only for given object, + obj: FreeCAD object + Shows trackers only for given object, if obj is None, shows all trackers """ if obj is None: @@ -718,8 +723,8 @@ class Edit: # PREVIEW # ------------------------------------------------------------------------- - def initGhost(self,obj): - "initialize preview ghost" + def initGhost(self, obj): + """Initialize preview ghost.""" if Draft.getType(obj) == "Wire": return trackers.wireTracker(obj.Shape) elif Draft.getType(obj) == "BSpline": @@ -729,7 +734,7 @@ class Edit: elif Draft.getType(obj) == "Circle": return trackers.arcTracker() - def updateGhost(self,obj,idx,pt): + def updateGhost(self, obj, idx, pt): if Draft.getType(obj) in ["Wire"]: self.ghost.on() pointList = self.applyPlacement(obj.Points) @@ -777,9 +782,9 @@ class Edit: self.ghost.setCenter(self.pl.multVec(p0)) return else: - p1=self.getArcStart(obj,global_placement=True) - p2=self.getArcMid(obj,global_placement=True) - p3=self.getArcEnd(obj,global_placement=True) + p1 = self.getArcStart(obj, global_placement=True) + p2 = self.getArcMid(obj, global_placement=True) + p3 = self.getArcEnd(obj, global_placement=True) if self.editing == 1: p1=pt elif self.editing == 3: @@ -801,7 +806,7 @@ class Edit: self.ghost.setRadius(self.invpl.multVec(pt).Length) DraftTools.redraw3DView() - def applyPlacement(self,pointList): + def applyPlacement(self, pointList): if self.pl: plist = [] for p in pointList: @@ -822,10 +827,10 @@ class Edit: # EDIT OBJECT TOOLS : Add/Delete Vertexes # ------------------------------------------------------------------------- - def addPoint(self,event): - "called by action, add point to obj and reset trackers" + def addPoint(self, event): + """Execute callback, add point to obj and reset trackers.""" pos = event.getPosition() - #self.setSelectState(self.obj, True) + # self.setSelectState(self.obj, True) selobjs = Gui.ActiveDocument.ActiveView.getObjectsInfo((pos[0],pos[1])) if not selobjs: return @@ -842,27 +847,26 @@ class Edit: pt = App.Vector(info["x"], info["y"], info["z"]) self.addPointToWire(self.obj, pt, int(info["Component"][4:])) elif Draft.getType(self.obj) in ["BSpline", "BezCurve"]: #to fix double vertex created - #pt = self.point + # pt = self.point if "x" in info:# prefer "real" 3D location over working-plane-driven one if possible pt = App.Vector(info["x"], info["y"], info["z"]) else: continue - self.addPointToCurve(pt,info) + self.addPointToCurve(pt, info) self.obj.recompute() self.removeTrackers(self.obj) self.setEditPoints(self.obj) # self.setSelectState(self.obj, False) return - def addPointToWire(self, obj, newPoint, edgeIndex): newPoints = [] hasAddedPoint = False if hasattr(obj, "ChamferSize") and hasattr(obj, "FilletRadius"): if obj.ChamferSize > 0 and obj.FilletRadius > 0: - edgeIndex = (edgeIndex +3) / 4 + edgeIndex = (edgeIndex + 3) / 4 elif obj.ChamferSize > 0 or obj.FilletRadius > 0: - edgeIndex = (edgeIndex +1) / 2 + edgeIndex = (edgeIndex + 1) / 2 for index, point in enumerate(self.obj.Points): if index == edgeIndex: @@ -874,24 +878,24 @@ class Edit: newPoints.append(self.invpl.multVec(newPoint)) obj.Points = newPoints - def addPointToCurve(self,point,info=None): + def addPointToCurve(self, point, info=None): import Part - if not (Draft.getType(self.obj) in ["BSpline","BezCurve"]): + if not (Draft.getType(self.obj) in ["BSpline", "BezCurve"]): return pts = self.obj.Points if Draft.getType(self.obj) == "BezCurve": if not info['Component'].startswith('Edge'): - return # clicked control point - edgeindex = int(info['Component'].lstrip('Edge')) -1 + return # clicked control point + edgeindex = int(info['Component'].lstrip('Edge')) - 1 wire = self.obj.Shape.Wires[0] bz = wire.Edges[edgeindex].Curve param = bz.parameter(point) seg1 = wire.Edges[edgeindex].copy().Curve seg2 = wire.Edges[edgeindex].copy().Curve - seg1.segment(seg1.FirstParameter,param) - seg2.segment(param,seg2.LastParameter) + seg1.segment(seg1.FirstParameter, param) + seg2.segment(param, seg2.LastParameter) if edgeindex == len(wire.Edges): - #we hit the last segment, we need to fix the degree + # we hit the last segment, we need to fix the degree degree=wire.Edges[0].Curve.Degree seg1.increase(degree) seg2.increase(degree) @@ -917,44 +921,44 @@ class Edit: uPoints = [] for p in self.obj.Points: uPoints.append(curve.parameter(p)) - for i in range(len(uPoints) -1): + for i in range(len(uPoints) - 1): if ( uNewPoint > uPoints[i] ) and ( uNewPoint < uPoints[i+1] ): pts.insert(i + 1, self.invpl.multVec(point)) break # DNC: fix: add points to last segment if curve is closed - if ( self.obj.Closed ) and ( uNewPoint > uPoints[-1] ) : + if self.obj.Closed and (uNewPoint > uPoints[-1]): pts.append(self.invpl.multVec(point)) self.obj.Points = pts - def delPoint(self,event): + def delPoint(self, event): pos = event.getPosition() node = self.getEditNode(pos) ep = self.getEditNodeIndex(node) if ep is None: return App.Console.PrintWarning(translate("draft", - "Node not found") - + "\n") + "Node not found") + + "\n") doc = App.getDocument(str(node.documentName.getValue())) self.obj = doc.getObject(str(node.objectName.getValue())) if self.obj is None: return - if not (Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]): + if not (Draft.getType(self.obj) in ["Wire", "BSpline", "BezCurve"]): return if len(self.obj.Points) <= 2: App.Console.PrintWarning(translate("draft", - "Active object must have more than two points/nodes") - + "\n") + "Active object must have more than two points/nodes") + + "\n") return pts = self.obj.Points pts.pop(ep) self.obj.Points = pts - if Draft.getType(self.obj) =="BezCurve": + if Draft.getType(self.obj) == "BezCurve": self.obj.Proxy.resetcontinuity(self.obj) self.obj.recompute() - + # don't do tan/sym on DWire/BSpline! self.removeTrackers(self.obj) self.setEditPoints(self.obj) @@ -963,22 +967,22 @@ class Edit: # EDIT OBJECT TOOLS : GENERAL # ------------------------------------------------------------------------- - def setEditPoints(self,obj): - "append given object's editpoints to self.edipoints and set EditTrackers" - + def setEditPoints(self, obj): + """append given object's editpoints to self.edipoints and set EditTrackers""" self.setPlacement(obj) self.editpoints = self.getEditPoints(obj) - if self.editpoints: # set trackers and align plane + if self.editpoints: # set trackers and align plane self.setTrackers(obj, self.editpoints) self.editpoints = [] def getEditPoints(self, obj): - """ - (object) return a list of App.Vectors relative to object edit nodes + """Return a list of App.Vectors relative to object edit nodes. + + (object) """ objectType = Draft.getType(obj) - if objectType in ["Wire","BSpline"]: + if objectType in ["Wire", "BSpline"]: self.ui.editUi("Wire") return self.getWirePts(obj) elif objectType == "BezCurve": @@ -1015,13 +1019,13 @@ class Edit: else: return None - def update(self,obj, nodeIndex, v): - "apply the App.Vector to the modified point and update self.obj" + def update(self, obj, nodeIndex, v): + """Apply the App.Vector to the modified point and update self.obj.""" objectType = Draft.getType(obj) App.ActiveDocument.openTransaction("Edit") - if objectType in ["Wire","BSpline"]: + if objectType in ["Wire", "BSpline"]: self.updateWire(obj, nodeIndex, v) elif objectType == "BezCurve": self.updateWire(obj, nodeIndex, v) @@ -1051,7 +1055,6 @@ class Edit: self.updatePartLine(obj, nodeIndex, v) elif objectType == "Part" and self.obj.TypeId == "Part::Box": self.updatePartBox(obj, nodeIndex, v) - obj.recompute() App.ActiveDocument.commitTransaction() @@ -1065,7 +1068,7 @@ class Edit: # EDIT OBJECT TOOLS : Line/Wire/Bspline/Bezcurve # ------------------------------------------------------------------------- - def getWirePts(self,obj): + def getWirePts(self, obj): editpoints = [] for p in obj.Points: p = obj.getGlobalPlacement().multVec(p) @@ -1108,8 +1111,8 @@ class Edit: obj.Points = pts self.trackers[obj.Name][nodeIndex].set(v) - - def recomputePointsBezier(self,obj,pts,idx,v,degree,moveTrackers=True): + def recomputePointsBezier(self, obj, pts, idx, v, + degree, moveTrackers=True): """ (object, Points as list, nodeIndex as Int, App.Vector of new point, moveTrackers as Bool) return the new point list, applying the App.Vector to the given index point @@ -1143,18 +1146,18 @@ class Edit: elif ispole == 1 and (idx >=2 or obj.Closed): #right pole knot = idx -1 - changep = idx -2 # -1 in case of closed curve + changep = idx - 2 # -1 in case of closed curve - elif ispole == degree-1 and idx <= len(pts)-3: #left pole - knot = idx +1 - changep = idx +2 + elif ispole == degree-1 and idx <= len(pts)-3: # left pole + knot = idx + 1 + changep = idx + 2 elif ispole == degree-1 and obj.Closed and idx == len(pts)-1: #last pole knot = 0 changep = 1 - if knot is not None: # we need to modify the opposite pole - segment = int(knot / degree) -1 + if knot is not None: # we need to modify the opposite pole + segment = int(knot / degree) - 1 cont = obj.Continuity[segment] if len(obj.Continuity) > segment else 0 if cont == 1: #tangent pts[changep] = obj.Proxy.modifytangentpole(pts[knot], @@ -1165,12 +1168,12 @@ class Edit: pts[changep] = obj.Proxy.modifysymmetricpole(pts[knot],editPnt) if moveTrackers: self.trackers[obj.Name][changep].set(pts[changep]) - pts[idx]=v + pts[idx] = v - return pts #returns the list of new points, taking into account knot continuity + return pts # returns the list of new points, taking into account knot continuity def resetTrackersBezier(self, obj): - #in future move tracker definition to DraftTrackers + # in future move tracker definition to DraftTrackers from pivy import coin knotmarkers = (coin.SoMarkerSet.DIAMOND_FILLED_9_9,#sharp coin.SoMarkerSet.SQUARE_FILLED_9_9, #tangent @@ -1188,8 +1191,8 @@ class Edit: knotmarkeri = cont[edgeindex] if len(cont) > edgeindex else 0 pointswithmarkers.append((poles[-1],knotmarkers[knotmarkeri])) for index, pwm in enumerate(pointswithmarkers): - p,marker = pwm - #if self.pl: p = self.pl.multVec(p) + p, marker = pwm + # if self.pl: p = self.pl.multVec(p) self.trackers[obj.Name].append(trackers.editTracker(p,obj.Name, index,obj.ViewObject.LineColor,marker=marker)) @@ -1204,8 +1207,8 @@ class Edit: deg = obj.Degree if deg < 2: return - if point % deg != 0: #point is a pole - if deg >=3: #allow to select poles + if point % deg != 0: # point is a pole + if deg >=3: # allow to select poles if (point % deg == 1) and (point > 2 or obj.Closed): #right pole knot = point -1 keepp = point @@ -1221,9 +1224,9 @@ class Edit: keepp = point changep = 1 else: - App.Console.PrintWarning(translate("draft", - "Can't change Knot belonging to pole %d"%point) - + "\n") + App.Console.PrintWarning(translate("draft", + "Can't change Knot belonging to pole %d"%point) + + "\n") return if knot: if style == 'Tangent': @@ -1235,9 +1238,9 @@ class Edit: else: #sharp pass # else: - App.Console.PrintWarning(translate("draft", - "Selection is not a Knot") - + "\n") + App.Console.PrintWarning(translate("draft", + "Selection is not a Knot") + + "\n") return else: #point is a knot if style == 'Sharp': @@ -1249,12 +1252,12 @@ class Edit: prev, next = obj.Proxy.tangentpoles(pts[point], pts[point-1], pts[point+1]) pts[point-1] = prev pts[point+1] = next - knot = point #index for continuity + knot = point # index for continuity elif style == 'Symmetric' and point > 0 and point < len(pts)-1: prev, next = obj.Proxy.symmetricpoles(pts[point], pts[point-1], pts[point+1]) pts[point-1] = prev pts[point+1] = next - knot = point #index for continuity + knot = point # index for continuity elif obj.Closed and (style == 'Symmetric' or style == 'Tangent'): if style == 'Tangent': pts[1], pts[-1] = obj.Proxy.tangentpoles(pts[0], pts[1], pts[-1]) @@ -1266,8 +1269,8 @@ class Edit: "Endpoint of BezCurve can't be smoothed") + "\n") return - segment = knot // deg #segment index - newcont = obj.Continuity[:] #don't edit a property inplace !!! + segment = knot // deg # segment index + newcont = obj.Continuity[:] # don't edit a property inplace !!! if not obj.Closed and (len(obj.Continuity) == segment -1 or segment == 0) : pass # open curve @@ -1276,7 +1279,7 @@ class Edit: newcont[segment-1] = style2cont.get(style) else: #should not happen App.Console.PrintWarning('Continuity indexing error:' - + 'point:%d deg:%d len(cont):%d' % (knot,deg, + + 'point:%d deg:%d len(cont):%d' % (knot,deg, len(obj.Continuity))) obj.Points = pts obj.Continuity = newcont @@ -1287,8 +1290,8 @@ class Edit: # ------------------------------------------------------------------------- def getRectanglePts(self, obj): - """ - returns the list of edipoints for the given Draft Rectangle + """Return the list of edipoints for the given Draft Rectangle. + 0 : Placement.Base 1 : Length 2 : Height @@ -1308,8 +1311,8 @@ class Edit: import DraftVecUtils delta = obj.getGlobalPlacement().inverse().multVec(v) if nodeIndex == 0: - #p = obj.getGlobalPlacement() - #p.move(delta) + # p = obj.getGlobalPlacement() + # p.move(delta) obj.Placement.move(delta) elif self.editing == 1: obj.Length = DraftVecUtils.project(delta,App.Vector(1,0,0)).Length @@ -1332,17 +1335,18 @@ class Edit: # ------------------------------------------------------------------------- def getCirclePts(self, obj): - """ - returns the list of edipoints for the given Draft Arc or Circle + """Return the list of edipoints for the given Draft Arc or Circle. + circle: 0 : Placement.Base or center 1 : radius + arc: 0 : Placement.Base or center 1 : first endpoint 2 : second endpoint 3 : midpoint - """ + """ editpoints = [] editpoints.append(obj.getGlobalPlacement().Base) if obj.FirstAngle == obj.LastAngle: @@ -1382,7 +1386,7 @@ class Edit: # edit arc by 3 points import Part if nodeIndex == 0: - #center point + # center point import DraftVecUtils p1 = self.getArcStart(obj) p2 = self.getArcEnd(obj) @@ -1436,7 +1440,7 @@ class Edit: def getArcStart(self, obj, global_placement=False):#Returns object midpoint if Draft.getType(obj) == "Circle": return self.pointOnCircle(obj, obj.FirstAngle, global_placement) - + def getArcEnd(self, obj, global_placement=False):#Returns object midpoint if Draft.getType(obj) == "Circle": return self.pointOnCircle(obj, obj.LastAngle, global_placement) @@ -1502,7 +1506,7 @@ class Edit: editpoints.append(obj.Start) editpoints.append(obj.End) editpoints.append(obj.Dimline) - editpoints.append(App.Vector(p[0],p[1],p[2])) + editpoints.append(App.Vector(p[0], p[1], p[2])) return editpoints def updateDimension(self, obj, nodeIndex, v): @@ -1522,8 +1526,9 @@ class Edit: # SKETCH: just if it's composed by a single segment----------------------- def getSketchPts(self, obj): - """ - returns the list of edipoints for the given single line sketch (WallTrace) + """Return the list of edipoints for the given single line sketch. + + (WallTrace) 0 : startpoint 1 : endpoint """ @@ -1534,13 +1539,14 @@ class Edit: return editpoints else: App.Console.PrintWarning(translate("draft", - "Sketch is too complex to edit: " - "it is suggested to use sketcher default editor") + "Sketch is too complex to edit: " + "it is suggested to use sketcher default editor") + "\n") return None def updateSketch(self, obj, nodeIndex, v): - """ + """Move a single line sketch vertex a certain displacement. + (single segment sketch object, node index as Int, App.Vector) move a single line sketch (WallTrace) vertex according to a given App.Vector 0 : startpoint @@ -1552,17 +1558,16 @@ class Edit: obj.movePoint(0,2,obj.getGlobalPlacement().inverse().multVec(v)) obj.recompute() - # WALL--------------------------------------------------------------------- def getWallPts(self, obj): - """ - returns the list of edipoints for the given Arch Wall object + """Return the list of edipoints for the given Arch Wall object. + 0 : height of the wall 1-to end : base object editpoints, in place with the wall """ editpoints = [] - #height of the wall + # height of the wall editpoints.append(obj.getGlobalPlacement().multVec(App.Vector(0,0,obj.Height))) # try to add here an editpoint based on wall height (maybe should be good to associate it with a circular tracker) if obj.Base: @@ -1575,29 +1580,25 @@ class Edit: editpoints.append(obj.Placement.multVec(point)) #works ok except if App::Part is rotated... why? return editpoints - def updateWallTrackers(self, obj): - """ - update self.trackers[obj.Name][0] to match with given object - """ + """Update self.trackers[obj.Name][0] to match with given object.""" pass def updateWall(self, obj, nodeIndex, v): import DraftVecUtils if nodeIndex == 0: delta= obj.getGlobalPlacement().inverse().multVec(v) - vz=DraftVecUtils.project(delta,App.Vector(0,0,1)) + vz=DraftVecUtils.project(delta,App.Vector(0, 0, 1)) if vz.Length > 0: obj.Height = vz.Length elif nodeIndex > 0: if obj.Base: - if Draft.getType(obj.Base) in ["Wire","Circle","Rectangle", - "Polygon", "Sketch"]: + if Draft.getType(obj.Base) in ["Wire", "Circle", "Rectangle", + "Polygon", "Sketch"]: self.update(obj.Base, nodeIndex - 1, obj.Placement.inverse().multVec(v)) obj.recompute() - # WINDOW------------------------------------------------------------------- def getWindowPts(self, obj): @@ -1615,9 +1616,9 @@ class Edit: return editpoints def updateWindow(self, obj, nodeIndex, v): - pos=self.obj.Base.Placement.Base + pos = self.obj.Base.Placement.Base if self.editing == 0: - self.obj.Base.Placement.Base=v + self.obj.Base.Placement.Base = v self.obj.Base.recompute() if self.editing == 1: self.obj.Width = pos.sub(v).Length @@ -1639,7 +1640,7 @@ class Edit: self.originalNodes = obj.ViewObject.ShowNodes self.obj.ViewObject.DisplayMode = "Wireframe" self.obj.ViewObject.NodeSize = 1 - # self.obj.ViewObject.ShowNodes = True + # self.obj.ViewObject.ShowNodes = True for p in obj.Nodes: if self.pl: p = self.pl.multVec(p) @@ -1719,9 +1720,9 @@ class Edit: def getPartBoxPts(self, obj): editpoints = [] editpoints.append(obj.Placement.Base) - editpoints.append(self.pl.multVec(App.Vector(obj.Length,0,0))) - editpoints.append(self.pl.multVec(App.Vector(0,obj.Width,0))) - editpoints.append(self.pl.multVec(App.Vector(0,0,obj.Height))) + editpoints.append(self.pl.multVec(App.Vector(obj.Length, 0, 0))) + editpoints.append(self.pl.multVec(App.Vector(0, obj.Width, 0))) + editpoints.append(self.pl.multVec(App.Vector(0, 0, obj.Height))) return editpoints def updatePartBox(self, obj, nodeIndex, v): @@ -1731,14 +1732,14 @@ class Edit: self.obj.Placement.Base = v self.setPlacement(self.obj) elif self.editing == 1: - xApp.Vector = DraftVecUtils.project(delta,App.Vector(1,0,0)) - self.obj.Length = xApp.Vector.Length + xApp.Vector = DraftVecUtils.project(delta, App.Vector(1, 0, 0)) + self.obj.Length = xApp.Vector.Length elif self.editing == 2: - xApp.Vector = DraftVecUtils.project(delta,App.Vector(0,1,0)) - self.obj.Width = xApp.Vector.Length + xApp.Vector = DraftVecUtils.project(delta, App.Vector(0, 1, 0)) + self.obj.Width = xApp.Vector.Length elif self.editing == 3: - xApp.Vector = DraftVecUtils.project(delta,App.Vector(0,0,1)) - self.obj.Height = xApp.Vector.Length + xApp.Vector = DraftVecUtils.project(delta, App.Vector(0, 0, 1)) + self.obj.Height = xApp.Vector.Length self.trackers[self.obj.Name][0].set(self.obj.Placement.Base) self.trackers[self.obj.Name][1].set(self.pl.multVec(App.Vector(self.obj.Length,0,0))) self.trackers[self.obj.Name][2].set(self.pl.multVec(App.Vector(0,self.obj.Width,0))) @@ -1761,23 +1762,24 @@ class Edit: actions = ["delete point"] elif Draft.getType(obj) in ["Circle"]: if obj.FirstAngle != obj.LastAngle: - if ep == 0: # user is over arc start point + if ep == 0: # user is over arc start point actions = ["move arc"] - elif ep == 1: # user is over arc start point + elif ep == 1: # user is over arc start point actions = ["set first angle"] - elif ep == 2: # user is over arc end point + elif ep == 2: # user is over arc end point actions = ["set last angle"] - elif ep == 3: # user is over arc mid point + elif ep == 3: # user is over arc mid point actions = ["set radius"] elif Draft.getType(obj) in ["BezCurve"]: - actions = ["make sharp", "make tangent", "make symmetric", "delete point"] + actions = ["make sharp", "make tangent", + "make symmetric", "delete point"] else: return else: # if user is over an edited object pos = self.event.getPosition() obj = self.get_selected_obj_at_position(pos) - if Draft.getType(obj) in ["Line", "Wire","BSpline", "BezCurve"]: + if Draft.getType(obj) in ["Line", "Wire", "BSpline", "BezCurve"]: actions = ["add point"] elif Draft.getType(obj) in ["Circle"] and obj.FirstAngle != obj.LastAngle: actions = ["invert arc"] @@ -1788,7 +1790,7 @@ class Edit: self.tracker_menu.popup(Gui.getMainWindow().cursor().pos()) QtCore.QObject.connect(self.tracker_menu,QtCore.SIGNAL("triggered(QAction *)"),self.evaluate_menu_action) - def evaluate_menu_action(self,labelname): + def evaluate_menu_action(self, labelname): action_label = str(labelname.text()) # Bezier curve menu if action_label in ["make sharp", "make tangent", "make symmetric"]: @@ -1807,7 +1809,8 @@ class Edit: elif action_label == "add point": self.addPoint(self.event) # arc tools - elif action_label in ["move arc","set radius", "set first angle", "set last angle"]: + elif action_label in ("move arc", "set radius", + "set first angle", "set last angle"): self.alt_edit_mode = 1 self.startEditing(self.event) elif action_label == "invert arc": From 9aa74f4f32bd2f43db373f90548842a628f0664b Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sun, 1 Mar 2020 01:58:07 -0600 Subject: [PATCH 22/62] Draft: gui_orthoarray cleanup Small spacing fixes like imports in separate lines for more clarity, the module docstring, and the position of the license. Remove unnecessary check for the graphical interface as this command should be imported when the interface is already up and running. Use proper `ToDo` class instead of importing `DraftGui`. --- src/Mod/Draft/draftguitools/gui_orthoarray.py | 50 ++++++------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_orthoarray.py b/src/Mod/Draft/draftguitools/gui_orthoarray.py index b7c0551f3b..fdd2f0b4f3 100644 --- a/src/Mod/Draft/draftguitools/gui_orthoarray.py +++ b/src/Mod/Draft/draftguitools/gui_orthoarray.py @@ -1,8 +1,3 @@ -"""Provide the Draft OrthoArray tool.""" -## @package gui_orthoarray -# \ingroup DRAFT -# \brief Provide the Draft OrthoArray tool. - # *************************************************************************** # * (c) 2020 Eliud Cabrera Castillo * # * * @@ -25,36 +20,23 @@ # * USA * # * * # *************************************************************************** +"""Provides the Draft OrthoArray GuiCommand.""" +## @package gui_orthoarray +# \ingroup DRAFT +# \brief Provides the Draft OrthoArray GuiCommand. + +from pivy import coin +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD as App import FreeCADGui as Gui import Draft -import DraftGui import Draft_rc -from . import gui_base +from draftguitools import gui_base from drafttaskpanels import task_orthoarray +import draftutils.todo as todo - -if App.GuiUp: - from PySide.QtCore import QT_TRANSLATE_NOOP - # import DraftTools - from draftutils.translate import translate - # from DraftGui import displayExternal - from pivy import coin -else: - def QT_TRANSLATE_NOOP(context, text): - return text - - def translate(context, text): - return text - - -def _tr(text): - """Translate the text with the context set.""" - return translate("Draft", text) - - -# So the resource file doesn't trigger errors from code checkers (flake8) +# The module is used to prevent complaints from code checkers (flake8) True if Draft_rc.__name__ else False @@ -85,7 +67,7 @@ class GuiCommandOrthoArray(gui_base.GuiCommandBase): return d def Activated(self): - """Execute this when the command is called. + """Execute when the command is called. We add callbacks that connect the 3D view with the widgets of the task panel. @@ -103,10 +85,10 @@ class GuiCommandOrthoArray(gui_base.GuiCommandBase): # of the interface, to be able to call a function from within it. self.ui.source_command = self # Gui.Control.showDialog(self.ui) - DraftGui.todo.delay(Gui.Control.showDialog, self.ui) + todo.ToDo.delay(Gui.Control.showDialog, self.ui) def click(self, event_cb=None): - """Run callback for when the mouse pointer clicks on the 3D view. + """Execute as a callback when the pointer clicks on the 3D view. It should act as if the Enter key was pressed, or the OK button was pressed in the task panel. @@ -123,7 +105,7 @@ class GuiCommandOrthoArray(gui_base.GuiCommandBase): self.ui.accept() def completed(self): - """Run when the command is terminated. + """Execute when the command is terminated. We should remove the callbacks that were added to the 3D view and then close the task panel. @@ -133,10 +115,8 @@ class GuiCommandOrthoArray(gui_base.GuiCommandBase): self.view.removeEventCallbackPivy(self.mouse_event, self.callback_click) if Gui.Control.activeDialog(): - Gui.Snapper.off() Gui.Control.closeDialog() super().finish() -if App.GuiUp: - Gui.addCommand('Draft_OrthoArray', GuiCommandOrthoArray()) +Gui.addCommand('Draft_OrthoArray', GuiCommandOrthoArray()) From fbd929af2b99d8e8a5b210d8d584198117d1e6e4 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Mon, 2 Mar 2020 18:48:34 -0600 Subject: [PATCH 23/62] Draft: gui_polararray cleanup Small spacing fixes like imports in separate lines for more clarity, the module docstrings, and the position of the license. Remove unnecessary check for the graphical interface as this command should be imported when the interface is already up and running. Use proper `ToDo` class instead of importing `DraftGui`. --- src/Mod/Draft/draftguitools/gui_polararray.py | 56 ++++++------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_polararray.py b/src/Mod/Draft/draftguitools/gui_polararray.py index e07a3b0742..0c277c5bcf 100644 --- a/src/Mod/Draft/draftguitools/gui_polararray.py +++ b/src/Mod/Draft/draftguitools/gui_polararray.py @@ -1,9 +1,3 @@ -"""This module provides the Draft PolarArray tool. -""" -## @package gui_polararray -# \ingroup DRAFT -# \brief This module provides the Draft PolarArray tool. - # *************************************************************************** # * (c) 2019 Eliud Cabrera Castillo * # * * @@ -26,41 +20,28 @@ # * USA * # * * # *************************************************************************** +"""Provides the Draft PolarArray tool.""" +## @package gui_polararray +# \ingroup DRAFT +# \brief This module provides the Draft PolarArray tool. + +from pivy import coin +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD as App import FreeCADGui as Gui import Draft -import DraftGui import Draft_rc -from . import gui_base +from draftguitools import gui_base from drafttaskpanels import task_polararray +import draftutils.todo as todo - -if App.GuiUp: - from PySide.QtCore import QT_TRANSLATE_NOOP - # import DraftTools - from DraftGui import translate - # from DraftGui import displayExternal - from pivy import coin -else: - def QT_TRANSLATE_NOOP(context, text): - return text - - def translate(context, text): - return text - - -def _tr(text): - """Function to translate with the context set""" - return translate("Draft", text) - - -# So the resource file doesn't trigger errors from code checkers (flake8) +# The module is used to prevent complaints from code checkers (flake8) True if Draft_rc.__name__ else False class GuiCommandPolarArray(gui_base.GuiCommandBase): - """Gui command for the PolarArray tool""" + """Gui command for the PolarArray tool.""" def __init__(self): super().__init__() @@ -74,6 +55,7 @@ class GuiCommandPolarArray(gui_base.GuiCommandBase): self.point = App.Vector() def GetResources(self): + """Set icon, menu and tooltip.""" _msg = ("Creates copies of a selected object, " "and places the copies in a polar pattern.\n" "The properties of the array can be further modified after " @@ -85,7 +67,7 @@ class GuiCommandPolarArray(gui_base.GuiCommandBase): return d def Activated(self): - """This is called when the command is executed. + """Execute when the command is called. We add callbacks that connect the 3D view with the widgets of the task panel. @@ -103,10 +85,10 @@ class GuiCommandPolarArray(gui_base.GuiCommandBase): # of the interface, to be able to call a function from within it. self.ui.source_command = self # Gui.Control.showDialog(self.ui) - DraftGui.todo.delay(Gui.Control.showDialog, self.ui) + todo.ToDo.delay(Gui.Control.showDialog, self.ui) def move(self, event_cb): - """This is a callback for when the mouse pointer moves in the 3D view. + """Execute as a callback when the pointer moves in the 3D view. It should automatically update the coordinates in the widgets of the task panel. @@ -119,7 +101,7 @@ class GuiCommandPolarArray(gui_base.GuiCommandBase): self.ui.display_point(self.point) def click(self, event_cb=None): - """This is a callback for when the mouse pointer clicks on the 3D view. + """Execute as a callback when the pointer clicks on the 3D view. It should act as if the Enter key was pressed, or the OK button was pressed in the task panel. @@ -136,7 +118,7 @@ class GuiCommandPolarArray(gui_base.GuiCommandBase): self.ui.accept() def completed(self): - """This is called when the command is terminated. + """Execute when the command is terminated. We should remove the callbacks that were added to the 3D view and then close the task panel. @@ -146,10 +128,8 @@ class GuiCommandPolarArray(gui_base.GuiCommandBase): self.view.removeEventCallbackPivy(self.mouse_event, self.callback_click) if Gui.Control.activeDialog(): - Gui.Snapper.off() Gui.Control.closeDialog() super().finish() -if App.GuiUp: - Gui.addCommand('Draft_PolarArray', GuiCommandPolarArray()) +Gui.addCommand('Draft_PolarArray', GuiCommandPolarArray()) From 4a68fb09c0e4c6dac84fff867933c22479f51295 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Mon, 2 Mar 2020 20:00:47 -0600 Subject: [PATCH 24/62] Draft: gui_selectplane cleanup Small spacing fixes like imports in separate lines for more clarity, and the position of the license. Added many docstrings to clarify the methods, and spaces after commas in order to comply with Python PEP8 style. Also break many lines so that they are shorter than 80 characters. --- .../Draft/draftguitools/gui_selectplane.py | 292 +++++++++++------- 1 file changed, 175 insertions(+), 117 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_selectplane.py b/src/Mod/Draft/draftguitools/gui_selectplane.py index 27ddfd94f7..ed9b9636cd 100644 --- a/src/Mod/Draft/draftguitools/gui_selectplane.py +++ b/src/Mod/Draft/draftguitools/gui_selectplane.py @@ -1,4 +1,3 @@ -# -*- coding: utf8 -*- # *************************************************************************** # * Copyright (c) 2019 Yorik van Havre * # * * @@ -19,23 +18,32 @@ # * USA * # * * # *************************************************************************** +"""Provides the Draft SelectPlane tool.""" +## @package gui_selectplane +# \ingroup DRAFT +# \brief This module provides the Draft SelectPlane tool. -__title__ = "FreeCAD Draft Workbench GUI Tools - Working plane-related tools" -__author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, Dmitry Chigrin" -__url__ = "https://www.freecadweb.org" - +import math +from pivy import coin +from PySide import QtGui +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import FreeCADGui -import math import Draft +import Draft_rc import DraftVecUtils from draftutils.todo import todo +from draftutils.messages import _msg from draftutils.translate import translate +# The module is used to prevent complaints from code checkers (flake8) +True if Draft_rc.__name__ else False -def QT_TRANSLATE_NOOP(ctx,txt): return txt - +__title__ = "FreeCAD Draft Workbench GUI Tools - Working plane-related tools" +__author__ = ("Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, " + "Dmitry Chigrin") +__url__ = "https://www.freecadweb.org" class Draft_SelectPlane: @@ -48,10 +56,15 @@ class Draft_SelectPlane: def GetResources(self): """Set icon, menu and tooltip.""" - return {'Pixmap' : 'Draft_SelectPlane', - 'Accel' : "W, P", - 'MenuText': QT_TRANSLATE_NOOP("Draft_SelectPlane", "SelectPlane"), - 'ToolTip' : QT_TRANSLATE_NOOP("Draft_SelectPlane", "Select a working plane for geometry creation")} + _msg = ("Select the face of solid body to create a working plane " + "on which to sketch Draft objects.\n" + "You may also select a three vertices or " + "a Working Plane Proxy.") + d = {'Pixmap': 'Draft_SelectPlane', + 'Accel': "W, P", + 'MenuText': QT_TRANSLATE_NOOP("Draft_SelectPlane", "SelectPlane"), + 'ToolTip': QT_TRANSLATE_NOOP("Draft_SelectPlane", _msg)} + return d def IsActive(self): """Return True when this command should be available.""" @@ -61,34 +74,33 @@ class Draft_SelectPlane: return False def Activated(self): - """Execute this when the command is called.""" - # reset variables + """Execute when the command is called.""" + # Reset variables self.view = Draft.get3DView() self.wpButton = FreeCADGui.draftToolBar.wplabel FreeCAD.DraftWorkingPlane.setup() - # write current WP if states are empty + # Write current WP if states are empty if not self.states: p = FreeCAD.DraftWorkingPlane self.states.append([p.u, p.v, p.axis, p.position]) - m = translate("draft", "Pick a face, 3 vertices or a WP Proxy to define the drawing plane") - FreeCAD.Console.PrintMessage(m+"\n") + m = translate("draft", "Pick a face, 3 vertices " + "or a WP Proxy to define the drawing plane") + _msg(m) - from PySide import QtCore,QtGui - - # create UI panel + # Create task panel FreeCADGui.Control.closeDialog() self.taskd = SelectPlane_TaskPanel() - # fill values - self.taskd.form.checkCenter.setChecked(self.param.GetBool("CenterPlaneOnView",False)) - q = FreeCAD.Units.Quantity(self.param.GetFloat("gridSpacing",1.0),FreeCAD.Units.Length) + # Fill values + self.taskd.form.checkCenter.setChecked(self.param.GetBool("CenterPlaneOnView", False)) + q = FreeCAD.Units.Quantity(self.param.GetFloat("gridSpacing", 1.0), FreeCAD.Units.Length) self.taskd.form.fieldGridSpacing.setText(q.UserString) - self.taskd.form.fieldGridMainLine.setValue(self.param.GetInt("gridEvery",10)) - self.taskd.form.fieldSnapRadius.setValue(self.param.GetInt("snapRange",8)) + self.taskd.form.fieldGridMainLine.setValue(self.param.GetInt("gridEvery", 10)) + self.taskd.form.fieldSnapRadius.setValue(self.param.GetInt("snapRange", 8)) - # set icons + # Set icons self.taskd.form.setWindowIcon(QtGui.QIcon(":/icons/Draft_SelectPlane.svg")) self.taskd.form.buttonTop.setIcon(QtGui.QIcon(":/icons/view-top.svg")) self.taskd.form.buttonFront.setIcon(QtGui.QIcon(":/icons/view-front.svg")) @@ -99,7 +111,7 @@ class Draft_SelectPlane: self.taskd.form.buttonCenter.setIcon(QtGui.QIcon(":/icons/view-fullscreen.svg")) self.taskd.form.buttonPrevious.setIcon(QtGui.QIcon(":/icons/edit-undo.svg")) - # connect slots + # Connect slots self.taskd.form.buttonTop.clicked.connect(self.onClickTop) self.taskd.form.buttonFront.clicked.connect(self.onClickFront) self.taskd.form.buttonSide.clicked.connect(self.onClickSide) @@ -112,57 +124,59 @@ class Draft_SelectPlane: self.taskd.form.fieldGridMainLine.valueChanged.connect(self.onSetMainline) self.taskd.form.fieldSnapRadius.valueChanged.connect(self.onSetSnapRadius) - # try to find a WP from the current selection + # Try to find a WP from the current selection if self.handle(): return - # try other method + # Try another method if FreeCAD.DraftWorkingPlane.alignToSelection(): FreeCADGui.Selection.clearSelection() self.display(FreeCAD.DraftWorkingPlane.axis) self.finish() return - - # rock 'n roll! + + # Execute the actual task panel FreeCADGui.Control.showDialog(self.taskd) self.call = self.view.addEventCallback("SoEvent", self.action) - def finish(self,close=False): + def finish(self, close=False): + """Execute when the command is terminated.""" + # Store values + self.param.SetBool("CenterPlaneOnView", + self.taskd.form.checkCenter.isChecked()) - # store values - self.param.SetBool("CenterPlaneOnView",self.taskd.form.checkCenter.isChecked()) - - # terminate coin callbacks + # Terminate coin callbacks if self.call: try: - self.view.removeEventCallback("SoEvent",self.call) + self.view.removeEventCallback("SoEvent", self.call) except RuntimeError: - # the view has been deleted already + # The view has been deleted already pass self.call = None - # reset everything else + # Reset everything else FreeCADGui.Control.closeDialog() FreeCAD.DraftWorkingPlane.restore() FreeCADGui.ActiveDocument.resetEdit() return True def reject(self): - + """Execute when clicking the Cancel button.""" self.finish() return True def action(self, arg): - + """Set the callbacks for the view.""" if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE": self.finish() if arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - # coin detection happens before the selection got a chance of being updated, so we must delay - todo.delay(self.checkSelection,None) + # Coin detection happens before the selection + # got a chance of being updated, so we must delay + todo.delay(self.checkSelection, None) def checkSelection(self): - + """Check the selection, if there is a handle, finish the command.""" if self.handle(): self.finish() @@ -175,18 +189,19 @@ class Draft_SelectPlane: FreeCAD.DraftWorkingPlane.alignToEdges(sel.Object.Shape.Edges) self.display(FreeCAD.DraftWorkingPlane.axis) return True - elif Draft.getType(sel.Object) in ["WorkingPlaneProxy","BuildingPart"]: - FreeCAD.DraftWorkingPlane.setFromPlacement(sel.Object.Placement,rebase=True) + elif Draft.getType(sel.Object) in ("WorkingPlaneProxy", + "BuildingPart"): + FreeCAD.DraftWorkingPlane.setFromPlacement(sel.Object.Placement, rebase=True) FreeCAD.DraftWorkingPlane.weak = False - if hasattr(sel.Object.ViewObject,"AutoWorkingPlane"): + if hasattr(sel.Object.ViewObject, "AutoWorkingPlane"): if sel.Object.ViewObject.AutoWorkingPlane: FreeCAD.DraftWorkingPlane.weak = True - if hasattr(sel.Object.ViewObject,"CutView") and hasattr(sel.Object.ViewObject,"AutoCutView"): + if hasattr(sel.Object.ViewObject, "CutView") and hasattr(sel.Object.ViewObject, "AutoCutView"): if sel.Object.ViewObject.AutoCutView: sel.Object.ViewObject.CutView = True - if hasattr(sel.Object.ViewObject,"RestoreView"): + if hasattr(sel.Object.ViewObject, "RestoreView"): if sel.Object.ViewObject.RestoreView: - if hasattr(sel.Object.ViewObject,"ViewData"): + if hasattr(sel.Object.ViewObject, "ViewData"): if len(sel.Object.ViewObject.ViewData) >= 12: d = sel.Object.ViewObject.ViewData camtype = "orthographic" @@ -194,16 +209,15 @@ class Draft_SelectPlane: if d[12] == 1: camtype = "perspective" c = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() - from pivy import coin - if isinstance(c,coin.SoOrthographicCamera): + if isinstance(c, coin.SoOrthographicCamera): if camtype == "perspective": FreeCADGui.ActiveDocument.ActiveView.setCameraType("Perspective") - elif isinstance(c,coin.SoPerspectiveCamera): + elif isinstance(c, coin.SoPerspectiveCamera): if camtype == "orthographic": FreeCADGui.ActiveDocument.ActiveView.setCameraType("Orthographic") c = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() - c.position.setValue([d[0],d[1],d[2]]) - c.orientation.setValue([d[3],d[4],d[5],d[6]]) + c.position.setValue([d[0], d[1], d[2]]) + c.orientation.setValue([d[3], d[4], d[5], d[6]]) c.nearDistance.setValue(d[7]) c.farDistance.setValue(d[8]) c.aspectRatio.setValue(d[9]) @@ -212,9 +226,9 @@ class Draft_SelectPlane: c.height.setValue(d[11]) else: c.heightAngle.setValue(d[11]) - if hasattr(sel.Object.ViewObject,"RestoreState"): + if hasattr(sel.Object.ViewObject, "RestoreState"): if sel.Object.ViewObject.RestoreState: - if hasattr(sel.Object.ViewObject,"VisibilityMap"): + if hasattr(sel.Object.ViewObject, "VisibilityMap"): if sel.Object.ViewObject.VisibilityMap: for k,v in sel.Object.ViewObject.VisibilityMap.items(): o = FreeCADGui.ActiveDocument.getObject(k) @@ -226,7 +240,7 @@ class Draft_SelectPlane: self.wpButton.setToolTip(translate("draft", "Current working plane")+": "+self.wpButton.text()) return True elif Draft.getType(sel.Object) == "SectionPlane": - FreeCAD.DraftWorkingPlane.setFromPlacement(sel.Object.Placement,rebase=True) + FreeCAD.DraftWorkingPlane.setFromPlacement(sel.Object.Placement, rebase=True) FreeCAD.DraftWorkingPlane.weak = False self.display(FreeCAD.DraftWorkingPlane.axis) self.wpButton.setText(sel.Object.Label) @@ -239,7 +253,7 @@ class Draft_SelectPlane: self.display(FreeCAD.DraftWorkingPlane.axis) return True elif sel.SubElementNames[0] == "Plane": - FreeCAD.DraftWorkingPlane.setFromPlacement(sel.Object.Placement,rebase=True) + FreeCAD.DraftWorkingPlane.setFromPlacement(sel.Object.Placement, rebase=True) self.display(FreeCAD.DraftWorkingPlane.axis) return True elif len(sel.SubElementNames) == 3: @@ -263,7 +277,7 @@ class Draft_SelectPlane: import Part for s in sel: for so in s.SubObjects: - if isinstance(so,Part.Vertex): + if isinstance(so, Part.Vertex): subs.append(so) if len(subs) == 3: FreeCAD.DraftWorkingPlane.alignTo3Points(subs[0].Point, @@ -275,25 +289,31 @@ class Draft_SelectPlane: return False def getCenterPoint(self, x, y, z): - + """Get the center point.""" if not self.taskd.form.checkCenter.isChecked(): return FreeCAD.Vector() - v = FreeCAD.Vector(x,y,z) - cam1 = FreeCAD.Vector(FreeCADGui.ActiveDocument.ActiveView.getCameraNode().position.getValue().getValue()) + v = FreeCAD.Vector(x, y, z) + view = FreeCADGui.ActiveDocument.ActiveView + camera = view.getCameraNode() + cam1 = FreeCAD.Vector(camera.position.getValue().getValue()) cam2 = FreeCADGui.ActiveDocument.ActiveView.getViewDirection() - vcam1 = DraftVecUtils.project(cam1,v) + vcam1 = DraftVecUtils.project(cam1, v) a = vcam1.getAngle(cam2) if a < 0.0001: return FreeCAD.Vector() d = vcam1.Length L = d/math.cos(a) - vcam2 = DraftVecUtils.scaleTo(cam2,L) + vcam2 = DraftVecUtils.scaleTo(cam2, L) cp = cam1.add(vcam2) return cp def tostr(self, v): """Make a string from a vector or tuple.""" - return "FreeCAD.Vector("+str(v[0])+","+str(v[1])+","+str(v[2])+")" + string = "FreeCAD.Vector(" + string += str(v[0]) + ", " + string += str(v[1]) + ", " + string += str(v[2]) + ")" + return string def getOffset(self): """Return the offset value as a float in mm.""" @@ -305,48 +325,66 @@ class Draft_SelectPlane: return o def onClickTop(self): - - o = str(self.getOffset()) - FreeCADGui.doCommandGui(self.ac+"("+self.tostr(self.getCenterPoint(0,0,1))+","+self.tostr((0,0,1))+","+o+")") + """Execute when pressing the top button.""" + offset = str(self.getOffset()) + _cmd = self.ac + _cmd += "(" + _cmd += self.tostr(self.getCenterPoint(0, 0, 1)) + ", " + _cmd += self.tostr((0, 0, 1)) + ", " + _cmd += offset + _cmd += ")" + FreeCADGui.doCommandGui(_cmd) self.display('Top') self.finish() def onClickFront(self): - - o = str(self.getOffset()) - FreeCADGui.doCommandGui(self.ac+"("+self.tostr(self.getCenterPoint(0,-1,0))+","+self.tostr((0,-1,0))+","+o+")") + """Execute when pressing the front button.""" + offset = str(self.getOffset()) + _cmd = self.ac + _cmd += "(" + _cmd += self.tostr(self.getCenterPoint(0, -1, 0)) + ", " + _cmd += self.tostr((0, -1, 0)) + ", " + _cmd += offset + _cmd += ")" + FreeCADGui.doCommandGui(_cmd) self.display('Front') self.finish() def onClickSide(self): - - o = str(self.getOffset()) - FreeCADGui.doCommandGui(self.ac+"("+self.tostr(self.getCenterPoint(1,0,0))+","+self.tostr((1,0,0))+","+o+")") + """Execute when pressing the side button.""" + offset = str(self.getOffset()) + _cmd = self.ac + _cmd += "(" + _cmd += self.tostr(self.getCenterPoint(1, 0, 0)) + ", " + _cmd += self.tostr((1, 0, 0)) + ", " + _cmd += offset + _cmd += ")" + FreeCADGui.doCommandGui(_cmd) self.display('Side') self.finish() def onClickAlign(self): - + """Execute when pressing the align.""" FreeCADGui.doCommandGui("FreeCAD.DraftWorkingPlane.setup(force=True)") d = self.view.getViewDirection().negative() self.display(d) self.finish() def onClickAuto(self): - + """Execute when pressing the auto button.""" FreeCADGui.doCommandGui("FreeCAD.DraftWorkingPlane.reset()") self.display('Auto') self.finish() def onClickMove(self): - + """Execute when pressing the move button.""" sel = FreeCADGui.Selection.getSelectionEx() if sel: verts = [] import Part for s in sel: for so in s.SubObjects: - if isinstance(so,Part.Vertex): + if isinstance(so, Part.Vertex): verts.append(so) if len(verts) == 1: target = verts[0].Point @@ -358,13 +396,13 @@ class Draft_SelectPlane: c = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() p = FreeCAD.Vector(c.position.getValue().getValue()) d = FreeCADGui.ActiveDocument.ActiveView.getViewDirection() - pp = FreeCAD.DraftWorkingPlane.projectPoint(p,d) + pp = FreeCAD.DraftWorkingPlane.projectPoint(p, d) FreeCAD.DraftWorkingPlane.position = pp self.display(pp) self.finish() def onClickCenter(self): - + """Execute when pressing the center button.""" c = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() r = FreeCAD.DraftWorkingPlane.getRotation().Rotation.Q c.orientation.setValue(r) @@ -377,7 +415,7 @@ class Draft_SelectPlane: self.finish() def onClickPrevious(self): - + """Execute when pressing the previous button.""" p = FreeCAD.DraftWorkingPlane if len(self.states) > 1: self.states.pop() # discard the last one @@ -389,32 +427,32 @@ class Draft_SelectPlane: FreeCADGui.Snapper.setGrid() self.finish() - def onSetGridSize(self,text): - + def onSetGridSize(self, text): + """Execute when setting the grid size.""" try: q = FreeCAD.Units.Quantity(text) - except: + except Exception: pass else: - self.param.SetFloat("gridSpacing",q.Value) - if hasattr(FreeCADGui,"Snapper"): + self.param.SetFloat("gridSpacing", q.Value) + if hasattr(FreeCADGui, "Snapper"): FreeCADGui.Snapper.setGrid() - def onSetMainline(self,i): - + def onSetMainline(self, i): + """Execute when setting main line grid spacing.""" if i > 1: - self.param.SetInt("gridEvery",i) - if hasattr(FreeCADGui,"Snapper"): + self.param.SetInt("gridEvery", i) + if hasattr(FreeCADGui, "Snapper"): FreeCADGui.Snapper.setGrid() - def onSetSnapRadius(self,i): - - self.param.SetInt("snapRange",i) + def onSetSnapRadius(self, i): + """Execute when setting the snap radius.""" + self.param.SetInt("snapRange", i) if hasattr(FreeCADGui, "Snapper"): FreeCADGui.Snapper.showradius() - def display(self,arg): - """Set the text of the working plane button.""" + def display(self, arg): + """Set the text of the working plane button in the toolbar.""" o = self.getOffset() if o: if o > 0: @@ -423,20 +461,33 @@ class Draft_SelectPlane: suffix = ' -O' else: suffix = '' - vdir = FreeCAD.DraftWorkingPlane.axis - vdir = '('+str(vdir.x)[:4]+','+str(vdir.y)[:4]+','+str(vdir.z)[:4]+')' - vdir = " "+translate("draft","Dir")+": "+vdir - if type(arg).__name__ == 'str': - self.wpButton.setText(arg+suffix) + _vdir = FreeCAD.DraftWorkingPlane.axis + vdir = '(' + vdir += str(_vdir.x)[:4] + ',' + vdir += str(_vdir.y)[:4] + ',' + vdir += str(_vdir.z)[:4] + vdir += ')' + + vdir = " " + translate("draft", "Dir") + ": " + vdir + if type(arg).__name__ == 'str': + self.wpButton.setText(arg + suffix) if o != 0: - o = " "+translate("draft","Offset")+": "+str(o) + o = " " + translate("draft", "Offset") + ": " + str(o) else: o = "" - self.wpButton.setToolTip(translate("draft", "Current working plane")+": "+self.wpButton.text()+o+vdir) + _tool = translate("draft", "Current working plane") + ": " + _tool += self.wpButton.text() + o + vdir + self.wpButton.setToolTip(_tool) elif type(arg).__name__ == 'Vector': - plv = '('+str(arg.x)[:6]+','+str(arg.y)[:6]+','+str(arg.z)[:6]+')' - self.wpButton.setText(translate("draft","Custom")) - self.wpButton.setToolTip(translate("draft", "Current working plane")+": "+plv+vdir) + plv = '(' + plv += str(arg.x)[:6] + ',' + plv += str(arg.y)[:6] + ',' + plv += str(arg.z)[:6] + plv += ')' + self.wpButton.setText(translate("draft", "Custom")) + _tool = translate("draft", "Current working plane") + _tool += ": " + plv + vdir + self.wpButton.setToolTip(_tool) p = FreeCAD.DraftWorkingPlane self.states.append([p.u, p.v, p.axis, p.position]) FreeCADGui.doCommandGui("FreeCADGui.Snapper.setGrid()") @@ -446,23 +497,26 @@ class SelectPlane_TaskPanel: """The task panel definition of the Draft_SelectPlane command.""" def __init__(self): - - import Draft_rc self.form = FreeCADGui.PySideUic.loadUi(":/ui/TaskSelectPlane.ui") def getStandardButtons(self): - + """Execute to set the standard buttons.""" return 2097152 # int(QtGui.QDialogButtonBox.Close) -class Draft_SetWorkingPlaneProxy(): - """The Draft_SetWorkingPlaneProxy FreeCAD command definition""" +class Draft_SetWorkingPlaneProxy: + """The Draft_SetWorkingPlaneProxy FreeCAD command definition.""" def GetResources(self): """Set icon, menu and tooltip.""" - return {'Pixmap': 'Draft_SelectPlane', - 'MenuText': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", "Create Working Plane Proxy"), - 'ToolTip': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", "Creates a proxy object from the current working plane")} + _menu = "Create Working Plane Proxy" + _tip = "Creates a proxy object from the current working plane" + d = {'Pixmap': 'Draft_SelectPlane', + 'MenuText': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", + _menu), + 'ToolTip': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", + _tip)} + return d def IsActive(self): """Return True when this command should be available.""" @@ -472,14 +526,18 @@ class Draft_SetWorkingPlaneProxy(): return False def Activated(self): - """Execute this when the command is called.""" + """Execute when the command is called.""" if hasattr(FreeCAD, "DraftWorkingPlane"): FreeCAD.ActiveDocument.openTransaction("Create WP proxy") FreeCADGui.addModule("Draft") - FreeCADGui.doCommand("Draft.makeWorkingPlaneProxy(FreeCAD.DraftWorkingPlane.getPlacement())") + _cmd = "Draft.makeWorkingPlaneProxy(" + _cmd += "FreeCAD.DraftWorkingPlane.getPlacement()" + _cmd += ")" + FreeCADGui.doCommand(_cmd) FreeCAD.ActiveDocument.recompute() FreeCAD.ActiveDocument.commitTransaction() FreeCADGui.addCommand('Draft_SelectPlane', Draft_SelectPlane()) -FreeCADGui.addCommand('Draft_SetWorkingPlaneProxy', Draft_SetWorkingPlaneProxy()) +FreeCADGui.addCommand('Draft_SetWorkingPlaneProxy', + Draft_SetWorkingPlaneProxy()) From 3838ee0302b507fbd4ffb9a6e7a087207768ce02 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Mon, 2 Mar 2020 23:47:14 -0600 Subject: [PATCH 25/62] Draft: gui_snapper clean up docstrings and spaces --- src/Mod/Draft/draftguitools/gui_snapper.py | 262 +++++++++++---------- 1 file changed, 140 insertions(+), 122 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index b9a739cfd5..fd453ee1c0 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -44,6 +44,7 @@ import Draft import DraftVecUtils from FreeCAD import Vector import draftguitools.gui_trackers as trackers +from draftutils.messages import _msg, _wrn __title__ = "FreeCAD Draft Snap tools" __author__ = "Yorik van Havre" @@ -158,9 +159,9 @@ class Snapper: ('special', ':/icons/Snap_Special.svg')]) def cstr(self, lastpoint, constrain, point): - "constrains if needed" + """Return constraints if needed.""" if constrain or self.mask: - fpt = self.constrain(point,lastpoint) + fpt = self.constrain(point, lastpoint) else: self.unconstrain() fpt = point @@ -168,15 +169,21 @@ class Snapper: self.radiusTracker.update(fpt) return fpt - def snap(self,screenpos,lastpoint=None,active=True,constrain=False,noTracker=False): - """snap(screenpos,lastpoint=None,active=True,constrain=False,noTracker=False): returns a snapped - point from the given (x,y) screenpos (the position of the mouse cursor), active is to - activate active point snapping or not (passive), lastpoint is an optional - other point used to draw an imaginary segment and get additional snap locations. Constrain can - be True to constrain the point against the closest working plane axis. - Screenpos can be a list, a tuple or a coin.SbVec2s object. If noTracker is True, - the tracking line is not displayed.""" + def snap(self, screenpos, + lastpoint=None, active=True, + constrain=False, noTracker=False): + """Return a snapped point from the given (x, y) screen position. + snap(screenpos,lastpoint=None,active=True,constrain=False, + noTracker=False): returns a snapped point from the given + (x,y) screenpos (the position of the mouse cursor), active is to + activate active point snapping or not (passive), + lastpoint is an optional other point used to draw an + imaginary segment and get additional snap locations. Constrain can + be True to constrain the point against the closest working plane axis. + Screenpos can be a list, a tuple or a coin.SbVec2s object. + If noTracker is True, the tracking line is not displayed. + """ if self.running: # do not allow concurrent runs return None @@ -187,44 +194,45 @@ class Snapper: import Part, DraftGeomUtils self.spoint = None - if not hasattr(self,"toolbar"): + if not hasattr(self, "toolbar"): self.makeSnapToolBar() mw = FreeCADGui.getMainWindow() - bt = mw.findChild(QtGui.QToolBar,"Draft Snap") + bt = mw.findChild(QtGui.QToolBar, "Draft Snap") if not bt: mw.addToolBar(self.toolbar) else: - if Draft.getParam("showSnapBar",True): + if Draft.getParam("showSnapBar", True): bt.show() self.snapInfo = None - # type conversion if needed - if isinstance(screenpos,list): + # Type conversion if needed + if isinstance(screenpos, list): screenpos = tuple(screenpos) - elif isinstance(screenpos,coin.SbVec2s): + elif isinstance(screenpos, coin.SbVec2s): screenpos = tuple(screenpos.getValue()) - elif not isinstance(screenpos,tuple): - print("snap needs valid screen position (list, tuple or sbvec2s)") + elif not isinstance(screenpos, tuple): + _wrn("Snap needs valid screen position (list, tuple or sbvec2s)") self.running = False return None - # setup trackers if needed + # Setup trackers if needed self.setTrackers() - - # show the grid if it's off (new view, for ex) - if self.grid and Draft.getParam("grid",True): + + # Show the grid if it's off (new view, for ex) + if self.grid and Draft.getParam("grid", True): self.grid.on() - # getting current snap Radius - self.radius = self.getScreenDist(Draft.getParam("snapRange", 8),screenpos) + # Get current snap radius + self.radius = self.getScreenDist(Draft.getParam("snapRange", 8), + screenpos) if self.radiusTracker: self.radiusTracker.update(self.radius) self.radiusTracker.off() - # activate snap + # Activate snap oldActive = False - if Draft.getParam("alwaysSnap",True): + if Draft.getParam("alwaysSnap", True): oldActive = active active = True if not self.active: @@ -244,29 +252,33 @@ class Snapper: if self.dim2: self.dim2.off() - point = self.getApparentPoint(screenpos[0],screenpos[1]) + point = self.getApparentPoint(screenpos[0], screenpos[1]) - # setup a track line if we got a last point + # Set up a track line if we got a last point if lastpoint and self.trackLine: self.trackLine.p1(lastpoint) - # checking if parallel to one of the edges of the last objects or to a polar direction + # Check if parallel to one of the edges of the last objects + # or to a polar direction eline = None if active: - point,eline = self.snapToPolar(point,lastpoint) - point,eline = self.snapToExtensions(point,lastpoint,constrain,eline) + point, eline = self.snapToPolar(point, lastpoint) + point, eline = self.snapToExtensions(point, lastpoint, + constrain, eline) - objectsUnderCursor = Draft.get3DView().getObjectsInfo((screenpos[0],screenpos[1])) + _view = Draft.get3DView() + objectsUnderCursor = _view.getObjectsInfo((screenpos[0], screenpos[1])) if objectsUnderCursor: if self.snapObjectIndex >= len(objectsUnderCursor): self.snapObjectIndex = 0 self.snapInfo = objectsUnderCursor[self.snapObjectIndex] if self.snapInfo and "Component" in self.snapInfo: - return self.snapToObject(lastpoint, active, constrain, eline, point, oldActive) + return self.snapToObject(lastpoint, active, constrain, + eline, point, oldActive) - # nothing has been snapped - # check for grid snap and ext crossings + # Nothing has been snapped. + # Check for grid snap and ext crossings if active: epoint = self.snapToCrossExtensions(point) if epoint: @@ -277,24 +289,25 @@ class Snapper: if self.trackLine and lastpoint and (not noTracker): self.trackLine.p2(fp) self.trackLine.on() - # set the arch point tracking + # Set the arch point tracking if lastpoint: - self.setArchDims(lastpoint,fp) + self.setArchDims(lastpoint, fp) self.spoint = fp self.running = False return fp def cycleSnapObject(self): + """Increse the index of the snap object by one.""" self.snapObjectIndex = self.snapObjectIndex + 1 - def snapToObject(self, lastpoint, active, constrain, eline, point, oldActive): - # we have an object to snap to - - parent = self.snapInfo.get('ParentObject',None) + def snapToObject(self, lastpoint, active, constrain, + eline, point, oldActive): + """Snap to an object.""" + parent = self.snapInfo.get('ParentObject', None) if parent: subname = self.snapInfo['SubName'] - obj = parent.getSubObject(subname,retType=1) + obj = parent.getSubObject(subname, retType=1) else: obj = FreeCAD.ActiveDocument.getObject(self.snapInfo['Object']) parent = obj @@ -307,35 +320,34 @@ class Snapper: snaps = [] self.lastSnappedObject = obj - if hasattr(obj.ViewObject,"Selectable"): + if hasattr(obj.ViewObject, "Selectable"): if not obj.ViewObject.Selectable: self.spoint = self.cstr(lastpoint, constrain, point) self.running = False return self.spoint if not active: - # passive snapping + # Passive snapping snaps = [self.snapToVertex(self.snapInfo)] - else: - # first stick to the snapped object + # First stick to the snapped object s = self.snapToVertex(self.snapInfo) if s: point = s[0] snaps = [s] - # active snapping + # Active snapping comp = self.snapInfo['Component'] - shape = Part.getShape(parent,subname, - needSubElement=True,noElementMap=True) + shape = Part.getShape(parent, subname, + needSubElement=True, + noElementMap=True) if not shape.isNull(): - - snaps.extend(self.snapToSpecials(obj,lastpoint,eline)) + snaps.extend(self.snapToSpecials(obj, lastpoint, eline)) if Draft.getType(obj) == "Polygon": - # special snapping for polygons: add the center + # Special snapping for polygons: add the center snaps.extend(self.snapToPolygon(obj)) if (not self.maxEdges) or (len(shape.Edges) <= self.maxEdges): @@ -351,9 +363,9 @@ class Snapper: if edge: snaps.extend(self.snapToEndpoints(edge)) snaps.extend(self.snapToMidpoint(edge)) - snaps.extend(self.snapToPerpendicular(edge,lastpoint)) + snaps.extend(self.snapToPerpendicular(edge, lastpoint)) snaps.extend(self.snapToIntersection(edge)) - snaps.extend(self.snapToElines(edge,eline)) + snaps.extend(self.snapToElines(edge, eline)) et = DraftGeomUtils.geomType(edge) if et == "Circle": @@ -370,10 +382,10 @@ class Snapper: snaps.extend(self.snapToFace(face)) elif "Vertex" in comp: # directly snapped to a vertex - snaps.append(self.snapToVertex(self.snapInfo,active=True)) + snaps.append(self.snapToVertex(self.snapInfo, active=True)) elif comp == '': # workaround for the new view provider - snaps.append(self.snapToVertex(self.snapInfo,active=True)) + snaps.append(self.snapToVertex(self.snapInfo, active=True)) else: # all other cases (face, etc...) default to passive snap snapArray = [self.snapToVertex(self.snapInfo)] @@ -395,9 +407,10 @@ class Snapper: # for points we only snap to points snaps.extend(self.snapToEndpoints(obj.Points)) - elif Draft.getType(obj) in ["WorkingPlaneProxy","BuildingPart"]: + elif Draft.getType(obj) in ("WorkingPlaneProxy", "BuildingPart"): # snap to the center of WPProxies and BuildingParts - snaps.append([obj.Placement.Base,'endpoint',self.toWP(obj.Placement.Base)]) + snaps.append([obj.Placement.Base, 'endpoint', + self.toWP(obj.Placement.Base)]) elif Draft.getType(obj) == "SectionPlane": # snap to corners of section planes @@ -420,13 +433,15 @@ class Snapper: # calculating the nearest snap point shortest = 1000000000000000000 - origin = Vector(self.snapInfo['x'],self.snapInfo['y'],self.snapInfo['z']) + origin = Vector(self.snapInfo['x'], + self.snapInfo['y'], + self.snapInfo['z']) winner = None fp = point for snap in snaps: if (not snap) or (snap[0] is None): pass - #print("debug: Snapper: invalid snap point: ",snaps) + # print("debug: Snapper: invalid snap point: ",snaps) else: delta = snap[0].sub(origin) if delta.Length < shortest: @@ -456,46 +471,48 @@ class Snapper: # set the arch point tracking if lastpoint: - self.setArchDims(lastpoint,fp) + self.setArchDims(lastpoint, fp) # return the final point self.spoint = fp self.running = False return self.spoint - def toWP(self,point): - "projects the given point on the working plane, if needed" + def toWP(self, point): + """Project the given point on the working plane, if needed.""" if self.isEnabled("WorkingPlane"): - if hasattr(FreeCAD,"DraftWorkingPlane"): + if hasattr(FreeCAD, "DraftWorkingPlane"): return FreeCAD.DraftWorkingPlane.projectPoint(point) return point - def getApparentPoint(self,x,y): - "returns a 3D point, projected on the current working plane" + def getApparentPoint(self, x, y): + """Return a 3D point, projected on the current working plane.""" view = Draft.get3DView() - pt = view.getPoint(x,y) + pt = view.getPoint(x, y) if self.mask != "z": - if hasattr(FreeCAD,"DraftWorkingPlane"): + if hasattr(FreeCAD, "DraftWorkingPlane"): if view.getCameraType() == "Perspective": camera = view.getCameraNode() p = camera.getField("position").getValue() - dv = pt.sub(Vector(p[0],p[1],p[2])) + dv = pt.sub(Vector(p[0], p[1], p[2])) else: dv = view.getViewDirection() - return FreeCAD.DraftWorkingPlane.projectPoint(pt,dv) + return FreeCAD.DraftWorkingPlane.projectPoint(pt, dv) return pt - def snapToDim(self,obj): + def snapToDim(self, obj): snaps = [] if obj.ViewObject: - if hasattr(obj.ViewObject.Proxy,"p2") and hasattr(obj.ViewObject.Proxy,"p3"): - snaps.append([obj.ViewObject.Proxy.p2,'endpoint',self.toWP(obj.ViewObject.Proxy.p2)]) - snaps.append([obj.ViewObject.Proxy.p3,'endpoint',self.toWP(obj.ViewObject.Proxy.p3)]) + if hasattr(obj.ViewObject.Proxy, "p2") and hasattr(obj.ViewObject.Proxy, "p3"): + snaps.append([obj.ViewObject.Proxy.p2, 'endpoint', self.toWP(obj.ViewObject.Proxy.p2)]) + snaps.append([obj.ViewObject.Proxy.p3, 'endpoint', self.toWP(obj.ViewObject.Proxy.p3)]) return snaps - def snapToExtensions(self,point,last,constrain,eline): - "returns a point snapped to extension or parallel line to last object, if any" + def snapToExtensions(self, point, last, constrain, eline): + """Return a point snapped to extension or parallel line. + The parallel line of the last object, if any. + """ tsnap = self.snapToHold(point) if tsnap: if self.tracker and not self.selectMode: @@ -507,9 +524,9 @@ class Snapper: self.extLine.p2(tsnap[2]) self.extLine.on() self.setCursor(tsnap[1]) - return tsnap[2],eline + return tsnap[2], eline if self.isEnabled("extension"): - tsnap = self.snapToExtOrtho(last,constrain,eline) + tsnap = self.snapToExtOrtho(last, constrain, eline) if tsnap: if (tsnap[0].sub(point)).Length < self.radius: if self.tracker and not self.selectMode: @@ -520,7 +537,7 @@ class Snapper: self.extLine.p2(tsnap[2]) self.extLine.on() self.setCursor(tsnap[1]) - return tsnap[2],eline + return tsnap[2], eline else: tsnap = self.snapToExtPerpendicular(last) if tsnap: @@ -533,10 +550,11 @@ class Snapper: self.extLine.p2(tsnap[2]) self.extLine.on() self.setCursor(tsnap[1]) - return tsnap[2],eline + return tsnap[2], eline - for o in [self.lastObj[1],self.lastObj[0]]: - if o and (self.isEnabled('extension') or self.isEnabled('parallel')): + for o in (self.lastObj[1], self.lastObj[0]): + if o and (self.isEnabled('extension') + or self.isEnabled('parallel')): ob = FreeCAD.ActiveDocument.getObject(o) if ob: if ob.isDerivedFrom("Part::Feature"): @@ -599,11 +617,11 @@ class Snapper: return np,de return point,eline - def snapToCrossExtensions(self,point): - "snaps to the intersection of the last 2 extension lines" + def snapToCrossExtensions(self, point): + """Snap to the intersection of the last 2 extension lines.""" if self.isEnabled('extension'): if len(self.lastExtensions) == 2: - np = DraftGeomUtils.findIntersection(self.lastExtensions[0],self.lastExtensions[1],True,True) + np = DraftGeomUtils.findIntersection(self.lastExtensions[0], self.lastExtensions[1], True, True) if np: for p in np: dv = point.sub(p) @@ -614,7 +632,7 @@ class Snapper: self.tracker.on() self.setCursor('intersection') if self.extLine and self.extLine2: - if DraftVecUtils.equals(self.extLine.p1(),self.lastExtensions[0].Vertexes[0].Point): + if DraftVecUtils.equals(self.extLine.p1(), self.lastExtensions[0].Vertexes[0].Point): p0 = self.lastExtensions[1].Vertexes[0].Point else: p0 = self.lastExtensions[0].Vertexes[0].Point @@ -629,35 +647,35 @@ class Snapper: return p return None - def snapToPolar(self,point,last): - "snaps to polar lines from the given point" + def snapToPolar(self, point, last): + """Snap to polar lines from the given point.""" if self.isEnabled('ortho') and (not self.mask): if last: vecs = [] - if hasattr(FreeCAD,"DraftWorkingPlane"): + if hasattr(FreeCAD, "DraftWorkingPlane"): ax = [FreeCAD.DraftWorkingPlane.u, - FreeCAD.DraftWorkingPlane.v, - FreeCAD.DraftWorkingPlane.axis] + FreeCAD.DraftWorkingPlane.v, + FreeCAD.DraftWorkingPlane.axis] else: - ax = [FreeCAD.Vector(1,0,0), - FreeCAD.Vector(0,1,0), - FreeCAD.Vector(0,0,1)] + ax = [FreeCAD.Vector(1, 0, 0), + FreeCAD.Vector(0, 1, 0), + FreeCAD.Vector(0, 0, 1)] for a in self.polarAngles: - if a == 90: - vecs.extend([ax[0],ax[0].negative()]) - vecs.extend([ax[1],ax[1].negative()]) - else: - v = DraftVecUtils.rotate(ax[0],math.radians(a),ax[2]) - vecs.extend([v,v.negative()]) - v = DraftVecUtils.rotate(ax[1],math.radians(a),ax[2]) - vecs.extend([v,v.negative()]) + if a == 90: + vecs.extend([ax[0], ax[0].negative()]) + vecs.extend([ax[1], ax[1].negative()]) + else: + v = DraftVecUtils.rotate(ax[0], math.radians(a), ax[2]) + vecs.extend([v, v.negative()]) + v = DraftVecUtils.rotate(ax[1], math.radians(a), ax[2]) + vecs.extend([v, v.negative()]) for v in vecs: if not DraftVecUtils.isNull(v): try: - de = Part.LineSegment(last,last.add(v)).toShape() + de = Part.LineSegment(last, last.add(v)).toShape() except Part.OCCError: - return point,None - np = self.getPerpendicular(de,point) + return point, None + np = self.getPerpendicular(de, point) if ((self.radius == 0) and (point.sub(last).getAngle(v) < 0.087)) \ or ((np.sub(point)).Length < self.radius): if self.tracker and not self.selectMode: @@ -666,10 +684,10 @@ class Snapper: self.tracker.on() self.setCursor('ortho') return np,de - return point,None + return point, None - def snapToGrid(self,point): - "returns a grid snap point if available" + def snapToGrid(self, point): + """Return a grid snap point if available.""" if self.grid: if self.grid.Visible: if self.isEnabled("grid"): @@ -685,32 +703,32 @@ class Snapper: return np return point - def snapToEndpoints(self,shape): - "returns a list of endpoints snap locations" + def snapToEndpoints(self, shape): + """Return a list of endpoints snap locations.""" snaps = [] if self.isEnabled("endpoint"): - if hasattr(shape,"Vertexes"): + if hasattr(shape, "Vertexes"): for v in shape.Vertexes: - snaps.append([v.Point,'endpoint',self.toWP(v.Point)]) - elif hasattr(shape,"Point"): - snaps.append([shape.Point,'endpoint',self.toWP(shape.Point)]) - elif hasattr(shape,"Points"): - if len(shape.Points) and hasattr(shape.Points[0],"Vector"): + snaps.append([v.Point, 'endpoint', self.toWP(v.Point)]) + elif hasattr(shape, "Point"): + snaps.append([shape.Point, 'endpoint', self.toWP(shape.Point)]) + elif hasattr(shape, "Points"): + if len(shape.Points) and hasattr(shape.Points[0], "Vector"): for v in shape.Points: - snaps.append([v.Vector,'endpoint',self.toWP(v.Vector)]) + snaps.append([v.Vector, 'endpoint', self.toWP(v.Vector)]) else: for v in shape.Points: - snaps.append([v,'endpoint',self.toWP(v)]) + snaps.append([v, 'endpoint', self.toWP(v)]) return snaps - def snapToMidpoint(self,shape): - "returns a list of midpoints snap locations" + def snapToMidpoint(self, shape): + """Return a list of midpoints snap locations.""" snaps = [] if self.isEnabled("midpoint"): - if isinstance(shape,Part.Edge): + if isinstance(shape, Part.Edge): mp = DraftGeomUtils.findMidpoint(shape) if mp: - snaps.append([mp,'midpoint',self.toWP(mp)]) + snaps.append([mp, 'midpoint', self.toWP(mp)]) return snaps def snapToPerpendicular(self,shape,last): From b206106df583c31a8c4e80edec3e9991d7920390 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 3 Mar 2020 00:40:57 -0600 Subject: [PATCH 26/62] Draft: gui_snapper clean up docstrings and spaces (2) --- src/Mod/Draft/draftguitools/gui_snapper.py | 433 +++++++++++---------- 1 file changed, 236 insertions(+), 197 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index fd453ee1c0..37a4a9e211 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -33,6 +33,7 @@ defined by `gui_trackers.gridTracker`. # everything that goes with it (toolbar buttons, cursor icons, etc.). import collections as coll +import inspect import itertools import math from pivy import coin @@ -731,175 +732,188 @@ class Snapper: snaps.append([mp, 'midpoint', self.toWP(mp)]) return snaps - def snapToPerpendicular(self,shape,last): - "returns a list of perpendicular snap locations" + def snapToPerpendicular(self, shape, last): + """Return a list of perpendicular snap locations.""" snaps = [] if self.isEnabled("perpendicular"): if last: - if isinstance(shape,Part.Edge): + if isinstance(shape, Part.Edge): if DraftGeomUtils.geomType(shape) == "Line": - np = self.getPerpendicular(shape,last) + np = self.getPerpendicular(shape, last) elif DraftGeomUtils.geomType(shape) == "Circle": dv = last.sub(shape.Curve.Center) - dv = DraftVecUtils.scaleTo(dv,shape.Curve.Radius) + dv = DraftVecUtils.scaleTo(dv, shape.Curve.Radius) np = (shape.Curve.Center).add(dv) elif DraftGeomUtils.geomType(shape) == "BSplineCurve": try: pr = shape.Curve.parameter(last) np = shape.Curve.value(pr) - except: + except Exception: return snaps else: return snaps - snaps.append([np,'perpendicular',self.toWP(np)]) + snaps.append([np, 'perpendicular', self.toWP(np)]) return snaps - def snapToOrtho(self,shape,last,constrain): - "returns a list of ortho snap locations" + def snapToOrtho(self, shape, last, constrain): + """Return a list of ortho snap locations.""" snaps = [] if self.isEnabled("ortho"): if constrain: - if isinstance(shape,Part.Edge): + if isinstance(shape, Part.Edge): if last: if DraftGeomUtils.geomType(shape) == "Line": if self.constraintAxis: - tmpEdge = Part.LineSegment(last,last.add(self.constraintAxis)).toShape() + tmpEdge = Part.LineSegment(last, last.add(self.constraintAxis)).toShape() # get the intersection points - pt = DraftGeomUtils.findIntersection(tmpEdge,shape,True,True) + pt = DraftGeomUtils.findIntersection(tmpEdge, shape, True, True) if pt: for p in pt: - snaps.append([p,'ortho',self.toWP(p)]) + snaps.append([p, 'ortho', self.toWP(p)]) return snaps - def snapToExtOrtho(self,last,constrain,eline): - "returns an ortho X extension snap location" + def snapToExtOrtho(self, last, constrain, eline): + """Return an ortho X extension snap location.""" if self.isEnabled("extension") and self.isEnabled("ortho"): if constrain and last and self.constraintAxis and self.extLine: - tmpEdge1 = Part.LineSegment(last,last.add(self.constraintAxis)).toShape() - tmpEdge2 = Part.LineSegment(self.extLine.p1(),self.extLine.p2()).toShape() + tmpEdge1 = Part.LineSegment(last, last.add(self.constraintAxis)).toShape() + tmpEdge2 = Part.LineSegment(self.extLine.p1(), self.extLine.p2()).toShape() # get the intersection points - pt = DraftGeomUtils.findIntersection(tmpEdge1,tmpEdge2,True,True) + pt = DraftGeomUtils.findIntersection(tmpEdge1, tmpEdge2, True, True) if pt: - return [pt[0],'ortho',pt[0]] + return [pt[0], 'ortho', pt[0]] if eline: try: - tmpEdge2 = Part.LineSegment(self.extLine.p1(),self.extLine.p2()).toShape() + tmpEdge2 = Part.LineSegment(self.extLine.p1(), self.extLine.p2()).toShape() # get the intersection points - pt = DraftGeomUtils.findIntersection(eline,tmpEdge2,True,True) + pt = DraftGeomUtils.findIntersection(eline, tmpEdge2, True, True) if pt: - return [pt[0],'ortho',pt[0]] - except: + return [pt[0], 'ortho', pt[0]] + except Exception: return None return None - def snapToHold(self,point): - "returns a snap location that is orthogonal to hold points or, if possible, at crossings" + def snapToHold(self, point): + """Return a snap location that is orthogonal to hold points. + + Or if possible at crossings. + """ if not self.holdPoints: return None - if hasattr(FreeCAD,"DraftWorkingPlane"): + if hasattr(FreeCAD, "DraftWorkingPlane"): u = FreeCAD.DraftWorkingPlane.u v = FreeCAD.DraftWorkingPlane.v else: - u = FreeCAD.Vector(1,0,0) - v = FreeCAD.Vector(0,1,0) + u = FreeCAD.Vector(1, 0, 0) + v = FreeCAD.Vector(0, 1, 0) if len(self.holdPoints) > 1: # first try mid points if self.isEnabled("midpoint"): l = list(self.holdPoints) - for p1,p2 in itertools.combinations(l,2): + for p1, p2 in itertools.combinations(l, 2): p3 = p1.add((p2.sub(p1)).multiply(0.5)) if (p3.sub(point)).Length < self.radius: - return [p1,'midpoint',p3] + return [p1, 'midpoint', p3] # then try int points ipoints = [] l = list(self.holdPoints) while len(l) > 1: p1 = l.pop() for p2 in l: - i1 = DraftGeomUtils.findIntersection(p1,p1.add(u),p2,p2.add(v),True,True) + i1 = DraftGeomUtils.findIntersection(p1, p1.add(u), p2, p2.add(v), True, True) if i1: - ipoints.append([p1,i1[0]]) - i2 = DraftGeomUtils.findIntersection(p1,p1.add(v),p2,p2.add(u),True,True) + ipoints.append([p1, i1[0]]) + i2 = DraftGeomUtils.findIntersection(p1, p1.add(v), p2, p2.add(u), True, True) if i2: - ipoints.append([p1,i2[0]]) + ipoints.append([p1, i2[0]]) for p in ipoints: if (p[1].sub(point)).Length < self.radius: - return [p[0],'ortho',p[1]] + return [p[0], 'ortho', p[1]] # then try to stick to a line for p in self.holdPoints: - d = DraftGeomUtils.findDistance(point,[p,p.add(u)]) + d = DraftGeomUtils.findDistance(point, [p, p.add(u)]) if d: if d.Length < self.radius: fp = point.add(d) - return [p,'extension',fp] - d = DraftGeomUtils.findDistance(point,[p,p.add(v)]) + return [p, 'extension', fp] + d = DraftGeomUtils.findDistance(point, [p, p.add(v)]) if d: if d.Length < self.radius: fp = point.add(d) - return [p,'extension',fp] + return [p, 'extension', fp] return None - def snapToExtPerpendicular(self,last): - "returns a perpendicular X extension snap location" + def snapToExtPerpendicular(self, last): + """Return a perpendicular X extension snap location.""" if self.isEnabled("extension") and self.isEnabled("perpendicular"): if last and self.extLine: if self.extLine.p1() != self.extLine.p2(): - tmpEdge = Part.LineSegment(self.extLine.p1(),self.extLine.p2()).toShape() - np = self.getPerpendicular(tmpEdge,last) - return [np,'perpendicular',np] + tmpEdge = Part.LineSegment(self.extLine.p1(), self.extLine.p2()).toShape() + np = self.getPerpendicular(tmpEdge, last) + return [np, 'perpendicular', np] return None - def snapToElines(self,e1,e2): - "returns a snap location at the infinite intersection of the given edges" + def snapToElines(self, e1, e2): + """Return a snap at the infinite intersection of the given edges.""" snaps = [] if self.isEnabled("intersection") and self.isEnabled("extension"): if e1 and e2: # get the intersection points - pts = DraftGeomUtils.findIntersection(e1,e2,True,True) + pts = DraftGeomUtils.findIntersection(e1, e2, True, True) if pts: for p in pts: - snaps.append([p,'intersection',self.toWP(p)]) + snaps.append([p, 'intersection', self.toWP(p)]) return snaps - def snapToAngles(self,shape): - "returns a list of angle snap locations" + def snapToAngles(self, shape): + """Return a list of angle snap locations.""" snaps = [] if self.isEnabled("angle"): rad = shape.Curve.Radius pos = shape.Curve.Center - for i in [0,30,45,60,90,120,135,150,180,210,225,240,270,300,315,330]: + for i in (0, 30, 45, 60, 90, + 120, 135, 150, 180, + 210, 225, 240, 270, + 300, 315, 330): ang = math.radians(i) - cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) - snaps.append([cur,'angle',self.toWP(cur)]) + cur = Vector(math.sin(ang) * rad + pos.x, + math.cos(ang) * rad + pos.y, + pos.z) + snaps.append([cur, 'angle', self.toWP(cur)]) return snaps - def snapToCenter(self,shape): - "returns a list of center snap locations" + def snapToCenter(self, shape): + """Return a list of center snap locations.""" snaps = [] if self.isEnabled("center"): pos = shape.Curve.Center c = self.toWP(pos) - if hasattr(shape.Curve,"Radius"): + if hasattr(shape.Curve, "Radius"): rad = shape.Curve.Radius - for i in [15,37.5,52.5,75,105,127.5,142.5,165,195,217.5,232.5,255,285,307.5,322.5,345]: + for i in (15, 37.5, 52.5, 75, + 105, 127.5, 142.5, 165, + 195, 217.5, 232.5, 255, + 285, 307.5, 322.5, 345): ang = math.radians(i) - cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) - snaps.append([cur,'center',c]) + cur = Vector(math.sin(ang) * rad + pos.x, + math.cos(ang) * rad + pos.y, + pos.z) + snaps.append([cur, 'center', c]) else: - snaps.append([c,'center',c]) + snaps.append([c, 'center', c]) return snaps - def snapToFace(self,shape): - "returns a face center snap location" + def snapToFace(self, shape): + """Return a face center snap location.""" snaps = [] if self.isEnabled("center"): pos = shape.CenterOfMass c = self.toWP(pos) - snaps.append([pos,'center',c]) + snaps.append([pos, 'center', c]) return snaps - def snapToIntersection(self,shape): - "returns a list of intersection snap locations" + def snapToIntersection(self, shape): + """Return a list of intersection snap locations.""" snaps = [] if self.isEnabled("intersection"): # get the stored objects to calculate intersections @@ -918,45 +932,47 @@ class Snapper: p2 = self.toWP(e.Vertexes[-1].Point) p3 = self.toWP(shape.Vertexes[0].Point) p4 = self.toWP(shape.Vertexes[-1].Point) - pt = DraftGeomUtils.findIntersection(p1,p2,p3,p4,True,True) + pt = DraftGeomUtils.findIntersection(p1, p2, p3, p4, True, True) else: - pt = DraftGeomUtils.findIntersection(e,shape) + pt = DraftGeomUtils.findIntersection(e, shape) if pt: for p in pt: - snaps.append([p,'intersection',self.toWP(p)]) + snaps.append([p, 'intersection', self.toWP(p)]) except: pass - # some curve types yield an error when trying to read their types... + # some curve types yield an error + # when trying to read their types return snaps - def snapToPolygon(self,obj): - "returns a list of polygon center snap locations" + def snapToPolygon(self, obj): + """Return a list of polygon center snap locations.""" snaps = [] if self.isEnabled("center"): c = obj.Placement.Base for edge in obj.Shape.Edges: p1 = edge.Vertexes[0].Point p2 = edge.Vertexes[-1].Point - v1 = p1.add((p2-p1).scale(.25,.25,.25)) - v2 = p1.add((p2-p1).scale(.75,.75,.75)) - snaps.append([v1,'center',self.toWP(c)]) - snaps.append([v2,'center',self.toWP(c)]) + v1 = p1.add((p2 - p1).scale(0.25, 0.25, 0.25)) + v2 = p1.add((p2 - p1).scale(0.75, 0.75, 0.75)) + snaps.append([v1, 'center', self.toWP(c)]) + snaps.append([v2, 'center', self.toWP(c)]) return snaps - def snapToVertex(self,info,active=False): - p = Vector(info['x'],info['y'],info['z']) + def snapToVertex(self, info, active=False): + """Return a vertex snap location.""" + p = Vector(info['x'], info['y'], info['z']) if active: if self.isEnabled("passive"): - return [p,'endpoint',self.toWP(p)] + return [p, 'endpoint', self.toWP(p)] else: return [] elif self.isEnabled("passive"): - return [p,'passive',p] + return [p, 'passive', p] else: return [] - def snapToSpecials(self,obj,lastpoint=None,eline=None): - "returns special snap locations, if any" + def snapToSpecials(self, obj, lastpoint=None, eline=None): + """Return special snap locations, if any.""" snaps = [] if self.isEnabled("special"): @@ -965,48 +981,48 @@ class Snapper: if obj.Base: if not obj.Base.Shape.Solids: for v in obj.Base.Shape.Vertexes: - snaps.append([v.Point,'special',self.toWP(v.Point)]) + snaps.append([v.Point, 'special', self.toWP(v.Point)]) elif (Draft.getType(obj) == "Structure"): # special snapping for struct: only to its base point if obj.Base: if not obj.Base.Shape.Solids: for v in obj.Base.Shape.Vertexes: - snaps.append([v.Point,'special',self.toWP(v.Point)]) + snaps.append([v.Point, 'special', self.toWP(v.Point)]) else: b = obj.Placement.Base - snaps.append([b,'special',self.toWP(b)]) + snaps.append([b, 'special', self.toWP(b)]) if obj.ViewObject.ShowNodes: for edge in obj.Proxy.getNodeEdges(obj): snaps.extend(self.snapToEndpoints(edge)) snaps.extend(self.snapToMidpoint(edge)) - snaps.extend(self.snapToPerpendicular(edge,lastpoint)) + snaps.extend(self.snapToPerpendicular(edge, lastpoint)) snaps.extend(self.snapToIntersection(edge)) - snaps.extend(self.snapToElines(edge,eline)) + snaps.extend(self.snapToElines(edge, eline)) - elif hasattr(obj,"SnapPoints"): + elif hasattr(obj, "SnapPoints"): for p in obj.SnapPoints: p2 = obj.Placement.multVec(p) - snaps.append([p2,'special',p2]) + snaps.append([p2, 'special', p2]) return snaps - def getScreenDist(self,dist,cursor): - "returns a distance in 3D space from a screen pixels distance" + def getScreenDist(self, dist, cursor): + """Return a distance in 3D space from a screen pixels distance.""" view = Draft.get3DView() p1 = view.getPoint(cursor) - p2 = view.getPoint((cursor[0]+dist,cursor[1])) + p2 = view.getPoint((cursor[0] + dist, cursor[1])) return (p2.sub(p1)).Length - def getPerpendicular(self,edge,pt): - "returns a point on an edge, perpendicular to the given point" + def getPerpendicular(self, edge, pt): + """Return a point on an edge, perpendicular to the given point.""" dv = pt.sub(edge.Vertexes[0].Point) - nv = DraftVecUtils.project(dv,DraftGeomUtils.vec(edge)) + nv = DraftVecUtils.project(dv, DraftGeomUtils.vec(edge)) np = (edge.Vertexes[0].Point).add(nv) return np - def setArchDims(self,p1,p2): - "show arch dimensions between 2 points" + def setArchDims(self, p1, p2): + """Show arc dimensions between 2 points.""" if self.isEnabled("Dimensions"): if not self.dim1: self.dim1 = trackers.archDimTracker(mode=2) @@ -1021,8 +1037,8 @@ class Snapper: if self.dim2.Distance: self.dim2.on() - def setCursor(self,mode=None): - "setCursor(self,mode=None): sets or resets the cursor to the given mode or resets" + def setCursor(self, mode=None): + """Set or reset the cursor to the given mode or resets.""" if self.selectMode: mw = FreeCADGui.getMainWindow() for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget): @@ -1038,16 +1054,16 @@ class Snapper: else: if mode != self.cursorMode: baseicon = QtGui.QPixmap(":/icons/Draft_Cursor.svg") - newicon = QtGui.QPixmap(32,24) + newicon = QtGui.QPixmap(32, 24) newicon.fill(QtCore.Qt.transparent) qp = QtGui.QPainter() qp.begin(newicon) - qp.drawPixmap(0,0,baseicon) + qp.drawPixmap(0, 0, baseicon) if not (mode == 'passive'): tp = QtGui.QPixmap(self.cursors[mode]).scaledToWidth(16) - qp.drawPixmap(QtCore.QPoint(16, 8), tp); + qp.drawPixmap(QtCore.QPoint(16, 8), tp) qp.end() - cur = QtGui.QCursor(newicon,8,8) + cur = QtGui.QCursor(newicon, 8, 8) mw = FreeCADGui.getMainWindow() for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget): if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget": @@ -1055,11 +1071,12 @@ class Snapper: self.cursorMode = mode def restack(self): + """Lower the grid tracker so it doesn't obscure other objects.""" if self.grid: self.grid.lowerTracker() def off(self, hideSnapBar=False): - "finishes snapping" + """Finish snapping.""" if self.tracker: self.tracker.off() if self.trackLine: @@ -1075,7 +1092,7 @@ class Snapper: if self.dim2: self.dim2.off() if self.grid: - if not Draft.getParam("alwaysShowGrid",True): + if not Draft.getParam("alwaysShowGrid", True): self.grid.off() if self.holdTracker: self.holdTracker.clear() @@ -1083,16 +1100,16 @@ class Snapper: self.unconstrain() self.radius = 0 self.setCursor() - if hideSnapBar or Draft.getParam("hideSnapBar",False): - if hasattr(self,"toolbar") and self.toolbar: + if hideSnapBar or Draft.getParam("hideSnapBar", False): + if hasattr(self, "toolbar") and self.toolbar: self.toolbar.hide() self.mask = None self.selectMode = False self.running = False self.holdPoints = [] - def setSelectMode(self,mode): - "sets the snapper into select mode (hides snapping temporarily)" + def setSelectMode(self, mode): + """Set the snapper into select mode (hides snapping temporarily).""" self.selectMode = mode if not mode: self.setCursor() @@ -1100,26 +1117,28 @@ class Snapper: if self.trackLine: self.trackLine.off() - def setAngle(self,delta=None): - "keeps the current angle" + def setAngle(self, delta=None): + """Keep the current angle.""" if delta: self.mask = delta - elif isinstance(self.mask,FreeCAD.Vector): + elif isinstance(self.mask, FreeCAD.Vector): self.mask = None elif self.trackLine: if self.trackLine.Visible: self.mask = self.trackLine.p2().sub(self.trackLine.p1()) - def constrain(self,point,basepoint=None,axis=None): - '''constrain(point,basepoint=None,axis=None: Returns a + def constrain(self, point, basepoint=None, axis=None): + """Return a constrained point. + + constrain(point,basepoint=None,axis=None: Returns a constrained point. Axis can be "x","y" or "z" or a custom vector. If None, the closest working plane axis will be picked. Basepoint is the base point used to figure out from where the point must be constrained. If no basepoint is given, the current point is - used as basepoint.''' - + used as basepoint. + """ # without the Draft module fully loaded, no axes system!" - if not hasattr(FreeCAD,"DraftWorkingPlane"): + if not hasattr(FreeCAD, "DraftWorkingPlane"): return point point = Vector(point) @@ -1144,7 +1163,7 @@ class Snapper: self.affinity = self.mask if not self.affinity: self.affinity = FreeCAD.DraftWorkingPlane.getClosestAxis(delta) - if isinstance(axis,FreeCAD.Vector): + if isinstance(axis, FreeCAD.Vector): self.constraintAxis = axis elif axis == "x": self.constraintAxis = FreeCAD.DraftWorkingPlane.u @@ -1159,7 +1178,7 @@ class Snapper: self.constraintAxis = FreeCAD.DraftWorkingPlane.v elif self.affinity == "z": self.constraintAxis = FreeCAD.DraftWorkingPlane.axis - elif isinstance(self.affinity,FreeCAD.Vector): + elif isinstance(self.affinity, FreeCAD.Vector): self.constraintAxis = self.affinity else: self.constraintAxis = None @@ -1168,7 +1187,7 @@ class Snapper: return point # calculating constrained point - cdelta = DraftVecUtils.project(delta,self.constraintAxis) + cdelta = DraftVecUtils.project(delta, self.constraintAxis) npoint = self.basepoint.add(cdelta) # setting constrain line @@ -1183,22 +1202,26 @@ class Snapper: return npoint def unconstrain(self): + """Unset the basepoint and the constrain line.""" self.basepoint = None self.affinity = None if self.constrainLine: self.constrainLine.off() - def getPoint(self,last=None,callback=None,movecallback=None,extradlg=None,title=None,mode="point"): + def getPoint(self, last=None, callback=None, movecallback=None, + extradlg=None, title=None, mode="point"): + """Get a 3D point from the screen. - """ - getPoint([last],[callback],[movecallback],[extradlg],[title]) : gets a 3D point - from the screen. You can provide an existing point, in that case additional - snap options and a tracker are available. + getPoint([last],[callback],[movecallback],[extradlg],[title]): + gets a 3D point from the screen. You can provide an existing point, + in that case additional snap options and a tracker are available. You can also pass a function as callback, which will get called - with the resulting point as argument, when a point is clicked, and optionally - another callback which gets called when the mouse is moved. + with the resulting point as argument, when a point is clicked, + and optionally another callback which gets called when + the mouse is moved. - If the operation gets cancelled (the user pressed Escape), no point is returned. + If the operation gets cancelled (the user pressed Escape), + no point is returned. Example: @@ -1208,17 +1231,15 @@ class Snapper: FreeCADGui.Snapper.getPoint(callback=cb) - If the callback function accepts more than one argument, it will also receive - the last snapped object. Finally, a qt widget can be passed as an extra taskbox. - title is the title of the point task box - mode is the dialog box you want (default is point, you can also use wire and line) + If the callback function accepts more than one argument, + it will also receive the last snapped object. Finally, a qt widget + can be passed as an extra taskbox. + title is the title of the point task box mode is the dialog box + you want (default is point, you can also use wire and line) - If getPoint() is invoked without any argument, nothing is done but the callbacks - are removed, so it can be used as a cancel function. + If getPoint() is invoked without any argument, nothing is done + but the callbacks are removed, so it can be used as a cancel function. """ - - import inspect - self.pt = None self.lastSnappedObject = None self.holdPoints = [] @@ -1227,9 +1248,9 @@ class Snapper: # remove any previous leftover callbacks if self.callbackClick: - self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) + self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.callbackClick) if self.callbackMove: - self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),self.callbackMove) + self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) self.callbackClick = None self.callbackMove = None @@ -1238,15 +1259,19 @@ class Snapper: mousepos = event.getPosition() ctrl = event.wasCtrlDown() shift = event.wasShiftDown() - self.pt = FreeCADGui.Snapper.snap(mousepos,lastpoint=last,active=ctrl,constrain=shift) - if hasattr(FreeCAD,"DraftWorkingPlane"): - self.ui.displayPoint(self.pt,last,plane=FreeCAD.DraftWorkingPlane,mask=FreeCADGui.Snapper.affinity) + self.pt = FreeCADGui.Snapper.snap(mousepos, lastpoint=last, + active=ctrl, constrain=shift) + if hasattr(FreeCAD, "DraftWorkingPlane"): + self.ui.displayPoint(self.pt, last, + plane=FreeCAD.DraftWorkingPlane, + mask=FreeCADGui.Snapper.affinity) if movecallback: - movecallback(self.pt,self.snapInfo) + movecallback(self.pt, self.snapInfo) - def getcoords(point,relative=False): + def getcoords(point, relative=False): + """Get the global coordinates from a point.""" self.pt = point - if relative and last and hasattr(FreeCAD,"DraftWorkingPlane"): + if relative and last and hasattr(FreeCAD, "DraftWorkingPlane"): v = FreeCAD.DraftWorkingPlane.getGlobalCoords(point) self.pt = last.add(v) accept() @@ -1259,9 +1284,9 @@ class Snapper: def accept(): if self.callbackClick: - self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) + self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.callbackClick) if self.callbackMove: - self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),self.callbackMove) + self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) self.callbackClick = None self.callbackMove = None obj = FreeCADGui.Snapper.lastSnappedObject @@ -1269,23 +1294,23 @@ class Snapper: self.ui.offUi() if callback: if len(inspect.getargspec(callback).args) > 1: - callback(self.pt,obj) + callback(self.pt, obj) else: callback(self.pt) self.pt = None def cancel(): if self.callbackClick: - self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) + self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.callbackClick) if self.callbackMove: - self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),self.callbackMove) + self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) self.callbackClick = None self.callbackMove = None FreeCADGui.Snapper.off() self.ui.offUi() if callback: if len(inspect.getargspec(callback).args) > 1: - callback(None,None) + callback(None, None) else: callback(None) @@ -1298,111 +1323,121 @@ class Snapper: interface = self.ui.pointUi if callback: if title: - interface(title=title,cancel=cancel,getcoords=getcoords,extra=extradlg,rel=bool(last)) + interface(title=title, cancel=cancel, getcoords=getcoords, + extra=extradlg, rel=bool(last)) else: interface(cancel=cancel,getcoords=getcoords,extra=extradlg,rel=bool(last)) self.callbackClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),click) self.callbackMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),move) def makeSnapToolBar(self): - "builds the Snap toolbar" + """Build the Snap toolbar.""" mw = FreeCADGui.getMainWindow() self.toolbar = QtGui.QToolBar(mw) mw.addToolBar(QtCore.Qt.TopToolBarArea, self.toolbar) self.toolbar.setObjectName("Draft Snap") self.toolbar.setWindowTitle(QtCore.QCoreApplication.translate("Workbench", "Draft Snap")) self.toolbarButtons = [] + # grid button self.gridbutton = QtGui.QAction(mw) self.gridbutton.setIcon(QtGui.QIcon.fromTheme("Draft_Grid", QtGui.QIcon(":/icons/Draft_Grid.svg"))) - self.gridbutton.setText(QtCore.QCoreApplication.translate("Draft_ToggleGrid","Grid")) - self.gridbutton.setToolTip(QtCore.QCoreApplication.translate("Draft_ToggleGrid","Toggles the Draft grid On/Off")) + self.gridbutton.setText(QtCore.QCoreApplication.translate("Draft_ToggleGrid", "Grid")) + self.gridbutton.setToolTip(QtCore.QCoreApplication.translate("Draft_ToggleGrid", "Toggles the Draft grid On/Off")) self.gridbutton.setObjectName("GridButton") self.gridbutton.setWhatsThis("Draft_ToggleGrid") - QtCore.QObject.connect(self.gridbutton,QtCore.SIGNAL("triggered()"),self.toggleGrid) + QtCore.QObject.connect(self.gridbutton, QtCore.SIGNAL("triggered()"), self.toggleGrid) self.toolbar.addAction(self.gridbutton) + # master button self.masterbutton = QtGui.QAction(mw) self.masterbutton.setIcon(QtGui.QIcon.fromTheme("Snap_Lock", QtGui.QIcon(":/icons/Snap_Lock.svg"))) - self.masterbutton.setText(QtCore.QCoreApplication.translate("Draft_Snap_Lock","Lock")) - self.masterbutton.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_Lock","Toggle On/Off")) + self.masterbutton.setText(QtCore.QCoreApplication.translate("Draft_Snap_Lock", "Lock")) + self.masterbutton.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_Lock", "Toggle On/Off")) self.masterbutton.setObjectName("SnapButtonMain") self.masterbutton.setWhatsThis("Draft_ToggleSnap") self.masterbutton.setCheckable(True) self.masterbutton.setChecked(True) - QtCore.QObject.connect(self.masterbutton,QtCore.SIGNAL("toggled(bool)"),self.toggle) + QtCore.QObject.connect(self.masterbutton, + QtCore.SIGNAL("toggled(bool)"), self.toggle) self.toolbar.addAction(self.masterbutton) for c,i in self.cursors.items(): if i: b = QtGui.QAction(mw) b.setIcon(QtGui.QIcon.fromTheme(i.replace(':/icons/', '').replace('.svg', ''), QtGui.QIcon(i))) if c == "passive": - b.setText(QtCore.QCoreApplication.translate("Draft_Snap_Near","Nearest")) - b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_Near","Nearest")) + b.setText(QtCore.QCoreApplication.translate("Draft_Snap_Near", "Nearest")) + b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_Near", "Nearest")) else: - b.setText(QtCore.QCoreApplication.translate("Draft_Snap_"+c.capitalize(),c.capitalize())) - b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_"+c.capitalize(),c.capitalize())) - b.setObjectName("SnapButton"+c) - b.setWhatsThis("Draft_"+c.capitalize()) + b.setText(QtCore.QCoreApplication.translate("Draft_Snap_"+c.capitalize(), c.capitalize())) + b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_"+c.capitalize(), c.capitalize())) + b.setObjectName("SnapButton" + c) + b.setWhatsThis("Draft_" + c.capitalize()) b.setCheckable(True) b.setChecked(True) self.toolbar.addAction(b) self.toolbarButtons.append(b) - QtCore.QObject.connect(b,QtCore.SIGNAL("toggled(bool)"),self.saveSnapModes) + QtCore.QObject.connect(b, QtCore.SIGNAL("toggled(bool)"), + self.saveSnapModes) + # adding non-snap button - for n in ["Dimensions","WorkingPlane"]: + for n in ("Dimensions", "WorkingPlane"): b = QtGui.QAction(mw) b.setIcon(QtGui.QIcon.fromTheme("Snap_" + n, QtGui.QIcon(":/icons/Snap_"+n+".svg"))) - b.setText(QtCore.QCoreApplication.translate("Draft_Snap_"+n,n)) - b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_"+n,n)) - b.setObjectName("SnapButton"+n) - b.setWhatsThis("Draft_"+n) + b.setText(QtCore.QCoreApplication.translate("Draft_Snap_" + n,n)) + b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_" + n,n)) + b.setObjectName("SnapButton" + n) + b.setWhatsThis("Draft_" + n) b.setCheckable(True) b.setChecked(True) self.toolbar.addAction(b) - QtCore.QObject.connect(b,QtCore.SIGNAL("toggled(bool)"),self.saveSnapModes) + QtCore.QObject.connect(b, QtCore.SIGNAL("toggled(bool)"), + self.saveSnapModes) self.toolbarButtons.append(b) + # set status tip where needed for b in self.toolbar.actions(): if len(b.statusTip()) == 0: b.setStatusTip(b.toolTip()) + # restoring states - t = Draft.getParam("snapModes","111111111101111") + t = Draft.getParam("snapModes", "111111111101111") if t: c = 0 - for b in [self.masterbutton]+self.toolbarButtons: + for b in [self.masterbutton] + self.toolbarButtons: if len(t) > c: state = bool(int(t[c])) b.setChecked(state) if state: - b.setToolTip(b.toolTip()+" (ON)") + b.setToolTip(b.toolTip() + " (ON)") else: - b.setToolTip(b.toolTip()+" (OFF)") + b.setToolTip(b.toolTip() + " (OFF)") c += 1 - if not Draft.getParam("showSnapBar",True): + if not Draft.getParam("showSnapBar", True): self.toolbar.hide() def toggleGrid(self): + """Run Draft_ToggleGrid.""" FreeCADGui.runCommand("Draft_ToggleGrid") def saveSnapModes(self): - "saves the snap modes for next sessions" + """Save the snap modes for next sessions.""" t = '' - for b in [self.masterbutton]+self.toolbarButtons: + for b in [self.masterbutton] + self.toolbarButtons: t += str(int(b.isChecked())) if b.isChecked(): - b.setToolTip(b.toolTip().replace("OFF","ON")) + b.setToolTip(b.toolTip().replace("OFF", "ON")) else: - b.setToolTip(b.toolTip().replace("ON","OFF")) - Draft.setParam("snapModes",t) + b.setToolTip(b.toolTip().replace("ON", "OFF")) + Draft.setParam("snapModes", t) - def toggle(self,checked=None): - "toggles the snap mode" - if hasattr(self,"toolbarButtons"): + def toggle(self, checked=None): + """Toggle the snap mode.""" + if hasattr(self, "toolbarButtons"): if checked is None: self.masterbutton.toggle() elif checked: - if hasattr(self,"savedButtonStates"): + if hasattr(self, "savedButtonStates"): for i in range(len(self.toolbarButtons)): self.toolbarButtons[i].setEnabled(True) self.toolbarButtons[i].setChecked(self.savedButtonStates[i]) @@ -1414,25 +1449,26 @@ class Snapper: self.saveSnapModes() def showradius(self): - "shows the snap radius indicator" - self.radius = self.getScreenDist(Draft.getParam("snapRange", 8),(400,300)) + """Show the snap radius indicator.""" + self.radius = self.getScreenDist(Draft.getParam("snapRange", 8), + (400, 300)) if self.radiusTracker: self.radiusTracker.update(self.radius) self.radiusTracker.on() - def isEnabled(self,but): - "returns true if the given button is turned on" + def isEnabled(self, but): + """Return true if the given button is turned on.""" for b in self.toolbarButtons: if str(b.objectName()) == "SnapButton" + but: return (b.isEnabled() and b.isChecked()) return False def show(self): - "shows the toolbar and the grid" - if not hasattr(self,"toolbar"): + """Show the toolbar and the grid.""" + if not hasattr(self, "toolbar"): self.makeSnapToolBar() mw = FreeCADGui.getMainWindow() - bt = mw.findChild(QtGui.QToolBar,"Draft Snap") + bt = mw.findChild(QtGui.QToolBar, "Draft Snap") if not bt: mw.addToolBar(self.toolbar) self.toolbar.setParent(mw) @@ -1451,18 +1487,20 @@ class Snapper: c.height.setValue(h) def hide(self): - if hasattr(self,"toolbar"): + """Hide the toolbar.""" + if hasattr(self, "toolbar"): self.toolbar.hide() self.toolbar.toggleViewAction().setVisible(True) def setGrid(self): - "sets the grid, if visible" + """Set the grid, if visible.""" self.setTrackers() if self.grid and (not self.forceGridOff): if self.grid.Visible: self.grid.set() def setTrackers(self): + """Set the trackers.""" v = Draft.get3DView() if v != self.activeview: if v in self.trackers[0]: @@ -1477,7 +1515,7 @@ class Snapper: self.extLine2 = self.trackers[8][i] self.holdTracker = self.trackers[9][i] else: - if Draft.getParam("grid",True): + if Draft.getParam("grid", True): self.grid = trackers.gridTracker() self.grid.on() else: @@ -1487,7 +1525,7 @@ class Snapper: if self.snapStyle: c = FreeCADGui.draftToolBar.getDefaultColor("snap") self.extLine = trackers.lineTracker(scolor=c) - self.extLine2 = trackers.lineTracker(scolor = c) + self.extLine2 = trackers.lineTracker(scolor=c) else: self.extLine = trackers.lineTracker(dotted=True) self.extLine2 = trackers.lineTracker(dotted=True) @@ -1512,7 +1550,8 @@ class Snapper: self.grid.set() def addHoldPoint(self): - if self.spoint and not(self.spoint in self.holdPoints): + """Add hold snap point to list of hold points.""" + if self.spoint and self.spoint not in self.holdPoints: if self.holdTracker: self.holdTracker.addCoords(self.spoint) self.holdTracker.on() From 5cb6644a24790b966eaa67eba8b9b230194b2259 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 3 Mar 2020 01:15:27 -0600 Subject: [PATCH 27/62] Draft: gui_snaps cleanup --- src/Mod/Draft/draftguitools/gui_snaps.py | 135 ++++++++++++----------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_snaps.py b/src/Mod/Draft/draftguitools/gui_snaps.py index 233fc754b2..019d93c47a 100644 --- a/src/Mod/Draft/draftguitools/gui_snaps.py +++ b/src/Mod/Draft/draftguitools/gui_snaps.py @@ -1,9 +1,3 @@ -"""Provide the Draft_Snap commands used by the snapping mechanism in Draft.""" -## @package gui_snaps -# \ingroup DRAFT -# \brief Provide the Draft_Snap commands used by the snapping mechanism -# in Draft. - # *************************************************************************** # * (c) 2009, 2010 Yorik van Havre * # * (c) 2009, 2010 Ken Cline * @@ -28,9 +22,16 @@ # * USA * # * * # *************************************************************************** -import FreeCADGui +"""Provide the Draft_Snap commands used by the snapping mechanism in Draft.""" +## @package gui_snaps +# \ingroup DRAFT +# \brief Provide the Draft_Snap commands used by the snapping mechanism +# in Draft. + from PySide.QtCore import QT_TRANSLATE_NOOP +import FreeCADGui as Gui + class Draft_Snap_Lock: """Command to activate or deactivate all snap commands.""" @@ -47,12 +48,12 @@ class Draft_Snap_Lock: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "masterbutton"): - FreeCADGui.Snapper.masterbutton.toggle() + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "masterbutton"): + Gui.Snapper.masterbutton.toggle() -FreeCADGui.addCommand('Draft_Snap_Lock', Draft_Snap_Lock()) +Gui.addCommand('Draft_Snap_Lock', Draft_Snap_Lock()) class Draft_Snap_Midpoint: @@ -68,14 +69,14 @@ class Draft_Snap_Midpoint: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonmidpoint": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Midpoint', Draft_Snap_Midpoint()) +Gui.addCommand('Draft_Snap_Midpoint', Draft_Snap_Midpoint()) class Draft_Snap_Perpendicular: @@ -93,14 +94,14 @@ class Draft_Snap_Perpendicular: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonperpendicular": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Perpendicular', Draft_Snap_Perpendicular()) +Gui.addCommand('Draft_Snap_Perpendicular', Draft_Snap_Perpendicular()) class Draft_Snap_Grid: @@ -115,14 +116,14 @@ class Draft_Snap_Grid: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtongrid": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Grid', Draft_Snap_Grid()) +Gui.addCommand('Draft_Snap_Grid', Draft_Snap_Grid()) class Draft_Snap_Intersection: @@ -140,14 +141,14 @@ class Draft_Snap_Intersection: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonintersection": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Intersection', Draft_Snap_Intersection()) +Gui.addCommand('Draft_Snap_Intersection', Draft_Snap_Intersection()) class Draft_Snap_Parallel: @@ -163,14 +164,14 @@ class Draft_Snap_Parallel: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonparallel": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Parallel', Draft_Snap_Parallel()) +Gui.addCommand('Draft_Snap_Parallel', Draft_Snap_Parallel()) class Draft_Snap_Endpoint: @@ -186,14 +187,14 @@ class Draft_Snap_Endpoint: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonendpoint": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Endpoint', Draft_Snap_Endpoint()) +Gui.addCommand('Draft_Snap_Endpoint', Draft_Snap_Endpoint()) class Draft_Snap_Angle: @@ -208,14 +209,14 @@ class Draft_Snap_Angle: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonangle": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Angle', Draft_Snap_Angle()) +Gui.addCommand('Draft_Snap_Angle', Draft_Snap_Angle()) class Draft_Snap_Center: @@ -230,14 +231,14 @@ class Draft_Snap_Center: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtoncenter": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Center', Draft_Snap_Center()) +Gui.addCommand('Draft_Snap_Center', Draft_Snap_Center()) class Draft_Snap_Extension: @@ -253,14 +254,14 @@ class Draft_Snap_Extension: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonextension": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Extension', Draft_Snap_Extension()) +Gui.addCommand('Draft_Snap_Extension', Draft_Snap_Extension()) class Draft_Snap_Near: @@ -275,14 +276,14 @@ class Draft_Snap_Near: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonpassive": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Near', Draft_Snap_Near()) +Gui.addCommand('Draft_Snap_Near', Draft_Snap_Near()) class Draft_Snap_Ortho: @@ -297,14 +298,14 @@ class Draft_Snap_Ortho: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonortho": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Ortho', Draft_Snap_Ortho()) +Gui.addCommand('Draft_Snap_Ortho', Draft_Snap_Ortho()) class Draft_Snap_Special: @@ -320,14 +321,14 @@ class Draft_Snap_Special: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonspecial": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Special', Draft_Snap_Special()) +Gui.addCommand('Draft_Snap_Special', Draft_Snap_Special()) class Draft_Snap_Dimensions: @@ -343,14 +344,14 @@ class Draft_Snap_Dimensions: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonDimensions": b.toggle() -FreeCADGui.addCommand('Draft_Snap_Dimensions', Draft_Snap_Dimensions()) +Gui.addCommand('Draft_Snap_Dimensions', Draft_Snap_Dimensions()) class Draft_Snap_WorkingPlane: @@ -368,11 +369,11 @@ class Draft_Snap_WorkingPlane: def Activated(self): """Execute this when the command is called.""" - if hasattr(FreeCADGui, "Snapper"): - if hasattr(FreeCADGui.Snapper, "toolbarButtons"): - for b in FreeCADGui.Snapper.toolbarButtons: + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "toolbarButtons"): + for b in Gui.Snapper.toolbarButtons: if b.objectName() == "SnapButtonWorkingPlane": b.toggle() -FreeCADGui.addCommand('Draft_Snap_WorkingPlane', Draft_Snap_WorkingPlane()) +Gui.addCommand('Draft_Snap_WorkingPlane', Draft_Snap_WorkingPlane()) From 5a15544465598ed8bf68ac2e3be88d340c276a4f Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 3 Mar 2020 09:12:16 -0600 Subject: [PATCH 28/62] Draft: gui_trackers clean up docstrings and spaces Many small spacing fixes in the code, to improve the Pythonic style according to PEP8. Also add many docstrings in triple quotes. --- src/Mod/Draft/draftguitools/gui_trackers.py | 317 ++++++++++++-------- 1 file changed, 184 insertions(+), 133 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py index 7e5f343b7a..1dfbdd7f0e 100644 --- a/src/Mod/Draft/draftguitools/gui_trackers.py +++ b/src/Mod/Draft/draftguitools/gui_trackers.py @@ -34,6 +34,7 @@ that is, previews, of the real objects that will be created on the 3D view. import math from pivy import coin +import re import FreeCAD import FreeCADGui @@ -76,12 +77,16 @@ class Tracker: ToDo.delay(self._insertSwitch, self.switch) def finalize(self): + """Finish the command by removing the switch.""" ToDo.delay(self._removeSwitch, self.switch) self.switch = None def _insertSwitch(self, switch): - '''insert self.switch into the scene graph. Must not be called - from an event handler (or other scene graph traversal).''' + """Insert self.switch into the scene graph. + + Must not be called + from an event handler (or other scene graph traversal). + """ sg = Draft.get3DView().getSceneGraph() if self.ontop: sg.insertChild(switch, 0) @@ -89,31 +94,40 @@ class Tracker: sg.addChild(switch) def _removeSwitch(self, switch): - '''remove self.switch from the scene graph. As with _insertSwitch, - must not be called during scene graph traversal).''' + """Remove self.switch from the scene graph. + + As with _insertSwitch, + must not be called during scene graph traversal). + """ sg = Draft.get3DView().getSceneGraph() if sg.findChild(switch) >= 0: sg.removeChild(switch) def on(self): + """Set the visibility to True.""" self.switch.whichChild = 0 self.Visible = True def off(self): + """Set the visibility to False.""" self.switch.whichChild = -1 self.Visible = False def lowerTracker(self): - '''lowers the tracker to the bottom of the scenegraph, so - it doesn't obscure the other objects''' + """Lower the tracker to the bottom of the scenegraph. + + So it doesn't obscure the other objects. + """ if self.switch: sg = Draft.get3DView().getSceneGraph() sg.removeChild(self.switch) sg.addChild(self.switch) def raiseTracker(self): - '''raises the tracker to the top of the scenegraph, so - it obscures the other objects''' + """Raise the tracker to the top of the scenegraph. + + So it obscures the other objects. + """ if self.switch: sg = Draft.get3DView().getSceneGraph() sg.removeChild(self.switch) @@ -126,100 +140,120 @@ class snapTracker(Tracker): def __init__(self): color = coin.SoBaseColor() color.rgb = FreeCADGui.draftToolBar.getDefaultColor("snap") - self.marker = coin.SoMarkerSet() # this is the marker symbol + self.marker = coin.SoMarkerSet() # this is the marker symbol self.marker.markerIndex = FreeCADGui.getMarkerIndex("", 9) - self.coords = coin.SoCoordinate3() # this is the coordinate - self.coords.point.setValue((0,0,0)) + self.coords = coin.SoCoordinate3() # this is the coordinate + self.coords.point.setValue((0, 0, 0)) node = coin.SoAnnotation() node.addChild(self.coords) node.addChild(color) node.addChild(self.marker) - Tracker.__init__(self,children=[node],name="snapTracker") + Tracker.__init__(self, children=[node], name="snapTracker") - def setMarker(self,style): + def setMarker(self, style): + """Set the marker index.""" self.marker.markerIndex = FreeCADGui.getMarkerIndex(style, 9) - def setCoords(self,point): - self.coords.point.setValue((point.x,point.y,point.z)) - - def addCoords(self,point): + def setCoords(self, point): + """Set the coordinates to the point.""" + self.coords.point.setValue((point.x, point.y, point.z)) + + def addCoords(self, point): + """Add the point to the current point.""" l = self.coords.point.getValues() - l.append(coin.SbVec3f(point.x,point.y,point.z)) + l.append(coin.SbVec3f(point.x, point.y, point.z)) self.coords.point.setValues(l) - + def clear(self): + """Delete the values of the point.""" self.coords.point.deleteValues(0) - + class lineTracker(Tracker): """A Line tracker, used by the tools that need to draw temporary lines""" - def __init__(self,dotted=False,scolor=None,swidth=None,ontop=False): + + def __init__(self, dotted=False, scolor=None, swidth=None, ontop=False): line = coin.SoLineSet() line.numVertices.setValue(2) - self.coords = coin.SoCoordinate3() # this is the coordinate - self.coords.point.setValues(0,2,[[0,0,0],[1,0,0]]) - Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line],ontop,name="lineTracker") + self.coords = coin.SoCoordinate3() # this is the coordinate + self.coords.point.setValues(0, 2, [[0, 0, 0], [1, 0, 0]]) + Tracker.__init__(self, dotted, scolor, swidth, + [self.coords, line], + ontop, name="lineTracker") - def p1(self,point=None): - """sets or gets the first point of the line""" + def p1(self, point=None): + """Set or get the first point of the line.""" if point: if self.coords.point.getValues()[0].getValue() != tuple(point): - self.coords.point.set1Value(0,point.x,point.y,point.z) + self.coords.point.set1Value(0, point.x, point.y, point.z) else: return Vector(self.coords.point.getValues()[0].getValue()) - def p2(self,point=None): - """sets or gets the second point of the line""" + def p2(self, point=None): + """Set or get the second point of the line.""" if point: if self.coords.point.getValues()[-1].getValue() != tuple(point): - self.coords.point.set1Value(1,point.x,point.y,point.z) + self.coords.point.set1Value(1, point.x, point.y, point.z) else: return Vector(self.coords.point.getValues()[-1].getValue()) - + def getLength(self): - """returns the length of the line""" + """Return the length of the line.""" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[-1].getValue()) return (p2.sub(p1)).Length + class rectangleTracker(Tracker): - """A Rectangle tracker, used by the rectangle tool""" - def __init__(self,dotted=False,scolor=None,swidth=None,face=False): - self.origin = Vector(0,0,0) + """A Rectangle tracker, used by the rectangle tool.""" + + def __init__(self, dotted=False, scolor=None, swidth=None, face=False): + self.origin = Vector(0, 0, 0) line = coin.SoLineSet() line.numVertices.setValue(5) - self.coords = coin.SoCoordinate3() # this is the coordinate - self.coords.point.setValues(0,50,[[0,0,0],[2,0,0],[2,2,0],[0,2,0],[0,0,0]]) + self.coords = coin.SoCoordinate3() # this is the coordinate + self.coords.point.setValues(0, 50, [[0, 0, 0], + [2, 0, 0], + [2, 2, 0], + [0, 2, 0], + [0, 0, 0]]) if face: m1 = coin.SoMaterial() m1.transparency.setValue(0.5) - m1.diffuseColor.setValue([0.5,0.5,1.0]) + m1.diffuseColor.setValue([0.5, 0.5, 1.0]) f = coin.SoIndexedFaceSet() - f.coordIndex.setValues([0,1,2,3]) - Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line,m1,f],name="rectangleTracker") + f.coordIndex.setValues([0, 1, 2, 3]) + Tracker.__init__(self, dotted, scolor, swidth, + [self.coords, line, m1, f], + name="rectangleTracker") else: - Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line],name="rectangleTracker") + Tracker.__init__(self, dotted, scolor, swidth, + [self.coords, line], + name="rectangleTracker") self.u = FreeCAD.DraftWorkingPlane.u self.v = FreeCAD.DraftWorkingPlane.v - def setorigin(self,point): - """sets the base point of the rectangle""" - self.coords.point.set1Value(0,point.x,point.y,point.z) - self.coords.point.set1Value(4,point.x,point.y,point.z) + def setorigin(self, point): + """Set the base point of the rectangle.""" + self.coords.point.set1Value(0, point.x, point.y, point.z) + self.coords.point.set1Value(4, point.x, point.y, point.z) self.origin = point - def update(self,point): - """sets the opposite (diagonal) point of the rectangle""" + def update(self, point): + """Set the opposite (diagonal) point of the rectangle.""" diagonal = point.sub(self.origin) - inpoint1 = self.origin.add(DraftVecUtils.project(diagonal,self.v)) - inpoint2 = self.origin.add(DraftVecUtils.project(diagonal,self.u)) - self.coords.point.set1Value(1,inpoint1.x,inpoint1.y,inpoint1.z) - self.coords.point.set1Value(2,point.x,point.y,point.z) - self.coords.point.set1Value(3,inpoint2.x,inpoint2.y,inpoint2.z) + inpoint1 = self.origin.add(DraftVecUtils.project(diagonal, self.v)) + inpoint2 = self.origin.add(DraftVecUtils.project(diagonal, self.u)) + self.coords.point.set1Value(1, inpoint1.x, inpoint1.y, inpoint1.z) + self.coords.point.set1Value(2, point.x, point.y, point.z) + self.coords.point.set1Value(3, inpoint2.x, inpoint2.y, inpoint2.z) - def setPlane(self,u,v=None): - '''sets given (u,v) vectors as working plane. You can give only u - and v will be deduced automatically given current workplane''' + def setPlane(self, u, v=None): + """Set given (u,v) vectors as working plane. + + You can give only `u` and `v` will be deduced automatically + given the current working plane. + """ self.u = u if v: self.v = v @@ -227,64 +261,73 @@ class rectangleTracker(Tracker): norm = FreeCAD.DraftWorkingPlane.u.cross(FreeCAD.DraftWorkingPlane.v) self.v = self.u.cross(norm) - def p1(self,point=None): - """sets or gets the base point of the rectangle""" + def p1(self, point=None): + """Set or get the base point of the rectangle.""" if point: self.setorigin(point) else: return Vector(self.coords.point.getValues()[0].getValue()) def p2(self): - """gets the second point (on u axis) of the rectangle""" + """Get the second point (on u axis) of the rectangle.""" return Vector(self.coords.point.getValues()[3].getValue()) - def p3(self,point=None): - """sets or gets the opposite (diagonal) point of the rectangle""" + def p3(self, point=None): + """Set or get the opposite (diagonal) point of the rectangle.""" if point: self.update(point) else: return Vector(self.coords.point.getValues()[2].getValue()) def p4(self): - """gets the fourth point (on v axis) of the rectangle""" + """Get the fourth point (on v axis) of the rectangle.""" return Vector(self.coords.point.getValues()[1].getValue()) - + def getSize(self): - """returns (length,width) of the rectangle""" + """Return (length, width) of the rectangle.""" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[2].getValue()) diag = p2.sub(p1) - return ((DraftVecUtils.project(diag,self.u)).Length,(DraftVecUtils.project(diag,self.v)).Length) + return ((DraftVecUtils.project(diag, self.u)).Length, + (DraftVecUtils.project(diag, self.v)).Length) def getNormal(self): - """returns the normal of the rectangle""" + """Return the normal of the rectangle.""" return (self.u.cross(self.v)).normalize() - - def isInside(self,point): - """returns True if the given point is inside the rectangle""" + + def isInside(self, point): + """Return True if the given point is inside the rectangle.""" vp = point.sub(self.p1()) uv = self.p2().sub(self.p1()) vv = self.p4().sub(self.p1()) - uvp = DraftVecUtils.project(vp,uv) - vvp = DraftVecUtils.project(vp,vv) + uvp = DraftVecUtils.project(vp, uv) + vvp = DraftVecUtils.project(vp, vv) if uvp.getAngle(uv) < 1: if vvp.getAngle(vv) < 1: if uvp.Length <= uv.Length: if vvp.Length <= vv.Length: return True return False - + + class dimTracker(Tracker): - """A Dimension tracker, used by the dimension tool""" - def __init__(self,dotted=False,scolor=None,swidth=None): + """A Dimension tracker, used by the dimension tool.""" + + def __init__(self, dotted=False, scolor=None, swidth=None): line = coin.SoLineSet() line.numVertices.setValue(4) - self.coords = coin.SoCoordinate3() # this is the coordinate - self.coords.point.setValues(0,4,[[0,0,0],[0,0,0],[0,0,0],[0,0,0]]) - Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line],name="dimTracker") + self.coords = coin.SoCoordinate3() # this is the coordinate + self.coords.point.setValues(0, 4, + [[0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0]]) + Tracker.__init__(self, dotted, scolor, swidth, + [self.coords, line], name="dimTracker") self.p1 = self.p2 = self.p3 = None - def update(self,pts): + def update(self, pts): + """Update the points and calculate.""" if not pts: return elif len(pts) == 1: @@ -295,50 +338,62 @@ class dimTracker(Tracker): if len(pts) > 2: self.p3 = pts[2] self.calc() - + def calc(self): + """Calculate the new points from p1 and p2.""" import Part - if (self.p1 != None) and (self.p2 != None): - points = [DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True),\ - DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True)] - if self.p3 != None: + if (self.p1 is not None) and (self.p2 is not None): + points = [DraftVecUtils.tup(self.p1, True), + DraftVecUtils.tup(self.p2, True), + DraftVecUtils.tup(self.p1, True), + DraftVecUtils.tup(self.p2, True)] + if self.p3 is not None: p1 = self.p1 p4 = self.p2 - if DraftVecUtils.equals(p1,p4): + if DraftVecUtils.equals(p1, p4): proj = None else: - base = Part.LineSegment(p1,p4).toShape() - proj = DraftGeomUtils.findDistance(self.p3,base) + base = Part.LineSegment(p1, p4).toShape() + proj = DraftGeomUtils.findDistance(self.p3, base) if not proj: p2 = p1 p3 = p4 else: p2 = p1.add(proj.negative()) p3 = p4.add(proj.negative()) - points = [DraftVecUtils.tup(p1),DraftVecUtils.tup(p2),DraftVecUtils.tup(p3),DraftVecUtils.tup(p4)] - self.coords.point.setValues(0,4,points) + points = [DraftVecUtils.tup(p1), + DraftVecUtils.tup(p2), + DraftVecUtils.tup(p3), + DraftVecUtils.tup(p4)] + self.coords.point.setValues(0, 4, points) + class bsplineTracker(Tracker): - """A bspline tracker""" - def __init__(self,dotted=False,scolor=None,swidth=None,points = []): + """A bspline tracker.""" + + def __init__(self, dotted=False, scolor=None, swidth=None, points=[]): self.bspline = None self.points = points self.trans = coin.SoTransform() self.sep = coin.SoSeparator() self.recompute() - Tracker.__init__(self,dotted,scolor,swidth,[self.trans,self.sep],name="bsplineTracker") - + Tracker.__init__(self, dotted, scolor, swidth, + [self.trans, self.sep], name="bsplineTracker") + def update(self, points): + """Update the points and recompute.""" self.points = points self.recompute() - + def recompute(self): - if (len(self.points) >= 2): - if self.bspline: self.sep.removeChild(self.bspline) + """Recompute the tracker.""" + if len(self.points) >= 2: + if self.bspline: + self.sep.removeChild(self.bspline) self.bspline = None c = Part.BSplineCurve() # DNC: allows to close the curve by placing ends close to each other - if ( len(self.points) >= 3 ) and ( (self.points[0] - self.points[-1]).Length < Draft.tolerance() ): + if len(self.points) >= 3 and ( (self.points[0] - self.points[-1]).Length < Draft.tolerance() ): # YVH: Added a try to bypass some hazardous situations try: c.interpolate(self.points[:-1], True) @@ -350,26 +405,25 @@ class bsplineTracker(Tracker): except Part.OCCError: pass c = c.toShape() - buf=c.writeInventor(2,0.01) - #fp=open("spline.iv","w") - #fp.write(buf) - #fp.close() + buf = c.writeInventor(2, 0.01) + # fp = open("spline.iv", "w") + # fp.write(buf) + # fp.close() try: ivin = coin.SoInput() ivin.setBuffer(buf) ivob = coin.SoDB.readAll(ivin) - except: + except Exception: # workaround for pivy SoInput.setBuffer() bug - import re - buf = buf.replace("\n","") - pts = re.findall("point \[(.*?)\]",buf)[0] + buf = buf.replace("\n", "") + pts = re.findall("point \[(.*?)\]", buf)[0] pts = pts.split(",") pc = [] for p in pts: v = p.strip().split() - pc.append([float(v[0]),float(v[1]),float(v[2])]) + pc.append([float(v[0]), float(v[1]), float(v[2])]) coords = coin.SoCoordinate3() - coords.point.setValues(0,len(pc),pc) + coords.point.setValues(0, len(pc), pc) line = coin.SoLineSet() line.numVertices.setValue(-1) self.bspline = coin.SoSeparator() @@ -384,73 +438,70 @@ class bsplineTracker(Tracker): self.sep.addChild(self.bspline) else: FreeCAD.Console.PrintWarning("bsplineTracker.recompute() failed to read-in Inventor string\n") -####################################### + + class bezcurveTracker(Tracker): - """A bezcurve tracker""" - def __init__(self,dotted=False,scolor=None,swidth=None,points = []): + """A bezcurve tracker.""" + + def __init__(self, dotted=False, scolor=None, swidth=None, points=[]): self.bezcurve = None self.points = points self.degree = None self.trans = coin.SoTransform() self.sep = coin.SoSeparator() self.recompute() - Tracker.__init__(self,dotted,scolor,swidth,[self.trans,self.sep],name="bezcurveTracker") - + Tracker.__init__(self, dotted, scolor, swidth, + [self.trans, self.sep], name="bezcurveTracker") + def update(self, points, degree=None): + """Update the points and recompute.""" self.points = points if degree: self.degree = degree self.recompute() - + def recompute(self): - + """Recompute the tracker.""" if self.bezcurve: for seg in self.bezcurve: self.sep.removeChild(seg) seg = None - + self.bezcurve = [] - + if (len(self.points) >= 2): - if self.degree: - - poles=self.points[1:] - + poles = self.points[1:] segpoleslst = [poles[x:x+self.degree] for x in range(0, len(poles), (self.degree or 1))] else: segpoleslst = [self.points] - - startpoint=self.points[0] + startpoint = self.points[0] - for segpoles in segpoleslst: - c = Part.BezierCurve() #last segment may have lower degree + c = Part.BezierCurve() # last segment may have lower degree c.increase(len(segpoles)) - c.setPoles([startpoint]+segpoles) + c.setPoles([startpoint] + segpoles) c = c.toShape() startpoint = segpoles[-1] - - buf=c.writeInventor(2,0.01) - #fp=open("spline.iv","w") - #fp.write(buf) - #fp.close() + buf = c.writeInventor(2, 0.01) + # fp=open("spline.iv", "w") + # fp.write(buf) + # fp.close() try: ivin = coin.SoInput() ivin.setBuffer(buf) ivob = coin.SoDB.readAll(ivin) - except: + except Exception: # workaround for pivy SoInput.setBuffer() bug - import re buf = buf.replace("\n","") - pts = re.findall("point \[(.*?)\]",buf)[0] + pts = re.findall("point \[(.*?)\]", buf)[0] pts = pts.split(",") pc = [] for p in pts: v = p.strip().split() - pc.append([float(v[0]),float(v[1]),float(v[2])]) + pc.append([float(v[0]), float(v[1]), float(v[2])]) coords = coin.SoCoordinate3() - coords.point.setValues(0,len(pc),pc) + coords.point.setValues(0, len(pc), pc) line = coin.SoLineSet() line.numVertices.setValue(-1) bezcurveseg = coin.SoSeparator() From ea1773c7d6fb6118efb04c17b32633f0de1114d3 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 3 Mar 2020 18:22:58 -0600 Subject: [PATCH 29/62] Draft: gui_trackers clean up docstrings and spaces (2) Many small spacing fixes in the code, to improve the Pythonic style according to PEP8. Also add many docstrings in triple quotes. --- src/Mod/Draft/draftguitools/gui_trackers.py | 303 +++++++++++--------- 1 file changed, 171 insertions(+), 132 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py index 1dfbdd7f0e..50d628b589 100644 --- a/src/Mod/Draft/draftguitools/gui_trackers.py +++ b/src/Mod/Draft/draftguitools/gui_trackers.py @@ -42,6 +42,7 @@ import Draft import DraftVecUtils from FreeCAD import Vector from draftutils.todo import ToDo +from draftutils.messages import _msg __title__ = "FreeCAD Draft Trackers" __author__ = "Yorik van Havre" @@ -518,16 +519,17 @@ class bezcurveTracker(Tracker): FreeCAD.Console.PrintWarning("bezcurveTracker.recompute() failed to read-in Inventor string\n") self.bezcurve.append(bezcurveseg) - -####################################### + class arcTracker(Tracker): - """An arc tracker""" - def __init__(self,dotted=False,scolor=None,swidth=None,start=0,end=math.pi*2,normal=None): + """An arc tracker.""" + + def __init__(self, dotted=False, scolor=None, swidth=None, + start=0, end=math.pi*2, normal=None): self.circle = None self.startangle = math.degrees(start) self.endangle = math.degrees(end) self.trans = coin.SoTransform() - self.trans.translation.setValue([0,0,0]) + self.trans.translation.setValue([0, 0, 0]) self.sep = coin.SoSeparator() self.autoinvert = True if normal: @@ -536,72 +538,74 @@ class arcTracker(Tracker): self.normal = FreeCAD.DraftWorkingPlane.axis self.basevector = self.getDeviation() self.recompute() - Tracker.__init__(self,dotted,scolor,swidth,[self.trans, self.sep],name="arcTracker") - + Tracker.__init__(self, dotted, scolor, swidth, + [self.trans, self.sep], name="arcTracker") + def getDeviation(self): - """returns a deviation vector that represents the base of the circle""" + """Return a deviation vector that represents the base of the circle.""" import Part - c = Part.makeCircle(1,Vector(0,0,0),self.normal) + c = Part.makeCircle(1, Vector(0, 0, 0), self.normal) return c.Vertexes[0].Point - def setCenter(self,cen): - """sets the center point""" - self.trans.translation.setValue([cen.x,cen.y,cen.z]) + def setCenter(self, cen): + """Set the center point.""" + self.trans.translation.setValue([cen.x, cen.y, cen.z]) - def setRadius(self,rad): - """sets the radius""" - self.trans.scaleFactor.setValue([rad,rad,rad]) + def setRadius(self, rad): + """Set the radius.""" + self.trans.scaleFactor.setValue([rad, rad, rad]) def getRadius(self): - """returns the current radius""" + """Return the current radius.""" return self.trans.scaleFactor.getValue()[0] - def setStartAngle(self,ang): - """sets the start angle""" + def setStartAngle(self, ang): + """Set the start angle.""" self.startangle = math.degrees(ang) self.recompute() - def setEndAngle(self,ang): - """sets the end angle""" + def setEndAngle(self, ang): + """Set the end angle.""" self.endangle = math.degrees(ang) self.recompute() - def getAngle(self,pt): - """returns the angle of a given vector in radians""" + def getAngle(self, pt): + """Return the angle of a given vector in radians.""" c = self.trans.translation.getValue() - center = Vector(c[0],c[1],c[2]) + center = Vector(c[0], c[1], c[2]) rad = pt.sub(center) - a = DraftVecUtils.angle(rad,self.basevector,self.normal) - #print(a) - return(a) + a = DraftVecUtils.angle(rad, self.basevector, self.normal) + # print(a) + return a def getAngles(self): - """returns the start and end angles in degrees""" - return(self.startangle,self.endangle) - - def setStartPoint(self,pt): - """sets the start angle from a point""" + """Return the start and end angles in degrees.""" + return(self.startangle, self.endangle) + + def setStartPoint(self, pt): + """Set the start angle from a point.""" self.setStartAngle(-self.getAngle(pt)) - def setEndPoint(self,pt): - """sets the end angle from a point""" + def setEndPoint(self, pt): + """Set the end angle from a point.""" self.setEndAngle(-self.getAngle(pt)) - - def setApertureAngle(self,ang): - """sets the end angle by giving the aperture angle""" + + def setApertureAngle(self, ang): + """Set the end angle by giving the aperture angle.""" ap = math.degrees(ang) self.endangle = self.startangle + ap self.recompute() - def setBy3Points(self,p1,p2,p3): - """sets the arc by three points""" + def setBy3Points(self, p1, p2, p3): + """Set the arc by three points.""" import Part try: - arc=Part.ArcOfCircle(p1,p2,p3) - except: return - e=arc.toShape() + arc = Part.ArcOfCircle(p1, p2, p3) + except Exception: + return + e = arc.toShape() self.autoinvert = False - self.normal = e.Curve.Axis.negative() # axis is always in wrong direction + self.normal = e.Curve.Axis.negative() # axis is always in wrong direction self.basevector = self.getDeviation() self.setCenter(e.Curve.Center) self.setRadius(e.Curve.Radius) @@ -609,30 +613,33 @@ class arcTracker(Tracker): self.setEndPoint(p3) def recompute(self): - import Part,re - if self.circle: + """Recompute the tracker.""" + import Part + if self.circle: self.sep.removeChild(self.circle) self.circle = None if (self.endangle < self.startangle) or not self.autoinvert: - c = Part.makeCircle(1,Vector(0,0,0),self.normal,self.endangle,self.startangle) + c = Part.makeCircle(1, Vector(0, 0, 0), + self.normal, self.endangle, self.startangle) else: - c = Part.makeCircle(1,Vector(0,0,0),self.normal,self.startangle,self.endangle) - buf=c.writeInventor(2,0.01) + c = Part.makeCircle(1, Vector(0, 0, 0), + self.normal, self.startangle, self.endangle) + buf = c.writeInventor(2, 0.01) try: ivin = coin.SoInput() ivin.setBuffer(buf) ivob = coin.SoDB.readAll(ivin) - except: + except Exception: # workaround for pivy SoInput.setBuffer() bug - buf = buf.replace("\n","") - pts = re.findall("point \[(.*?)\]",buf)[0] + buf = buf.replace("\n", "") + pts = re.findall("point \[(.*?)\]", buf)[0] pts = pts.split(",") pc = [] for p in pts: v = p.strip().split() - pc.append([float(v[0]),float(v[1]),float(v[2])]) + pc.append([float(v[0]), float(v[1]), float(v[2])]) coords = coin.SoCoordinate3() - coords.point.setValues(0,len(pc),pc) + coords.point.setValues(0, len(pc), pc) line = coin.SoLineSet() line.numVertices.setValue(-1) self.circle = coin.SoSeparator() @@ -650,14 +657,17 @@ class arcTracker(Tracker): class ghostTracker(Tracker): - '''A Ghost tracker, that allows to copy whole object representations. - You can pass it an object or a list of objects, or a shape.''' - def __init__(self,sel,dotted=False,scolor=None,swidth=None): + """A Ghost tracker, that allows to copy whole object representations. + + You can pass it an object or a list of objects, or a shape. + """ + + def __init__(self, sel, dotted=False, scolor=None, swidth=None): self.trans = coin.SoTransform() - self.trans.translation.setValue([0,0,0]) + self.trans.translation.setValue([0, 0, 0]) self.children = [self.trans] rootsep = coin.SoSeparator() - if not isinstance(sel,list): + if not isinstance(sel, list): sel = [sel] for obj in sel: import Part @@ -665,10 +675,10 @@ class ghostTracker(Tracker): rootsep.addChild(self.getNode(obj)) else: self.coords = coin.SoCoordinate3() - self.coords.point.setValue((obj.X,obj.Y,obj.Z)) + self.coords.point.setValue((obj.X, obj.Y, obj.Z)) color = coin.SoBaseColor() color.rgb = FreeCADGui.draftToolBar.getDefaultColor("snap") - self.marker = coin.SoMarkerSet() # this is the marker symbol + self.marker = coin.SoMarkerSet() # this is the marker symbol self.marker.markerIndex = FreeCADGui.getMarkerIndex("quad", 9) node = coin.SoAnnotation() selnode = coin.SoSeparator() @@ -677,63 +687,67 @@ class ghostTracker(Tracker): selnode.addChild(self.marker) node.addChild(selnode) rootsep.addChild(node) - self.children.append(rootsep) - Tracker.__init__(self,dotted,scolor,swidth,children=self.children,name="ghostTracker") + self.children.append(rootsep) + Tracker.__init__(self, dotted, scolor, swidth, + children=self.children, name="ghostTracker") - def update(self,obj): - """recreates the ghost from a new object""" + def update(self, obj): + """Recreate the ghost from a new object.""" obj.ViewObject.show() self.finalize() sep = self.getNode(obj) - Tracker.__init__(self,children=[self.sep]) + Tracker.__init__(self, children=[self.sep]) self.on() obj.ViewObject.hide() - def move(self,delta): - """moves the ghost to a given position, relative from its start position""" - self.trans.translation.setValue([delta.x,delta.y,delta.z]) + def move(self, delta): + """Move the ghost to a given position. - def rotate(self,axis,angle): - """rotates the ghost of a given angle""" - self.trans.rotation.setValue(coin.SbVec3f(DraftVecUtils.tup(axis)),angle) + Relative from its start position. + """ + self.trans.translation.setValue([delta.x, delta.y, delta.z]) - def center(self,point): - """sets the rotation/scale center of the ghost""" - self.trans.center.setValue(point.x,point.y,point.z) + def rotate(self, axis, angle): + """Rotate the ghost of a given angle.""" + self.trans.rotation.setValue(coin.SbVec3f(DraftVecUtils.tup(axis)), angle) - def scale(self,delta): - """scales the ghost by the given factor""" - self.trans.scaleFactor.setValue([delta.x,delta.y,delta.z]) + def center(self, point): + """Set the rotation/scale center of the ghost.""" + self.trans.center.setValue(point.x, point.y, point.z) - def getNode(self,obj): - """returns a coin node representing the given object""" + def scale(self, delta): + """Scale the ghost by the given factor.""" + self.trans.scaleFactor.setValue([delta.x, delta.y, delta.z]) + + def getNode(self, obj): + """Return a coin node representing the given object.""" import Part - if isinstance(obj,Part.Shape): + if isinstance(obj, Part.Shape): return self.getNodeLight(obj) elif obj.isDerivedFrom("Part::Feature"): return self.getNodeFull(obj) else: return self.getNodeFull(obj) - def getNodeFull(self,obj): - """gets a coin node which is a full copy of the current representation""" + def getNodeFull(self, obj): + """Get a coin node which is a copy of the current representation.""" sep = coin.SoSeparator() try: sep.addChild(obj.ViewObject.RootNode.copy()) # add Part container offset - if hasattr(obj,"getGlobalPlacement"): + if hasattr(obj, "getGlobalPlacement"): if obj.Placement != obj.getGlobalPlacement(): if sep.getChild(0).getNumChildren() > 0: if isinstance(sep.getChild(0).getChild(0),coin.SoTransform): gpl = obj.getGlobalPlacement() sep.getChild(0).getChild(0).translation.setValue(tuple(gpl.Base)) sep.getChild(0).getChild(0).rotation.setValue(gpl.Rotation.Q) - except: - print("ghostTracker: Error retrieving coin node (full)") + except Exception: + _msg("ghostTracker: Error retrieving coin node (full)") return sep - def getNodeLight(self,shape): - """extract a lighter version directly from a shape""" + def getNodeLight(self, shape): + """Extract a lighter version directly from a shape.""" # error-prone sep = coin.SoSeparator() try: @@ -743,43 +757,48 @@ class ghostTracker(Tracker): # only add wireframe or full node? sep.addChild(coinobj.getChildren()[1]) # sep.addChild(coinobj) - except: - print("ghostTracker: Error retrieving coin node (light)") + except Exception: + _msg("ghostTracker: Error retrieving coin node (light)") return sep - + def getMatrix(self): + """Get matrix of the active view.""" r = FreeCADGui.ActiveDocument.ActiveView.getViewer().getSoRenderManager().getViewportRegion() v = coin.SoGetMatrixAction(r) m = self.trans.getMatrix(v) if m: m = m.getValue() - return FreeCAD.Matrix(m[0][0],m[0][1],m[0][2],m[0][3], - m[1][0],m[1][1],m[1][2],m[1][3], - m[2][0],m[2][1],m[2][2],m[2][3], - m[3][0],m[3][1],m[3][2],m[3][3]) + return FreeCAD.Matrix(m[0][0], m[0][1], m[0][2], m[0][3], + m[1][0], m[1][1], m[1][2], m[1][3], + m[2][0], m[2][1], m[2][2], m[2][3], + m[3][0], m[3][1], m[3][2], m[3][3]) else: return FreeCAD.Matrix() - - def setMatrix(self,matrix): - m = coin.SbMatrix(matrix.A11,matrix.A12,matrix.A13,matrix.A14, - matrix.A21,matrix.A22,matrix.A23,matrix.A24, - matrix.A31,matrix.A32,matrix.A33,matrix.A34, - matrix.A41,matrix.A42,matrix.A43,matrix.A44) + + def setMatrix(self, matrix): + """Set the transformation matrix.""" + m = coin.SbMatrix(matrix.A11, matrix.A12, matrix.A13, matrix.A14, + matrix.A21, matrix.A22, matrix.A23, matrix.A24, + matrix.A31, matrix.A32, matrix.A33, matrix.A34, + matrix.A41, matrix.A42, matrix.A43, matrix.A44) self.trans.setMatrix(m) + class editTracker(Tracker): - """A node edit tracker""" - def __init__(self,pos=Vector(0,0,0),name=None,idx=0,objcol=None,\ - marker=FreeCADGui.getMarkerIndex("quad", 9),inactive=False): + """A node edit tracker.""" + + def __init__(self, pos=Vector(0, 0, 0), name=None, idx=0, objcol=None, + marker=FreeCADGui.getMarkerIndex("quad", 9), + inactive=False): self.color = coin.SoBaseColor() if objcol: self.color.rgb = objcol[:3] else: self.color.rgb = FreeCADGui.draftToolBar.getDefaultColor("snap") - self.marker = coin.SoMarkerSet() # this is the marker symbol + self.marker = coin.SoMarkerSet() # this is the marker symbol self.marker.markerIndex = marker - self.coords = coin.SoCoordinate3() # this is the coordinate - self.coords.point.setValue((pos.x,pos.y,pos.z)) + self.coords = coin.SoCoordinate3() # this is the coordinate + self.coords.point.setValue((pos.x, pos.y, pos.z)) if inactive: self.selnode = coin.SoSeparator() else: @@ -788,72 +807,89 @@ class editTracker(Tracker): self.selnode.useNewSelection = False self.selnode.documentName.setValue(FreeCAD.ActiveDocument.Name) self.selnode.objectName.setValue(name) - self.selnode.subElementName.setValue("EditNode"+str(idx)) + self.selnode.subElementName.setValue("EditNode" + str(idx)) node = coin.SoAnnotation() self.selnode.addChild(self.coords) self.selnode.addChild(self.color) self.selnode.addChild(self.marker) node.addChild(self.selnode) ontop = not inactive - Tracker.__init__(self,children=[node],ontop=ontop,name="editTracker") + Tracker.__init__(self, children=[node], + ontop=ontop, name="editTracker") self.on() - def set(self,pos): - self.coords.point.setValue((pos.x,pos.y,pos.z)) + def set(self, pos): + """Set the point to the position.""" + self.coords.point.setValue((pos.x, pos.y, pos.z)) def get(self): + """Get a vector from the point.""" p = self.coords.point.getValues()[0] - return Vector(p[0],p[1],p[2]) + return Vector(p[0], p[1], p[2]) def get_doc_name(self): + """Get the document name.""" return str(self.selnode.documentName.getValue()) def get_obj_name(self): + """Get the object name.""" return str(self.selnode.objectName.getValue()) def get_subelement_name(self): + """Get the subelement name.""" return str(self.selnode.subElementName.getValue()) def get_subelement_index(self): + """Get the subelement index.""" subElement = self.get_subelement_name() idx = int(subElement[8:]) return idx - def move(self,delta): + def move(self, delta): + """Get the point and add a delta, and set the new point.""" self.set(self.get().add(delta)) - def setColor(self,color): + def setColor(self, color): + """Set the color.""" if color: self.color.rgb = color else: self.color.rgb = FreeCADGui.draftToolBar.getDefaultColor("snap") + class PlaneTracker(Tracker): - """A working plane tracker""" + """A working plane tracker.""" + def __init__(self): # getting screen distance - p1 = Draft.get3DView().getPoint((100,100)) - p2 = Draft.get3DView().getPoint((110,100)) - bl = (p2.sub(p1)).Length * (Draft.getParam("snapRange", 8)/2) + p1 = Draft.get3DView().getPoint((100, 100)) + p2 = Draft.get3DView().getPoint((110, 100)) + bl = (p2.sub(p1)).Length * (Draft.getParam("snapRange", 8)/2.0) pick = coin.SoPickStyle() pick.style.setValue(coin.SoPickStyle.UNPICKABLE) self.trans = coin.SoTransform() - self.trans.translation.setValue([0,0,0]) + self.trans.translation.setValue([0, 0, 0]) m1 = coin.SoMaterial() m1.transparency.setValue(0.8) - m1.diffuseColor.setValue([0.4,0.4,0.6]) + m1.diffuseColor.setValue([0.4, 0.4, 0.6]) c1 = coin.SoCoordinate3() - c1.point.setValues([[-bl,-bl,0],[bl,-bl,0],[bl,bl,0],[-bl,bl,0]]) + c1.point.setValues([[-bl, -bl, 0], + [bl, -bl, 0], + [bl, bl, 0], + [-bl, bl, 0]]) f = coin.SoIndexedFaceSet() - f.coordIndex.setValues([0,1,2,3]) + f.coordIndex.setValues([0, 1, 2, 3]) m2 = coin.SoMaterial() m2.transparency.setValue(0.7) - m2.diffuseColor.setValue([0.2,0.2,0.3]) + m2.diffuseColor.setValue([0.2, 0.2, 0.3]) c2 = coin.SoCoordinate3() - c2.point.setValues([[0,bl,0],[0,0,0],[bl,0,0],[-.05*bl,.95*bl,0],[0,bl,0], - [.05*bl,.95*bl,0],[.95*bl,.05*bl,0],[bl,0,0],[.95*bl,-.05*bl,0]]) + c2.point.setValues([[0, bl, 0], [0, 0, 0], + [bl, 0, 0], [-0.05*bl, 0.95*bl, 0], + [0, bl, 0], [0.05*bl, 0.95*bl, 0], + [0.95*bl, 0.05*bl, 0], [bl, 0, 0], + [0.95*bl, -0.05*bl, 0]]) l = coin.SoLineSet() - l.numVertices.setValues([3,3,3]) + l.numVertices.setValues([3, 3, 3]) s = coin.SoSeparator() s.addChild(pick) s.addChild(self.trans) @@ -863,21 +899,24 @@ class PlaneTracker(Tracker): s.addChild(m2) s.addChild(c2) s.addChild(l) - Tracker.__init__(self,children=[s],name="planeTracker") + Tracker.__init__(self, children=[s], name="planeTracker") - def set(self,pos=None): - if pos: + def set(self, pos=None): + """Set the translation to the position.""" + if pos: Q = FreeCAD.DraftWorkingPlane.getRotation().Rotation.Q else: plm = FreeCAD.DraftWorkingPlane.getPlacement() Q = plm.Rotation.Q pos = plm.Base - self.trans.translation.setValue([pos.x,pos.y,pos.z]) - self.trans.rotation.setValue([Q[0],Q[1],Q[2],Q[3]]) + self.trans.translation.setValue([pos.x, pos.y, pos.z]) + self.trans.rotation.setValue([Q[0], Q[1], Q[2], Q[3]]) self.on() - -class wireTracker(Tracker): - """A wire tracker""" + + +class wireTracker(Tracker): + """A wire tracker.""" + def __init__(self,wire): self.line = coin.SoLineSet() self.closed = DraftGeomUtils.isReallyClosed(wire) From 5f5c86dd190fa5c64e18d7956d6716547978f1d6 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 3 Mar 2020 18:52:56 -0600 Subject: [PATCH 30/62] Draft: gui_trackers clean up docstrings and spaces (3) Many small spacing fixes in the code, to improve the Pythonic style according to PEP8. Also add many docstrings in triple quotes. --- src/Mod/Draft/draftguitools/gui_trackers.py | 239 +++++++++++--------- 1 file changed, 137 insertions(+), 102 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py index 50d628b589..6d2d2b87cd 100644 --- a/src/Mod/Draft/draftguitools/gui_trackers.py +++ b/src/Mod/Draft/draftguitools/gui_trackers.py @@ -917,7 +917,7 @@ class PlaneTracker(Tracker): class wireTracker(Tracker): """A wire tracker.""" - def __init__(self,wire): + def __init__(self, wire): self.line = coin.SoLineSet() self.closed = DraftGeomUtils.isReallyClosed(wire) if self.closed: @@ -926,36 +926,41 @@ class wireTracker(Tracker): self.line.numVertices.setValue(len(wire.Vertexes)) self.coords = coin.SoCoordinate3() self.update(wire) - Tracker.__init__(self,children=[self.coords,self.line],name="wireTracker") + Tracker.__init__(self, children=[self.coords, self.line], + name="wireTracker") - def update(self,wire,forceclosed=False): + def update(self, wire, forceclosed=False): + """Update the tracker.""" if wire: if self.closed or forceclosed: - self.line.numVertices.setValue(len(wire.Vertexes)+1) + self.line.numVertices.setValue(len(wire.Vertexes) + 1) else: self.line.numVertices.setValue(len(wire.Vertexes)) for i in range(len(wire.Vertexes)): - p=wire.Vertexes[i].Point - self.coords.point.set1Value(i,[p.x,p.y,p.z]) + p = wire.Vertexes[i].Point + self.coords.point.set1Value(i, [p.x, p.y, p.z]) if self.closed or forceclosed: t = len(wire.Vertexes) p = wire.Vertexes[0].Point - self.coords.point.set1Value(t,[p.x,p.y,p.z]) + self.coords.point.set1Value(t, [p.x, p.y, p.z]) - def updateFromPointlist(self,points,forceclosed=False): + def updateFromPointlist(self, points, forceclosed=False): + """Update the tracker from points.""" if points: for i in range(len(points)): - p=points[i] - self.coords.point.set1Value(i,[p.x,p.y,p.z]) + p = points[i] + self.coords.point.set1Value(i, [p.x, p.y, p.z]) + class gridTracker(Tracker): - """A grid tracker""" + """A grid tracker.""" + def __init__(self): col = self.getGridColor() pick = coin.SoPickStyle() pick.style.setValue(coin.SoPickStyle.UNPICKABLE) self.trans = coin.SoTransform() - self.trans.translation.setValue([0,0,0]) + self.trans.translation.setValue([0, 0, 0]) mat1 = coin.SoMaterial() mat1.transparency.setValue(0.7) mat1.diffuseColor.setValue(col) @@ -984,46 +989,48 @@ class gridTracker(Tracker): s.addChild(mat3) s.addChild(self.coords3) s.addChild(self.lines3) - Tracker.__init__(self,children=[s],name="gridTracker") + Tracker.__init__(self, children=[s], name="gridTracker") self.reset() def getGridColor(self): + """Get the grid color from the parameter editor.""" color = Draft.getParam("gridColor", 842157055) - r = ((color>>24)&0xFF)/255 - g = ((color>>16)&0xFF)/255 - b = ((color>>8)&0xFF)/255 + r = ((color >> 24) & 0xFF) / 255 + g = ((color >> 16) & 0xFF) / 255 + b = ((color >> 8) & 0xFF) / 255 return [r, g, b] def update(self): - """redraws the grid""" - # resize the grid to make sure it fits an exact pair number of main lines - numlines = self.numlines//self.mainlines//2*2*self.mainlines - bound = (numlines//2)*self.space + """Redraw the grid.""" + # Resize the grid to make sure it fits + # an exact pair number of main lines + numlines = self.numlines // self.mainlines // 2 * 2 * self.mainlines + bound = (numlines // 2) * self.space pts = [] mpts = [] apts = [] - for i in range(numlines+1): - curr = -bound + i*self.space + for i in range(numlines + 1): + curr = -bound + i * self.space z = 0 - if i/float(self.mainlines) == i//self.mainlines: - if round(curr,4) == 0: - apts.extend([[-bound,curr,z],[bound,curr,z]]) - apts.extend([[curr,-bound,z],[curr,bound,z]]) + if i / float(self.mainlines) == i // self.mainlines: + if round(curr, 4) == 0: + apts.extend([[-bound, curr, z], [bound, curr, z]]) + apts.extend([[curr, -bound, z], [curr, bound, z]]) else: - mpts.extend([[-bound,curr,z],[bound,curr,z]]) - mpts.extend([[curr,-bound,z],[curr,bound,z]]) + mpts.extend([[-bound, curr, z], [bound, curr, z]]) + mpts.extend([[curr, -bound, z], [curr, bound, z]]) else: - pts.extend([[-bound,curr,z],[bound,curr,z]]) - pts.extend([[curr,-bound,z],[curr,bound,z]]) + pts.extend([[-bound, curr, z], [bound, curr, z]]) + pts.extend([[curr, -bound, z], [curr, bound, z]]) if pts != self.pts: idx = [] midx = [] aidx = [] - for p in range(0,len(pts),2): + for p in range(0, len(pts), 2): idx.append(2) - for mp in range(0,len(mpts),2): + for mp in range(0, len(mpts), 2): midx.append(2) - for ap in range(0,len(apts),2): + for ap in range(0, len(apts), 2): aidx.append(2) self.lines1.numVertices.deleteValues(0) self.lines2.numVertices.deleteValues(0) @@ -1035,52 +1042,57 @@ class gridTracker(Tracker): self.coords3.point.setValues(apts) self.lines3.numVertices.setValues(aidx) self.pts = pts - - def setSize(self,size): + + def setSize(self, size): + """Set size of the lines and update.""" self.numlines = size self.update() - def setSpacing(self,space): + def setSpacing(self, space): + """Set spacing and update.""" self.space = space self.update() - def setMainlines(self,ml): + def setMainlines(self, ml): + """Set mainlines and update.""" self.mainlines = ml self.update() - + def reset(self): - """resets the grid according to preferences settings""" - self.space = Draft.getParam("gridSpacing",1) - self.mainlines = Draft.getParam("gridEvery",10) - self.numlines = Draft.getParam("gridSize",100) + """Reset the grid according to preferences settings.""" + self.space = Draft.getParam("gridSpacing", 1) + self.mainlines = Draft.getParam("gridEvery", 10) + self.numlines = Draft.getParam("gridSize", 100) self.update() def set(self): - """moves and rotates the grid according to the current WP""" + """Move and rotate the grid according to the current working plane.""" self.reset() Q = FreeCAD.DraftWorkingPlane.getRotation().Rotation.Q P = FreeCAD.DraftWorkingPlane.position - self.trans.rotation.setValue([Q[0],Q[1],Q[2],Q[3]]) - self.trans.translation.setValue([P.x,P.y,P.z]) + self.trans.rotation.setValue([Q[0], Q[1], Q[2], Q[3]]) + self.trans.translation.setValue([P.x, P.y, P.z]) self.on() - def getClosestNode(self,point): - """returns the closest node from the given point""" + def getClosestNode(self, point): + """Return the closest node from the given point.""" # get the 2D coords. # point = FreeCAD.DraftWorkingPlane.projectPoint(point) pt = FreeCAD.DraftWorkingPlane.getLocalCoords(point) - pu = (round(pt.x/self.space,0))*self.space - pv = (round(pt.y/self.space,0))*self.space - pt = FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(pu,pv,0)) + pu = round(pt.x / self.space, 0) * self.space + pv = round(pt.y / self.space, 0) * self.space + pt = FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(pu, pv, 0)) return pt - -class boxTracker(Tracker): - """A box tracker, can be based on a line object""" - def __init__(self,line=None,width=0.1,height=1,shaded=False): + + +class boxTracker(Tracker): + """A box tracker, can be based on a line object.""" + + def __init__(self, line=None, width=0.1, height=1, shaded=False): self.trans = coin.SoTransform() m = coin.SoMaterial() m.transparency.setValue(0.8) - m.diffuseColor.setValue([0.4,0.4,0.6]) + m.diffuseColor.setValue([0.4, 0.4, 0.6]) w = coin.SoDrawStyle() w.style = coin.SoDrawStyle.LINES self.cube = coin.SoCube() @@ -1091,16 +1103,19 @@ class boxTracker(Tracker): self.baseline = line self.update() if shaded: - Tracker.__init__(self,children=[self.trans,m,self.cube],name="boxTracker") + Tracker.__init__(self, children=[self.trans, m, self.cube], + name="boxTracker") else: - Tracker.__init__(self,children=[self.trans,w,self.cube],name="boxTracker") + Tracker.__init__(self, children=[self.trans, w, self.cube], + name="boxTracker") - def update(self,line=None,normal=None): + def update(self, line=None, normal=None): + """Update the tracker.""" import WorkingPlane, DraftGeomUtils if not normal: normal = FreeCAD.DraftWorkingPlane.axis if line: - if isinstance(line,list): + if isinstance(line, list): bp = line[0] lvec = line[1].sub(line[0]) else: @@ -1113,109 +1128,129 @@ class boxTracker(Tracker): return right = lvec.cross(normal) self.cube.width.setValue(lvec.Length) - p = WorkingPlane.getPlacementFromPoints([bp,bp.add(lvec),bp.add(right)]) + p = WorkingPlane.getPlacementFromPoints([bp, + bp.add(lvec), + bp.add(right)]) if p: self.trans.rotation.setValue(p.Rotation.Q) bp = bp.add(lvec.multiply(0.5)) - bp = bp.add(DraftVecUtils.scaleTo(normal,self.cube.depth.getValue()/2)) + bp = bp.add(DraftVecUtils.scaleTo(normal, self.cube.depth.getValue()/2.0)) self.pos(bp) - - def setRotation(self,rot): + + def setRotation(self, rot): + """Set the rotation.""" self.trans.rotation.setValue(rot.Q) - def pos(self,p): + def pos(self, p): + """Set the translation.""" self.trans.translation.setValue(DraftVecUtils.tup(p)) - def width(self,w=None): + def width(self, w=None): + """Set the width.""" if w: self.cube.height.setValue(w) else: return self.cube.height.getValue() - def length(self,l=None): + def length(self, l=None): + """Set the length.""" if l: self.cube.width.setValue(l) else: return self.cube.width.getValue() - - def height(self,h=None): + + def height(self, h=None): + """Set the height.""" if h: self.cube.depth.setValue(h) self.update() else: return self.cube.depth.getValue() + class radiusTracker(Tracker): - """A tracker that displays a transparent sphere to inicate a radius""" - def __init__(self,position=FreeCAD.Vector(0,0,0),radius=1): + """A tracker that displays a transparent sphere to inicate a radius.""" + + def __init__(self, position=FreeCAD.Vector(0, 0, 0), radius=1): self.trans = coin.SoTransform() - self.trans.translation.setValue([position.x,position.y,position.z]) + self.trans.translation.setValue([position.x, position.y, position.z]) m = coin.SoMaterial() m.transparency.setValue(0.9) - m.diffuseColor.setValue([0,1,0]) + m.diffuseColor.setValue([0, 1, 0]) self.sphere = coin.SoSphere() self.sphere.radius.setValue(radius) self.baseline = None - Tracker.__init__(self,children=[self.trans,m,self.sphere],name="radiusTracker") + Tracker.__init__(self, children=[self.trans, m, self.sphere], + name="radiusTracker") - def update(self,arg1,arg2=None): - if isinstance(arg1,FreeCAD.Vector): - self.trans.translation.setValue([arg1.x,arg1.y,arg1.z]) + def update(self, arg1, arg2=None): + """Update the tracker.""" + if isinstance(arg1, FreeCAD.Vector): + self.trans.translation.setValue([arg1.x, arg1.y, arg1.z]) else: self.sphere.radius.setValue(arg1) - if arg2 != None: - if isinstance(arg2,FreeCAD.Vector): - self.trans.translation.setValue([arg2.x,arg2.y,arg2.z]) + if arg2 is not None: + if isinstance(arg2, FreeCAD.Vector): + self.trans.translation.setValue([arg2.x, arg2.y, arg2.z]) else: self.sphere.radius.setValue(arg2) - + + class archDimTracker(Tracker): - """A wrapper around a Sketcher dim""" - def __init__(self,p1=FreeCAD.Vector(0,0,0),p2=FreeCAD.Vector(1,0,0),mode=1): + """A wrapper around a Sketcher dim.""" + + def __init__(self, + p1=FreeCAD.Vector(0, 0, 0), + p2=FreeCAD.Vector(1, 0, 0), mode=1): import SketcherGui self.dimnode = coin.SoType.fromName("SoDatumLabel").createInstance() - p1node = coin.SbVec3f([p1.x,p1.y,p1.z]) - p2node = coin.SbVec3f([p2.x,p2.y,p2.z]) - self.dimnode.pnts.setValues([p1node,p2node]) + p1node = coin.SbVec3f([p1.x, p1.y, p1.z]) + p2node = coin.SbVec3f([p2.x, p2.y, p2.z]) + self.dimnode.pnts.setValues([p1node, p2node]) self.dimnode.lineWidth = 1 color = FreeCADGui.draftToolBar.getDefaultColor("snap") self.dimnode.textColor.setValue(coin.SbVec3f(color)) self.setString() self.setMode(mode) - Tracker.__init__(self,children=[self.dimnode],name="archDimTracker") - - def setString(self,text=None): - """sets the dim string to the given value or auto value""" + Tracker.__init__(self, children=[self.dimnode], name="archDimTracker") + + def setString(self, text=None): + """Set the dim string to the given value or auto value.""" self.dimnode.param1.setValue(.5) p1 = Vector(self.dimnode.pnts.getValues()[0].getValue()) p2 = Vector(self.dimnode.pnts.getValues()[-1].getValue()) m = self.dimnode.datumtype.getValue() if m == 2: - self.Distance = (DraftVecUtils.project(p2.sub(p1),Vector(1,0,0))).Length + self.Distance = (DraftVecUtils.project(p2.sub(p1), Vector(1, 0, 0))).Length elif m == 3: - self.Distance = (DraftVecUtils.project(p2.sub(p1),Vector(0,1,0))).Length + self.Distance = (DraftVecUtils.project(p2.sub(p1), Vector(0, 1, 0))).Length else: self.Distance = (p2.sub(p1)).Length - text = FreeCAD.Units.Quantity(self.Distance,FreeCAD.Units.Length).UserString + text = FreeCAD.Units.Quantity(self.Distance, FreeCAD.Units.Length).UserString self.dimnode.string.setValue(text.encode('utf8')) - - def setMode(self,mode=1): - """sets the mode: 0 = without lines (a simple mark), 1 = - aligned (default), 2 = horizontal, 3 = vertical.""" + + def setMode(self, mode=1): + """Set the mode. + + 0 = without lines (a simple mark) + 1 = aligned (default) + 2 = horizontal + 3 = vertical. + """ self.dimnode.datumtype.setValue(mode) - def p1(self,point=None): - """sets or gets the first point of the dim""" + def p1(self, point=None): + """Set or get the first point of the dim.""" if point: - self.dimnode.pnts.set1Value(0,point.x,point.y,point.z) + self.dimnode.pnts.set1Value(0, point.x, point.y, point.z) self.setString() else: return Vector(self.dimnode.pnts.getValues()[0].getValue()) - def p2(self,point=None): - """sets or gets the second point of the dim""" + def p2(self, point=None): + """Set or get the second point of the dim.""" if point: - self.dimnode.pnts.set1Value(1,point.x,point.y,point.z) + self.dimnode.pnts.set1Value(1, point.x, point.y, point.z) self.setString() else: return Vector(self.dimnode.pnts.getValues()[-1].getValue()) From e2df36fc64dd300738add7dd3308e2c52614c646 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 5 Mar 2020 23:00:53 -0600 Subject: [PATCH 31/62] Draft: clean up init_tools and messages --- src/Mod/Draft/draftutils/init_tools.py | 23 +++++++++++------------ src/Mod/Draft/draftutils/messages.py | 15 ++++++++++----- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Mod/Draft/draftutils/init_tools.py b/src/Mod/Draft/draftutils/init_tools.py index 327756dba5..6228a41680 100644 --- a/src/Mod/Draft/draftutils/init_tools.py +++ b/src/Mod/Draft/draftutils/init_tools.py @@ -1,14 +1,3 @@ -"""Provides lists of commands for the Draft Workbench. - -This module returns lists of commands, so that the toolbars -can be initialized by Draft, and by other workbenches. -These commands should be defined in `DraftTools`, and in the individual -modules in `draftguitools`. -""" -## @package init_tools -# \ingroup DRAFT -# \brief This module provides lists of commands for the Draft Workbench. - # *************************************************************************** # * (c) 2020 Eliud Cabrera Castillo * # * * @@ -31,6 +20,16 @@ modules in `draftguitools`. # * USA * # * * # *************************************************************************** +"""Provides lists of commands for the Draft Workbench. + +This module returns lists of commands, so that the toolbars +can be initialized by Draft, and by other workbenches. +These commands should be defined in `DraftTools`, and in the individual +modules in `draftguitools`. +""" +## @package init_tools +# \ingroup DRAFT +# \brief This module provides lists of commands for the Draft Workbench. from PySide.QtCore import QT_TRANSLATE_NOOP @@ -61,7 +60,7 @@ def get_draft_modification_commands(): """Return the modification commands list.""" lst = ["Draft_Move", "Draft_Rotate", "Draft_Scale", "Draft_Mirror", - "Draft_Offset", "Draft_Trimex", + "Draft_Offset", "Draft_Trimex", "Draft_Stretch", "Separator", "Draft_Clone"] diff --git a/src/Mod/Draft/draftutils/messages.py b/src/Mod/Draft/draftutils/messages.py index 7686fa5039..e1f8c99cdc 100644 --- a/src/Mod/Draft/draftutils/messages.py +++ b/src/Mod/Draft/draftutils/messages.py @@ -1,8 +1,3 @@ -"""Provide message utility functions for the Draft Workbench.""" -## @package messages -# \ingroup DRAFT -# \brief Provide message utility functions for the Draft Workbench. - # *************************************************************************** # * (c) 2020 Eliud Cabrera Castillo * # * * @@ -25,6 +20,16 @@ # * USA * # * * # *************************************************************************** +"""Provide message utility functions for the Draft Workbench. + +The Console module has long function names, so we define some shorthands +that are suitable for use in every workbench. These shorthands also include +a newline character at the end of the string, so it doesn't have to be +added manually. +""" +## @package messages +# \ingroup DRAFT +# \brief Provide message utility functions for the Draft Workbench. import FreeCAD as App From fea5dc667d599bb445e4816d7e0a8cb629c5366a Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 5 Mar 2020 23:27:48 -0600 Subject: [PATCH 32/62] Draft: gui_utils, autogroup return when GuiUp is False --- src/Mod/Draft/draftutils/gui_utils.py | 94 ++++++++++++++------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/Mod/Draft/draftutils/gui_utils.py b/src/Mod/Draft/draftutils/gui_utils.py index e3b76ece5d..390f7feb8d 100644 --- a/src/Mod/Draft/draftutils/gui_utils.py +++ b/src/Mod/Draft/draftutils/gui_utils.py @@ -97,50 +97,56 @@ def autogroup(obj): obj : App::DocumentObject Any type of object that will be stored in the group. """ - if FreeCAD.GuiUp: - # look for active Arch container - active_arch_obj = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") - if hasattr(FreeCADGui,"draftToolBar"): - if (hasattr(FreeCADGui.draftToolBar,"autogroup") - and not FreeCADGui.draftToolBar.isConstructionMode() - ): - if FreeCADGui.draftToolBar.autogroup is not None: - active_group = FreeCAD.ActiveDocument.getObject(FreeCADGui.draftToolBar.autogroup) - if active_group: - found = False - for o in active_group.Group: - if o.Name == obj.Name: - found = True - if not found: - gr = active_group.Group - gr.append(obj) - active_group.Group = gr - elif active_arch_obj: - active_arch_obj.addObject(obj) - elif FreeCADGui.ActiveDocument.ActiveView.getActiveObject("part", False) is not None: - # add object to active part and change it's placement accordingly - # so object does not jump to different position, works with App::Link - # if not scaled. Modified accordingly to realthunder suggestions - p, parent, sub = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("part", False) - matrix = parent.getSubObject(sub, retType=4) - if matrix.hasScale() == 1: - FreeCAD.Console.PrintMessage(translate("Draft", - "Unable to insert new object into " - "a scaled part") - ) - return - inverse_placement = FreeCAD.Placement(matrix.inverse()) - if get_type(obj) == 'Point': - # point vector have a kind of placement, so should be - # processed before generic object with placement - point_vector = FreeCAD.Vector(obj.X, obj.Y, obj.Z) - real_point = inverse_placement.multVec(point_vector) - obj.X = real_point.x - obj.Y = real_point.y - obj.Z = real_point.z - elif hasattr(obj,"Placement"): - obj.Placement = FreeCAD.Placement(inverse_placement.multiply(obj.Placement)) - p.addObject(obj) + if not FreeCAD.GuiUp: + return + + Gui = FreeCADGui + doc = FreeCAD.ActiveDocument + view = FreeCADGui.ActiveDocument.ActiveView + + # Look for active Arch container + active_arch_obj = Gui.ActiveDocument.ActiveView.getActiveObject("Arch") + if hasattr(FreeCADGui, "draftToolBar"): + if (hasattr(FreeCADGui.draftToolBar, "autogroup") + and not FreeCADGui.draftToolBar.isConstructionMode()): + if FreeCADGui.draftToolBar.autogroup is not None: + active_group = doc.getObject(FreeCADGui.draftToolBar.autogroup) + if active_group: + found = False + for o in active_group.Group: + if o.Name == obj.Name: + found = True + if not found: + gr = active_group.Group + gr.append(obj) + active_group.Group = gr + elif active_arch_obj: + active_arch_obj.addObject(obj) + elif view.getActiveObject("part", False) is not None: + # Add object to active part and change its placement + # accordingly so the object does not jump + # to a different position, works with App::Link if not scaled. + # Modified accordingly to realthunder suggestions + p, parent, sub = view.getActiveObject("part", False) + matrix = parent.getSubObject(sub, retType=4) + if matrix.hasScale() == 1: + _msg(translate("Draft", + "Unable to insert new object into " + "a scaled part")) + return + inverse_placement = FreeCAD.Placement(matrix.inverse()) + if get_type(obj) == 'Point': + # point vector have a kind of placement, so should be + # processed before generic object with placement + point_vector = FreeCAD.Vector(obj.X, obj.Y, obj.Z) + real_point = inverse_placement.multVec(point_vector) + obj.X = real_point.x + obj.Y = real_point.y + obj.Z = real_point.z + elif hasattr(obj, "Placement"): + place = inverse_placement.multiply(obj.Placement) + obj.Placement = FreeCAD.Placement(place) + p.addObject(obj) def dim_symbol(symbol=None, invert=False): From 863e1a879e2f2273f1d2d8e86df0beda2be65362 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Fri, 28 Feb 2020 11:43:07 -0600 Subject: [PATCH 33/62] Draft: importSVG.py, FreeCADGui with interface only Also small fixes in imports and spacing --- src/Mod/Draft/importSVG.py | 68 ++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index 6faf63e823..d760552062 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -1,23 +1,3 @@ -## @package importSVG -# \ingroup DRAFT -# \brief SVG file importer & exporter -'''@package importSVG -\ingroup DRAFT -\brief SVG file importer & exporter - -This module provides support for importing and exporting SVG files. It -enables importing/exporting objects directly to/from the 3D document, but -doesn't handle the SVG output from the Drawing and TechDraw modules. - -Currently it only reads the following entities: -* paths, lines, circular arcs, rects, circles, ellipses, polygons, polylines. - -Currently unsupported: -* use, image. -''' -# Check code with -# flake8 --ignore=E226,E266,E401,W503 - # *************************************************************************** # * Copyright (c) 2009 Yorik van Havre * # * * @@ -38,12 +18,29 @@ Currently unsupported: # * USA * # * * # *************************************************************************** +"""Provides support for importing and exporting SVG files. + +It enables importing/exporting objects directly to/from the 3D document +but doesn't handle the SVG output from the Drawing and TechDraw modules. + +Currently it only reads the following entities: +* paths, lines, circular arcs, rects, circles, ellipses, polygons, polylines. + +Currently unsupported: +* use, image. +""" +## @package importSVG +# \ingroup DRAFT +# \brief SVG file importer and exporter + +# Check code with +# flake8 --ignore=E226,E266,E401,W503 __title__ = "FreeCAD Draft Workbench - SVG importer/exporter" __author__ = "Yorik van Havre, Sebastian Hoogen" __url__ = "https://www.freecadweb.org" -# ToDo: +# TODO: # ignoring CDATA # handle image element (external references and inline base64) # debug Problem with 'Sans' font from Inkscape @@ -51,27 +48,28 @@ __url__ = "https://www.freecadweb.org" # implement inheriting fill style from group # handle relative units -import xml.sax, FreeCAD, os, math, re, Draft, DraftVecUtils +import math +import os +import re +import xml.sax + +import FreeCAD +import Draft +import DraftVecUtils from FreeCAD import Vector from FreeCAD import Console as FCC +from draftutils.translate import translate if FreeCAD.GuiUp: - from DraftTools import translate from PySide import QtGui -else: - def translate(context, txt): - return txt - -try: import FreeCADGui -except ImportError: - gui = False -else: gui = True - -try: - draftui = FreeCADGui.draftToolBar -except AttributeError: + try: + draftui = FreeCADGui.draftToolBar + except AttributeError: + draftui = None +else: + gui = False draftui = None # Save the native open function to avoid collisions From 536e0ad133546e65d67baa9cf52c61955ef50c6e Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 11 Mar 2020 01:11:54 -0600 Subject: [PATCH 34/62] Draft: move ShapeString to the creation tools Previously it was placed in the `annotation` category but since it creates a group of shapes, it is better in the `creation` category. Also small fixes in the menu text and tooltip. --- src/Mod/Draft/DraftTools.py | 18 +++++++++++++----- src/Mod/Draft/InitGui.py | 4 +++- src/Mod/Draft/draftutils/init_tools.py | 5 +++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index aa9b520afd..fb3456818f 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -2237,14 +2237,22 @@ class Dimension(Creator): if not self.cont: self.finish() + class ShapeString(Creator): - """This class creates a shapestring feature.""" + """The Draft_ShapeString FreeCAD command definition.""" def GetResources(self): - return {'Pixmap' : 'Draft_ShapeString', - 'Accel' : "S, S", - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", "Shape from text..."), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", "Creates text string in shapes.")} + """Set icon, menu and tooltip.""" + _menu = "Shape from text" + _tooltip = ("Creates a shape from a text string by choosing " + "a specific font and a placement.\n" + "The closed shapes can be used for extrusions " + "and boolean operations.") + d = {'Pixmap': 'Draft_ShapeString', + 'Accel': "S, S", + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", _menu), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", _tooltip)} + return d def Activated(self): name = translate("draft","ShapeString") diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index d864f31af4..ee9cc8f248 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -1,4 +1,3 @@ -"""Initialization of the Draft workbench (graphical interface).""" # *************************************************************************** # * Copyright (c) 2009 Yorik van Havre * # * * @@ -19,7 +18,10 @@ # * USA * # * * # *************************************************************************** +"""Initialization of the Draft workbench (graphical interface).""" + import os + import FreeCAD import FreeCADGui diff --git a/src/Mod/Draft/draftutils/init_tools.py b/src/Mod/Draft/draftutils/init_tools.py index 6228a41680..44c5cc1b08 100644 --- a/src/Mod/Draft/draftutils/init_tools.py +++ b/src/Mod/Draft/draftutils/init_tools.py @@ -42,12 +42,13 @@ def get_draft_drawing_commands(): "Draft_ArcTools", "Draft_Circle", "Draft_Ellipse", "Draft_Rectangle", "Draft_Polygon", "Draft_BSpline", "Draft_BezierTools", - "Draft_Point", "Draft_Facebinder"] + "Draft_Point", "Draft_Facebinder", + "Draft_ShapeString"] def get_draft_annotation_commands(): """Return the annotation commands list.""" - return ["Draft_Text", "Draft_ShapeString", "Draft_Dimension", + return ["Draft_Text", "Draft_Dimension", "Draft_Label"] From a76a438fdac562f7373e4891024d28c1fbcd1ae5 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Sat, 21 Mar 2020 01:14:06 -0600 Subject: [PATCH 35/62] Draft: gui_utils, add small stylistic changes These changes are added by carlopav in pull request #3102. We add them in this commit already so that this branch and that branch are easier to rebase and merge. --- src/Mod/Draft/draftutils/gui_utils.py | 108 +++++++++++++------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Mod/Draft/draftutils/gui_utils.py b/src/Mod/Draft/draftutils/gui_utils.py index 390f7feb8d..37b4c899d9 100644 --- a/src/Mod/Draft/draftutils/gui_utils.py +++ b/src/Mod/Draft/draftutils/gui_utils.py @@ -2,6 +2,7 @@ # * (c) 2009, 2010 * # * Yorik van Havre , Ken Cline * # * (c) 2019 Eliud Cabrera Castillo * +# * (c) 2020 Carlo Pavan * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -37,14 +38,14 @@ import math import os import six -import FreeCAD +import FreeCAD as App from draftutils.messages import _msg, _wrn from draftutils.utils import getParam from draftutils.utils import get_type from draftutils.translate import _tr, translate -if FreeCAD.GuiUp: - import FreeCADGui +if App.GuiUp: + import FreeCADGui as Gui from pivy import coin from PySide import QtGui # from PySide import QtSvg # for load_texture @@ -61,13 +62,13 @@ def get_3d_view(): Return `None` if the graphical interface is not available. """ - if FreeCAD.GuiUp: - v = FreeCADGui.ActiveDocument.ActiveView + if App.GuiUp: + v = Gui.ActiveDocument.ActiveView if "View3DInventor" in str(type(v)): return v # print("Debug: Draft: Warning, not working in active view") - v = FreeCADGui.ActiveDocument.mdiViewsOfType("Gui::View3DInventor") + v = Gui.ActiveDocument.mdiViewsOfType("Gui::View3DInventor") if v: return v[0] @@ -82,7 +83,7 @@ def autogroup(obj): """Add a given object to the defined Draft autogroup, if applicable. This function only works if the graphical interface is available. - It checks that the `FreeCAD.draftToolBar` class is available, + It checks that the `App.draftToolBar` class is available, which contains the group to use to automatically store new created objects. @@ -94,23 +95,22 @@ def autogroup(obj): Parameters ---------- - obj : App::DocumentObject + obj: App::DocumentObject Any type of object that will be stored in the group. """ - if not FreeCAD.GuiUp: + if not App.GuiUp: return - Gui = FreeCADGui - doc = FreeCAD.ActiveDocument - view = FreeCADGui.ActiveDocument.ActiveView + doc = App.ActiveDocument + view = Gui.ActiveDocument.ActiveView # Look for active Arch container active_arch_obj = Gui.ActiveDocument.ActiveView.getActiveObject("Arch") - if hasattr(FreeCADGui, "draftToolBar"): - if (hasattr(FreeCADGui.draftToolBar, "autogroup") - and not FreeCADGui.draftToolBar.isConstructionMode()): - if FreeCADGui.draftToolBar.autogroup is not None: - active_group = doc.getObject(FreeCADGui.draftToolBar.autogroup) + if hasattr(Gui, "draftToolBar"): + if (hasattr(Gui.draftToolBar, "autogroup") + and not Gui.draftToolBar.isConstructionMode()): + if Gui.draftToolBar.autogroup is not None: + active_group = doc.getObject(Gui.draftToolBar.autogroup) if active_group: found = False for o in active_group.Group: @@ -134,18 +134,18 @@ def autogroup(obj): "Unable to insert new object into " "a scaled part")) return - inverse_placement = FreeCAD.Placement(matrix.inverse()) + inverse_placement = App.Placement(matrix.inverse()) if get_type(obj) == 'Point': # point vector have a kind of placement, so should be # processed before generic object with placement - point_vector = FreeCAD.Vector(obj.X, obj.Y, obj.Z) + point_vector = App.Vector(obj.X, obj.Y, obj.Z) real_point = inverse_placement.multVec(point_vector) obj.X = real_point.x obj.Y = real_point.y obj.Z = real_point.z elif hasattr(obj, "Placement"): place = inverse_placement.multiply(obj.Placement) - obj.Placement = FreeCAD.Placement(place) + obj.Placement = App.Placement(place) p.addObject(obj) @@ -154,7 +154,7 @@ def dim_symbol(symbol=None, invert=False): Parameters ---------- - symbol : int, optional + symbol: int, optional It defaults to `None`, in which it gets the value from the parameter database, `get_param("dimsymbol", 0)`. @@ -166,7 +166,7 @@ def dim_symbol(symbol=None, invert=False): * 4, `SoSeparator` with a `SoLineSet`, calling `dim_dash` * Otherwise, `SoSphere` - invert : bool, optional + invert: bool, optional It defaults to `False`. If it is `True` and `symbol=2`, the cone will be rotated -90 degrees around the Z axis, otherwise the rotation is positive, @@ -186,7 +186,7 @@ def dim_symbol(symbol=None, invert=False): return coin.SoSphere() elif symbol == 1: marker = coin.SoMarkerSet() - marker.markerIndex = FreeCADGui.getMarkerIndex("circle", 9) + marker.markerIndex = Gui.getMarkerIndex("circle", 9) return marker elif symbol == 2: marker = coin.SoSeparator() @@ -229,10 +229,10 @@ def dim_dash(p1, p2): Parameters ---------- - p1 : tuple of three floats or Base::Vector3 + p1: tuple of three floats or Base::Vector3 A point to define a line vertex. - p2 : tuple of three floats or Base::Vector3 + p2: tuple of three floats or Base::Vector3 A point to define a line vertex. Returns @@ -263,7 +263,7 @@ def remove_hidden(objectslist): Parameters ---------- - objectslist : list of App::DocumentObject + objectslist: list of App::DocumentObject List of any type of object. Returns @@ -296,19 +296,19 @@ def format_object(target, origin=None): Parameters ---------- - target : App::DocumentObject + target: App::DocumentObject Any type of scripted object. This object will adopt the applicable visual properties, `FontSize`, `TextColor`, `LineWidth`, `PointColor`, `LineColor`, and `ShapeColor`, defined in the Draft toolbar - (`FreeCADGui.draftToolBar`) or will adopt + (`Gui.draftToolBar`) or will adopt the properties from the `origin` object. The `target` is also placed in the construction group if the construction mode in the Draft toolbar is active. - origin : App::DocumentObject, optional + origin: App::DocumentObject, optional It defaults to `None`. If it exists, it will provide the visual properties to assign to `target`, with the exception of `BoundingBox`, `Proxy`, @@ -320,11 +320,11 @@ def format_object(target, origin=None): if not obrep: return ui = None - if FreeCAD.GuiUp: - if hasattr(FreeCADGui, "draftToolBar"): - ui = FreeCADGui.draftToolBar + if App.GuiUp: + if hasattr(Gui, "draftToolBar"): + ui = Gui.draftToolBar if ui: - doc = FreeCAD.ActiveDocument + doc = App.ActiveDocument if ui.isConstructionMode(): col = fcol = ui.getDefaultColor("constr") gname = getParam("constructiongroupname", "Construction") @@ -379,18 +379,18 @@ def format_object(target, origin=None): formatObject = format_object -def get_selection(gui=FreeCAD.GuiUp): +def get_selection(gui=App.GuiUp): """Return the current selected objects. This function only works if the graphical interface is available as the selection module only works on the 3D view. - It wraps around `FreeCADGui.Selection.getSelection` + It wraps around `Gui.Selection.getSelection` Parameters ---------- - gui : bool, optional - It defaults to the value of `FreeCAD.GuiUp`, which is `True` + gui: bool, optional + It defaults to the value of `App.GuiUp`, which is `True` when the interface exists, and `False` otherwise. This value can be set to `False` to simulate @@ -405,25 +405,25 @@ def get_selection(gui=FreeCAD.GuiUp): If the interface is not available, it returns `None`. """ if gui: - return FreeCADGui.Selection.getSelection() + return Gui.Selection.getSelection() return None getSelection = get_selection -def get_selection_ex(gui=FreeCAD.GuiUp): +def get_selection_ex(gui=App.GuiUp): """Return the current selected objects together with their subelements. This function only works if the graphical interface is available as the selection module only works on the 3D view. - It wraps around `FreeCADGui.Selection.getSelectionEx` + It wraps around `Gui.Selection.getSelectionEx` Parameters ---------- - gui : bool, optional - It defaults to the value of `FreeCAD.GuiUp`, which is `True` + gui: bool, optional + It defaults to the value of `App.GuiUp`, which is `True` when the interface exists, and `False` otherwise. This value can be set to `False` to simulate @@ -453,14 +453,14 @@ def get_selection_ex(gui=FreeCAD.GuiUp): if `HasSubObjects` is `False`. """ if gui: - return FreeCADGui.Selection.getSelectionEx() + return Gui.Selection.getSelectionEx() return None getSelectionEx = get_selection_ex -def select(objs=None, gui=FreeCAD.GuiUp): +def select(objs=None, gui=App.GuiUp): """Unselects everything and selects only the given list of objects. This function only works if the graphical interface is available @@ -468,29 +468,29 @@ def select(objs=None, gui=FreeCAD.GuiUp): Parameters ---------- - objs : list of App::DocumentObject, optional + objs: list of App::DocumentObject, optional It defaults to `None`. Any type of scripted object. It may be a list of objects or a single object. - gui : bool, optional - It defaults to the value of `FreeCAD.GuiUp`, which is `True` + gui: bool, optional + It defaults to the value of `App.GuiUp`, which is `True` when the interface exists, and `False` otherwise. This value can be set to `False` to simulate when the interface is not available. """ if gui: - FreeCADGui.Selection.clearSelection() + Gui.Selection.clearSelection() if objs: if not isinstance(objs, list): objs = [objs] for obj in objs: if obj: - FreeCADGui.Selection.addSelection(obj) + Gui.Selection.addSelection(obj) -def load_texture(filename, size=None, gui=FreeCAD.GuiUp): +def load_texture(filename, size=None, gui=App.GuiUp): """Return a Coin.SoSFImage to use as a texture for a 2D plane. This function only works if the graphical interface is available @@ -499,11 +499,11 @@ def load_texture(filename, size=None, gui=FreeCAD.GuiUp): Parameters ---------- - filename : str + filename: str A path to a pixel image file (PNG) that can be used as a texture on the face of an object. - size : tuple of two int, or a single int, optional + size: tuple of two int, or a single int, optional It defaults to `None`. If a tuple is given, the two values define the width and height in pixels to which the loaded image will be scaled. @@ -515,8 +515,8 @@ def load_texture(filename, size=None, gui=FreeCAD.GuiUp): CURRENTLY the input `size` parameter IS NOT USED. It always uses the `QImage` to determine this information. - gui : bool, optional - It defaults to the value of `FreeCAD.GuiUp`, which is `True` + gui: bool, optional + It defaults to the value of `App.GuiUp`, which is `True` when the interface exists, and `False` otherwise. This value can be set to `False` to simulate From 4acdf2613dc5ae27aa0321ac027e6d32eeacfd6f Mon Sep 17 00:00:00 2001 From: "luz.paz" Date: Mon, 6 Apr 2020 14:51:55 -0400 Subject: [PATCH 36/62] [skip-ci] Various typo fixes Found via codespell v1.17.0.dev0 ``` codespell -q 3 -L aci,ake,aline,alle,alledges,alocation,als,ang,anid,ba,beginn,behaviour,bloaded,byteorder,calculater,cancelled,cancelling,cas,cascade,centimetre,childs,colour,colours,commen,connexion,currenty,dof,doubleclick,dum,eiter,elemente,ende,feld,finde,findf,freez,hist,iff,indicies,initialisation,initialise,initialised,initialises,initialisiert,ist,kilometre,lod,mantatory,methode,metres,millimetre,modell,nd,noe,normale,normaly,nto,numer,oder,orgin,orginx,orginy,ot,pard,pres,programm,que,recurrance,rougly,seperator,serie,sinc,strack,substraction,te,thist,thru,tread,uint,unter,vertexes,wallthickness,whitespaces -S ./.git,*.po,*.ts,./ChangeLog.txt,./src/3rdParty,./src/Mod/Assembly/App/opendcm,./src/CXX,./src/zipios++,./src/Base/swig*,./src/Mod/Robot/App/kdl_cp,./src/Mod/Import/App/SCL,./src/WindowsInstaller,./src/Doc/FreeCAD.uml ``` --- src/Mod/Assembly/App/AppAssembly.cpp | 4 ++-- src/Mod/PartDesign/Gui/ViewProviderDatum.h | 2 +- src/Mod/Path/App/ParamsHelper.h | 2 +- src/Mod/Spreadsheet/App/PropertySheet.cpp | 2 +- src/Mod/TechDraw/Gui/TaskWeldingSymbol.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssembly.cpp b/src/Mod/Assembly/App/AppAssembly.cpp index 27a1b7f13a..5a8bd4a9d4 100644 --- a/src/Mod/Assembly/App/AppAssembly.cpp +++ b/src/Mod/Assembly/App/AppAssembly.cpp @@ -77,12 +77,12 @@ void AssemblyExport initAssembly() // call PyType_Ready, otherwise we run into a segmentation fault, later on. // This function is responsible for adding inherited slots from a type's base class. - // Item hirachy + // Item hierarchy Assembly::Item ::init(); Assembly::Product ::init(); Assembly::ProductRef ::init(); - // constraint hirachy + // constraint hierarchy Assembly::Constraint ::init(); Assembly::ConstraintGroup ::init(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.h b/src/Mod/PartDesign/Gui/ViewProviderDatum.h index 43a5057360..e801d9418e 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.h @@ -94,7 +94,7 @@ public: * Computes appropriate bounding box for the given list of objects to be passed to setExtents () * @param bboxAction a coin action for traverse the given objects views. * @param objs the list of objects to traverse, due to we traverse the scene graph, the geo children - * will likely be traveresed too. + * will likely be traversed too. */ static SbBox3f getRelevantBoundBox ( SoGetBoundingBoxAction &bboxAction, diff --git a/src/Mod/Path/App/ParamsHelper.h b/src/Mod/Path/App/ParamsHelper.h index 234cdfcecb..025cf677ef 100644 --- a/src/Mod/Path/App/ParamsHelper.h +++ b/src/Mod/Path/App/ParamsHelper.h @@ -119,7 +119,7 @@ * * - \c default is the default value of this parameter. Right now, you must * supply a default value. Boost.PP has trouble dealing with empty values. - * Remember that a sequence cannot be empty. Neight can tuple. Only array, + * Remember that a sequence cannot be empty. Neither can tuple. Only array, * something like (0,()) for an empty array. It is awkward to write, * and didn't add much functionality I want, hence the restriction of * non-empty defaults here. diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index 28012a70f5..a9a7afdd2d 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -1067,7 +1067,7 @@ void PropertySheet::removeDependencies(CellAddress key) void PropertySheet::recomputeDependants(const App::DocumentObject *owner, const char *propName) { // First, search without actual property name for sub-object/link - // references, i.e indirect references. The depenedecies of these + // references, i.e indirect references. The dependencies of these // references are too complex to track exactly, so we only track the // top parent object instead, and mark the involved expression // whenever the top parent changes. diff --git a/src/Mod/TechDraw/Gui/TaskWeldingSymbol.cpp b/src/Mod/TechDraw/Gui/TaskWeldingSymbol.cpp index 215e2706bb..bfcc9223d2 100644 --- a/src/Mod/TechDraw/Gui/TaskWeldingSymbol.cpp +++ b/src/Mod/TechDraw/Gui/TaskWeldingSymbol.cpp @@ -376,7 +376,7 @@ void TaskWeldingSymbol::onFlipSidesClicked() ui->leOtherTextR->setText(ui->leArrowTextR->text()); ui->leArrowTextR->setText(tempText); - // one cannot get the path from the icon therfore read out + // one cannot get the path from the icon therefore read out // the path property auto tempPathArrow = m_arrowFeat->SymbolFile.getValue(); auto tempPathOther = m_otherFeat->SymbolFile.getValue(); From 97e525ea93b734a26ffd8de58a0726da47d8635c Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Tue, 7 Apr 2020 16:59:24 +0200 Subject: [PATCH 37/62] [PartDesign] Remove 'Set tip' from Body contextual menu ; fixes #4304 --- src/Mod/PartDesign/Gui/Workbench.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index ac7407d2cc..350c14dbe3 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -175,7 +175,6 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con body = PartDesignGui::getBodyFor (feature, false, false, assertModern); // lote of assertion so feature should be marked as a tip if ( selection.size () == 1 && feature && ( - feature->isDerivedFrom ( PartDesign::Body::getClassTypeId () ) || ( feature->isDerivedFrom ( PartDesign::Feature::getClassTypeId () ) && body ) || ( feature->isDerivedFrom ( Part::Feature::getClassTypeId () ) && body && body->BaseFeature.getValue() == feature ) From b2d78ee95a85ffd3288b122b321b5d02ee372d89 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 7 Apr 2020 21:00:48 +0200 Subject: [PATCH 38/62] Arch: rebar, add error prints --- src/Mod/Arch/ArchRebar.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Mod/Arch/ArchRebar.py b/src/Mod/Arch/ArchRebar.py index 7786f39eef..9ce7aceb00 100644 --- a/src/Mod/Arch/ArchRebar.py +++ b/src/Mod/Arch/ArchRebar.py @@ -301,15 +301,35 @@ class _Rebar(ArchComponent.Component): if self.clone(obj): return if not obj.Base: + FreeCAD.Console.PrintError( + "No Base, return without a rebar shape for {}.\n" + .format(obj.Name) + ) return if not obj.Base.Shape: + FreeCAD.Console.PrintError( + "No Shape in Base, return without a rebar shape for {}.\n" + .format(obj.Name) + ) return if not obj.Base.Shape.Wires: + FreeCAD.Console.PrintError( + "No Wires in Shape of Base, return without a rebar shape for {}.\n" + .format(obj.Name) + ) return if not obj.Diameter.Value: + FreeCAD.Console.PrintError( + "No Diameter Value, return without a rebar shape for {}.\n" + .format(obj.Name) + ) return if not obj.Amount: return + FreeCAD.Console.PrintError( + "No Amount, return without a rebar shape for {}.\n" + .format(obj.Name) + ) father = obj.Host fathershape = None if not father: From bf114b606ad6ac3585adcf4fd8b4f711afba4651 Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Sun, 5 Apr 2020 19:52:03 -0500 Subject: [PATCH 39/62] Path: Fix broken `Gui::QuantitySpinBox` class Now, custom expressions are applied to spinbox. Spinbox now updates, after clicking elsewhere. Path: Shorten for loop search --- src/Mod/Path/PathScripts/PathGui.py | 262 +++++++++++++++------------- 1 file changed, 143 insertions(+), 119 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathGui.py b/src/Mod/Path/PathScripts/PathGui.py index 98cf988106..0e9d924b5a 100644 --- a/src/Mod/Path/PathScripts/PathGui.py +++ b/src/Mod/Path/PathScripts/PathGui.py @@ -1,119 +1,143 @@ -# -*- coding: utf-8 -*- - -# *************************************************************************** -# * * -# * Copyright (c) 2017 sliptonic * -# * * -# * This program is free software; you can redistribute it and/or modify * -# * it under the terms of the GNU Lesser General Public License (LGPL) * -# * as published by the Free Software Foundation; either version 2 of * -# * the License, or (at your option) any later version. * -# * for detail see the LICENCE text file. * -# * * -# * This program is distributed in the hope that it will be useful, * -# * but WITHOUT ANY WARRANTY; without even the implied warranty of * -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -# * GNU Library General Public License for more details. * -# * * -# * You should have received a copy of the GNU Library General Public * -# * License along with this program; if not, write to the Free Software * -# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -# * USA * -# * * -# *************************************************************************** - -import FreeCAD -import PathScripts.PathGeom as PathGeom -import PathScripts.PathLog as PathLog -import PathScripts.PathUtil as PathUtil -import PySide - - -__title__ = "Path UI helper and utility functions" -__author__ = "sliptonic (Brad Collette)" -__url__ = "http://www.freecadweb.org" -__doc__ = "A collection of helper and utility functions for the Path GUI." - -def translate(context, text, disambig=None): - return PySide.QtCore.QCoreApplication.translate(context, text, disambig) - -LOGLEVEL = False - -if LOGLEVEL: - PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) - PathLog.trackModule(PathLog.thisModule()) -else: - PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) - -def updateInputField(obj, prop, widget, onBeforeChange=None): - '''updateInputField(obj, prop, widget) ... update obj's property prop with the value of widget. -The property's value is only assigned if the new value differs from the current value. -This prevents onChanged notifications where the value didn't actually change. -Gui::InputField and Gui::QuantitySpinBox widgets are supported - and the property can -be of type Quantity or Float. -If onBeforeChange is specified it is called before a new value is assigned to the property. -Returns True if a new value was assigned, False otherwise (new value is the same as the current). -''' - value = FreeCAD.Units.Quantity(widget.text()).Value - attr = PathUtil.getProperty(obj, prop) - attrValue = attr.Value if hasattr(attr, 'Value') else attr - if not PathGeom.isRoughly(attrValue, value): - PathLog.debug("updateInputField(%s, %s): %.2f -> %.2f" % (obj.Label, prop, attr, value)) - if onBeforeChange: - onBeforeChange(obj) - PathUtil.setProperty(obj, prop, value) - return True - return False - -class QuantitySpinBox: - '''Controller class to interface a Gui::QuantitySpinBox. -The spin box gets bound to a given property and supports update in both directions. - QuatitySpinBox(widget, obj, prop, onBeforeChange=None) - widget ... expected to be reference to a Gui::QuantitySpinBox - obj ... document object - prop ... canonical name of the (sub-) property - onBeforeChange ... an optional callback being executed before the value of the property is changed -''' - - def __init__(self, widget, obj, prop, onBeforeChange=None): - self.obj = obj - self.widget = widget - self.prop = prop - self.onBeforeChange = onBeforeChange - attr = PathUtil.getProperty(self.obj, self.prop) - if attr is not None: - if hasattr(attr, 'Value'): - widget.setProperty('unit', attr.getUserPreferred()[2]) - widget.setProperty('binding', "%s.%s" % (obj.Name, prop)) - self.valid = True - else: - PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label)) - self.valid = False - - def expression(self): - '''expression() ... returns the expression if one is bound to the property''' - if self.valid: - return self.widget.property('expression') - return '' - - def setMinimum(self, quantity): - if self.valid: - value = quantity.Value if hasattr(quantity, 'Value') else quantity - self.widget.setProperty('setMinimum', value) - - def updateSpinBox(self, quantity=None): - '''updateSpinBox(quantity=None) ... update the display value of the spin box. -If no value is provided the value of the bound property is used. -quantity can be of type Quantity or Float.''' - if self.valid: - if quantity is None: - quantity = PathUtil.getProperty(self.obj, self.prop) - value = quantity.Value if hasattr(quantity, 'Value') else quantity - self.widget.setProperty('rawValue', value) - - def updateProperty(self): - '''updateProperty() ... update the bound property with the value from the spin box''' - if self.valid: - return updateInputField(self.obj, self.prop, self.widget, self.onBeforeChange) - return None - +# -*- coding: utf-8 -*- + +# *************************************************************************** +# * * +# * Copyright (c) 2017 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD +import PathScripts.PathGeom as PathGeom +import PathScripts.PathLog as PathLog +import PathScripts.PathUtil as PathUtil +import PySide + + +__title__ = "Path UI helper and utility functions" +__author__ = "sliptonic (Brad Collette)" +__url__ = "http://www.freecadweb.org" +__doc__ = "A collection of helper and utility functions for the Path GUI." + +def translate(context, text, disambig=None): + return PySide.QtCore.QCoreApplication.translate(context, text, disambig) + +LOGLEVEL = False + +if LOGLEVEL: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + +def updateInputField(obj, prop, widget, onBeforeChange=None): + '''updateInputField(obj, prop, widget) ... update obj's property prop with the value of widget. +The property's value is only assigned if the new value differs from the current value. +This prevents onChanged notifications where the value didn't actually change. +Gui::InputField and Gui::QuantitySpinBox widgets are supported - and the property can +be of type Quantity or Float. +If onBeforeChange is specified it is called before a new value is assigned to the property. +Returns True if a new value was assigned, False otherwise (new value is the same as the current). +''' + value = FreeCAD.Units.Quantity(widget.text()).Value + attr = PathUtil.getProperty(obj, prop) + attrValue = attr.Value if hasattr(attr, 'Value') else attr + + isDiff = False + if not PathGeom.isRoughly(attrValue, value): + isDiff = True + else: + if hasattr(obj, 'ExpressionEngine'): + noExpr = True + for (prp, expr) in obj.ExpressionEngine: + if prp == prop: + noExpr = False + PathLog.debug('prop = "expression": {} = "{}"'.format(prp, expr)) + value = FreeCAD.Units.Quantity(obj.evalExpression(expr)).Value + if not PathGeom.isRoughly(attrValue, value): + isDiff = True + break + if noExpr: + widget.setReadOnly(False) + widget.setStyleSheet("color: black") + else: + widget.setReadOnly(True) + widget.setStyleSheet("color: gray") + widget.update() + + if isDiff: + PathLog.debug("updateInputField(%s, %s): %.2f -> %.2f" % (obj.Label, prop, attr, value)) + if onBeforeChange: + onBeforeChange(obj) + PathUtil.setProperty(obj, prop, value) + return True + return False + +class QuantitySpinBox: + '''Controller class to interface a Gui::QuantitySpinBox. +The spin box gets bound to a given property and supports update in both directions. + QuatitySpinBox(widget, obj, prop, onBeforeChange=None) + widget ... expected to be reference to a Gui::QuantitySpinBox + obj ... document object + prop ... canonical name of the (sub-) property + onBeforeChange ... an optional callback being executed before the value of the property is changed +''' + + def __init__(self, widget, obj, prop, onBeforeChange=None): + self.obj = obj + self.widget = widget + self.prop = prop + self.onBeforeChange = onBeforeChange + + attr = PathUtil.getProperty(self.obj, self.prop) + if attr is not None: + if hasattr(attr, 'Value'): + widget.setProperty('unit', attr.getUserPreferred()[2]) + widget.setProperty('binding', "%s.%s" % (obj.Name, prop)) + self.valid = True + else: + PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label)) + self.valid = False + + def expression(self): + '''expression() ... returns the expression if one is bound to the property''' + if self.valid: + return self.widget.property('expression') + return '' + + def setMinimum(self, quantity): + if self.valid: + value = quantity.Value if hasattr(quantity, 'Value') else quantity + self.widget.setProperty('setMinimum', value) + + def updateSpinBox(self, quantity=None): + '''updateSpinBox(quantity=None) ... update the display value of the spin box. +If no value is provided the value of the bound property is used. +quantity can be of type Quantity or Float.''' + if self.valid: + if quantity is None: + quantity = PathUtil.getProperty(self.obj, self.prop) + value = quantity.Value if hasattr(quantity, 'Value') else quantity + self.widget.setProperty('rawValue', value) + + def updateProperty(self): + '''updateProperty() ... update the bound property with the value from the spin box''' + if self.valid: + return updateInputField(self.obj, self.prop, self.widget, self.onBeforeChange) + return None + From db18f3322a0b2a17f71eae713800f03edf10f7a9 Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Sun, 5 Apr 2020 19:55:47 -0500 Subject: [PATCH 40/62] Path: PEP8 cleanup line endings fix --- src/Mod/Path/PathScripts/PathGui.py | 288 +++++++++++++------------- src/Mod/Path/PathScripts/PathOpGui.py | 8 +- 2 files changed, 150 insertions(+), 146 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathGui.py b/src/Mod/Path/PathScripts/PathGui.py index 0e9d924b5a..b3ea83ccd8 100644 --- a/src/Mod/Path/PathScripts/PathGui.py +++ b/src/Mod/Path/PathScripts/PathGui.py @@ -1,143 +1,145 @@ -# -*- coding: utf-8 -*- - -# *************************************************************************** -# * * -# * Copyright (c) 2017 sliptonic * -# * * -# * This program is free software; you can redistribute it and/or modify * -# * it under the terms of the GNU Lesser General Public License (LGPL) * -# * as published by the Free Software Foundation; either version 2 of * -# * the License, or (at your option) any later version. * -# * for detail see the LICENCE text file. * -# * * -# * This program is distributed in the hope that it will be useful, * -# * but WITHOUT ANY WARRANTY; without even the implied warranty of * -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -# * GNU Library General Public License for more details. * -# * * -# * You should have received a copy of the GNU Library General Public * -# * License along with this program; if not, write to the Free Software * -# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -# * USA * -# * * -# *************************************************************************** - -import FreeCAD -import PathScripts.PathGeom as PathGeom -import PathScripts.PathLog as PathLog -import PathScripts.PathUtil as PathUtil -import PySide - - -__title__ = "Path UI helper and utility functions" -__author__ = "sliptonic (Brad Collette)" -__url__ = "http://www.freecadweb.org" -__doc__ = "A collection of helper and utility functions for the Path GUI." - -def translate(context, text, disambig=None): - return PySide.QtCore.QCoreApplication.translate(context, text, disambig) - -LOGLEVEL = False - -if LOGLEVEL: - PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) - PathLog.trackModule(PathLog.thisModule()) -else: - PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) - -def updateInputField(obj, prop, widget, onBeforeChange=None): - '''updateInputField(obj, prop, widget) ... update obj's property prop with the value of widget. -The property's value is only assigned if the new value differs from the current value. -This prevents onChanged notifications where the value didn't actually change. -Gui::InputField and Gui::QuantitySpinBox widgets are supported - and the property can -be of type Quantity or Float. -If onBeforeChange is specified it is called before a new value is assigned to the property. -Returns True if a new value was assigned, False otherwise (new value is the same as the current). -''' - value = FreeCAD.Units.Quantity(widget.text()).Value - attr = PathUtil.getProperty(obj, prop) - attrValue = attr.Value if hasattr(attr, 'Value') else attr - - isDiff = False - if not PathGeom.isRoughly(attrValue, value): - isDiff = True - else: - if hasattr(obj, 'ExpressionEngine'): - noExpr = True - for (prp, expr) in obj.ExpressionEngine: - if prp == prop: - noExpr = False - PathLog.debug('prop = "expression": {} = "{}"'.format(prp, expr)) - value = FreeCAD.Units.Quantity(obj.evalExpression(expr)).Value - if not PathGeom.isRoughly(attrValue, value): - isDiff = True - break - if noExpr: - widget.setReadOnly(False) - widget.setStyleSheet("color: black") - else: - widget.setReadOnly(True) - widget.setStyleSheet("color: gray") - widget.update() - - if isDiff: - PathLog.debug("updateInputField(%s, %s): %.2f -> %.2f" % (obj.Label, prop, attr, value)) - if onBeforeChange: - onBeforeChange(obj) - PathUtil.setProperty(obj, prop, value) - return True - return False - -class QuantitySpinBox: - '''Controller class to interface a Gui::QuantitySpinBox. -The spin box gets bound to a given property and supports update in both directions. - QuatitySpinBox(widget, obj, prop, onBeforeChange=None) - widget ... expected to be reference to a Gui::QuantitySpinBox - obj ... document object - prop ... canonical name of the (sub-) property - onBeforeChange ... an optional callback being executed before the value of the property is changed -''' - - def __init__(self, widget, obj, prop, onBeforeChange=None): - self.obj = obj - self.widget = widget - self.prop = prop - self.onBeforeChange = onBeforeChange - - attr = PathUtil.getProperty(self.obj, self.prop) - if attr is not None: - if hasattr(attr, 'Value'): - widget.setProperty('unit', attr.getUserPreferred()[2]) - widget.setProperty('binding', "%s.%s" % (obj.Name, prop)) - self.valid = True - else: - PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label)) - self.valid = False - - def expression(self): - '''expression() ... returns the expression if one is bound to the property''' - if self.valid: - return self.widget.property('expression') - return '' - - def setMinimum(self, quantity): - if self.valid: - value = quantity.Value if hasattr(quantity, 'Value') else quantity - self.widget.setProperty('setMinimum', value) - - def updateSpinBox(self, quantity=None): - '''updateSpinBox(quantity=None) ... update the display value of the spin box. -If no value is provided the value of the bound property is used. -quantity can be of type Quantity or Float.''' - if self.valid: - if quantity is None: - quantity = PathUtil.getProperty(self.obj, self.prop) - value = quantity.Value if hasattr(quantity, 'Value') else quantity - self.widget.setProperty('rawValue', value) - - def updateProperty(self): - '''updateProperty() ... update the bound property with the value from the spin box''' - if self.valid: - return updateInputField(self.obj, self.prop, self.widget, self.onBeforeChange) - return None - +# -*- coding: utf-8 -*- + +# *************************************************************************** +# * * +# * Copyright (c) 2017 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD +import PathScripts.PathGeom as PathGeom +import PathScripts.PathLog as PathLog +import PathScripts.PathUtil as PathUtil +import PySide + + +__title__ = "Path UI helper and utility functions" +__author__ = "sliptonic (Brad Collette)" +__url__ = "http://www.freecadweb.org" +__doc__ = "A collection of helper and utility functions for the Path GUI." + +def translate(context, text, disambig=None): + return PySide.QtCore.QCoreApplication.translate(context, text, disambig) + +LOGLEVEL = False + +if LOGLEVEL: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + + +def updateInputField(obj, prop, widget, onBeforeChange=None): + '''updateInputField(obj, prop, widget) ... update obj's property prop with the value of widget. + The property's value is only assigned if the new value differs from the current value. + This prevents onChanged notifications where the value didn't actually change. + Gui::InputField and Gui::QuantitySpinBox widgets are supported - and the property can + be of type Quantity or Float. + If onBeforeChange is specified it is called before a new value is assigned to the property. + Returns True if a new value was assigned, False otherwise (new value is the same as the current). + ''' + value = FreeCAD.Units.Quantity(widget.text()).Value + attr = PathUtil.getProperty(obj, prop) + attrValue = attr.Value if hasattr(attr, 'Value') else attr + + isDiff = False + if not PathGeom.isRoughly(attrValue, value): + isDiff = True + else: + if hasattr(obj, 'ExpressionEngine'): + noExpr = True + for (prp, expr) in obj.ExpressionEngine: + if prp == prop: + noExpr = False + PathLog.debug('prop = "expression": {} = "{}"'.format(prp, expr)) + value = FreeCAD.Units.Quantity(obj.evalExpression(expr)).Value + if not PathGeom.isRoughly(attrValue, value): + isDiff = True + break + if noExpr: + widget.setReadOnly(False) + widget.setStyleSheet("color: black") + else: + widget.setReadOnly(True) + widget.setStyleSheet("color: gray") + widget.update() + + if isDiff: + PathLog.debug("updateInputField(%s, %s): %.2f -> %.2f" % (obj.Label, prop, attr, value)) + if onBeforeChange: + onBeforeChange(obj) + PathUtil.setProperty(obj, prop, value) + return True + + return False + + +class QuantitySpinBox: + '''Controller class to interface a Gui::QuantitySpinBox. + The spin box gets bound to a given property and supports update in both directions. + QuatitySpinBox(widget, obj, prop, onBeforeChange=None) + widget ... expected to be reference to a Gui::QuantitySpinBox + obj ... document object + prop ... canonical name of the (sub-) property + onBeforeChange ... an optional callback being executed before the value of the property is changed + ''' + + def __init__(self, widget, obj, prop, onBeforeChange=None): + self.obj = obj + self.widget = widget + self.prop = prop + self.onBeforeChange = onBeforeChange + + attr = PathUtil.getProperty(self.obj, self.prop) + if attr is not None: + if hasattr(attr, 'Value'): + widget.setProperty('unit', attr.getUserPreferred()[2]) + widget.setProperty('binding', "%s.%s" % (obj.Name, prop)) + self.valid = True + else: + PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label)) + self.valid = False + + def expression(self): + '''expression() ... returns the expression if one is bound to the property''' + if self.valid: + return self.widget.property('expression') + return '' + + def setMinimum(self, quantity): + if self.valid: + value = quantity.Value if hasattr(quantity, 'Value') else quantity + self.widget.setProperty('setMinimum', value) + + def updateSpinBox(self, quantity=None): + '''updateSpinBox(quantity=None) ... update the display value of the spin box. + If no value is provided the value of the bound property is used. + quantity can be of type Quantity or Float.''' + if self.valid: + if quantity is None: + quantity = PathUtil.getProperty(self.obj, self.prop) + value = quantity.Value if hasattr(quantity, 'Value') else quantity + self.widget.setProperty('rawValue', value) + + def updateProperty(self): + '''updateProperty() ... update the bound property with the value from the spin box''' + if self.valid: + return updateInputField(self.obj, self.prop, self.widget, self.onBeforeChange) + return None diff --git a/src/Mod/Path/PathScripts/PathOpGui.py b/src/Mod/Path/PathScripts/PathOpGui.py index 4a792322d3..9a8a100810 100644 --- a/src/Mod/Path/PathScripts/PathOpGui.py +++ b/src/Mod/Path/PathScripts/PathOpGui.py @@ -157,8 +157,6 @@ class ViewProvider(object): else: return ":/icons/Path-OpActive.svg" - #return self.OpIcon - def getTaskPanelOpPage(self, obj): '''getTaskPanelOpPage(obj) ... use the stored information to instantiate the receiver op's page controller.''' mod = importlib.import_module(self.OpPageModule) @@ -190,6 +188,7 @@ class ViewProvider(object): action.triggered.connect(self.setEdit) menu.addAction(action) + class TaskPanelPage(object): '''Base class for all task panel pages.''' @@ -377,7 +376,7 @@ class TaskPanelPage(object): combo.clear() combo.addItems(options) combo.blockSignals(False) - + if hasattr(obj, 'CoolantMode'): self.selectInComboBox(obj.CoolantMode, combo) @@ -704,10 +703,13 @@ class TaskPanelDepthsPage(TaskPanelPage): def haveStartDepth(self): return PathOp.FeatureDepths & self.features + def haveFinalDepth(self): return PathOp.FeatureDepths & self.features and not PathOp.FeatureNoFinalDepth & self.features + def haveFinishDepth(self): return PathOp.FeatureDepths & self.features and PathOp.FeatureFinishDepth & self.features + def haveStepDown(self): return PathOp.FeatureStepDown & self. features From 4ed4e2d496e6fd580356fac8624d813c2b780c3a Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Mon, 24 Feb 2020 23:46:42 -0600 Subject: [PATCH 41/62] Draft: unit tests registered in Init.py This means that now the unit tests will run from the console mode when using ``` FreeCADCmd -t 0 FreeCAD --console -t 0 ``` This will allow us to catch errors more easily, as we separate better the behavior of non-GUI and GUI-required modules. Also small spacing fixes and position of the license. --- src/Mod/Draft/Init.py | 63 ++++++++++++++++++++------------------ src/Mod/Draft/InitGui.py | 2 -- src/Mod/Draft/TestDraft.py | 18 +++++------ 3 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/Mod/Draft/Init.py b/src/Mod/Draft/Init.py index 47d60d6f63..8798db3f9e 100644 --- a/src/Mod/Draft/Init.py +++ b/src/Mod/Draft/Init.py @@ -1,31 +1,36 @@ -#*************************************************************************** -#* Copyright (c) 2009 Yorik van Havre * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** +# *************************************************************************** +# * Copyright (c) 2009 Yorik van Havre * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Initialization file of the workbench, non-GUI.""" + +import FreeCAD as App # add Import/Export types -App.addImportType("Autodesk DXF 2D (*.dxf)","importDXF") -App.addImportType("SVG as geometry (*.svg)","importSVG") -App.addImportType("Open CAD Format (*.oca *.gcad)","importOCA") -App.addImportType("Common airfoil data (*.dat)","importAirfoilDAT") -App.addExportType("Autodesk DXF 2D (*.dxf)","importDXF") -App.addExportType("Flattened SVG (*.svg)","importSVG") -App.addExportType("Open CAD Format (*.oca)","importOCA") -App.addImportType("Autodesk DWG 2D (*.dwg)","importDWG") -App.addExportType("Autodesk DWG 2D (*.dwg)","importDWG") +App.addImportType("Autodesk DXF 2D (*.dxf)", "importDXF") +App.addImportType("SVG as geometry (*.svg)", "importSVG") +App.addImportType("Open CAD Format (*.oca *.gcad)", "importOCA") +App.addImportType("Common airfoil data (*.dat)", "importAirfoilDAT") +App.addExportType("Autodesk DXF 2D (*.dxf)", "importDXF") +App.addExportType("Flattened SVG (*.svg)", "importSVG") +App.addExportType("Open CAD Format (*.oca)", "importOCA") +App.addImportType("Autodesk DWG 2D (*.dwg)", "importDWG") +App.addExportType("Autodesk DWG 2D (*.dwg)", "importDWG") + +App.__unit_test__ += ["TestDraft"] diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index ee9cc8f248..252268ee01 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -174,5 +174,3 @@ FreeCADGui.addPreferencePage(":/ui/preferences-dxf.ui", QT_TRANSLATE_NOOP("Draft FreeCADGui.addPreferencePage(":/ui/preferences-dwg.ui", QT_TRANSLATE_NOOP("Draft", "Import-Export")) FreeCADGui.addPreferencePage(":/ui/preferences-svg.ui", QT_TRANSLATE_NOOP("Draft", "Import-Export")) FreeCADGui.addPreferencePage(":/ui/preferences-oca.ui", QT_TRANSLATE_NOOP("Draft", "Import-Export")) - -FreeCAD.__unit_test__ += ["TestDraft"] diff --git a/src/Mod/Draft/TestDraft.py b/src/Mod/Draft/TestDraft.py index 0c9c096544..092d436d45 100644 --- a/src/Mod/Draft/TestDraft.py +++ b/src/Mod/Draft/TestDraft.py @@ -1,12 +1,3 @@ -"""Unit tests for the Draft workbench. - -From the terminal, run the following: -FreeCAD -t TestDraft - -From within FreeCAD, run the following: -import Test, TestDraft -Test.runTestsFromModule(TestDraft) -""" # *************************************************************************** # * Copyright (c) 2013 Yorik van Havre * # * Copyright (c) 2019 Eliud Cabrera Castillo * @@ -30,6 +21,15 @@ Test.runTestsFromModule(TestDraft) # * USA * # * * # *************************************************************************** +"""Unit tests for the Draft workbench. + +From the terminal, run the following: +FreeCAD -t TestDraft + +From within FreeCAD, run the following: +import Test, TestDraft +Test.runTestsFromModule(TestDraft) +""" # =========================================================================== # The unit tests can be run from the operating system terminal, or from From b74841a5b117c2257ae48ae1a89a5203471bebd3 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Fri, 28 Feb 2020 00:51:14 -0600 Subject: [PATCH 42/62] Draft: Coin (Pivy) tests only when the graphical interface is up --- src/Mod/Draft/drafttests/test_pivy.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Mod/Draft/drafttests/test_pivy.py b/src/Mod/Draft/drafttests/test_pivy.py index 4a9e0fb1ed..41d28908b5 100644 --- a/src/Mod/Draft/drafttests/test_pivy.py +++ b/src/Mod/Draft/drafttests/test_pivy.py @@ -25,7 +25,6 @@ import unittest import FreeCAD as App -import FreeCADGui as Gui import drafttests.auxiliary as aux from draftutils.messages import _msg @@ -53,6 +52,10 @@ class DraftPivy(unittest.TestCase): def test_pivy_import(self): """Import Coin (Pivy).""" module = "pivy.coin" + if not App.GuiUp: + aux._no_gui(module) + self.assertTrue(True) + return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) @@ -64,8 +67,9 @@ class DraftPivy(unittest.TestCase): self.assertTrue(True) return - import pivy.coin - cube = pivy.coin.SoCube() + import FreeCADGui as Gui + import pivy.coin as coin + cube = coin.SoCube() _msg(" Draw cube") Gui.ActiveDocument.ActiveView.getSceneGraph().addChild(cube) _msg(" Adding cube to the active view scene") From d40bf0d5e82cc36ca2a27854202ed1fd9ca12382 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 10 Mar 2020 18:14:36 -0600 Subject: [PATCH 43/62] Draft: moved some unit tests to TestDraftGui Those unit tests that are registered in `Init.py` will always run, while those that are registerd in `InitGui.py` will only run when the graphical interface is available. This allows us to more clearly distinguish functions that should be able to run always, from those that may run only when the interfce is available. --- src/Mod/Draft/CMakeLists.txt | 1 + src/Mod/Draft/InitGui.py | 2 + src/Mod/Draft/TestDraft.py | 24 ++-- src/Mod/Draft/TestDraftGui.py | 105 ++++++++++++++++++ src/Mod/Draft/drafttests/test_import_gui.py | 17 --- src/Mod/Draft/drafttests/test_import_tools.py | 21 ---- src/Mod/Draft/drafttests/test_pivy.py | 12 +- 7 files changed, 119 insertions(+), 63 deletions(-) create mode 100644 src/Mod/Draft/TestDraftGui.py diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 37658b24c4..12857548f5 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -17,6 +17,7 @@ SET(Draft_SRCS_base WorkingPlane.py getSVG.py TestDraft.py + TestDraftGui.py ) SET(Draft_import diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index 252268ee01..1141e911dd 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -174,3 +174,5 @@ FreeCADGui.addPreferencePage(":/ui/preferences-dxf.ui", QT_TRANSLATE_NOOP("Draft FreeCADGui.addPreferencePage(":/ui/preferences-dwg.ui", QT_TRANSLATE_NOOP("Draft", "Import-Export")) FreeCADGui.addPreferencePage(":/ui/preferences-svg.ui", QT_TRANSLATE_NOOP("Draft", "Import-Export")) FreeCADGui.addPreferencePage(":/ui/preferences-oca.ui", QT_TRANSLATE_NOOP("Draft", "Import-Export")) + +FreeCAD.__unit_test__ += ["TestDraftGui"] diff --git a/src/Mod/Draft/TestDraft.py b/src/Mod/Draft/TestDraft.py index 092d436d45..d585a9fa75 100644 --- a/src/Mod/Draft/TestDraft.py +++ b/src/Mod/Draft/TestDraft.py @@ -21,7 +21,7 @@ # * USA * # * * # *************************************************************************** -"""Unit tests for the Draft workbench. +"""Unit tests for the Draft workbench, non-GUI only. From the terminal, run the following: FreeCAD -t TestDraft @@ -29,6 +29,8 @@ FreeCAD -t TestDraft From within FreeCAD, run the following: import Test, TestDraft Test.runTestsFromModule(TestDraft) + +For the GUI-only tests see TestDraftGui. """ # =========================================================================== @@ -94,20 +96,17 @@ Test.runTestsFromModule(TestDraft) # Import tests from drafttests.test_import import DraftImport as DraftTest01 -from drafttests.test_import_gui import DraftGuiImport as DraftTest02 -from drafttests.test_import_tools import DraftImportTools as DraftTest03 -from drafttests.test_pivy import DraftPivy as DraftTest04 # Objects tests -from drafttests.test_creation import DraftCreation as DraftTest05 -from drafttests.test_modification import DraftModification as DraftTest06 +from drafttests.test_creation import DraftCreation as DraftTest02 +from drafttests.test_modification import DraftModification as DraftTest03 # Handling of file formats tests -from drafttests.test_svg import DraftSVG as DraftTest07 -from drafttests.test_dxf import DraftDXF as DraftTest08 -from drafttests.test_dwg import DraftDWG as DraftTest09 -from drafttests.test_oca import DraftOCA as DraftTest10 -from drafttests.test_airfoildat import DraftAirfoilDAT as DraftTest11 +from drafttests.test_svg import DraftSVG as DraftTest04 +from drafttests.test_dxf import DraftDXF as DraftTest05 +from drafttests.test_dwg import DraftDWG as DraftTest06 +from drafttests.test_oca import DraftOCA as DraftTest07 +from drafttests.test_airfoildat import DraftAirfoilDAT as DraftTest08 # Use the modules so that code checkers don't complain (flake8) True if DraftTest01 else False @@ -118,6 +117,3 @@ True if DraftTest05 else False True if DraftTest06 else False True if DraftTest07 else False True if DraftTest08 else False -True if DraftTest09 else False -True if DraftTest10 else False -True if DraftTest11 else False diff --git a/src/Mod/Draft/TestDraftGui.py b/src/Mod/Draft/TestDraftGui.py new file mode 100644 index 0000000000..268a0502e2 --- /dev/null +++ b/src/Mod/Draft/TestDraftGui.py @@ -0,0 +1,105 @@ +# *************************************************************************** +# * Copyright (c) 2013 Yorik van Havre * +# * Copyright (c) 2020 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Unit tests for the Draft workbench, GUI only. + +From the terminal, run the following: +FreeCAD -t TestDraftGui + +From within FreeCAD, run the following: +import Test, TestDraftGui +Test.runTestsFromModule(TestDraftGui) + +For the non-GUI tests see TestDraft. +""" + +# =========================================================================== +# The unit tests can be run from the operating system terminal, or from +# within FreeCAD itself. +# +# The tests can be run using the full 'FreeCAD' executable +# or the console only 'FreeCADCmd' executable. In the latter case +# some functions cannot be tested as the view providers (visual properties) +# are not available. +# +# =========================================================================== +# In the following, first the command to run the test from the operating +# system terminal is listed, followed by the commands to run the test +# from the Python console within FreeCAD. +# +# =========================================================================== +# Run all Draft tests +# ---- +# FreeCAD -t TestDraft +# +# >>> import Test, TestDraft +# >>> Test.runTestsFromModule(TestDraft) +# +# =========================================================================== +# Run tests from a specific module (all classes within this module) +# ---- +# FreeCAD -t drafttests.test_creation +# +# >>> import Test, drafttests.test_creation +# >>> Test.runTestsFromModule(drafttests.test_creation) +# +# =========================================================================== +# Run tests from a specific class within a module +# ---- +# FreeCAD -t drafttests.test_creation.DraftCreation +# +# >>> import Test, drafttests.test_creation +# >>> Test.runTestsFromClass(drafttests.test_creation.DraftCreation) +# +# =========================================================================== +# Run a specific unit test from a class within a module +# ---- +# FreeCAD -t drafttests.test_creation.DraftCreation.test_line +# +# >>> import unittest +# >>> one_test = "drafttests.test_creation.DraftCreation.test_line" +# >>> all_tests = unittest.TestLoader().loadTestsFromName(one_test) +# >>> unittest.TextTestRunner().run(all_tests) + +# =========================================================================== +# When the full test is run +# FreeCAD -t TestDraft +# +# all classes that are found in this file are run. +# +# We import the classes from submodules. These classes contain +# the actual unit tests. +# +# The classes will be run in alphabetical order. So, to force +# a particular order of testing we import them with a name +# that follows a defined alphanumeric sequence. + +# Import tests +from drafttests.test_import_gui import DraftGuiImport as DraftTestGui01 +from drafttests.test_import_tools import DraftImportTools as DraftTestGui02 +from drafttests.test_pivy import DraftPivy as DraftTestGui03 + +# Use the modules so that code checkers don't complain (flake8) +True if DraftTestGui01 else False +True if DraftTestGui02 else False +True if DraftTestGui03 else False diff --git a/src/Mod/Draft/drafttests/test_import_gui.py b/src/Mod/Draft/drafttests/test_import_gui.py index decec80ac7..5576f60826 100644 --- a/src/Mod/Draft/drafttests/test_import_gui.py +++ b/src/Mod/Draft/drafttests/test_import_gui.py @@ -24,7 +24,6 @@ """Unit test for the Draft Workbench, GUI import tests.""" import unittest -import FreeCAD as App import drafttests.auxiliary as aux @@ -39,39 +38,23 @@ class DraftGuiImport(unittest.TestCase): def test_import_gui_draftgui(self): """Import Draft TaskView GUI tools.""" module = "DraftGui" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_import_gui_draft_snap(self): """Import Draft snapping.""" module = "draftguitools.gui_snapper" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_import_gui_draft_tools(self): """Import Draft graphical commands.""" module = "DraftTools" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_import_gui_draft_trackers(self): """Import Draft tracker utilities.""" module = "draftguitools.gui_trackers" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) diff --git a/src/Mod/Draft/drafttests/test_import_tools.py b/src/Mod/Draft/drafttests/test_import_tools.py index 1232da5ef0..5827f7a75b 100644 --- a/src/Mod/Draft/drafttests/test_import_tools.py +++ b/src/Mod/Draft/drafttests/test_import_tools.py @@ -24,7 +24,6 @@ """Unit test for the Draft Workbench, tools import tests.""" import unittest -import FreeCAD as App import drafttests.auxiliary as aux @@ -39,49 +38,29 @@ class DraftImportTools(unittest.TestCase): def test_import_gui_draftedit(self): """Import Draft Edit.""" module = "draftguitools.gui_edit" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_import_gui_draftfillet(self): """Import Draft Fillet.""" module = "DraftFillet" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_import_gui_draftlayer(self): """Import Draft Layer.""" module = "DraftLayer" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_import_gui_draftplane(self): """Import Draft SelectPlane.""" module = "draftguitools.gui_selectplane" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_import_gui_workingplane(self): """Import Draft WorkingPlane.""" module = "WorkingPlane" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) diff --git a/src/Mod/Draft/drafttests/test_pivy.py b/src/Mod/Draft/drafttests/test_pivy.py index 41d28908b5..c099b91d9a 100644 --- a/src/Mod/Draft/drafttests/test_pivy.py +++ b/src/Mod/Draft/drafttests/test_pivy.py @@ -25,6 +25,7 @@ import unittest import FreeCAD as App +import FreeCADGui as Gui import drafttests.auxiliary as aux from draftutils.messages import _msg @@ -52,22 +53,11 @@ class DraftPivy(unittest.TestCase): def test_pivy_import(self): """Import Coin (Pivy).""" module = "pivy.coin" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return imported = aux._import_test(module) self.assertTrue(imported, "Problem importing '{}'".format(module)) def test_pivy_draw(self): """Use Coin (pivy.coin) to draw a cube on the active view.""" - module = "pivy.coin" - if not App.GuiUp: - aux._no_gui(module) - self.assertTrue(True) - return - - import FreeCADGui as Gui import pivy.coin as coin cube = coin.SoCube() _msg(" Draw cube") From c6743999ec485e80c7260701e2b13bba52463abf Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 5 Mar 2020 00:13:24 -0600 Subject: [PATCH 44/62] Draft: utils, add function to log calls --- src/Mod/Draft/draftutils/utils.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Mod/Draft/draftutils/utils.py b/src/Mod/Draft/draftutils/utils.py index bb747008e4..b13d3e3d87 100644 --- a/src/Mod/Draft/draftutils/utils.py +++ b/src/Mod/Draft/draftutils/utils.py @@ -38,7 +38,7 @@ from PySide import QtCore import FreeCAD import Draft_rc -from draftutils.messages import _msg +from draftutils.messages import _msg, _log from draftutils.translate import _tr App = FreeCAD @@ -1019,3 +1019,29 @@ def utf8_decode(text): return text.decode("utf-8") except AttributeError: return text + + +def print_header(name, description, debug=True): + """Print a line to the console when something is called, and log it. + + Parameters + ---------- + name: str + The name of the function or class that is being called. + This `name` will be logged in the log file, so if there are problems + the log file can be investigated for clues. + + description: str + Arbitrary text that will be printed to the console + when the function or class is called. + + debug: bool, optional + It defaults to `True`. + If it is `False` the `description` will not be printed + to the console. + On the other hand the `name` will always be logged. + """ + _log(name) + if debug: + _msg(16 * "-") + _msg(description) From 144ecfce89418ff371dc89aff668e188b40defe5 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 3 Mar 2020 21:49:13 -0600 Subject: [PATCH 45/62] Draft: arc_3points, clean up imports and checks --- src/Mod/Draft/draftobjects/arc_3points.py | 68 +++++++++++++++-------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/src/Mod/Draft/draftobjects/arc_3points.py b/src/Mod/Draft/draftobjects/arc_3points.py index 9dc7e45dad..b386591544 100644 --- a/src/Mod/Draft/draftobjects/arc_3points.py +++ b/src/Mod/Draft/draftobjects/arc_3points.py @@ -1,8 +1,3 @@ -"""Provides the object code for Draft Arc_3Points.""" -## @package arc_3points -# \ingroup DRAFT -# \brief Provides the object code for Draft Arc_3Points. - # *************************************************************************** # * (c) 2020 Eliud Cabrera Castillo * # * * @@ -25,14 +20,21 @@ # * USA * # * * # *************************************************************************** +"""Provides the object code for Draft Arc_3Points.""" +## @package arc_3points +# \ingroup DRAFT +# \brief Provides the object code for Draft Arc_3Points. + import math + import FreeCAD as App import Part import Draft -from draftutils.messages import _msg, _err, _log +import draftutils.utils as utils +from draftutils.messages import _msg, _err from draftutils.translate import _tr -if App.GuiUp: - import draftutils.gui_utils as gui_utils + +import draftutils.gui_utils as gui_utils def make_arc_3points(points, placement=None, face=False, @@ -109,40 +111,62 @@ def make_arc_3points(points, placement=None, face=False, Normally it returns a parametric Draft object (`Part::Part2DObject`). If `primitive` is `True`, it returns a basic `Part::Feature`. """ - _log("make_arc_3points") - _msg(16 * "-") - _msg(_tr("Arc by 3 points")) + _name = "make_arc_3points" + utils.print_header(_name, "Arc by 3 points") - if not isinstance(points, (list, tuple)): - _err(_tr("Wrong input: must be list or tuple of three points.")) + try: + utils.type_check([(points, (list, tuple))], name=_name) + except TypeError: + _err(_tr("Points: ") + "{}".format(points)) + _err(_tr("Wrong input: " + "must be list or tuple of three points exactly.")) return None if len(points) != 3: - _err(_tr("Wrong input: must be three points.")) + _err(_tr("Points: ") + "{}".format(points)) + _err(_tr("Wrong input: " + "must be list or tuple of three points exactly.")) return None if placement is not None: - if not isinstance(placement, App.Placement): - _err(_tr("Wrong input: incorrect placement")) + try: + utils.type_check([(placement, App.Placement)], name=_name) + except TypeError: + _err(_tr("Placement: ") + "{}".format(placement)) + _err(_tr("Wrong input: incorrect type of placement.")) return None p1, p2, p3 = points - _edge = Part.Arc(p1, p2, p3) + _msg("p1: {}".format(p1)) + _msg("p2: {}".format(p2)) + _msg("p3: {}".format(p3)) + + try: + utils.type_check([(p1, App.Vector), + (p2, App.Vector), + (p3, App.Vector)], name=_name) + except TypeError: + _err(_tr("Wrong input: incorrect type of points.")) + return None + + try: + _edge = Part.Arc(p1, p2, p3) + except Part.OCCError as error: + _err(_tr("Cannot generate shape: ") + "{}".format(error)) + return None + edge = _edge.toShape() radius = edge.Curve.Radius center = edge.Curve.Center - _msg("p1: {}".format(p1)) - _msg("p2: {}".format(p2)) - _msg("p3: {}".format(p3)) _msg(_tr("Radius: ") + "{}".format(radius)) _msg(_tr("Center: ") + "{}".format(center)) if primitive: + _msg(_tr("Create primitive object")) obj = App.ActiveDocument.addObject("Part::Feature", "Arc") obj.Shape = edge - _msg(_tr("Primitive object")) return obj rot = App.Rotation(edge.Curve.XAxis, @@ -168,8 +192,8 @@ def make_arc_3points(points, placement=None, face=False, _msg(_tr("Face: True")) if support: _msg(_tr("Support: ") + "{}".format(support)) - obj.MapMode = map_mode _msg(_tr("Map mode: " + "{}".format(map_mode))) + obj.MapMode = map_mode if placement: obj.AttachmentOffset.Base = placement.Base obj.AttachmentOffset.Rotation = original_placement.Rotation From 65acf43391672f0615cfbd61158226a995b495c8 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 4 Mar 2020 00:16:09 -0600 Subject: [PATCH 46/62] Draft: circulararray, clean up imports, docstrings, and checks --- src/Mod/Draft/Draft.py | 2 +- src/Mod/Draft/draftobjects/circulararray.py | 130 ++++++++++++++++-- src/Mod/Draft/drafttests/test_modification.py | 2 +- 3 files changed, 119 insertions(+), 15 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 1e67841e31..2f0aea0d45 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -714,7 +714,7 @@ def makeArray(baseobject,arg1,arg2,arg3,arg4=None,arg5=None,arg6=None,name="Arra _Array(obj) obj.Base = baseobject if arg6: - if isinstance(arg1, (int, float)): + if isinstance(arg1, (int, float, FreeCAD.Units.Quantity)): obj.ArrayType = "circular" obj.RadialDistance = arg1 obj.TangentialDistance = arg2 diff --git a/src/Mod/Draft/draftobjects/circulararray.py b/src/Mod/Draft/draftobjects/circulararray.py index 803b923b47..621ef8ffbd 100644 --- a/src/Mod/Draft/draftobjects/circulararray.py +++ b/src/Mod/Draft/draftobjects/circulararray.py @@ -1,9 +1,3 @@ -"""This module provides the object code for Draft CircularArray. -""" -## @package circulararray -# \ingroup DRAFT -# \brief This module provides the object code for Draft CircularArray. - # *************************************************************************** # * (c) 2019 Eliud Cabrera Castillo * # * * @@ -26,20 +20,130 @@ # * USA * # * * # *************************************************************************** +"""Provides the object code for Draft CircularArray.""" +## @package circulararray +# \ingroup DRAFT +# \brief This module provides the object code for Draft CircularArray. import FreeCAD as App import Draft +import draftutils.utils as utils +from draftutils.messages import _msg, _err +from draftutils.translate import _tr def make_circular_array(obj, r_distance=100, tan_distance=100, - axis=App.Vector(0, 0, 1), center=App.Vector(0, 0, 0), number=2, symmetry=1, - use_link=False): + axis=App.Vector(0, 0, 1), center=App.Vector(0, 0, 0), + use_link=True): """Create a circular array from the given object. + + Parameters + ---------- + obj: Part::Feature + Any type of object that has a `Part::TopoShape` + that can be duplicated. + + r_distance: float, optional + It defaults to `100`. + Radial distance to the next ring of circular arrays. + + tan_distance: float, optional + It defaults to `100`. + The tangential distance between two elements located + in the same circular ring. + The tangential distance together with the radial distance + determine how many copies are created. + + number: int, optional + It defaults to 2. + The number of layers or rings of repeated objects. + The original object stays at the center, and is counted + as a layer itself. So, if you want at least one layer of circular + copies, this number must be at least 2. + + symmetry: int, optional + It defaults to 1. + It indicates how many lines of symmetry the entire circular pattern + has. That is, with 1, the array is symmetric only after a full + 360 degrees rotation. + + When it is 2, the array is symmetric at 0 and 180 degrees. + When it is 3, the array is symmetric at 0, 120, and 240 degrees. + When it is 4, the array is symmetric at 0, 90, 180, and 270 degrees. + Et cetera. + + axis: Base::Vector3, optional + It defaults to `App.Vector(0, 0, 1)` or the `+Z` axis. + The unit vector indicating the axis of rotation. + + center: Base::Vector3, optional + It defaults to `App.Vector(0, 0, 0)` or the global origin. + The point through which the `axis` passes to define + the axis of rotation. + + use_link: bool, optional + It defaults to `True`. + If it is `True` the produced copies are not `Part::TopoShape` copies, + but rather `App::Link` objects. + The Links repeat the shape of the original `obj` exactly, + and therefore the resulting array is more memory efficient. + + Also, when `use_link` is `True`, the `Fuse` property + of the resulting array does not work; the array doesn't + contain separate shapes, it only has the original shape repeated + many times, so there is nothing to fuse together. + + If `use_link` is `False` the original shape is copied many times. + In this case the `Fuse` property is able to fuse + all copies into a single object, if they touch each other. + + Returns + ------- + Part::FeaturePython + A scripted object with `Proxy.Type='Array'`. + Its `Shape` is a compound of the copies of the original object. """ - obj = Draft.makeArray(obj, - arg1=r_distance, arg2=tan_distance, - arg3=axis, arg4=center, arg5=number, arg6=symmetry, - use_link=use_link) - return obj + _name = "make_circular_array" + utils.print_header(_name, _tr("Circular array")) + + _msg("r_distance: {}".format(r_distance)) + _msg("tan_distance: {}".format(tan_distance)) + + try: + utils.type_check([(r_distance, (int, float, App.Units.Quantity)), + (tan_distance, (int, float, App.Units.Quantity))], + name=_name) + except TypeError: + _err(_tr("Wrong input: must be a number or quantity.")) + return None + + _msg("number: {}".format(number)) + _msg("symmetry: {}".format(symmetry)) + + try: + utils.type_check([(number, int), + (symmetry, int)], name=_name) + except TypeError: + _err(_tr("Wrong input: must be an integer number.")) + return None + + _msg("axis: {}".format(axis)) + _msg("center: {}".format(center)) + + try: + utils.type_check([(axis, App.Vector), + (center, App.Vector)], name=_name) + except TypeError: + _err(_tr("Wrong input: must be a vector.")) + return None + + _msg("use_link: {}".format(bool(use_link))) + + new_obj = Draft.makeArray(obj, + arg1=r_distance, arg2=tan_distance, + arg3=axis, arg4=center, + arg5=number, arg6=symmetry, + use_link=use_link) + return new_obj diff --git a/src/Mod/Draft/drafttests/test_modification.py b/src/Mod/Draft/drafttests/test_modification.py index 3de9fbbb56..d9537883ea 100644 --- a/src/Mod/Draft/drafttests/test_modification.py +++ b/src/Mod/Draft/drafttests/test_modification.py @@ -433,9 +433,9 @@ class DraftModification(unittest.TestCase): _msg(" Array") _msg(" radial_distance={0}, " "tangential_distance={1}".format(rad_distance, tan_distance)) + _msg(" number={0}, symmetry={1}".format(number, symmetry)) _msg(" axis={}".format(axis)) _msg(" center={}".format(center)) - _msg(" number={0}, symmetry={1}".format(number, symmetry)) obj = Draft.makeArray(rect, rad_distance, tan_distance, axis, center, From af46040e683c98f712963d3daf2098e6c58bd1dc Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 4 Mar 2020 13:51:24 -0600 Subject: [PATCH 47/62] Draft: orthoarray, clean up imports, docstrings, and checks --- src/Mod/Draft/draftobjects/orthoarray.py | 268 +++++++++++++++++++++-- 1 file changed, 244 insertions(+), 24 deletions(-) diff --git a/src/Mod/Draft/draftobjects/orthoarray.py b/src/Mod/Draft/draftobjects/orthoarray.py index e1193fda8d..d87146a36b 100644 --- a/src/Mod/Draft/draftobjects/orthoarray.py +++ b/src/Mod/Draft/draftobjects/orthoarray.py @@ -1,8 +1,3 @@ -"""Provide the object code for Draft Array.""" -## @package orthoarray -# \ingroup DRAFT -# \brief Provide the object code for Draft Array. - # *************************************************************************** # * (c) 2020 Eliud Cabrera Castillo * # * * @@ -25,9 +20,16 @@ # * USA * # * * # *************************************************************************** +"""Provide the object code for Draft Array.""" +## @package orthoarray +# \ingroup DRAFT +# \brief Provide the object code for Draft Array. import FreeCAD as App import Draft +import draftutils.utils as utils +from draftutils.messages import _msg, _wrn, _err +from draftutils.translate import _tr def make_ortho_array(obj, @@ -37,24 +39,242 @@ def make_ortho_array(obj, n_x=2, n_y=2, n_z=1, - use_link=False): - """Create an orthogonal array from the given object.""" - obj = Draft.makeArray(obj, - arg1=v_x, arg2=v_y, arg3=v_z, - arg4=n_x, arg5=n_y, arg6=n_z, - use_link=use_link) - return obj + use_link=True): + """Create an orthogonal array from the given object. + + Parameters + ---------- + obj: Part::Feature + Any type of object that has a `Part::TopoShape` + that can be duplicated. + This means most 2D and 3D objects produced + with any workbench. + + v_x, v_y, v_z: Base::Vector3, optional + The vector indicating the vector displacement between two elements + in the specified orthogonal direction X, Y, Z. + + By default: + :: + v_x = App.Vector(10, 0, 0) + v_y = App.Vector(0, 10, 0) + v_z = App.Vector(0, 0, 10) + + Given that this is a vectorial displacement + the next object can appear displaced in one, two or three axes + at the same time. + + For example + :: + v_x = App.Vector(10, 5, 0) + + means that the next element in the X direction will be displaced + 10 mm in X, 5 mm in Y, and 0 mm in Z. + + A traditional "rectangular" array is obtained when + the displacement vector only has its corresponding component, + like in the default case. + + If these values are entered as single numbers instead + of vectors, the single value is expanded into a vector + of the corresponding direction, and the other components are assumed + to be zero. + + For example + :: + v_x = 15 + v_y = 10 + v_z = 1 + becomes + :: + v_x = App.Vector(15, 0, 0) + v_y = App.Vector(0, 10, 0) + v_z = App.Vector(0, 0, 1) + + n_x, n_y, n_z: int, optional + The number of copies in the specified orthogonal direction X, Y, Z. + This number includes the original object, therefore, it must be + at least 1. + + The values of `n_x` and `n_y` default to 2, + while `n_z` defaults to 1. + This means the array by default is a planar array. + + use_link: bool, optional + It defaults to `True`. + If it is `True` the produced copies are not `Part::TopoShape` copies, + but rather `App::Link` objects. + The Links repeat the shape of the original `obj` exactly, + and therefore the resulting array is more memory efficient. + + Also, when `use_link` is `True`, the `Fuse` property + of the resulting array does not work; the array doesn't + contain separate shapes, it only has the original shape repeated + many times, so there is nothing to fuse together. + + If `use_link` is `False` the original shape is copied many times. + In this case the `Fuse` property is able to fuse + all copies into a single object, if they touch each other. + + Returns + ------- + Part::FeaturePython + A scripted object with `Proxy.Type='Array'`. + Its `Shape` is a compound of the copies of the original object. + + See Also + -------- + make_ortho_array2d + """ + _name = "make_ortho_array" + utils.print_header(_name, _tr("Orthogonal array")) + + _msg("v_x: {}".format(v_x)) + _msg("v_y: {}".format(v_y)) + _msg("v_z: {}".format(v_z)) + + try: + utils.type_check([(v_x, (int, float, App.Vector)), + (v_y, (int, float, App.Vector)), + (v_z, (int, float, App.Vector))], + name=_name) + except TypeError: + _err(_tr("Wrong input: must be a number or vector.")) + return None + + _text = "Input: single value expanded to vector." + if not isinstance(v_x, App.Vector): + v_x = App.Vector(v_x, 0, 0) + _wrn(_tr(_text)) + if not isinstance(v_y, App.Vector): + v_y = App.Vector(0, v_y, 0) + _wrn(_tr(_text)) + if not isinstance(v_z, App.Vector): + v_z = App.Vector(0, 0, v_z) + _wrn(_tr(_text)) + + _msg("n_x: {}".format(n_x)) + _msg("n_y: {}".format(n_y)) + _msg("n_z: {}".format(n_z)) + + try: + utils.type_check([(n_x, int), + (n_y, int), + (n_z, int)], name=_name) + except TypeError: + _err(_tr("Wrong input: must be an integer number.")) + return None + + _text = ("Input: number of elements must be at least 1. " + "It is set to 1.") + if n_x < 1: + _wrn(_tr(_text)) + n_x = 1 + if n_y < 1: + _wrn(_tr(_text)) + n_y = 1 + if n_z < 1: + _wrn(_tr(_text)) + n_z = 1 + + _msg("use_link: {}".format(bool(use_link))) + + new_obj = Draft.makeArray(obj, + arg1=v_x, arg2=v_y, arg3=v_z, + arg4=n_x, arg5=n_y, arg6=n_z, + use_link=use_link) + return new_obj -def make_ortho_array2(obj, - v_x=App.Vector(10, 0, 0), - v_y=App.Vector(0, 10, 0), - n_x=2, - n_y=2, - use_link=False): - """Create a 2D orthogonal array from the given object.""" - obj = Draft.makeArray(obj, - arg1=v_x, arg2=v_y, - arg3=n_x, arg4=n_y, - use_link=use_link) - return obj +def make_ortho_array2d(obj, + v_x=App.Vector(10, 0, 0), + v_y=App.Vector(0, 10, 0), + n_x=2, + n_y=2, + use_link=True): + """Create a 2D orthogonal array from the given object. + + This works the same as `make_ortho_array`. + The Z component is ignored so it only considers vector displacements + in X and Y directions. + + Parameters + ---------- + obj: Part::Feature + Any type of object that has a `Part::TopoShape` + that can be duplicated. + This means most 2D and 3D objects produced + with any workbench. + + v_x, v_y: Base::Vector3, optional + Vectorial displacement of elements + in the corresponding X and Y directions. + See `make_ortho_array`. + + n_x, n_y: int, optional + Number of elements + in the corresponding X and Y directions. + See `make_ortho_array`. + + use_link: bool, optional + If it is `True`, create `App::Link` array. + See `make_ortho_array`. + + Returns + ------- + Part::FeaturePython + A scripted object with `Proxy.Type='Array'`. + Its `Shape` is a compound of the copies of the original object. + + See Also + -------- + make_ortho_array + """ + _name = "make_ortho_array2d" + utils.print_header(_name, _tr("Orthogonal array 2D")) + + _msg("v_x: {}".format(v_x)) + _msg("v_y: {}".format(v_y)) + + try: + utils.type_check([(v_x, (int, float, App.Vector)), + (v_y, (int, float, App.Vector))], + name=_name) + except TypeError: + _err(_tr("Wrong input: must be a number or vector.")) + return None + + _text = "Input: single value expanded to vector." + if not isinstance(v_x, App.Vector): + v_x = App.Vector(v_x, 0, 0) + _wrn(_tr(_text)) + if not isinstance(v_y, App.Vector): + v_y = App.Vector(0, v_y, 0) + _wrn(_tr(_text)) + + _msg("n_x: {}".format(n_x)) + _msg("n_y: {}".format(n_y)) + + try: + utils.type_check([(n_x, int), + (n_y, int)], name=_name) + except TypeError: + _err(_tr("Wrong input: must be an integer number.")) + return None + + _text = ("Input: number of elements must be at least 1. " + "It is set to 1.") + if n_x < 1: + _wrn(_tr(_text)) + n_x = 1 + if n_y < 1: + _wrn(_tr(_text)) + n_y = 1 + + _msg("use_link: {}".format(bool(use_link))) + + new_obj = Draft.makeArray(obj, + arg1=v_x, arg2=v_y, + arg3=n_x, arg4=n_y, + use_link=use_link) + return new_obj From a749c9419645050273c78edb473e613f6fc3df41 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 4 Mar 2020 19:31:39 -0600 Subject: [PATCH 48/62] Draft: orthoarray, add strictly rectangular arrays --- src/Mod/Draft/draftobjects/orthoarray.py | 138 ++++++++++++++++++++++- 1 file changed, 136 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/draftobjects/orthoarray.py b/src/Mod/Draft/draftobjects/orthoarray.py index d87146a36b..a5fedf693b 100644 --- a/src/Mod/Draft/draftobjects/orthoarray.py +++ b/src/Mod/Draft/draftobjects/orthoarray.py @@ -124,7 +124,7 @@ def make_ortho_array(obj, See Also -------- - make_ortho_array2d + make_ortho_array2d, make_rect_array, make_rect_array2d """ _name = "make_ortho_array" utils.print_header(_name, _tr("Orthogonal array")) @@ -228,7 +228,7 @@ def make_ortho_array2d(obj, See Also -------- - make_ortho_array + make_ortho_array, make_rect_array, make_rect_array2d """ _name = "make_ortho_array2d" utils.print_header(_name, _tr("Orthogonal array 2D")) @@ -278,3 +278,137 @@ def make_ortho_array2d(obj, arg3=n_x, arg4=n_y, use_link=use_link) return new_obj + + +def make_rect_array(obj, + d_x=10, + d_y=10, + d_z=10, + n_x=2, + n_y=2, + n_z=1, + use_link=True): + """Create a rectangular array from the given object. + + This function wraps around `make_ortho_array` + to produce strictly rectangular arrays, in which + the displacement vectors `v_x`, `v_y`, and `v_z` + only have their respective components in X, Y, and Z. + + Parameters + ---------- + obj: Part::Feature + Any type of object that has a `Part::TopoShape` + that can be duplicated. + This means most 2D and 3D objects produced + with any workbench. + + d_x, d_y, d_z: Base::Vector3, optional + Displacement of elements in the corresponding X, Y, and Z directions. + + n_x, n_y, n_z: int, optional + Number of elements in the corresponding X, Y, and Z directions. + + use_link: bool, optional + If it is `True`, create `App::Link` array. + See `make_ortho_array`. + + Returns + ------- + Part::FeaturePython + A scripted object with `Proxy.Type='Array'`. + Its `Shape` is a compound of the copies of the original object. + + See Also + -------- + make_ortho_array, make_ortho_array2d, make_rect_array2d + """ + _name = "make_rect_array" + utils.print_header(_name, _tr("Rectangular array")) + + _msg("d_x: {}".format(d_x)) + _msg("d_y: {}".format(d_y)) + _msg("d_z: {}".format(d_z)) + + try: + utils.type_check([(d_x, (int, float)), + (d_y, (int, float)), + (d_z, (int, float))], + name=_name) + except TypeError: + _err(_tr("Wrong input: must be a number.")) + return None + + new_obj = make_ortho_array(obj, + v_x=App.Vector(d_x, 0, 0), + v_y=App.Vector(0, d_y, 0), + v_z=App.Vector(0, 0, d_z), + n_x=n_x, + n_y=n_y, + n_z=n_z, + use_link=use_link) + return new_obj + + +def make_rect_array2d(obj, + d_x=10, + d_y=10, + n_x=2, + n_y=2, + use_link=True): + """Create a 2D rectangular array from the given object. + + This function wraps around `make_ortho_array2d` + to produce strictly rectangular arrays, in which + the displacement vectors `v_x` and `v_y` + only have their respective components in X and Y. + + Parameters + ---------- + obj: Part::Feature + Any type of object that has a `Part::TopoShape` + that can be duplicated. + This means most 2D and 3D objects produced + with any workbench. + + d_x, d_y: Base::Vector3, optional + Displacement of elements in the corresponding X and Y directions. + + n_x, n_y: int, optional + Number of elements in the corresponding X and Y directions. + + use_link: bool, optional + If it is `True`, create `App::Link` array. + See `make_ortho_array`. + + Returns + ------- + Part::FeaturePython + A scripted object with `Proxy.Type='Array'`. + Its `Shape` is a compound of the copies of the original object. + + See Also + -------- + make_ortho_array, make_ortho_array2d, make_rect_array + """ + _name = "make_rect_array2d" + utils.print_header(_name, _tr("Rectangular array 2D")) + + _msg("d_x: {}".format(d_x)) + _msg("d_y: {}".format(d_y)) + + try: + utils.type_check([(d_x, (int, float)), + (d_y, (int, float))], + name=_name) + except TypeError: + _err(_tr("Wrong input: must be a number.")) + return None + + new_obj = make_ortho_array2d(obj, + v_x=App.Vector(d_x, 0, 0), + v_y=App.Vector(0, d_y, 0), + n_x=n_x, + n_y=n_y, + use_link=use_link) + return new_obj From 27be059164aa256ce760682283f543c6d40b60b6 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 5 Mar 2020 02:03:12 -0600 Subject: [PATCH 49/62] Draft: polararray, clean up imports, docstrings, and checks --- src/Mod/Draft/draftobjects/polararray.py | 94 +++++++++++++++++++++--- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/src/Mod/Draft/draftobjects/polararray.py b/src/Mod/Draft/draftobjects/polararray.py index 52d1573f73..b7e128245b 100644 --- a/src/Mod/Draft/draftobjects/polararray.py +++ b/src/Mod/Draft/draftobjects/polararray.py @@ -1,9 +1,3 @@ -"""This module provides the object code for Draft PolarArray. -""" -## @package polararray -# \ingroup DRAFT -# \brief This module provides the object code for Draft PolarArray. - # *************************************************************************** # * (c) 2019 Eliud Cabrera Castillo * # * * @@ -26,17 +20,93 @@ # * USA * # * * # *************************************************************************** +"""Provide the object code for Draft PolarArray.""" +## @package polararray +# \ingroup DRAFT +# \brief This module provides the object code for Draft PolarArray. import FreeCAD as App import Draft +import draftutils.utils as utils +from draftutils.messages import _msg, _err +from draftutils.translate import _tr def make_polar_array(obj, - center=App.Vector(0, 0, 0), angle=180, number=4, - use_link=False): + number=4, angle=360, center=App.Vector(0, 0, 0), + use_link=True): """Create a polar array from the given object. + + Parameters + ---------- + obj: Part::Feature + Any type of object that has a `Part::TopoShape` + that can be duplicated. + This means most 2D and 3D objects produced + with any workbench. + + number: int, optional + It defaults to 4. + The number of copies produced in the circular pattern. + + angle: float, optional + It defaults to 360. + The magnitude in degrees swept by the polar pattern. + + center: Base::Vector3, optional + It defaults to the origin `App.Vector(0, 0, 0)`. + The vector indicating the center of rotation of the array. + + use_link: bool, optional + It defaults to `True`. + If it is `True` the produced copies are not `Part::TopoShape` copies, + but rather `App::Link` objects. + The Links repeat the shape of the original `obj` exactly, + and therefore the resulting array is more memory efficient. + + Also, when `use_link` is `True`, the `Fuse` property + of the resulting array does not work; the array doesn't + contain separate shapes, it only has the original shape repeated + many times, so there is nothing to fuse together. + + If `use_link` is `False` the original shape is copied many times. + In this case the `Fuse` property is able to fuse + all copies into a single object, if they touch each other. + + Returns + ------- + Part::FeaturePython + A scripted object with `Proxy.Type='Array'`. + Its `Shape` is a compound of the copies of the original object. """ - obj = Draft.makeArray(obj, - arg1=center, arg2=angle, arg3=number, - use_link=use_link) - return obj + _name = "make_polar_array" + utils.print_header(_name, _tr("Polar array")) + + _msg("Number: {}".format(number)) + _msg("Angle: {}".format(angle)) + _msg("Center: {}".format(center)) + + try: + utils.type_check([(number, int)], name=_name) + except TypeError: + _err(_tr("Wrong input: must be an integer number.")) + return None + + try: + utils.type_check([(angle, (int, float))], name=_name) + except TypeError: + _err(_tr("Wrong input: must be a number.")) + return None + + try: + utils.type_check([(center, App.Vector)], name=_name) + except TypeError: + _err(_tr("Wrong input: must be a vector.")) + return None + + _msg("use_link: {}".format(bool(use_link))) + + new_obj = Draft.makeArray(obj, + arg1=center, arg2=angle, arg3=number, + use_link=use_link) + return new_obj From d7e3ed178e60bc219a895ac71b42dd753ff7e6f3 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 8 Apr 2020 14:34:51 +0200 Subject: [PATCH 50/62] Arch: rebar, allow to make rebars from an edge too --- src/Mod/Arch/ArchRebar.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Mod/Arch/ArchRebar.py b/src/Mod/Arch/ArchRebar.py index 9ce7aceb00..0f4c40f921 100644 --- a/src/Mod/Arch/ArchRebar.py +++ b/src/Mod/Arch/ArchRebar.py @@ -312,9 +312,15 @@ class _Rebar(ArchComponent.Component): .format(obj.Name) ) return - if not obj.Base.Shape.Wires: + if obj.Base.Shape.Faces: FreeCAD.Console.PrintError( - "No Wires in Shape of Base, return without a rebar shape for {}.\n" + "Faces in Shape of Base, return without a rebar shape for {}.\n" + .format(obj.Name) + ) + return + if not obj.Base.Shape.Edges: + FreeCAD.Console.PrintError( + "No Edges in Shape of Base, return without a rebar shape for {}.\n" .format(obj.Name) ) return @@ -342,13 +348,22 @@ class _Rebar(ArchComponent.Component): if hasattr(father,'Shape'): fathershape = father.Shape - wire = obj.Base.Shape.Wires[0] + import Part + # corner cases: + # compound from more Wires + # compound without Wires but with multiple Edges + # Does they make sense? If yes handle them. + # Does it makes sense to handle Shapes with Faces or even Solids? + if not obj.Base.Shape.Wires and len(obj.Base.Shape.Edges) == 1: + wire = Part.Wire(obj.Base.Shape.Edges[0]) + else: + wire = obj.Base.Shape.Wires[0] if hasattr(obj,"Rounding"): #print(obj.Rounding) if obj.Rounding: radius = obj.Rounding * obj.Diameter.Value - import DraftGeomUtils - wire = DraftGeomUtils.filletWire(wire,radius) + from DraftGeomUtils import filletWire + wire = filletWire(wire,radius) bpoint, bvec = self.getBaseAndAxis(wire) if not bpoint: return @@ -382,7 +397,6 @@ class _Rebar(ArchComponent.Component): if length: obj.Length = length pl = obj.Placement - import Part circle = Part.makeCircle(obj.Diameter.Value/2,bpoint,bvec) circle = Part.Wire(circle) try: From 6edcc8e95ad71e7949ef9e21fe9997a8cae82a39 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Wed, 8 Apr 2020 12:14:19 +0200 Subject: [PATCH 51/62] [Mesh] Deviation preference can't be 0 ; fixes #4171 Prevent user to involuntarily set deviation value to 0 which makes FC to lag https://forum.freecadweb.org/viewtopic.php?f=3&t=40214 --- src/Mod/Mesh/Gui/DlgSettingsImportExport.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Mesh/Gui/DlgSettingsImportExport.ui b/src/Mod/Mesh/Gui/DlgSettingsImportExport.ui index 9a0b08c7d0..018fa469f1 100644 --- a/src/Mod/Mesh/Gui/DlgSettingsImportExport.ui +++ b/src/Mod/Mesh/Gui/DlgSettingsImportExport.ui @@ -31,7 +31,7 @@ mm - 0.000000000000000 + 0.000010000000000 100000000.000000000000000 From a5fbf61dea1ab8428078b8e2705fbea91deedf69 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 8 Apr 2020 18:01:13 +0200 Subject: [PATCH 52/62] Base: [skip ci] support of spheres in InventorBuilder --- src/Base/Builder3D.cpp | 7 +++++++ src/Base/Builder3D.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/Base/Builder3D.cpp b/src/Base/Builder3D.cpp index 427e707ddc..58c7403180 100644 --- a/src/Base/Builder3D.cpp +++ b/src/Base/Builder3D.cpp @@ -856,6 +856,13 @@ void InventorBuilder::addCylinder(float radius, float height) << Base::blanks(indent) << "}\n"; } +void InventorBuilder::addSphere(float radius) +{ + result << Base::blanks(indent) << "Sphere {\n" + << Base::blanks(indent) << " radius " << radius << "\n" + << Base::blanks(indent) << "}\n"; +} + void InventorBuilder::addBoundingBox(const Vector3f& pt1, const Vector3f& pt2, short lineWidth, float color_r,float color_g,float color_b) { diff --git a/src/Base/Builder3D.h b/src/Base/Builder3D.h index 8b6800d441..39f936db08 100644 --- a/src/Base/Builder3D.h +++ b/src/Base/Builder3D.h @@ -301,6 +301,7 @@ public: int numUControlPoints, int numVControlPoints, const std::vector& uKnots, const std::vector& vKnots); void addCylinder(float radius, float height); + void addSphere(float radius); //@} /** @name Bounding Box handling */ From 8f2c4e4d6abb40937bed9b99e92bb28769b5afcc Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 8 Apr 2020 18:45:51 +0200 Subject: [PATCH 53/62] Arch: Added Wall Thickness property to Arch Pipes --- src/Mod/Arch/ArchPipe.py | 50 ++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Mod/Arch/ArchPipe.py b/src/Mod/Arch/ArchPipe.py index 12e751c722..6b5923a593 100644 --- a/src/Mod/Arch/ArchPipe.py +++ b/src/Mod/Arch/ArchPipe.py @@ -190,15 +190,17 @@ class _ArchPipe(ArchComponent.Component): pl = obj.PropertiesList if not "Diameter" in pl: - obj.addProperty("App::PropertyLength", "Diameter", "Pipe", QT_TRANSLATE_NOOP("App::Property","The diameter of this pipe, if not based on a profile")) + obj.addProperty("App::PropertyLength", "Diameter", "Pipe", QT_TRANSLATE_NOOP("App::Property","The diameter of this pipe, if not based on a profile")) if not "Length" in pl: - obj.addProperty("App::PropertyLength", "Length", "Pipe", QT_TRANSLATE_NOOP("App::Property","The length of this pipe, if not based on an edge")) + obj.addProperty("App::PropertyLength", "Length", "Pipe", QT_TRANSLATE_NOOP("App::Property","The length of this pipe, if not based on an edge")) if not "Profile" in pl: - obj.addProperty("App::PropertyLink", "Profile", "Pipe", QT_TRANSLATE_NOOP("App::Property","An optional closed profile to base this pipe on")) + obj.addProperty("App::PropertyLink", "Profile", "Pipe", QT_TRANSLATE_NOOP("App::Property","An optional closed profile to base this pipe on")) if not "OffsetStart" in pl: - obj.addProperty("App::PropertyLength", "OffsetStart", "Pipe", QT_TRANSLATE_NOOP("App::Property","Offset from the start point")) + obj.addProperty("App::PropertyLength", "OffsetStart", "Pipe", QT_TRANSLATE_NOOP("App::Property","Offset from the start point")) if not "OffsetEnd" in pl: - obj.addProperty("App::PropertyLength", "OffsetEnd", "Pipe", QT_TRANSLATE_NOOP("App::Property","Offset from the end point")) + obj.addProperty("App::PropertyLength", "OffsetEnd", "Pipe", QT_TRANSLATE_NOOP("App::Property","Offset from the end point")) + if not "WallThickness" in pl: + obj.addProperty("App::PropertyLength", "WallThickness","Pipe", QT_TRANSLATE_NOOP("App::Property","The wall thickness of this pipe, if not based on a profile")) self.Type = "Pipe" def onDocumentRestored(self,obj): @@ -231,7 +233,11 @@ class _ArchPipe(ArchComponent.Component): FreeCAD.Console.PrintError(translate("Arch","Unable to build the profile")+"\n") return # move and rotate the profile to the first point - delta = w.Vertexes[0].Point-p.CenterOfMass + if hasattr(p,"CenterOfMass"): + c = p.CenterOfMass + else: + c = p.BoundBox.Center + delta = w.Vertexes[0].Point-c p.translate(delta) import Draft if Draft.getType(obj.Base) == "BezCurve": @@ -240,12 +246,30 @@ class _ArchPipe(ArchComponent.Component): v1 = w.Vertexes[1].Point-w.Vertexes[0].Point v2 = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(v2,v1) - p.rotate(p.CenterOfMass,rot.Axis,math.degrees(rot.Angle)) + p.rotate(c,rot.Axis,math.degrees(rot.Angle)) + shapes = [] try: - sh = w.makePipeShell([p],True,False,2) + if p.Faces: + for f in p.Faces: + sh = w.makePipeShell([f.OuterWire],True,False,2) + for shw in f.Wires: + if shw.hashCode() != f.OuterWire.hashCode(): + sh2 = w.makePipeShell([shw],True,False,2) + sh = sh.cut(sh2) + shapes.append(sh) + elif p.Wires: + for pw in p.Wires: + sh = w.makePipeShell([pw],True,False,2) + shapes.append(sh) except: FreeCAD.Console.PrintError(translate("Arch","Unable to build the pipe")+"\n") else: + if len(shapes) == 0: + return + elif len(shapes) == 1: + sh = shapes[0] + else: + sh = Part.makeCompound(shapes) obj.Shape = sh if obj.Base: obj.Length = w.Length @@ -279,17 +303,19 @@ class _ArchPipe(ArchComponent.Component): if not obj.Profile.getLinkedObject().isDerivedFrom("Part::Part2DObject"): FreeCAD.Console.PrintError(translate("Arch","The profile is not a 2D Part")+"\n") return - if len(obj.Profile.Shape.Wires) != 1: - FreeCAD.Console.PrintError(translate("Arch","Too many wires in the profile")+"\n") - return if not obj.Profile.Shape.Wires[0].isClosed(): FreeCAD.Console.PrintError(translate("Arch","The profile is not closed")+"\n") return - p = obj.Profile.Shape.Wires[0] + p = obj.Profile.Shape else: if obj.Diameter.Value == 0: return p = Part.Wire([Part.Circle(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),obj.Diameter.Value/2).toShape()]) + if obj.WallThickness.Value and (obj.WallThickness.Value < obj.Diameter.Value/2): + p2 = Part.Wire([Part.Circle(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),(obj.Diameter.Value/2-obj.WallThickness.Value)).toShape()]) + p = Part.Face(p) + p2 = Part.Face(p2) + p = p.cut(p2) return p From 595bfdabf53a2fa61f90e1b0ea6b4a5d8921fbd6 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 8 Apr 2020 18:55:49 +0200 Subject: [PATCH 54/62] Arch: Ability to add windows presets --- src/Mod/Arch/ArchWindow.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 9448d2173a..9fe8773919 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -784,6 +784,15 @@ class _CommandWindow: self.librarypresets.append([wtype+" - "+subtype+" - "+os.path.splitext(subfile)[0],os.path.join(subdir,subfile)]) else: librarypath = None + # check for existing presets + presetdir = os.path.join(FreeCAD.getUserAppDataDir(),"Arch") + for tp in ["Windows","Doors"]: + wdir = os.path.join(presetdir,tp) + if os.path.exists(wdir): + for wfile in os.listdir(wdir): + if wfile.lower().endswith(".fcstd"): + self.librarypresets.append([tp[:-1]+" - "+wfile[:-6],wfile]) + # presets box labelp = QtGui.QLabel(translate("Arch","Preset")) From 2cfb124ac62b06c4c3ae8fee3d6e0a7edc7ad2c4 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Tue, 7 Apr 2020 11:30:57 -0400 Subject: [PATCH 55/62] [TD]dialog for Detail #4221 --- src/Mod/TechDraw/App/DrawUtil.cpp | 7 + src/Mod/TechDraw/App/DrawUtil.h | 1 + src/Mod/TechDraw/App/DrawViewDetail.cpp | 2 - src/Mod/TechDraw/Gui/CMakeLists.txt | 9 + src/Mod/TechDraw/Gui/Command.cpp | 2770 ++++++++--------- src/Mod/TechDraw/Gui/QGIGhostHighlight.cpp | 115 + src/Mod/TechDraw/Gui/QGIGhostHighlight.h | 66 + src/Mod/TechDraw/Gui/QGIHighlight.cpp | 59 +- src/Mod/TechDraw/Gui/QGIHighlight.h | 16 +- src/Mod/TechDraw/Gui/QGIUserTypes.h | 46 +- src/Mod/TechDraw/Gui/QGIView.h | 11 +- src/Mod/TechDraw/Gui/Rez.cpp | 6 + src/Mod/TechDraw/Gui/Rez.h | 2 + src/Mod/TechDraw/Gui/TaskDetail.cpp | 585 ++++ src/Mod/TechDraw/Gui/TaskDetail.h | 179 ++ src/Mod/TechDraw/Gui/TaskDetail.ui | 296 ++ src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp | 64 + src/Mod/TechDraw/Gui/ViewProviderViewPart.h | 3 + 18 files changed, 2813 insertions(+), 1424 deletions(-) create mode 100644 src/Mod/TechDraw/Gui/QGIGhostHighlight.cpp create mode 100644 src/Mod/TechDraw/Gui/QGIGhostHighlight.h create mode 100644 src/Mod/TechDraw/Gui/TaskDetail.cpp create mode 100644 src/Mod/TechDraw/Gui/TaskDetail.h create mode 100644 src/Mod/TechDraw/Gui/TaskDetail.ui diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index 786daaf79b..27908dbcca 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -570,6 +570,13 @@ Base::Vector3d DrawUtil::invertY(Base::Vector3d v) return result; } +QPointF DrawUtil::invertY(QPointF v) +{ + QPointF result(v.x(), -v.y()); + return result; +} + + //obs? was used in CSV prototype of Cosmetics std::vector DrawUtil::split(std::string csvLine) { diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index 8b9f66c92a..aa70753220 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -110,6 +110,7 @@ class TechDrawExport DrawUtil { static std::string shapeToString(TopoDS_Shape s); static TopoDS_Shape shapeFromString(std::string s); static Base::Vector3d invertY(Base::Vector3d v); + static QPointF invertY(QPointF p); static std::vector split(std::string csvLine); static std::vector tokenize(std::string csvLine, std::string delimiter = ",$$$,"); static App::Color pyTupleToColor(PyObject* pColor); diff --git a/src/Mod/TechDraw/App/DrawViewDetail.cpp b/src/Mod/TechDraw/App/DrawViewDetail.cpp index 4e2e3f21ed..53c02f5894 100644 --- a/src/Mod/TechDraw/App/DrawViewDetail.cpp +++ b/src/Mod/TechDraw/App/DrawViewDetail.cpp @@ -100,8 +100,6 @@ using namespace std; PROPERTY_SOURCE(TechDraw::DrawViewDetail, TechDraw::DrawViewPart) DrawViewDetail::DrawViewDetail() -// : -// m_mattingStyle(0) { static const char *dgroup = "Detail"; diff --git a/src/Mod/TechDraw/Gui/CMakeLists.txt b/src/Mod/TechDraw/Gui/CMakeLists.txt index fb03ba059a..43ab8e5eeb 100644 --- a/src/Mod/TechDraw/Gui/CMakeLists.txt +++ b/src/Mod/TechDraw/Gui/CMakeLists.txt @@ -70,6 +70,8 @@ set(TechDrawGui_MOC_HDRS QGIWeldSymbol.h SymbolChooser.h TaskActiveView.h + TaskDetail.h + QGIGhostHighlight.h ) fc_wrap_cpp(TechDrawGui_MOC_SRCS ${TechDrawGui_MOC_HDRS}) @@ -103,6 +105,7 @@ set(TechDrawGui_UIC_SRCS TaskWeldingSymbol.ui SymbolChooser.ui TaskActiveView.ui + TaskDetail.ui ) if(BUILD_QT5) @@ -203,6 +206,9 @@ SET(TechDrawGui_SRCS TaskActiveView.h Grabber3d.cpp Grabber3d.h + TaskDetail.ui + TaskDetail.cpp + TaskDetail.h ) SET(TechDrawGuiView_SRCS @@ -299,6 +305,8 @@ SET(TechDrawGuiView_SRCS TemplateTextField.cpp TemplateTextField.h ZVALUE.h + QGIGhostHighlight.cpp + QGIGhostHighlight.h ) SET(TechDrawGuiViewProvider_SRCS ViewProviderPage.cpp @@ -366,6 +374,7 @@ SET(TechDrawGuiTaskDlgs_SRCS TaskWeldingSymbol.ui SymbolChooser.ui TaskActiveView.ui + TaskDetail.ui ) SOURCE_GROUP("TaskDialogs" FILES ${TechDrawGuiTaskDlgs_SRCS}) diff --git a/src/Mod/TechDraw/Gui/Command.cpp b/src/Mod/TechDraw/Gui/Command.cpp index e28271917e..89b680d198 100644 --- a/src/Mod/TechDraw/Gui/Command.cpp +++ b/src/Mod/TechDraw/Gui/Command.cpp @@ -1,1392 +1,1378 @@ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Library General Public License as * - * published by the Free Software Foundation; either version 2 of the * - * License, or (at your option) any later version. * - * for detail see the LICENCE text file. * - * Jürgen Riegel 2002 * - * Copyright (c) 2014 Luke Parry * - * * - ***************************************************************************/ - -#include "PreCompiled.h" -#ifndef _PreComp_ -# include -# include -# include -# include -# include -# include -# include -#endif - -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "DrawGuiUtil.h" -#include "MDIViewPage.h" -#include "TaskProjGroup.h" -#include "TaskSectionView.h" -#include "TaskActiveView.h" -#include "ViewProviderPage.h" - -using namespace TechDrawGui; -using namespace std; - - -//=========================================================================== -// TechDraw_PageDefault -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawPageDefault) - -CmdTechDrawPageDefault::CmdTechDrawPageDefault() - : Command("TechDraw_PageDefault") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Default Page"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_PageDefault"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-PageDefault"; -} - -void CmdTechDrawPageDefault::activated(int iMsg) -{ - Q_UNUSED(iMsg); - Base::Reference hGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Files"); - - std::string defaultDir = App::Application::getResourceDir() + "Mod/TechDraw/Templates/"; - std::string defaultFileName = defaultDir + "A4_LandscapeTD.svg"; - QString templateFileName = QString::fromStdString(hGrp->GetASCII("TemplateFile",defaultFileName.c_str())); - if (templateFileName.isEmpty()) { - templateFileName = QString::fromStdString(defaultFileName); - } - - std::string PageName = getUniqueObjectName("Page"); - std::string TemplateName = getUniqueObjectName("Template"); - - QFileInfo tfi(templateFileName); - if (tfi.isReadable()) { - Gui::WaitCursor wc; - openCommand("Drawing create page"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawPage','%s')",PageName.c_str()); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawSVGTemplate','%s')",TemplateName.c_str()); - - doCommand(Doc,"App.activeDocument().%s.Template = '%s'",TemplateName.c_str(), templateFileName.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Template = App.activeDocument().%s",PageName.c_str(),TemplateName.c_str()); - - commitCommand(); - TechDraw::DrawPage* fp = dynamic_cast(getDocument()->getObject(PageName.c_str())); - if (!fp) { - throw Base::TypeError("CmdTechDrawPageDefault fp not found\n"); - } - - Gui::ViewProvider* vp = Gui::Application::Instance->getDocument(getDocument())->getViewProvider(fp); - TechDrawGui::ViewProviderPage* dvp = dynamic_cast(vp); - if (dvp) { - dvp->show(); - } - else { - Base::Console().Log("INFO - Template: %s for Page: %s NOT Found\n", PageName.c_str(),TemplateName.c_str()); - } - } else { - QMessageBox::critical(Gui::getMainWindow(), - QLatin1String("No template"), - QLatin1String("No default template found")); - } -} - -bool CmdTechDrawPageDefault::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// TechDraw_PageTemplate -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawPageTemplate) - -CmdTechDrawPageTemplate::CmdTechDrawPageTemplate() - : Command("TechDraw_PageTemplate") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Page using Template"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_PageTemplate"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-PageTemplate"; -} - -void CmdTechDrawPageTemplate::activated(int iMsg) -{ - Q_UNUSED(iMsg); - Base::Reference hGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Files"); - - std::string defaultDir = App::Application::getResourceDir() + "Mod/TechDraw/Templates"; - QString templateDir = QString::fromStdString(hGrp->GetASCII("TemplateDir", defaultDir.c_str())); - QString templateFileName = Gui::FileDialog::getOpenFileName(Gui::getMainWindow(), - QString::fromUtf8(QT_TR_NOOP("Select a Template File")), - templateDir, - QString::fromUtf8(QT_TR_NOOP("Template (*.svg *.dxf)"))); - - if (templateFileName.isEmpty()) { - return; - } - - std::string PageName = getUniqueObjectName("Page"); - std::string TemplateName = getUniqueObjectName("Template"); - - QFileInfo tfi(templateFileName); - if (tfi.isReadable()) { - Gui::WaitCursor wc; - openCommand("Drawing create page"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawPage','%s')",PageName.c_str()); - - // Create the Template Object to attach to the page - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawSVGTemplate','%s')",TemplateName.c_str()); - - //why is "Template" property set twice? -wf - // once to set DrawSVGTemplate.Template to OS template file name - templateFileName = Base::Tools::escapeEncodeFilename(templateFileName); - doCommand(Doc,"App.activeDocument().%s.Template = \"%s\"",TemplateName.c_str(), templateFileName.toUtf8().constData()); - // once to set Page.Template to DrawSVGTemplate.Name - doCommand(Doc,"App.activeDocument().%s.Template = App.activeDocument().%s",PageName.c_str(),TemplateName.c_str()); - // consider renaming DrawSVGTemplate.Template property? - - commitCommand(); - TechDraw::DrawPage* fp = dynamic_cast(getDocument()->getObject(PageName.c_str())); - if (!fp) { - throw Base::TypeError("CmdTechDrawNewPagePick fp not found\n"); - } - Gui::ViewProvider* vp = Gui::Application::Instance->getDocument(getDocument())->getViewProvider(fp); - TechDrawGui::ViewProviderPage* dvp = dynamic_cast(vp); - if (dvp) { - dvp->show(); - } - else { - Base::Console().Log("INFO - Template: %s for Page: %s NOT Found\n", PageName.c_str(),TemplateName.c_str()); - } - } - else { - QMessageBox::critical(Gui::getMainWindow(), - QLatin1String("No template"), - QLatin1String("Template file is invalid")); - } -} - -bool CmdTechDrawPageTemplate::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// TechDraw_RedrawPage -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawRedrawPage) - -CmdTechDrawRedrawPage::CmdTechDrawRedrawPage() - : Command("TechDraw_RedrawPage") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Redraw Page"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_RedrawPage"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-RedrawPage"; -} - -void CmdTechDrawRedrawPage::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - Gui::WaitCursor wc; - - page->redrawCommand(); -} - -bool CmdTechDrawRedrawPage::isActive(void) -{ - bool havePage = DrawGuiUtil::needPage(this); - bool haveView = DrawGuiUtil::needView(this,false); - return (havePage && haveView); -} - -//=========================================================================== -// TechDraw_View -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawView) - -CmdTechDrawView::CmdTechDrawView() - : Command("TechDraw_View") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert View"); - sToolTipText = QT_TR_NOOP("Insert a View"); - sWhatsThis = "TechDraw_View"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-View"; -} - -void CmdTechDrawView::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - - //set projection direction from selected Face - //use first object with a face selected - std::vector shapes; - App::DocumentObject* partObj = nullptr; - std::string faceName; - int resolve = 1; //mystery - bool single = false; //mystery - auto selection = getSelection().getSelectionEx(0, - App::DocumentObject::getClassTypeId(), - resolve, - single); - for (auto& sel: selection) { - auto obj = sel.getObject(); - if (obj->isDerivedFrom(TechDraw::DrawPage::getClassTypeId()) ) { - continue; - } - if (obj != nullptr) { - shapes.push_back(obj); - } - if(partObj != nullptr) { - continue; - } - for(auto& sub : sel.getSubNames()) { - if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { - faceName = sub; - partObj = obj; - break; - } - } - } - - if ((shapes.empty())) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No Shapes, Groups or Links in this selection")); - return; - } - - Base::Vector3d projDir; - - Gui::WaitCursor wc; - openCommand("Create view"); - std::string FeatName = getUniqueObjectName("View"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewPart','%s')",FeatName.c_str()); - App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); - TechDraw::DrawViewPart* dvp = dynamic_cast(docObj); - if (!dvp) { - throw Base::TypeError("CmdTechDrawView DVP not found\n"); - } - dvp->Source.setValues(shapes); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); - if (faceName.size()) { - std::pair dirs = DrawGuiUtil::getProjDirFromFace(partObj,faceName); - projDir = dirs.first; - getDocument()->setStatus(App::Document::Status::SkipRecompute, true); - doCommand(Doc,"App.activeDocument().%s.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", - FeatName.c_str(), projDir.x,projDir.y,projDir.z); - //do something clever with dirs.second; -// dvp->setXDir(dirs.second); - doCommand(Doc,"App.activeDocument().%s.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", - FeatName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); - doCommand(Doc,"App.activeDocument().%s.recompute()", FeatName.c_str()); - getDocument()->setStatus(App::Document::Status::SkipRecompute, false); - } else { - std::pair dirs = DrawGuiUtil::get3DDirAndRot(); - projDir = dirs.first; - getDocument()->setStatus(App::Document::Status::SkipRecompute, true); - doCommand(Doc,"App.activeDocument().%s.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", - FeatName.c_str(), projDir.x,projDir.y,projDir.z); - doCommand(Doc,"App.activeDocument().%s.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", - FeatName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); -// dvp->setXDir(dirs.second); - getDocument()->setStatus(App::Document::Status::SkipRecompute, false); - doCommand(Doc,"App.activeDocument().%s.recompute()", FeatName.c_str()); - } - commitCommand(); -} - -bool CmdTechDrawView::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -//=========================================================================== -// TechDraw_ActiveView -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawActiveView) - -CmdTechDrawActiveView::CmdTechDrawActiveView() - : Command("TechDraw_ActiveView") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Active View (3D View)"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_ActiveView"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ActiveView"; -} - -void CmdTechDrawActiveView::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - Gui::Control().showDialog(new TaskDlgActiveView(page)); -} - -bool CmdTechDrawActiveView::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -//=========================================================================== -// TechDraw_SectionView -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawSectionView) - -CmdTechDrawSectionView::CmdTechDrawSectionView() - : Command("TechDraw_SectionView") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Section View"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_SectionView"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-SectionView"; -} - -void CmdTechDrawSectionView::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - - std::vector baseObj = getSelection().getObjectsOfType(TechDraw::DrawViewPart::getClassTypeId()); - if (baseObj.empty()) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select at least 1 DrawViewPart object as Base.")); - return; - } - TechDraw::DrawViewPart* dvp = static_cast(*baseObj.begin()); -// std::string BaseName = dvp->getNameInDocument(); -// std::string PageName = page->getNameInDocument(); -// double baseScale = dvp->getScale(); - -// Gui::WaitCursor wc; -// openCommand("Create view"); -// std::string FeatName = getUniqueObjectName("Section"); - -// doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewSection','%s')",FeatName.c_str()); - -// App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); -// TechDraw::DrawViewSection* dsv = dynamic_cast(docObj); -// if (!dsv) { -// throw Base::TypeError("CmdTechDrawSectionView DVS not found\n"); -// } -// dsv->Source.setValues(dvp->Source.getValues()); -// doCommand(Doc,"App.activeDocument().%s.BaseView = App.activeDocument().%s",FeatName.c_str(),BaseName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.ScaleType = App.activeDocument().%s.ScaleType",FeatName.c_str(),BaseName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Scale = %0.6f",FeatName.c_str(),baseScale); - Gui::Control().showDialog(new TaskDlgSectionView(dvp)); - - updateActive(); //ok here since dialog doesn't call doc.recompute() - commitCommand(); -} - -bool CmdTechDrawSectionView::isActive(void) -{ - bool havePage = DrawGuiUtil::needPage(this); - bool haveView = DrawGuiUtil::needView(this); - bool taskInProgress = false; - if (havePage) { - taskInProgress = Gui::Control().activeDialog(); - } - return (havePage && haveView && !taskInProgress); -} - -//=========================================================================== -// TechDraw_DetailView -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawDetailView) - -CmdTechDrawDetailView::CmdTechDrawDetailView() - : Command("TechDraw_DetailView") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Detail View"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_DetailView"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-DetailView"; -} - -void CmdTechDrawDetailView::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - - std::vector baseObj = getSelection().getObjectsOfType(TechDraw::DrawViewPart::getClassTypeId()); - if (baseObj.empty()) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select at least 1 DrawViewPart object as Base.")); - return; - } - TechDraw::DrawViewPart* dvp = static_cast(*(baseObj.begin())); - - std::string PageName = page->getNameInDocument(); - - Gui::WaitCursor wc; - openCommand("Create view"); - - std::string FeatName = getUniqueObjectName("Detail"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewDetail','%s')",FeatName.c_str()); - App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); - TechDraw::DrawViewDetail* dvd = dynamic_cast(docObj); - if (!dvd) { - throw Base::TypeError("CmdTechDrawDetailView DVD not found\n"); - } - dvd->Source.setValues(dvp->Source.getValues()); - - doCommand(Doc,"App.activeDocument().%s.BaseView = App.activeDocument().%s",FeatName.c_str(),dvp->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Direction = App.activeDocument().%s.Direction",FeatName.c_str(),dvp->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.XDirection = App.activeDocument().%s.XDirection",FeatName.c_str(),dvp->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); - - updateActive(); //ok here, no preceding recompute - commitCommand(); -} - -bool CmdTechDrawDetailView::isActive(void) -{ - bool havePage = DrawGuiUtil::needPage(this); - bool haveView = DrawGuiUtil::needView(this); - bool taskInProgress = false; - if (havePage) { - taskInProgress = Gui::Control().activeDialog(); - } - return (havePage && haveView && !taskInProgress); -} - -//=========================================================================== -// TechDraw_ProjectionGroup -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawProjectionGroup) - -CmdTechDrawProjectionGroup::CmdTechDrawProjectionGroup() - : Command("TechDraw_ProjectionGroup") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Projection Group"); - sToolTipText = QT_TR_NOOP("Insert multiple linked views of drawable object(s)"); - sWhatsThis = "TechDraw_ProjectionGroup"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ProjectionGroup"; -} - -void CmdTechDrawProjectionGroup::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); -// auto inlist = page->getInListEx(true); -// inlist.insert(page); - - //set projection direction from selected Face - //use first object with a face selected - std::vector shapes; - App::DocumentObject* partObj = nullptr; - std::string faceName; - int resolve = 1; //mystery - bool single = false; //mystery - auto selection = getSelection().getSelectionEx(0, - App::DocumentObject::getClassTypeId(), - resolve, - single); - for (auto& sel: selection) { -// for(auto &sel : getSelection().getSelectionEx(0,App::DocumentObject::getClassTypeId(),false)) { - auto obj = sel.getObject(); - if (obj->isDerivedFrom(TechDraw::DrawPage::getClassTypeId()) ) { - continue; - } -// if(!obj || inlist.count(obj)) //?????? -// continue; - if (obj != nullptr) { //can this happen? - shapes.push_back(obj); - } - if(partObj != nullptr) { - continue; - } - for(auto& sub : sel.getSubNames()) { - if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { - faceName = sub; - partObj = obj; - break; - } - } - } - if (shapes.empty()) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No Shapes or Groups in this selection")); - return; - } - - Base::Vector3d projDir; - Gui::WaitCursor wc; - - openCommand("Create Projection Group"); - - std::string multiViewName = getUniqueObjectName("ProjGroup"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawProjGroup','%s')", - multiViewName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)", - PageName.c_str(),multiViewName.c_str()); - - App::DocumentObject *docObj = getDocument()->getObject(multiViewName.c_str()); - auto multiView( static_cast(docObj) ); - multiView->Source.setValues(shapes); - doCommand(Doc,"App.activeDocument().%s.addProjection('Front')",multiViewName.c_str()); - - if (faceName.size()) { - std::pair dirs = DrawGuiUtil::getProjDirFromFace(partObj,faceName); - getDocument()->setStatus(App::Document::Status::SkipRecompute, true); - doCommand(Doc,"App.activeDocument().%s.Anchor.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", - multiViewName.c_str(), dirs.first.x,dirs.first.y,dirs.first.z); - doCommand(Doc,"App.activeDocument().%s.Anchor.RotationVector = FreeCAD.Vector(%.3f,%.3f,%.3f)", - multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); - doCommand(Doc,"App.activeDocument().%s.Anchor.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", - multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); - getDocument()->setStatus(App::Document::Status::SkipRecompute, false); - } else { - std::pair dirs = DrawGuiUtil::get3DDirAndRot(); - getDocument()->setStatus(App::Document::Status::SkipRecompute, true); - doCommand(Doc,"App.activeDocument().%s.Anchor.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", - multiViewName.c_str(), dirs.first.x,dirs.first.y,dirs.first.z); - doCommand(Doc,"App.activeDocument().%s.Anchor.RotationVector = FreeCAD.Vector(%.3f,%.3f,%.3f)", - multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); - doCommand(Doc,"App.activeDocument().%s.Anchor.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", - multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); - getDocument()->setStatus(App::Document::Status::SkipRecompute, false); - } - - doCommand(Doc,"App.activeDocument().%s.Anchor.recompute()", multiViewName.c_str()); - commitCommand(); - updateActive(); - - // create the rest of the desired views - Gui::Control().showDialog(new TaskDlgProjGroup(multiView,true)); -} - -bool CmdTechDrawProjectionGroup::isActive(void) -{ - bool havePage = DrawGuiUtil::needPage(this); - bool taskInProgress = false; - if (havePage) { - taskInProgress = Gui::Control().activeDialog(); - } - return (havePage && !taskInProgress); -} - -//=========================================================================== -// TechDraw_NewMulti **deprecated** -//=========================================================================== - -//DEF_STD_CMD_A(CmdTechDrawNewMulti); - -//CmdTechDrawNewMulti::CmdTechDrawNewMulti() -// : Command("TechDraw_NewMulti") -//{ -// sAppModule = "TechDraw"; -// sGroup = QT_TR_NOOP("TechDraw"); -// sMenuText = QT_TR_NOOP("Insert multi-part view in drawing"); -// sToolTipText = QT_TR_NOOP("Insert a new View of a multiple Parts in the active drawing"); -// sWhatsThis = "TechDraw_NewMulti"; -// sStatusTip = sToolTipText; -// sPixmap = "actions/techdraw-multiview"; -//} - -//void CmdTechDrawNewMulti::activated(int iMsg) -//{ -// Q_UNUSED(iMsg); -// TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); -// if (!page) { -// return; -// } - -// std::vector shapes = getSelection().getObjectsOfType(App::DocumentObject::getClassTypeId()); -// if (shapes.empty()) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Can not MultiView from this selection.")); -// return; -// } - -// std::string PageName = page->getNameInDocument(); - -// Gui::WaitCursor wc; - -// openCommand("Create view"); -// std::string FeatName = getUniqueObjectName("MultiView"); -// doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewMulti','%s')",FeatName.c_str()); -// App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); -// auto multiView( static_cast(docObj) ); -// multiView->Sources.setValues(shapes); -// doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); -// updateActive(); -// commitCommand(); -//} - -//bool CmdTechDrawNewMulti::isActive(void) -//{ -// return DrawGuiUtil::needPage(this); -//} - -//=========================================================================== -// TechDraw_Balloon -//=========================================================================== - -//! common checks of Selection for Dimension commands -//non-empty selection, no more than maxObjs selected and at least 1 DrawingPage exists -bool _checkSelectionBalloon(Gui::Command* cmd, unsigned maxObjs) { - std::vector selection = cmd->getSelection().getSelectionEx(); - if (selection.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), - QObject::tr("Select an object first")); - return false; - } - - const std::vector SubNames = selection[0].getSubNames(); - if (SubNames.size() > maxObjs){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), - QObject::tr("Too many objects selected")); - return false; - } - - std::vector pages = cmd->getDocument()->getObjectsOfType(TechDraw::DrawPage::getClassTypeId()); - if (pages.empty()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), - QObject::tr("Create a page first.")); - return false; - } - return true; -} - -bool _checkDrawViewPartBalloon(Gui::Command* cmd) { - std::vector selection = cmd->getSelection().getSelectionEx(); - auto objFeat( dynamic_cast(selection[0].getObject()) ); - if( !objFeat ) { - QMessageBox::warning( Gui::getMainWindow(), - QObject::tr("Incorrect selection"), - QObject::tr("No View of a Part in selection.") ); - return false; - } - return true; -} - -DEF_STD_CMD_A(CmdTechDrawBalloon) - -CmdTechDrawBalloon::CmdTechDrawBalloon() - : Command("TechDraw_Balloon") -{ - sAppModule = "TechDraw"; - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Balloon Annotation"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_Balloon"; - sStatusTip = sToolTipText; - sPixmap = "TechDraw_Balloon"; -} - -void CmdTechDrawBalloon::activated(int iMsg) -{ - Q_UNUSED(iMsg); - bool result = _checkSelectionBalloon(this,1); - if (!result) - return; - result = _checkDrawViewPartBalloon(this); - if (!result) - return; - - std::vector selection = getSelection().getSelectionEx(); - auto objFeat( dynamic_cast(selection[0].getObject()) ); - if( objFeat == nullptr ) { - return; - } - - TechDraw::DrawPage* page = objFeat->findParentPage(); - std::string PageName = page->getNameInDocument(); - - page->balloonParent = objFeat; - page->balloonPlacing = true; - -} - -bool CmdTechDrawBalloon::isActive(void) -{ - bool havePage = DrawGuiUtil::needPage(this); - bool haveView = DrawGuiUtil::needView(this); - return (havePage && haveView); -} - -//=========================================================================== -// TechDraw_ClipGroup -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawClipGroup) - -CmdTechDrawClipGroup::CmdTechDrawClipGroup() - : Command("TechDraw_ClipGroup") -{ - // setting the - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Clip Group"); - sToolTipText = sToolTipText; - sWhatsThis = "TechDraw_ClipGroup"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ClipGroup"; -} - -void CmdTechDrawClipGroup::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - - std::string FeatName = getUniqueObjectName("Clip"); - openCommand("Create Clip"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewClip','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); - updateActive(); - commitCommand(); -} - -bool CmdTechDrawClipGroup::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -//=========================================================================== -// TechDraw_ClipGroupAdd -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawClipGroupAdd) - -CmdTechDrawClipGroupAdd::CmdTechDrawClipGroupAdd() - : Command("TechDraw_ClipGroupAdd") -{ - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Add View to Clip Group"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_ClipGroupAdd"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ClipGroupAdd"; -} - -void CmdTechDrawClipGroupAdd::activated(int iMsg) -{ - Q_UNUSED(iMsg); - std::vector selection = getSelection().getSelectionEx(); - if (selection.size() != 2) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select one Clip group and one View.")); - return; - } - - TechDraw::DrawViewClip* clip = 0; - TechDraw::DrawView* view = 0; - std::vector::iterator itSel = selection.begin(); - for (; itSel != selection.end(); itSel++) { - if ((*itSel).getObject()->isDerivedFrom(TechDraw::DrawViewClip::getClassTypeId())) { - clip = static_cast((*itSel).getObject()); - } else if ((*itSel).getObject()->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) { - view = static_cast((*itSel).getObject()); - } - } - if (!view) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select exactly one View to add to group.")); - return; - } - if (!clip) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select exactly one Clip group.")); - return; - } - - TechDraw::DrawPage* pageClip = clip->findParentPage(); - TechDraw::DrawPage* pageView = view->findParentPage(); - - if (pageClip != pageView) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Clip and View must be from same Page.")); - return; - } - - std::string PageName = pageClip->getNameInDocument(); - std::string ClipName = clip->getNameInDocument(); - std::string ViewName = view->getNameInDocument(); - - openCommand("ClipGroupAdd"); - doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = False",ViewName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",ClipName.c_str(),ViewName.c_str()); - doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = True",ViewName.c_str()); - updateActive(); - commitCommand(); -} - -bool CmdTechDrawClipGroupAdd::isActive(void) -{ - bool havePage = DrawGuiUtil::needPage(this); - bool haveClip = false; - if (havePage) { - auto drawClipType( TechDraw::DrawViewClip::getClassTypeId() ); - auto selClips = getDocument()->getObjectsOfType(drawClipType); - if (!selClips.empty()) { - haveClip = true; - } - } - return (havePage && haveClip); -} - -//=========================================================================== -// TechDraw_ClipGroupRemove -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawClipGroupRemove) - -CmdTechDrawClipGroupRemove::CmdTechDrawClipGroupRemove() - : Command("TechDraw_ClipGroupRemove") -{ - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Remove View from Clip Group"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_ClipGroupRemove"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ClipGroupRemove"; -} - -void CmdTechDrawClipGroupRemove::activated(int iMsg) -{ - Q_UNUSED(iMsg); - auto dObj( getSelection().getObjectsOfType(TechDraw::DrawView::getClassTypeId()) ); - if (dObj.empty()) { - QMessageBox::warning( Gui::getMainWindow(), - QObject::tr("Wrong selection"), - QObject::tr("Select exactly one View to remove from Group.") ); - return; - } - - auto view( static_cast(dObj.front()) ); - - TechDraw::DrawPage* page = view->findParentPage(); - const std::vector pViews = page->Views.getValues(); - TechDraw::DrawViewClip *clip(nullptr); - for (auto &v : pViews) { - clip = dynamic_cast(v); - if (clip && clip->isViewInClip(view)) { - break; - } - clip = nullptr; - } - - if (!clip) { - QMessageBox::warning( Gui::getMainWindow(), - QObject::tr("Wrong selection"), - QObject::tr("View does not belong to a Clip") ); - return; - } - - std::string ClipName = clip->getNameInDocument(); - std::string ViewName = view->getNameInDocument(); - - openCommand("ClipGroupRemove"); - doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = False",ViewName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeView(App.activeDocument().%s)",ClipName.c_str(),ViewName.c_str()); - doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = True",ViewName.c_str()); - updateActive(); - commitCommand(); -} - -bool CmdTechDrawClipGroupRemove::isActive(void) -{ - bool havePage = DrawGuiUtil::needPage(this); - bool haveClip = false; - if (havePage) { - auto drawClipType( TechDraw::DrawViewClip::getClassTypeId() ); - auto selClips = getDocument()->getObjectsOfType(drawClipType); - if (!selClips.empty()) { - haveClip = true; - } - } - return (havePage && haveClip); -} - - -//=========================================================================== -// TechDraw_Symbol -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawSymbol) - -CmdTechDrawSymbol::CmdTechDrawSymbol() - : Command("TechDraw_Symbol") -{ - // setting the Gui eye-candy - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert SVG Symbol"); - sToolTipText = QT_TR_NOOP("Insert symbol from a SVG file"); - sWhatsThis = "TechDraw_Symbol"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-symbol"; -} - -void CmdTechDrawSymbol::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - - // Reading an image - QString filename = Gui::FileDialog::getOpenFileName(Gui::getMainWindow(), QObject::tr("Choose an SVG file to open"), QString::null, - QString::fromLatin1("%1 (*.svg *.svgz)").arg(QObject::tr("Scalable Vector Graphic"))); - if (!filename.isEmpty()) - { - std::string FeatName = getUniqueObjectName("Symbol"); - filename = Base::Tools::escapeEncodeFilename(filename); - openCommand("Create Symbol"); -#if PY_MAJOR_VERSION < 3 - doCommand(Doc,"f = open(unicode(\"%s\",'utf-8'),'r')",(const char*)filename.toUtf8()); -#else - doCommand(Doc,"f = open(\"%s\",'r')",(const char*)filename.toUtf8()); -#endif - doCommand(Doc,"svg = f.read()"); - doCommand(Doc,"f.close()"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewSymbol','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Symbol = svg",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); - updateActive(); - commitCommand(); - } -} - -bool CmdTechDrawSymbol::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -//=========================================================================== -// TechDraw_DraftView -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawDraftView) - -CmdTechDrawDraftView::CmdTechDrawDraftView() - : Command("TechDraw_DraftView") -{ - // setting the Gui eye-candy - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Draft Workbench Object"); - sToolTipText = QT_TR_NOOP("Insert a View of a Draft Workbench object"); - sWhatsThis = "TechDraw_NewDraft"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-DraftView"; -} - -void CmdTechDrawDraftView::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - - std::vector objects = getSelection(). - getObjectsOfType(App::DocumentObject::getClassTypeId()); - - if (objects.empty()) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select at least one object.")); - return; - } - - int draftItemsFound = 0; - for (std::vector::iterator it = objects.begin(); it != objects.end(); ++it) { - if (DrawGuiUtil::isDraftObject((*it))) { - draftItemsFound++; - std::string FeatName = getUniqueObjectName("DraftView"); - std::string SourceName = (*it)->getNameInDocument(); - openCommand("Create DraftView"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewDraft','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s", - FeatName.c_str(),SourceName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)", - PageName.c_str(),FeatName.c_str()); - updateActive(); - commitCommand(); - } - } - if (draftItemsFound == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("There were no DraftWB objects in the selection.")); - } -} - -bool CmdTechDrawDraftView::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -//=========================================================================== -// TechDraw_ArchView -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawArchView) - -CmdTechDrawArchView::CmdTechDrawArchView() - : Command("TechDraw_ArchView") -{ - // setting the Gui eye-candy - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Arch Workbench Object"); - sToolTipText = QT_TR_NOOP("Insert a View of a Section Plane from Arch Workbench"); - sWhatsThis = "TechDraw_NewArch"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ArchView"; -} - -void CmdTechDrawArchView::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - - - const std::vector objects = getSelection(). - getObjectsOfType(App::DocumentObject::getClassTypeId()); - App::DocumentObject* archObject = nullptr; - int archCount = 0; - for (auto& obj : objects) { - if (DrawGuiUtil::isArchSection(obj) ) { - archCount++; - archObject = obj; - } - } - if ( archCount > 1 ) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Please select only 1 Arch Section.")); - return; - } - - if (archObject == nullptr) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No Arch Sections in selection.")); - return; - } - - std::string FeatName = getUniqueObjectName("ArchView"); - std::string SourceName = archObject->getNameInDocument(); - openCommand("Create ArchView"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewArch','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s",FeatName.c_str(),SourceName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); - updateActive(); - commitCommand(); -} - -bool CmdTechDrawArchView::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -//=========================================================================== -// TechDraw_SpreadsheetView -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawSpreadsheetView) - -CmdTechDrawSpreadsheetView::CmdTechDrawSpreadsheetView() - : Command("TechDraw_SpreadsheetView") -{ - // setting the - sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert Spreadsheet View"); - sToolTipText = QT_TR_NOOP("Insert View to a spreadsheet"); - sWhatsThis = "TechDraw_SpreadsheetView"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-SpreadsheetView"; -} - -void CmdTechDrawSpreadsheetView::activated(int iMsg) -{ - Q_UNUSED(iMsg); - const std::vector spreads = getSelection().getObjectsOfType(Spreadsheet::Sheet::getClassTypeId()); - if (spreads.size() != 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select exactly one Spreadsheet object.")); - return; - } - std::string SpreadName = spreads.front()->getNameInDocument(); - - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - - openCommand("Create spreadsheet view"); - std::string FeatName = getUniqueObjectName("Sheet"); - doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewSpreadsheet','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s",FeatName.c_str(),SpreadName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); - updateActive(); - commitCommand(); -} - -bool CmdTechDrawSpreadsheetView::isActive(void) -{ - //need a Page and a SpreadSheet::Sheet - bool havePage = DrawGuiUtil::needPage(this); - bool haveSheet = false; - if (havePage) { - auto spreadSheetType( Spreadsheet::Sheet::getClassTypeId() ); - auto selSheets = getDocument()->getObjectsOfType(spreadSheetType); - if (!selSheets.empty()) { - haveSheet = true; - } - } - return (havePage && haveSheet); -} - - -//=========================================================================== -// TechDraw_ExportPageSVG -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawExportPageSVG) - -CmdTechDrawExportPageSVG::CmdTechDrawExportPageSVG() - : Command("TechDraw_ExportPageSVG") -{ - sGroup = QT_TR_NOOP("File"); - sMenuText = QT_TR_NOOP("Export Page as SVG"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_ExportPageSVG"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ExportPageSVG"; -} - -void CmdTechDrawExportPageSVG::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - std::string PageName = page->getNameInDocument(); - - Gui::Document* activeGui = Gui::Application::Instance->getDocument(page->getDocument()); - Gui::ViewProvider* vp = activeGui->getViewProvider(page); - ViewProviderPage* dvp = dynamic_cast(vp); - - if (dvp && dvp->getMDIViewPage()) { - dvp->getMDIViewPage()->saveSVG(); - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No Drawing View"), - QObject::tr("Open Drawing View before attempting export to SVG.")); - return; - } -} - -bool CmdTechDrawExportPageSVG::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -//=========================================================================== -// TechDraw_ExportPageDXF -//=========================================================================== - -DEF_STD_CMD_A(CmdTechDrawExportPageDXF) - -CmdTechDrawExportPageDXF::CmdTechDrawExportPageDXF() - : Command("TechDraw_ExportPageDXF") -{ - sGroup = QT_TR_NOOP("File"); - sMenuText = QT_TR_NOOP("Export Page as DXF"); - sToolTipText = sMenuText; - sWhatsThis = "TechDraw_ExportPageDXF"; - sStatusTip = sToolTipText; - sPixmap = "actions/techdraw-ExportPageDXF"; -} - -void CmdTechDrawExportPageDXF::activated(int iMsg) -{ - Q_UNUSED(iMsg); - TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); - if (!page) { - return; - } - - std::vector views = page->Views.getValues(); - for (auto& v: views) { - if (v->isDerivedFrom(TechDraw::DrawViewArch::getClassTypeId())) { - QMessageBox::StandardButton rc = - QMessageBox::question(Gui::getMainWindow(), QObject::tr("Can not export selection"), - QObject::tr("Page contains DrawViewArch which will not be exported. Continue?"), - QMessageBox::StandardButtons(QMessageBox::Yes| QMessageBox::No)); - if (rc == QMessageBox::No) { - return; - } else { - break; - } - } - } - -//WF? allow more than one TD Page per Dxf file?? 1 TD page = 1 DXF file = 1 drawing? - QString defaultDir; - QString fileName = Gui::FileDialog::getSaveFileName(Gui::getMainWindow(), - QString::fromUtf8(QT_TR_NOOP("Save Dxf File ")), - defaultDir, - QString::fromUtf8(QT_TR_NOOP("Dxf (*.dxf)"))); - - if (fileName.isEmpty()) { - return; - } - - std::string PageName = page->getNameInDocument(); - openCommand("Save page to dxf"); - doCommand(Doc,"import TechDraw"); - fileName = Base::Tools::escapeEncodeFilename(fileName); - doCommand(Doc,"TechDraw.writeDXFPage(App.activeDocument().%s,u\"%s\")",PageName.c_str(),(const char*)fileName.toUtf8()); - commitCommand(); -} - - -bool CmdTechDrawExportPageDXF::isActive(void) -{ - return DrawGuiUtil::needPage(this); -} - -void CreateTechDrawCommands(void) -{ - Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); - - rcCmdMgr.addCommand(new CmdTechDrawPageDefault()); - rcCmdMgr.addCommand(new CmdTechDrawPageTemplate()); - rcCmdMgr.addCommand(new CmdTechDrawRedrawPage()); - rcCmdMgr.addCommand(new CmdTechDrawView()); - rcCmdMgr.addCommand(new CmdTechDrawActiveView()); - rcCmdMgr.addCommand(new CmdTechDrawSectionView()); - rcCmdMgr.addCommand(new CmdTechDrawDetailView()); - rcCmdMgr.addCommand(new CmdTechDrawProjectionGroup()); - rcCmdMgr.addCommand(new CmdTechDrawClipGroup()); - rcCmdMgr.addCommand(new CmdTechDrawClipGroupAdd()); - rcCmdMgr.addCommand(new CmdTechDrawClipGroupRemove()); - rcCmdMgr.addCommand(new CmdTechDrawSymbol()); - rcCmdMgr.addCommand(new CmdTechDrawExportPageSVG()); - rcCmdMgr.addCommand(new CmdTechDrawExportPageDXF()); - rcCmdMgr.addCommand(new CmdTechDrawDraftView()); - rcCmdMgr.addCommand(new CmdTechDrawArchView()); - rcCmdMgr.addCommand(new CmdTechDrawSpreadsheetView()); - rcCmdMgr.addCommand(new CmdTechDrawBalloon()); -} +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * for detail see the LICENCE text file. * + * Jürgen Riegel 2002 * + * Copyright (c) 2014 Luke Parry * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +#endif + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DrawGuiUtil.h" +#include "MDIViewPage.h" +#include "TaskProjGroup.h" +#include "TaskSectionView.h" +#include "TaskActiveView.h" +#include "TaskDetail.h" +#include "ViewProviderPage.h" + +using namespace TechDrawGui; +using namespace std; + + +//=========================================================================== +// TechDraw_PageDefault +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawPageDefault) + +CmdTechDrawPageDefault::CmdTechDrawPageDefault() + : Command("TechDraw_PageDefault") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Default Page"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_PageDefault"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-PageDefault"; +} + +void CmdTechDrawPageDefault::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Files"); + + std::string defaultDir = App::Application::getResourceDir() + "Mod/TechDraw/Templates/"; + std::string defaultFileName = defaultDir + "A4_LandscapeTD.svg"; + QString templateFileName = QString::fromStdString(hGrp->GetASCII("TemplateFile",defaultFileName.c_str())); + if (templateFileName.isEmpty()) { + templateFileName = QString::fromStdString(defaultFileName); + } + + std::string PageName = getUniqueObjectName("Page"); + std::string TemplateName = getUniqueObjectName("Template"); + + QFileInfo tfi(templateFileName); + if (tfi.isReadable()) { + Gui::WaitCursor wc; + openCommand("Drawing create page"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawPage','%s')",PageName.c_str()); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawSVGTemplate','%s')",TemplateName.c_str()); + + doCommand(Doc,"App.activeDocument().%s.Template = '%s'",TemplateName.c_str(), templateFileName.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Template = App.activeDocument().%s",PageName.c_str(),TemplateName.c_str()); + + commitCommand(); + TechDraw::DrawPage* fp = dynamic_cast(getDocument()->getObject(PageName.c_str())); + if (!fp) { + throw Base::TypeError("CmdTechDrawPageDefault fp not found\n"); + } + + Gui::ViewProvider* vp = Gui::Application::Instance->getDocument(getDocument())->getViewProvider(fp); + TechDrawGui::ViewProviderPage* dvp = dynamic_cast(vp); + if (dvp) { + dvp->show(); + } + else { + Base::Console().Log("INFO - Template: %s for Page: %s NOT Found\n", PageName.c_str(),TemplateName.c_str()); + } + } else { + QMessageBox::critical(Gui::getMainWindow(), + QLatin1String("No template"), + QLatin1String("No default template found")); + } +} + +bool CmdTechDrawPageDefault::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// TechDraw_PageTemplate +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawPageTemplate) + +CmdTechDrawPageTemplate::CmdTechDrawPageTemplate() + : Command("TechDraw_PageTemplate") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Page using Template"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_PageTemplate"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-PageTemplate"; +} + +void CmdTechDrawPageTemplate::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Files"); + + std::string defaultDir = App::Application::getResourceDir() + "Mod/TechDraw/Templates"; + QString templateDir = QString::fromStdString(hGrp->GetASCII("TemplateDir", defaultDir.c_str())); + QString templateFileName = Gui::FileDialog::getOpenFileName(Gui::getMainWindow(), + QString::fromUtf8(QT_TR_NOOP("Select a Template File")), + templateDir, + QString::fromUtf8(QT_TR_NOOP("Template (*.svg *.dxf)"))); + + if (templateFileName.isEmpty()) { + return; + } + + std::string PageName = getUniqueObjectName("Page"); + std::string TemplateName = getUniqueObjectName("Template"); + + QFileInfo tfi(templateFileName); + if (tfi.isReadable()) { + Gui::WaitCursor wc; + openCommand("Drawing create page"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawPage','%s')",PageName.c_str()); + + // Create the Template Object to attach to the page + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawSVGTemplate','%s')",TemplateName.c_str()); + + //why is "Template" property set twice? -wf + // once to set DrawSVGTemplate.Template to OS template file name + templateFileName = Base::Tools::escapeEncodeFilename(templateFileName); + doCommand(Doc,"App.activeDocument().%s.Template = \"%s\"",TemplateName.c_str(), templateFileName.toUtf8().constData()); + // once to set Page.Template to DrawSVGTemplate.Name + doCommand(Doc,"App.activeDocument().%s.Template = App.activeDocument().%s",PageName.c_str(),TemplateName.c_str()); + // consider renaming DrawSVGTemplate.Template property? + + commitCommand(); + TechDraw::DrawPage* fp = dynamic_cast(getDocument()->getObject(PageName.c_str())); + if (!fp) { + throw Base::TypeError("CmdTechDrawNewPagePick fp not found\n"); + } + Gui::ViewProvider* vp = Gui::Application::Instance->getDocument(getDocument())->getViewProvider(fp); + TechDrawGui::ViewProviderPage* dvp = dynamic_cast(vp); + if (dvp) { + dvp->show(); + } + else { + Base::Console().Log("INFO - Template: %s for Page: %s NOT Found\n", PageName.c_str(),TemplateName.c_str()); + } + } + else { + QMessageBox::critical(Gui::getMainWindow(), + QLatin1String("No template"), + QLatin1String("Template file is invalid")); + } +} + +bool CmdTechDrawPageTemplate::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// TechDraw_RedrawPage +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawRedrawPage) + +CmdTechDrawRedrawPage::CmdTechDrawRedrawPage() + : Command("TechDraw_RedrawPage") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Redraw Page"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_RedrawPage"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-RedrawPage"; +} + +void CmdTechDrawRedrawPage::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + Gui::WaitCursor wc; + + page->redrawCommand(); +} + +bool CmdTechDrawRedrawPage::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this,false); + return (havePage && haveView); +} + +//=========================================================================== +// TechDraw_View +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawView) + +CmdTechDrawView::CmdTechDrawView() + : Command("TechDraw_View") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert View"); + sToolTipText = QT_TR_NOOP("Insert a View"); + sWhatsThis = "TechDraw_View"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-View"; +} + +void CmdTechDrawView::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + + //set projection direction from selected Face + //use first object with a face selected + std::vector shapes; + App::DocumentObject* partObj = nullptr; + std::string faceName; + int resolve = 1; //mystery + bool single = false; //mystery + auto selection = getSelection().getSelectionEx(0, + App::DocumentObject::getClassTypeId(), + resolve, + single); + for (auto& sel: selection) { + auto obj = sel.getObject(); + if (obj->isDerivedFrom(TechDraw::DrawPage::getClassTypeId()) ) { + continue; + } + if (obj != nullptr) { + shapes.push_back(obj); + } + if(partObj != nullptr) { + continue; + } + for(auto& sub : sel.getSubNames()) { + if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { + faceName = sub; + partObj = obj; + break; + } + } + } + + if ((shapes.empty())) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No Shapes, Groups or Links in this selection")); + return; + } + + Base::Vector3d projDir; + + Gui::WaitCursor wc; + openCommand("Create view"); + std::string FeatName = getUniqueObjectName("View"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewPart','%s')",FeatName.c_str()); + App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); + TechDraw::DrawViewPart* dvp = dynamic_cast(docObj); + if (!dvp) { + throw Base::TypeError("CmdTechDrawView DVP not found\n"); + } + dvp->Source.setValues(shapes); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + if (faceName.size()) { + std::pair dirs = DrawGuiUtil::getProjDirFromFace(partObj,faceName); + projDir = dirs.first; + getDocument()->setStatus(App::Document::Status::SkipRecompute, true); + doCommand(Doc,"App.activeDocument().%s.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", + FeatName.c_str(), projDir.x,projDir.y,projDir.z); + //do something clever with dirs.second; +// dvp->setXDir(dirs.second); + doCommand(Doc,"App.activeDocument().%s.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", + FeatName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); + doCommand(Doc,"App.activeDocument().%s.recompute()", FeatName.c_str()); + getDocument()->setStatus(App::Document::Status::SkipRecompute, false); + } else { + std::pair dirs = DrawGuiUtil::get3DDirAndRot(); + projDir = dirs.first; + getDocument()->setStatus(App::Document::Status::SkipRecompute, true); + doCommand(Doc,"App.activeDocument().%s.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", + FeatName.c_str(), projDir.x,projDir.y,projDir.z); + doCommand(Doc,"App.activeDocument().%s.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", + FeatName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); +// dvp->setXDir(dirs.second); + getDocument()->setStatus(App::Document::Status::SkipRecompute, false); + doCommand(Doc,"App.activeDocument().%s.recompute()", FeatName.c_str()); + } + commitCommand(); +} + +bool CmdTechDrawView::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +//=========================================================================== +// TechDraw_ActiveView +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawActiveView) + +CmdTechDrawActiveView::CmdTechDrawActiveView() + : Command("TechDraw_ActiveView") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Active View (3D View)"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_ActiveView"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ActiveView"; +} + +void CmdTechDrawActiveView::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + Gui::Control().showDialog(new TaskDlgActiveView(page)); +} + +bool CmdTechDrawActiveView::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +//=========================================================================== +// TechDraw_SectionView +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawSectionView) + +CmdTechDrawSectionView::CmdTechDrawSectionView() + : Command("TechDraw_SectionView") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Section View"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_SectionView"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-SectionView"; +} + +void CmdTechDrawSectionView::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + + std::vector baseObj = getSelection().getObjectsOfType(TechDraw::DrawViewPart::getClassTypeId()); + if (baseObj.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select at least 1 DrawViewPart object as Base.")); + return; + } + TechDraw::DrawViewPart* dvp = static_cast(*baseObj.begin()); +// std::string BaseName = dvp->getNameInDocument(); +// std::string PageName = page->getNameInDocument(); +// double baseScale = dvp->getScale(); + +// Gui::WaitCursor wc; +// openCommand("Create view"); +// std::string FeatName = getUniqueObjectName("Section"); + +// doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewSection','%s')",FeatName.c_str()); + +// App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); +// TechDraw::DrawViewSection* dsv = dynamic_cast(docObj); +// if (!dsv) { +// throw Base::TypeError("CmdTechDrawSectionView DVS not found\n"); +// } +// dsv->Source.setValues(dvp->Source.getValues()); +// doCommand(Doc,"App.activeDocument().%s.BaseView = App.activeDocument().%s",FeatName.c_str(),BaseName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.ScaleType = App.activeDocument().%s.ScaleType",FeatName.c_str(),BaseName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Scale = %0.6f",FeatName.c_str(),baseScale); + Gui::Control().showDialog(new TaskDlgSectionView(dvp)); + + updateActive(); //ok here since dialog doesn't call doc.recompute() + commitCommand(); +} + +bool CmdTechDrawSectionView::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this); + bool taskInProgress = false; + if (havePage) { + taskInProgress = Gui::Control().activeDialog(); + } + return (havePage && haveView && !taskInProgress); +} + +//=========================================================================== +// TechDraw_DetailView +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawDetailView) + +CmdTechDrawDetailView::CmdTechDrawDetailView() + : Command("TechDraw_DetailView") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Detail View"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_DetailView"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-DetailView"; +} + +void CmdTechDrawDetailView::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + + std::vector baseObj = getSelection(). + getObjectsOfType(TechDraw::DrawViewPart::getClassTypeId()); + if (baseObj.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select at least 1 DrawViewPart object as Base.")); + return; + } + TechDraw::DrawViewPart* dvp = static_cast(*(baseObj.begin())); + + Gui::Control().showDialog(new TaskDlgDetail(dvp)); +} + +bool CmdTechDrawDetailView::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this); + bool taskInProgress = false; + if (havePage) { + taskInProgress = Gui::Control().activeDialog(); + } + return (havePage && haveView && !taskInProgress); +} + +//=========================================================================== +// TechDraw_ProjectionGroup +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawProjectionGroup) + +CmdTechDrawProjectionGroup::CmdTechDrawProjectionGroup() + : Command("TechDraw_ProjectionGroup") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Projection Group"); + sToolTipText = QT_TR_NOOP("Insert multiple linked views of drawable object(s)"); + sWhatsThis = "TechDraw_ProjectionGroup"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ProjectionGroup"; +} + +void CmdTechDrawProjectionGroup::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); +// auto inlist = page->getInListEx(true); +// inlist.insert(page); + + //set projection direction from selected Face + //use first object with a face selected + std::vector shapes; + App::DocumentObject* partObj = nullptr; + std::string faceName; + int resolve = 1; //mystery + bool single = false; //mystery + auto selection = getSelection().getSelectionEx(0, + App::DocumentObject::getClassTypeId(), + resolve, + single); + for (auto& sel: selection) { +// for(auto &sel : getSelection().getSelectionEx(0,App::DocumentObject::getClassTypeId(),false)) { + auto obj = sel.getObject(); + if (obj->isDerivedFrom(TechDraw::DrawPage::getClassTypeId()) ) { + continue; + } +// if(!obj || inlist.count(obj)) //?????? +// continue; + if (obj != nullptr) { //can this happen? + shapes.push_back(obj); + } + if(partObj != nullptr) { + continue; + } + for(auto& sub : sel.getSubNames()) { + if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") { + faceName = sub; + partObj = obj; + break; + } + } + } + if (shapes.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No Shapes or Groups in this selection")); + return; + } + + Base::Vector3d projDir; + Gui::WaitCursor wc; + + openCommand("Create Projection Group"); + + std::string multiViewName = getUniqueObjectName("ProjGroup"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawProjGroup','%s')", + multiViewName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)", + PageName.c_str(),multiViewName.c_str()); + + App::DocumentObject *docObj = getDocument()->getObject(multiViewName.c_str()); + auto multiView( static_cast(docObj) ); + multiView->Source.setValues(shapes); + doCommand(Doc,"App.activeDocument().%s.addProjection('Front')",multiViewName.c_str()); + + if (faceName.size()) { + std::pair dirs = DrawGuiUtil::getProjDirFromFace(partObj,faceName); + getDocument()->setStatus(App::Document::Status::SkipRecompute, true); + doCommand(Doc,"App.activeDocument().%s.Anchor.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", + multiViewName.c_str(), dirs.first.x,dirs.first.y,dirs.first.z); + doCommand(Doc,"App.activeDocument().%s.Anchor.RotationVector = FreeCAD.Vector(%.3f,%.3f,%.3f)", + multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); + doCommand(Doc,"App.activeDocument().%s.Anchor.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", + multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); + getDocument()->setStatus(App::Document::Status::SkipRecompute, false); + } else { + std::pair dirs = DrawGuiUtil::get3DDirAndRot(); + getDocument()->setStatus(App::Document::Status::SkipRecompute, true); + doCommand(Doc,"App.activeDocument().%s.Anchor.Direction = FreeCAD.Vector(%.3f,%.3f,%.3f)", + multiViewName.c_str(), dirs.first.x,dirs.first.y,dirs.first.z); + doCommand(Doc,"App.activeDocument().%s.Anchor.RotationVector = FreeCAD.Vector(%.3f,%.3f,%.3f)", + multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); + doCommand(Doc,"App.activeDocument().%s.Anchor.XDirection = FreeCAD.Vector(%.3f,%.3f,%.3f)", + multiViewName.c_str(), dirs.second.x,dirs.second.y,dirs.second.z); + getDocument()->setStatus(App::Document::Status::SkipRecompute, false); + } + + doCommand(Doc,"App.activeDocument().%s.Anchor.recompute()", multiViewName.c_str()); + commitCommand(); + updateActive(); + + // create the rest of the desired views + Gui::Control().showDialog(new TaskDlgProjGroup(multiView,true)); +} + +bool CmdTechDrawProjectionGroup::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool taskInProgress = false; + if (havePage) { + taskInProgress = Gui::Control().activeDialog(); + } + return (havePage && !taskInProgress); +} + +//=========================================================================== +// TechDraw_NewMulti **deprecated** +//=========================================================================== + +//DEF_STD_CMD_A(CmdTechDrawNewMulti); + +//CmdTechDrawNewMulti::CmdTechDrawNewMulti() +// : Command("TechDraw_NewMulti") +//{ +// sAppModule = "TechDraw"; +// sGroup = QT_TR_NOOP("TechDraw"); +// sMenuText = QT_TR_NOOP("Insert multi-part view in drawing"); +// sToolTipText = QT_TR_NOOP("Insert a new View of a multiple Parts in the active drawing"); +// sWhatsThis = "TechDraw_NewMulti"; +// sStatusTip = sToolTipText; +// sPixmap = "actions/techdraw-multiview"; +//} + +//void CmdTechDrawNewMulti::activated(int iMsg) +//{ +// Q_UNUSED(iMsg); +// TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); +// if (!page) { +// return; +// } + +// std::vector shapes = getSelection().getObjectsOfType(App::DocumentObject::getClassTypeId()); +// if (shapes.empty()) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("Can not MultiView from this selection.")); +// return; +// } + +// std::string PageName = page->getNameInDocument(); + +// Gui::WaitCursor wc; + +// openCommand("Create view"); +// std::string FeatName = getUniqueObjectName("MultiView"); +// doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewMulti','%s')",FeatName.c_str()); +// App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); +// auto multiView( static_cast(docObj) ); +// multiView->Sources.setValues(shapes); +// doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); +// updateActive(); +// commitCommand(); +//} + +//bool CmdTechDrawNewMulti::isActive(void) +//{ +// return DrawGuiUtil::needPage(this); +//} + +//=========================================================================== +// TechDraw_Balloon +//=========================================================================== + +//! common checks of Selection for Dimension commands +//non-empty selection, no more than maxObjs selected and at least 1 DrawingPage exists +bool _checkSelectionBalloon(Gui::Command* cmd, unsigned maxObjs) { + std::vector selection = cmd->getSelection().getSelectionEx(); + if (selection.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), + QObject::tr("Select an object first")); + return false; + } + + const std::vector SubNames = selection[0].getSubNames(); + if (SubNames.size() > maxObjs){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), + QObject::tr("Too many objects selected")); + return false; + } + + std::vector pages = cmd->getDocument()->getObjectsOfType(TechDraw::DrawPage::getClassTypeId()); + if (pages.empty()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Incorrect selection"), + QObject::tr("Create a page first.")); + return false; + } + return true; +} + +bool _checkDrawViewPartBalloon(Gui::Command* cmd) { + std::vector selection = cmd->getSelection().getSelectionEx(); + auto objFeat( dynamic_cast(selection[0].getObject()) ); + if( !objFeat ) { + QMessageBox::warning( Gui::getMainWindow(), + QObject::tr("Incorrect selection"), + QObject::tr("No View of a Part in selection.") ); + return false; + } + return true; +} + +DEF_STD_CMD_A(CmdTechDrawBalloon) + +CmdTechDrawBalloon::CmdTechDrawBalloon() + : Command("TechDraw_Balloon") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Balloon Annotation"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_Balloon"; + sStatusTip = sToolTipText; + sPixmap = "TechDraw_Balloon"; +} + +void CmdTechDrawBalloon::activated(int iMsg) +{ + Q_UNUSED(iMsg); + bool result = _checkSelectionBalloon(this,1); + if (!result) + return; + result = _checkDrawViewPartBalloon(this); + if (!result) + return; + + std::vector selection = getSelection().getSelectionEx(); + auto objFeat( dynamic_cast(selection[0].getObject()) ); + if( objFeat == nullptr ) { + return; + } + + TechDraw::DrawPage* page = objFeat->findParentPage(); + std::string PageName = page->getNameInDocument(); + + page->balloonParent = objFeat; + page->balloonPlacing = true; + +} + +bool CmdTechDrawBalloon::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this); + return (havePage && haveView); +} + +//=========================================================================== +// TechDraw_ClipGroup +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawClipGroup) + +CmdTechDrawClipGroup::CmdTechDrawClipGroup() + : Command("TechDraw_ClipGroup") +{ + // setting the + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Clip Group"); + sToolTipText = sToolTipText; + sWhatsThis = "TechDraw_ClipGroup"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ClipGroup"; +} + +void CmdTechDrawClipGroup::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + + std::string FeatName = getUniqueObjectName("Clip"); + openCommand("Create Clip"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewClip','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdTechDrawClipGroup::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +//=========================================================================== +// TechDraw_ClipGroupAdd +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawClipGroupAdd) + +CmdTechDrawClipGroupAdd::CmdTechDrawClipGroupAdd() + : Command("TechDraw_ClipGroupAdd") +{ + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Add View to Clip Group"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_ClipGroupAdd"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ClipGroupAdd"; +} + +void CmdTechDrawClipGroupAdd::activated(int iMsg) +{ + Q_UNUSED(iMsg); + std::vector selection = getSelection().getSelectionEx(); + if (selection.size() != 2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select one Clip group and one View.")); + return; + } + + TechDraw::DrawViewClip* clip = 0; + TechDraw::DrawView* view = 0; + std::vector::iterator itSel = selection.begin(); + for (; itSel != selection.end(); itSel++) { + if ((*itSel).getObject()->isDerivedFrom(TechDraw::DrawViewClip::getClassTypeId())) { + clip = static_cast((*itSel).getObject()); + } else if ((*itSel).getObject()->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) { + view = static_cast((*itSel).getObject()); + } + } + if (!view) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select exactly one View to add to group.")); + return; + } + if (!clip) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select exactly one Clip group.")); + return; + } + + TechDraw::DrawPage* pageClip = clip->findParentPage(); + TechDraw::DrawPage* pageView = view->findParentPage(); + + if (pageClip != pageView) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Clip and View must be from same Page.")); + return; + } + + std::string PageName = pageClip->getNameInDocument(); + std::string ClipName = clip->getNameInDocument(); + std::string ViewName = view->getNameInDocument(); + + openCommand("ClipGroupAdd"); + doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = False",ViewName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",ClipName.c_str(),ViewName.c_str()); + doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = True",ViewName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdTechDrawClipGroupAdd::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveClip = false; + if (havePage) { + auto drawClipType( TechDraw::DrawViewClip::getClassTypeId() ); + auto selClips = getDocument()->getObjectsOfType(drawClipType); + if (!selClips.empty()) { + haveClip = true; + } + } + return (havePage && haveClip); +} + +//=========================================================================== +// TechDraw_ClipGroupRemove +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawClipGroupRemove) + +CmdTechDrawClipGroupRemove::CmdTechDrawClipGroupRemove() + : Command("TechDraw_ClipGroupRemove") +{ + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Remove View from Clip Group"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_ClipGroupRemove"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ClipGroupRemove"; +} + +void CmdTechDrawClipGroupRemove::activated(int iMsg) +{ + Q_UNUSED(iMsg); + auto dObj( getSelection().getObjectsOfType(TechDraw::DrawView::getClassTypeId()) ); + if (dObj.empty()) { + QMessageBox::warning( Gui::getMainWindow(), + QObject::tr("Wrong selection"), + QObject::tr("Select exactly one View to remove from Group.") ); + return; + } + + auto view( static_cast(dObj.front()) ); + + TechDraw::DrawPage* page = view->findParentPage(); + const std::vector pViews = page->Views.getValues(); + TechDraw::DrawViewClip *clip(nullptr); + for (auto &v : pViews) { + clip = dynamic_cast(v); + if (clip && clip->isViewInClip(view)) { + break; + } + clip = nullptr; + } + + if (!clip) { + QMessageBox::warning( Gui::getMainWindow(), + QObject::tr("Wrong selection"), + QObject::tr("View does not belong to a Clip") ); + return; + } + + std::string ClipName = clip->getNameInDocument(); + std::string ViewName = view->getNameInDocument(); + + openCommand("ClipGroupRemove"); + doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = False",ViewName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeView(App.activeDocument().%s)",ClipName.c_str(),ViewName.c_str()); + doCommand(Doc,"App.activeDocument().%s.ViewObject.Visibility = True",ViewName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdTechDrawClipGroupRemove::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveClip = false; + if (havePage) { + auto drawClipType( TechDraw::DrawViewClip::getClassTypeId() ); + auto selClips = getDocument()->getObjectsOfType(drawClipType); + if (!selClips.empty()) { + haveClip = true; + } + } + return (havePage && haveClip); +} + + +//=========================================================================== +// TechDraw_Symbol +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawSymbol) + +CmdTechDrawSymbol::CmdTechDrawSymbol() + : Command("TechDraw_Symbol") +{ + // setting the Gui eye-candy + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert SVG Symbol"); + sToolTipText = QT_TR_NOOP("Insert symbol from a SVG file"); + sWhatsThis = "TechDraw_Symbol"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-symbol"; +} + +void CmdTechDrawSymbol::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + + // Reading an image + QString filename = Gui::FileDialog::getOpenFileName(Gui::getMainWindow(), + QObject::tr("Choose an SVG file to open"), QString::null, + QString::fromLatin1("%1 (*.svg *.svgz);;%2 (*.*)"). + arg(QObject::tr("Scalable Vector Graphic")). + arg(QObject::tr("All Files"))); + + if (!filename.isEmpty()) + { + std::string FeatName = getUniqueObjectName("Symbol"); + filename = Base::Tools::escapeEncodeFilename(filename); + openCommand("Create Symbol"); +#if PY_MAJOR_VERSION < 3 + doCommand(Doc,"f = open(unicode(\"%s\",'utf-8'),'r')",(const char*)filename.toUtf8()); +#else + doCommand(Doc,"f = open(\"%s\",'r')",(const char*)filename.toUtf8()); +#endif + doCommand(Doc,"svg = f.read()"); + doCommand(Doc,"f.close()"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewSymbol','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Symbol = svg",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); + } +} + +bool CmdTechDrawSymbol::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +//=========================================================================== +// TechDraw_DraftView +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawDraftView) + +CmdTechDrawDraftView::CmdTechDrawDraftView() + : Command("TechDraw_DraftView") +{ + // setting the Gui eye-candy + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Draft Workbench Object"); + sToolTipText = QT_TR_NOOP("Insert a View of a Draft Workbench object"); + sWhatsThis = "TechDraw_NewDraft"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-DraftView"; +} + +void CmdTechDrawDraftView::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + + std::vector objects = getSelection(). + getObjectsOfType(App::DocumentObject::getClassTypeId()); + + if (objects.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select at least one object.")); + return; + } + + int draftItemsFound = 0; + for (std::vector::iterator it = objects.begin(); it != objects.end(); ++it) { + if (DrawGuiUtil::isDraftObject((*it))) { + draftItemsFound++; + std::string FeatName = getUniqueObjectName("DraftView"); + std::string SourceName = (*it)->getNameInDocument(); + openCommand("Create DraftView"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewDraft','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s", + FeatName.c_str(),SourceName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)", + PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); + } + } + if (draftItemsFound == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("There were no DraftWB objects in the selection.")); + } +} + +bool CmdTechDrawDraftView::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +//=========================================================================== +// TechDraw_ArchView +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawArchView) + +CmdTechDrawArchView::CmdTechDrawArchView() + : Command("TechDraw_ArchView") +{ + // setting the Gui eye-candy + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Arch Workbench Object"); + sToolTipText = QT_TR_NOOP("Insert a View of a Section Plane from Arch Workbench"); + sWhatsThis = "TechDraw_NewArch"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ArchView"; +} + +void CmdTechDrawArchView::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + + + const std::vector objects = getSelection(). + getObjectsOfType(App::DocumentObject::getClassTypeId()); + App::DocumentObject* archObject = nullptr; + int archCount = 0; + for (auto& obj : objects) { + if (DrawGuiUtil::isArchSection(obj) ) { + archCount++; + archObject = obj; + } + } + if ( archCount > 1 ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Please select only 1 Arch Section.")); + return; + } + + if (archObject == nullptr) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No Arch Sections in selection.")); + return; + } + + std::string FeatName = getUniqueObjectName("ArchView"); + std::string SourceName = archObject->getNameInDocument(); + openCommand("Create ArchView"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewArch','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s",FeatName.c_str(),SourceName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdTechDrawArchView::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +//=========================================================================== +// TechDraw_SpreadsheetView +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawSpreadsheetView) + +CmdTechDrawSpreadsheetView::CmdTechDrawSpreadsheetView() + : Command("TechDraw_SpreadsheetView") +{ + // setting the + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Spreadsheet View"); + sToolTipText = QT_TR_NOOP("Insert View to a spreadsheet"); + sWhatsThis = "TechDraw_SpreadsheetView"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-SpreadsheetView"; +} + +void CmdTechDrawSpreadsheetView::activated(int iMsg) +{ + Q_UNUSED(iMsg); + const std::vector spreads = getSelection().getObjectsOfType(Spreadsheet::Sheet::getClassTypeId()); + if (spreads.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select exactly one Spreadsheet object.")); + return; + } + std::string SpreadName = spreads.front()->getNameInDocument(); + + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + + openCommand("Create spreadsheet view"); + std::string FeatName = getUniqueObjectName("Sheet"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewSpreadsheet','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s",FeatName.c_str(),SpreadName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdTechDrawSpreadsheetView::isActive(void) +{ + //need a Page and a SpreadSheet::Sheet + bool havePage = DrawGuiUtil::needPage(this); + bool haveSheet = false; + if (havePage) { + auto spreadSheetType( Spreadsheet::Sheet::getClassTypeId() ); + auto selSheets = getDocument()->getObjectsOfType(spreadSheetType); + if (!selSheets.empty()) { + haveSheet = true; + } + } + return (havePage && haveSheet); +} + + +//=========================================================================== +// TechDraw_ExportPageSVG +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawExportPageSVG) + +CmdTechDrawExportPageSVG::CmdTechDrawExportPageSVG() + : Command("TechDraw_ExportPageSVG") +{ + sGroup = QT_TR_NOOP("File"); + sMenuText = QT_TR_NOOP("Export Page as SVG"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_ExportPageSVG"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ExportPageSVG"; +} + +void CmdTechDrawExportPageSVG::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + std::string PageName = page->getNameInDocument(); + + Gui::Document* activeGui = Gui::Application::Instance->getDocument(page->getDocument()); + Gui::ViewProvider* vp = activeGui->getViewProvider(page); + ViewProviderPage* dvp = dynamic_cast(vp); + + if (dvp && dvp->getMDIViewPage()) { + dvp->getMDIViewPage()->saveSVG(); + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No Drawing View"), + QObject::tr("Open Drawing View before attempting export to SVG.")); + return; + } +} + +bool CmdTechDrawExportPageSVG::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +//=========================================================================== +// TechDraw_ExportPageDXF +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawExportPageDXF) + +CmdTechDrawExportPageDXF::CmdTechDrawExportPageDXF() + : Command("TechDraw_ExportPageDXF") +{ + sGroup = QT_TR_NOOP("File"); + sMenuText = QT_TR_NOOP("Export Page as DXF"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_ExportPageDXF"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-ExportPageDXF"; +} + +void CmdTechDrawExportPageDXF::activated(int iMsg) +{ + Q_UNUSED(iMsg); + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + + std::vector views = page->Views.getValues(); + for (auto& v: views) { + if (v->isDerivedFrom(TechDraw::DrawViewArch::getClassTypeId())) { + QMessageBox::StandardButton rc = + QMessageBox::question(Gui::getMainWindow(), QObject::tr("Can not export selection"), + QObject::tr("Page contains DrawViewArch which will not be exported. Continue?"), + QMessageBox::StandardButtons(QMessageBox::Yes| QMessageBox::No)); + if (rc == QMessageBox::No) { + return; + } else { + break; + } + } + } + +//WF? allow more than one TD Page per Dxf file?? 1 TD page = 1 DXF file = 1 drawing? + QString defaultDir; + QString fileName = Gui::FileDialog::getSaveFileName(Gui::getMainWindow(), + QString::fromUtf8(QT_TR_NOOP("Save Dxf File ")), + defaultDir, + QString::fromUtf8(QT_TR_NOOP("Dxf (*.dxf)"))); + + if (fileName.isEmpty()) { + return; + } + + std::string PageName = page->getNameInDocument(); + openCommand("Save page to dxf"); + doCommand(Doc,"import TechDraw"); + fileName = Base::Tools::escapeEncodeFilename(fileName); + doCommand(Doc,"TechDraw.writeDXFPage(App.activeDocument().%s,u\"%s\")",PageName.c_str(),(const char*)fileName.toUtf8()); + commitCommand(); +} + + +bool CmdTechDrawExportPageDXF::isActive(void) +{ + return DrawGuiUtil::needPage(this); +} + +void CreateTechDrawCommands(void) +{ + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + + rcCmdMgr.addCommand(new CmdTechDrawPageDefault()); + rcCmdMgr.addCommand(new CmdTechDrawPageTemplate()); + rcCmdMgr.addCommand(new CmdTechDrawRedrawPage()); + rcCmdMgr.addCommand(new CmdTechDrawView()); + rcCmdMgr.addCommand(new CmdTechDrawActiveView()); + rcCmdMgr.addCommand(new CmdTechDrawSectionView()); + rcCmdMgr.addCommand(new CmdTechDrawDetailView()); + rcCmdMgr.addCommand(new CmdTechDrawProjectionGroup()); + rcCmdMgr.addCommand(new CmdTechDrawClipGroup()); + rcCmdMgr.addCommand(new CmdTechDrawClipGroupAdd()); + rcCmdMgr.addCommand(new CmdTechDrawClipGroupRemove()); + rcCmdMgr.addCommand(new CmdTechDrawSymbol()); + rcCmdMgr.addCommand(new CmdTechDrawExportPageSVG()); + rcCmdMgr.addCommand(new CmdTechDrawExportPageDXF()); + rcCmdMgr.addCommand(new CmdTechDrawDraftView()); + rcCmdMgr.addCommand(new CmdTechDrawArchView()); + rcCmdMgr.addCommand(new CmdTechDrawSpreadsheetView()); + rcCmdMgr.addCommand(new CmdTechDrawBalloon()); +} diff --git a/src/Mod/TechDraw/Gui/QGIGhostHighlight.cpp b/src/Mod/TechDraw/Gui/QGIGhostHighlight.cpp new file mode 100644 index 0000000000..c0ac483a4c --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGIGhostHighlight.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (c) 2020 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include "Rez.h" +#include "DrawGuiUtil.h" +#include "QGIView.h" +#include "QGIGhostHighlight.h" + +using namespace TechDrawGui; +using namespace TechDraw; + +QGIGhostHighlight::QGIGhostHighlight() +{ + setInteractive(true); + m_dragging = false; + + //make the ghost very visible + QFont f(QGIView::getPrefFont()); + double fontSize = QGIView::getPrefFontSize(); + setFont(f, fontSize); + setReference("drag"); + setStyle(Qt::SolidLine); + setColor(prefSelectColor()); + setWidth(Rez::guiX(1.0)); + setRadius(10.0); //placeholder +} + +QGIGhostHighlight::~QGIGhostHighlight() +{ + +} + +QVariant QGIGhostHighlight::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemPositionHasChanged && scene()) { + // nothing to do here? + } + return QGIHighlight::itemChange(change, value); +} + +void QGIGhostHighlight::mousePressEvent(QGraphicsSceneMouseEvent * event) +{ +// Base::Console().Message("QGIGhostHighlight::mousePress() - %X\n", this); + if ( (event->button() == Qt::LeftButton) && + (flags() && QGraphicsItem::ItemIsMovable) ) { + m_dragging = true; + event->accept(); + } + QGIHighlight::mousePressEvent(event); +} + +void QGIGhostHighlight::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) +{ +// Base::Console().Message("QGIGhostHighlight::mouseRelease() - pos: %s scenePos: %s\n", +// DrawUtil::formatVector(pos()).c_str(), +// DrawUtil::formatVector(mapToScene(pos())).c_str()); + if (m_dragging) { + m_dragging = false; + Q_EMIT positionChange(scenePos()); + event->accept(); + } + QGIHighlight::mouseReleaseEvent(event); +} + +void QGIGhostHighlight::setInteractive(bool state) +{ + setFlag(QGraphicsItem::ItemIsSelectable, state); + setFlag(QGraphicsItem::ItemIsMovable, state); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges, state); + setFlag(QGraphicsItem::ItemSendsGeometryChanges, state); +} + +//radius should scaled, but not Rez::guix() +void QGIGhostHighlight::setRadius(double r) +{ + setBounds(-r, r, r, -r); +} + +#include diff --git a/src/Mod/TechDraw/Gui/QGIGhostHighlight.h b/src/Mod/TechDraw/Gui/QGIGhostHighlight.h new file mode 100644 index 0000000000..0f86095a79 --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGIGhostHighlight.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (c) 2020 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef TECHDRAWGUI_QGIGHOSTHIGHLIGHT_H +#define TECHDRAWGUI_QGIGHOSTHIGHLIGHT_H + +#include +#include +#include +#include + +#include "QGIHighlight.h" + +//a movable, selectable surrogate for detail highlights in QGIVPart + +namespace TechDrawGui +{ + +class TechDrawGuiExport QGIGhostHighlight : public QObject, public QGIHighlight +{ + Q_OBJECT +public: + explicit QGIGhostHighlight(); + ~QGIGhostHighlight(); + + enum {Type = QGraphicsItem::UserType + 177}; + int type() const { return Type;} + + void setInteractive(bool state); + void setRadius(double r); + +Q_SIGNALS: + void positionChange(QPointF p); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + + bool m_dragging; + +private: +}; + +} + +#endif // TECHDRAWGUI_QGIGHOSTHIGHLIGHT_H diff --git a/src/Mod/TechDraw/Gui/QGIHighlight.cpp b/src/Mod/TechDraw/Gui/QGIHighlight.cpp index f67212861e..8501a8106e 100644 --- a/src/Mod/TechDraw/Gui/QGIHighlight.cpp +++ b/src/Mod/TechDraw/Gui/QGIHighlight.cpp @@ -46,19 +46,65 @@ QGIHighlight::QGIHighlight() { m_refText = ""; m_refSize = 0.0; + setInteractive(false); + m_circle = new QGraphicsEllipseItem(); addToGroup(m_circle); + m_circle->setFlag(QGraphicsItem::ItemIsSelectable, false); + m_rect = new QGCustomRect(); addToGroup(m_rect); + m_rect->setFlag(QGraphicsItem::ItemIsSelectable, false); + m_reference = new QGCustomText(); addToGroup(m_reference); + m_reference->setFlag(QGraphicsItem::ItemIsSelectable, false); setWidth(Rez::guiX(0.75)); setStyle(getHighlightStyle()); setColor(getHighlightColor()); +} + +QGIHighlight::~QGIHighlight() +{ } +//really only want to emit signal at end of movement +//QVariant QGIHighlight::itemChange(GraphicsItemChange change, const QVariant &value) +//{ +// if (change == ItemPositionHasChanged && scene()) { +// // nothing to do here +// } +// return QGraphicsItem::itemChange(change, value); +//} + +//void QGIHighlight::mousePressEvent(QGraphicsSceneMouseEvent * event) +//{ +// Base::Console().Message("QGIHighlight::mousePress() - %X\n", this); +//// if(scene() && m_reference == scene()->mouseGrabberItem()) { +// if ( (event->button() == Qt::LeftButton) && +// (flags() && QGraphicsItem::ItemIsMovable) ) { +// m_dragging = true; +// } +//// } +// QGIDecoration::mousePressEvent(event); +//} + +//void QGIHighlight::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) +//{ +// Base::Console().Message("QGIHighlight::mouseRelease() - %X grabber: %X\n", this, scene()->mouseGrabberItem()); +//// if(scene() && this == scene()->mouseGrabberItem()) { +// if (m_dragging) { +// m_dragging = false; +//// QString itemName = data(0).toString(); +// Q_EMIT positionChange(pos()); +// return; +// } +//// } +// QGIDecoration::mouseReleaseEvent(event); +//} + void QGIHighlight::draw() { prepareGeometryChange(); @@ -100,6 +146,15 @@ void QGIHighlight::makeReference() } } +void QGIHighlight::setInteractive(bool state) +{ +// setAcceptHoverEvents(state); + setFlag(QGraphicsItem::ItemIsSelectable, state); + setFlag(QGraphicsItem::ItemIsMovable, state); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges, state); + setFlag(QGraphicsItem::ItemSendsGeometryChanges, state); +} + void QGIHighlight::setBounds(double x1,double y1,double x2,double y2) { m_start = QPointF(Rez::guiX(x1),Rez::guiX(-y1)); @@ -142,10 +197,9 @@ int QGIHighlight::getHoleStyle() return style; } - void QGIHighlight::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { QStyleOptionGraphicsItem myOption(*option); - myOption.state &= ~QStyle::State_Selected; +// myOption.state &= ~QStyle::State_Selected; setTools(); // painter->drawRect(boundingRect()); //good for debugging @@ -165,3 +219,4 @@ void QGIHighlight::setTools() m_reference->setDefaultTextColor(m_colCurrent); } + diff --git a/src/Mod/TechDraw/Gui/QGIHighlight.h b/src/Mod/TechDraw/Gui/QGIHighlight.h index 809f9b3fe3..4b3a9f02e5 100644 --- a/src/Mod/TechDraw/Gui/QGIHighlight.h +++ b/src/Mod/TechDraw/Gui/QGIHighlight.h @@ -25,9 +25,12 @@ #include #include +#include #include #include #include +#include +#include #include #include @@ -45,19 +48,25 @@ class TechDrawGuiExport QGIHighlight : public QGIDecoration { public: explicit QGIHighlight(); - ~QGIHighlight() {} + ~QGIHighlight(); - enum {Type = QGraphicsItem::UserType + 172}; + enum {Type = QGraphicsItem::UserType + 176}; int type() const { return Type;} - virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); + virtual void paint(QPainter * painter, + const QStyleOptionGraphicsItem * option, + QWidget * widget = 0 ) override; void setBounds(double x1,double y1,double x2,double y2); void setReference(char* sym); void setFont(QFont f, double fsize); virtual void draw(); + void setInteractive(bool state); protected: +/* virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;*/ +/* virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;*/ +/* virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;*/ QColor getHighlightColor(); Qt::PenStyle getHighlightStyle(); void makeHighlight(); @@ -65,6 +74,7 @@ protected: void setTools(); int getHoleStyle(void); +/* bool m_dragging;*/ private: char* m_refText; diff --git a/src/Mod/TechDraw/Gui/QGIUserTypes.h b/src/Mod/TechDraw/Gui/QGIUserTypes.h index 7995cfa785..df54412148 100644 --- a/src/Mod/TechDraw/Gui/QGIUserTypes.h +++ b/src/Mod/TechDraw/Gui/QGIUserTypes.h @@ -1,26 +1,26 @@ /* -Derived QGraphicsItem Classes type() Values +Derived QGI Classes type() Values Qt First UserType>> QGraphicsItem::UserType = 65536 -QGraphicsItemView : 101 -QGraphicsItemViewPart : 102 -QGraphicsItemEdge: 103 -QGraphicsItemFace: 104 -QGraphicsItemVertex: 105 -QGraphicsItemViewDimension : 106 -QGraphicsItemViewBalloon : 140 -QGraphicsItemBalloonLabel : 141 -QGraphicsItemDatumLabel : 107 -QGraphicsItemViewSection : 108 -QGraphicsItemArrow: 109 -QGraphicsItemViewCollection : 110 -QGraphicsItemViewOrthographic : 113 -QGraphicsItemViewAnnotation : 120 -QGraphicsItemViewSymbol : 121 -QGraphicsItemHatch : 122 //obsolete -QGraphicsItemClip : 123 -QGraphicsItemSpreadsheet : 124 +QGIView : 101 +QGIViewPart : 102 +QGIEdge: 103 +QGIFace: 104 +QGIVertex: 105 +QGIViewDimension : 106 +QGIViewBalloon : 140 +QGIBalloonLabel : 141 +QGIDatumLabel : 107 +QGIViewSection : 108 +QGIArrow: 109 +QGIViewCollection : 110 +QGIProjGroup : 113 +QGIViewAnnotation : 120 +QGIViewSymbol : 121 +QGIHatch : 122 //obsolete +QGIClip : 123 +QGISpreadsheet : 124 QGCustomText: 130 QGCustomSvg: 131 QGCustomClip: 132 @@ -28,9 +28,9 @@ QGCustomRect: 133 QGCustomLabel:135 QGCustomBorder: 136 QGDisplayArea: 137 -QGraphicsItemTemplate: 150 -QGraphicsItemDrawingTemplate: 151 -QGraphicsItemSVGTemplate: 153 +QGITemplate: 150 +QGIDrawingTemplate: 151 +QGISVGTemplate: 153 TemplateTextField: 160 QGIPrimPath: 170 QGICMark: 171 @@ -38,6 +38,8 @@ QGISectionLine: 172 QGIDecoration: 173 QGICenterLine: 174 QGIDimLines: 175 +QGIHighlight: 176 +QGIGhostHighlight: 177 QGICaption: 180 QGIViewImage: 200 QGCustomImage: 201 diff --git a/src/Mod/TechDraw/Gui/QGIView.h b/src/Mod/TechDraw/Gui/QGIView.h index ac8faff4ef..7ba639ee6c 100644 --- a/src/Mod/TechDraw/Gui/QGIView.h +++ b/src/Mod/TechDraw/Gui/QGIView.h @@ -121,6 +121,11 @@ public: static int calculateFontPixelWidth(const QFont &font); static const double DefaultFontSizeInMM; + static QString getPrefFont(void); + static double getPrefFontSize(void); + static double getDimFontSize(void); + + MDIViewPage* getMDIViewPage(void) const; virtual void removeChild(QGIView* child); @@ -145,9 +150,9 @@ protected: virtual QRectF customChildrenBoundingRect(void) const; void dumpRect(const char* text, QRectF r); - QString getPrefFont(void); - double getPrefFontSize(void); - double getDimFontSize(void); +/* QString getPrefFont(void);*/ +/* double getPrefFontSize(void);*/ +/* double getDimFontSize(void);*/ Base::Reference getParmGroupCol(void); diff --git a/src/Mod/TechDraw/Gui/Rez.cpp b/src/Mod/TechDraw/Gui/Rez.cpp index e75c0ca02e..21ab1eb63f 100644 --- a/src/Mod/TechDraw/Gui/Rez.cpp +++ b/src/Mod/TechDraw/Gui/Rez.cpp @@ -67,6 +67,11 @@ Base::Vector2d Rez::guiX(Base::Vector3d v, bool planar) return Base::Vector2d(guiX(v.x), guiX(v.y)); } +QPointF Rez::guiX(QPointF p) +{ + return Rez::guiPt(p); +} + //turn Gui side value to App side value double Rez::appX(double x) { @@ -85,6 +90,7 @@ QPointF Rez::appX(QPointF p) } + //Misc conversions QPointF Rez::guiPt(QPointF p) { diff --git a/src/Mod/TechDraw/Gui/Rez.h b/src/Mod/TechDraw/Gui/Rez.h index f35e48a76c..5a03e8551f 100644 --- a/src/Mod/TechDraw/Gui/Rez.h +++ b/src/Mod/TechDraw/Gui/Rez.h @@ -43,6 +43,8 @@ public: static double guiX(double x); static Base::Vector3d guiX(Base::Vector3d v); static Base::Vector2d guiX(Base::Vector3d v, bool planar); + static QPointF guiX(QPointF p); + //turn Gui side value to App side value static double appX(double x); static Base::Vector3d appX(Base::Vector3d v); diff --git a/src/Mod/TechDraw/Gui/TaskDetail.cpp b/src/Mod/TechDraw/Gui/TaskDetail.cpp new file mode 100644 index 0000000000..270b8fb612 --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskDetail.cpp @@ -0,0 +1,585 @@ +/*************************************************************************** + * Copyright (c) 2020 Wandererfan +#include +#endif // #ifndef _PreComp_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "DrawGuiStd.h" +#include "QGVPage.h" +#include "QGIView.h" +#include "QGIPrimPath.h" +#include "QGIGhostHighlight.h" +#include "MDIViewPage.h" +#include "ViewProviderPage.h" +#include "Rez.h" +#include "QGIViewPart.h" + +#include "TaskDetail.h" + +using namespace TechDrawGui; +using namespace TechDraw; +using namespace Gui; + +#define CREATEMODE 0 +#define EDITMODE 1 + +//creation ctor +TaskDetail::TaskDetail(TechDraw::DrawViewPart* baseFeat): + ui(new Ui_TaskDetail), + m_detailFeat(nullptr), + m_baseFeat(baseFeat), + m_basePage(nullptr), + m_inProgressLock(false), + m_saveAnchor(Base::Vector3d(0.0, 0.0, 0.0)), + m_saveRadius(0.0), + m_baseName(std::string()), + m_pageName(std::string()), + m_detailName(std::string()), + m_doc(nullptr), + m_mode(CREATEMODE), + m_created(false) +{ + if (m_baseFeat == nullptr) { + //should be caught in CMD caller + Base::Console().Error("TaskDetail - bad parameters - base feature. Can not proceed.\n"); + return; + } + m_basePage = m_baseFeat->findParentPage(); + if (m_basePage == nullptr) { + Base::Console().Error("TaskDetail - bad parameters - base page. Can not proceed.\n"); + } + + m_baseName = m_baseFeat->getNameInDocument(); + m_doc = m_baseFeat->getDocument(); + m_pageName = m_basePage->getNameInDocument(); + + ui->setupUi(this); + + Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_doc); + Gui::ViewProvider* vp = activeGui->getViewProvider(m_basePage); + ViewProviderPage* vpp = static_cast(vp); + m_mdi = vpp->getMDIViewPage(); + m_scene = m_mdi->m_scene; + m_view = m_mdi->getQGVPage(); + + createDetail(); + setUiFromFeat(); + setWindowTitle(QObject::tr("New Detail")); + + connect(ui->pbDragger, SIGNAL(clicked(bool)), + this, SLOT(onDraggerClicked(bool))); + connect(ui->qsbX, SIGNAL(editingFinished()), + this, SLOT(onXEdit())); + connect(ui->qsbY, SIGNAL(editingFinished()), + this, SLOT(onYEdit())); + connect(ui->qsbRadius, SIGNAL(editingFinished()), + this, SLOT(onRadiusEdit())); + + m_ghost = new QGIGhostHighlight(); + m_scene->addItem(m_ghost); + m_ghost->hide(); + connect(m_ghost, SIGNAL(positionChange(QPointF)), + this, SLOT(onHighlightMoved(QPointF))); +} + +//edit ctor +TaskDetail::TaskDetail(TechDraw::DrawViewDetail* detailFeat): + ui(new Ui_TaskDetail), + m_detailFeat(detailFeat), + m_baseFeat(nullptr), + m_basePage(nullptr), + m_inProgressLock(false), + m_saveAnchor(Base::Vector3d(0.0, 0.0, 0.0)), + m_saveRadius(0.0), + m_baseName(std::string()), + m_pageName(std::string()), + m_detailName(std::string()), + m_doc(nullptr), + m_mode(EDITMODE), + m_created(false) +{ + if (m_detailFeat == nullptr) { + //should be caught in CMD caller + Base::Console().Error("TaskDetail - bad parameters. Can not proceed.\n"); + return; + } + + m_doc = m_detailFeat->getDocument(); + m_detailName = m_detailFeat->getNameInDocument(); + + m_basePage = m_detailFeat->findParentPage(); + if (m_basePage != nullptr) { + m_pageName = m_basePage->getNameInDocument(); + } + + App::DocumentObject* baseObj = m_detailFeat->BaseView.getValue(); + m_baseFeat = dynamic_cast(baseObj); + if (m_baseFeat != nullptr) { + m_baseName = m_baseFeat->getNameInDocument(); + } else { + Base::Console().Error("TaskDetail - no BaseView. Can not proceed.\n"); + return; + } + + ui->setupUi(this); + + Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_basePage->getDocument()); + Gui::ViewProvider* vp = activeGui->getViewProvider(m_basePage); + ViewProviderPage* vpp = static_cast(vp); + m_mdi = vpp->getMDIViewPage(); + m_scene = m_mdi->m_scene; + m_view = m_mdi->getQGVPage(); + + saveDetailState(); + setUiFromFeat(); + setWindowTitle(QObject::tr("Edit Detail")); + + connect(ui->pbDragger, SIGNAL(clicked(bool)), + this, SLOT(onDraggerClicked(bool))); + connect(ui->qsbX, SIGNAL(editingFinished()), + this, SLOT(onXEdit())); + connect(ui->qsbY, SIGNAL(editingFinished()), + this, SLOT(onYEdit())); + connect(ui->qsbRadius, SIGNAL(editingFinished()), + this, SLOT(onRadiusEdit())); + connect(ui->aeReference, SIGNAL(editingFinished()), + this, SLOT(onReferenceEdit())); + + m_ghost = new QGIGhostHighlight(); + m_scene->addItem(m_ghost); + m_ghost->hide(); + connect(m_ghost, SIGNAL(positionChange(QPointF)), + this, SLOT(onHighlightMoved(QPointF))); +} + +TaskDetail::~TaskDetail() +{ + delete ui; +} + +void TaskDetail::updateTask() +{ +// blockUpdate = true; + +// blockUpdate = false; +} + +void TaskDetail::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } +} + +//save the start conditions +void TaskDetail::saveDetailState() +{ +// Base::Console().Message("TD::saveDetailState()\n"); + TechDraw::DrawViewDetail* dvd = getDetailFeat(); + m_saveAnchor = dvd->AnchorPoint.getValue(); + m_saveRadius = dvd->Radius.getValue(); + m_saved = true; +} + +void TaskDetail::restoreDetailState() +{ +// Base::Console().Message("TD::restoreDetailState()\n"); + TechDraw::DrawViewDetail* dvd = getDetailFeat(); + dvd->AnchorPoint.setValue(m_saveAnchor); + dvd->Radius.setValue(m_saveRadius); +} + +//***** ui stuff *************************************************************** + +void TaskDetail::setUiFromFeat() +{ +// Base::Console().Message("TD::setUIFromFeat()\n"); + if (m_baseFeat != nullptr) { + std::string baseName = getBaseFeat()->getNameInDocument(); + ui->leBaseView->setText(Base::Tools::fromStdString(baseName)); + } + + Base::Vector3d anchor; + double radius; + + TechDraw::DrawViewDetail* detailFeat = getDetailFeat(); + QString detailDisplay = QString::fromUtf8(detailFeat->getNameInDocument()) + + QString::fromUtf8(" / ") + + QString::fromUtf8(detailFeat->Label.getValue()); + ui->leDetailView->setText(detailDisplay); + anchor = detailFeat->AnchorPoint.getValue(); + radius = detailFeat->Radius.getValue(); + QString ref = QString::fromUtf8(detailFeat->Reference.getValue()); + + ui->pbDragger->setText(QString::fromUtf8("Drag Highlight")); + ui->pbDragger->setEnabled(true); + int decimals = Base::UnitsApi::getDecimals(); + ui->qsbX->setUnit(Base::Unit::Length); + ui->qsbX->setDecimals(decimals); + ui->qsbY->setUnit(Base::Unit::Length); + ui->qsbY->setDecimals(decimals); + ui->qsbRadius->setDecimals(decimals); + ui->qsbRadius->setUnit(Base::Unit::Length); + ui->qsbX->setValue(anchor.x); + ui->qsbY->setValue(anchor.y); + ui->qsbRadius->setValue(radius); + ui->aeReference->setText(ref); +} + +//update ui point fields after tracker finishes +void TaskDetail::updateUi(QPointF p) +{ + ui->qsbX->setValue(p.x()); + ui->qsbY->setValue(- p.y()); +} + +void TaskDetail::enableInputFields(bool b) +{ + ui->qsbX->setEnabled(b); + ui->qsbY->setEnabled(b); + ui->qsbRadius->setEnabled(b); + ui->aeReference->setEnabled(b); +} + +void TaskDetail::onXEdit() +{ + updateDetail(); +} + +void TaskDetail::onYEdit() +{ + updateDetail(); +} + +void TaskDetail::onRadiusEdit() +{ + updateDetail(); +} + +void TaskDetail::onReferenceEdit() +{ + updateDetail(); +} + +void TaskDetail::onDraggerClicked(bool b) +{ + Q_UNUSED(b); + ui->pbDragger->setEnabled(false); + enableInputFields(false); + editByHighlight(); + return; +} + +void TaskDetail::editByHighlight() +{ +// Base::Console().Message("TD::editByHighlight()\n"); + if (m_ghost == nullptr) { + Base::Console().Error("TaskDetail::editByHighlight - no ghost object\n"); + return; + } + + m_scene->clearSelection(); + m_ghost->setSelected(true); + m_ghost->setPos(getAnchorScene()); + m_ghost->draw(); + m_ghost->show(); +} + +//dragEnd is in scene coords. +void TaskDetail::onHighlightMoved(QPointF dragEnd) +{ +// Base::Console().Message("TD::onHighlightMoved(%s) - highlight: %X\n", +// DrawUtil::formatVector(dragEnd).c_str(), m_ghost); + ui->pbDragger->setEnabled(true); + + double scale = getBaseFeat()->getScale(); + double x = Rez::guiX(getBaseFeat()->X.getValue()) * scale; + double y = Rez::guiX(getBaseFeat()->Y.getValue()) * scale; + QPointF basePosScene(x, -y); //base position in scene coords + + QPointF anchorDisplace = dragEnd - basePosScene; + QPointF newAnchorPos = Rez::appX(anchorDisplace) / scale; + + updateUi(newAnchorPos); + updateDetail(); + enableInputFields(true); + m_ghost->setSelected(false); + m_ghost->hide(); +} + +void TaskDetail::saveButtons(QPushButton* btnOK, + QPushButton* btnCancel) +{ + m_btnOK = btnOK; + m_btnCancel = btnCancel; +} + +void TaskDetail::enableTaskButtons(bool b) +{ + m_btnOK->setEnabled(b); + m_btnCancel->setEnabled(b); +} + +//***** Feature create & edit stuff ******************************************* +void TaskDetail::createDetail() +{ +// Base::Console().Message("TD::createDetail()\n"); + Gui::Command::openCommand("Create Detail"); + + m_detailName = m_doc->getUniqueObjectName("Detail"); + + Gui::Command::doCommand(Command::Doc,"App.activeDocument().addObject('TechDraw::DrawViewDetail','%s')", + m_detailName.c_str()); + App::DocumentObject *docObj = m_doc->getObject(m_detailName.c_str()); + TechDraw::DrawViewDetail* dvd = dynamic_cast(docObj); + if (!dvd) { + throw Base::TypeError("TaskDetail - new detail not found\n"); + } + m_detailFeat = dvd; + + dvd->Source.setValues(getBaseFeat()->Source.getValues()); + + Gui::Command::doCommand(Command::Doc,"App.activeDocument().%s.BaseView = App.activeDocument().%s", + m_detailName.c_str(),m_baseName.c_str()); + Gui::Command::doCommand(Command::Doc,"App.activeDocument().%s.Direction = App.activeDocument().%s.Direction", + m_detailName.c_str(),m_baseName.c_str()); + Gui::Command::doCommand(Command::Doc,"App.activeDocument().%s.XDirection = App.activeDocument().%s.XDirection", + m_detailName.c_str(),m_baseName.c_str()); + Gui::Command::doCommand(Command::Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)", + m_pageName.c_str(), m_detailName.c_str()); + + Gui::Command::updateActive(); + Gui::Command::commitCommand(); + + getBaseFeat()->requestPaint(); + m_created = true; +} + +void TaskDetail::updateDetail() +{ +// Base::Console().Message("TD::updateDetail()\n"); + Gui::Command::openCommand("Update Detail"); + double x = ui->qsbX->rawValue(); + double y = ui->qsbY->rawValue(); + Base::Vector3d temp(x, y, 0.0); + TechDraw::DrawViewDetail* detailFeat = getDetailFeat(); + detailFeat->AnchorPoint.setValue(temp); + + double radius = ui->qsbRadius->rawValue(); + detailFeat->Radius.setValue(radius); + QString qRef = ui->aeReference->text(); + std::string ref = Base::Tools::toStdString(qRef); + detailFeat->Reference.setValue(ref); + + detailFeat->recomputeFeature(); + getBaseFeat()->requestPaint(); + Gui::Command::updateActive(); + Gui::Command::commitCommand(); +} + +//***** Getters **************************************************************** + +//get the current Anchor highlight position in scene coords +QPointF TaskDetail::getAnchorScene() +{ + TechDraw::DrawViewPart* dvp = getBaseFeat(); + TechDraw::DrawViewDetail* dvd = getDetailFeat(); + + Base::Vector3d anchorPos = dvd->AnchorPoint.getValue(); + double x = dvp->X.getValue(); + double y = dvp->Y.getValue(); + Base::Vector3d basePos(x, y, 0.0); + Base::Vector3d netPos = basePos + anchorPos; + netPos = Rez::guiX(netPos * dvp->getScale()); + + QPointF qAnchor(netPos.x, - netPos.y); + return qAnchor; +} + +// protects against stale pointers +DrawViewPart* TaskDetail::getBaseFeat() +{ +// Base::Console().Message("TD::getBaseFeat()\n"); + DrawViewPart* result = nullptr; + + if (m_doc != nullptr) { + App::DocumentObject* baseObj = m_doc->getObject(m_baseName.c_str()); + if (baseObj != nullptr) { + result = static_cast(baseObj); + } + } + if (result == nullptr) { + std::string msg = "TaskDetail - base feature " + + m_baseName + + " not found \n"; + throw Base::TypeError(msg); + } + return result; +} + +// protects against stale pointers +DrawViewDetail* TaskDetail::getDetailFeat() +{ +// Base::Console().Message("TD::getDetailFeat()\n"); + DrawViewDetail* result = nullptr; + + if (m_doc != nullptr) { + App::DocumentObject* detailObj = m_doc->getObject(m_detailName.c_str()); + if (detailObj != nullptr) { + result = static_cast(detailObj); + } + } + if (result == nullptr) { + std::string msg = "TaskDetail - detail feature " + + m_detailName + + " not found \n"; +// throw Base::TypeError("TaskDetail - detail feature not found\n"); + throw Base::TypeError(msg); + } + return result; +} + +//****************************************************************************** + +bool TaskDetail::accept() +{ +// Base::Console().Message("TD::accept()\n"); + + Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument()); + if (!doc) return false; + + getDetailFeat()->requestPaint(); + getBaseFeat()->requestPaint(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + + return true; +} + +bool TaskDetail::reject() +{ +// Base::Console().Message("TD::reject()\n"); + Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument()); + if (!doc) return false; + + if (m_mode == CREATEMODE) { + if (m_created) { + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().removeObject('%s')", + m_detailName.c_str()); + } + } else { + restoreDetailState(); + getDetailFeat()->recomputeFeature(); + getBaseFeat()->requestPaint(); + } + + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TaskDlgDetail::TaskDlgDetail(TechDraw::DrawViewPart* baseFeat) + : TaskDialog() +{ + widget = new TaskDetail(baseFeat); + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/techdraw-DetailView"), + widget->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskDlgDetail::TaskDlgDetail(TechDraw::DrawViewDetail* detailFeat) + : TaskDialog() +{ + widget = new TaskDetail(detailFeat); + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/techdraw-DetailView"), + widget->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskDlgDetail::~TaskDlgDetail() +{ +} + +void TaskDlgDetail::update() +{ +// widget->updateTask(); +} + +void TaskDlgDetail::modifyStandardButtons(QDialogButtonBox* box) +{ + QPushButton* btnOK = box->button(QDialogButtonBox::Ok); + QPushButton* btnCancel = box->button(QDialogButtonBox::Cancel); + widget->saveButtons(btnOK, btnCancel); +} + +//==== calls from the TaskView =============================================================== +void TaskDlgDetail::open() +{ +} + +void TaskDlgDetail::clicked(int) +{ +} + +bool TaskDlgDetail::accept() +{ + widget->accept(); + return true; +} + +bool TaskDlgDetail::reject() +{ + widget->reject(); + return true; +} + +#include diff --git a/src/Mod/TechDraw/Gui/TaskDetail.h b/src/Mod/TechDraw/Gui/TaskDetail.h new file mode 100644 index 0000000000..588dcaea23 --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskDetail.h @@ -0,0 +1,179 @@ +/*************************************************************************** + * Copyright (c) 2020 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef TECHDRAWGUI_TASKCOSVERTEX_H +#define TECHDRAWGUI_TASKCOSVERTEX_H + +#include +#include +#include +#include + +#include + +//TODO: make this a proper enum +#define TRACKERPICK 0 +#define TRACKEREDIT 1 +#define TRACKERCANCEL 2 +#define TRACKERCANCELEDIT 3 + +class Ui_TaskDetail; + +namespace App { +class DocumentObject; +} + +namespace TechDraw +{ +class DrawPage; +class DrawView; +class DrawDetail; +class DrawViewPart; +} + +namespace TechDrawGui +{ +class QGVPage; +class QGIView; +class QGIPrimPath; +class MDIViewPage; +class QGEPath; +class QGIDetail; +class QGIGhostHighlight; +class ViewProviderLeader; + +class TaskDetail : public QWidget +{ + Q_OBJECT + +public: + TaskDetail(TechDraw::DrawViewPart* baseFeat); + TaskDetail(TechDraw::DrawViewDetail* detailFeat); + ~TaskDetail(); + +public Q_SLOTS: + void onDraggerClicked(bool b); + void onHighlightMoved(QPointF newPos); + void onXEdit(); + void onYEdit(); + void onRadiusEdit(); + void onReferenceEdit(); + +public: + virtual bool accept(); + virtual bool reject(); + void updateTask(); + void saveButtons(QPushButton* btnOK, + QPushButton* btnCancel); + void enableTaskButtons(bool b); + +protected: + void changeEvent(QEvent *e); + void startDragger(void); + + void createDetail(); + void updateDetail(); + + void editByHighlight(); + + void blockButtons(bool b); + void setUiFromFeat(void); + void updateUi(QPointF p); + void enableInputFields(bool b); + + void saveDetailState(); + void restoreDetailState(); + QPointF getAnchorScene(); + + TechDraw::DrawViewPart* getBaseFeat(); + TechDraw::DrawViewDetail* getDetailFeat(); + +private: + Ui_TaskDetail * ui; + bool blockUpdate; + + QGIGhostHighlight* m_ghost; + + MDIViewPage* m_mdi; + QGraphicsScene* m_scene; + QGVPage* m_view; + TechDraw::DrawViewDetail* m_detailFeat; + TechDraw::DrawViewPart* m_baseFeat; + TechDraw::DrawPage* m_basePage; + QGIView* m_qgParent; + std::string m_qgParentName; + + bool m_inProgressLock; + + QPushButton* m_btnOK; + QPushButton* m_btnCancel; + + Base::Vector3d m_saveAnchor; + double m_saveRadius; + bool m_saved; + QPointF m_dragStart; + + std::string m_baseName; + std::string m_pageName; + std::string m_detailName; + App::Document* m_doc; + + bool m_mode; + bool m_created; +}; + +class TaskDlgDetail : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgDetail(TechDraw::DrawViewPart* baseFeat); + TaskDlgDetail(TechDraw::DrawViewDetail* detailFeat); + ~TaskDlgDetail(); + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual void helpRequested() { return;} + virtual bool isAllowedAlterDocument(void) const + { return false; } + void update(); + + void modifyStandardButtons(QDialogButtonBox* box); + +protected: + +private: + TaskDetail * widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} //namespace TechDrawGui + +#endif // #ifndef TECHDRAWGUI_TASKCOSVERTEX_H diff --git a/src/Mod/TechDraw/Gui/TaskDetail.ui b/src/Mod/TechDraw/Gui/TaskDetail.ui new file mode 100644 index 0000000000..bf7d9798f3 --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskDetail.ui @@ -0,0 +1,296 @@ + + + TechDrawGui::TaskDetail + + + + 0 + 0 + 381 + 405 + + + + + 0 + 0 + + + + + 250 + 0 + + + + Detail Anchor + + + + :/icons/actions/techdraw-DetailView.svg:/icons/actions/techdraw-DetailView.svg + + + + + + + 0 + 0 + + + + + 300 + 300 + + + + + 300 + 300 + + + + QFrame::Box + + + QFrame::Raised + + + + + + + + + + false + + + false + + + Qt::NoFocus + + + false + + + + + + + Base View + + + + + + + Detail View + + + + + + + false + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Click to drag detail highlight to new position + + + Drag Highlight + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + + + + + + size of detail view + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10.000000000000000 + + + + + + + X + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Y + + + + + + + + + + + + + + x position of detail highlight within view + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 0.000000000000000 + + + + + + + y position of detail highlight within view + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Radius + + + + + + + Reference + + + + + + + Detail identifier + + + 1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Gui::AccelLineEdit + QLineEdit +
Gui/Widgets.h
+
+ + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
+ + + + +
diff --git a/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp b/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp index a1c35d66cf..b8469fc1a2 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp @@ -37,19 +37,29 @@ #include #include #include +#include +#include +#include +#include #include +#include +#include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include "QGIView.h" +#include "TaskDetail.h" #include "ViewProviderViewPart.h" using namespace TechDrawGui; @@ -166,8 +176,11 @@ void ViewProviderViewPart::onChanged(const App::Property* prop) void ViewProviderViewPart::attach(App::DocumentObject *pcFeat) { TechDraw::DrawViewMulti* dvm = dynamic_cast(pcFeat); + TechDraw::DrawViewDetail* dvd = dynamic_cast(pcFeat); if (dvm != nullptr) { sPixmap = "TechDraw_Tree_Multi"; + } else if (dvd != nullptr) { + sPixmap = "actions/techdraw-DetailView"; } ViewProviderDrawingView::attach(pcFeat); @@ -232,6 +245,57 @@ std::vector ViewProviderViewPart::claimChildren(void) cons return tmp; } } +bool ViewProviderViewPart::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + if (Gui::Control().activeDialog()) { //TaskPanel already open! + return false; + } + TechDraw::DrawViewPart* dvp = getViewObject(); + TechDraw::DrawViewDetail* dvd = dynamic_cast(dvp); + if (dvd != nullptr) { + // clear the selection (convenience) + Gui::Selection().clearSelection(); + Gui::Control().showDialog(new TaskDlgDetail(dvd)); +// Gui::Selection().clearSelection(); +// flush any lingering gui objects + Gui::Selection().addSelection(dvd->getDocument()->getName(), + dvd->getNameInDocument()); + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(dvd->getDocument()->getName(), + dvd->getNameInDocument()); + +//Gui.ActiveDocument.resetEdit() +//>>> # Gui.Selection.addSelection('aaStart121','Detail') +//>>> # Gui.Selection.clearSelection() +//>>> # Gui.Selection.addSelection('aaStart121','Detail') +//>>> # Gui.Selection.addSelection('aaStart121','Detail') +//>>> # Gui.Selection.clearSelection() +//>>> # Gui.Selection.addSelection('aaStart121','Detail') + return true; + } + } else { + return ViewProviderDrawingView::setEdit(ModNum); + } + return true; +} + +void ViewProviderViewPart::unsetEdit(int ModNum) +{ + Q_UNUSED(ModNum); + if (ModNum == ViewProvider::Default) { + Gui::Control().closeDialog(); + } + else { + ViewProviderDrawingView::unsetEdit(ModNum); + } +} + +bool ViewProviderViewPart::doubleClicked(void) +{ + setEdit(ViewProvider::Default); + return true; +} TechDraw::DrawViewPart* ViewProviderViewPart::getViewObject() const { diff --git a/src/Mod/TechDraw/Gui/ViewProviderViewPart.h b/src/Mod/TechDraw/Gui/ViewProviderViewPart.h index 9ab6a4501e..13ff73242c 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderViewPart.h +++ b/src/Mod/TechDraw/Gui/ViewProviderViewPart.h @@ -68,6 +68,9 @@ public: virtual std::vector getDisplayModes(void) const; virtual bool onDelete(const std::vector &); virtual bool canDelete(App::DocumentObject* obj) const; + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + virtual bool doubleClicked(void); public: virtual void onChanged(const App::Property *prop); From 9e0a668a12e0ba51bbb67fa6ae0a38df4e84eb77 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Wed, 8 Apr 2020 21:01:24 +0200 Subject: [PATCH 56/62] Arch: rebar, fix code error --- src/Mod/Arch/ArchRebar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Arch/ArchRebar.py b/src/Mod/Arch/ArchRebar.py index 0f4c40f921..c9e2168001 100644 --- a/src/Mod/Arch/ArchRebar.py +++ b/src/Mod/Arch/ArchRebar.py @@ -331,11 +331,11 @@ class _Rebar(ArchComponent.Component): ) return if not obj.Amount: - return FreeCAD.Console.PrintError( "No Amount, return without a rebar shape for {}.\n" .format(obj.Name) ) + return father = obj.Host fathershape = None if not father: From 824199c9b8a06a9f10cc9b2ccc454fd937b01e69 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 5 Mar 2020 19:50:44 -0600 Subject: [PATCH 57/62] Draft: move SelectPlane task panel to a separate module --- src/Mod/Draft/CMakeLists.txt | 1 + .../Draft/draftguitools/gui_selectplane.py | 14 +----- .../Draft/drafttaskpanels/task_selectplane.py | 50 +++++++++++++++++++ 3 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 src/Mod/Draft/drafttaskpanels/task_selectplane.py diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 12857548f5..33bf9751ab 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -95,6 +95,7 @@ SET(Draft_task_panels drafttaskpanels/task_orthoarray.py drafttaskpanels/task_polararray.py drafttaskpanels/task_scale.py + drafttaskpanels/task_selectplane.py drafttaskpanels/task_shapestring.py drafttaskpanels/README.md ) diff --git a/src/Mod/Draft/draftguitools/gui_selectplane.py b/src/Mod/Draft/draftguitools/gui_selectplane.py index ed9b9636cd..ccd7f122b2 100644 --- a/src/Mod/Draft/draftguitools/gui_selectplane.py +++ b/src/Mod/Draft/draftguitools/gui_selectplane.py @@ -33,6 +33,7 @@ import FreeCADGui import Draft import Draft_rc import DraftVecUtils +import drafttaskpanels.task_selectplane as task_selectplane from draftutils.todo import todo from draftutils.messages import _msg from draftutils.translate import translate @@ -91,7 +92,7 @@ class Draft_SelectPlane: # Create task panel FreeCADGui.Control.closeDialog() - self.taskd = SelectPlane_TaskPanel() + self.taskd = task_selectplane.SelectPlaneTaskPanel() # Fill values self.taskd.form.checkCenter.setChecked(self.param.GetBool("CenterPlaneOnView", False)) @@ -493,17 +494,6 @@ class Draft_SelectPlane: FreeCADGui.doCommandGui("FreeCADGui.Snapper.setGrid()") -class SelectPlane_TaskPanel: - """The task panel definition of the Draft_SelectPlane command.""" - - def __init__(self): - self.form = FreeCADGui.PySideUic.loadUi(":/ui/TaskSelectPlane.ui") - - def getStandardButtons(self): - """Execute to set the standard buttons.""" - return 2097152 # int(QtGui.QDialogButtonBox.Close) - - class Draft_SetWorkingPlaneProxy: """The Draft_SetWorkingPlaneProxy FreeCAD command definition.""" diff --git a/src/Mod/Draft/drafttaskpanels/task_selectplane.py b/src/Mod/Draft/drafttaskpanels/task_selectplane.py new file mode 100644 index 0000000000..8889cd6e85 --- /dev/null +++ b/src/Mod/Draft/drafttaskpanels/task_selectplane.py @@ -0,0 +1,50 @@ +# *************************************************************************** +# * Copyright (c) 2019 Yorik van Havre * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provides the task panel for the Draft SelectPlane tool.""" +## @package task_selectplane +# \ingroup DRAFT +# \brief This module provides the task panel code for the SelectPlane tool. + +import FreeCADGui as Gui + +# As it is right now this code only loads the task panel .ui file. +# All logic on how to use the widgets is located in the GuiCommand class +# itself. +# On the other hand, the newer tools introduced in v0.19 like OrthoArray, +# PolarArray, and CircularArray include the logic and manipulation +# of the widgets in this task panel class. +# In addition, the task panel code launches the actual function +# using the delayed mechanism defined by the `todo.ToDo` class. +# Therefore, at some point this class should be refactored +# to be more similar to OrthoArray and the new tools. + + +class SelectPlaneTaskPanel: + """The task panel definition of the Draft_SelectPlane command.""" + + def __init__(self): + self.form = Gui.PySideUic.loadUi(":/ui/TaskSelectPlane.ui") + + def getStandardButtons(self): + """Execute to set the standard buttons.""" + return 2097152 # int(QtGui.QDialogButtonBox.Close) From fd00904b9e41481fc0c8b60c79e97412e600eb00 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 5 Mar 2020 20:14:44 -0600 Subject: [PATCH 58/62] Draft: add WorkingPlaneProxy button to the toolbar We also rename it from `Draft_SetWorkingPlaneProxy` to `Draft_WorkingPlaneProxy` as we want to indicate a new object is created. --- src/Mod/Draft/Resources/Draft.qrc | 1 + .../Resources/icons/Draft_PlaneProxy.svg | 436 ++++++++++++++++++ .../Draft/draftguitools/gui_selectplane.py | 20 +- src/Mod/Draft/draftutils/init_tools.py | 5 +- 4 files changed, 452 insertions(+), 10 deletions(-) create mode 100644 src/Mod/Draft/Resources/icons/Draft_PlaneProxy.svg diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index ec7219db5c..fc9da4a2e6 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -55,6 +55,7 @@ icons/Draft_Offset.svg icons/Draft_PathArray.svg icons/Draft_PathLinkArray.svg + icons/Draft_PlaneProxy.svg icons/Draft_Point.svg icons/Draft_PointArray.svg icons/Draft_PolarArray.svg diff --git a/src/Mod/Draft/Resources/icons/Draft_PlaneProxy.svg b/src/Mod/Draft/Resources/icons/Draft_PlaneProxy.svg new file mode 100644 index 0000000000..129e3a3658 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Draft_PlaneProxy.svg @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Mon Oct 10 13:44:52 2011 +0000 + + + [wmayer] + + + + + FreeCAD LGPL2+ + + + + + FreeCAD + + + FreeCAD/src/Mod/Draft/Resources/icons/Draft_PlaneProxy.svg + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + [agryson] Alexander Gryson, vocx + + + + + rectangle + grid + plane + + + A rectangle sitting on a plane aligned to a grid that is going into the page from the left to the right; color variation + + + + + diff --git a/src/Mod/Draft/draftguitools/gui_selectplane.py b/src/Mod/Draft/draftguitools/gui_selectplane.py index ccd7f122b2..fb9ca62319 100644 --- a/src/Mod/Draft/draftguitools/gui_selectplane.py +++ b/src/Mod/Draft/draftguitools/gui_selectplane.py @@ -494,14 +494,18 @@ class Draft_SelectPlane: FreeCADGui.doCommandGui("FreeCADGui.Snapper.setGrid()") -class Draft_SetWorkingPlaneProxy: - """The Draft_SetWorkingPlaneProxy FreeCAD command definition.""" +class Draft_WorkingPlaneProxy: + """The Draft_WorkingPlaneProxy command definition.""" def GetResources(self): """Set icon, menu and tooltip.""" - _menu = "Create Working Plane Proxy" - _tip = "Creates a proxy object from the current working plane" - d = {'Pixmap': 'Draft_SelectPlane', + _menu = "Create working plane proxy" + _tip = ("Creates a proxy object from the current working plane.\n" + "Once the object is created double click it in the tree view " + "to restore the camera position and objects' visibilities.\n" + "Then you can use it to save a different camera position " + "and objects' states any time you need.") + d = {'Pixmap': 'Draft_PlaneProxy', 'MenuText': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", _menu), 'ToolTip': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", @@ -524,10 +528,10 @@ class Draft_SetWorkingPlaneProxy: _cmd += "FreeCAD.DraftWorkingPlane.getPlacement()" _cmd += ")" FreeCADGui.doCommand(_cmd) - FreeCAD.ActiveDocument.recompute() FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() FreeCADGui.addCommand('Draft_SelectPlane', Draft_SelectPlane()) -FreeCADGui.addCommand('Draft_SetWorkingPlaneProxy', - Draft_SetWorkingPlaneProxy()) +FreeCADGui.addCommand('Draft_WorkingPlaneProxy', + Draft_WorkingPlaneProxy()) diff --git a/src/Mod/Draft/draftutils/init_tools.py b/src/Mod/Draft/draftutils/init_tools.py index 44c5cc1b08..d9e71c7578 100644 --- a/src/Mod/Draft/draftutils/init_tools.py +++ b/src/Mod/Draft/draftutils/init_tools.py @@ -74,7 +74,8 @@ def get_draft_modification_commands(): "Separator", "Draft_WireToBSpline", "Draft_Draft2Sketch", "Separator", - "Draft_Shape2DView", "Draft_Drawing"] + "Draft_Shape2DView", "Draft_Drawing", + "Draft_WorkingPlaneProxy"] return lst @@ -97,7 +98,7 @@ def get_draft_utility_commands(): return ["Draft_Layer", "Draft_Heal", "Draft_FlipDimension", "Draft_ToggleConstructionMode", "Draft_ToggleContinueMode", "Draft_Edit", - "Draft_Slope", "Draft_SetWorkingPlaneProxy", + "Draft_Slope", "Draft_WorkingPlaneProxy", "Draft_AddConstruction"] From a1e8f97be29dfa261566582b821ee8c72c8d2cb2 Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Thu, 5 Mar 2020 22:26:23 -0600 Subject: [PATCH 59/62] Draft: move WorkingPlaneProxy to separate module Previously it was in the `gui_selectplane` module but we prefer to place it in its own module so that the files are as small as possible. --- src/Mod/Draft/CMakeLists.txt | 1 + src/Mod/Draft/DraftTools.py | 1 + src/Mod/Draft/draftguitools/gui_planeproxy.py | 79 +++++++++++++++++++ .../Draft/draftguitools/gui_selectplane.py | 40 ---------- 4 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 src/Mod/Draft/draftguitools/gui_planeproxy.py diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 33bf9751ab..c32795e1c3 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -80,6 +80,7 @@ SET(Draft_GUI_tools draftguitools/gui_circulararray.py draftguitools/gui_orthoarray.py draftguitools/gui_polararray.py + draftguitools/gui_planeproxy.py draftguitools/gui_selectplane.py draftguitools/gui_arrays.py draftguitools/gui_snaps.py diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index fb3456818f..569c8d0704 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -76,6 +76,7 @@ if not hasattr(FreeCAD, "DraftWorkingPlane"): # --------------------------------------------------------------------------- import draftguitools.gui_edit import draftguitools.gui_selectplane +import draftguitools.gui_planeproxy # import DraftFillet import drafttaskpanels.task_shapestring as task_shapestring import drafttaskpanels.task_scale as task_scale diff --git a/src/Mod/Draft/draftguitools/gui_planeproxy.py b/src/Mod/Draft/draftguitools/gui_planeproxy.py new file mode 100644 index 0000000000..270dd04032 --- /dev/null +++ b/src/Mod/Draft/draftguitools/gui_planeproxy.py @@ -0,0 +1,79 @@ +# *************************************************************************** +# * Copyright (c) 2019 Yorik van Havre * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provides the Draft WorkingPlaneProxy tool.""" +## @package gui_planeproxy +# \ingroup DRAFT +# \brief This module provides the Draft WorkingPlaneProxy tool. + +from PySide.QtCore import QT_TRANSLATE_NOOP + +import FreeCAD as App +import FreeCADGui as Gui +import Draft_rc + +# The module is used to prevent complaints from code checkers (flake8) +True if Draft_rc.__name__ else False + +__title__ = "FreeCAD Draft Workbench GUI Tools - Working plane-related tools" +__author__ = ("Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, " + "Dmitry Chigrin") +__url__ = "https://www.freecadweb.org" + + +class Draft_WorkingPlaneProxy: + """The Draft_WorkingPlaneProxy command definition.""" + + def GetResources(self): + """Set icon, menu and tooltip.""" + _menu = "Create working plane proxy" + _tip = ("Creates a proxy object from the current working plane.\n" + "Once the object is created double click it in the tree view " + "to restore the camera position and objects' visibilities.\n" + "Then you can use it to save a different camera position " + "and objects' states any time you need.") + d = {'Pixmap': 'Draft_PlaneProxy', + 'MenuText': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", + _menu), + 'ToolTip': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", + _tip)} + return d + + def IsActive(self): + """Return True when this command should be available.""" + if Gui.ActiveDocument: + return True + else: + return False + + def Activated(self): + """Execute when the command is called.""" + if hasattr(App, "DraftWorkingPlane"): + App.ActiveDocument.openTransaction("Create WP proxy") + Gui.addModule("Draft") + _cmd = "Draft.makeWorkingPlaneProxy(" + _cmd += "FreeCAD.DraftWorkingPlane.getPlacement()" + _cmd += ")" + Gui.doCommand(_cmd) + App.ActiveDocument.commitTransaction() + App.ActiveDocument.recompute() + + +Gui.addCommand('Draft_WorkingPlaneProxy', Draft_WorkingPlaneProxy()) diff --git a/src/Mod/Draft/draftguitools/gui_selectplane.py b/src/Mod/Draft/draftguitools/gui_selectplane.py index fb9ca62319..60834847cd 100644 --- a/src/Mod/Draft/draftguitools/gui_selectplane.py +++ b/src/Mod/Draft/draftguitools/gui_selectplane.py @@ -494,44 +494,4 @@ class Draft_SelectPlane: FreeCADGui.doCommandGui("FreeCADGui.Snapper.setGrid()") -class Draft_WorkingPlaneProxy: - """The Draft_WorkingPlaneProxy command definition.""" - - def GetResources(self): - """Set icon, menu and tooltip.""" - _menu = "Create working plane proxy" - _tip = ("Creates a proxy object from the current working plane.\n" - "Once the object is created double click it in the tree view " - "to restore the camera position and objects' visibilities.\n" - "Then you can use it to save a different camera position " - "and objects' states any time you need.") - d = {'Pixmap': 'Draft_PlaneProxy', - 'MenuText': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", - _menu), - 'ToolTip': QT_TRANSLATE_NOOP("Draft_SetWorkingPlaneProxy", - _tip)} - return d - - def IsActive(self): - """Return True when this command should be available.""" - if FreeCADGui.ActiveDocument: - return True - else: - return False - - def Activated(self): - """Execute when the command is called.""" - if hasattr(FreeCAD, "DraftWorkingPlane"): - FreeCAD.ActiveDocument.openTransaction("Create WP proxy") - FreeCADGui.addModule("Draft") - _cmd = "Draft.makeWorkingPlaneProxy(" - _cmd += "FreeCAD.DraftWorkingPlane.getPlacement()" - _cmd += ")" - FreeCADGui.doCommand(_cmd) - FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() - - FreeCADGui.addCommand('Draft_SelectPlane', Draft_SelectPlane()) -FreeCADGui.addCommand('Draft_WorkingPlaneProxy', - Draft_WorkingPlaneProxy()) From 82d70a114d76fa1bc3bd17fd1ea6db60f8752a5b Mon Sep 17 00:00:00 2001 From: mwganson Date: Mon, 6 Apr 2020 15:20:27 -0500 Subject: [PATCH 60/62] [skip ci] Add getShortcut(string) command to Gui, returns string value representing shortcut key accelerator for this command --- src/Gui/Application.h | 1 + src/Gui/ApplicationPy.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Gui/Application.h b/src/Gui/Application.h index df5df231c8..36de3b5b4e 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -259,6 +259,7 @@ public: static PyObject* sRunCommand (PyObject *self,PyObject *args); static PyObject* sAddCommand (PyObject *self,PyObject *args); static PyObject* sListCommands (PyObject *self,PyObject *args); + static PyObject* sGetShortcut (PyObject *self,PyObject *args); static PyObject* sIsCommandActive (PyObject *self,PyObject *args); static PyObject* sUpdateCommands (PyObject *self,PyObject *args); diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index cf059d2906..d040510160 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -144,6 +144,9 @@ PyMethodDef Application::Methods[] = { {"listCommands", (PyCFunction) Application::sListCommands, METH_VARARGS, "listCommands() -> list of strings\n\n" "Returns a list of all commands known to FreeCAD."}, + {"getShortcut", (PyCFunction) Application::sGetShortcut, METH_VARARGS, + "getShortcut(string) -> string\n\n" + "Returns shortcut string representing shortcut key accelerator for command."}, {"updateCommands", (PyCFunction) Application::sUpdateCommands, METH_VARARGS, "updateCommands\n\n" "Update all command active status"}, @@ -1273,6 +1276,28 @@ PyObject* Application::sUpdateCommands(PyObject * /*self*/, PyObject *args) Py_Return; } +PyObject* Application::sGetShortcut(PyObject * /*self*/, PyObject *args) +{ + char* pName; + if (!PyArg_ParseTuple(args, "s", &pName)) + return NULL; + + Command* cmd = Application::Instance->commandManager().getCommandByName(pName); + if (cmd) { + +#if PY_MAJOR_VERSION >= 3 + PyObject* str = PyUnicode_FromString(cmd->getAccel()); +#else + PyObject* str = PyString_FromString(cmd->getAccel()); +#endif + return str; + } + else { + PyErr_Format(Base::BaseExceptionFreeCADError, "No such command '%s'", pName); + return 0; + } +} + PyObject* Application::sListCommands(PyObject * /*self*/, PyObject *args) { if (!PyArg_ParseTuple(args, "")) From c5c595226d59a1563a7cd582be04cadd0c45673a Mon Sep 17 00:00:00 2001 From: mwganson Date: Wed, 8 Apr 2020 10:23:29 -0500 Subject: [PATCH 61/62] add getCommandInfo() rename getShortcut to getCommandShortcut --- src/Gui/Application.h | 3 +- src/Gui/ApplicationPy.cpp | 60 +++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 36de3b5b4e..8925f29ee6 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -258,8 +258,9 @@ public: static PyObject* sRunCommand (PyObject *self,PyObject *args); static PyObject* sAddCommand (PyObject *self,PyObject *args); + static PyObject* sGetCommandInfo (PyObject *self,PyObject *args); static PyObject* sListCommands (PyObject *self,PyObject *args); - static PyObject* sGetShortcut (PyObject *self,PyObject *args); + static PyObject* sGetCommandShortcut (PyObject *self,PyObject *args); static PyObject* sIsCommandActive (PyObject *self,PyObject *args); static PyObject* sUpdateCommands (PyObject *self,PyObject *args); diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index d040510160..894f76ff58 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -144,9 +144,12 @@ PyMethodDef Application::Methods[] = { {"listCommands", (PyCFunction) Application::sListCommands, METH_VARARGS, "listCommands() -> list of strings\n\n" "Returns a list of all commands known to FreeCAD."}, - {"getShortcut", (PyCFunction) Application::sGetShortcut, METH_VARARGS, - "getShortcut(string) -> string\n\n" - "Returns shortcut string representing shortcut key accelerator for command."}, + {"getCommandInfo", (PyCFunction) Application::sGetCommandInfo, METH_VARARGS, + "getCommandInfo(string) -> list of strings\n\n" + "Usage: menuText,tooltipText,whatsThisText,statustipText,pixmapText,shortcutText = getCommandInfo(string)"}, + {"getCommandShortcut", (PyCFunction) Application::sGetCommandShortcut, METH_VARARGS, + "getCommandShortcut(string) -> string\n\n" + "Returns string representing shortcut key accelerator for command."}, {"updateCommands", (PyCFunction) Application::sUpdateCommands, METH_VARARGS, "updateCommands\n\n" "Update all command active status"}, @@ -1276,7 +1279,7 @@ PyObject* Application::sUpdateCommands(PyObject * /*self*/, PyObject *args) Py_Return; } -PyObject* Application::sGetShortcut(PyObject * /*self*/, PyObject *args) +PyObject* Application::sGetCommandShortcut(PyObject * /*self*/, PyObject *args) { char* pName; if (!PyArg_ParseTuple(args, "s", &pName)) @@ -1286,9 +1289,9 @@ PyObject* Application::sGetShortcut(PyObject * /*self*/, PyObject *args) if (cmd) { #if PY_MAJOR_VERSION >= 3 - PyObject* str = PyUnicode_FromString(cmd->getAccel()); + PyObject* str = PyUnicode_FromString(cmd->getAccel() ? cmd->getAccel() : ""); #else - PyObject* str = PyString_FromString(cmd->getAccel()); + PyObject* str = PyString_FromString(cmd->getAccel() ? cmd->getAccel() : ""); #endif return str; } @@ -1298,6 +1301,51 @@ PyObject* Application::sGetShortcut(PyObject * /*self*/, PyObject *args) } } +PyObject* Application::sGetCommandInfo(PyObject * /*self*/, PyObject *args) +{ + char* pName; + if (!PyArg_ParseTuple(args, "s", &pName)) + return NULL; + + Command* cmd = Application::Instance->commandManager().getCommandByName(pName); + if (cmd) { + PyObject* pyList = PyList_New(6); + const char* menuTxt = cmd->getMenuText(); + const char* tooltipTxt = cmd->getToolTipText(); + const char* whatsThisTxt = cmd->getWhatsThis(); + const char* statustipTxt = cmd->getStatusTip(); + const char* pixMapTxt = cmd->getPixmap(); + const char* shortcutTxt = cmd->getAccel(); + +#if PY_MAJOR_VERSION >= 3 + PyObject* strMenuTxt = PyUnicode_FromString(menuTxt ? menuTxt : ""); + PyObject* strTooltipTxt = PyUnicode_FromString(tooltipTxt ? tooltipTxt : ""); + PyObject* strWhatsThisTxt = PyUnicode_FromString(whatsThisTxt ? whatsThisTxt : ""); + PyObject* strStatustipTxt = PyUnicode_FromString(statustipTxt ? statustipTxt : ""); + PyObject* strPixMapTxt = PyUnicode_FromString(pixMapTxt ? pixMapTxt : ""); + PyObject* strShortcutTxt = PyUnicode_FromString(shortcutTxt ? shortcutTxt : ""); +#else + PyObject* strMenuTxt = PyString_FromString(menuTxt ? menuTxt : ""); + PyObject* strTooltipTxt = PyString_FromString(tooltipTxt ? tooltipTxt : ""); + PyObject* strWhatsThisTxt = PyString_FromString(whatsThisTxt ? whatsThisTxt : ""); + PyObject* strStatustipTxt = PyString_FromString(statustipTxt ? statustipTxt : ""); + PyObject* strPixMapTxt = PyString_FromString(pixMapTxt ? pixMapTxt : ""); + PyObject* strShortcutTxt = PyString_FromString(shortcutTxt ? shortcutTxt : ""); +#endif + PyList_SetItem(pyList, 0, strMenuTxt); + PyList_SetItem(pyList, 1, strTooltipTxt); + PyList_SetItem(pyList, 2, strWhatsThisTxt); + PyList_SetItem(pyList, 3, strStatustipTxt); + PyList_SetItem(pyList, 4, strPixMapTxt); + PyList_SetItem(pyList, 5, strShortcutTxt); + return pyList; + } + else { + PyErr_Format(Base::BaseExceptionFreeCADError, "No such command '%s'", pName); + return 0; + } +} + PyObject* Application::sListCommands(PyObject * /*self*/, PyObject *args) { if (!PyArg_ParseTuple(args, "")) From 2175eb0939aa3061c7a69d6e1ff2c5cfaad4eba5 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 9 Apr 2020 16:59:01 +0200 Subject: [PATCH 62/62] Draft: Added convenience methods to the Draft Working Plane to set top, front and side positions --- src/Mod/Draft/WorkingPlane.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index 7efe0f4c81..7201433eaf 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -726,6 +726,39 @@ class Plane: self.doc = None self.weak = True + def setTop(self): + """sets the WP to top position and updates the GUI""" + self.alignToPointAndAxis(FreeCAD.Vector(0.0, 0.0, 0.0), FreeCAD.Vector(0, 0, 1), 0.0) + if FreeCAD.GuiUp: + import FreeCADGui + from draftutils.translate import translate + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.setGrid() + if hasattr(FreeCADGui,"draftToolBar"): + FreeCADGui.draftToolBar.wplabel.setText(translate("draft", "Top")) + + def setFront(self): + """sets the WP to front position and updates the GUI""" + self.alignToPointAndAxis(FreeCAD.Vector(0.0, 0.0, 0.0), FreeCAD.Vector(0, 1, 0), 0.0) + if FreeCAD.GuiUp: + import FreeCADGui + from draftutils.translate import translate + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.setGrid() + if hasattr(FreeCADGui,"draftToolBar"): + FreeCADGui.draftToolBar.wplabel.setText(translate("draft", "Front")) + + def setSide(self): + """sets the WP to top position and updates the GUI""" + self.alignToPointAndAxis(FreeCAD.Vector(0.0, 0.0, 0.0), FreeCAD.Vector(-1, 0, 0), 0.0) + if FreeCAD.GuiUp: + import FreeCADGui + from draftutils.translate import translate + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.setGrid() + if hasattr(FreeCADGui,"draftToolBar"): + FreeCADGui.draftToolBar.wplabel.setText(translate("draft", "Side")) + def getRotation(self): """Return a placement describing the plane orientation only.