0030930: Draw Harness, ViewerTest - add commands vlistcolors and vlistmaterials listi...
[occt.git] / src / ViewerTest / ViewerTest_ViewerCommands.cxx
index 0992d83..833ac10 100644 (file)
 // commercial license or contractual agreement.
 
 #include <OpenGl_GlCore20.hxx>
+#include <ViewerTest.hxx>
 
-#include <AIS_Animation.hxx>
 #include <AIS_AnimationCamera.hxx>
 #include <AIS_AnimationObject.hxx>
 #include <AIS_CameraFrustum.hxx>
 #include <AIS_ColorScale.hxx>
-#include <AIS_Manipulator.hxx>
-#include <AIS_RubberBand.hxx>
-#include <AIS_Shape.hxx>
-#include <AIS_InteractiveObject.hxx>
+#include <AIS_InteractiveContext.hxx>
 #include <AIS_ListOfInteractive.hxx>
 #include <AIS_ListIteratorOfListOfInteractive.hxx>
+#include <AIS_Manipulator.hxx>
+#include <AIS_ViewCube.hxx>
+#include <AIS_Shape.hxx>
+#include <Aspect_DisplayConnection.hxx>
 #include <Aspect_Grid.hxx>
-#include <DBRep.hxx>
+#include <Aspect_TypeOfLine.hxx>
+#include <Draw.hxx>
+#include <Draw_Appli.hxx>
+#include <Draw_Interpretor.hxx>
 #include <Draw_ProgressIndicator.hxx>
+#include <gp_Dir.hxx>
+#include <gp_Pln.hxx>
+#include <gp_Pnt.hxx>
 #include <Graphic3d_ArrayOfPolylines.hxx>
+#include <Graphic3d_AspectFillArea3d.hxx>
 #include <Graphic3d_AspectMarker3d.hxx>
-#include <Graphic3d_NameOfTextureEnv.hxx>
+#include <Graphic3d_ClipPlane.hxx>
+#include <Graphic3d_CubeMapPacked.hxx>
+#include <Graphic3d_CubeMapSeparate.hxx>
 #include <Graphic3d_GraduatedTrihedron.hxx>
+#include <Graphic3d_NameOfTextureEnv.hxx>
+#include <Graphic3d_Texture2Dmanual.hxx>
 #include <Graphic3d_TextureEnv.hxx>
 #include <Graphic3d_TextureParams.hxx>
 #include <Graphic3d_TypeOfTextureFilter.hxx>
-#include <Graphic3d_AspectFillArea3d.hxx>
-#include <ViewerTest.hxx>
-#include <ViewerTest_AutoUpdater.hxx>
-#include <ViewerTest_EventManager.hxx>
-#include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
-#include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
-#include <ViewerTest_CmdParser.hxx>
-#include <V3d_AmbientLight.hxx>
-#include <V3d_DirectionalLight.hxx>
-#include <V3d_PositionalLight.hxx>
-#include <V3d_SpotLight.hxx>
+#include <Image_AlienPixMap.hxx>
+#include <Image_Diff.hxx>
+#include <Image_VideoRecorder.hxx>
 #include <Message_ProgressSentry.hxx>
-#include <NCollection_DoubleMap.hxx>
+#include <NCollection_DataMap.hxx>
 #include <NCollection_List.hxx>
 #include <NCollection_Vector.hxx>
-#include <AIS_InteractiveContext.hxx>
-#include <Draw_Interpretor.hxx>
-#include <Draw.hxx>
-#include <Draw_Appli.hxx>
-#include <Image_AlienPixMap.hxx>
-#include <Image_VideoRecorder.hxx>
-#include <OpenGl_GraphicDriver.hxx>
+#include <OSD.hxx>
 #include <OSD_Timer.hxx>
-#include <TColStd_HSequenceOfAsciiString.hxx>
-#include <TColStd_SequenceOfInteger.hxx>
-#include <TColStd_HSequenceOfReal.hxx>
-#include <TColgp_Array1OfPnt2d.hxx>
-#include <TColStd_MapOfAsciiString.hxx>
-#include <Aspect_TypeOfLine.hxx>
-#include <Image_Diff.hxx>
-#include <Aspect_DisplayConnection.hxx>
-#include <gp_Pnt.hxx>
-#include <gp_Dir.hxx>
-#include <gp_Pln.hxx>
-#include <PrsMgr_PresentableObject.hxx>
-#include <Graphic3d_ClipPlane.hxx>
-#include <NCollection_DataMap.hxx>
-#include <Graphic3d_Texture2Dmanual.hxx>
+#include <OpenGl_GraphicDriver.hxx>
 #include <Prs3d_ShadingAspect.hxx>
 #include <Prs3d_Drawer.hxx>
 #include <Prs3d_LineAspect.hxx>
 #include <Prs3d_Root.hxx>
 #include <Prs3d_Text.hxx>
 #include <Select3D_SensitivePrimitiveArray.hxx>
+#include <TColStd_HSequenceOfAsciiString.hxx>
+#include <TColStd_SequenceOfInteger.hxx>
+#include <TColStd_HSequenceOfReal.hxx>
+#include <TColgp_Array1OfPnt2d.hxx>
+#include <TColStd_MapOfAsciiString.hxx>
+#include <ViewerTest_AutoUpdater.hxx>
+#include <ViewerTest_EventManager.hxx>
+#include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
+#include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
+#include <ViewerTest_CmdParser.hxx>
+#include <ViewerTest_V3dView.hxx>
+#include <V3d_AmbientLight.hxx>
+#include <V3d_DirectionalLight.hxx>
+#include <V3d_PositionalLight.hxx>
+#include <V3d_SpotLight.hxx>
 
-#ifdef _WIN32
-#undef DrawText
-#endif
+#include <tcl.h>
 
 #include <cstdlib>
 
   #include <tk.h>
 #endif
 
-// Auxiliary definitions
-static const char THE_KEY_DELETE = 127;
-static const char THE_KEY_ESCAPE = 27;
-
 //==============================================================================
 //  VIEWER GLOBAL VARIABLES
 //==============================================================================
@@ -114,10 +107,6 @@ Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
 
-extern int VErase (Draw_Interpretor& theDI,
-                   Standard_Integer  theArgNb,
-                   const char**      theArgVec);
-
 #if defined(_WIN32)
 static Handle(WNT_Window)& VT_GetWindow() {
   static Handle(WNT_Window) WNTWin;
@@ -130,7 +119,6 @@ static Handle(Cocoa_Window)& VT_GetWindow()
   return aWindow;
 }
 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
-extern void SetCocoaWindowTitle (const Handle(Cocoa_Window)& theWindow, Standard_CString theTitle);
 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
 
 #else
@@ -153,76 +141,6 @@ static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDis
   GetDisplayConnection() = theDisplayConnection;
 }
 
-#if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
-Aspect_Handle GetWindowHandle(const Handle(Aspect_Window)& theWindow)
-{
-  Aspect_Handle aWindowHandle = (Aspect_Handle)NULL;
-#if defined(_WIN32)
-  const Handle (WNT_Window) aWindow = Handle(WNT_Window)::DownCast (theWindow);
-  if (!aWindow.IsNull())
-    return aWindow->HWindow();
-#elif (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
-  const Handle (Xw_Window) aWindow = Handle(Xw_Window)::DownCast (theWindow);
-  if (!aWindow.IsNull())
-  return aWindow->XWindow();
-#endif
-  return aWindowHandle;
-}
-#endif
-
-//! Setting additional flag to store 2D mode of the View to avoid scene rotation by mouse/key events
-class ViewerTest_V3dView : public V3d_View
-{
-  DEFINE_STANDARD_RTTI_INLINE(ViewerTest_V3dView, V3d_View)
-public:
-  //! Initializes the view.
-  ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, const V3d_TypeOfView theType = V3d_ORTHOGRAPHIC,
-                      bool theIs2dMode = false)
-  : V3d_View (theViewer, theType), myIs2dMode (theIs2dMode) {}
-
-  //! Initializes the view by copying.
-  ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, const Handle(V3d_View)& theView)
-  : V3d_View (theViewer, theView), myIs2dMode (false)
-  {
-    if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (theView))
-    {
-      myIs2dMode = aV3dView->IsViewIn2DMode();
-    }
-  }
-
-  //! Returns true if 2D mode is set for the view
-  bool IsViewIn2DMode() const { return myIs2dMode; }
-
-  //! Sets 2D mode for the view
-  void SetView2DMode (bool the2dMode) { myIs2dMode = the2dMode; }
-
-public:
-
-  //! Returns true if active view in 2D mode.
-  static bool IsCurrentViewIn2DMode()
-  {
-    if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView()))
-    {
-      return aV3dView->IsViewIn2DMode();
-    }
-    return false;
-  }
-
-  //! Set if active view in 2D mode.
-  static void SetCurrentView2DMode (bool theIs2d)
-  {
-    if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView()))
-    {
-      aV3dView->SetView2DMode (theIs2d);
-    }
-  }
-
-private:
-
-  Standard_Boolean myIs2dMode; //!< 2D mode flag
-
-};
-
 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
@@ -242,179 +160,1341 @@ static struct
 //  EVENT GLOBAL VARIABLES
 //==============================================================================
 
-static int Start_Rot = 0;
-Standard_Boolean HasHlrOnBeforeRotation = Standard_False;
-int X_Motion = 0; // Current cursor position
-int Y_Motion = 0;
-int X_ButtonPress = 0; // Last ButtonPress position
-int Y_ButtonPress = 0;
-Standard_Boolean IsDragged = Standard_False;
-Standard_Boolean DragFirst = Standard_False;
 Standard_Boolean TheIsAnimating = Standard_False;
-Standard_Boolean Draw_ToExitOnCloseView = Standard_False;
-Standard_Boolean Draw_ToCloseViewOnEsc  = Standard_False;
 
-
-Standard_EXPORT const Handle(AIS_RubberBand)& GetRubberBand()
+namespace
 {
-  static Handle(AIS_RubberBand) aBand;
-  if (aBand.IsNull())
+
+  //! Checks if some set is a subset of other set
+  //! @tparam TheSuperSet the type of the superset
+  //! @tparam TheSubSet the type of the subset
+  //! @param theSuperSet the superset
+  //! @param theSubSet the subset to be checked
+  //! @return true if the superset includes subset, or false otherwise
+  template <typename TheSuperSet, typename TheSubSet>
+  static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
   {
-    aBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0);
-    aBand->SetDisplayMode (0);
+    return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
   }
-  return aBand;
-}
 
-typedef NCollection_Map<AIS_Manipulator*> ViewerTest_MapOfAISManipulators;
-
-Standard_EXPORT ViewerTest_MapOfAISManipulators& GetMapOfAISManipulators()
-{
-  static ViewerTest_MapOfAISManipulators aMap;
-  return aMap;
-}
-
-Standard_EXPORT Handle(AIS_Manipulator) GetActiveAISManipulator()
-{
-  ViewerTest_MapOfAISManipulators::Iterator anIt (GetMapOfAISManipulators());
-  for (; anIt.More(); anIt.Next())
+  //! A variable set of keys for command-line options.
+  //! It includes a set of mandatory keys and a set of all possible keys.
+  class CommandOptionKeyVariableSet
   {
-    if (anIt.Value()->HasActiveMode())
+  public:
+    //! Default constructor
+    CommandOptionKeyVariableSet()
     {
-      return anIt.Value();
     }
-  }
-  return NULL;
-}
-
-//==============================================================================
 
-#ifdef _WIN32
-static LRESULT WINAPI ViewerWindowProc(
-                                       HWND hwnd,
-                                       UINT uMsg,
-                                       WPARAM wParam,
-                                       LPARAM lParam );
-static LRESULT WINAPI AdvViewerWindowProc(
-  HWND hwnd,
-  UINT uMsg,
-  WPARAM wParam,
-  LPARAM lParam );
-#endif
+    //! Constructor
+    //! @param theMandatoryKeySet the set of the mandatory option keys
+    //! @param theAdditionalKeySet the set of additional options that could be omitted
+    CommandOptionKeyVariableSet (
+      const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
+      const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
+    : myMandatoryKeySet (theMandatoryKeySet)
+    {
+      std::set_union (theMandatoryKeySet.begin(),
+                      theMandatoryKeySet.end(),
+                      theAdditionalKeySet.begin(),
+                      theAdditionalKeySet.end(),
+                      std::inserter (myFullKeySet, myFullKeySet.begin()));
+    }
 
+    //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
+    //! and be contained in the full key set)
+    //! @param theCheckedKeySet the set of option keys to be checked
+    bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
+    {
+      return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
+    }
 
-//==============================================================================
-//function : WClass
-//purpose  :
-//==============================================================================
+  private:
+    //! A set of mandatory command-line option keys
+    ViewerTest_CommandOptionKeySet myMandatoryKeySet;
 
-const Handle(Standard_Transient)& ViewerTest::WClass()
-{
-  static Handle(Standard_Transient) theWClass;
-#if defined(_WIN32)
-  if (theWClass.IsNull())
-  {
-    theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
-                                CS_VREDRAW | CS_HREDRAW, 0, 0,
-                                ::LoadCursor (NULL, IDC_ARROW));
-  }
-#endif
-  return theWClass;
-}
+    //! A full set of command-line option keys (includes mandatory and additional option keys)
+    ViewerTest_CommandOptionKeySet myFullKeySet;
+  };
 
-//==============================================================================
-//function : CreateName
-//purpose  : Create numerical name for new object in theMap
-//==============================================================================
-template <typename ObjectType>
-TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
-                                    const TCollection_AsciiString& theDefaultString)
-{
-  if (theObjectMap.IsEmpty())
-    return theDefaultString + TCollection_AsciiString(1);
+  //! Gets some code by its name
+  //! @tparam TheCode the type of a code to be found
+  //! @param theCodeNameMap the map from code names to codes
+  //! @param theCodeName the name of a code to be found
+  //! @param theCode the code to be found
+  //! @return true if a code is found, or false otherwise
+  template <typename TheCode>
+  static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
+                                 TCollection_AsciiString                           theCodeName,
+                                 TheCode&                                          theCode)
+  {
+    theCodeName.LowerCase();
+    const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
+      theCodeName);
+    if (aCodeIterator == theCodeNameMap.end())
+    {
+      return false;
+    }
+    theCode = aCodeIterator->second;
+    return true;
+  }
+
+  // Defines possible commands related to background changing
+  enum BackgroundCommand
+  {
+    BackgroundCommand_Main,              //!< The main command that manages other commands through options
+    BackgroundCommand_Image,             //!< Sets an image as a background
+    BackgroundCommand_ImageMode,         //!< Changes a background image mode
+    BackgroundCommand_Gradient,          //!< Sets a gradient as a background
+    BackgroundCommand_GradientMode,      //!< Changes a background gradient mode
+    BackgroundCommand_Color,             //!< Fills background with a specified color
+    BackgroundCommand_Default            //!< Sets the background default color or gradient
+  };
 
-  Standard_Integer aNextKey = 1;
-  Standard_Boolean isFound = Standard_False;
-  while (!isFound)
+  //! Map from background command names to its codes
+  typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
+
+  //! Creates a map from background command names to its codes
+  //! @return a map from background command names to its codes
+  static BackgroundCommandNameMap createBackgroundCommandNameMap()
+  {
+    BackgroundCommandNameMap aBackgroundCommandNameMap;
+    aBackgroundCommandNameMap["vbackground"]      = BackgroundCommand_Main;
+    aBackgroundCommandNameMap["vsetbg"]           = BackgroundCommand_Image;
+    aBackgroundCommandNameMap["vsetbgmode"]       = BackgroundCommand_ImageMode;
+    aBackgroundCommandNameMap["vsetgradientbg"]   = BackgroundCommand_Gradient;
+    aBackgroundCommandNameMap["vsetgrbgmode"]     = BackgroundCommand_GradientMode;
+    aBackgroundCommandNameMap["vsetcolorbg"]      = BackgroundCommand_Color;
+    aBackgroundCommandNameMap["vsetdefaultbg"]    = BackgroundCommand_Default;
+    return aBackgroundCommandNameMap;
+  }
+
+  //! Gets a background command by its name
+  //! @param theBackgroundCommandName the name of the background command
+  //! @param theBackgroundCommand the background command to be found
+  //! @return true if a background command is found, or false otherwise
+  static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
+                                          BackgroundCommand&             theBackgroundCommand)
+  {
+    static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
+    return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
+  }
+
+  //! Map from background image fill method names to its codes
+  typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
+
+  //! Creates a map from background image fill method names to its codes
+  //! @return a map from background image fill method names to its codes
+  static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
+  {
+    BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
+    aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
+    aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
+    aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
+    aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
+    return aBackgroundImageFillMethodNameMap;
+  }
+
+  //! Gets a background image fill method by its name
+  //! @param theBackgroundImageFillMethodName the name of the background image fill method
+  //! @param theBackgroundImageFillMethod the background image fill method to be found
+  //! @return true if a background image fill method is found, or false otherwise
+  static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
+                                                  Aspect_FillMethod&             theBackgroundImageFillMethod)
+  {
+    static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
+      createBackgroundImageFillMethodNameMap();
+    return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
+                              theBackgroundImageFillMethodName,
+                              theBackgroundImageFillMethod);
+  }
+
+  //! Map from background gradient fill method names to its codes
+  typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
+
+  //! Creates a map from background gradient fill method names to its codes
+  //! @return a map from background gradient fill method names to its codes
+  static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
+  {
+    BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
+    aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
+    aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
+    aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
+    aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
+    aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
+    aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
+    aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
+    aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
+    aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
+    aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
+    aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
+    aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
+    aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
+    return aBackgroundGradientFillMethodNameMap;
+  }
+
+  //! Gets a gradient fill method by its name
+  //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
+  //! @param theBackgroundGradientFillMethod the gradient fill method to be found
+  //! @return true if a gradient fill method is found, or false otherwise
+  static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
+                                                     Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
+  {
+    static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
+      createBackgroundGradientFillMethodNameMap();
+    return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
+                              theBackgroundGradientFillMethodName,
+                              theBackgroundGradientFillMethod);
+  }
+
+  //! Changes the background in accordance with passed command line options
+  class BackgroundChanger
   {
-    TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
-    // Look for objects with default names
-    if (theObjectMap.IsBound1(aStringKey))
+  public:
+    //! Constructor. Prepares the command parser
+    BackgroundChanger()
     {
-      aNextKey++;
+      prepareCommandParser();
     }
-    else
-      isFound = Standard_True;
-  }
 
-  return theDefaultString + TCollection_AsciiString(aNextKey);
-}
+    //! Processes the command line and changes the background
+    //! @param theDrawInterpretor the interpreter of the Draw Harness application
+    //! @param theNumberOfCommandLineArguments the number of passed command line arguments
+    //! @param theCommandLineArguments the array of command line arguments
+    bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
+                             const Standard_Integer   theNumberOfCommandLineArguments,
+                             const char* const* const theCommandLineArguments)
+    {
+      const char* const aBackgroundCommandName = theCommandLineArguments[0];
+      BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
+      if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
+      {
+        return false;
+      }
+      addCommandDescription (aBackgroundCommand);
+      myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
+      return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
+    }
 
-//==============================================================================
-//structure : ViewerTest_Names
-//purpose   : Allow to operate with full view name: driverName/viewerName/viewName
-//==============================================================================
-struct ViewerTest_Names
-{
-private:
-  TCollection_AsciiString myDriverName;
-  TCollection_AsciiString myViewerName;
-  TCollection_AsciiString myViewName;
+  private:
+    //! The type of functions that are able to set gradient background filling
+    typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
+                                      const Quantity_Color& /* theColor2 */,
+                                      const Aspect_GradientFillMethod /* theGradientMode */);
 
-public:
+    //! The type of functions that are able to fill a background with a specific color
+    typedef void SetColorFunction (const Quantity_Color& /* theColor */);
 
-  const TCollection_AsciiString& GetDriverName () const
-  {
-    return myDriverName;
-  }
-  void SetDriverName (const TCollection_AsciiString& theDriverName)
-  {
-    myDriverName = theDriverName;
-  }
-  const TCollection_AsciiString& GetViewerName () const
-  {
-    return myViewerName;
-  }
-  void SetViewerName (const TCollection_AsciiString& theViewerName)
-  {
-    myViewerName = theViewerName;
-  }
-  const TCollection_AsciiString& GetViewName () const
-  {
-    return myViewName;
-  }
-  void SetViewName (const TCollection_AsciiString& theViewName)
-  {
-    myViewName = theViewName;
-  }
+    //! the command parser used to parse command line options and its arguments
+    ViewerTest_CmdParser myCommandParser;
 
-  //===========================================================================
-  //function : Constructor for ViewerTest_Names
-  //purpose  : Get view, viewer, driver names from custom string
-  //===========================================================================
+    //! the option key for the command that sets an image as a background
+    ViewerTest_CommandOptionKey myImageOptionKey;
 
