diff --git a/src/AIS/AIS_InteractiveContext.cxx b/src/AIS/AIS_InteractiveContext.cxx
index 030fd67623..31ef42a643 100644
--- a/src/AIS/AIS_InteractiveContext.cxx
+++ b/src/AIS/AIS_InteractiveContext.cxx
@@ -937,6 +937,11 @@ void AIS_InteractiveContext::RecomputePrsOnly(const Handle(AIS_InteractiveObject
   {
     myMainVwr->Update();
   }
+
+  if (!myMainVwr->ActiveViews().IsEmpty())
+  {
+    theIObj->RecomputeTransformation(myMainVwr->ActiveViewIterator().Value()->Camera());
+  }
 }
 
 //=================================================================================================
diff --git a/src/AIS/AIS_Manipulator.cxx b/src/AIS/AIS_Manipulator.cxx
index 13fb9fec20..e839f744a1 100644
--- a/src/AIS/AIS_Manipulator.cxx
+++ b/src/AIS/AIS_Manipulator.cxx
@@ -236,6 +236,7 @@ AIS_Manipulator::AIS_Manipulator()
     : myPosition(gp::XOY()),
       myCurrentIndex(-1),
       myCurrentMode(AIS_MM_None),
+      mySkinMode(ManipulatorSkin_Shaded),
       myIsActivationOnDetection(Standard_False),
       myIsZoomPersistentMode(Standard_True),
       myHasStartedTransformation(Standard_False),
@@ -255,6 +256,7 @@ AIS_Manipulator::AIS_Manipulator(const gp_Ax2& thePosition)
     : myPosition(thePosition),
       myCurrentIndex(-1),
       myCurrentMode(AIS_MM_None),
+      mySkinMode(ManipulatorSkin_Shaded),
       myIsActivationOnDetection(Standard_False),
       myIsZoomPersistentMode(Standard_True),
       myHasStartedTransformation(Standard_False),
@@ -609,6 +611,41 @@ Standard_Boolean AIS_Manipulator::ObjectTransformation(const Standard_Integer  t
       gp_Dir        aCurrentAxis = gce_MakeDir(aPosLoc, aNewPosition);
       Standard_Real anAngle      = aStartAxis.AngleWithRef(aCurrentAxis, aCurrAxis.Direction());
 
+      if (Abs(anAngle) < Precision::Confusion())
+      {
+        return Standard_False;
+      }
+
+      // Draw a sector indicating the rotation angle
+      if (mySkinMode == ManipulatorSkin_Flat)
+      {
+        const gp_Ax1& anAxis = myAxes[myCurrentIndex].ReferenceAxis();
+        const gp_Dir  aRotationStart =
+          anAxis.Direction().Z() > 0 ? myStartPosition.YDirection() : myStartPosition.Direction();
+        Standard_Real aRotationAngle =
+          aRotationStart.AngleWithRef(aCurrentAxis, aCurrAxis.Direction());
+        aRotationAngle -= (anAngle > 0) ? anAngle * 2.0 : anAngle;
+        if (anAxis.Direction().Z() > 0)
+        {
+          aRotationAngle += M_PI_2;
+        }
+
+        gp_Trsf aTrsf;
+        aTrsf.SetRotation(anAxis, aRotationAngle);
+
+        Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect();
+        anAspect->Aspect()->SetShadingModel(Graphic3d_TypeOfShadingModel_Unlit);
+        anAspect->SetMaterial(myDrawer->ShadingAspect()->Material());
+        anAspect->SetTransparency(0.5);
+        anAspect->SetColor(myAxes[myCurrentIndex].Color());
+
+        mySector.Init(0.0f, myAxes[myCurrentIndex].InnerRadius(), anAxis, Abs(anAngle));
+        mySectorGroup->Clear();
+        mySectorGroup->SetPrimitivesAspect(anAspect->Aspect());
+        mySectorGroup->AddPrimitiveArray(mySector.Array());
+        mySectorGroup->SetTransformation(aTrsf);
+      }
+
       // Change value of an angle if it should have different sign.
       if (anAngle * myPrevState < 0 && Abs(anAngle) < M_PI_2)
       {
@@ -616,11 +653,6 @@ Standard_Boolean AIS_Manipulator::ObjectTransformation(const Standard_Integer  t
         anAngle             = aSign * (M_PI * 2 - anAngle);
       }
 
-      if (Abs(anAngle) < Precision::Confusion())
-      {
-        return Standard_False;
-      }
-
       gp_Trsf aNewTrsf;
       aNewTrsf.SetRotation(aCurrAxis, anAngle);
       theTrsf *= aNewTrsf;
@@ -695,10 +727,14 @@ Standard_Boolean AIS_Manipulator::ProcessDragging(const Handle(AIS_InteractiveCo
       return Standard_True;
     }
     case AIS_DragAction_Stop: {
-      // at the end of transformation redisplay for updating sensitive areas
       StopTransform(true);
-      if (aCtx->IsDisplayed(this))
+      if (mySkinMode == ManipulatorSkin_Flat)
       {
+        mySectorGroup->Clear();
+      }
+      else if (aCtx->IsDisplayed(this))
+      {
+        // at the end of transformation redisplay for updating sensitive areas
         aCtx->Redisplay(this, true);
       }
       return Standard_True;
@@ -750,6 +786,195 @@ void AIS_Manipulator::StopTransform(const Standard_Boolean theToApply)
 
 //=================================================================================================
 
+void AIS_Manipulator::RecomputeTransformation(const Handle(Graphic3d_Camera)& theCamera)
+{
+  if (mySkinMode == ManipulatorSkin_Shaded)
+  {
+    return;
+  }
+
+  Standard_Boolean isRecomputedTranslation = Standard_False;
+  Standard_Boolean isRecomputedRotation    = Standard_False;
+  Standard_Boolean isRecomputedDragging    = Standard_False;
+  Standard_Boolean isRecomputedScaling     = Standard_False;
+
+  // Remove transformation from dragger group
+  for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
+  {
+    if (myAxes[anIt].HasDragging())
+    {
+      myAxes[anIt].DraggerGroup()->SetTransformation(gp_Trsf());
+      isRecomputedDragging = Standard_True;
+    }
+  }
+
+  const gp_Dir& aCameraDir = theCamera->Direction();
+  for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
+  {
+    Axis&         anAxis   = myAxes[anIt];
+    const gp_Ax1& aRefAxis = anAxis.ReferenceAxis();
+    gp_Dir        anAxisDir, aNormal;
+
+    if (aRefAxis.Direction().X() > 0)
+    {
+      aNormal   = myPosition.YDirection().Reversed();
+      anAxisDir = myPosition.XDirection();
+    }
+    else if (aRefAxis.Direction().Y() > 0)
+    {
+      aNormal   = myPosition.XDirection().Crossed(myPosition.YDirection()).Reversed();
+      anAxisDir = myPosition.YDirection();
+    }
+    else
+    {
+      aNormal   = myPosition.XDirection().Reversed();
+      anAxisDir = myPosition.XDirection().Crossed(myPosition.YDirection());
+    }
+
+    const gp_Dir aCameraProj = Abs(Abs(anAxisDir.Dot(aCameraDir)) - 1.0) <= gp::Resolution()
+                                 ? aCameraDir
+                                 : anAxisDir.Crossed(aCameraDir).Crossed(anAxisDir);
+    const Standard_Boolean isReversed = anAxisDir.Dot(aCameraDir) > 0;
+    Standard_Real          anAngle    = aNormal.AngleWithRef(aCameraProj, anAxisDir);
+    if (aRefAxis.Direction().X() > 0)
+      anAngle -= M_PI_2;
+
+    if (anAxis.HasTranslation())
+    {
+      Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect();
+      anAspect->Aspect()->SetShadingModel(Graphic3d_TypeOfShadingModel_Unlit);
+
+      Quantity_Color aColor =
+        isReversed ? Quantity_Color(anAxis.Color().Rgb() * 0.1f) : anAxis.Color();
+      anAspect->Aspect()->SetInteriorColor(aColor);
+
+      gp_Trsf aTranslatorTrsf;
+      aTranslatorTrsf.SetRotation(aRefAxis, anAngle);
+      if (isReversed)
+      {
+        const Standard_Real aLength = anAxis.AxisLength() + anAxis.Indent() * 4.0f;
+        aTranslatorTrsf.SetTranslationPart(aRefAxis.Direction().XYZ().Reversed() * aLength);
+      }
+
+      anAxis.TranslatorGroup()->SetGroupPrimitivesAspect(anAspect->Aspect());
+      anAxis.TranslatorGroup()->SetTransformation(aTranslatorTrsf);
+      anAxis.TranslatorHighlightPrs()->CurrentGroup()->SetTransformation(aTranslatorTrsf);
+      isRecomputedTranslation = Standard_True;
+    }
+
+    if (anAxis.HasRotation())
+    {
+      gp_Trsf aRotatorTrsf;
+      aRotatorTrsf.SetRotation(aRefAxis, anAngle - M_PI_2);
+      anAxis.RotatorGroup()->SetTransformation(aRotatorTrsf);
+      anAxis.RotatorHighlightPrs()->CurrentGroup()->SetTransformation(aRotatorTrsf);
+      isRecomputedRotation = Standard_True;
+    }
+
+    if (anAxis.HasDragging() && isReversed)
+    {
+      for (Standard_Integer anIndexIter = 0; anIndexIter < 3; ++anIndexIter)
+      {
+        gp_Vec aTranslation =
+          (anIndexIter == anIt)
+            ? aRefAxis.Direction().XYZ() * myAxes[anIndexIter].AxisRadius() * 2.0f
+            : aRefAxis.Direction().XYZ().Reversed() * myAxes[anIndexIter].AxisLength();
+        gp_Trsf aDraggerTrsf;
+        aDraggerTrsf.SetTranslation(aTranslation);
+
+        const Handle(Graphic3d_Group)& aDraggerGroup = myAxes[anIndexIter].DraggerGroup();
+        aDraggerTrsf *= aDraggerGroup->Transformation();
+        aDraggerGroup->SetTransformation(aDraggerTrsf);
+      }
+    }
+
+    if (anAxis.HasScaling())
+    {
+      gp_Trsf aScalerTrsf;
+      if (aRefAxis.Direction().X() > 0)
+      {
+        anAngle += M_PI_2;
+      }
+      aScalerTrsf.SetRotation(aRefAxis, anAngle);
+      if (isReversed)
+      {
+        Standard_ShortReal aLength =
+          anAxis.AxisLength() * 2.0f + anAxis.BoxSize() + anAxis.Indent() * 4.0f;
+        aScalerTrsf.SetTranslationPart(gp_Vec(aRefAxis.Direction().XYZ().Reversed() * aLength));
+      }
+      anAxis.ScalerGroup()->SetTransformation(aScalerTrsf);
+      anAxis.ScalerHighlightPrs()->CurrentGroup()->SetTransformation(aScalerTrsf);
+      isRecomputedScaling = Standard_True;
+    }
+  }
+
+  if (isRecomputedRotation)
+  {
+    const gp_Dir aXDir  = gp::DX();
+    const gp_Dir anYDir = gp::DY();
+    const gp_Dir aZDir  = gp::DZ();
+
+    const gp_Dir aCameraProjection =
+      Abs(aXDir.Dot(aCameraDir)) <= gp::Resolution()
+          || Abs(anYDir.Dot(aCameraDir)) <= gp::Resolution()
+        ? aCameraDir
+        : aXDir.XYZ() * (aXDir.Dot(aCameraDir)) + anYDir.XYZ() * (anYDir.Dot(aCameraDir));
+    const Standard_Boolean isReversed = aZDir.Dot(aCameraDir) > 0;
+
+    const Standard_Real anAngle  = M_PI_2 - aCameraDir.Angle(aCameraProjection);
+    gp_Dir              aRotAxis = Abs(Abs(aCameraProjection.Dot(aZDir)) - 1.0) <= gp::Resolution()
+                                     ? aZDir
+                                     : aCameraProjection.Crossed(aZDir);
+    if (isReversed)
+    {
+      aRotAxis.Reverse();
+    }
+
+    gp_Trsf aRotationTrsf;
+    aRotationTrsf.SetRotation(gp_Ax1(gp::Origin(), aRotAxis), anAngle);
+
+    gp_Ax3 aToSystem(gp::Origin(),
+                     myPosition.XDirection().Crossed(myPosition.YDirection()),
+                     myPosition.XDirection());
+    gp_Ax3 aFromSystem(gp::XOY());
+    aFromSystem.Transform(aRotationTrsf);
+
+    gp_Trsf aTrsf;
+    aTrsf.SetTransformation(aFromSystem, aToSystem);
+    myCircleGroup->SetTransformation(aTrsf);
+  }
+
+  if (isRecomputedDragging)
+  {
+    for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
+    {
+      myAxes[anIt].DraggerHighlightPrs()->CurrentGroup()->SetTransformation(
+        myAxes[anIt].DraggerGroup()->Transformation());
+    }
+  }
+
+  if (isRecomputedTranslation)
+  {
+    RecomputeSelection(AIS_MM_Translation);
+  };
+  if (isRecomputedRotation)
+  {
+    RecomputeSelection(AIS_MM_Rotation);
+  };
+  if (isRecomputedDragging)
+  {
+    RecomputeSelection(AIS_MM_TranslationPlane);
+  };
+  if (isRecomputedScaling)
+  {
+    RecomputeSelection(AIS_MM_Scaling);
+  };
+
+  Object()->GetContext()->RecomputeSelectionOnly(this);
+}
+
+//=================================================================================================
+
 void AIS_Manipulator::Transform(const gp_Trsf& theTrsf)
 {
   if (!IsAttached() || !myHasStartedTransformation)
@@ -918,6 +1143,10 @@ void AIS_Manipulator::DeactivateCurrentMode()
     }
 
     Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect();
+    if (mySkinMode == ManipulatorSkin_Flat)
+    {
+      anAspect->Aspect()->SetShadingModel(Graphic3d_TypeOfShadingModel_Unlit);
+    }
     anAspect->Aspect()->SetInteriorStyle(Aspect_IS_SOLID);
     anAspect->SetMaterial(myDrawer->ShadingAspect()->Material());
     if (myCurrentMode == AIS_MM_TranslationPlane)
@@ -961,6 +1190,17 @@ void AIS_Manipulator::SetZoomPersistence(const Standard_Boolean theToEnable)
 
 //=================================================================================================
 
+void AIS_Manipulator::SetSkinMode(const ManipulatorSkin theSkinMode)
+{
+  if (mySkinMode != theSkinMode)
+  {
+    SetToUpdate();
+  }
+  mySkinMode = theSkinMode;
+}
+
+//=================================================================================================
+
 void AIS_Manipulator::SetTransformPersistence(const Handle(Graphic3d_TransformPers)& theTrsfPers)
 {
   Standard_ASSERT_RETURN(!myIsZoomPersistentMode,
@@ -1005,16 +1245,37 @@ void AIS_Manipulator::Compute(const Handle(PrsMgr_PresentationManager)& thePrsMg
   thePrs->SetMutable(Standard_True);
   Handle(Graphic3d_Group)     aGroup;
   Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect();
+  if (mySkinMode == ManipulatorSkin_Flat)
+  {
+    anAspect->Aspect()->SetShadingModel(Graphic3d_TypeOfShadingModel_Unlit);
+  }
   anAspect->Aspect()->SetInteriorStyle(Aspect_IS_SOLID);
   anAspect->SetMaterial(myDrawer->ShadingAspect()->Material());
   anAspect->SetTransparency(myDrawer->ShadingAspect()->Transparency());
 
   // Display center
-  myCenter.Init(myAxes[0].AxisRadius() * 2.0f, gp::Origin());
+  myCenter.Init(myAxes[0].AxisRadius() * 2.0f, gp::Origin(), mySkinMode);
   aGroup = thePrs->NewGroup();
   aGroup->SetPrimitivesAspect(myDrawer->ShadingAspect()->Aspect());
   aGroup->AddPrimitiveArray(myCenter.Array());
 
+  // Display outer circle
+  if (mySkinMode == ManipulatorSkin_Flat
+      && (myAxes[0].HasRotation() || myAxes[1].HasRotation() || myAxes[2].HasRotation()))
+  {
+    myCircle.Init(myAxes[0].InnerRadius(),
+                  myAxes[0].Size(),
+                  gp_Ax1(gp::Origin(), gp::DZ()),
+                  2.0f * M_PI,
+                  myAxes[0].FacettesNumber() * 4);
+    myCircleGroup = thePrs->NewGroup();
+    myCircleGroup->SetPrimitivesAspect(myDrawer->ShadingAspect()->Aspect());
+    myCircleGroup->AddPrimitiveArray(myCircle.Array());
+
+    mySectorGroup = thePrs->NewGroup();
+    mySectorGroup->SetGroupPrimitivesAspect(anAspect->Aspect());
+  }
+
   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
   {
     // Display axes
@@ -1024,7 +1285,7 @@ void AIS_Manipulator::Compute(const Handle(PrsMgr_PresentationManager)& thePrsMg
       new Prs3d_ShadingAspect(new Graphic3d_AspectFillArea3d(*anAspect->Aspect()));
     anAspectAx->SetColor(myAxes[anIt].Color());
     aGroup->SetGroupPrimitivesAspect(anAspectAx->Aspect());
-    myAxes[anIt].Compute(thePrsMgr, thePrs, anAspectAx);
+    myAxes[anIt].Compute(thePrsMgr, thePrs, anAspectAx, mySkinMode);
     myAxes[anIt].SetTransformPersistence(TransformPersistence());
   }
 
@@ -1060,7 +1321,7 @@ void AIS_Manipulator::HilightSelected(const Handle(PrsMgr_PresentationManager)&
     return;
   }
 
-  if (anOwner->Mode() == AIS_MM_TranslationPlane)
+  if (anOwner->Mode() == AIS_MM_TranslationPlane && mySkinMode == ManipulatorSkin_Shaded)
   {
     myDraggerHighlight->SetColor(myAxes[anOwner->Index()].Color());
     aGroup->SetGroupPrimitivesAspect(myDraggerHighlight->Aspect());
@@ -1094,7 +1355,7 @@ void AIS_Manipulator::HilightOwnerWithColor(const Handle(PrsMgr_PresentationMana
 
   aPresentation->CStructure()->ViewAffinity = myViewAffinity;
 
-  if (anOwner->Mode() == AIS_MM_TranslationPlane)
+  if (anOwner->Mode() == AIS_MM_TranslationPlane && mySkinMode == ManipulatorSkin_Shaded)
   {
     Handle(Prs3d_Drawer) aStyle = new Prs3d_Drawer();
     aStyle->SetColor(myAxes[anOwner->Index()].Color());
@@ -1132,6 +1393,23 @@ void AIS_Manipulator::HilightOwnerWithColor(const Handle(PrsMgr_PresentationMana
 
 //=================================================================================================
 
+void AIS_Manipulator::RecomputeSelection(const AIS_ManipulatorMode theMode)
+{
+  if (theMode == AIS_MM_None)
+  {
+    return;
+  }
+
+  const Handle(SelectMgr_Selection)& aSelection = Object()->Selection(theMode);
+  if (!aSelection.IsNull())
+  {
+    aSelection->Clear();
+    ComputeSelection(aSelection, theMode);
+  }
+}
+
+//=================================================================================================
+
 void AIS_Manipulator::ComputeSelection(const Handle(SelectMgr_Selection)& theSelection,
                                        const Standard_Integer             theMode)
 {
@@ -1164,18 +1442,25 @@ void AIS_Manipulator::ComputeSelection(const Handle(SelectMgr_Selection)& theSel
         const Axis& anAxis = myAxes[anIt];
         anOwner            = new AIS_ManipulatorOwner(this, anIt, AIS_MM_Translation, 9);
 
-        // define sensitivity by line
-        Handle(Select3D_SensitiveSegment) aLine =
-          new Select3D_SensitiveSegment(anOwner, gp::Origin(), anAxis.TranslatorTipPosition());
-        aLine->SetSensitivityFactor(aHighSensitivity);
-        theSelection->Add(aLine);
+        if (mySkinMode == ManipulatorSkin_Shaded)
+        {
+          // define sensitivity by line
+          Handle(Select3D_SensitiveSegment) aLine =
+            new Select3D_SensitiveSegment(anOwner, gp::Origin(), anAxis.TranslatorTipPosition());
+          aLine->SetSensitivityFactor(aHighSensitivity);
+          theSelection->Add(aLine);
+        }
 
         // enlarge sensitivity by triangulation
         Handle(Select3D_SensitivePrimitiveArray) aTri =
           new Select3D_SensitivePrimitiveArray(anOwner);
+        TopLoc_Location aTrsf =
+          !myAxes[anIt].TranslatorGroup().IsNull()
+            ? TopLoc_Location(myAxes[anIt].TranslatorGroup()->Transformation())
+            : TopLoc_Location();
         aTri->InitTriangulation(anAxis.TriangleArray()->Attributes(),
                                 anAxis.TriangleArray()->Indices(),
-                                TopLoc_Location());
+                                aTrsf);
         theSelection->Add(aTri);
       }
       break;
@@ -1190,17 +1475,24 @@ void AIS_Manipulator::ComputeSelection(const Handle(SelectMgr_Selection)& theSel
         const Axis& anAxis = myAxes[anIt];
         anOwner            = new AIS_ManipulatorOwner(this, anIt, AIS_MM_Rotation, 9);
 
-        // define sensitivity by circle
-        const gp_Circ aGeomCircle(gp_Ax2(gp::Origin(), anAxis.ReferenceAxis().Direction()),
-                                  anAxis.RotatorDiskRadius());
-        Handle(Select3D_SensitiveCircle) aCircle = new ManipSensCircle(anOwner, aGeomCircle);
-        aCircle->SetSensitivityFactor(aLowSensitivity);
-        theSelection->Add(aCircle);
+        if (mySkinMode == ManipulatorSkin_Shaded)
+        {
+          // define sensitivity by circle
+          const gp_Circ aGeomCircle(gp_Ax2(gp::Origin(), anAxis.ReferenceAxis().Direction()),
+                                    anAxis.RotatorDiskRadius());
+          Handle(Select3D_SensitiveCircle) aCircle = new ManipSensCircle(anOwner, aGeomCircle);
+          aCircle->SetSensitivityFactor(aLowSensitivity);
+          theSelection->Add(aCircle);
+        }
         // enlarge sensitivity by triangulation
-        Handle(Select3D_SensitiveTriangulation) aTri =
-          new ManipSensTriangulation(anOwner,
-                                     myAxes[anIt].RotatorDisk().Triangulation(),
-                                     anAxis.ReferenceAxis().Direction());
+        Handle(Select3D_SensitivePrimitiveArray) aTri =
+          new Select3D_SensitivePrimitiveArray(anOwner);
+        const Handle(Graphic3d_Group)& aGroup = myAxes[anIt].RotatorGroup();
+        TopLoc_Location                aTrsf =
+          !aGroup.IsNull() ? TopLoc_Location(aGroup->Transformation()) : TopLoc_Location();
+        aTri->InitTriangulation(myAxes[anIt].RotatorDisk().Array()->Attributes(),
+                                myAxes[anIt].RotatorDisk().Array()->Indices(),
+                                aTrsf);
         theSelection->Add(aTri);
       }
       break;
@@ -1214,17 +1506,23 @@ void AIS_Manipulator::ComputeSelection(const Handle(SelectMgr_Selection)& theSel
         }
         anOwner = new AIS_ManipulatorOwner(this, anIt, AIS_MM_Scaling, 9);
 
-        // define sensitivity by point
-        Handle(Select3D_SensitivePoint) aPnt =
-          new Select3D_SensitivePoint(anOwner, myAxes[anIt].ScalerCubePosition());
-        aPnt->SetSensitivityFactor(aHighSensitivity);
-        theSelection->Add(aPnt);
+        if (mySkinMode == ManipulatorSkin_Shaded)
+        {
+          // define sensitivity by point
+          Handle(Select3D_SensitivePoint) aPnt =
+            new Select3D_SensitivePoint(anOwner, myAxes[anIt].ScalerCubePosition());
+          aPnt->SetSensitivityFactor(aHighSensitivity);
+          theSelection->Add(aPnt);
+        }
         // enlarge sensitivity by triangulation
-        Handle(Select3D_SensitiveTriangulation) aTri =
-          new Select3D_SensitiveTriangulation(anOwner,
-                                              myAxes[anIt].ScalerCube().Triangulation(),
-                                              TopLoc_Location(),
-                                              Standard_True);
+        Handle(Select3D_SensitivePrimitiveArray) aTri =
+          new Select3D_SensitivePrimitiveArray(anOwner);
+        const Handle(Graphic3d_Group)& aGroup = myAxes[anIt].ScalerGroup();
+        TopLoc_Location                aTrsf =
+          !aGroup.IsNull() ? TopLoc_Location(aGroup->Transformation()) : TopLoc_Location();
+        aTri->InitTriangulation(myAxes[anIt].ScalerCube().Array()->Attributes(),
+                                myAxes[anIt].ScalerCube().Array()->Indices(),
+                                aTrsf);
         theSelection->Add(aTri);
       }
       break;
@@ -1238,30 +1536,37 @@ void AIS_Manipulator::ComputeSelection(const Handle(SelectMgr_Selection)& theSel
         }
         anOwner = new AIS_ManipulatorOwner(this, anIt, AIS_MM_TranslationPlane, 9);
 
-        // define sensitivity by two crossed lines
-        Standard_Real aSensitivityOffset =
-          ZoomPersistence() ? aHighSensitivity * (0.5 + M_SQRT2) : 0.0;
-        gp_Pnt aP1 = myAxes[((anIt + 1) % 3)].TranslatorTipPosition().Translated(
-          myAxes[((anIt + 2) % 3)].ReferenceAxis().Direction().XYZ() * aSensitivityOffset);
-        gp_Pnt aP2 = myAxes[((anIt + 2) % 3)].TranslatorTipPosition().Translated(
-          myAxes[((anIt + 1) % 3)].ReferenceAxis().Direction().XYZ() * aSensitivityOffset);
-        gp_XYZ aMidP  = (aP1.XYZ() + aP2.XYZ()) / 2.0;
-        gp_XYZ anOrig = aMidP.Normalized().Multiplied(aSensitivityOffset);
+        if (mySkinMode == ManipulatorSkin_Shaded)
+        {
+          // define sensitivity by two crossed lines
+          Standard_Real aSensitivityOffset =
+            ZoomPersistence() ? aHighSensitivity * (0.5 + M_SQRT2) : 0.0;
+          gp_Pnt aP1 = myAxes[((anIt + 1) % 3)].TranslatorTipPosition().Translated(
+            myAxes[((anIt + 2) % 3)].ReferenceAxis().Direction().XYZ() * aSensitivityOffset);
+          gp_Pnt aP2 = myAxes[((anIt + 2) % 3)].TranslatorTipPosition().Translated(
+            myAxes[((anIt + 1) % 3)].ReferenceAxis().Direction().XYZ() * aSensitivityOffset);
+          gp_XYZ aMidP  = (aP1.XYZ() + aP2.XYZ()) / 2.0;
+          gp_XYZ anOrig = aMidP.Normalized().Multiplied(aSensitivityOffset);
 
-        Handle(Select3D_SensitiveSegment) aLine1 = new Select3D_SensitiveSegment(anOwner, aP1, aP2);
-        aLine1->SetSensitivityFactor(aLowSensitivity);
-        theSelection->Add(aLine1);
-        Handle(Select3D_SensitiveSegment) aLine2 =
-          new Select3D_SensitiveSegment(anOwner, anOrig, aMidP);
-        aLine2->SetSensitivityFactor(aLowSensitivity);
-        theSelection->Add(aLine2);
+          Handle(Select3D_SensitiveSegment) aLine1 =
+            new Select3D_SensitiveSegment(anOwner, aP1, aP2);
+          aLine1->SetSensitivityFactor(aLowSensitivity);
+          theSelection->Add(aLine1);
+          Handle(Select3D_SensitiveSegment) aLine2 =
+            new Select3D_SensitiveSegment(anOwner, anOrig, aMidP);
+          aLine2->SetSensitivityFactor(aLowSensitivity);
+          theSelection->Add(aLine2);
+        }
 
         // enlarge sensitivity by triangulation
-        Handle(Select3D_SensitiveTriangulation) aTri =
-          new Select3D_SensitiveTriangulation(anOwner,
-                                              myAxes[anIt].DraggerSector().Triangulation(),
-                                              TopLoc_Location(),
-                                              Standard_True);
+        Handle(Select3D_SensitivePrimitiveArray) aTri =
+          new Select3D_SensitivePrimitiveArray(anOwner);
+        const Handle(Graphic3d_Group)& aGroup = myAxes[anIt].DraggerGroup();
+        TopLoc_Location                aTrsf =
+          !aGroup.IsNull() ? TopLoc_Location(aGroup->Transformation()) : TopLoc_Location();
+        aTri->InitTriangulation(myAxes[anIt].DraggerSector().Array()->Attributes(),
+                                myAxes[anIt].DraggerSector().Array()->Indices(),
+                                aTrsf);
         theSelection->Add(aTri);
       }
       break;
@@ -1281,6 +1586,7 @@ void AIS_Manipulator::ComputeSelection(const Handle(SelectMgr_Selection)& theSel
 void AIS_Manipulator::Disk::Init(const Standard_ShortReal theInnerRadius,
                                  const Standard_ShortReal theOuterRadius,
                                  const gp_Ax1&            thePosition,
+                                 const Standard_Real      theAngle,
                                  const Standard_Integer   theSlicesNb,
                                  const Standard_Integer   theStacksNb)
 {
@@ -1289,8 +1595,9 @@ void AIS_Manipulator::Disk::Init(const Standard_ShortReal theInnerRadius,
   myOuterRad = theOuterRadius;
 
   Prs3d_ToolDisk aTool(theInnerRadius, theOuterRadius, theSlicesNb, theStacksNb);
-  gp_Ax3         aSystem(myPosition.Location(), myPosition.Direction());
-  gp_Trsf        aTrsf;
+  aTool.SetAngleRange(0, theAngle);
+  gp_Ax3  aSystem(myPosition.Location(), myPosition.Direction());
+  gp_Trsf aTrsf;
   aTrsf.SetTransformation(aSystem, gp_Ax3());
   myArray         = aTool.CreateTriangulation(aTrsf);
   myTriangulation = aTool.CreatePolyTriangulation(aTrsf);
@@ -1303,15 +1610,18 @@ void AIS_Manipulator::Disk::Init(const Standard_ShortReal theInnerRadius,
 //=======================================================================
 void AIS_Manipulator::Sphere::Init(const Standard_ShortReal theRadius,
                                    const gp_Pnt&            thePosition,
+                                   const ManipulatorSkin    theSkinMode,
                                    const Standard_Integer   theSlicesNb,
                                    const Standard_Integer   theStacksNb)
 {
   myPosition = thePosition;
   myRadius   = theRadius;
 
-  Prs3d_ToolSphere aTool(theRadius, theSlicesNb, theStacksNb);
-  gp_Trsf          aTrsf;
+  gp_Trsf aTrsf;
   aTrsf.SetTranslation(gp_Vec(gp::Origin(), thePosition));
+
+  const Standard_Real aRadius = theSkinMode == ManipulatorSkin_Flat ? theRadius * 0.5 : theRadius;
+  Prs3d_ToolSphere    aTool(aRadius, theSlicesNb, theStacksNb);
   myArray         = aTool.CreateTriangulation(aTrsf);
   myTriangulation = aTool.CreatePolyTriangulation(aTrsf);
 }
@@ -1321,56 +1631,80 @@ void AIS_Manipulator::Sphere::Init(const Standard_ShortReal theRadius,
 // function : Init
 // purpose  :
 //=======================================================================
-void AIS_Manipulator::Cube::Init(const gp_Ax1& thePosition, const Standard_ShortReal theSize)
+void AIS_Manipulator::Cube::Init(const gp_Ax1&            thePosition,
+                                 const Standard_ShortReal theSize,
+                                 const ManipulatorSkin    theSkinMode)
 {
-  myArray = new Graphic3d_ArrayOfTriangles(12 * 3, 0, Standard_True);
+  if (theSkinMode == ManipulatorSkin_Flat)
+  {
+    gp_Dir aXDirection;
+    if (thePosition.Direction().X() > 0)
+      aXDirection = gp::DY();
+    else if (thePosition.Direction().Y() > 0)
+      aXDirection = gp::DZ();
+    else
+      aXDirection = gp::DX();
 
-  Poly_Array1OfTriangle      aPolyTriangles(1, 12);
-  TColgp_Array1OfPnt         aPoints(1, 36);
-  NCollection_Array1<gp_Dir> aNormals(1, 12);
-  myTriangulation = new Poly_Triangulation(aPoints, aPolyTriangles);
+    gp_Pnt aLocation =
+      thePosition.Location().Translated(gp_Vec(thePosition.Direction().XYZ() * theSize));
+    gp_Ax3  aSystem(aLocation, aXDirection, thePosition.Direction());
+    gp_Trsf aTrsf;
+    aTrsf.SetTransformation(aSystem, gp_Ax3());
 
-  gp_Ax2 aPln(thePosition.Location(), thePosition.Direction());
-  gp_Pnt aBottomLeft = thePosition.Location().XYZ() - aPln.XDirection().XYZ() * theSize * 0.5
-                       - aPln.YDirection().XYZ() * theSize * 0.5;
-  gp_Pnt aV2 = aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize;
-  gp_Pnt aV3 =
-    aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize + aPln.XDirection().XYZ() * theSize;
-  gp_Pnt aV4       = aBottomLeft.XYZ() + aPln.XDirection().XYZ() * theSize;
-  gp_Pnt aTopRight = thePosition.Location().XYZ() + thePosition.Direction().XYZ() * theSize
-                     + aPln.XDirection().XYZ() * theSize * 0.5
-                     + aPln.YDirection().XYZ() * theSize * 0.5;
-  gp_Pnt aV5 = aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize;
-  gp_Pnt aV6 =
-    aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize - aPln.XDirection().XYZ() * theSize;
-  gp_Pnt aV7 = aTopRight.XYZ() - aPln.XDirection().XYZ() * theSize;
+    Prs3d_ToolDisk aTool(0.0, theSize, 40, 40);
+    myArray         = aTool.CreateTriangulation(aTrsf);
+    myTriangulation = aTool.CreatePolyTriangulation(aTrsf);
+  }
+  else
+  {
+    myArray = new Graphic3d_ArrayOfTriangles(12 * 3, 0, Standard_True);
 
-  gp_Dir aRight((gp_Vec(aTopRight, aV7) ^ gp_Vec(aTopRight, aV2)).XYZ());
-  gp_Dir aFront((gp_Vec(aV3, aV4) ^ gp_Vec(aV3, aV5)).XYZ());
+    Poly_Array1OfTriangle aPolyTriangles(1, 12);
+    TColgp_Array1OfPnt    aPoints(1, 36);
+    myTriangulation = new Poly_Triangulation(aPoints, aPolyTriangles);
 
-  // Bottom
-  addTriangle(0, aBottomLeft, aV2, aV3, -thePosition.Direction());
-  addTriangle(1, aBottomLeft, aV3, aV4, -thePosition.Direction());
+    gp_Ax2 aPln(thePosition.Location(), thePosition.Direction());
+    gp_Pnt aBottomLeft = thePosition.Location().XYZ() - aPln.XDirection().XYZ() * theSize * 0.5
+                         - aPln.YDirection().XYZ() * theSize * 0.5;
+    gp_Pnt aV2 = aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize;
+    gp_Pnt aV3 =
+      aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize + aPln.XDirection().XYZ() * theSize;
+    gp_Pnt aV4       = aBottomLeft.XYZ() + aPln.XDirection().XYZ() * theSize;
+    gp_Pnt aTopRight = thePosition.Location().XYZ() + thePosition.Direction().XYZ() * theSize
+                       + aPln.XDirection().XYZ() * theSize * 0.5
+                       + aPln.YDirection().XYZ() * theSize * 0.5;
+    gp_Pnt aV5 = aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize;
+    gp_Pnt aV6 =
+      aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize - aPln.XDirection().XYZ() * theSize;
+    gp_Pnt aV7 = aTopRight.XYZ() - aPln.XDirection().XYZ() * theSize;
 
-  // Front
-  addTriangle(2, aV3, aV5, aV4, -aFront);
-  addTriangle(3, aV3, aTopRight, aV5, -aFront);
+    gp_Dir aRight((gp_Vec(aTopRight, aV7) ^ gp_Vec(aTopRight, aV2)).XYZ());
+    gp_Dir aFront((gp_Vec(aV3, aV4) ^ gp_Vec(aV3, aV5)).XYZ());
 
-  // Back
-  addTriangle(4, aBottomLeft, aV7, aV2, aFront);
-  addTriangle(5, aBottomLeft, aV6, aV7, aFront);
+    // Bottom
+    addTriangle(0, aBottomLeft, aV2, aV3, -thePosition.Direction());
+    addTriangle(1, aBottomLeft, aV3, aV4, -thePosition.Direction());
 
-  // aTop
-  addTriangle(6, aV7, aV6, aV5, thePosition.Direction());
-  addTriangle(7, aTopRight, aV7, aV5, thePosition.Direction());
+    // Front
+    addTriangle(2, aV3, aV5, aV4, -aFront);
+    addTriangle(3, aV3, aTopRight, aV5, -aFront);
 
-  // Left
-  addTriangle(8, aV6, aV4, aV5, aRight);
-  addTriangle(9, aBottomLeft, aV4, aV6, aRight);
+    // Back
+    addTriangle(4, aBottomLeft, aV7, aV2, aFront);
+    addTriangle(5, aBottomLeft, aV6, aV7, aFront);
 
-  // Right
-  addTriangle(10, aV3, aV7, aTopRight, -aRight);
-  addTriangle(11, aV3, aV2, aV7, -aRight);
+    // aTop
+    addTriangle(6, aV7, aV6, aV5, thePosition.Direction());
+    addTriangle(7, aTopRight, aV7, aV5, thePosition.Direction());
+
+    // Left
+    addTriangle(8, aV6, aV4, aV5, aRight);
+    addTriangle(9, aBottomLeft, aV4, aV6, aRight);
+
+    // Right
+    addTriangle(10, aV3, aV7, aTopRight, -aRight);
+    addTriangle(11, aV3, aV2, aV7, -aRight);
+  }
 }
 
 //=======================================================================
@@ -1403,15 +1737,46 @@ void AIS_Manipulator::Cube::addTriangle(const Standard_Integer theIndex,
 void AIS_Manipulator::Sector::Init(const Standard_ShortReal theRadius,
                                    const gp_Ax1&            thePosition,
                                    const gp_Dir&            theXDirection,
+                                   const ManipulatorSkin    theSkinMode,
                                    const Standard_Integer   theSlicesNb,
                                    const Standard_Integer   theStacksNb)
 {
-  Prs3d_ToolSector aTool(theRadius, theSlicesNb, theStacksNb);
-  gp_Ax3           aSystem(thePosition.Location(), thePosition.Direction(), theXDirection);
-  gp_Trsf          aTrsf;
+  gp_Ax3  aSystem(thePosition.Location(), thePosition.Direction(), theXDirection);
+  gp_Trsf aTrsf;
   aTrsf.SetTransformation(aSystem, gp_Ax3());
-  myArray         = aTool.CreateTriangulation(aTrsf);
-  myTriangulation = aTool.CreatePolyTriangulation(aTrsf);
+
+  if (theSkinMode == ManipulatorSkin_Flat)
+  {
+    myArray         = new Graphic3d_ArrayOfTriangles(4, 6, Graphic3d_ArrayFlags_VertexNormal);
+    myTriangulation = new Poly_Triangulation(4, 2, Standard_False);
+
+    const Standard_Real anIndent = theRadius / 3.0;
+    gp_Pnt              aV1      = gp_Pnt(anIndent, anIndent, 0.0).Transformed(aTrsf);
+    gp_Pnt              aV2      = gp_Pnt(anIndent, anIndent * 2.0, 0.0).Transformed(aTrsf);
+    gp_Pnt              aV3      = gp_Pnt(anIndent * 2.0, anIndent * 2.0, 0.0).Transformed(aTrsf);
+    gp_Pnt              aV4      = gp_Pnt(anIndent * 2.0, anIndent, 0.0).Transformed(aTrsf);
+    gp_Dir              aNormal  = gp_Dir(0.0, 0.0, -1.0).Transformed(aTrsf);
+
+    myArray->AddVertex(aV1, aNormal);
+    myArray->AddVertex(aV2, aNormal);
+    myArray->AddVertex(aV3, aNormal);
+    myArray->AddVertex(aV4, aNormal);
+    myArray->AddTriangleEdges(3, 1, 2);
+    myArray->AddTriangleEdges(1, 3, 4);
+
+    myTriangulation->SetNode(1, aV1);
+    myTriangulation->SetNode(2, aV2);
+    myTriangulation->SetNode(3, aV3);
+    myTriangulation->SetNode(4, aV4);
+    myTriangulation->SetTriangle(1, Poly_Triangle(3, 1, 2));
+    myTriangulation->SetTriangle(2, Poly_Triangle(1, 3, 4));
+  }
+  else
+  {
+    Prs3d_ToolSector aTool(theRadius, theSlicesNb, theStacksNb);
+    myArray         = aTool.CreateTriangulation(aTrsf);
+    myTriangulation = aTool.CreatePolyTriangulation(aTrsf);
+  }
 }
 
 //=======================================================================
@@ -1449,7 +1814,8 @@ AIS_Manipulator::Axis::Axis(const gp_Ax1&            theAxis,
 
 void AIS_Manipulator::Axis::Compute(const Handle(PrsMgr_PresentationManager)& thePrsMgr,
                                     const Handle(Prs3d_Presentation)&         thePrs,
-                                    const Handle(Prs3d_ShadingAspect)&        theAspect)
+                                    const Handle(Prs3d_ShadingAspect)&        theAspect,
+                                    const ManipulatorSkin                     theSkinMode)
 {
   if (myHasTranslation)
   {
@@ -1458,16 +1824,80 @@ void AIS_Manipulator::Axis::Compute(const Handle(PrsMgr_PresentationManager)& th
     myArrowTipPos =
       gp_Pnt(0.0, 0.0, 0.0).Translated(myReferenceAxis.Direction().XYZ() * aCylinderLength);
 
-    myTriangleArray   = Prs3d_Arrow::DrawShaded(gp_Ax1(gp::Origin(), myReferenceAxis.Direction()),
-                                              myAxisRadius,
-                                              myLength,
-                                              myAxisRadius * 1.5,
-                                              anArrowLength,
-                                              myFacettesNumber);
     myTranslatorGroup = thePrs->NewGroup();
-    myTranslatorGroup->SetClosed(true);
+    myTranslatorGroup->SetClosed(theSkinMode == ManipulatorSkin_Shaded);
     myTranslatorGroup->SetGroupPrimitivesAspect(theAspect->Aspect());
-    myTranslatorGroup->AddPrimitiveArray(myTriangleArray);
+
+    if (theSkinMode == ManipulatorSkin_Flat)
+    {
+      const Standard_Integer aStripsNb = 14;
+
+      myTriangleArray = new Graphic3d_ArrayOfTriangles(aStripsNb * 4,
+                                                       aStripsNb * 6,
+                                                       Graphic3d_ArrayFlags_VertexNormal);
+      Handle(Graphic3d_ArrayOfTriangles) aColorlessArr =
+        new Graphic3d_ArrayOfTriangles(aStripsNb * 2,
+                                       aStripsNb * 3,
+                                       Graphic3d_ArrayFlags_VertexNormal);
+      Handle(Graphic3d_ArrayOfTriangles) aColoredArr = new Graphic3d_ArrayOfTriangles(
+        aStripsNb * 2,
+        aStripsNb * 3,
+        Graphic3d_ArrayFlags_VertexNormal | Graphic3d_ArrayFlags_VertexColor);
+
+      gp_Ax3  aSystem(gp::Origin(), myReferenceAxis.Direction());
+      gp_Trsf aTrsf;
+      aTrsf.SetTransformation(aSystem, gp_Ax3());
+
+      gp_Dir        aNormal = gp_Dir(1.0, 0.0, 0.0).Transformed(aTrsf);
+      Standard_Real aLength = myLength + myIndent * 4.0f;
+
+      const Standard_Real aStepV = 1.0f / aStripsNb;
+      for (Standard_Integer aU = 0; aU <= 1; ++aU)
+      {
+        for (Standard_Integer aV = 0; aV <= aStripsNb; ++aV)
+        {
+          gp_Pnt aVertex = gp_Pnt(0.0, myAxisRadius * (1.5f * aU - 0.75f), aLength * aV * aStepV)
+                             .Transformed(aTrsf);
+          myTriangleArray->AddVertex(aVertex, aNormal);
+
+          if (aV != 0)
+          {
+            aColorlessArr->AddVertex(aVertex, aNormal);
+          }
+          if (aV != aStripsNb)
+          {
+            aColoredArr->AddVertex(aVertex, aNormal, myColor);
+          }
+
+          if (aU != 0 && aV != 0)
+          {
+            int aVertId = myTriangleArray->VertexNumber();
+            myTriangleArray->AddTriangleEdges(aVertId, aVertId - aStripsNb - 2, aVertId - 1);
+            myTriangleArray->AddTriangleEdges(aVertId - aStripsNb - 2,
+                                              aVertId,
+                                              aVertId - aStripsNb - 1);
+
+            Handle(Graphic3d_ArrayOfTriangles) aSquares = aV % 2 == 0 ? aColorlessArr : aColoredArr;
+
+            aVertId = aSquares->VertexNumber();
+            aSquares->AddTriangleEdges(aVertId, aVertId - aStripsNb - 1, aVertId - 1);
+            aSquares->AddTriangleEdges(aVertId - aStripsNb - 1, aVertId, aVertId - aStripsNb);
+          }
+        }
+      }
+      myTranslatorGroup->AddPrimitiveArray(aColoredArr);
+      myTranslatorGroup->AddPrimitiveArray(aColorlessArr);
+    }
+    else
+    {
+      myTriangleArray = Prs3d_Arrow::DrawShaded(gp_Ax1(gp::Origin(), myReferenceAxis.Direction()),
+                                                myAxisRadius,
+                                                myLength,
+                                                myAxisRadius * 1.5,
+                                                anArrowLength,
+                                                myFacettesNumber);
+      myTranslatorGroup->AddPrimitiveArray(myTriangleArray);
+    }
 
     if (myHighlightTranslator.IsNull())
     {
@@ -1487,10 +1917,12 @@ void AIS_Manipulator::Axis::Compute(const Handle(PrsMgr_PresentationManager)& th
   if (myHasScaling)
   {
     myCubePos = myReferenceAxis.Direction().XYZ() * (myLength + myIndent);
-    myCube.Init(gp_Ax1(myCubePos, myReferenceAxis.Direction()), myBoxSize);
+    const Standard_ShortReal aBoxSize =
+      theSkinMode == ManipulatorSkin_Shaded ? myBoxSize : myBoxSize * 0.5f + myIndent;
+    myCube.Init(gp_Ax1(myCubePos, myReferenceAxis.Direction()), aBoxSize, theSkinMode);
 
     myScalerGroup = thePrs->NewGroup();
-    myScalerGroup->SetClosed(true);
+    myScalerGroup->SetClosed(theSkinMode == ManipulatorSkin_Shaded);
     myScalerGroup->SetGroupPrimitivesAspect(theAspect->Aspect());
     myScalerGroup->AddPrimitiveArray(myCube.Array());
 
@@ -1511,10 +1943,12 @@ void AIS_Manipulator::Axis::Compute(const Handle(PrsMgr_PresentationManager)& th
 
   if (myHasRotation)
   {
-    myCircleRadius = myInnerRadius + myIndent * 2 + myDiskThickness * 0.5f;
-    myCircle.Init(myInnerRadius + myIndent * 2,
-                  myInnerRadius + myDiskThickness + myIndent * 2,
+    myCircleRadius              = myInnerRadius + myIndent * 2.0f + myDiskThickness * 0.5f;
+    const Standard_Real anAngle = theSkinMode == ManipulatorSkin_Shaded ? M_PI * 2.0f : M_PI;
+    myCircle.Init(myInnerRadius + myIndent * 2.0f,
+                  Size(),
                   gp_Ax1(gp::Origin(), myReferenceAxis.Direction()),
+                  anAngle,
                   myFacettesNumber * 2);
     myRotatorGroup = thePrs->NewGroup();
     myRotatorGroup->SetGroupPrimitivesAspect(theAspect->Aspect());
@@ -1545,13 +1979,21 @@ void AIS_Manipulator::Axis::Compute(const Handle(PrsMgr_PresentationManager)& th
     else
       aXDirection = gp::DX();
 
-    mySector.Init(myInnerRadius + myIndent * 2,
-                  gp_Ax1(gp::Origin(), myReferenceAxis.Direction()),
+    gp_Pnt             aPosition = theSkinMode == ManipulatorSkin_Flat
+                                     ? gp_Pnt(myReferenceAxis.Direction().Reversed().XYZ() * (myAxisRadius))
+                                     : gp::Origin();
+    Standard_ShortReal aRadius =
+      theSkinMode == ManipulatorSkin_Flat ? myLength : myInnerRadius + myIndent * 2;
+    mySector.Init(aRadius,
+                  gp_Ax1(aPosition, myReferenceAxis.Direction()),
                   aXDirection,
+                  theSkinMode,
                   myFacettesNumber * 2);
     myDraggerGroup = thePrs->NewGroup();
 
-    Handle(Graphic3d_AspectFillArea3d) aFillArea = new Graphic3d_AspectFillArea3d();
+    Handle(Graphic3d_AspectFillArea3d) aFillArea =
+      theSkinMode == ManipulatorSkin_Flat ? theAspect->Aspect() : new Graphic3d_AspectFillArea3d();
+
     myDraggerGroup->SetGroupPrimitivesAspect(aFillArea);
     myDraggerGroup->AddPrimitiveArray(mySector.Array());
 
diff --git a/src/AIS/AIS_Manipulator.hxx b/src/AIS/AIS_Manipulator.hxx
index 47c18b307f..925d67b07c 100644
--- a/src/AIS/AIS_Manipulator.hxx
+++ b/src/AIS/AIS_Manipulator.hxx
@@ -217,6 +217,14 @@ public:
   //! @warning It will does nothing if transformation is not initiated (with StartTransform() call).
   Standard_EXPORT void Transform(const gp_Trsf& aTrsf);
 
+  //! Apply camera transformation to flat skin manipulator
+  Standard_EXPORT void RecomputeTransformation(const Handle(Graphic3d_Camera)& theCamera)
+    Standard_OVERRIDE;
+
+  //! Recomputes sensitive primitives for the given selection mode.
+  //! @param theMode selection mode to recompute sensitive primitives
+  Standard_EXPORT void RecomputeSelection(const AIS_ManipulatorMode theMode);
+
   //! Reset start (reference) transformation.
   //! @param[in] theToApply  option to apply or to cancel the started transformation.
   //! @warning It is used in chain with StartTransform-Transform(gp_Trsf)-StopTransform
@@ -304,6 +312,18 @@ public: //! @name Configuration of graphical transformations
     const Handle(Graphic3d_TransformPers)& theTrsfPers) Standard_OVERRIDE;
 
 public: //! @name Setters for parameters
+  enum ManipulatorSkin
+  {
+    ManipulatorSkin_Shaded,
+    ManipulatorSkin_Flat
+  };
+
+  //! @return current manipulator skin mode.
+  ManipulatorSkin SkinMode() const { return mySkinMode; }
+
+  //! Sets skin mode for the manipulator.
+  Standard_EXPORT void SetSkinMode(const ManipulatorSkin theSkinMode);
+
   AIS_ManipulatorMode ActiveMode() const { return myCurrentMode; }
 
   Standard_Integer ActiveAxisIndex() const { return myCurrentIndex; }
@@ -468,6 +488,7 @@ protected: //! @name Auxiliary classes to fill presentation with proper primitiv
     void Init(const Standard_ShortReal theInnerRadius,
               const Standard_ShortReal theOuterRadius,
               const gp_Ax1&            thePosition,
+              const Standard_Real      theAngle,
               const Standard_Integer   theSlicesNb = 20,
               const Standard_Integer   theStacksNb = 20);
 
@@ -488,6 +509,7 @@ protected: //! @name Auxiliary classes to fill presentation with proper primitiv
 
     void Init(const Standard_ShortReal theRadius,
               const gp_Pnt&            thePosition,
+              const ManipulatorSkin    theSkinMode,
               const Standard_Integer   theSlicesNb = 20,
               const Standard_Integer   theStacksNb = 20);
 
@@ -503,7 +525,9 @@ protected: //! @name Auxiliary classes to fill presentation with proper primitiv
 
     ~Cube() {}
 
-    void Init(const gp_Ax1& thePosition, const Standard_ShortReal myBoxSize);
+    void Init(const gp_Ax1&            thePosition,
+              const Standard_ShortReal myBoxSize,
+              const ManipulatorSkin    theSkinMode);
 
     const Handle(Poly_Triangulation)& Triangulation() const { return myTriangulation; }
 
@@ -535,6 +559,7 @@ protected: //! @name Auxiliary classes to fill presentation with proper primitiv
     void Init(const Standard_ShortReal theRadius,
               const gp_Ax1&            thePosition,
               const gp_Dir&            theXDirection,
+              const ManipulatorSkin    theSkinMode,
               const Standard_Integer   theSlicesNb = 5,
               const Standard_Integer   theStacksNb = 5);
 
@@ -557,7 +582,8 @@ protected: //! @name Auxiliary classes to fill presentation with proper primitiv
 
     void Compute(const Handle(PrsMgr_PresentationManager)& thePrsMgr,
                  const Handle(Prs3d_Presentation)&         thePrs,
-                 const Handle(Prs3d_ShadingAspect)&        theAspect);
+                 const Handle(Prs3d_ShadingAspect)&        theAspect,
+                 const ManipulatorSkin                     theSkinMode);
 
     const gp_Ax1& ReferenceAxis() const { return myReferenceAxis; }
 
@@ -631,8 +657,12 @@ protected: //! @name Auxiliary classes to fill presentation with proper primitiv
 
     Standard_ShortReal AxisLength() const { return myLength; }
 
+    Standard_ShortReal BoxSize() const { return myBoxSize; }
+
     Standard_ShortReal AxisRadius() const { return myAxisRadius; }
 
+    Standard_ShortReal Indent() const { return myIndent; }
+
     void SetAxisRadius(const Standard_ShortReal theValue) { myAxisRadius = theValue; }
 
     const Handle(Prs3d_Presentation)& TranslatorHighlightPrs() const
@@ -658,10 +688,9 @@ protected: //! @name Auxiliary classes to fill presentation with proper primitiv
 
     void SetIndent(const Standard_ShortReal theValue) { myIndent = theValue; }
 
-    Standard_ShortReal Size() const
-    {
-      return myLength + myBoxSize + myDiskThickness + myIndent * 2.0f;
-    }
+    Standard_ShortReal Size() const { return myInnerRadius + myDiskThickness + myIndent * 2; }
+
+    Standard_ShortReal InnerRadius() const { return myInnerRadius + myIndent * 2.0f; }
 
     gp_Pnt ScalerCenter(const gp_Pnt& theLocation) const
     {
@@ -752,8 +781,15 @@ protected:
                     // clang-format off
   gp_Ax2 myPosition; //!< Position of the manipulator object. it displays its location and position of its axes.
 
+  Disk                    myCircle; //!< Outer circle
+  Handle(Graphic3d_Group) myCircleGroup;
+
+  Disk                    mySector; //!< Sector indicating the rotation angle
+  Handle(Graphic3d_Group) mySectorGroup;
+
   Standard_Integer myCurrentIndex; //!< Index of active axis.
   AIS_ManipulatorMode myCurrentMode; //!< Name of active manipulation mode.
+  ManipulatorSkin mySkinMode; //!< Name of active skin mode.
 
   Standard_Boolean myIsActivationOnDetection; //!< Manual activation of modes (not on parts selection).
   Standard_Boolean myIsZoomPersistentMode; //!< Zoom persistence mode activation.
diff --git a/src/AIS/AIS_ViewController.cxx b/src/AIS/AIS_ViewController.cxx
index 03c80656eb..74181291dd 100644
--- a/src/AIS/AIS_ViewController.cxx
+++ b/src/AIS/AIS_ViewController.cxx
@@ -2280,6 +2280,13 @@ void AIS_ViewController::handleCameraActions(const Handle(AIS_InteractiveContext
     myGL.Orientation.ToFitAll = false;
   }
 
+  AIS_ListOfInteractive anObjects;
+  theCtx->DisplayedObjects(anObjects);
+  for (AIS_ListIteratorOfListOfInteractive anObjIter(anObjects); anObjIter.More(); anObjIter.Next())
+  {
+    anObjIter.Value()->RecomputeTransformation(theView->Camera());
+  }
+
   if (myGL.IsNewGesture)
   {
     if (myAnchorPointPrs1->HasInteractiveContext())
diff --git a/src/Graphic3d/Graphic3d_CView.cxx b/src/Graphic3d/Graphic3d_CView.cxx
index 6281cdd1f9..ee2edb2f20 100644
--- a/src/Graphic3d/Graphic3d_CView.cxx
+++ b/src/Graphic3d/Graphic3d_CView.cxx
@@ -447,6 +447,8 @@ void Graphic3d_CView::ReCompute(const Handle(Graphic3d_Structure)& theStruct)
     return;
   }
 
+  theStruct->RecomputeTransformation(myCamera);
+
   const Graphic3d_TypeOfAnswer anAnswer = acceptDisplay(theStruct->Visual());
   if (anAnswer != Graphic3d_TOA_COMPUTE)
   {
@@ -726,6 +728,12 @@ void Graphic3d_CView::Compute()
     aStructIter.Value()->SetHLRValidation(Standard_False);
   }
 
+  for (Graphic3d_MapOfStructure::Iterator aStructIter(myStructsDisplayed); aStructIter.More();
+       aStructIter.Next())
+  {
+    aStructIter.Value()->RecomputeTransformation(myCamera);
+  }
+
   if (!ComputedMode())
   {
     return;
@@ -828,6 +836,8 @@ void Graphic3d_CView::Display(const Handle(Graphic3d_Structure)& theStructure)
     anIndex = 0;
   }
 
+  theStructure->RecomputeTransformation(myCamera);
+
   Graphic3d_TypeOfAnswer anAnswer = acceptDisplay(theStructure->Visual());
   if (anAnswer == Graphic3d_TOA_NO)
   {
diff --git a/src/Graphic3d/Graphic3d_Group.hxx b/src/Graphic3d/Graphic3d_Group.hxx
index 5184fd10ff..b667d56d99 100644
--- a/src/Graphic3d/Graphic3d_Group.hxx
+++ b/src/Graphic3d/Graphic3d_Group.hxx
@@ -131,6 +131,12 @@ public:
   Standard_EXPORT virtual void SetFlippingOptions(const Standard_Boolean theIsEnabled,
                                                   const gp_Ax2&          theRefPlane) = 0;
 
+  //! Return transformation.
+  const gp_Trsf& Transformation() const { return myTrsf; }
+
+  //! Assign transformation.
+  virtual void SetTransformation(const gp_Trsf& theTrsf) { myTrsf = theTrsf; }
+
   //! Return transformation persistence.
   const Handle(Graphic3d_TransformPers)& TransformPersistence() const { return myTrsfPers; }
 
@@ -310,6 +316,7 @@ protected:
   Handle(Graphic3d_TransformPers) myTrsfPers;  //!< current transform persistence
   Graphic3d_Structure*            myStructure; //!< pointer to the parent structure
   Graphic3d_BndBox4f              myBounds;    //!< bounding box
+  gp_Trsf                         myTrsf;      //!< group transformation
   bool                            myIsClosed;  //!< flag indicating closed volume
 };
 
diff --git a/src/Graphic3d/Graphic3d_Structure.hxx b/src/Graphic3d/Graphic3d_Structure.hxx
index d5447f0af9..2ae8fcbad1 100644
--- a/src/Graphic3d/Graphic3d_Structure.hxx
+++ b/src/Graphic3d/Graphic3d_Structure.hxx
@@ -203,6 +203,12 @@ public:
     (void)theStructure;
   }
 
+  //! Calculates structure transformation for specific camera position
+  virtual void RecomputeTransformation(const Handle(Graphic3d_Camera)& theProjector)
+  {
+    (void)theProjector;
+  }
+
   //! Forces a new construction of the structure <me>
   //! if <me> is displayed and TOS_COMPUTED.
   Standard_EXPORT void ReCompute();
diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx
index 1153ecb15c..2508964081 100644
--- a/src/OpenGl/OpenGl_Structure.cxx
+++ b/src/OpenGl/OpenGl_Structure.cxx
@@ -406,6 +406,12 @@ void OpenGl_Structure::renderGeometry(const Handle(OpenGl_Workspace)& theWorkspa
   {
     const OpenGl_Group* aGroup = aGroupIter.Value();
 
+    const gp_Trsf& aTrsf = aGroup->Transformation();
+    if (aTrsf.Form() != gp_Identity)
+    {
+      applyTransformation(aCtx, aTrsf, Standard_True);
+    }
+
     const Handle(Graphic3d_TransformPers)& aTrsfPers = aGroup->TransformPersistence();
     if (!aTrsfPers.IsNull())
     {
@@ -421,6 +427,35 @@ void OpenGl_Structure::renderGeometry(const Handle(OpenGl_Workspace)& theWorkspa
       revertPersistence(aCtx, aTrsfPers, true, anOldCastShadows);
       aCtx->ApplyModelViewMatrix();
     }
+
+    if (aTrsf.Form() != gp_Identity)
+    {
+      applyTransformation(aCtx, aTrsf, Standard_False);
+    }
+  }
+}
+
+// =======================================================================
+// function : applyTransformation
+// purpose  :
+// =======================================================================
+void OpenGl_Structure::applyTransformation(const Handle(OpenGl_Context)& theContext,
+                                           const gp_Trsf&                theTrsf,
+                                           const Standard_Boolean        toEnable) const
+{
+  if (toEnable)
+  {
+    OpenGl_Mat4 aTrsf;
+    theTrsf.GetMat4(aTrsf);
+    theContext->ModelWorldState.Push();
+    OpenGl_Mat4& aModelWorld = theContext->ModelWorldState.ChangeCurrent();
+    aModelWorld              = aModelWorld * aTrsf;
+    theContext->ApplyModelViewMatrix();
+  }
+  else
+  {
+    theContext->ModelWorldState.Pop();
+    theContext->ApplyModelViewMatrix();
   }
 }
 
diff --git a/src/OpenGl/OpenGl_Structure.hxx b/src/OpenGl/OpenGl_Structure.hxx
index 773ef5dfbe..98d404784a 100644
--- a/src/OpenGl/OpenGl_Structure.hxx
+++ b/src/OpenGl/OpenGl_Structure.hxx
@@ -144,6 +144,14 @@ protected:
   //! Render the bounding box.
   Standard_EXPORT void renderBoundingBox(const Handle(OpenGl_Workspace)& theWorkspace) const;
 
+  //! Apply transformation into context.
+  //! @param theWorkspace current workspace
+  //! @param theTrsf transformation
+  //! @param toEnable flag to switch ON/OFF transformation
+  Standard_EXPORT void applyTransformation(const Handle(OpenGl_Context)& theContext,
+                                           const gp_Trsf&                theTrsf,
+                                           const Standard_Boolean        toEnable) const;
+
   //! Apply transform persistence into context.
   //! It disables shadows on non-3d objects when toEnable is true and restores otherwise.
   //! @param[in]  theCtx current context
diff --git a/src/PrsMgr/PrsMgr_PresentableObject.hxx b/src/PrsMgr/PrsMgr_PresentableObject.hxx
index 9b035fa695..70ee54a3ef 100644
--- a/src/PrsMgr/PrsMgr_PresentableObject.hxx
+++ b/src/PrsMgr/PrsMgr_PresentableObject.hxx
@@ -309,6 +309,15 @@ public: //! @name object transformation
   //! Updates final transformation (parent + local) of presentable object and its presentations.
   Standard_EXPORT virtual void UpdateTransformation();
 
+  //! Calculates object presentation for specific camera position.
+  //! Each of the views in the viewer and every modification such as rotation, for example, entails
+  //! recalculation.
+  //! @param theProjector [in] view orientation
+  virtual void RecomputeTransformation(const Handle(Graphic3d_Camera)& theProjector)
+  {
+    (void)theProjector;
+  }
+
 public: //! @name clipping planes
   //! Get clip planes.
   //! @return set of previously added clip planes for all display mode presentations.
diff --git a/src/PrsMgr/PrsMgr_Presentation.cxx b/src/PrsMgr/PrsMgr_Presentation.cxx
index 5855d23f0a..fe1902ea9d 100644
--- a/src/PrsMgr/PrsMgr_Presentation.cxx
+++ b/src/PrsMgr/PrsMgr_Presentation.cxx
@@ -186,6 +186,13 @@ void PrsMgr_Presentation::computeHLR(const Handle(Graphic3d_Camera)& theProjecto
 
 //=================================================================================================
 
+void PrsMgr_Presentation::RecomputeTransformation(const Handle(Graphic3d_Camera)& theProjector)
+{
+  myPresentableObject->RecomputeTransformation(theProjector);
+}
+
+//=================================================================================================
+
 PrsMgr_Presentation::~PrsMgr_Presentation()
 {
   Erase();
diff --git a/src/PrsMgr/PrsMgr_Presentation.hxx b/src/PrsMgr/PrsMgr_Presentation.hxx
index 0a007263f9..792f1c6890 100644
--- a/src/PrsMgr/PrsMgr_Presentation.hxx
+++ b/src/PrsMgr/PrsMgr_Presentation.hxx
@@ -100,6 +100,9 @@ protected:
                                           Handle(Graphic3d_Structure)&    theGivenStruct)
     Standard_OVERRIDE;
 
+  Standard_EXPORT virtual void RecomputeTransformation(const Handle(Graphic3d_Camera)& theProjector)
+    Standard_OVERRIDE;
+
 protected:
   Handle(PrsMgr_PresentationManager) myPresentationManager;
   PrsMgr_PresentableObject*          myPresentableObject;
diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx
index 0e094872f3..117949a620 100644
--- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx
+++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx
@@ -10836,7 +10836,8 @@ static Standard_Integer VRenderParams(Draw_Interpretor& theDI,
         }
         else
         {
-          theDI << "off" << " ";
+          theDI << "off"
+                << " ";
         }
         continue;
       }
@@ -10917,15 +10918,18 @@ static Standard_Integer VRenderParams(Draw_Interpretor& theDI,
       {
         if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
         {
-          theDI << "normal" << " ";
+          theDI << "normal"
+                << " ";
         }
         else if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
         {
-          theDI << "light" << " ";
+          theDI << "light"
+                << " ";
         }
         else
         {
-          theDI << "off" << " ";
+          theDI << "off"
+                << " ";
         }
         continue;
       }
@@ -10964,15 +10968,18 @@ static Standard_Integer VRenderParams(Draw_Interpretor& theDI,
       {
         if ((aParams.FontHinting & Font_Hinting_ForceAutohint) != 0)
         {
-          theDI << "force" << " ";
+          theDI << "force"
+                << " ";
         }
         else if ((aParams.FontHinting & Font_Hinting_NoAutohint) != 0)
         {
-          theDI << "disallow" << " ";
+          theDI << "disallow"
+                << " ";
         }
         else
         {
-          theDI << "auto" << " ";
+          theDI << "auto"
+                << " ";
         }
         continue;
       }
@@ -12098,7 +12105,7 @@ static int VManipulator(Draw_Interpretor& theDi, Standard_Integer theArgsNb, con
   TCollection_AsciiString                   aName;
   // parameters
   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1,
-                   toFollowDragging = -1, isZoomable = -1;
+                   toFollowDragging = -1, isZoomable = -1, isFlat = -1;
   Standard_Real                            aGap = -1.0, aSize = -1.0;
   NCollection_Sequence<ManipAxisModeOnOff> aParts;
   gp_XYZ aLocation(RealLast(), RealLast(), RealLast()), aVDir, anXDir;
@@ -12207,6 +12214,10 @@ static int VManipulator(Draw_Interpretor& theDi, Standard_Integer theArgsNb, con
     {
       isZoomable = Draw::ParseOnOffNoIterator(theArgsNb, theArgVec, anArgIter) ? 1 : 0;
     }
+    else if (anArg == "-flat")
+    {
+      isFlat = Draw::ParseOnOffNoIterator(theArgsNb, theArgVec, anArgIter) ? 1 : 0;
+    }
     //
     else if (anArg == "-adjustposition" || anArg == "-noadjustposition")
     {
@@ -12437,6 +12448,16 @@ static int VManipulator(Draw_Interpretor& theDi, Standard_Integer theArgsNb, con
       ViewerTest::GetAISContext()->Display(aManipulator, Standard_False);
     }
   }
+  if (isFlat != -1)
+  {
+    aManipulator->SetSkinMode((AIS_Manipulator::ManipulatorSkin)isFlat);
+
+    if (ViewerTest::GetAISContext()->IsDisplayed(aManipulator))
+    {
+      ViewerTest::GetAISContext()->Remove(aManipulator, Standard_False);
+      ViewerTest::GetAISContext()->Display(aManipulator, Standard_False);
+    }
+  }
 
   // ----------------------------------
   // detach existing manipulator object
@@ -14543,6 +14564,7 @@ Options:
  '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator
  '-size value'                     - set size of manipulator
  '-zoomable {0|1}'                 - set zoom persistence
+ '-flat {0|1}'                     - set flat skin mode",
 )" /* [vmanipulator] */);
 
   addCmd("vselprops", VSelectionProperties, /* [vselprops] */ R"(
diff --git a/tests/v3d/manipulator/flat b/tests/v3d/manipulator/flat
new file mode 100644
index 0000000000..cdaf74a0b2
--- /dev/null
+++ b/tests/v3d/manipulator/flat
@@ -0,0 +1,50 @@
+puts "==========================="
+puts "AIS_Manipulator - flat skin"
+puts "==========================="
+
+pload MODELING VISUALIZATION
+
+set anImage1 $imagedir/${casename}_1.png
+set anImage2 $imagedir/${casename}_2.png
+set anImage3 $imagedir/${casename}_3.png
+
+# create manipulated and helper objects
+box b 0 0 0 20 20 20
+
+# display manipulated objects
+vdisplay b -dispmode 1
+vright
+vrotate -mouseStart 400 200 -mouseMove 300 300
+vzoom 3
+
+# attach manipulator
+vmanipulator m -attach b -zoomable 1 -flat 1
+
+# test translation transform
+set mouse_pick {180 215}
+set mouse_drag {065 350}
+
+vmoveto 0 0
+vmoveto {*}$mouse_pick
+vdump $anImage1
+
+vselect {*}$mouse_pick
+vmanipulator m -startTransform {*}$mouse_pick
+vmanipulator m -transform {*}$mouse_drag
+vmanipulator m -stopTransform
+vselect 0 0
+vdump $anImage2
+
+# test plane dragging transform
+set mouse_pick {115 280}
+set mouse_drag {320 040}
+
+vmoveto 0 0
+vmoveto {*}$mouse_pick
+vdump $anImage3
+
+vselect {*}$mouse_pick
+vmanipulator m -startTransform {*}$mouse_pick
+vmanipulator m -transform {*}$mouse_drag
+vmanipulator m -stopTransform
+vselect 0 0
diff --git a/tests/vselect/bugs/bug32750 b/tests/vselect/bugs/bug32750
index 36cf6dbdc5..a982d6bd2d 100644
--- a/tests/vselect/bugs/bug32750
+++ b/tests/vselect/bugs/bug32750
@@ -18,8 +18,8 @@ vzoom 0.5
 vmanipulator m -attach b
 
 #set mouse coordinates for actions
-set mouse_pick {205 155}
-set mouse_drag1 {205 55}
+set mouse_pick {206 155}
+set mouse_drag1 {206 55}
 set mouse_pick2 {250 10}
 set mouse_pick3 {250 200}