-  ViewerTest_Names (const TCollection_AsciiString& theInputString)
-  {
-    TCollection_AsciiString aName(theInputString);
-    if (theInputString.IsEmpty())
-    {
-      // Get current configuration
-      if (ViewerTest_myDrivers.IsEmpty())
-        myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
-          (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
-      else
-        myDriverName = ViewerTest_myDrivers.Find2
-        (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
+    //! the option key for the command that sets a background image fill type
+    ViewerTest_CommandOptionKey myImageModeOptionKey;
 
-      if(ViewerTest_myContexts.IsEmpty())
-      {
-        myViewerName = CreateName <Handle(AIS_InteractiveContext)>
-          (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
-      }
-      else
-      {
-        myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
-      }
+    //! the option key for the command that sets a gradient filling for the background
+    ViewerTest_CommandOptionKey myGradientOptionKey;
+
+    //! the option key for the command that sets a background gradient filling method
+    ViewerTest_CommandOptionKey myGradientModeOptionKey;
+
+    //! the option key for the command that fills background with a specific color
+    ViewerTest_CommandOptionKey myColorOptionKey;
+
+    //! the option key for the command that sets default background gradient or color
+    ViewerTest_CommandOptionKey myDefaultOptionKey;
+
+    //! the option key for the command that sets an environment cubemap as a background
+    ViewerTest_CommandOptionKey myCubeMapOptionKey;
+
+    //! the option key for the command that defines order of tiles in one image packed cubemap
+    ViewerTest_CommandOptionKey myCubeMapOrderOptionKey;
+
+    //! the option key for the command that sets inversion of Z axis for background cubemap
+    ViewerTest_CommandOptionKey myCubeMapInvertedZOptionKey;
+
+    //! the variable set of options that are allowed for the old scenario (without any option passed)
+    CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
+
+    //! the variable set of options that are allowed for setting an environment cubemap as background
+    CommandOptionKeyVariableSet myCubeMapOptionVariableSet;
+
+    //! the variable set of options that are allowed for setting an image as a background
+    CommandOptionKeyVariableSet myImageOptionVariableSet;
+
+    //! the variable set of options that are allowed for setting a background image fill type
+    CommandOptionKeyVariableSet myImageModeOptionVariableSet;
+
+    //! the variable set of options that are allowed for setting a gradient filling for the background
+    CommandOptionKeyVariableSet myGradientOptionVariableSet;
+
+    //! the variable set of options that are allowed for setting a background gradient filling method
+    CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
+
+    //! the variable set of options that are allowed for filling a background with a specific color
+    CommandOptionKeyVariableSet myColorOptionVariableSet;
+
+    //! the variable set of options that are allowed for setting a default background gradient
+    CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
+
+    //! the variable set of options that are allowed for setting a default background color
+    CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
+
+    //! the variable set of options that are allowed for printing help
+    CommandOptionKeyVariableSet myHelpOptionVariableSet;
+
+    //! Adds options to command parser
+    void addOptionsToCommandParser()
+    {
+      myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
+                                                    "filename of image used as background");
+      myImageModeOptionKey = myCommandParser.AddOption (
+        "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
+      myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
+                                                       "sets background gradient starting and ending colors");
+      myGradientModeOptionKey =
+        myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
+                                   "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
+                                   "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
+      myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
+      myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
+
+      myCubeMapOptionKey           = myCommandParser.AddOption ("cubemap|cmap|cm", "background cubemap");
+      myCubeMapOrderOptionKey      = myCommandParser.AddOption ("order|o", "order of sides in one image packed cubemap");
+      myCubeMapInvertedZOptionKey = myCommandParser.AddOption (
+        "invertedz|invz|iz", "whether Z axis is inverted or not during background cubemap rendering");
+    }
+
+    //! Creates option sets used to determine if a passed option set is valid or not
+    void createOptionSets()
+    {
+      ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
+      anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
+      myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
+
+      ViewerTest_CommandOptionKeySet aCubeMapOptionSet;
+      aCubeMapOptionSet.insert (myCubeMapOptionKey);
+      ViewerTest_CommandOptionKeySet aCubeMapAdditionalOptionKeySet;
+      aCubeMapAdditionalOptionKeySet.insert (myCubeMapInvertedZOptionKey);
+      aCubeMapAdditionalOptionKeySet.insert (myCubeMapOrderOptionKey);
+      myCubeMapOptionVariableSet     = CommandOptionKeyVariableSet (aCubeMapOptionSet, aCubeMapAdditionalOptionKeySet);
+
+      ViewerTest_CommandOptionKeySet anImageOptionSet;
+      anImageOptionSet.insert (myImageOptionKey);
+      ViewerTest_CommandOptionKeySet anImageModeOptionSet;
+      anImageModeOptionSet.insert (myImageModeOptionKey);
+      myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
+      myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
+
+      ViewerTest_CommandOptionKeySet aGradientOptionSet;
+      aGradientOptionSet.insert (myGradientOptionKey);
+      ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
+      aGradientModeOptionSet.insert (myGradientModeOptionKey);
+      myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
+      myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
+
+      ViewerTest_CommandOptionKeySet aColorOptionSet;
+      aColorOptionSet.insert (myColorOptionKey);
+      myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
+
+      aGradientOptionSet.insert (myDefaultOptionKey);
+      myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
+      aColorOptionSet.insert (myDefaultOptionKey);
+      myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
+
+      ViewerTest_CommandOptionKeySet aHelpOptionSet;
+      aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
+      myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
+    }
+
+    //! Prepares the command parser. Adds options and creates option sets used to determine
+    //! if a passed option set is valid or not
+    void prepareCommandParser()
+    {
+      addOptionsToCommandParser();
+      createOptionSets();
+    }
+
+    //! Adds a command description to the command parser
+    //! @param theBackgroundCommand the key of the command which description is added to the command parser
+    void addCommandDescription (const BackgroundCommand theBackgroundCommand)
+    {
+      std::string aDescription;
+      bool        isMainCommand = false;
+      switch (theBackgroundCommand)
+      {
+        case BackgroundCommand_Main:
+          aDescription  = "Command: vbackground (changes background or some background settings)";
+          isMainCommand = true;
+          break;
+        case BackgroundCommand_Image:
+          aDescription = "Command: vsetbg (loads image as a background)";
+          break;
+        case BackgroundCommand_ImageMode:
+          aDescription = "Command: vsetbgmode (changes background fill type)";
+          break;
+        case BackgroundCommand_Gradient:
+          aDescription = "Command: vsetgradientbg (mounts gradient background)";
+          break;
+        case BackgroundCommand_GradientMode:
+          aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
+          break;
+        case BackgroundCommand_Color:
+          aDescription = "Command: vsetcolorbg (sets color background)";
+          break;
+        case BackgroundCommand_Default:
+          aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
+          break;
+        default:
+          return;
+      }
+      if (!isMainCommand)
+      {
+        aDescription += "\nThis command is obsolete. Use vbackground instead.";
+      }
+      myCommandParser.SetDescription (aDescription);
+    }
+
+    //! Check if a viewer is needed to be initialized
+    //! @param theBackgroundCommand the key of the command that changes the background
+    //! @return true if processing was successful, or false otherwise
+    bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
+    {
+      const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
+      const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
+      const bool                           aViewerIsNotNeeded =
+        (theBackgroundCommand == BackgroundCommand_Default)
+        || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
+        || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
+        || myHelpOptionVariableSet.IsInSet (aUsedOptions);
+      return !aViewerIsNotNeeded;
+    }
+
+    //! Check if a viewer is initialized
+    //! @param theBackgroundCommandName the name of the command that changes the background
+    //! @param theDrawInterpretor the interpreter of the Draw Harness application
+    //! @return true if a viewer is initialized, or false otherwise
+    static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
+                                          Draw_Interpretor& theDrawInterpretor)
+    {
+      const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
+      if (anAISContext.IsNull())
+      {
+        theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
+        return false;
+      }
+      return true;
+    }
+
+    //! Processes command options
+    //! @param theBackgroundCommandName the name of the command that changes the background
+    //! @param theBackgroundCommand the key of the command that changes the background
+    //! @param theDrawInterpretor the interpreter of the Draw Harness application
+    //! @return true if processing was successful, or false otherwise
+    bool processCommandOptions (const char* const       theBackgroundCommandName,
+                                const BackgroundCommand theBackgroundCommand,
+                                Draw_Interpretor&       theDrawInterpretor) const
+    {
+      if (myCommandParser.HasNoOption())
+      {
+        return printHelp (theBackgroundCommandName, theDrawInterpretor);
+      }
+      if (checkViewerIsNeeded (theBackgroundCommand)
+          && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
+      {
+        return false;
+      }
+      if (myCommandParser.HasOnlyUnnamedOption())
+      {
+        return processUnnamedOption (theBackgroundCommand);
+      }
+      return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
+    }
+
+    //! Processes the unnamed option
+    //! @param theBackgroundCommand the key of the command that changes the background
+    //! @return true if processing was successful, or false otherwise
+    bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
+    {
+      switch (theBackgroundCommand)
+      {
+        case BackgroundCommand_Main:
+          return false;
+        case BackgroundCommand_Image:
+          return processImageUnnamedOption();
+        case BackgroundCommand_ImageMode:
+          return processImageModeUnnamedOption();
+        case BackgroundCommand_Gradient:
+          return processGradientUnnamedOption();
+        case BackgroundCommand_GradientMode:
+          return processGradientModeUnnamedOption();
+        case BackgroundCommand_Color:
+          return processColorUnnamedOption();
+        case BackgroundCommand_Default:
+          return processDefaultUnnamedOption();
+        default:
+          return false;
+      }
+    }
+
+    //! Processes the image unnamed option
+    //! @return true if processing was successful, or false otherwise
+    bool processImageUnnamedOption() const
+    {
+      const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
+        ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
+      if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
+      {
+        return false;
+      }
+      std::string anImageFileName;
+      if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
+      {
+        return false;
+      }
+      Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
+      if (aNumberOfImageUnnamedOptionArguments == 2)
+      {
+        std::string anImageModeString;
+        if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
+        {
+          return false;
+        }
+        if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
+        {
+          return false;
+        }
+      }
+      setImage (anImageFileName.c_str(), anImageMode);
+      return true;
+    }
+
+    //! Processes the image mode unnamed option
+    //! @return true if processing was successful, or false otherwise
+    bool processImageModeUnnamedOption() const
+    {
+      return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
+    }
+
+    //! Processes the gradient unnamed option
+    //! @param theSetGradient the function used to set a background gradient filling
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
+    {
+      const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
+        ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
+      if (aNumberOfGradientUnnamedOptionArguments < 2)
+      {
+        return false;
+      }
+
+      Standard_Integer anArgumentIndex = 0;
+      Quantity_Color   aColor1;
+      if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
+      {
+        return false;
+      }
+      if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
+      {
+        return false;
+      }
+
+      Quantity_Color aColor2;
+      if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
+      {
+        return false;
+      }
+      if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
+      {
+        return false;
+      }
+
+      Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
+      if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
+      {
+        std::string anGradientModeString;
+
+        if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
+                                  anArgumentIndex,
+                                  anGradientModeString))
+        {
+          return false;
+        }
+        if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
+        {
+          return false;
+        }
+        ++anArgumentIndex;
+      }
+      if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
+      {
+        return false;
+      }
+      theSetGradient (aColor1, aColor2, aGradientMode);
+      return true;
+    }
+
+    //! Processes the gradient mode unnamed option
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientModeUnnamedOption() const
+    {
+      return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
+    }
+
+    //! Processes the color unnamed option
+    //! @param theSetColor the function used to set a background color
+    //! @return true if processing was successful, or false otherwise
+    bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
+    {
+      return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
+    }
+
+    //! Processes the default back unnamed option
+    //! @return true if processing was successful, or false otherwise
+    bool processDefaultUnnamedOption() const
+    {
+      if (processGradientUnnamedOption (setDefaultGradient))
+      {
+        return true;
+      }
+      return processColorUnnamedOption (setDefaultColor);
+    }
+
+    //! Processes named options
+    //! @param theBackgroundCommandName the name of the command that changes the background
+    //! @param theBackgroundCommand the key of the command that changes the background
+    //! @param theDrawInterpretor the interpreter of the Draw Harness application
+    //! @return true if processing was successful, or false otherwise
+    bool processNamedOptions (const char* const       theBackgroundCommandName,
+                              const BackgroundCommand theBackgroundCommand,
+                              Draw_Interpretor&       theDrawInterpretor) const
+    {
+      const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
+      const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
+      if (myCubeMapOptionVariableSet.IsInSet (aUsedOptions) && isMain)
+      {
+        return processCubeMapOptionSet();
+      }
+      if (myImageOptionVariableSet.IsInSet (aUsedOptions)
+          && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
+      {
+        return processImageOptionSet();
+      }
+      if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
+          && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
+      {
+        return processImageModeOptionSet();
+      }
+      if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
+          && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
+      {
+        return processGradientOptionSet();
+      }
+      if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
+          && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
+      {
+        return processGradientModeOptionSet();
+      }
+      if (myColorOptionVariableSet.IsInSet (aUsedOptions)
+          && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
+      {
+        return processColorOptionSet();
+      }
+      if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
+          || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
+              && (theBackgroundCommand == BackgroundCommand_Default)))
+      {
+        return processDefaultGradientOptionSet();
+      }
+      if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
+          || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
+      {
+        return processDefaultColorOptionSet();
+      }
+      if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
+      {
+        return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
+      }
+      return false;
+    }
+
+    //! Process the cubemap option set in named and unnamed case.
+    //! @return true if processing was successful, or false otherwise
+    bool processCubeMapOptionSet() const
+    {
+      NCollection_Array1<TCollection_AsciiString> aFilePaths;
+
+      if (!processCubeMapOptions (aFilePaths))
+      {
+        return false;
+      }
+
+      Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
+
+      if (myCommandParser.HasOption (myCubeMapOrderOptionKey))
+      {
+        if (!processCubeMapOrderOptions (anOrder))
+        {
+          return false;
+        }
+      }
+
+      bool aZIsInverted = false;
+      if (myCommandParser.HasOption (myCubeMapInvertedZOptionKey))
+      {
+        if (!processCubeMapInvertedZOptionSet())
+        {
+          return false;
+        }
+        aZIsInverted = true;
+      }
+
+      setCubeMap (aFilePaths, anOrder.Validated(), aZIsInverted);
+      return true;
+    }
+
+    //! Processes the image option set
+    //! @return true if processing was successful, or false otherwise
+    bool processImageOptionSet() const
+    {
+      std::string anImageFileName;
+      if (!processImageOption (anImageFileName))
+      {
+        return false;
+      }
+      Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
+      if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
+      {
+        return false;
+      }
+      setImage (anImageFileName.c_str(), anImageMode);
+      return true;
+    }
+
+    //! Processes the image mode option set
+    //! @return true if processing was successful, or false otherwise
+    bool processImageModeOptionSet() const
+    {
+      return processImageModeOptionSet (myImageModeOptionKey);
+    }
+
+    //! Processes the image mode option set
+    //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
+    //! @return true if processing was successful, or false otherwise
+    bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
+    {
+      Aspect_FillMethod anImageMode = Aspect_FM_NONE;
+      if (!processImageModeOption (theImageModeOptionKey, anImageMode))
+      {
+        return false;
+      }
+      setImageMode (anImageMode);
+      return true;
+    }
+
+    //! Processes the gradient option set
+    //! @param theSetGradient the function used to set a background gradient filling
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
+    {
+      Quantity_Color aColor1;
+      Quantity_Color aColor2;
+      if (!processGradientOption (aColor1, aColor2))
+      {
+        return false;
+      }
+      Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
+      if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
+      {
+        return false;
+      }
+      theSetGradient (aColor1, aColor2, aGradientMode);
+      return true;
+    }
+
+    //! Processes the gradient mode option set
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientModeOptionSet() const
+    {
+      return processGradientModeOptionSet (myGradientModeOptionKey);
+    }
+
+    //! Processes the gradient mode option set
+    //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
+    {
+      Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
+      if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
+      {
+        return false;
+      }
+      setGradientMode (aGradientMode);
+      return true;
+    }
+
+    //! Processes the color option set
+    //! @param theSetColor the function used to set a background color
+    //! @return true if processing was successful, or false otherwise
+    bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
+    {
+      return processColorOptionSet (myColorOptionKey, theSetColor);
+    }
+
+    //! Processes the default color option set
+    //! @return true if processing was successful, or false otherwise
+    bool processDefaultGradientOptionSet() const
+    {
+      return processGradientOptionSet (setDefaultGradient);
+    }
+
+    //! Processes the default gradient option set
+    //! @return true if processing was successful, or false otherwise
+    bool processDefaultColorOptionSet() const
+    {
+      return processColorOptionSet (setDefaultColor);
+    }
+
+    //! Processes the color option set
+    //! @param theColorOptionKey the key of the option that is interpreted as a color option
+    //! @param theSetColor the function used to set a background color
+    //! @return true if processing was successful, or false otherwise
+    bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
+                                SetColorFunction* const           theSetColor = setColor) const
+    {
+      Quantity_Color aColor;
+      if (!processColorOption (theColorOptionKey, aColor))
+      {
+        return false;
+      }
+      theSetColor (aColor);
+      return true;
+    }
+
+    //! Processes the help option set
+    //! @param theBackgroundCommandName the name of the command that changes the background
+    //! @param theDrawInterpretor the interpreter of the Draw Harness application
+    //! @return true if processing was successful, or false otherwise
+    bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
+    {
+      const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
+        ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
+      if (aNumberOfHelpOptionArguments != 0)
+      {
+        return false;
+      }
+      return printHelp (theBackgroundCommandName, theDrawInterpretor);
+    }
+
+    //! Processes the cubemap option
+    //! @param theFilePaths the array of filenames of cubemap sides
+    //! @return true if processing was successful, or false otherwise
+    bool processCubeMapOptions (NCollection_Array1<TCollection_AsciiString> &theFilePaths) const
+    {
+      const Standard_Integer aNumberOfCubeMapOptionArguments = myCommandParser.GetNumberOfOptionArguments (myCubeMapOptionKey);
+
+      if (aNumberOfCubeMapOptionArguments != 1
+       && aNumberOfCubeMapOptionArguments != 6)
+      {
+        return false;
+      }
+
+      theFilePaths.Resize(0, aNumberOfCubeMapOptionArguments - 1, Standard_False);
+
+      for (int i = 0; i < aNumberOfCubeMapOptionArguments; ++i)
+      {
+        std::string aCubeMapFileName;
+        if (!myCommandParser.Arg (myCubeMapOptionKey, i, aCubeMapFileName))
+        {
+          return false;
+        }
+        theFilePaths[i] = aCubeMapFileName.c_str();
+      }
+
+      return true;
+    }
+
+    //! Processes the cubemap option
+    //! @param theIsNeededToRedraw defines need of redraw after option's processing 
+    //! @return true if processing was successful, or false otherwise
+    bool processCubeMapInvertedZOptionSet () const
+    {
+      const Standard_Integer aNumberOfCubeMapZInversionOptionArguments =
+        myCommandParser.GetNumberOfOptionArguments (myCubeMapInvertedZOptionKey);
+
+      if (aNumberOfCubeMapZInversionOptionArguments != 0)
+      {
+        return false;
+      }
+
+      return true;
+    }
+
+    //! Processes the tiles order option
+    //! @param theOrder the array of indexes if cubemap sides in tile grid
+    //! @return true if processing was successful, or false otherwise
+    bool processCubeMapOrderOptions (Graphic3d_CubeMapOrder& theOrder) const
+    {
+      const Standard_Integer aNumberOfCubeMapOrderOptionArguments = myCommandParser.GetNumberOfOptionArguments(
+        myCubeMapOrderOptionKey);
+
+      if (aNumberOfCubeMapOrderOptionArguments != 6)
+      {
+        return false;
+      }
+
+
+      for (unsigned int i = 0; i < 6; ++i)
+      {
+        std::string anOrderItem;
+        if (!myCommandParser.Arg (myCubeMapOrderOptionKey, i, anOrderItem)) 
+        {
+          return false;
+        }
+
+        theOrder.Set (Graphic3d_CubeMapSide (i),
+                      static_cast<unsigned char> (Draw::Atoi (anOrderItem.c_str())));
+      }
+
+      return theOrder.IsValid();
+    }
+
+    //! Processes the image option
+    //! @param theImageFileName the filename of the image to be used as a background
+    //! @return true if processing was successful, or false otherwise
+    bool processImageOption (std::string& theImageFileName) const
+    {
+      const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
+        myImageOptionKey);
+      if (aNumberOfImageOptionArguments != 1)
+      {
+        return false;
+      }
+      std::string anImageFileName;
+      if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
+      {
+        return false;
+      }
+      theImageFileName = anImageFileName;
+      return true;
+    }
+
+    //! Processes the image mode option
+    //! @param theImageMode the fill type used for a background image
+    //! @return true if processing was successful, or false otherwise
+    bool processImageModeOption (Aspect_FillMethod& theImageMode) const
+    {
+      return processImageModeOption (myImageModeOptionKey, theImageMode);
+    }
+
+    //! Processes the image mode option
+    //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
+    //! @param theImageMode the fill type used for a background image
+    //! @return true if processing was successful, or false otherwise
+    bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
+                                 Aspect_FillMethod&                theImageMode) const
+    {
+      return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
+    }
+
+    //! Processes the gradient option
+    //! @param theColor1 the gradient starting color
+    //! @param theColor2 the gradient ending color
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
+    {
+      Standard_Integer anArgumentIndex = 0;
+      Quantity_Color   aColor1;
+      if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
+      {
+        return false;
+      }
+      Quantity_Color aColor2;
+      if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
+      {
+        return false;
+      }
+      const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
+        myGradientOptionKey);
+      if (anArgumentIndex != aNumberOfGradientOptionArguments)
+      {
+        return false;
+      }
+      theColor1 = aColor1;
+      theColor2 = aColor2;
+      return true;
+    }
+
+    //! Processes the gradient mode option
+    //! @param theGradientMode the fill method used for a background gradient filling
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
+    {
+      return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
+    }
+
+    //! Processes the gradient mode option
+    //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
+    //! @param theGradientMode the fill method used for a background gradient filling
+    //! @return true if processing was successful, or false otherwise
+    bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
+                                    Aspect_GradientFillMethod&        theGradientMode) const
+    {
+      return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
+    }
+
+    //! Processes some mode option
+    //! @tparam TheMode the type of a mode to be processed
+    //! @param theModeOptionKey the key of the option that is interpreted as a mode option
+    //! @param theMode a mode to be processed
+    //! @return true if processing was successful, or false otherwise
+    template <typename TheMode>
+    bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
+                            bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
+                                                            TheMode& /* theMode */),
+                            TheMode& theMode) const
+    {
+      const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
+        theModeOptionKey);
+      if (aNumberOfModeOptionArguments != 1)
+      {
+        return false;
+      }
+      std::string aModeString;
+      if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
+      {
+        return false;
+      }
+      TheMode aMode = TheMode();
+      if (!theGetModeByName (aModeString.c_str(), aMode))
+      {
+        return false;
+      }
+      theMode = aMode;
+      return true;
+    }
+
+    //! Processes the color option
+    //! @param theColor a color used for filling a background
+    //! @return true if processing was successful, or false otherwise
+    bool processColorOption (Quantity_Color& theColor) const
+    {
+      return processColorOption (myColorOptionKey, theColor);
+    }
+
+    //! Processes the color option
+    //! @param theColorOptionKey the key of the option that is interpreted as a color option
+    //! @param theColor a color used for filling a background
+    //! @return true if processing was successful, or false otherwise
+    bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
+    {
+      Standard_Integer anArgumentIndex = 0;
+      Quantity_Color   aColor;
+      if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
+      {
+        return false;
+      }
+      const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
+        theColorOptionKey);
+      if (anArgumentIndex != aNumberOfColorOptionArguments)
+      {
+        return false;
+      }
+      theColor = aColor;
+      return true;
+    }
+
+    //! Prints helping message
+    //! @param theBackgroundCommandName the name of the command that changes the background
+    //! @param theDrawInterpretor the interpreter of the Draw Harness application
+    //! @return true if printing was successful, or false otherwise
+    static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
+    {
+      return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
+    }
+
+    //! Sets the cubemap as a background
+    //! @param theFileNames the array of filenames of packed or multifile cubemap
+    //! @param theOrder array of cubemap sides indexes mapping them from tiles in packed cubemap
+    static void setCubeMap (const NCollection_Array1<TCollection_AsciiString>& theFileNames,
+                            const Graphic3d_ValidatedCubeMapOrder              theOrder = Graphic3d_CubeMapOrder::Default(),
+                            bool                                               theZIsInverted = false)
+    {
+      const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
+      Handle(Graphic3d_CubeMap) aCubeMap;
+
+      if (theFileNames.Size() == 1)
+        aCubeMap = new Graphic3d_CubeMapPacked(theFileNames[0], theOrder);
+      else
+        aCubeMap = new Graphic3d_CubeMapSeparate(theFileNames);
+
+      aCubeMap->SetZInversion (theZIsInverted);
+
+      aCubeMap->GetParams()->SetFilter(Graphic3d_TOTF_BILINEAR);
+      aCubeMap->GetParams()->SetRepeat(Standard_False);
+      aCubeMap->GetParams()->SetTextureUnit(Graphic3d_TextureUnit_EnvMap);
+
+      aCurrentView->SetBackgroundCubeMap (aCubeMap, Standard_True);
+    }
+
+    //! Sets the image as a background
+    //! @param theImageFileName the filename of the image to be used as a background
+    //! @param theImageMode the fill type used for a background image
+    static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
+    {
+      const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
+      aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
+    }
+
+    //! Sets the fill type used for a background image
+    //! @param theImageMode the fill type used for a background image
+    static void setImageMode (const Aspect_FillMethod theImageMode)
+    {
+      const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
+      aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
+    }
+
+    //! Sets the gradient filling for a background
+    //! @param theColor1 the gradient starting color
+    //! @param theColor2 the gradient ending color
+    //! @param theGradientMode the fill method used for a background gradient filling
+    static void setGradient (const Quantity_Color&           theColor1,
+                             const Quantity_Color&           theColor2,
+                             const Aspect_GradientFillMethod theGradientMode)
+    {
+      const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
+      aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
+    }
+
+    //! Sets the fill method used for a background gradient filling
+    //! @param theGradientMode the fill method used for a background gradient filling
+    static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
+    {
+      const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
+      aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
+    }
+
+    //! Sets the color used for filling a background
+    //! @param theColor the color used for filling a background
+    static void setColor (const Quantity_Color& theColor)
+    {
+      const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
+      aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
+      aCurrentView->SetBackgroundColor (theColor);
+      aCurrentView->Update();
+    }
+
+    //! Sets the gradient filling for a background in a default viewer
+    //! @param theColor1 the gradient starting color
+    //! @param theColor2 the gradient ending color
+    //! @param theGradientMode the fill method used for a background gradient filling
+    static void setDefaultGradient (const Quantity_Color&           theColor1,
+                                    const Quantity_Color&           theColor2,
+                                    const Aspect_GradientFillMethod theGradientMode)
+    {
+      ViewerTest_DefaultBackground.GradientColor1 = theColor1;
+      ViewerTest_DefaultBackground.GradientColor2 = theColor2;
+      ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
+      setDefaultGradient();
+    }
+
+    //! Sets the color used for filling a background in a default viewer
+    //! @param theColor the color used for filling a background
+    static void setDefaultColor (const Quantity_Color& theColor)
+    {
+      ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
+      ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
+      ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
+      ViewerTest_DefaultBackground.FlatColor      = theColor;
+      setDefaultGradient();
+      setDefaultColor();
+    }
+
+    //! Sets the gradient filling for a background in a default viewer.
+    //! Gradient settings are taken from ViewerTest_DefaultBackground structure
+    static void setDefaultGradient()
+    {
+      for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
+             anInteractiveContextIterator (ViewerTest_myContexts);
+           anInteractiveContextIterator.More();
+           anInteractiveContextIterator.Next())
+      {
+        const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
+        aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
+                                             ViewerTest_DefaultBackground.GradientColor2,
+                                             ViewerTest_DefaultBackground.FillMethod);
+      }
+    }
+
+    //! Sets the color used for filling a background in a default viewer.
+    //! The color value is taken from ViewerTest_DefaultBackground structure
+    static void setDefaultColor()
+    {
+      for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
+             anInteractiveContextIterator (ViewerTest_myContexts);
+           anInteractiveContextIterator.More();
+           anInteractiveContextIterator.Next())
+      {
+        const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
+        aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
+      }
+    }
+  };
+
+} // namespace
+
+typedef NCollection_Map<AIS_Manipulator*> ViewerTest_MapOfAISManipulators;
+
+Standard_EXPORT ViewerTest_MapOfAISManipulators& GetMapOfAISManipulators()
+{
+  static ViewerTest_MapOfAISManipulators aMap;
+  return aMap;
+}
+
+Standard_EXPORT Handle(AIS_Manipulator) GetActiveAISManipulator()
+{
+  ViewerTest_MapOfAISManipulators::Iterator anIt (GetMapOfAISManipulators());
+  for (; anIt.More(); anIt.Next())
+  {
+    if (anIt.Value()->HasActiveMode())
+    {
+      return anIt.Value();
+    }
+  }
+  return NULL;
+}
+
+//==============================================================================
+
+#ifdef _WIN32
+static LRESULT WINAPI ViewerWindowProc(
+                                       HWND hwnd,
+                                       UINT uMsg,
+                                       WPARAM wParam,
+                                       LPARAM lParam );
+static LRESULT WINAPI AdvViewerWindowProc(
+  HWND hwnd,
+  UINT uMsg,
+  WPARAM wParam,
+  LPARAM lParam );
+#endif
+
+
+//==============================================================================
+//function : WClass
+//purpose  :
+//==============================================================================
+
+const Handle(Standard_Transient)& ViewerTest::WClass()
+{
+  static Handle(Standard_Transient) theWClass;
+#if defined(_WIN32)
+  if (theWClass.IsNull())
+  {
+    theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
+                                CS_VREDRAW | CS_HREDRAW, 0, 0,
+                                ::LoadCursor (NULL, IDC_ARROW));
+  }
+#endif
+  return theWClass;
+}
+
+//==============================================================================
+//function : CreateName
+//purpose  : Create numerical name for new object in theMap
+//==============================================================================
+template <typename ObjectType>
+TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
+                                    const TCollection_AsciiString& theDefaultString)
+{
+  if (theObjectMap.IsEmpty())
+    return theDefaultString + TCollection_AsciiString(1);
+
+  Standard_Integer aNextKey = 1;
+  Standard_Boolean isFound = Standard_False;
+  while (!isFound)
+  {
+    TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
+    // Look for objects with default names
+    if (theObjectMap.IsBound1(aStringKey))
+    {
+      aNextKey++;
+    }
+    else
+      isFound = Standard_True;
+  }
+
+  return theDefaultString + TCollection_AsciiString(aNextKey);
+}
+
+//==============================================================================
+//structure : ViewerTest_Names
+//purpose   : Allow to operate with full view name: driverName/viewerName/viewName
+//==============================================================================
+struct ViewerTest_Names
+{
+private:
+  TCollection_AsciiString myDriverName;
+  TCollection_AsciiString myViewerName;
+  TCollection_AsciiString myViewName;
+
+public:
+
+  const TCollection_AsciiString& GetDriverName () const
+  {
+    return myDriverName;
+  }
+  void SetDriverName (const TCollection_AsciiString& theDriverName)
+  {
+    myDriverName = theDriverName;
+  }
+  const TCollection_AsciiString& GetViewerName () const
+  {
+    return myViewerName;
+  }
+  void SetViewerName (const TCollection_AsciiString& theViewerName)
+  {
+    myViewerName = theViewerName;
+  }
+  const TCollection_AsciiString& GetViewName () const
+  {
+    return myViewName;
+  }
+  void SetViewName (const TCollection_AsciiString& theViewName)
+  {
+    myViewName = theViewName;
+  }
+
+  //===========================================================================
+  //function : Constructor for ViewerTest_Names
+  //purpose  : Get view, viewer, driver names from custom string
+  //===========================================================================
+
+  ViewerTest_Names (const TCollection_AsciiString& theInputString)
+  {
+    TCollection_AsciiString aName(theInputString);
+    if (theInputString.IsEmpty())
+    {
+      // Get current configuration
+      if (ViewerTest_myDrivers.IsEmpty())
+        myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
+          (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
+      else
+        myDriverName = ViewerTest_myDrivers.Find2
+        (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
+
+      if(ViewerTest_myContexts.IsEmpty())
+      {
+        myViewerName = CreateName <Handle(AIS_InteractiveContext)>
+          (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
+      }
+      else
+      {
+        myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
+      }
 
       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
     }
@@ -503,30 +1583,6 @@ Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theVie
   return anAISContext;
 }
 
-
-//==============================================================================
-//function : SetWindowTitle
-//purpose  : Set window title
-//==============================================================================
-
-void SetWindowTitle (const Handle(Aspect_Window)& theWindow,
-                     Standard_CString theTitle)
-{
-#if defined(_WIN32)
-  const TCollection_ExtendedString theTitleW (theTitle);
-  SetWindowTextW ((HWND )Handle(WNT_Window)::DownCast(theWindow)->HWindow(), theTitleW.ToWideString());
-#elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
-  SetCocoaWindowTitle (Handle(Cocoa_Window)::DownCast(theWindow), theTitle);
-#else
-  if(GetDisplayConnection()->GetDisplay())
-  {
-    Window aWindow =
-      Handle(Xw_Window)::DownCast(theWindow)->XWindow();
-    XStoreName (GetDisplayConnection()->GetDisplay(), aWindow , theTitle);
-  }
-#endif
-}
-
 //==============================================================================
 //function : IsWindowOverlapped
 //purpose  : Check if theWindow overlapp another view
@@ -574,6 +1630,121 @@ TCollection_AsciiString ViewerTest::GetCurrentViewName ()
 {
   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
 }
+
+//! Auxiliary tool performing continuous redraws of specified window.
+class ViewerTest_ContinuousRedrawer
+{
+public:
+  //! Return global instance.
+  static ViewerTest_ContinuousRedrawer& Instance()
+  {
+    static ViewerTest_ContinuousRedrawer aRedrawer;
+    return aRedrawer;
+  }
+public:
+
+  //! Destructor.
+  ~ViewerTest_ContinuousRedrawer()
+  {
+    Stop();
+  }
+
+  //! Start thread.
+  void Start (const Handle(Aspect_Window)& theWindow,
+              Standard_Real theTargetFps)
+  {
+    if (myWindow != theWindow
+     || myTargetFps != theTargetFps)
+    {
+      Stop();
+      myWindow = theWindow;
+      myTargetFps = theTargetFps;
+    }
+    if (myThread.GetId() == 0)
+    {
+      myToStop = false;
+      myThread.Run (this);
+    }
+  }
+
+  //! Stop thread.
+  void Stop (const Handle(Aspect_Window)& theWindow = NULL)
+  {
+    if (!theWindow.IsNull()
+      && myWindow != theWindow)
+    {
+      return;
+    }
+
+    {
+      Standard_Mutex::Sentry aLock (myMutex);
+      myToStop = true;
+    }
+    myThread.Wait();
+    myToStop = false;
+    myWindow.Nullify();
+  }
+
+private:
+
+  //! Thread loop.
+  void doThreadLoop()
+  {
+    Handle(Aspect_DisplayConnection) aDisp = new Aspect_DisplayConnection();
+    OSD_Timer aTimer;
+    aTimer.Start();
+    Standard_Real aTimeOld = 0.0;
+    const Standard_Real aTargetDur = myTargetFps > 0.0 ? 1.0 / myTargetFps : -1.0;
+    for (;;)
+    {
+      {
+        Standard_Mutex::Sentry aLock (myMutex);
+        if (myToStop)
+        {
+          return;
+        }
+      }
+      if (myTargetFps > 0.0)
+      {
+        const Standard_Real aTimeNew  = aTimer.ElapsedTime();
+        const Standard_Real aDuration = aTimeNew - aTimeOld;
+        if (aDuration >= aTargetDur)
+        {
+          myWindow->InvalidateContent (aDisp);
+          aTimeOld = aTimeNew;
+        }
+      }
+      else
+      {
+        myWindow->InvalidateContent (aDisp);
+      }
+
+      OSD::MilliSecSleep (1);
+    }
+  }
+
+  //! Thread creation callback.
+  static Standard_Address doThreadWrapper (Standard_Address theData)
+  {
+    ViewerTest_ContinuousRedrawer* aThis = (ViewerTest_ContinuousRedrawer* )theData;
+    aThis->doThreadLoop();
+    return 0;
+  }
+
+  //! Empty constructor.
+  ViewerTest_ContinuousRedrawer()
+  : myThread (doThreadWrapper),
+    myTargetFps (0.0),
+    myToStop (false) {}
+
+private:
+  Handle(Aspect_Window) myWindow;
+  OSD_Thread      myThread;
+  Standard_Mutex  myMutex;
+  Standard_Real   myTargetFps;
+  volatile bool   myToStop;
+};
+
 //==============================================================================
 //function : ViewerInit
 //purpose  : Create the window viewer and initialize all the global variable
@@ -617,15 +1788,26 @@ TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft
     aPxHeight = thePxHeight;
 
   // Get graphic driver (create it or get from another view)
-  if (!ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName()))
+  const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
+  if (isNewDriver)
   {
     // Get connection string
   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
-    TCollection_AsciiString aDisplayName(theDisplayName);
-    if (!aDisplayName.IsEmpty())
-      SetDisplayConnection (new Aspect_DisplayConnection ());
+    if (!theDisplayName.IsEmpty())
+    {
+      SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
+    }
     else
-      SetDisplayConnection (new Aspect_DisplayConnection (aDisplayName));
+    {
+      ::Display* aDispX = NULL;
+      // create dedicated display connection instead of reusing Tk connection
+      // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
+      /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
+      Tcl_Interp* aTclInterp = aCommands.Interp();
+      Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
+      aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
+      SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
+    }
   #else
     (void)theDisplayName; // avoid warning on unused argument
     SetDisplayConnection (new Aspect_DisplayConnection ());
@@ -638,8 +1820,9 @@ TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft
       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
     }
-    aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection());
+    aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection(), false);
     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
+    aGraphicDriver->InitContext();
 
     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
     toCreateViewer = Standard_True;
@@ -701,12 +1884,9 @@ TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft
   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
 
   // Change name of current active window
-  if (!ViewerTest::CurrentView().IsNull())
+  if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
   {
-    TCollection_AsciiString anActiveWindowTitle("3D View - ");
-    anActiveWindowTitle = anActiveWindowTitle
-      + ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
-    SetWindowTitle (ViewerTest::CurrentView()->Window(), anActiveWindowTitle.ToCString());
+    aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
   }
 
   // Create viewer
@@ -800,15 +1980,13 @@ TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft
     a3DViewer->SetLightOn();
   }
 
-  #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
-  #if TCL_MAJOR_VERSION  < 8
-  Tk_CreateFileHandler((void*)XConnectionNumber(GetDisplayConnection()->GetDisplay()),
-      TK_READABLE, VProcessEvents, (ClientData) VT_GetWindow()->XWindow() );
-  #else
-  Tk_CreateFileHandler(XConnectionNumber(GetDisplayConnection()->GetDisplay()),
-      TK_READABLE, VProcessEvents, (ClientData) VT_GetWindow()->XWindow() );
-  #endif
-  #endif
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
+  if (isNewDriver)
+  {
+    ::Display* aDispX = GetDisplayConnection()->GetDisplay();
+    Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
+  }
+#endif
 
   VT_GetWindow()->Map();
 
@@ -886,9 +2064,9 @@ static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const cha
     }
     else if (anArgCase == "-exitonclose")
     {
-      Draw_ToExitOnCloseView = true;
+      ViewerTest_EventManager::ToExitOnCloseView() = true;
       if (anArgIt + 1 < theArgsNb
-       && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], Draw_ToExitOnCloseView))
+       && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
       {
         ++anArgIt;
       }
@@ -896,9 +2074,9 @@ static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const cha
     else if (anArgCase == "-closeonescape"
           || anArgCase == "-closeonesc")
     {
-      Draw_ToCloseViewOnEsc = true;
+      ViewerTest_EventManager::ToCloseViewOnEscape() = true;
       if (anArgIt + 1 < theArgsNb
-       && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], Draw_ToCloseViewOnEsc))
+       && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
       {
         ++anArgIt;
       }
@@ -1250,13 +2428,13 @@ static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** arg
 //function : FindViewIdByWindowHandle
 //purpose  : Find theView Id in the map of views by window handle
 //==============================================================================
-#if defined(_WIN32) || defined(__WIN32__) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
-TCollection_AsciiString FindViewIdByWindowHandle(const Aspect_Handle theWindowHandle)
+#if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
+TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
 {
   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
   {
-    Aspect_Handle aWindowHandle = GetWindowHandle(anIter.Value()->Window());
+    Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
     if (aWindowHandle == theWindowHandle)
       return anIter.Key1();
   }
@@ -1277,17 +2455,14 @@ void ActivateView (const TCollection_AsciiString& theViewName,
   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
   if (!anAISContext.IsNull())
   {
-    if (!ViewerTest::CurrentView().IsNull())
+    if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
     {
-      TCollection_AsciiString aTitle("3D View - ");
-      aTitle = aTitle + ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
-      SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
+      aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
     }
 
     ViewerTest::CurrentView (aView);
     ViewerTest::SetAISContext (anAISContext);
-    TCollection_AsciiString aTitle = TCollection_AsciiString("3D View - ") + theViewName + "(*)";
-    SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
+    aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
 #if defined(_WIN32)
     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
@@ -1327,7 +2502,7 @@ void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const S
 {
   if (!ViewerTest_myViews.IsBound1(theViewName))
   {
-    cout << "Wrong view name\n";
+    std::cout << "Wrong view name\n";
     return;
   }
 
@@ -1363,6 +2538,8 @@ void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const S
   // Delete view
   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
+  ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
+  aRedrawer.Stop (aView->Window());
 
   // Remove view resources
   ViewerTest_myViews.UnBind1(theViewName);
@@ -1399,19 +2576,15 @@ void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const S
       {
         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
-        #if TCL_MAJOR_VERSION  < 8
-        Tk_DeleteFileHandler((void*)XConnectionNumber(aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
-        #else
-        Tk_DeleteFileHandler(XConnectionNumber(aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
-        #endif
+        Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
       #endif
       }
 
       ViewerTest_myContexts.UnBind2(aCurrentContext);
     }
   }
-  cout << "3D View - " << theViewName << " was deleted.\n";
-  if (Draw_ToExitOnCloseView)
+  std::cout << "3D View - " << theViewName << " was deleted.\n";
+  if (ViewerTest_EventManager::ToExitOnCloseView())
   {
     Draw_Interprete ("exit");
   }
@@ -1506,9 +2679,7 @@ static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const
           && aNameString.IsEmpty()
           && anArg == "none")
     {
-      TCollection_AsciiString aTitle("3D View - ");
-      aTitle = aTitle + ViewerTest_myViews.Find2(ViewerTest::CurrentView());
-      SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
+      ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
       VT_GetWindow().Nullify();
       ViewerTest::CurrentView (Handle(V3d_View)());
       ViewerTest::ResetEventManager();
@@ -1517,618 +2688,430 @@ static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const
     }
     else if (toActivate
           && aNameString.IsEmpty())
-    {
-      aNameString = theArgVec[anArgIter];
-    }
-    else
-    {
-      std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
-      return 1;
-    }
-  }
-
-  if (!toActivate)
-  {
-    return 0;
-  }
-  else if (aNameString.IsEmpty())
-  {
-    std::cout << "Syntax error: wrong number of arguments\n";
-    return 1;
-  }
-
-  // Check if this view exists in the viewer with the driver
-  ViewerTest_Names aViewNames (aNameString);
-  if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
-  {
-    theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
-    return 1;
-  }
-
-  // Check if it is active already
-  if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
-  {
-    theDi << theArgVec[0] << ": the view is active already\n";
-    return 0;
-  }
-
-  ActivateView (aViewNames.GetViewName(), toUpdate);
-  return 0;
-}
-
-//==============================================================================
-//function : VViewList
-//purpose  : Print current list of views per viewer and graphic driver ID
-//           shared between viewers
-//==============================================================================
-
-static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
-{
-  if (theArgsNb > 2)
-  {
-    theDi << theArgVec[0] << ": Wrong number of command arguments\n"
-          << "Usage: " << theArgVec[0] << " name";
-    return 1;
-  }
-  if (ViewerTest_myContexts.Size() < 1)
-    return 0;
-
-  Standard_Boolean isTreeView =
-    (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
-
-  if (isTreeView)
-  {
-    theDi << theArgVec[0] <<":\n";
-  }
-
-  for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
-       aDriverIter.More(); aDriverIter.Next())
-  {
-    if (isTreeView)
-      theDi << aDriverIter.Key1() << ":\n";
-
-    for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
-      aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
-    {
-      if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
-      {
-        if (isTreeView)
-        {
-          TCollection_AsciiString aContextName(aContextIter.Key1());
-          theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
-        }
-
-        for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
-             aViewIter.More(); aViewIter.Next())
-        {
-          if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
-          {
-            TCollection_AsciiString aViewName(aViewIter.Key1());
-            if (isTreeView)
-            {
-              if (aViewIter.Value() == ViewerTest::CurrentView())
-                theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
-              else
-                theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
-            }
-            else
-            {
-              theDi << aViewName << " ";
-            }
-          }
-        }
-      }
-    }
-  }
-  return 0;
-}
-
-//==============================================================================
-//function : VT_ProcessKeyPress
-//purpose  : Handle KeyPress event from a CString
-//==============================================================================
-void VT_ProcessKeyPress (const char* buf_ret)
-{
-  //cout << "KeyPress" << endl;
-  const Handle(V3d_View) aView = ViewerTest::CurrentView();
-  // Letter in alphabetic order
-
-  if (!strcasecmp (buf_ret, "A")
-   && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
-  {
-    // AXO
-    aView->SetProj(V3d_XposYnegZpos);
-  }
-  else if (!strcasecmp (buf_ret, "D")
-        && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
-  {
-    // Reset
-    aView->Reset();
-  }
-  else if (!strcasecmp (buf_ret, "F"))
-  {
-    if (ViewerTest::GetAISContext()->NbSelected() > 0)
-    {
-      ViewerTest::GetAISContext()->FitSelected (aView);
-    }
-    else
-    {
-      // FitAll
-      aView->FitAll();
-    }
-  }
-  else if (!strcasecmp (buf_ret, "H"))
-  {
-    // HLR
-    std::cout << "HLR" << std::endl;
-    aView->SetComputedMode (!aView->ComputedMode());
-    aView->Redraw();
-  }
-  else if (!strcasecmp (buf_ret, "P"))
-  {
-    // Type of HLR
-    Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
-    if (aContext->DefaultDrawer()->TypeOfHLR() == Prs3d_TOH_Algo)
-      aContext->DefaultDrawer()->SetTypeOfHLR(Prs3d_TOH_PolyAlgo);
-    else
-      aContext->DefaultDrawer()->SetTypeOfHLR(Prs3d_TOH_Algo);
-    if (aContext->NbSelected()==0)
-    {
-      AIS_ListOfInteractive aListOfShapes;
-      aContext->DisplayedObjects(aListOfShapes);
-      for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes);
-        anIter.More(); anIter.Next())
-      {
-        Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
-        if (aShape.IsNull())
-          continue;
-        if (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo)
-          aShape->SetTypeOfHLR (Prs3d_TOH_Algo);
-        else
-          aShape->SetTypeOfHLR (Prs3d_TOH_PolyAlgo);
-        aContext->Redisplay (aShape, Standard_False);
-      }
-    }
-    else
-    {
-      for (aContext->InitSelected();aContext->MoreSelected();aContext->NextSelected())
-      {
-        Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(aContext->SelectedInteractive());
-        if (aShape.IsNull())
-          continue;
-        if(aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo)
-          aShape->SetTypeOfHLR (Prs3d_TOH_Algo);
-        else
-          aShape->SetTypeOfHLR (Prs3d_TOH_PolyAlgo);
-        aContext->Redisplay (aShape, Standard_False);
-      }
-    }
-
-    aContext->UpdateCurrentViewer();
-
-  }
-  else if (!strcasecmp (buf_ret, "S"))
-  {
-    std::cout << "setup Shaded display mode" << std::endl;
-
-    Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext();
-    if(Ctx->NbSelected()==0)
-      Ctx->SetDisplayMode (AIS_Shaded, Standard_True);
-    else{
-      for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected())
-        Ctx->SetDisplayMode(Ctx->SelectedInteractive(),1,Standard_False);
-      Ctx->UpdateCurrentViewer();
-    }
-  }
-  else if (!strcasecmp (buf_ret, "U"))
-  {
-    // Unset display mode
-    std::cout << "reset display mode to defaults" << std::endl;
-
-    Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext();
-    if(Ctx->NbSelected()==0)
-      Ctx->SetDisplayMode (AIS_WireFrame, Standard_True);
-    else{
-      for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected())
-        Ctx->UnsetDisplayMode(Ctx->SelectedInteractive(),Standard_False);
-      Ctx->UpdateCurrentViewer();
-    }
-
-  }
-  else if (!strcasecmp (buf_ret, "T")
-        && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
-  {
-    // Top
-    aView->SetProj(V3d_Zpos);
-  }
-  else if (!strcasecmp (buf_ret, "B")
-        && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
-  {
-    // Bottom
-    aView->SetProj(V3d_Zneg);
-  }
-  else if (!strcasecmp (buf_ret, "L")
-        && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
-  {
-    // Left
-    aView->SetProj(V3d_Xneg);
-  }
-  else if (!strcasecmp (buf_ret, "R")
-        && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
-  {
-    // Right
-    aView->SetProj(V3d_Xpos);
-  }
-  else if (!strcasecmp (buf_ret, "W"))
-  {
-    std::cout << "setup WireFrame display mode" << std::endl;
-    Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext();
-    if(Ctx->NbSelected()==0)
-      Ctx->SetDisplayMode (AIS_WireFrame, Standard_True);
-    else{
-      for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected())
-        Ctx->SetDisplayMode(Ctx->SelectedInteractive(),0,Standard_False);
-      Ctx->UpdateCurrentViewer();
+    {
+      aNameString = theArgVec[anArgIter];
+    }
+    else
+    {
+      std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
+      return 1;
     }
   }
-  else if (!strcasecmp (buf_ret, ","))
+
+  if (!toActivate)
   {
-    ViewerTest::GetAISContext()->HilightNextDetected(ViewerTest::CurrentView());
+    return 0;
   }
-  else if (!strcasecmp (buf_ret, "."))
+  else if (aNameString.IsEmpty())
   {
-    ViewerTest::GetAISContext()->HilightPreviousDetected(ViewerTest::CurrentView());
+    std::cout << "Syntax error: wrong number of arguments\n";
+    return 1;
   }
-  else if (!strcasecmp (buf_ret, "/"))
+
+  // Check if this view exists in the viewer with the driver
+  ViewerTest_Names aViewNames (aNameString);
+  if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
   {
-    Handle(Graphic3d_Camera) aCamera = aView->Camera();
-    if (aCamera->IsStereo())
-    {
-      aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01);
-      aView->Redraw();
-    }
+    theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
+    return 1;
   }
-  else if (!strcasecmp (buf_ret, "*"))
+
+  // Check if it is active already
+  if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
   {
-    Handle(Graphic3d_Camera) aCamera = aView->Camera();
-    if (aCamera->IsStereo())
-    {
-      aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01);
-      aView->Redraw();
-    }
+    theDi << theArgVec[0] << ": the view is active already\n";
+    return 0;
   }
-  else if (*buf_ret == THE_KEY_DELETE)
+
+  ActivateView (aViewNames.GetViewName(), toUpdate);
+  return 0;
+}
+
+//==============================================================================
+//function : VViewList
+//purpose  : Print current list of views per viewer and graphic driver ID
+//           shared between viewers
+//==============================================================================
+
+static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
+{
+  if (theArgsNb > 2)
   {
-    Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
-    if (!aCtx.IsNull()
-     && aCtx->NbSelected() > 0)
-    {
-      Draw_Interprete ("verase");
-    }
+    theDi << theArgVec[0] << ": Wrong number of command arguments\n"
+          << "Usage: " << theArgVec[0] << " name";
+    return 1;
   }
-  else if (*buf_ret == THE_KEY_ESCAPE)
+  if (ViewerTest_myContexts.Size() < 1)
+    return 0;
+
+  Standard_Boolean isTreeView =
+    (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
+
+  if (isTreeView)
   {
-    Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
-    if (!aCtx.IsNull()
-     && Draw_ToCloseViewOnEsc)
-    {
-      Draw_Interprete (Draw_ToExitOnCloseView ? "exit" : "vclose");
-    }
+    theDi << theArgVec[0] <<":\n";
   }
-  else
+
+  for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
+       aDriverIter.More(); aDriverIter.Next())
   {
-    // Number
-    const Standard_Integer aSelMode = Draw::Atoi(buf_ret);
-    if (aSelMode >= 0 && aSelMode <= 7)
+    if (isTreeView)
+      theDi << aDriverIter.Key1() << ":\n";
+
+    for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
+      aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
     {
-      bool toEnable = true;
-      if (const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext())
+      if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
       {
-        AIS_ListOfInteractive aPrsList;
-        aCtx->DisplayedObjects (aPrsList);
-        for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More() && toEnable; aPrsIter.Next())
+        if (isTreeView)
+        {
+          TCollection_AsciiString aContextName(aContextIter.Key1());
+          theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
+        }
+
+        for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
+             aViewIter.More(); aViewIter.Next())
         {
-          TColStd_ListOfInteger aModes;
-          aCtx->ActivatedModes (aPrsIter.Value(), aModes);
-          for (TColStd_ListOfInteger::Iterator aModeIter (aModes); aModeIter.More() && toEnable; aModeIter.Next())
+          if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
           {
-            if (aModeIter.Value() == aSelMode)
+            TCollection_AsciiString aViewName(aViewIter.Key1());
+            if (isTreeView)
+            {
+              if (aViewIter.Value() == ViewerTest::CurrentView())
+                theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
+              else
+                theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
+            }
+            else
             {
-              toEnable = false;
+              theDi << aViewName << " ";
             }
           }
         }
       }
-      TCollection_AsciiString aCmd = TCollection_AsciiString ("vselmode ") + aSelMode + (toEnable ? " 1" : " 0");
-      Draw_Interprete (aCmd.ToCString());
     }
   }
+  return 0;
 }
 
 //==============================================================================
-//function : VT_ProcessExpose
-//purpose  : Redraw the View on an Expose Event
+//function : GetMousePosition
+//purpose  :
 //==============================================================================
-void VT_ProcessExpose()
+void ViewerTest::GetMousePosition (Standard_Integer& theX,
+                                   Standard_Integer& theY)
 {
-  Handle(V3d_View) aView3d = ViewerTest::CurrentView();
-  if (!aView3d.IsNull())
+  if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
   {
-    aView3d->Redraw();
+    theX = aViewCtrl->LastMousePosition().x();
+    theY = aViewCtrl->LastMousePosition().y();
   }
 }
 
 //==============================================================================
-//function : VT_ProcessConfigure
-//purpose  : Resize the View on an Configure Event
+//function : VViewProj
+//purpose  : Switch view projection
 //==============================================================================
-void VT_ProcessConfigure()
+static int VViewProj (Draw_Interpretor& ,
+                      Standard_Integer theNbArgs,
+                      const char** theArgVec)
 {
-  Handle(V3d_View) aView3d = ViewerTest::CurrentView();
-  if (aView3d.IsNull())
+  static Standard_Boolean isYup = Standard_False;
+  const Handle(V3d_View)& aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
   {
-    return;
+    std::cout << "Error: no active view\n";
+    return 1;
   }
 
-  aView3d->MustBeResized();
-  aView3d->Update();
-  aView3d->Redraw();
-}
-
-//==============================================================================
-//function : VT_ProcessButton1Press
-//purpose  : Picking
-//==============================================================================
-Standard_Boolean VT_ProcessButton1Press (Standard_Integer ,
-                                         const char**     theArgVec,
-                                         Standard_Boolean theToPick,
-                                         Standard_Boolean theIsShift)
-{
-  if (TheIsAnimating)
+  TCollection_AsciiString aCmdName (theArgVec[0]);
+  Standard_Boolean isGeneralCmd = Standard_False;
+  if (aCmdName == "vfront")
   {
-    TheIsAnimating = Standard_False;
-    return Standard_False;
+    aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
   }
-
-  if (theToPick)
+  else if (aCmdName == "vback")
   {
-    Standard_Real X, Y, Z;
-    ViewerTest::CurrentView()->Convert (X_Motion, Y_Motion, X, Y, Z);
-
-    Draw::Set (theArgVec[1], X);
-    Draw::Set (theArgVec[2], Y);
-    Draw::Set (theArgVec[3], Z);
+    aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
   }
-
-  if (theIsShift)
+  else if (aCmdName == "vtop")
   {
-    ViewerTest::CurrentEventManager()->ShiftSelect();
+    aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
   }
-  else
+  else if (aCmdName == "vbottom")
   {
-    ViewerTest::CurrentEventManager()->Select();
+    aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
   }
-
-  return Standard_False;
-}
-
-//==============================================================================
-//function : VT_ProcessButton1Release
-//purpose  : End selecting
-//==============================================================================
-void VT_ProcessButton1Release (Standard_Boolean theIsShift)
-{
-  if (IsDragged)
+  else if (aCmdName == "vleft")
   {
-    IsDragged = Standard_False;
-    Handle(ViewerTest_EventManager) EM = ViewerTest::CurrentEventManager();
-    if (theIsShift)
-    {
-      EM->ShiftSelect (X_ButtonPress, Y_ButtonPress,
-                       X_Motion, Y_Motion);
-    }
-    else
-    {
-      EM->Select (X_ButtonPress, Y_ButtonPress,
-                  X_Motion, Y_Motion);
-    }
+    aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
   }
-}
-
-//==============================================================================
-//function : VT_ProcessButton3Press
-//purpose  : Start Rotation
-//==============================================================================
-void VT_ProcessButton3Press()
-{
-  if (ViewerTest_V3dView::IsCurrentViewIn2DMode())
+  else if (aCmdName == "vright")
   {
-    return;
+    aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
   }
-
-  Start_Rot = 1;
-  HasHlrOnBeforeRotation = ViewerTest::CurrentView()->ComputedMode();
-  if (HasHlrOnBeforeRotation)
+  else if (aCmdName == "vaxo")
   {
-    ViewerTest::CurrentView()->SetComputedMode (Standard_False);
+    aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
   }
-  ViewerTest::CurrentView()->StartRotation( X_ButtonPress, Y_ButtonPress );
-}
-
-//==============================================================================
-//function : VT_ProcessButton3Release
-//purpose  : End rotation
-//==============================================================================
-void VT_ProcessButton3Release()
-{
-  if (Start_Rot)
+  else
   {
-    Start_Rot = 0;
-    if (HasHlrOnBeforeRotation)
+    isGeneralCmd = Standard_True;
+    for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
     {
-      HasHlrOnBeforeRotation = Standard_False;
-      ViewerTest::CurrentView()->SetComputedMode (Standard_True);
-      ViewerTest::CurrentView()->Redraw();
-    }
-  }
-}
-
-//==============================================================================
-//function : ProcessControlButton1Motion
-//purpose  : Zoom
-//==============================================================================
-
-#if defined(_WIN32) || ! defined(__APPLE__) || defined(MACOSX_USE_GLX)
-static void ProcessControlButton1Motion()
-{
-  ViewerTest::CurrentView()->Zoom( X_ButtonPress, Y_ButtonPress, X_Motion, Y_Motion);
-
-  X_ButtonPress = X_Motion;
-  Y_ButtonPress = Y_Motion;
-}
-#endif
-
-//==============================================================================
-//function : VT_ProcessControlButton2Motion
-//purpose  : Panning
-//==============================================================================
-void VT_ProcessControlButton2Motion()
-{
-  Standard_Integer aDx = X_Motion - X_ButtonPress;
-  Standard_Integer aDy = Y_Motion - Y_ButtonPress;
-
-  aDy = -aDy; // Xwindow Y axis is from top to Bottom
-
-  ViewerTest::CurrentView()->Pan (aDx, aDy);
-
-  X_ButtonPress = X_Motion;
-  Y_ButtonPress = Y_Motion;
-}
-
-//==============================================================================
-//function : VT_ProcessControlButton3Motion
-//purpose  : Rotation
-//==============================================================================
-void VT_ProcessControlButton3Motion()
-{
-  if (Start_Rot)
-  {
-    ViewerTest::CurrentView()->Rotation (X_Motion, Y_Motion);
-  }
-}
-
-//==============================================================================
-//function : VT_ProcessMotion
-//purpose  :
-//==============================================================================
-void VT_ProcessMotion()
-{
-  //pre-hilights detected objects at mouse position
+      TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
+      anArgCase.LowerCase();
+      if (anArgCase == "-zup")
+      {
+        isYup = Standard_False;
+      }
+      else if (anArgCase == "-yup")
+      {
+        isYup = Standard_True;
+      }
+      else if (anArgCase == "-front"
+            || anArgCase == "front"
+            || anArgCase == "-f"
+            || anArgCase == "f")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
+      }
+      else if (anArgCase == "-back"
+            || anArgCase == "back"
+            || anArgCase == "-b"
+            || anArgCase == "b")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
+      }
+      else if (anArgCase == "-top"
+            || anArgCase == "top"
+            || anArgCase == "-t"
+            || anArgCase == "t")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
+      }
+      else if (anArgCase == "-bottom"
+            || anArgCase == "bottom"
+            || anArgCase == "-bot"
+            || anArgCase == "bot"
+            || anArgCase == "-b"
+            || anArgCase == "b")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
+      }
+      else if (anArgCase == "-left"
+            || anArgCase == "left"
+            || anArgCase == "-l"
+            || anArgCase == "l")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
+      }
+      else if (anArgCase == "-right"
+            || anArgCase == "right"
+            || anArgCase == "-r"
+            || anArgCase == "r")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
+      }
+      else if (anArgCase == "-axoleft"
+            || anArgCase == "-leftaxo"
+            || anArgCase == "axoleft"
+            || anArgCase == "leftaxo")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
+      }
+      else if (anArgCase == "-axo"
+            || anArgCase == "axo"
+            || anArgCase == "-a"
+            || anArgCase == "a"
+            || anArgCase == "-axoright"
+            || anArgCase == "-rightaxo"
+            || anArgCase == "axoright"
+            || anArgCase == "rightaxo")
+      {
+        aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
+      }
+      else if (anArgCase == "+x")
+      {
+        aView->SetProj (V3d_Xpos, isYup);
+      }
+      else if (anArgCase == "-x")
+      {
+        aView->SetProj (V3d_Xneg, isYup);
+      }
+      else if (anArgCase == "+y")
+      {
+        aView->SetProj (V3d_Ypos, isYup);
+      }
+      else if (anArgCase == "-y")
+      {
+        aView->SetProj (V3d_Yneg, isYup);
+      }
+      else if (anArgCase == "+z")
+      {
+        aView->SetProj (V3d_Zpos, isYup);
+      }
+      else if (anArgCase == "-z")
+      {
+        aView->SetProj (V3d_Zneg, isYup);
+      }
+      else if (anArgCase == "+x+y+z")
+      {
+        aView->SetProj (V3d_XposYposZpos, isYup);
+      }
+      else if (anArgCase == "+x+y-z")
+      {
+        aView->SetProj (V3d_XposYposZneg, isYup);
+      }
+      else if (anArgCase == "+x-y+z")
+      {
+        aView->SetProj (V3d_XposYnegZpos, isYup);
+      }
+      else if (anArgCase == "+x-y-z")
+      {
+        aView->SetProj (V3d_XposYnegZneg, isYup);
+      }
+      else if (anArgCase == "-x+y+z")
+      {
+        aView->SetProj (V3d_XnegYposZpos, isYup);
+      }
+      else if (anArgCase == "-x+y-z")
+      {
+        aView->SetProj (V3d_XnegYposZneg, isYup);
+      }
+      else if (anArgCase == "-x-y+z")
+      {
+        aView->SetProj (V3d_XnegYnegZpos, isYup);
+      }
+      else if (anArgCase == "-x-y-z")
+      {
+        aView->SetProj (V3d_XnegYnegZneg, isYup);
+      }
+      else if (anArgCase == "+x+y")
+      {
+        aView->SetProj (V3d_XposYpos, isYup);
+      }
+      else if (anArgCase == "+x-y")
+      {
+        aView->SetProj (V3d_XposYneg, isYup);
+      }
+      else if (anArgCase == "-x+y")
+      {
+        aView->SetProj (V3d_XnegYpos, isYup);
+      }
+      else if (anArgCase == "-x-y")
+      {
+        aView->SetProj (V3d_XnegYneg, isYup);
+      }
+      else if (anArgCase == "+x+z")
+      {
+        aView->SetProj (V3d_XposZpos, isYup);
+      }
+      else if (anArgCase == "+x-z")
+      {
+        aView->SetProj (V3d_XposZneg, isYup);
+      }
+      else if (anArgCase == "-x+z")
+      {
+        aView->SetProj (V3d_XnegZpos, isYup);
+      }
+      else if (anArgCase == "-x-z")
+      {
+        aView->SetProj (V3d_XnegZneg, isYup);
+      }
+      else if (anArgCase == "+y+z")
+      {
+        aView->SetProj (V3d_YposZpos, isYup);
+      }
+      else if (anArgCase == "+y-z")
+      {
+        aView->SetProj (V3d_YposZneg, isYup);
+      }
+      else if (anArgCase == "-y+z")
+      {
+        aView->SetProj (V3d_YnegZpos, isYup);
+      }
+      else if (anArgCase == "-y-z")
+      {
+        aView->SetProj (V3d_YnegZneg, isYup);
+      }
+      else if (anArgIter + 1 < theNbArgs
+            && anArgCase == "-frame"
+            && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
+      {
+        TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
+        aFrameDef.LowerCase();
+        gp_Dir aRight, anUp;
+        if (aFrameDef.Value (2) == aFrameDef.Value (4))
+        {
+          std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
+          return 1;
+        }
 
-  Handle(ViewerTest_EventManager) EM = ViewerTest::CurrentEventManager();
-  EM->MoveTo(X_Motion, Y_Motion);
-}
+        if (aFrameDef.Value (2) == 'x')
+        {
+          aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
+        }
+        else if (aFrameDef.Value (2) == 'y')
+        {
+          aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
+        }
+        else if (aFrameDef.Value (2) == 'z')
+        {
+          aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
+        }
+        else
+        {
+          std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
+          return 1;
+        }
 
+        if (aFrameDef.Value (4) == 'x')
+        {
+          anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
+        }
+        else if (aFrameDef.Value (4) == 'y')
+        {
+          anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
+        }
+        else if (aFrameDef.Value (4) == 'z')
+        {
+          anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
+        }
+        else
+        {
+          std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
+          return 1;
+        }
 
-void ViewerTest::GetMousePosition(Standard_Integer& Xpix,Standard_Integer& Ypix)
-{
-  Xpix = X_Motion;Ypix=Y_Motion;
-}
+        const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
+        const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
+        const gp_Dir aDir = anUp.Crossed (aRight);
+        aCamera->SetCenter (gp_Pnt (0, 0, 0));
+        aCamera->SetDirection (aDir);
+        aCamera->SetUp (anUp);
+        aCamera->OrthogonalizeUp();
 
-//==============================================================================
-//function : ViewProject: implements VAxo, VTop, VLeft, ...
-//purpose  : Switches to an axonometric, top, left and other views
-//==============================================================================
+        aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
+        aView->Update();
+      }
+      else
+      {
+        std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
+        return 1;
+      }
+    }
+  }
 
-static int ViewProject(Draw_Interpretor& di, const V3d_TypeOfOrientation ori)
-{
-  if ( ViewerTest::CurrentView().IsNull() )
+  if (!isGeneralCmd
+    && theNbArgs != 1)
   {
-    di<<"Call vinit before this command, please\n";
+    std::cout << "Syntax error: wrong number of arguments\n";
     return 1;
   }
-
-  ViewerTest::CurrentView()->SetProj(ori);
   return 0;
 }
 
-//==============================================================================
-//function : VAxo
-//purpose  : Switch to an Axonometric view
-//Draw arg : No args
-//==============================================================================
-
-static int VAxo(Draw_Interpretor& di, Standard_Integer , const char** )
-{
-  return ViewProject(di, V3d_XposYnegZpos);
-}
-
-//==============================================================================
-//function : VTop
-//purpose  : Switch to a Top View
-//Draw arg : No args
-//==============================================================================
-
-static int VTop(Draw_Interpretor& di, Standard_Integer , const char** )
-{
-  return ViewProject(di, V3d_Zpos);
-}
-
-//==============================================================================
-//function : VBottom
-//purpose  : Switch to a Bottom View
-//Draw arg : No args
-//==============================================================================
-
-static int VBottom(Draw_Interpretor& di, Standard_Integer , const char** )
-{
-  return ViewProject(di, V3d_Zneg);
-}
-
-//==============================================================================
-//function : VLeft
-//purpose  : Switch to a Left View
-//Draw arg : No args
-//==============================================================================
-
-static int VLeft(Draw_Interpretor& di, Standard_Integer , const char** )
-{
-  return ViewProject(di, V3d_Xneg);
-}
-
-//==============================================================================
-//function : VRight
-//purpose  : Switch to a Right View
-//Draw arg : No args
-//==============================================================================
-
-static int VRight(Draw_Interpretor& di, Standard_Integer , const char** )
-{
-  return ViewProject(di, V3d_Xpos);
-}
-
-//==============================================================================
-//function : VFront
-//purpose  : Switch to a Front View
-//Draw arg : No args
-//==============================================================================
-
-static int VFront(Draw_Interpretor& di, Standard_Integer , const char** )
-{
-  return ViewProject(di, V3d_Yneg);
-}
-
-//==============================================================================
-//function : VBack
-//purpose  : Switch to a Back View
-//Draw arg : No args
-//==============================================================================
-
-static int VBack(Draw_Interpretor& di, Standard_Integer , const char** )
-{
-  return ViewProject(di, V3d_Ypos);
-}
-
 //==============================================================================
 //function : VHelp
 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
@@ -2137,9 +3120,6 @@ static int VBack(Draw_Interpretor& di, Standard_Integer , const char** )
 
 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
 {
-
-  di << "Q : Quit the application\n";
-
   di << "=========================\n";
   di << "F : FitAll\n";
   di << "T : TopView\n";
@@ -2152,7 +3132,7 @@ static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
   di << "=========================\n";
   di << "S : Shading\n";
   di << "W : Wireframe\n";
-  di << "H : HidelLineRemoval\n";
+  di << "H : HiddenLineRemoval\n";
   di << "U : Unset display mode\n";
   di << "Delete : Remove selection from viewer\n";
 
@@ -2168,338 +3148,220 @@ static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
   di << "7 : Compound\n";
 
   di << "=========================\n";
-  di << "Z : Switch Z clipping On/Off\n";
-  di << ", : Hilight next detected\n";
-  di << ". : Hilight previous detected\n";
+  di << "< : Hilight next detected\n";
+  di << "> : Hilight previous detected\n";
 
   return 0;
 }
 
 #ifdef _WIN32
 
-static Standard_Boolean Ppick = 0;
-static Standard_Integer Pargc = 0;
-static const char**           Pargv = NULL;
-
-
-static LRESULT WINAPI AdvViewerWindowProc( HWND hwnd,
-                                          UINT Msg,
-                                          WPARAM wParam,
-                                          LPARAM lParam )
+static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
+                                           UINT theMsg,
+                                           WPARAM wParam,
+                                           LPARAM lParam )
 {
-  if (!ViewerTest_myViews.IsEmpty()) {
-
-    WPARAM fwKeys = wParam;
+  if (ViewerTest_myViews.IsEmpty())
+  {
+    return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
+  }
 
-    switch( Msg ) {
+  switch (theMsg)
+  {
     case WM_CLOSE:
-       {
-         // Delete view from map of views
-         ViewerTest::RemoveView(FindViewIdByWindowHandle(hwnd));
-         return 0;
-       }
-       break;
+    {
+      // Delete view from map of views
+      ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
+      return 0;
+    }
     case WM_ACTIVATE:
-      if(LOWORD(wParam) == WA_CLICKACTIVE || LOWORD(wParam) == WA_ACTIVE
-        || ViewerTest::CurrentView().IsNull())
+    {
+      if (LOWORD(wParam) == WA_CLICKACTIVE
+       || LOWORD(wParam) == WA_ACTIVE
+       || ViewerTest::CurrentView().IsNull())
       {
         // Activate inactive window
-        if(GetWindowHandle(VT_GetWindow()) != hwnd)
-        {
-          ActivateView (FindViewIdByWindowHandle(hwnd));
-        }
-      }
-      break;
-
-    case WM_LBUTTONUP:
-      if (IsDragged && !DragFirst)
-      {
-        if (!GetActiveAISManipulator().IsNull())
-        {
-          GetActiveAISManipulator()->StopTransform();
-          ViewerTest::GetAISContext()->ClearSelected (Standard_True);
-        }
-
-        if (ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand()))
-        {
-          ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False);
-          ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate();
-        }
-
-        VT_ProcessButton1Release ((fwKeys & MK_SHIFT) != 0);
-      }
-      IsDragged = Standard_False;
-      return ViewerWindowProc( hwnd, Msg, wParam, lParam );
-
-    case WM_RBUTTONUP:
-      if (IsDragged && !DragFirst)
-      {
-        if (!GetActiveAISManipulator().IsNull())
-        {
-          GetActiveAISManipulator()->StopTransform (Standard_False);
-          ViewerTest::GetAISContext()->ClearSelected (Standard_True);
-        }
-        IsDragged = Standard_False;
-      }
-      return ViewerWindowProc (hwnd, Msg, wParam, lParam);
-
-    case WM_LBUTTONDOWN:
-      if (!GetActiveAISManipulator().IsNull())
-      {
-        IsDragged = ( fwKeys == MK_LBUTTON );
-      }
-      else
-      {
-        IsDragged = ( fwKeys == MK_LBUTTON || fwKeys == ( MK_LBUTTON | MK_SHIFT ) );
-      }
-
-      if (IsDragged)
-      {
-        DragFirst = Standard_True;
-        X_ButtonPress = LOWORD(lParam);
-        Y_ButtonPress = HIWORD(lParam);
-      }
-      return ViewerWindowProc( hwnd, Msg, wParam, lParam );
-
-    case WM_MOUSEMOVE:
-      if (IsDragged)
-      {
-        X_Motion = LOWORD (lParam);
-        Y_Motion = HIWORD (lParam);
-        if (!GetActiveAISManipulator().IsNull())
-        {
-          if (DragFirst)
-          {
-            GetActiveAISManipulator()->StartTransform (X_ButtonPress, Y_ButtonPress, ViewerTest::CurrentView());
-          }
-          else
-          {
-            GetActiveAISManipulator()->Transform (X_Motion, Y_Motion, ViewerTest::CurrentView());
-            ViewerTest::GetAISContext()->CurrentViewer()->Redraw();
-          }
-        }
-        else
+        if (VT_GetWindow().IsNull()
+         || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
         {
-          bool toRedraw = false;
-          if (!DragFirst && ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand()))
-          {
-            ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False);
-            toRedraw = true;
-          }
-
-          RECT aRect;
-          if (GetClientRect (hwnd, &aRect))
-          {
-            int aHeight = aRect.bottom - aRect.top;
-            GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion);
-            ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, AIS_DS_Displayed);
-            toRedraw = true;
-          }
-          if (toRedraw)
-          {
-            ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate();
-          }
+          ActivateView (FindViewIdByWindowHandle (theWinHandle));
         }
-
-        DragFirst = Standard_False;
       }
-      else
-        return ViewerWindowProc( hwnd, Msg, wParam, lParam );
       break;
-
+    }
     default:
-      return ViewerWindowProc( hwnd, Msg, wParam, lParam );
+    {
+      return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
     }
-    return 0;
   }
-  return ViewerWindowProc( hwnd, Msg, wParam, lParam );
+  return 0;
 }
 
-
-static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
-                                       UINT Msg,
-                                       WPARAM wParam,
-                                       LPARAM lParam )
+static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle,
+                                        UINT theMsg,
+                                        WPARAM wParam,
+                                        LPARAM lParam)
 {
-  static int Up = 1;
   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
   if (aView.IsNull())
   {
-    return DefWindowProcW (hwnd, Msg, wParam, lParam);
+    return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
   }
 
-    PAINTSTRUCT    ps;
-
-    switch( Msg ) {
+  switch (theMsg)
+  {
     case WM_PAINT:
-      BeginPaint(hwnd, &ps);
-      EndPaint(hwnd, &ps);
-      VT_ProcessExpose();
+    {
+      PAINTSTRUCT aPaint;
+      BeginPaint(theWinHandle, &aPaint);
+      EndPaint  (theWinHandle, &aPaint);
+      ViewerTest::CurrentEventManager()->ProcessExpose();
       break;
-
+    }
     case WM_SIZE:
-      VT_ProcessConfigure();
+    {
+      ViewerTest::CurrentEventManager()->ProcessConfigure();
       break;
+    }
     case WM_MOVE:
     case WM_MOVING:
     case WM_SIZING:
+    {
       switch (aView->RenderingParams().StereoMode)
       {
         case Graphic3d_StereoMode_RowInterlaced:
         case Graphic3d_StereoMode_ColumnInterlaced:
         case Graphic3d_StereoMode_ChessBoard:
-          VT_ProcessConfigure(); // track window moves to reverse stereo pair
+        {
+          // track window moves to reverse stereo pair
+          aView->MustBeResized();
+          aView->Update();
           break;
+        }
         default:
           break;
       }
       break;
-
+    }
+    case WM_KEYUP:
     case WM_KEYDOWN:
-      if ((wParam != VK_SHIFT) && (wParam != VK_CONTROL))
+    {
+      const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam);
+      if (aVKey != Aspect_VKey_UNKNOWN)
       {
-        char c[2];
-        c[0] = (char) wParam;
-        c[1] = '\0';
-        if (wParam == VK_DELETE)
-        {
-          c[0] = THE_KEY_DELETE;
-        }
-        else if (wParam == VK_ESCAPE)
+        const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
+        if (theMsg == WM_KEYDOWN)
         {
-          c[0] = THE_KEY_ESCAPE;
+          ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
         }
-        // comma
-        else if (wParam == VK_OEM_COMMA)
-        {
-          c[0] = ',';
-        }
-        // dot
-        else if (wParam == VK_OEM_PERIOD)
-        {
-          c[0] = '.';
-        }
-        else if (wParam == VK_DIVIDE)
-        {
-          c[0] = '/';
-        }
-        // dot
-        else if (wParam == VK_MULTIPLY)
+        else
         {
-          c[0] = '*';
+          ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
         }
-        VT_ProcessKeyPress (c);
+        ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
       }
       break;
-
+    }
     case WM_LBUTTONUP:
     case WM_MBUTTONUP:
     case WM_RBUTTONUP:
-      Up = 1;
-      VT_ProcessButton3Release();
-      break;
-
     case WM_LBUTTONDOWN:
     case WM_MBUTTONDOWN:
     case WM_RBUTTONDOWN:
+    {
+      const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
+      const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
+      Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
+      switch (theMsg)
       {
-        WPARAM fwKeys = wParam;
-
-        Up = 0;
-
-        X_ButtonPress = LOWORD(lParam);
-        Y_ButtonPress = HIWORD(lParam);
-
-        if (Msg == WM_LBUTTONDOWN)
-        {
-          if ((fwKeys & MK_CONTROL) != 0)
-          {
-            Ppick = VT_ProcessButton1Press (Pargc, Pargv, Ppick, (fwKeys & MK_SHIFT) != 0);
-          }
-          else
-          {
-            VT_ProcessButton1Press (Pargc, Pargv, Ppick, (fwKeys & MK_SHIFT) != 0);
-          }
-        }
-        else if (Msg == WM_RBUTTONDOWN)
-        {
-          // Start rotation
-          VT_ProcessButton3Press();
-        }
+        case WM_LBUTTONUP:
+        case WM_LBUTTONDOWN:
+          aButton = Aspect_VKeyMouse_LeftButton;
+          break;
+        case WM_MBUTTONUP:
+        case WM_MBUTTONDOWN:
+          aButton = Aspect_VKeyMouse_MiddleButton;
+          break;
+        case WM_RBUTTONUP:
+        case WM_RBUTTONDOWN:
+          aButton = Aspect_VKeyMouse_RightButton;
+          break;
       }
-      break;
-
-    case WM_MOUSEWHEEL:
-    {
-      int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
-      if (wParam & MK_CONTROL)
+      if (theMsg == WM_LBUTTONDOWN
+       || theMsg == WM_MBUTTONDOWN
+       || theMsg == WM_RBUTTONDOWN)
       {
-        if (aView->Camera()->IsStereo())
+        if (aButton == Aspect_VKeyMouse_LeftButton)
         {
-          Standard_Real aFocus = aView->Camera()->ZFocus() + (aDelta > 0 ? 0.05 : -0.05);
-          if (aFocus > 0.2
-           && aFocus < 2.0)
-          {
-            aView->Camera()->SetZFocus (aView->Camera()->ZFocusType(), aFocus);
-            aView->Redraw();
-          }
+          TheIsAnimating = Standard_False;
         }
+
+        SetFocus  (theWinHandle);
+        SetCapture(theWinHandle);
+        ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
       }
       else
       {
-        aView->Zoom (0, 0, aDelta / 40, aDelta / 40);
+        ReleaseCapture();
+        ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
       }
+      ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
       break;
     }
-
-    case WM_MOUSEMOVE:
+    case WM_MOUSEWHEEL:
+    {
+      const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
+      const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
+      const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
+      Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam))));
+      POINT aCursorPnt = { aPos.x(), aPos.y() };
+      if (ScreenToClient (theWinHandle, &aCursorPnt))
       {
-        //cout << "\t WM_MOUSEMOVE" << endl;
-        WPARAM fwKeys = wParam;
-        X_Motion = LOWORD(lParam);
-        Y_Motion = HIWORD(lParam);
+        aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
+      }
 
-        if ( Up &&
-          (fwKeys & ( MK_LBUTTON|MK_MBUTTON|MK_RBUTTON )) != 0 )
-          {
-            Up = 0;
-            X_ButtonPress = LOWORD(lParam);
-            Y_ButtonPress = HIWORD(lParam);
+      ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
+      ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
+      break;
+    }
+    case WM_MOUSEMOVE:
+    {
+      Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
+      Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam);
+      Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(wParam);
 
-            if ((fwKeys & MK_RBUTTON) != 0) {
-              // Start rotation
-              VT_ProcessButton3Press();
-            }
-          }
+      // don't make a slide-show from input events - fetch the actual mouse cursor position
+      CURSORINFO aCursor;
+      aCursor.cbSize = sizeof(aCursor);
+      if (::GetCursorInfo (&aCursor) != FALSE)
+      {
+        POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
+        if (ScreenToClient (theWinHandle, &aCursorPnt))
+        {
+          // as we override mouse position, we need overriding also mouse state
+          aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
+          aButtons = WNT_Window::MouseButtonsAsync();
+          aFlags   = WNT_Window::MouseKeyFlagsAsync();
+        }
+      }
 
-          if ((fwKeys & MK_CONTROL) != 0)
-          {
-            if ((fwKeys & MK_LBUTTON) != 0)
-            {
-              ProcessControlButton1Motion();
-            }
-            else if ((fwKeys & MK_MBUTTON) != 0
-                 || ((fwKeys & MK_LBUTTON) != 0
-                  && (fwKeys & MK_RBUTTON) != 0))
-            {
-              VT_ProcessControlButton2Motion();
-            }
-            else if ((fwKeys & MK_RBUTTON) != 0)
-            {
-              VT_ProcessControlButton3Motion();
-            }
-          }
-          else if (GetWindowHandle (VT_GetWindow()) == hwnd)
-          {
-            VT_ProcessMotion();
-          }
+      if (VT_GetWindow().IsNull()
+      || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
+      {
+        // mouse move events come also for inactive windows
+        break;
       }
-      break;
 
+      ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
+      ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
+      break;
+    }
     default:
-      return DefWindowProcW (hwnd, Msg, wParam, lParam);
+    {
+      return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
     }
-    return 0L;
+  }
+  return 0L;
 }
 
 //==============================================================================
@@ -2507,32 +3369,33 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
 //purpose  : Get a Event on the view and dispatch it
 //==============================================================================
 
-
-int ViewerMainLoop(Standard_Integer argc, const char** argv)
+int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
 {
-  Ppick = (argc > 0)? 1 : 0;
-  Pargc = argc;
-  Pargv = argv;
+  Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
+  if (aViewCtrl.IsNull()
+   || theNbArgs < 4)
+  {
+    return 0;
+  }
 
-  if ( Ppick ) {
-    MSG msg;
-    msg.wParam = 1;
+  aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
 
-    cout << "Start picking" << endl;
+  std::cout << "Start picking\n";
 
-    while ( Ppick == 1 ) {
-      // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
-      if (GetMessageW (&msg, NULL, 0, 0))
-      {
-        TranslateMessage (&msg);
-        DispatchMessageW (&msg);
-      }
+  MSG aMsg;
+  aMsg.wParam = 1;
+  while (aViewCtrl->ToPickPoint())
+  {
+    // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
+    if (GetMessageW (&aMsg, NULL, 0, 0))
+    {
+      TranslateMessage (&aMsg);
+      DispatchMessageW (&aMsg);
     }
-
-    cout << "Picking done" << endl;
   }
 
-  return Ppick;
+  std::cout << "Picking done\n";
+  return 0;
 }
 
 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
@@ -2553,235 +3416,277 @@ int max( int a, int b )
     return b;
 }
 
-int ViewerMainLoop(Standard_Integer argc, const char** argv)
+int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
+{
+  static XEvent aReport;
+  const Standard_Boolean toPick = theNbArgs > 0;
+  if (theNbArgs > 0)
+  {
+    if (ViewerTest::CurrentEventManager().IsNull())
+    {
+      return 0;
+    }
+    ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
+  }
+
+  Display* aDisplay = GetDisplayConnection()->GetDisplay();
+  XNextEvent (aDisplay, &aReport);
+
+  // Handle event for the chosen display connection
+  switch (aReport.type)
+  {
+    case ClientMessage:
+    {
+      if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
+      {
+        // Close the window
+        ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
+        return toPick ? 0 : 1;
+      }
+      break;
+    }
+    case FocusIn:
+    {
+      // Activate inactive view
+      Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
+      if (aWindow != aReport.xfocus.window)
+      {
+        ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
+      }
+      break;
+    }
+    case Expose:
+    {
+      Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
+      if (anXWindow == aReport.xexpose.window)
+      {
+        ViewerTest::CurrentEventManager()->ProcessExpose();
+      }
 
-{
-  static XEvent aReport;
-  Standard_Boolean pick = argc > 0;
-  Display *aDisplay = GetDisplayConnection()->GetDisplay();
-  XNextEvent (aDisplay, &aReport);
+      // remove all the ExposureMask and process them at once
+      for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
+      {
+        if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
+        {
+          break;
+        }
+      }
 
-  // Handle event for the chosen display connection
-  switch (aReport.type) {
-      case ClientMessage:
+      break;
+    }
+    case ConfigureNotify:
+    {
+      // remove all the StructureNotifyMask and process them at once
+      Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
+      for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
+      {
+        if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
         {
-          if((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
-          {
-            // Close the window
-            ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
-          }
+          break;
         }
-        return 0;
-     case FocusIn:
+      }
+
+      if (anXWindow == aReport.xconfigure.window)
       {
-         // Activate inactive view
-         Window aWindow = GetWindowHandle(VT_GetWindow());
-         if(aWindow != aReport.xfocus.window)
-         {
-           ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
-         }
+        ViewerTest::CurrentEventManager()->ProcessConfigure();
       }
       break;
-      case Expose:
+    }
+    case KeyPress:
+    case KeyRelease:
+    {
+      XKeyEvent*   aKeyEvent = (XKeyEvent* )&aReport;
+      const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
+      const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
+      if (aVKey != Aspect_VKey_UNKNOWN)
+      {
+        const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
+        if (aReport.type == KeyPress)
         {
-          VT_ProcessExpose();
+          ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
         }
-        break;
-      case ConfigureNotify:
+        else
         {
-          VT_ProcessConfigure();
+          ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
         }
-        break;
-      case KeyPress:
-        {
-
-          KeySym ks_ret ;
-          char buf_ret[11] ;
-          int ret_len ;
-          XComposeStatus status_in_out;
-
-          ret_len = XLookupString( ( XKeyEvent *)&aReport ,
-            (char *) buf_ret , 10 ,
-            &ks_ret , &status_in_out ) ;
-
+        ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
+      }
+      break;
+    }
+    case ButtonPress:
+    case ButtonRelease:
+    {
+      const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y);
+      Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
+      Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
+      if (aReport.xbutton.button == Button1)
+      {
+        aButton = Aspect_VKeyMouse_LeftButton;
+      }
+      if (aReport.xbutton.button == Button2)
+      {
+        aButton = Aspect_VKeyMouse_MiddleButton;
+      }
+      if (aReport.xbutton.button == Button3)
+      {
+        aButton = Aspect_VKeyMouse_RightButton;
+      }
 
-          buf_ret[ret_len] = '\0' ;
+      if (aReport.xbutton.state & ControlMask)
+      {
+        aFlags |= Aspect_VKeyFlags_CTRL;
+      }
+      if (aReport.xbutton.state & ShiftMask)
+      {
+        aFlags |= Aspect_VKeyFlags_SHIFT;
+      }
+      if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
+      {
+        aFlags |= Aspect_VKeyFlags_ALT;
+      }
 
-          if (ret_len)
-          {
-            VT_ProcessKeyPress (buf_ret);
-          }
-        }
-        break;
-      case ButtonPress:
+      if (aReport.xbutton.button == Button4
+       || aReport.xbutton.button == Button5)
+      {
+        if (aReport.type != ButtonPress)
         {
-          X_ButtonPress = aReport.xbutton.x;
-          Y_ButtonPress = aReport.xbutton.y;
+          break;
+        }
 
-          if (aReport.xbutton.button == Button1)
-          {
-            if (aReport.xbutton.state & ControlMask)
-            {
-              pick = VT_ProcessButton1Press (argc, argv, pick, (aReport.xbutton.state & ShiftMask));
-            }
-            else
-            {
-              IsDragged = Standard_True;
-              DragFirst = Standard_True;
-            }
-          }
-          else if (aReport.xbutton.button == Button3)
-          {
-            // Start rotation
-            VT_ProcessButton3Press();
-          }
+        const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0);
+        ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
+      }
+      else if (aReport.type == ButtonPress)
+      {
+        if (aButton == Aspect_VKeyMouse_LeftButton)
+        {
+          TheIsAnimating = Standard_False;
         }
+        ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
+      }
+      else
+      {
+        ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
+      }
+      ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
+      break;
+    }
+    case MotionNotify:
+    {
+      Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
+      if (anXWindow != aReport.xmotion.window)
+      {
         break;
-      case ButtonRelease:
-        {
-          if( IsDragged )
-          {
-            if( !DragFirst )
-            {
-              if (ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand()))
-              {
-                ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False);
-                ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate();
-              }
-            }
+      }
 
-            Handle( AIS_InteractiveContext ) aContext = ViewerTest::GetAISContext();
-            if( aContext.IsNull() )
-            {
-              cout << "The context is null. Please use vinit before createmesh" << endl;
-              return 0;
-            }
+      // remove all the ButtonMotionMask and process them at once
+      for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
+      {
+        if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport))
+        {
+          break;
+        }
+      }
 
-            Standard_Boolean ShiftPressed = ( aReport.xbutton.state & ShiftMask );
-            if( aReport.xbutton.button==1 )
-              if( DragFirst )
-                if( ShiftPressed )
-                {
-                  aContext->ShiftSelect (Standard_True);
-                }
-                else
-                {
-                  aContext->Select (Standard_True);
-                }
-              else
-                if( ShiftPressed )
-                {
-                  aContext->ShiftSelect(Min(X_ButtonPress, X_Motion), Min(Y_ButtonPress, Y_Motion),
-                                        Max(X_ButtonPress, X_Motion), Max(Y_ButtonPress, Y_Motion),
-                                        ViewerTest::CurrentView(), Standard_True);
-                }
-                else
-                {
-                  aContext->Select(Min(X_ButtonPress, X_Motion), Min(Y_ButtonPress, Y_Motion),
-                                   Max(X_ButtonPress, X_Motion), Max(Y_ButtonPress, Y_Motion),
-                                   ViewerTest::CurrentView(), Standard_True);
-                }
-            else
-              VT_ProcessButton3Release();
+      Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y);
+      Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
+      Aspect_VKeyFlags aFlags   = Aspect_VKeyFlags_NONE;
+      if ((aReport.xmotion.state & Button1Mask) != 0)
+      {
+        aButtons |= Aspect_VKeyMouse_LeftButton;
+      }
+      else if ((aReport.xmotion.state & Button2Mask) != 0)
+      {
+        aButtons |= Aspect_VKeyMouse_MiddleButton;
+      }
+      else if ((aReport.xmotion.state & Button3Mask) != 0)
+      {
+        aButtons |= Aspect_VKeyMouse_RightButton;
+      }
 
-            IsDragged = Standard_False;
-          }
-          else
-            VT_ProcessButton3Release();
-        }
-        break;
-      case MotionNotify:
-        {
-          if (GetWindowHandle (VT_GetWindow()) != aReport.xmotion.window)
-          {
-            break;
-          }
-          if( IsDragged )
-          {
-            if( !DragFirst )
-            {
-              if (ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand()))
-              {
-                ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False);
-              }
-            }
+      if (aReport.xmotion.state & ControlMask)
+      {
+        aFlags |= Aspect_VKeyFlags_CTRL;
+      }
+      if (aReport.xmotion.state & ShiftMask)
+      {
+        aFlags |= Aspect_VKeyFlags_SHIFT;
+      }
+      if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
+      {
+        aFlags |= Aspect_VKeyFlags_ALT;
+      }
 
-            X_Motion = aReport.xmotion.x;
-            Y_Motion = aReport.xmotion.y;
-            DragFirst = Standard_False;
-
-            Window aWindow = GetWindowHandle(VT_GetWindow());
-            Window aRoot;
-            int anX, anY;
-            unsigned int aWidth, aHeight, aBorderWidth, aDepth;
-            XGetGeometry (aDisplay, aWindow, &aRoot, &anX, &anY, &aWidth, &aHeight, &aBorderWidth, &aDepth);
-            GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion);
-            ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, AIS_DS_Displayed);
-            ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate();
-          }
-          else
-          {
-            X_Motion = aReport.xmotion.x;
-            Y_Motion = aReport.xmotion.y;
-
-            // remove all the ButtonMotionMaskr
-            while( XCheckMaskEvent( aDisplay, ButtonMotionMask, &aReport) ) ;
-
-            if ( aReport.xmotion.state & ControlMask ) {
-              if ( aReport.xmotion.state & Button1Mask ) {
-                ProcessControlButton1Motion();
-              }
-              else if ( aReport.xmotion.state & Button2Mask ) {
-                VT_ProcessControlButton2Motion();
-              }
-              else if ( aReport.xmotion.state & Button3Mask ) {
-                VT_ProcessControlButton3Motion();
-              }
-            }
-            else
-            {
-              VT_ProcessMotion();
-            }
-          }
-        }
-        break;
-}
-return pick;
+      ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
+      ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
+      break;
+    }
+  }
+  return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
 }
 
 //==============================================================================
 //function : VProcessEvents
-//purpose  : call by Tk_CreateFileHandler() to be able to manage the
-//       event in the Viewer window
+//purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
 //==============================================================================
-
-static void VProcessEvents(ClientData,int)
+static void VProcessEvents (ClientData theDispX, int)
 {
-  NCollection_Vector<int> anEventNumbers;
-  // Get number of messages from every display
-  for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
-       anIter (ViewerTest_myDrivers); anIter.More(); anIter.Next())
+  Display* aDispX = (Display* )theDispX;
+  Handle(Aspect_DisplayConnection) aDispConn;
+  for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
+       aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
+  {
+    const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
+    if (aDispConnTmp->GetDisplay() == aDispX)
+    {
+      aDispConn = aDispConnTmp;
+      break;
+    }
+  }
+  if (aDispConn.IsNull())
   {
-    anEventNumbers.Append(XPending (anIter.Key2()->GetDisplayConnection()->GetDisplay()));
+    std::cerr << "Error: ViewerTest is unable processing messages for unknown X Display\n";
+    return;
   }
-    // Handle events for every display
-  int anEventIter = 0;
-  for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
-       anIter (ViewerTest_myDrivers); anIter.More(); anIter.Next(), anEventIter++)
+
+  // process new events in queue
+  SetDisplayConnection (aDispConn);
+  int aNbRemain = 0;
+  for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
   {
-    for (int i = 0; i < anEventNumbers.Value(anEventIter) &&
-         XPending (anIter.Key2()->GetDisplayConnection()->GetDisplay()) > 0; ++i)
+    const int anEventResult = ViewerMainLoop (0, NULL);
+    if (anEventResult == 0)
+    {
+      return;
+    }
+
+    aNbRemain = XPending (aDispX);
+    if (++anEventIter >= aNbEventsMax
+     || aNbRemain <= 0)
     {
-      SetDisplayConnection (anIter.Key2()->GetDisplayConnection());
-      int anEventResult = ViewerMainLoop( 0, NULL);
-      // If window is closed or context was not found finish current event processing loop
-      if (!anEventResult)
-       return;
+      break;
     }
   }
 
-  SetDisplayConnection (ViewerTest::GetAISContext()->CurrentViewer()->Driver()->GetDisplayConnection());
+  // Listening X events through Tcl_CreateFileHandler() callback is fragile,
+  // it is possible that new events will arrive to queue before the end of this callback
+  // so that either this callback should go into an infinite loop (blocking processing of other events)
+  // or to keep unprocessed events till the next queue update (which can arrive not soon).
+  // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
+  if (aNbRemain != 0)
+  {
+    XEvent aDummyEvent;
+    memset (&aDummyEvent, 0, sizeof(aDummyEvent));
+    aDummyEvent.type = ClientMessage;
+    aDummyEvent.xclient.format = 32;
+    XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
+    XFlush (aDispX);
+  }
 
+  if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
+  {
+    SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
+  }
 }
 #endif
 
@@ -2808,7 +3713,7 @@ static void OSWindowSetup()
 
   XSetWMHints( aDisplay, window, &wmhints);
 
-  XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask |
+  XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask | KeyReleaseMask |
     ButtonPressMask | ButtonReleaseMask |
     StructureNotifyMask |
     PointerMotionMask |
@@ -2966,339 +3871,145 @@ static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const
 }
 
 //==============================================================================
-//function : VRepaint
-//purpose  :
-//==============================================================================
-static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
-{
-  Handle(V3d_View) aView = ViewerTest::CurrentView();
-  if (aView.IsNull())
-  {
-    std::cout << "Error: no active viewer!\n";
-    return 1;
-  }
-
-  Standard_Boolean isImmediateUpdate = Standard_False;
-  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
-  {
-    TCollection_AsciiString anArg (theArgVec[anArgIter]);
-    anArg.LowerCase();
-    if (anArg == "-immediate")
-    {
-      isImmediateUpdate = Standard_True;
-      if (anArgIter + 1 < theArgNb
-       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
-      {
-        ++anArgIter;
-      }
-    }
-    else
-    {
-      std::cout << "Syntax error at '" << anArg << "'\n";
-    }
-  }
-
-  if (isImmediateUpdate)
-  {
-    aView->RedrawImmediate();
-  }
-  else
-  {
-    aView->Redraw();
-  }
-  return 0;
-}
-
-//==============================================================================
-//function : VClear
-//purpose  : Remove all the object from the viewer
-//Draw arg : No args
-//==============================================================================
-
-static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
-{
-  Handle(V3d_View) V = ViewerTest::CurrentView();
-  if(!V.IsNull())
-    ViewerTest::Clear();
-  return 0;
-}
-
-//==============================================================================
-//function : VPick
-//purpose  :
-//==============================================================================
-
-static int VPick(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
-{ if (ViewerTest::CurrentView().IsNull() ) return 1;
-
-if ( argc < 4 ) {
-  di << argv[0] << "Invalid number of arguments\n";
-  return 1;
-}
-
-while (ViewerMainLoop( argc, argv)) {
-}
-
-return 0;
-}
-
-//==============================================================================
-//function : VSetBg
-//purpose  : Load image as background
-//==============================================================================
-
-static int VSetBg(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
-{
-  if (argc < 2 || argc > 3)
-  {
-    di << "Usage : " << argv[0] << " imagefile [filltype] : Load image as background\n";
-    di << "filltype can be one of CENTERED, TILED, STRETCH, NONE\n";
-    return 1;
-  }
-
-  Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
-  if(AISContext.IsNull())
-  {
-    di << "use 'vinit' command before " << argv[0] << "\n";
-    return 1;
-  }
-
-  Aspect_FillMethod aFillType = Aspect_FM_CENTERED;
-  if (argc == 3)
-  {
-    const char* szType = argv[2];
-    if      (strcmp(szType, "NONE"    ) == 0) aFillType = Aspect_FM_NONE;
-    else if (strcmp(szType, "CENTERED") == 0) aFillType = Aspect_FM_CENTERED;
-    else if (strcmp(szType, "TILED"   ) == 0) aFillType = Aspect_FM_TILED;
-    else if (strcmp(szType, "STRETCH" ) == 0) aFillType = Aspect_FM_STRETCH;
-    else
-    {
-      di << "Wrong fill type : " << szType << "\n";
-      di << "Must be one of CENTERED, TILED, STRETCH, NONE\n";
-      return 1;
-    }
-  }
-
-  Handle(V3d_View) V3dView = ViewerTest::CurrentView();
-  V3dView->SetBackgroundImage(argv[1], aFillType, Standard_True);
-
-  return 0;
-}
-
-//==============================================================================
-//function : VSetBgMode
-//purpose  : Change background image fill type
-//==============================================================================
-
-static int VSetBgMode(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
-{
-  if (argc != 2)
-  {
-    di << "Usage : " << argv[0] << " filltype : Change background image mode\n";
-    di << "filltype must be one of CENTERED, TILED, STRETCH, NONE\n";
-    return 1;
-  }
-
-  Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
-  if(AISContext.IsNull())
-  {
-    di << "use 'vinit' command before " << argv[0] << "\n";
-    return 1;
-  }
-  Aspect_FillMethod aFillType = Aspect_FM_NONE;
-  const char* szType = argv[1];
-  if      (strcmp(szType, "NONE"    ) == 0) aFillType = Aspect_FM_NONE;
-  else if (strcmp(szType, "CENTERED") == 0) aFillType = Aspect_FM_CENTERED;
-  else if (strcmp(szType, "TILED"   ) == 0) aFillType = Aspect_FM_TILED;
-  else if (strcmp(szType, "STRETCH" ) == 0) aFillType = Aspect_FM_STRETCH;
-  else
-  {
-    di << "Wrong fill type : " << szType << "\n";
-    di << "Must be one of CENTERED, TILED, STRETCH, NONE\n";
-    return 1;
-  }
-  Handle(V3d_View) V3dView = ViewerTest::CurrentView();
-  V3dView->SetBgImageStyle(aFillType, Standard_True);
-  return 0;
-}
-
-//==============================================================================
-//function : VSetGradientBg
-//purpose  : Mount gradient background
+//function : VRepaint
+//purpose  :
 //==============================================================================
-static int VSetGradientBg(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
+static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
 {
-  if (argc != 8 )
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
   {
-    di << "Usage : " << argv[0] << " R1 G1 B1 R2 G2 B2 Type : Mount gradient background\n";
-    di << "R1,G1,B1,R2,G2,B2 = [0..255]\n";
-    di << "Type must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
-    di << "                    5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
+    std::cout << "Error: no active viewer!\n";
     return 1;
   }
 
-  Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
-  if(AISContext.IsNull())
-  {
-    di << "use 'vinit' command before " << argv[0] << "\n";
-    return 1;
-  }
-  if (argc == 8)
+  Standard_Boolean isImmediateUpdate = Standard_False;
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anArg == "-immediate"
+     || anArg == "-imm")
+    {
+      isImmediateUpdate = Standard_True;
+      if (anArgIter + 1 < theArgNb
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
+      {
+        ++anArgIter;
+      }
+    }
+    else if (anArg == "-continuous"
+          || anArg == "-cont"
+          || anArg == "-fps"
+          || anArg == "-framerate")
+    {
+      Standard_Real aFps = -1.0;
+      if (anArgIter + 1 < theArgNb
+       && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
+      {
+        aFps = Draw::Atof (theArgVec[++anArgIter]);
+      }
 
-    Standard_Real R1 = Draw::Atof(argv[1])/255.;
-    Standard_Real G1 = Draw::Atof(argv[2])/255.;
-    Standard_Real B1 = Draw::Atof(argv[3])/255.;
-    Quantity_Color aColor1(R1,G1,B1,Quantity_TOC_RGB);
-
-    Standard_Real R2 = Draw::Atof(argv[4])/255.;
-    Standard_Real G2 = Draw::Atof(argv[5])/255.;
-    Standard_Real B2 = Draw::Atof(argv[6])/255.;
-
-    Quantity_Color aColor2(R2,G2,B2,Quantity_TOC_RGB);
-    int aType = Draw::Atoi(argv[7]);
-    if( aType < 0 || aType > 8 )
+      ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
+      if (Abs (aFps) >= 1.0)
+      {
+        aRedrawer.Start (aView->Window(), aFps);
+      }
+      else
+      {
+        aRedrawer.Stop();
+      }
+    }
+    else
     {
-      di << "Wrong fill type \n";
-      di << "Must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
-      di << "               5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
+      std::cout << "Syntax error at '" << anArg << "'\n";
       return 1;
     }
-
-    Aspect_GradientFillMethod aMethod = Aspect_GradientFillMethod(aType);
-
-    Handle(V3d_View) V3dView = ViewerTest::CurrentView();
-    V3dView->SetBgGradientColors( aColor1, aColor2, aMethod, 1);
   }
 
-  return 0;
-}
-
-//==============================================================================
-//function : VSetGradientBgMode
-//purpose  : Change gradient background fill style
-//==============================================================================
-static int VSetGradientBgMode(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
-{
-  if (argc != 2 )
+  if (isImmediateUpdate)
   {
-    di << "Usage : " << argv[0] << " Type : Change gradient background fill type\n";
-    di << "Type must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
-    di << "                    5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
-    return 1;
+    aView->RedrawImmediate();
   }
-
-  Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
-  if(AISContext.IsNull())
+  else
   {
-    di << "use 'vinit' command before " << argv[0] << "\n";
-    return 1;
+    aView->Redraw();
   }
-  if (argc == 2)
-  {
-    int aType = Draw::Atoi(argv[1]);
-    if( aType < 0 || aType > 8 )
-    {
-      di << "Wrong fill type \n";
-      di << "Must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
-      di << "               5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
-      return 1;
-    }
-
-    Aspect_GradientFillMethod aMethod = Aspect_GradientFillMethod(aType);
+  return 0;
+}
 
-    Handle(V3d_View) V3dView = ViewerTest::CurrentView();
-    V3dView->SetBgGradientStyle( aMethod, 1 );
-  }
+//==============================================================================
+//function : VClear
+//purpose  : Remove all the object from the viewer
+//Draw arg : No args
+//==============================================================================
 
+static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
+{
+  Handle(V3d_View) V = ViewerTest::CurrentView();
+  if(!V.IsNull())
+    ViewerTest::Clear();
   return 0;
 }
 
 //==============================================================================
-//function : VSetColorBg
-//purpose  : Set color background
+//function : VPick
+//purpose  :
 //==============================================================================
-static int VSetColorBg(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
+
+static int VPick (Draw_Interpretor& ,
+                  Standard_Integer theNbArgs,
+                  const char** theArgVec)
 {
-  if (argc != 4 )
+  if (ViewerTest::CurrentView().IsNull())
   {
-    di << "Usage : " << argv[0] << " R G B : Set color background\n";
-    di << "R,G,B = [0..255]\n";
     return 1;
   }
 
-  Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
-  if(AISContext.IsNull())
+  if (theNbArgs < 4)
   {
-    di << "use 'vinit' command before " << argv[0] << "\n";
+    std::cout << "Syntax error: Invalid number of arguments\n";
     return 1;
   }
-  if (argc == 4)
-  {
-
-    Standard_Real R = Draw::Atof(argv[1])/255.;
-    Standard_Real G = Draw::Atof(argv[2])/255.;
-    Standard_Real B = Draw::Atof(argv[3])/255.;
-    Quantity_Color aColor(R,G,B,Quantity_TOC_RGB);
 
-    Handle(V3d_View) V3dView = ViewerTest::CurrentView();
-    V3dView->SetBackgroundColor( aColor );
-    V3dView->Update();
+  while (ViewerMainLoop (theNbArgs, theArgVec))
+  {
+    //
   }
 
   return 0;
 }
 
-//==============================================================================
-//function : VSetDefaultBg
-//purpose  : Set default viewer background fill color
-//==============================================================================
-static int VSetDefaultBg (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
+namespace
 {
-  if (theArgNb != 4
-   && theArgNb != 8)
-  {
-    std::cout << "Error: wrong syntax! See usage:\n";
-    theDI.PrintHelp (theArgVec[0]);
-    return 1;
-  }
-
-  ViewerTest_DefaultBackground.FillMethod =
-    theArgNb == 4 ? Aspect_GFM_NONE
-                  : (Aspect_GradientFillMethod) Draw::Atoi (theArgVec[7]);
-
-  if (theArgNb == 4)
-  {
-    Standard_Real R = Draw::Atof (theArgVec[1]) / 255.;
-    Standard_Real G = Draw::Atof (theArgVec[2]) / 255.;
-    Standard_Real B = Draw::Atof (theArgVec[3]) / 255.;
-    ViewerTest_DefaultBackground.FlatColor.SetValues (R, G, B, Quantity_TOC_RGB);
-  }
-  else
-  {
-    Standard_Real R1 = Draw::Atof (theArgVec[1]) / 255.;
-    Standard_Real G1 = Draw::Atof (theArgVec[2]) / 255.;
-    Standard_Real B1 = Draw::Atof (theArgVec[3]) / 255.;
-    ViewerTest_DefaultBackground.GradientColor1.SetValues (R1, G1, B1, Quantity_TOC_RGB);
-
-    Standard_Real R2 = Draw::Atof (theArgVec[4]) / 255.;
-    Standard_Real G2 = Draw::Atof (theArgVec[5]) / 255.;
-    Standard_Real B2 = Draw::Atof (theArgVec[6]) / 255.;
-    ViewerTest_DefaultBackground.GradientColor2.SetValues (R2, G2, B2, Quantity_TOC_RGB);
-  }
 
-  for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
-       anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
+  //! Changes the background
+  //! @param theDrawInterpretor the interpreter of the Draw Harness application
+  //! @param theNumberOfCommandLineArguments the number of passed command line arguments
+  //! @param theCommandLineArguments the array of command line arguments
+  //! @return TCL_OK if changing was successful, or TCL_ERROR otherwise
+  static int vbackground (Draw_Interpretor&      theDrawInterpretor,
+                          const Standard_Integer theNumberOfCommandLineArguments,
+                          const char** const     theCommandLineArguments)
   {
-    const Handle(V3d_Viewer)& aViewer = anIter.Value()->CurrentViewer();
-    aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
-    aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
-                                         ViewerTest_DefaultBackground.GradientColor2,
-                                         ViewerTest_DefaultBackground.FillMethod);
+    if (theNumberOfCommandLineArguments < 1)
+    {
+      return TCL_ERROR;
+    }
+    BackgroundChanger aBackgroundChanger;
+    if (!aBackgroundChanger.ProcessCommandLine (theDrawInterpretor,
+                                                theNumberOfCommandLineArguments,
+                                                theCommandLineArguments))
+    {
+      theDrawInterpretor << "Wrong command arguments.\n"
+                            "Type 'help "
+                         << theCommandLineArguments[0] << "' for information about command options and its arguments.\n";
+      return TCL_ERROR;
+    }
+    return TCL_OK;
   }
 
-  return 0;
-}
+} // namespace
 
 //==============================================================================
 //function : VScale
@@ -4759,60 +5470,23 @@ static int VZLayer (Draw_Interpretor& theDI,
     ++anArgIter;
   }
 
-  TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
-  if (aFirstArg.IsIntegerValue())
-  {
-    ++anArgIter;
-    aLayerId = aFirstArg.IntegerValue();
-  }
-  else
   {
-    aFirstArg.LowerCase();
-    if (aFirstArg == "default"
-     || aFirstArg == "def")
-    {
-      aLayerId = Graphic3d_ZLayerId_Default;
-      ++anArgIter;
-    }
-    else if (aFirstArg == "top")
-    {
-      aLayerId = Graphic3d_ZLayerId_Top;
-      ++anArgIter;
-    }
-    else if (aFirstArg == "topmost")
-    {
-      aLayerId = Graphic3d_ZLayerId_Topmost;
-      ++anArgIter;
-    }
-    else if (aFirstArg == "overlay"
-          || aFirstArg == "toposd")
-    {
-      aLayerId = Graphic3d_ZLayerId_TopOSD;
-      ++anArgIter;
-    }
-    else if (aFirstArg == "underlay"
-          || aFirstArg == "botosd")
+    TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
+    if (aFirstArg.IsIntegerValue())
     {
-      aLayerId = Graphic3d_ZLayerId_BotOSD;
       ++anArgIter;
+      aLayerId = aFirstArg.IntegerValue();
     }
     else
     {
-      TColStd_SequenceOfInteger aLayers;
-      aViewer->GetAllZLayers (aLayers);
-      for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
+      if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
       {
-        Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
-        if (TCollection_AsciiString::IsSameString (aSettings.Name(), aFirstArg, Standard_False))
-        {
-          aLayerId = aLayeriter.Value();
-          ++anArgIter;
-          break;
-        }
+        ++anArgIter;
       }
     }
   }
 
+  Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
   for (; anArgIter < theArgNb; ++anArgIter)
   {
     // perform operation
@@ -4834,6 +5508,34 @@ static int VZLayer (Draw_Interpretor& theDI,
 
       theDI << aLayerId;
     }
+    else if (anArg == "-insertbefore"
+          && anArgIter + 1 < theArgNb
+          && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
+    {
+      ++anArgIter;
+      aLayerId = Graphic3d_ZLayerId_UNKNOWN;
+      if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
+      {
+        std::cout << "Error: can not add a new z layer!\n";
+        return 0;
+      }
+
+      theDI << aLayerId;
+    }
+    else if (anArg == "-insertafter"
+          && anArgIter + 1 < theArgNb
+          && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
+    {
+      ++anArgIter;
+      aLayerId = Graphic3d_ZLayerId_UNKNOWN;
+      if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
+      {
+        std::cout << "Error: can not add a new z layer!\n";
+        return 0;
+      }
+
+      theDI << aLayerId;
+    }
     else if (anArg == "-del"
           || anArg == "-delete"
           || anArg == "del")
@@ -5075,6 +5777,10 @@ static int VZLayer (Draw_Interpretor& theDI,
       {
         aSettings.SetEnvironmentTexture (toEnable);
       }
+      else if (aSubOp == "raytracing")
+      {
+        aSettings.SetRaytracable (toEnable);
+      }
 
       aViewer->SetZLayerSettings (aLayerId, aSettings);
     }
@@ -5238,102 +5944,257 @@ static int VGrid (Draw_Interpretor& /*theDI*/,
                   Standard_Integer  theArgNb,
                   const char**      theArgVec)
 {
-  // get the active view
   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
   if (aView.IsNull() || aViewer.IsNull())
   {
-    std::cerr << "No active view. Please call vinit.\n";
+    std::cerr << "Error: no active view\n";
     return 1;
   }
 
   Aspect_GridType     aType = aViewer->GridType();
   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
+  Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
+  Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
+  bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
-  Standard_Integer anIter = 1;
-  for (; anIter < theArgNb; ++anIter)
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
-    const char* aValue = theArgVec[anIter];
-    if (anUpdateTool.parseRedrawMode (aValue))
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
     {
       continue;
     }
-    else if (*aValue == 'r')
+    else if (anArgIter + 1 < theArgNb
+          && anArg == "-type")
+    {
+      TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
+      anArgNext.LowerCase();
+      if (anArgNext == "r"
+       || anArgNext == "rect"
+       || anArgNext == "rectangular")
+      {
+        aType = Aspect_GT_Rectangular;
+      }
+      else if (anArgNext == "c"
+            || anArgNext == "circ"
+            || anArgNext == "circular")
+      {
+        aType = Aspect_GT_Circular;
+      }
+      else
+      {
+        std::cout << "Syntax error at '" << anArgNext << "'\n";
+        return 1;
+      }
+    }
+    else if (anArgIter + 1 < theArgNb
+          && anArg == "-mode")
+    {
+      TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
+      anArgNext.LowerCase();
+      if (anArgNext == "l"
+       || anArgNext == "line"
+       || anArgNext == "lines")
+      {
+        aMode = Aspect_GDM_Lines;
+      }
+      else if (anArgNext == "p"
+            || anArgNext == "point"
+            || anArgNext == "points")
+      {
+        aMode = Aspect_GDM_Points;
+      }
+      else
+      {
+        std::cout << "Syntax error at '" << anArgNext << "'\n";
+        return 1;
+      }
+    }
+    else if (anArgIter + 2 < theArgNb
+          && (anArg == "-origin"
+           || anArg == "-orig"))
+    {
+      hasOrigin = true;
+      aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
+                              Draw::Atof (theArgVec[anArgIter + 2]));
+      anArgIter += 2;
+    }
+    else if (anArgIter + 2 < theArgNb
+          && anArg == "-step")
+    {
+      hasStep = true;
+      aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
+                            Draw::Atof (theArgVec[anArgIter + 2]));
+      if (aNewStepXY.x() <= 0.0
+       || aNewStepXY.y() <= 0.0)
+      {
+        std::cout << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'\n";
+        return 1;
+      }
+      anArgIter += 2;
+    }
+    else if (anArgIter + 1 < theArgNb
+          && (anArg == "-angle"
+           || anArg == "-rotangle"
+           || anArg == "-rotationangle"))
+    {
+      hasRotAngle = true;
+      aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
+    }
+    else if (anArgIter + 1 < theArgNb
+          && (anArg == "-zoffset"
+           || anArg == "-dz"))
+    {
+      hasZOffset = true;
+      aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
+    }
+    else if (anArgIter + 1 < theArgNb
+          && anArg == "-radius")
+    {
+      hasSize = true;
+      ++anArgIter;
+      aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
+      if (aNewStepXY.x() <= 0.0)
+      {
+        std::cout << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'\n";
+        return 1;
+      }
+    }
+    else if (anArgIter + 2 < theArgNb
+          && anArg == "-size")
+    {
+      hasSize = true;
+      aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
+                            Draw::Atof (theArgVec[anArgIter + 2]));
+      if (aNewStepXY.x() <= 0.0
+       || aNewStepXY.y() <= 0.0)
+      {
+        std::cout << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'\n";
+        return 1;
+      }
+      anArgIter += 2;
+    }
+    else if (anArg == "r"
+          || anArg == "rect"
+          || anArg == "rectangular")
     {
       aType = Aspect_GT_Rectangular;
     }
-    else if (*aValue == 'c')
+    else if (anArg == "c"
+          || anArg == "circ"
+          || anArg == "circular")
     {
       aType = Aspect_GT_Circular;
     }
-    else if (*aValue == 'l')
+    else if (anArg == "l"
+          || anArg == "line"
+          || anArg == "lines")
     {
       aMode = Aspect_GDM_Lines;
     }
-    else if (*aValue == 'p')
+    else if (anArg == "p"
+          || anArg == "point"
+          || anArg == "points")
     {
       aMode = Aspect_GDM_Points;
     }
-    else if (strcmp (aValue, "off" ) == 0)
+    else if (anArgIter + 1 >= theArgNb
+          && anArg == "off")
     {
       aViewer->DeactivateGrid();
       return 0;
     }
     else
     {
-      break;
+      std::cout << "Syntax error at '" << anArg << "'\n";
+      return 1;
     }
   }
 
-  Standard_Integer aTail = (theArgNb - anIter);
-  if (aTail == 0)
-  {
-    aViewer->ActivateGrid (aType, aMode);
-    return 0;
-  }
-  else if (aTail != 2 && aTail != 5)
-  {
-    std::cerr << "Incorrect arguments number! Usage:\n"
-              << "vgrid [off] [Mode={r|c}] [Type={l|p}] [OriginX OriginY [StepX/StepRadius StepY/DivNb RotAngle]]\n";
-    return 1;
-  }
-
-  Standard_Real anOriginX, anOriginY, aRotAngle;
   if (aType == Aspect_GT_Rectangular)
   {
-    Standard_Real aRStepX, aRStepY;
-    aViewer->RectangularGridValues (anOriginX, anOriginY, aRStepX, aRStepY, aRotAngle);
-
-    anOriginX = Draw::Atof (theArgVec[anIter++]);
-    anOriginY = Draw::Atof (theArgVec[anIter++]);
-    if (aTail == 5)
+    Graphic3d_Vec2d anOrigXY, aStepXY;
+    Standard_Real aRotAngle = 0.0;
+    aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
+    if (hasOrigin)
+    {
+      anOrigXY = aNewOriginXY;
+    }
+    if (hasStep)
+    {
+      aStepXY = aNewStepXY;
+    }
+    if (hasRotAngle)
+    {
+      aRotAngle = aNewRotAngle;
+    }
+    aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
+    if (hasSize || hasZOffset)
     {
-      aRStepX   = Draw::Atof (theArgVec[anIter++]);
-      aRStepY   = Draw::Atof (theArgVec[anIter++]);
-      aRotAngle = Draw::Atof (theArgVec[anIter++]);
+      Graphic3d_Vec3d aSize;
+      aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
+      if (hasSize)
+      {
+        aSize.x() = aNewSizeXY.x();
+        aSize.y() = aNewSizeXY.y();
+      }
+      if (hasZOffset)
+      {
+        aSize.z() = aNewZOffset;
+      }
+      aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
     }
-    aViewer->SetRectangularGridValues (anOriginX, anOriginY, aRStepX, aRStepY, aRotAngle);
-    aViewer->ActivateGrid (aType, aMode);
   }
   else if (aType == Aspect_GT_Circular)
   {
+    Graphic3d_Vec2d anOrigXY;
     Standard_Real aRadiusStep;
     Standard_Integer aDivisionNumber;
-    aViewer->CircularGridValues (anOriginX, anOriginY, aRadiusStep, aDivisionNumber, aRotAngle);
-
-    anOriginX = Draw::Atof (theArgVec[anIter++]);
-    anOriginY = Draw::Atof (theArgVec[anIter++]);
-    if (aTail == 5)
+    Standard_Real aRotAngle = 0.0;
+    aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
+    if (hasOrigin)
+    {
+      anOrigXY = aNewOriginXY;
+    }
+    if (hasStep)
+    {
+      aRadiusStep     = aNewStepXY[0];
+      aDivisionNumber = (int )aNewStepXY[1];
+      if (aDivisionNumber < 1)
+      {
+        std::cout << "Syntax error: invalid division number '" << aNewStepXY[1] << "'\n";
+        return 1;
+      }
+    }
+    if (hasRotAngle)
     {
-      aRadiusStep     = Draw::Atof (theArgVec[anIter++]);
-      aDivisionNumber = Draw::Atoi (theArgVec[anIter++]);
-      aRotAngle       = Draw::Atof (theArgVec[anIter++]);
+      aRotAngle = aNewRotAngle;
     }
 
-    aViewer->SetCircularGridValues (anOriginX, anOriginY, aRadiusStep, aDivisionNumber, aRotAngle);
-    aViewer->ActivateGrid (aType, aMode);
+    aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
+    if (hasSize || hasZOffset)
+    {
+      Standard_Real aRadius = 0.0, aZOffset = 0.0;
+      aViewer->CircularGridGraphicValues (aRadius, aZOffset);
+      if (hasSize)
+      {
+        aRadius = aNewSizeXY.x();
+        if (aNewSizeXY.y() != 0.0)
+        {
+          std::cout << "Syntax error: circular size should be specified as radius\n";
+          return 1;
+        }
+      }
+      if (hasZOffset)
+      {
+        aZOffset = aNewZOffset;
+      }
+      aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
+    }
   }
-
+  aViewer->ActivateGrid (aType, aMode);
   return 0;
 }
 
@@ -5928,6 +6789,8 @@ static int VCaps (Draw_Interpretor& theDI,
     theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
     theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
+    theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
+    theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
     return 0;
   }
 
@@ -6060,16 +6923,54 @@ static int VCaps (Draw_Interpretor& theDI,
         aCaps->ffpEnable = Standard_False;
       }
     }
-    else if (anArgCase == "-stereo"
-          || anArgCase == "-quadbuffer")
+    else if (anArgCase == "-stereo"
+          || anArgCase == "-quadbuffer")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aCaps->contextStereo = toEnable;
+    }
+    else if (anArgCase == "-noext"
+          || anArgCase == "-noextensions"
+          || anArgCase == "-noextension")
+    {
+      Standard_Boolean toDisable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toDisable))
+      {
+        --anArgIter;
+      }
+      aCaps->contextNoExtensions = toDisable;
+    }
+    else if (anArgCase == "-maxversion"
+          || anArgCase == "-upperversion"
+          || anArgCase == "-limitversion")
     {
-      Standard_Boolean toEnable = Standard_True;
-      if (++anArgIter < theArgNb
-      && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
+      Standard_Integer aVer[2] = { -2, -1 };
+      for (Standard_Integer aValIter = 0; aValIter < 2; ++aValIter)
       {
-        --anArgIter;
+        if (anArgIter + 1 < theArgNb)
+        {
+          const TCollection_AsciiString aStr (theArgVec[anArgIter + 1]);
+          if (aStr.IsIntegerValue())
+          {
+            aVer[aValIter] = aStr.IntegerValue();
+            ++anArgIter;
+          }
+        }
       }
-      aCaps->contextStereo = toEnable;
+      if (aVer[0] < -1
+       || aVer[1] < -1)
+      {
+        std::cout << "Syntax error at '" << anArgCase << "'\n";
+        return 1;
+      }
+      aCaps->contextMajorVersionUpper = aVer[0];
+      aCaps->contextMinorVersionUpper = aVer[1];
     }
     else
     {
@@ -6168,41 +7069,52 @@ static int VReadPixel (Draw_Interpretor& theDI,
   {
     TCollection_AsciiString aParam (theArgVec[anIter]);
     aParam.LowerCase();
-    if (aParam == "rgb")
+    if (aParam == "-rgb"
+     || aParam == "rgb")
     {
       aFormat     = Image_Format_RGB;
       aBufferType = Graphic3d_BT_RGB;
     }
-    else if (aParam == "hls")
+    else if (aParam == "-hls"
+          || aParam == "hls")
     {
       aFormat     = Image_Format_RGB;
       aBufferType = Graphic3d_BT_RGB;
       toShowHls   = Standard_True;
     }
-    else if (aParam == "rgbf")
+    else if (aParam == "-rgbf"
+          || aParam == "rgbf")
     {
       aFormat     = Image_Format_RGBF;
       aBufferType = Graphic3d_BT_RGB;
     }
-    else if (aParam == "rgba")
+    else if (aParam == "-rgba"
+          || aParam == "rgba")
     {
       aFormat     = Image_Format_RGBA;
       aBufferType = Graphic3d_BT_RGBA;
     }
-    else if (aParam == "rgbaf")
+    else if (aParam == "-rgbaf"
+          || aParam == "rgbaf")
     {
       aFormat     = Image_Format_RGBAF;
       aBufferType = Graphic3d_BT_RGBA;
     }
-    else if (aParam == "depth")
+    else if (aParam == "-depth"
+          || aParam == "depth")
     {
       aFormat     = Image_Format_GrayF;
       aBufferType = Graphic3d_BT_Depth;
     }
-    else if (aParam == "name")
+    else if (aParam == "-name"
+          || aParam == "name")
     {
       toShowName = Standard_True;
     }
+    else
+    {
+      std::cout << "Syntax error at '" << aParam << "'\n";
+    }
   }
 
   Image_PixMap anImage;
@@ -6444,9 +7356,9 @@ static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const
     }
     else if (anArg == "-exitonclose")
     {
-      Draw_ToExitOnCloseView = true;
+      ViewerTest_EventManager::ToExitOnCloseView() = true;
       if (anArgIter + 1 < theArgNb
-       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], Draw_ToExitOnCloseView))
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
       {
         ++anArgIter;
       }
@@ -6454,9 +7366,9 @@ static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const
     else if (anArg == "-closeonescape"
           || anArg == "-closeonesc")
     {
-      Draw_ToCloseViewOnEsc = true;
+      ViewerTest_EventManager::ToCloseViewOnEscape() = true;
       if (anArgIter + 1 < theArgNb
-       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], Draw_ToCloseViewOnEsc))
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
       {
         ++anArgIter;
       }
@@ -6632,71 +7544,93 @@ static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const
 //           pixel positions (x1,y1),...,(xn,yn)
 //           4) any of these selections with shift button pressed
 //=======================================================================
-static Standard_Integer VSelect (Draw_Interpretor& di,
-                                 Standard_Integer argc,
-                                 const char ** argv)
+static Standard_Integer VSelect (Draw_Interpretor& ,
+                                 Standard_Integer theNbArgs,
+                                 const char** theArgVec)
 {
-  if(argc < 3)
-  {
-    di << "Usage : " << argv[0] << " x1 y1 [x2 y2 [... xn yn]] [shift_selection = 1|0]\n";
-    return 1;
-  }
-
-  Handle(AIS_InteractiveContext) myAIScontext = ViewerTest::GetAISContext();
-  if(myAIScontext.IsNull())
+  const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
+  if (aCtx.IsNull())
   {
-    di << "use 'vinit' command before " << argv[0] << "\n";
+    std::cout << "Error: no active View\n";
     return 1;
   }
 
-  const Standard_Boolean isShiftSelection = (argc > 3 && !(argc % 2) && (atoi (argv[argc - 1]) == 1));
-  Standard_Integer aCoordsNb = isShiftSelection ? argc - 2 : argc - 1;
-  TCollection_AsciiString anArg;
-  anArg = isShiftSelection ? argv[argc - 3] : argv[argc - 2];
-  anArg.LowerCase();
-  if (anArg == "-allowoverlap")
+  NCollection_Sequence<Graphic3d_Vec2i> aPnts;
+  bool isShiftSelection = false, toAllowOverlap = false;
+  for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
   {
-    Standard_Boolean isValidated = isShiftSelection ? argc == 8
-      : argc == 7;
-    if (!isValidated)
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anArg == "-allowoverlap")
+    {
+      toAllowOverlap = true;
+      if (anArgIter + 1 < theNbArgs
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
+      {
+        ++anArgIter;
+      }
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && anArg.IsIntegerValue()
+          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
+    {
+      const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
+      aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
+    }
+    else if (anArgIter + 1 == theNbArgs
+          && anArg.IsIntegerValue())
     {
-      di << "Wrong number of arguments! -allowoverlap key is applied only for rectangle selection";
+      isShiftSelection = anArg.IntegerValue() == 1;
+    }
+    else
+    {
+      std::cout << "Syntax error at '" << anArg << "'\n";
       return 1;
     }
-
-    Standard_Integer isToAllow = isShiftSelection ? Draw::Atoi(argv[argc - 2]) : Draw::Atoi(argv[argc - 1]);
-    myAIScontext->MainSelector()->AllowOverlapDetection (isToAllow != 0);
-    aCoordsNb -= 2;
+  }
+  if (toAllowOverlap
+   && aPnts.Length() != 2)
+  {
+    std::cout << "Syntax error: -allowoverlap key is applied only for rectangle selection\n";
+    return 1;
+  }
+  if (toAllowOverlap)
+  {
+    aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
   }
 
   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
-  aCurrentEventManager->MoveTo(atoi(argv[1]),atoi(argv[2]));
-  if(aCoordsNb == 2)
+  if (aPnts.IsEmpty())
   {
-    if(isShiftSelection)
-      aCurrentEventManager->ShiftSelect();
+    if (isShiftSelection)
+    {
+      aCtx->ShiftSelect (false);
+    }
     else
-      aCurrentEventManager->Select();
+    {
+      aCtx->Select (false);
+    }
+    aCtx->CurrentViewer()->Invalidate();
   }
-  else if(aCoordsNb == 4)
+  else if (aPnts.Length() == 2)
   {
-    if(isShiftSelection)
-      aCurrentEventManager->ShiftSelect (atoi (argv[1]), atoi (argv[2]), atoi (argv[3]), atoi (argv[4]), Standard_False);
-    else
-      aCurrentEventManager->Select (atoi (argv[1]), atoi (argv[2]), atoi (argv[3]), atoi (argv[4]), Standard_False);
+    if (toAllowOverlap
+     && aPnts.First().y() < aPnts.Last().y())
+    {
+      std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
+    }
+    else if (!toAllowOverlap
+           && aPnts.First().y() > aPnts.Last().y())
+    {
+      std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
+    }
+    aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection);
   }
   else
   {
-    TColgp_Array1OfPnt2d aPolyline (1,aCoordsNb / 2);
-
-    for(Standard_Integer i=1;i<=aCoordsNb / 2;++i)
-      aPolyline.SetValue(i,gp_Pnt2d(atoi(argv[2*i-1]),atoi(argv[2*i])));
-
-    if(isShiftSelection)
-      aCurrentEventManager->ShiftSelect(aPolyline);
-    else
-      aCurrentEventManager->Select(aPolyline);
+    aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection);
   }
+  aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
   return 0;
 }
 
@@ -6766,7 +7700,10 @@ static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
     return 1;
   }
 
-  ViewerTest::CurrentEventManager()->MoveTo (aMousePos.x(), aMousePos.y());
+  ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
+  ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
+  ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
+
   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
@@ -11504,52 +12441,6 @@ static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
   return 0;
 }
 
-//=======================================================================
-//function : VProgressiveMode
-//purpose  :
-//=======================================================================
-#if defined(_WIN32)
-static Standard_Integer VProgressiveMode (Draw_Interpretor& /*theDI*/,
-                                          Standard_Integer  /*theNbArgs*/,
-                                          const char**      /*theArgs*/)
-{
-  Handle(V3d_View) aView = ViewerTest::CurrentView();
-  if (aView.IsNull())
-  {
-    std::cerr << "Error: no active viewer!\n";
-    return 1;
-  }
-
-  std::cout << "Press Enter or Escape key to exit progressive rendering mode" << std::endl;
-
-  for (;;)
-  {
-    aView->Redraw();
-
-    Standard_Boolean toExit = Standard_False;
-
-    MSG aMsg;
-    while (PeekMessageW (&aMsg, NULL, 0, 0, PM_REMOVE))
-    {
-      if (aMsg.message == WM_KEYDOWN && (aMsg.wParam == 0x0d || aMsg.wParam == 0x1b))
-      {
-        toExit = Standard_True;
-      }
-
-      TranslateMessage (&aMsg);
-      DispatchMessageW (&aMsg);
-    }
-
-    if (toExit)
-    {
-      break;
-    }
-  }
-
-  return 0;
-}
-#endif
-
 //=======================================================================
 //function : VXRotate
 //purpose  :
@@ -11564,7 +12455,7 @@ static Standard_Integer VXRotate (Draw_Interpretor& di,
     di << argv[0] << "ERROR : use 'vinit' command before \n";
     return 1;
   }
-  
+
   if (argc != 3)
   {
     di << "ERROR : Usage : " << argv[0] << " name angle\n";
@@ -11626,10 +12517,10 @@ static int VManipulator (Draw_Interpretor& theDi,
                          Standard_Integer  theArgsNb,
                          const char**      theArgVec)
 {
-  Handle(V3d_View)   aView   = ViewerTest::CurrentView();
+  Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
   ViewerTest::GetAISContext()->MainSelector()->SetPickClosest (Standard_False);
-  if (aView.IsNull()
+  if (aCurrentView.IsNull()
    || aViewer.IsNull())
   {
     std::cerr << "No active viewer!\n";
@@ -11644,11 +12535,12 @@ static int VManipulator (Draw_Interpretor& theDi,
   }
 
   ViewerTest_CmdParser aCmd;
-  aCmd.AddDescription ("Manages manipulator for interactive objects:");
+  aCmd.SetDescription ("Manages manipulator for interactive objects:");
   aCmd.AddOption ("attach",         "... object - attach manipulator to an object");
   aCmd.AddOption ("adjustPosition", "... {0|1} - adjust position when attaching");
   aCmd.AddOption ("adjustSize",     "... {0|1} - adjust size when attaching ");
   aCmd.AddOption ("enableModes",    "... {0|1} - enable modes when attaching ");
+  aCmd.AddOption ("view",           "... {active | [view name]} - define view in which manipulator will be displayed, 'all' by default");
   aCmd.AddOption ("detach",         "...       - detach manipulator");
 
   aCmd.AddOption ("startTransform",   "... mouse_x mouse_y - invoke start transformation");
@@ -11662,8 +12554,10 @@ static int VManipulator (Draw_Interpretor& theDi,
   aCmd.AddOption ("autoActivate",      "... {0|1} - set activation on detection");
   aCmd.AddOption ("followTranslation", "... {0|1} - set following translation transform");
   aCmd.AddOption ("followRotation",    "... {0|1} - set following rotation transform");
+  aCmd.AddOption ("followDragging",    "... {0|1} - set following dragging transform");
   aCmd.AddOption ("gap",               "... value - set gap between sub-parts");
   aCmd.AddOption ("part",              "... axis mode {0|1} - set visual part");
+  aCmd.AddOption ("parts",             "... all axes mode {0|1} - set visual part");
   aCmd.AddOption ("pos",               "... x y z [nx ny nz [xx xy xz]] - set position of manipulator");
   aCmd.AddOption ("size",              "... size - set size of manipulator");
   aCmd.AddOption ("zoomable",          "... {0|1} - set zoom persistence");
@@ -11678,7 +12572,7 @@ static int VManipulator (Draw_Interpretor& theDi,
 
   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
 
-  TCollection_AsciiString aName (aCmd.Arg ("", 0).c_str());
+  TCollection_AsciiString aName (aCmd.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0).c_str());
 
   if (aName.IsEmpty())
   {
@@ -11722,6 +12616,7 @@ static int VManipulator (Draw_Interpretor& theDi,
     std::cout << theArgVec[0] << ": AIS object \"" << aName << "\" has been created.\n";
 
     aManipulator = new ViewerTest_AISManipulator();
+    aManipulator->SetModeActivationOnDetection (true);
     aMapAIS.Bind (aManipulator, aName);
   }
   else
@@ -11750,6 +12645,10 @@ static int VManipulator (Draw_Interpretor& theDi,
   {
     aManipulator->ChangeTransformBehavior().SetFollowRotation (aCmd.ArgBool ("followRotation"));
   }
+  if (aCmd.HasOption("followDragging", 1, Standard_True))
+  {
+    aManipulator->ChangeTransformBehavior().SetFollowDragging(aCmd.ArgBool("followDragging"));
+  }
   if (aCmd.HasOption ("gap", 1, Standard_True))
   {
     aManipulator->SetGap (aCmd.ArgFloat ("gap"));
@@ -11759,14 +12658,26 @@ static int VManipulator (Draw_Interpretor& theDi,
     Standard_Integer anAxis = aCmd.ArgInt  ("part", 0);
     Standard_Integer aMode  = aCmd.ArgInt  ("part", 1);
     Standard_Boolean aOnOff = aCmd.ArgBool ("part", 2);
-    if (aMode < 1 || aMode > 3)
+    if (aMode < 1 || aMode > 4)
     {
-      std::cerr << theArgVec[0] << " error: mode value should be in range [1, 3].\n";
+      std::cerr << theArgVec[0] << " error: mode value should be in range [1, 4].\n";
       return 1;
     }
 
     aManipulator->SetPart (anAxis, static_cast<AIS_ManipulatorMode> (aMode), aOnOff);
   }
+  if (aCmd.HasOption("parts", 2, Standard_True))
+  {
+    Standard_Integer aMode = aCmd.ArgInt("parts", 0);
+    Standard_Boolean aOnOff = aCmd.ArgBool("parts", 1);
+    if (aMode < 1 || aMode > 4)
+    {
+      std::cerr << theArgVec[0] << " error: mode value should be in range [1, 4].\n";
+      return 1;
+    }
+
+    aManipulator->SetPart(static_cast<AIS_ManipulatorMode>(aMode), aOnOff);
+  }
   if (aCmd.HasOption ("pos", 3, Standard_True))
   {
     gp_Pnt aLocation = aCmd.ArgPnt ("pos", 0);
@@ -11835,6 +12746,42 @@ static int VManipulator (Draw_Interpretor& theDi,
     }
 
     aManipulator->Attach (anObject, anOptions);
+
+    // Check view option
+    if (aCmd.HasOption ("view"))
+    {
+      if (!aCmd.HasOption ("view", 1, Standard_True))
+      {
+        return 1;
+      }
+      TCollection_AsciiString aViewString (aCmd.Arg ("view", 0).c_str());
+      Handle(V3d_View) aView;
+      if (aViewString.IsEqual ("active"))
+      {
+        aView = ViewerTest::CurrentView();
+      }
+      else // Check view name
+      {
+        ViewerTest_Names aViewNames (aViewString);
+        if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
+        {
+          std::cerr << theArgVec[0] << " error: wrong view name '" << aViewString << "'\n";
+          return 1;
+        }
+        aView = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
+        if (aView.IsNull())
+        {
+          std::cerr << theArgVec[0] << " error: cannot find view with name '" << aViewString << "'\n";
+          return 1;
+        }
+      }
+      for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
+        anIter (ViewerTest_myViews); anIter.More(); anIter.Next())
+      {
+        ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), Standard_False);
+      }
+      ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aView, Standard_True);
+    }
   }
 
   // --------------------------------------
@@ -12072,16 +13019,12 @@ static int VSelectionProperties (Draw_Interpretor& theDi,
         return 1;
       }
 
-      const Standard_Integer aNewLayer = Draw::Atoi (theArgVec[++anArgIter]);
-      if (aNewLayer != Graphic3d_ZLayerId_UNKNOWN)
+      ++anArgIter;
+      Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
+      if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
       {
-        TColStd_SequenceOfInteger aLayers;
-        aCtx->CurrentViewer()->GetAllZLayers (aLayers);
-        if (std::find (aLayers.begin(), aLayers.end(), aNewLayer) == aLayers.end())
-        {
-          std::cout << "Syntax error: Layer " << aNewLayer << " is undefined\n";
-          return 1;
-        }
+        std::cerr << "Error: wrong syntax at " << theArgVec[anArgIter] << ".\n";
+        return 1;
       }
 
       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
@@ -12345,6 +13288,258 @@ static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
   return 0;
 }
 
+//===============================================================================================
+//function : VViewCube
+//purpose  :
+//===============================================================================================
+static int VViewCube (Draw_Interpretor& ,
+                      Standard_Integer  theNbArgs,
+                      const char**      theArgVec)
+{
+  const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
+  const Handle(V3d_View)& aView = ViewerTest::CurrentView();
+  if (aContext.IsNull() || aView.IsNull())
+  {
+    std::cout << "Error: no active view.\n";
+    return 1;
+  }
+  else if (theNbArgs < 2)
+  {
+    std::cout << "Syntax error: wrong number arguments\n";
+    return 1;
+  }
+
+  Handle(AIS_ViewCube) aViewCube;
+  ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
+  Quantity_Color aColorRgb;
+  TCollection_AsciiString aName;
+  for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anUpdateTool.parseRedrawMode (anArg))
+    {
+      //
+    }
+    else if (aViewCube.IsNull())
+    {
+      aName = theArgVec[anArgIter];
+      if (aName.StartsWith ("-"))
+      {
+        std::cout << "Syntax error: object name should be specified.\n";
+        return 1;
+      }
+      Handle(AIS_InteractiveObject) aPrs;
+      GetMapOfAIS().Find2 (aName, aPrs);
+      aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
+      if (aViewCube.IsNull())
+      {
+        aViewCube = new AIS_ViewCube();
+        aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
+        aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
+        aViewCube->SetFixedAnimationLoop (false);
+      }
+    }
+    else if (anArg == "-reset")
+    {
+      aViewCube->ResetStyles();
+    }
+    else if (anArg == "-color"
+          || anArg == "-boxcolor"
+          || anArg == "-boxsidecolor"
+          || anArg == "-sidecolor"
+          || anArg == "-boxedgecolor"
+          || anArg == "-edgecolor"
+          || anArg == "-boxcornercolor"
+          || anArg == "-cornercolor"
+          || anArg == "-innercolor"
+          || anArg == "-textcolor")
+    {
+      Standard_Integer aNbParsed = ViewerTest::ParseColor (theNbArgs - anArgIter - 1,
+                                                           theArgVec + anArgIter + 1,
+                                                           aColorRgb);
+      if (aNbParsed == 0)
+      {
+        std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
+        return 1;
+      }
+      anArgIter += aNbParsed;
+      if (anArg == "-boxcolor")
+      {
+        aViewCube->SetBoxColor (aColorRgb);
+      }
+      else if (anArg == "-boxsidecolor"
+            || anArg == "-sidecolor")
+      {
+        aViewCube->BoxSideStyle()->SetColor (aColorRgb);
+        aViewCube->SynchronizeAspects();
+      }
+      else if (anArg == "-boxedgecolor"
+            || anArg == "-edgecolor")
+      {
+        aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
+        aViewCube->SynchronizeAspects();
+      }
+      else if (anArg == "-boxcornercolor"
+            || anArg == "-cornercolor")
+      {
+        aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
+        aViewCube->SynchronizeAspects();
+      }
+      else if (anArg == "-innercolor")
+      {
+        aViewCube->SetInnerColor (aColorRgb);
+      }
+      else if (anArg == "-textcolor")
+      {
+        aViewCube->SetTextColor (aColorRgb);
+      }
+      else
+      {
+        aViewCube->SetColor (aColorRgb);
+      }
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && (anArg == "-transparency"
+           || anArg == "-boxtransparency"))
+    {
+      const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
+      if (aValue < 0.0 || aValue > 1.0)
+      {
+        std::cout << "Syntax error: invalid transparency value " << theArgVec[anArgIter] << "\n";
+        return 1;
+      }
+
+      if (anArg == "-boxtransparency")
+      {
+        aViewCube->SetBoxTransparency (aValue);
+      }
+      else
+      {
+        aViewCube->SetTransparency (aValue);
+      }
+    }
+    else if (anArg == "-axes"
+          || anArg == "-edges"
+          || anArg == "-vertices"
+          || anArg == "-vertexes"
+          || anArg == "-fixedanimation")
+    {
+      bool toShow = true;
+      if (anArgIter + 1 < theNbArgs
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toShow))
+      {
+        ++anArgIter;
+      }
+      if (anArg == "-fixedanimation")
+      {
+        aViewCube->SetFixedAnimationLoop (toShow);
+      }
+      else if (anArg == "-axes")
+      {
+        aViewCube->SetDrawAxes (toShow);
+      }
+      else if (anArg == "-edges")
+      {
+        aViewCube->SetDrawEdges (toShow);
+      }
+      else
+      {
+        aViewCube->SetDrawVertices (toShow);
+      }
+    }
+    else if (anArg == "-yup"
+          || anArg == "-zup")
+    {
+      bool isOn = true;
+      if (anArgIter + 1 < theNbArgs
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], isOn))
+      {
+        ++anArgIter;
+      }
+      if (anArg == "-yup")
+      {
+        aViewCube->SetYup (isOn);
+      }
+      else
+      {
+        aViewCube->SetYup (!isOn);
+      }
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && anArg == "-font")
+    {
+      aViewCube->SetFont (theArgVec[++anArgIter]);
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && anArg == "-fontheight")
+    {
+      aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && (anArg == "-size"
+           || anArg == "-boxsize"))
+    {
+      aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
+                          anArg != "-boxsize");
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && (anArg == "-boxfacet"
+           || anArg == "-boxfacetextension"
+           || anArg == "-facetextension"
+           || anArg == "-extension"))
+    {
+      aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && (anArg == "-boxedgegap"
+           || anArg == "-edgegap"))
+    {
+      aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && (anArg == "-boxedgeminsize"
+           || anArg == "-edgeminsize"))
+    {
+      aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && (anArg == "-boxcornerminsize"
+           || anArg == "-cornerminsize"))
+    {
+      aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && anArg == "-axespadding")
+    {
+      aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && anArg == "-roundradius")
+    {
+      aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else if (anArgIter + 1 < theNbArgs
+          && anArg == "-duration")
+    {
+      aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
+    }
+    else
+    {
+      std::cout << "Syntax error: unknown argument '" << anArg << "'\n";
+      return 1;
+    }
+  }
+  if (aViewCube.IsNull())
+  {
+    std::cout << "Syntax error: wrong number of arguments\n";
+    return 1;
+  }
+
+  ViewerTest::Display (aName, aViewCube, false);
+  return 0;
+}
+
 //=======================================================================
 //function : ViewerCommands
 //purpose  :
@@ -12398,27 +13593,38 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vhelp" ,
     "vhelp            : display help on the viewer commands",
     __FILE__,VHelp,group);
+  theCommands.Add("vviewproj",
+          "vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]"
+    "\n\t\t:         [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]"
+    "\n\t\t: Setup view direction"
+    "\n\t\t:   -Yup      use Y-up convention instead of Zup (which is default)."
+    "\n\t\t:   +-X+-Y+-Z define direction as combination of DX, DY and DZ;"
+    "\n\t\t:             for example '+Z' will show front of the model,"
+    "\n\t\t:             '-X-Y+Z' will define left axonometrical view."
+    "\n\t\t:   -frame    define camera Up and Right directions (regardless Up convention);"
+    "\n\t\t:             for example '+X+Z' will show front of the model with Z-up."
+    __FILE__,VViewProj,group);
   theCommands.Add("vtop" ,
     "vtop or <T>      : Top view. Orientation +X+Y" ,
-    __FILE__,VTop,group);
+    __FILE__,VViewProj,group);
   theCommands.Add("vbottom" ,
     "vbottom          : Bottom view. Orientation +X-Y" ,
-    __FILE__,VBottom,group);
+    __FILE__,VViewProj,group);
   theCommands.Add("vleft" ,
     "vleft            : Left view. Orientation -Y+Z" ,
-    __FILE__,VLeft,group);
+    __FILE__,VViewProj,group);
   theCommands.Add("vright" ,
     "vright           : Right view. Orientation +Y+Z" ,
-    __FILE__,VRight,group);
+    __FILE__,VViewProj,group);
   theCommands.Add("vaxo" ,
     " vaxo or <A>     : Axonometric view. Orientation +X-Y+Z",
-    __FILE__,VAxo,group);
+    __FILE__,VViewProj,group);
   theCommands.Add("vfront" ,
     "vfront           : Front view. Orientation +X+Z" ,
-    __FILE__,VFront,group);
+    __FILE__,VViewProj,group);
   theCommands.Add("vback" ,
     "vback            : Back view. Orientation -X+Z" ,
-    __FILE__,VBack,group);
+    __FILE__,VViewProj,group);
   theCommands.Add("vpick" ,
     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
     VPick,group);
@@ -12437,33 +13643,107 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "   \"scale\" - specifies factor to scale computed z range.\n",
     __FILE__, VZFit, group);
   theCommands.Add("vrepaint",
-            "vrepaint [-immediate]"
-    "\n\t\t: force redraw",
+            "vrepaint [-immediate] [-continuous FPS]"
+    "\n\t\t: force redraw of active View"
+    "\n\t\t:   -immediate  flag performs redraw of immediate layers only;"
+    "\n\t\t:   -continuous activates/deactivates continuous redraw of active View,"
+    "\n\t\t:                0 means no continuous rendering,"
+    "\n\t\t:               -1 means non-stop redraws,"
+    "\n\t\t:               >0 specifies target framerate,",
     __FILE__,VRepaint,group);
   theCommands.Add("vclear",
     "vclear          : vclear"
     "\n\t\t: remove all the object from the viewer",
     __FILE__,VClear,group);
-  theCommands.Add("vsetbg",
-    "vsetbg          : vsetbg imagefile [filltype] : Load image as background",
-    __FILE__,VSetBg,group);
-  theCommands.Add("vsetbgmode",
-    "vsetbgmode      : vsetbgmode filltype : Change background image fill type",
-    __FILE__,VSetBgMode,group);
-  theCommands.Add("vsetgradientbg",
-    "vsetgradientbg  : vsetgradientbg r1 g1 b1 r2 g2 b2 filltype : Mount gradient background",
-    __FILE__,VSetGradientBg,group);
-  theCommands.Add("vsetgrbgmode",
-    "vsetgrbgmode    : vsetgrbgmode filltype : Change gradient background fill type",
-    __FILE__,VSetGradientBgMode,group);
-  theCommands.Add("vsetcolorbg",
-    "vsetcolorbg     : vsetcolorbg r g b : Set background color",
-    __FILE__,VSetColorBg,group);
-  theCommands.Add("vsetdefaultbg",
-    "vsetdefaultbg r g b\n"
-    "\n\t\t: vsetdefaultbg r1 g1 b1 r2 g2 b2 fillmode"
-    "\n\t\t: Set default viewer background fill color (flat/gradient).",
-    __FILE__,VSetDefaultBg,group);
+  theCommands.Add (
+    "vbackground",
+    "Changes background or some background settings.\n"
+    "\n"
+    "Usage:\n"
+    "  vbackground -imageFile ImageFile [-imageMode FillType]\n"
+    "  vbackground -imageMode FillType\n"
+    "  vbackground -gradient Color1 Color2 [-gradientMode FillMethod]\n"
+    "  vbackground -gradientMode FillMethod\n"
+    "  vbackground -cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]\n"
+    "  vbackground -color Color\n"
+    "  vbackground -default -gradient Color1 Color2 [-gradientMode FillType]\n"
+    "  vbackground -default -color Color\n"
+    "  vbackground -help\n"
+    "\n"
+    "Options:\n"
+    "  -imageFile    (-imgFile, -image, -img):             sets filename of image used as background\n"
+    "  -imageMode    (-imgMode, -imageMd, -imgMd):         sets image fill type\n"
+    "  -gradient     (-grad, -gr):                         sets background gradient starting and ending colors\n"
+    "  -gradientMode (-gradMode, -gradMd, -grMode, -grMd): sets gradient fill method\n"
+    "  -cubemap      (-cmap, -cm):                         sets environmet cubemap as background\n"
+    "  -invertedz    (-invz, -iz):                         sets inversion of Z axis for background cubemap rendering\n"
+    "  -order        (-o):                                 defines order of tiles in one image cubemap\n"
+    "                                                      (has no effect in case of multi image cubemaps)\n"
+    "  -color        (-col):                               sets background color\n"
+    "  -default      (-def):                               sets background default gradient or color\n"
+    "  -help         (-h):                                 outputs short help message\n"
+    "\n"
+    "Arguments:\n"
+    "  Color:        Red Green Blue  - where Red, Green, Blue must be integers within the range [0, 255]\n"
+    "                                  or reals within the range [0.0, 1.0]\n"
+    "                ColorName       - one of WHITE, BLACK, RED, GREEN, BLUE, etc.\n"
+    "                #HHH, [#]HHHHHH - where H is a hexadecimal digit (0 .. 9, a .. f, or A .. F)\n"
+    "  FillMethod:   one of NONE, HOR[IZONTAL], VER[TICAL], DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, "
+    "CORNER4\n"
+    "  FillType:     one of CENTERED, TILED, STRETCH, NONE\n"
+    "  ImageFile:    a name of the file with the image used as a background\n"
+    "  CubemapFilei: a name of the file with one image packed cubemap or names of separate files with every cubemap side\n"
+    "  TileIndexi:   a cubemap side index in range [0, 5] for i tile of one image packed cubemap\n",
+    __FILE__,
+    vbackground,
+    group);
+  theCommands.Add ("vsetbg",
+                   "Loads image as background."
+                   "\n\t\t: vsetbg ImageFile [FillType]"
+                   "\n\t\t: vsetbg -imageFile ImageFile [-imageMode FillType]"
+                   "\n\t\t: Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.",
+                   __FILE__,
+                   vbackground,
+                   group);
+  theCommands.Add ("vsetbgmode",
+                   "Changes background image fill type."
+                   "\n\t\t: vsetbgmode [-imageMode] FillType"
+                   "\n\t\t: Alias for 'vbackground -imageMode FillType'.",
+                   __FILE__,
+                   vbackground,
+                   group);
+  theCommands.Add ("vsetgradientbg",
+                   "Mounts gradient background."
+                   "\n\t\t: vsetgradientbg Color1 Color2 [FillMethod]"
+                   "\n\t\t: vsetgradientbg -gradient Color1 Color2 [-gradientMode FillMethod]"
+                   "\n\t\t: Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.",
+                   __FILE__,
+                   vbackground,
+                   group);
+  theCommands.Add ("vsetgrbgmode",
+                   "Changes gradient background fill method."
+                   "\n\t\t: vsetgrbgmode [-gradientMode] FillMethod"
+                   "\n\t\t: Alias for 'vbackground -gradientMode FillMethod'.",
+                   __FILE__,
+                   vbackground,
+                   group);
+  theCommands.Add ("vsetcolorbg",
+                   "Sets background color."
+                   "\n\t\t: vsetcolorbg [-color] Color."
+                   "\n\t\t: Alias for 'vbackground -color Color'.",
+                   __FILE__,
+                   vbackground,
+                   group);
+  theCommands.Add ("vsetdefaultbg",
+                   "Sets default viewer background fill color (flat/gradient)."
+                   "\n\t\t: vsetdefaultbg Color1 Color2 [FillMethod]"
+                   "\n\t\t: vsetdefaultbg -gradient Color1 Color2 [-gradientMode FillMethod]"
+                   "\n\t\t: Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'."
+                   "\n\t\t: vsetdefaultbg [-color] Color"
+                   "\n\t\t: Alias for 'vbackground -default -color Color'.",
+                   __FILE__,
+                   vbackground,
+                   group);
   theCommands.Add("vscale",
     "vscale          : vscale X Y Z",
     __FILE__,VScale,group);
@@ -12552,12 +13832,14 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     __FILE__, VTile, group);
   theCommands.Add("vzlayer",
               "vzlayer [layerId]"
-      "\n\t\t:         [-add|-delete|-get|-settings]"
+      "\n\t\t:         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]"
       "\n\t\t:         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]"
       "\n\t\t:         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]"
-      "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv}]"
+      "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]"
       "\n\t\t: ZLayer list management:"
       "\n\t\t:   -add      add new z layer to viewer and print its id"
+      "\n\t\t:   -insertBefore add new z layer and insert it before existing one"
+      "\n\t\t:   -insertAfter  add new z layer and insert it after  existing one"
       "\n\t\t:   -delete   delete z layer"
       "\n\t\t:   -get      print sequence of z layers"
       "\n\t\t:   -settings print status of z layer settings"
@@ -12567,10 +13849,10 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vlayerline",
     "vlayerline : vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]",
     __FILE__,VLayerLine,group);
-  theCommands.Add ("vgrid",
-    "vgrid [off] [Mode={r|c}] [Type={l|p}] [OriginX OriginY [StepX/StepRadius StepY/DivNb RotAngle]]"
-    " : Mode - rectangular or circular"
-    " : Type - lines or points",
+  theCommands.Add("vgrid",
+              "vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]"
+      "\n\t\t:       [-step X Y] [-size DX DY]"
+      "\n\t\t:       [-step StepRadius NbDivisions] [-radius Radius]",
     __FILE__, VGrid, group);
   theCommands.Add ("vpriviledgedplane",
     "vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]"
@@ -12641,6 +13923,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}]"
     "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
+    "\n\t\t:       [-noExtensions {0|1}] [-maxVersion Major Minor]"
     "\n\t\t: Modify particular graphic driver options:"
     "\n\t\t:  FFP      - use fixed-function pipeline instead of"
     "\n\t\t:             built-in GLSL programs"
@@ -12655,6 +13938,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:  softMode          - software OpenGL implementation"
     "\n\t\t:  compatibleProfile - backward-compatible profile"
     "\n\t\t:  quadbuffer        - QuadBuffer"
+    "\n\t\t:  noExtensions      - disallow usage of extensions"
+    "\n\t\t:  maxVersion        - force upper OpenGL version to be used"
     "\n\t\t: Unlike vrenderparams, these parameters control alternative"
     "\n\t\t: rendering paths producing the same visual result when"
     "\n\t\t: possible."
@@ -12665,7 +13950,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     " with f option returns free memory in bytes",
     __FILE__, VMemGpu, group);
   theCommands.Add ("vreadpixel",
-    "vreadpixel xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]"
+    "vreadpixel xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [-name]"
     " : Read pixel value for active view",
     __FILE__, VReadPixel, group);
   theCommands.Add("diffimage",
@@ -12962,7 +14247,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n      '-nbtiles      64..1024'    Specifies number of screen tiles per Redraw in ISS mode (256 by default)"
     "\n      '-rebuildGlsl  on|off'      Rebuild Ray-Tracing GLSL programs (for debugging)"
     "\n      '-shadingModel model'       Controls shading model from enumeration"
-    "\n                                  color, flat, gouraud, phong"
+    "\n                                  unlit, flat, gouraud, phong"
     "\n      '-resolution   value'       Sets a new pixels density (PPI), defines scaling factor for parameters like text size"
     "\n      '-aperture     >= 0.0'      Aperture size  of perspective camera for depth-of-field effect (0 disables DOF)"
     "\n      '-focal        >= 0.0'      Focal distance of perspective camera for depth-of-field effect"
@@ -13009,6 +14294,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
       "\n      '-adjustPosition {0|1}'             adjust position when attaching"
       "\n      '-adjustSize     {0|1}'             adjust size when attaching"
       "\n      '-enableModes    {0|1}'             enable modes when attaching"
+      "\n      '-view  {active | [name of view]}'  display manipulator only in defined view,"
+      "\n                                          by default it is displayed in all views of the current viewer"
       "\n      '-detach'                           detach manipulator"
       "\n      '-startTransform mouse_x mouse_y' - invoke start of transformation"
       "\n      '-transform      mouse_x mouse_y' - invoke transformation"
@@ -13019,8 +14306,10 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
       "\n      '-autoActivate      {0|1}'        - set activation on detection"
       "\n      '-followTranslation {0|1}'        - set following translation transform"
       "\n      '-followRotation    {0|1}'        - set following rotation transform"
+      "\n      '-followDragging    {0|1}'        - set following dragging transform"
       "\n      '-gap value'                      - set gap between sub-parts"
       "\n      '-part axis mode    {0|1}'        - set visual part"
+      "\n      '-parts axis mode   {0|1}'        - set visual part"
       "\n      '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator"
       "\n      '-size value'                     - set size of manipulator"
       "\n      '-zoomable {0|1}'                 - set zoom persistence",
@@ -13058,9 +14347,36 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
                    "\n\t\t:   entity      color of etected entity",
                    __FILE__, VDumpSelectionImage, group);
 
-#if defined(_WIN32)
-  theCommands.Add("vprogressive",
-    "vprogressive",
-    __FILE__, VProgressiveMode, group);
-#endif
+  theCommands.Add ("vviewcube",
+                   "vviewcube name"
+                   "\n\t\t: Displays interactive view manipualtion object."
+                   "\n\t\t: Options: "
+                   "\n\t\t:   -reset                   reset geomertical and visual attributes'"
+                   "\n\t\t:   -size Size               adapted size of View Cube"
+                   "\n\t\t:   -boxSize Size            box size"
+                   "\n\t\t:   -axes {0|1 }             show/hide axes (trihedron)"
+                   "\n\t\t:   -edges {0|1}             show/hide edges of View Cube"
+                   "\n\t\t:   -vertices {0|1}          show/hide vertices of View Cube"
+                   "\n\t\t:   -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation"
+                   "\n\t\t:   -color Color             color of View Cube"
+                   "\n\t\t:   -boxColor Color          box color"
+                   "\n\t\t:   -boxSideColor Color      box sides color"
+                   "\n\t\t:   -boxEdgeColor Color      box edges color"
+                   "\n\t\t:   -boxCornerColor Color    box corner color"
+                   "\n\t\t:   -textColor Color         color of side text of view cube"
+                   "\n\t\t:   -innerColor Color        inner box color"
+                   "\n\t\t:   -transparency Value      transparency of object within [0, 1] range"
+                   "\n\t\t:   -boxTransparency Value   transparency of box    within [0, 1] range"
+                   "\n\t\t:   -font Name               font name"
+                   "\n\t\t:   -fontHeight Value        font height"
+                   "\n\t\t:   -boxFacetExtension Value box facet extension"
+                   "\n\t\t:   -boxEdgeGap Value        gap between box edges and box sides"
+                   "\n\t\t:   -boxEdgeMinSize Value    minimal box edge size"
+                   "\n\t\t:   -boxCornerMinSize Value  minimal box corner size"
+                   "\n\t\t:   -axesPadding Value       padding between box and arrows"
+                   "\n\t\t:   -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range"
+                   "\n\t\t:   -fixedanimation {0|1}    uninterruptible animation loop"
+                   "\n\t\t:   -duration Seconds        animation duration in seconds",
+    __FILE__, VViewCube, group);
+
 }